102 lines
2.1 KiB
Go
102 lines
2.1 KiB
Go
package uploads
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"github.com/sirupsen/logrus"
|
|
"io"
|
|
"net/http"
|
|
"nf-repo/internal/interfaces"
|
|
"nf-repo/internal/model"
|
|
"nf-repo/internal/util/rerr"
|
|
"nf-repo/internal/verify"
|
|
"strconv"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
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{}) {
|
|
logrus.
|
|
WithField("path", "handleBlobs.Put").
|
|
WithField("repo", repo).
|
|
WithField("hash", hash.String()).
|
|
WithField("err", fmt.Sprintf("Digest mismatch: %v", err)).Debug()
|
|
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),
|
|
}
|
|
}
|