package server import ( "context" "net/http" "music-server/internal/backend" "github.com/danielgtaylor/huma/v2" ) type characterInput struct { Name string `query:"name" required:"true" doc:"File name of the character image, from the character list"` } type redirectOutput struct { Status int Location string `header:"Location" doc:"Download URL of the asset"` } type healthOutput struct { Body map[string]string } func (s *Server) registerMisc(a apis) { get := func(id, path, tag, summary, description string, errs ...int) huma.Operation { return huma.Operation{ OperationID: id, Method: http.MethodGet, Path: path, Summary: summary, Description: description, Tags: []string{tag}, Errors: errs, } } register(s, a, route{op: get("get-health", "/health", "server", "Health check", "Returns {\"status\": \"up\"} when the server and database work, otherwise status \"down\" and an error."), public: true, legacyPath: "/health"}, func(ctx context.Context, _ *struct{}) (*healthOutput, error) { return &healthOutput{Body: s.db.Health(ctx)}, nil }) register(s, a, route{op: get("get-version", "/version", "server", "Latest server version", "Returns the server version and its changelog."), legacyPath: "/version"}, func(ctx context.Context, _ *struct{}) (*jsonBody[backend.VersionData], error) { return ok(backend.GetLatestVersion(), nil) }) register(s, a, route{op: get("get-version-history", "/version/history", "server", "Version history", "Returns all server versions with their changelogs, newest first."), legacyPath: "/version/history"}, func(ctx context.Context, _ *struct{}) (*jsonBody[[]backend.VersionData], error) { return ok(backend.GetVersionHistory(), nil) }) register(s, a, route{op: get("list-characters", "/character/list", "characters", "List characters", "Returns the file names of all character images."), legacyPath: "/characters"}, func(ctx context.Context, _ *struct{}) (*jsonBody[[]string], error) { return ok(s.characters.List()) }) image := get("get-character", "/character", "characters", "Character image", "Returns a character image.", http.StatusBadRequest, http.StatusNotFound) image.Responses = fileResponses("The image", "image/png", "image/jpeg") register(s, a, route{op: image, legacyPath: "/character"}, func(ctx context.Context, in *characterInput) (*huma.StreamResponse, error) { f, err := s.characters.Open(in.Name) if err != nil { return nil, apiError(err) } return streamOpenFile(f, "", false) }) r := s.releases register(s, a, route{op: get("get-latest-client-version", "/download", "download", "Latest client version", "Returns the name of the latest MusicPlayer release.", http.StatusBadGateway), legacyPath: "/download"}, func(ctx context.Context, _ *struct{}) (*jsonBody[string], error) { return ok(r.LatestVersion(ctx)) }) register(s, a, route{op: get("list-client-assets", "/download/list", "download", "Latest client assets", "Returns the file names of the latest MusicPlayer release.", http.StatusBadGateway), legacyPath: "/download/list"}, func(ctx context.Context, _ *struct{}) (*jsonBody[[]string], error) { return ok(r.AssetNames(ctx)) }) download := func(id, path, platform, suffix string) { op := get(id, path, "download", "Download the latest client for "+platform, "Redirects to the download URL of the latest MusicPlayer release for "+platform+".", http.StatusNotFound, http.StatusBadGateway) op.DefaultStatus = http.StatusFound register(s, a, route{op: op, legacyPath: path}, func(ctx context.Context, _ *struct{}) (*redirectOutput, error) { url, err := r.AssetURL(ctx, suffix) if err != nil { return nil, apiError(err) } return &redirectOutput{Status: http.StatusFound, Location: url}, nil }) } download("download-client-windows", "/download/windows", "Windows", ".exe") download("download-client-linux", "/download/linux", "Linux", ".x86_64") }