100 lines
2.1 KiB
Go
Raw Permalink Normal View History

2024-04-10 22:10:09 +08:00
package uploads
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"net/http"
"strconv"
"sync"
"time"
"nf-repo/internal/interfaces"
"nf-repo/internal/model"
"nf-repo/internal/tool/rerr"
"nf-repo/internal/verify"
"github.com/loveuer/nf/nft/log"
2024-04-10 22:10:09 +08:00
)
type memUploader struct {
lock sync.Mutex
uploads map[string][]byte
}
func (m *memUploader) UploadId() string {
m.lock.Lock()
m.lock.Unlock()
id := strconv.Itoa(int(time.Now().UnixNano()))
m.uploads[id] = []byte{}
return id
}
func (m *memUploader) Write(ctx context.Context, id string, reader io.ReadCloser, start, end int) (int, *rerr.RepositoryError) {
m.lock.Lock()
defer m.lock.Unlock()
if start != len(m.uploads[id]) {
return 0, &rerr.RepositoryError{
Status: http.StatusRequestedRangeNotSatisfiable,
Code: "BLOB_UPLOAD_UNKNOWN",
Message: "Your content range doesn't match what we have",
}
}
l := bytes.NewBuffer(m.uploads[id])
size, err := io.Copy(l, reader)
if err != nil {
return 0, rerr.ErrInternal(err)
}
_ = size
m.uploads[id] = l.Bytes()
return len(m.uploads[id]), nil
}
func (m *memUploader) Done(ctx context.Context, bh interfaces.BlobHandler, id string, reader io.ReadCloser, contentLength int, repo string, hash model.Hash) *rerr.RepositoryError {
size := verify.SizeUnknown
if contentLength > 0 {
size = len(m.uploads[id]) + contentLength
}
m.lock.Lock()
defer m.lock.Unlock()
in := io.NopCloser(io.MultiReader(bytes.NewBuffer(m.uploads[id]), reader))
vrc, err := verify.ReadCloser(in, int64(size), hash)
if err != nil {
return rerr.ErrInternal(err)
}
defer vrc.Close()
if err := bh.Put(ctx, repo, hash, vrc); err != nil {
if errors.As(err, &verify.Error{}) {
log.Debug("memUploader: handle blob put err, repo = %s, hash = %s, err = %s", repo, hash.String(), fmt.Sprintf("Digest mismatch: %v", err))
2024-04-10 22:10:09 +08:00
return rerr.ErrDigestMismatch
}
return rerr.ErrInternal(err)
}
m.uploads[id] = nil
delete(m.uploads, id)
return nil
}
func NewMemUploader() interfaces.UploadHandler {
return &memUploader{
lock: sync.Mutex{},
uploads: make(map[string][]byte),
}
}