/* * Copyright 2026 Oleg Borodin */ package service import ( "context" "net" "net/http" "time" "mstore/app/handler" "mstore/app/logger" "mstore/app/router" ) type ServiceParams struct { Handler *handler.Handler Listener net.Listener } type Service struct { hand *handler.Handler rout *router.Router logg *logger.Logger listen net.Listener hsrv *http.Server } func NewService(params *ServiceParams) (*Service, error) { var err error svc := &Service{ hand: params.Handler, listen: params.Listener, } svc.logg = logger.NewLoggerWithSubject("service") return svc, err } func (svc *Service) Build() error { var err error svc.logg.Infof("Service build ") svc.rout = router.NewRouter() svc.rout.Use(router.NewRecoveryMiddleware(svc.logg.Errorf)) svc.rout.Use(router.NewLoggingMiddleware(svc.logg.Infof)) svc.rout.Use(router.NewCorsMiddleware()) svc.rout.Use(svc.hand.AuthMiddleware) svc.rout.Head(`/v2/{name}/blobs/{digest}`, svc.hand.BlobExists) svc.rout.Get(`/v3/api/service/hello`, svc.hand.SendHello) svc.rout.Head(`/v3/api/file/{filepath}`, svc.hand.FileInfo) svc.rout.Put(`/v3/api/file/{filepath}`, svc.hand.PutFile) svc.rout.Get(`/v3/api/file/{filepath}`, svc.hand.GetFile) svc.rout.Delete(`/v3/api/file/{filepath}`, svc.hand.DeleteFile) svc.rout.Get(`/v3/api/files/{filepath}`, svc.hand.ListFiles) svc.rout.Get(`/v3/api/files/`, svc.hand.ListFiles) svc.rout.Post(`/v3/api/checker/{filepath}`, svc.hand.CheckFiles) svc.rout.Post(`/v3/api/checker/`, svc.hand.CheckFiles) svc.rout.Get(`/v3/api/collections/{path}`, svc.hand.ListCollections) svc.rout.Get(`/v3/api/collections/`, svc.hand.ListCollections) svc.rout.Delete(`/v3/api/collection/{path}`, svc.hand.DeleteCollection) svc.rout.Delete(`/v3/api/collection/`, svc.hand.DeleteCollection) svc.rout.Get(`/v2/`, svc.hand.GetVersion) svc.rout.Head(`/v2/{name}/manifests/{reference}`, svc.hand.ManifestExists) svc.rout.Put(`/v2/{name}/manifests/{reference}`, svc.hand.PutManifest) svc.rout.Get(`/v2/{name}/manifests/{reference}`, svc.hand.GetManifest) svc.rout.Delete(`/v2/{name}/manifests/{reference}`, svc.hand.DeleteManifest) svc.rout.Post(`/v2/{name}/blobs/uploads/`, svc.hand.PostUpload) svc.rout.Patch(`/v2/{name}/blobs/uploads/{reference}`, svc.hand.PatchUpload) svc.rout.Put(`/v2/{name}/blobs/uploads/{reference}`, svc.hand.PutUpload) svc.rout.Put(`/v2/{name}/uploads/{reference}`, svc.hand.PutUpload) svc.rout.Get(`/v2/{name}/blobs/{digest}`, svc.hand.GetBlob) svc.rout.Delete(`/v2/{name}/blobs/{digest}`, svc.hand.DeleteBlob) svc.rout.Get(`/v2/{name}/tags/list`, svc.hand.GetTags) svc.rout.Get(`/v2/{name}/referrers/{digest}`, svc.hand.GetReferer) svc.rout.Get(`/v2/_catalog`, svc.hand.ListManifests) svc.rout.Post(`/v2/checker/{name}`, svc.hand.CheckImages) svc.rout.Post(`/v2/checker`, svc.hand.CheckImages) svc.rout.Post(`/v3/api/account/create`, svc.hand.CreateAccount) svc.rout.Post(`/v3/api/account/get`, svc.hand.GetAccount) svc.rout.Post(`/v3/api/account/update`, svc.hand.UpdateAccount) svc.rout.Post(`/v3/api/account/delete`, svc.hand.DeleteAccount) svc.rout.Post(`/v3/api/accounts/list`, svc.hand.ListAccounts) svc.rout.Post(`/v3/api/grant/create`, svc.hand.CreateGrant) svc.rout.Post(`/v3/api/grant/get`, svc.hand.GetGrant) svc.rout.Post(`/v3/api/grant/update`, svc.hand.UpdateGrant) svc.rout.Post(`/v3/api/grant/delete`, svc.hand.DeleteGrant) svc.rout.Post(`/v3/api/grants/list`, svc.hand.ListGrants) svc.rout.Get(`/{filepath}`, svc.hand.GetFile) svc.rout.NotFound(svc.hand.NotFound) selector := svc.rout.Selector() for _, item := range selector.Routes { svc.logg.Infof("%s\t%s", item.Method, item.RawPath) } svc.logg.Infof("Service listening at %v", svc.listen.Addr()) svc.hsrv = &http.Server{ Handler: svc.rout, } return err } func (svc *Service) Run() error { var err error svc.logg.Infof("Service run") err = svc.hsrv.Serve(svc.listen) if err == http.ErrServerClosed { svc.logg.Warningf("Service Closed") err = nil } if err != nil { return err } return err } func (svc *Service) Stop() { if svc.hsrv != nil { svc.logg.Infof("Service stop") downWaiting := 10 * time.Second ctx, cancel := context.WithTimeout(context.Background(), downWaiting) defer cancel() err := svc.hsrv.Shutdown(ctx) if err != nil { svc.logg.Errorf("Error service shutdown: %v", err) } } }