loveuer 6e866b83e4 feat: as docker mirror registry
feat: add global proxy config
upgrade: upgrade front(angular) to 19
chore: deployment staff
  1. Dockerfile: build frontend, backend, and run in nginx base image
2024-12-23 22:46:34 -08:00

149 lines
3.8 KiB
Go

package handler
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
"nf-repo/internal/controller"
"nf-repo/internal/interfaces"
"nf-repo/internal/model"
"nf-repo/internal/tool/rerr"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/loveuer/nf"
"github.com/loveuer/nf/nft/log"
)
func handleManifest(ctx *nf.Ctx, m interfaces.ManifestHandler, blobHandler interfaces.BlobHandler) error {
elem := strings.Split(ctx.Path(), "/")
elem = elem[1:]
target := elem[len(elem)-1]
repo := strings.Join(elem[1:len(elem)-2], "/")
log.Debug("handleManifest: path = %s, method = %s, repo = %s, target = %s",
ctx.Path(), ctx.Method(), repo, target)
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 {
if re.Status == 404 {
log.Debug("handleManifest: repo not found, start pull, repo = %s, tag = %s", repo, target)
var manifest *v1.Manifest
if manifest, err = controller.PullRepo(ctx.Context(), repo, target, "", m, blobHandler); err != nil {
return rerr.Error(ctx, &rerr.RepositoryError{
Status: http.StatusInternalServerError,
Code: "INTERNAL_SERVER_ERROR",
Message: err.Error(),
})
}
contentType = string(manifest.MediaType)
bs, _ = json.Marshal(manifest)
goto RETURN_GET
}
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(),
})
}
RETURN_GET:
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:
var (
err error
buf = &bytes.Buffer{}
hash model.Hash
)
if _, err = io.Copy(buf, ctx.Request.Body); err != nil {
return rerr.Error(ctx, rerr.ErrInternal(err))
}
if hash, _, err = model.SHA256(bytes.NewReader(buf.Bytes())); err != nil {
return rerr.Error(ctx, rerr.ErrInternal(err))
}
digest := hash.String()
mf := model.RepoSimpleManifest{
Blob: buf.Bytes(),
ContentType: ctx.Get("Content-Type"),
}
log.Debug("handleManifest: path = %s, method = %s, repo = %s, target = %s, digest = %s, content-type = %s, content = %s",
ctx.Path(), ctx.Method(), repo, target, digest, ctx.Get("Content-Type"), buf.String())
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",
})
}
}