Returns every character image with when it was last changed, in Unix seconds, so clients can cache the images and download only the ones that changed.
106 lines
4.1 KiB
Go
106 lines
4.1 KiB
Go
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 huma.API) {
|
|
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},
|
|
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.")},
|
|
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.")},
|
|
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.")},
|
|
func(ctx context.Context, _ *struct{}) (*jsonBody[[]string], error) {
|
|
return ok(s.characters.List())
|
|
})
|
|
register(s, a, route{op: get("list-character-details", "/character/details", "characters",
|
|
"List characters with change times",
|
|
"Returns every character image with the time it was last changed, so clients can cache images and download only the changed ones.")},
|
|
func(ctx context.Context, _ *struct{}) (*jsonBody[[]backend.CharacterDetails], error) {
|
|
return ok(s.characters.ListDetails())
|
|
})
|
|
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},
|
|
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)},
|
|
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)},
|
|
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},
|
|
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")
|
|
}
|