repo.me/internal/handler/manifest.go
2024-04-14 21:48:27 +08:00

128 lines
3.1 KiB
Go

package handler
import (
"bytes"
"fmt"
"github.com/loveuer/nf"
"github.com/sirupsen/logrus"
"io"
"net/http"
"nf-repo/internal/interfaces"
"nf-repo/internal/model"
"nf-repo/internal/util/rerr"
"strings"
)
func handleManifest(ctx *nf.Ctx, m interfaces.ManifestHandler) error {
elem := strings.Split(ctx.Path(), "/")
elem = elem[1:]
target := elem[len(elem)-1]
repo := strings.Join(elem[1:len(elem)-2], "/")
logrus.
WithField("handler", "handleManifest").
WithField("path", ctx.Path()).
WithField("method", ctx.Method()).
WithField("repo", repo).
WithField("target", target).
Debug()
switch ctx.Method() {
case http.MethodGet:
var (
err error
reader io.ReadCloser
contentType string
re *rerr.RepositoryError
bs []byte
)
if reader, contentType, re = m.Get(ctx.Request.Context(), repo, target); re != nil {
return rerr.Error(ctx, re)
}
if bs, err = io.ReadAll(reader); err != nil {
return rerr.Error(ctx, &rerr.RepositoryError{
Status: http.StatusInternalServerError,
Code: "INTERNAL_SERVER_ERROR",
Message: err.Error(),
})
}
h, _, _ := model.SHA256(bytes.NewReader(bs))
ctx.Set("Docker-Content-Digest", h.String())
ctx.Set("Content-Type", contentType)
ctx.Set("Content-Length", fmt.Sprint(len(bs)))
ctx.Status(http.StatusOK)
_, err = ctx.Write(bs)
return err
case http.MethodHead:
var (
err error
reader io.ReadCloser
contentType string
re *rerr.RepositoryError
bs []byte
)
if reader, contentType, re = m.Get(ctx.Request.Context(), repo, target); re != nil {
return rerr.Error(ctx, re)
}
if bs, err = io.ReadAll(reader); err != nil {
return rerr.Error(ctx, &rerr.RepositoryError{
Status: http.StatusInternalServerError,
Code: "INTERNAL_SERVER_ERROR",
Message: err.Error(),
})
}
h, _, _ := model.SHA256(bytes.NewReader(bs))
ctx.Set("Docker-Content-Digest", h.String())
ctx.Set("Content-Type", contentType)
ctx.Set("Content-Length", fmt.Sprint(len(bs)))
return ctx.SendStatus(http.StatusOK)
case http.MethodPut:
b := &bytes.Buffer{}
io.Copy(b, ctx.Request.Body)
h, _, _ := model.SHA256(bytes.NewReader(b.Bytes()))
digest := h.String()
mf := model.Manifest{
Blob: b.Bytes(),
ContentType: ctx.Get("Content-Type"),
}
logrus.
WithField("handler", "handleManifest").
WithField("path", ctx.Path()).
WithField("method", ctx.Method()).
WithField("repo", repo).
WithField("target", target).
WithField("digest", digest).
WithField("content-type", ctx.Get("Content-Type")).
WithField("content", b.String()).
Debug()
if err := m.Put(ctx.Request.Context(), repo, target, digest, &mf); err != nil {
return rerr.Error(ctx, err)
}
ctx.Set("Docker-Content-Digest", digest)
return ctx.SendStatus(http.StatusCreated)
case http.MethodDelete:
return ctx.SendStatus(http.StatusAccepted)
default:
return rerr.Error(ctx, &rerr.RepositoryError{
Status: http.StatusBadRequest,
Code: "METHOD_UNKNOWN",
Message: "We don't understand your method + url",
})
}
}