You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: item_handler.go
    path of file: ./repos/cds/engine/cdn
    
    the code of the file until where you have to start completion: package cdn

import (
	"bytes"
	"context"
	"encoding/hex"
	"net/http"

	"github.com/gorilla/mux"

	"github.com/ovh/cds/engine/cdn/item"
	"github.com/ovh/cds/engine/cdn/storage"
	"github.com/ovh/cds/engine/gorpmapper"
	"github.com/ovh/cds/engine/service"
	"github.com/ovh/cds/sdk"
)

func (s *Service) bulkDeleteItemsHandler() service.Handler {
	return func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
		var req sdk.CDNMarkDelete
		if err := service.UnmarshalBody(r, &req); err != nil {
			return err
		}

		if req.RunID <= 0 {
			return sdk.WrapError(sdk.ErrWrongRequest, "missing runID")
		}
		tx, err := s.mustDBWithCtx(ctx).Begin()
		if err != nil {
			return sdk.WrapError(err, "unable to start transaction")
		}
		defer tx.Rollback() //nolint

		if err := item.MarkToDeleteByRunIDs(tx, req.RunID); err != nil {
			return err
		}

		return sdk.WrapError(tx.Commit(), "unable to commit transaction")
	}
}

func (s *Service) getItemDownloadInUnitHandler() service.Handler {
	return func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
		vars := mux.Vars(r)
		itemType := sdk.CDNItemType(vars["type"])
		apiRef := vars["apiRef"]
		unitName := vars["unit"]

		return s.downloadItemFromUnit(ctx, itemType, apiRef, unitName, w)
	}
}

func (s *Service) getItemDownloadHandler() service.Handler {
	return func(ctx context.Context, w http.ResponseWriter, r *htt
    
func (s *Service) getItemCheckSyncHandler() service.Handler {
	return func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
		vars := mux.Vars(r)
		itemType := sdk.CDNItemType(vars["type"])
		apiRef := vars["apiRef"]

		it, err := item.LoadByAPIRefHashAndType(ctx, s.Mapper, s.mustDBWithCtx(ctx), apiRef, itemType, gorpmapper.GetOptions.WithDecryption)
		if err != nil {
			return err
		}

		itemsUnits, err := storage.LoadAllItemUnitsByItemIDs(ctx, s.Mapper, s.mustDBWithCtx(ctx), it.ID, gorpmapper.GetOptions.WithDecryption)
		if err != nil {
			return err
		}

		if len(itemsUnits) == 0 {
			return sdk.WithStack(sdk.ErrNotFound)
		}

		itemsUnits = s.Units.FilterItemUnitReaderByType(itemsUnits)

		var contents = map[string]*bytes.Buffer{}
		for _, iu := range itemsUnits {
			src, err := s.Units.NewSource(ctx, iu)
			if err != nil {
				return err
			}
			reader, err := src.NewReader(ctx)
			if err != nil {
				return err
			}
			buf := new(bytes.Buffer)
			if err := src.Read(reader, buf); err != nil {
				return err
			}
			contents[src.Name()] = buf
		}

		var lastContent string
		for st, buffer := range contents {
			if lastContent == "" {
				lastContent = hex.EncodeToString(buffer.Bytes())
				continue
			}
			if lastContent != hex.EncodeToString(buffer.Bytes()) {
				return sdk.NewErrorFrom(sdk.ErrInvalidData, "content of %s on %s doesn't match", apiRef, st)
			}
		}

		var result = struct {
			ID         string
			APIRefHash string
			SHA512     string
			Content    string
		}{
			ID:         it.ID,
			APIRefHash: it.APIRefHash,
			SHA512:     it.Hash,
			Content:    lastContent,
		}

		return service.WriteJSON(w, result, http.StatusOK)
	}
}