package server import ( "context" "net/http" "reflect" "music-server/internal/backend" "music-server/internal/logging" "github.com/danielgtaylor/huma/v2" ) func (s *Server) registerSync(a apis) { registry := a.v1.OpenAPI().Components.Schemas progress := huma.Operation{ OperationID: "get-sync-progress", Method: http.MethodGet, Path: "/sync/progress", Summary: "Sync progress or result", Description: "While a sync is running, returns its progress. Otherwise returns the result of the last sync.", Tags: []string{"sync"}, Responses: map[string]*huma.Response{ "200": { Description: "Progress of the running sync, or the result of the last sync", Content: map[string]*huma.MediaType{"application/json": {Schema: &huma.Schema{OneOf: []*huma.Schema{ registry.Schema(reflect.TypeFor[backend.ProgressResponse](), true, ""), registry.Schema(reflect.TypeFor[backend.SyncResponse](), true, ""), }}}}, }, }, } register(s, a, route{op: progress, legacyPath: "/sync/progress"}, func(ctx context.Context, _ *struct{}) (*jsonBody[any], error) { if s.sync.IsSyncing() { return ok[any](s.sync.Progress(), nil) } return ok[any](s.sync.Result(), nil) }) start := func(id, path, summary, description string, full bool) { register(s, a, route{ op: huma.Operation{ OperationID: id, Method: http.MethodPost, Path: path, Summary: summary, Description: description, Tags: []string{"sync"}, Errors: []int{http.StatusLocked}, }, legacyPath: path, }, func(ctx context.Context, _ *struct{}) (*jsonBody[string], error) { message := "Start syncing soundtracks" if full { message += " full" } if !s.sync.Start(full) { return nil, huma.Error423Locked("Syncing is in progress") } logging.GetLogger().Info(message) return ok(message, nil) }) } start("start-sync", "/sync", "Sync changed soundtracks", "Starts syncing the music folder in the background, skipping soundtracks that have not changed. "+ "Poll /sync/progress for the result.", false) start("start-full-sync", "/sync/full", "Sync all soundtracks", "Starts a full sync in the background that re-reads every soundtrack and removes songs whose files are gone. "+ "Poll /sync/progress for the result.", true) reset := huma.Operation{ OperationID: "reset-library", Method: http.MethodPost, Path: "/sync/reset", Summary: "Delete all soundtracks and songs", Description: "For debugging only.", Tags: []string{"sync"}, Hidden: true, } register(s, a, route{op: reset, legacyPath: "/sync/reset", locked: true}, func(ctx context.Context, _ *struct{}) (*jsonBody[string], error) { logging.GetLogger().Info("Resetting soundtracks database") return ok("Soundtracks and songs are deleted from the database", s.sync.ResetDB(ctx)) }) }