From 834db962958652502aba88362dbe91df2ee618ee Mon Sep 17 00:00:00 2001 From: Ophestra Date: Tue, 15 Sep 2026 00:06:21 +0900 Subject: cmd/mbf: rename pkgsite This name is less ambiguous than pkgserver. Signed-off-by: Ophestra --- cmd/mbf/internal/pkgserver/api.go | 202 -------------------------------------- 1 file changed, 202 deletions(-) delete mode 100644 cmd/mbf/internal/pkgserver/api.go (limited to 'cmd/mbf/internal/pkgserver/api.go') diff --git a/cmd/mbf/internal/pkgserver/api.go b/cmd/mbf/internal/pkgserver/api.go deleted file mode 100644 index 68ccd471..00000000 --- a/cmd/mbf/internal/pkgserver/api.go +++ /dev/null @@ -1,202 +0,0 @@ -// Package pkgserver implements the package metadata service backend. -package pkgserver - -import ( - "context" - "encoding/json" - "log" - "net/http" - "net/url" - "path" - "strconv" - "sync" - "time" - - "hakurei.app/internal/info" - "hakurei.app/internal/rosa" -) - -// for lazy initialisation of serveInfo -var ( - infoPayload struct { - // Current package count. - Count int `json:"count"` - // Hakurei version, set at link time. - HakureiVersion string `json:"hakurei_version"` - } - infoPayloadOnce sync.Once -) - -// handleInfo writes constant system information. -func handleInfo(w http.ResponseWriter, _ *http.Request) { - infoPayloadOnce.Do(func() { - infoPayload.Count = len(rosa.Collect()) - infoPayload.HakureiVersion = info.Version() - }) - // TODO(mae): cache entire response if no additional fields are planned - writeAPIPayload(w, infoPayload) -} - -// newStatusHandler returns a [http.HandlerFunc] that offers status files for -// viewing or download, if available. -func (index *packageIndex) newStatusHandler(disposition bool) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - m, ok := index.names[path.Base(r.URL.Path)] - if !ok || !m.HasReport { - http.NotFound(w, r) - return - } - - contentType := "text/plain; charset=utf-8" - if disposition { - contentType = "application/octet-stream" - - // quoting like this is unsound, but okay, because metadata is hardcoded - contentDisposition := `attachment; filename="` - contentDisposition += m.Name + "-" - if m.Version != "" { - contentDisposition += m.Version + "-" - } - contentDisposition += m.ids + `.log"` - w.Header().Set("Content-Disposition", contentDisposition) - } - w.Header().Set("Content-Type", contentType) - w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") - if err := func() (err error) { - defer index.handleAccess(&err)() - _, err = w.Write(m.status) - return - }(); err != nil { - log.Println(err) - http.Error( - w, "cannot deliver status, contact maintainers", - http.StatusInternalServerError, - ) - } - } -} - -// handleGet writes a slice of metadata with specified order. -func (index *packageIndex) handleGet(w http.ResponseWriter, r *http.Request) { - q := r.URL.Query() - limit, err := strconv.Atoi(q.Get("limit")) - if err != nil || limit > 100 || limit < 1 { - http.Error( - w, "limit must be an integer between 1 and 100", - http.StatusBadRequest, - ) - return - } - i, err := strconv.Atoi(q.Get("index")) - if err != nil || i >= len(index.sorts[0]) || i < 0 { - http.Error( - w, "index must be an integer between 0 and "+ - strconv.Itoa(len(index.sorts[0])-1), - http.StatusBadRequest, - ) - return - } - sort, err := strconv.Atoi(q.Get("sort")) - if err != nil || sort >= len(index.sorts) || sort < 0 { - http.Error( - w, "sort must be an integer between 0 and "+ - strconv.Itoa(sortOrderEnd), - http.StatusBadRequest, - ) - return - } - values := index.sorts[sort][i:min(i+limit, len(index.sorts[sort]))] - writeAPIPayload(w, &struct { - Values []*metadata `json:"values"` - }{values}) -} - -func (index *packageIndex) handleSearch(w http.ResponseWriter, r *http.Request) { - q := r.URL.Query() - limit, err := strconv.Atoi(q.Get("limit")) - if err != nil || limit > 100 || limit < 1 { - http.Error( - w, "limit must be an integer between 1 and 100", - http.StatusBadRequest, - ) - return - } - i, err := strconv.Atoi(q.Get("index")) - if err != nil || i >= len(index.sorts[0]) || i < 0 { - http.Error( - w, "index must be an integer between 0 and "+ - strconv.Itoa(len(index.sorts[0])-1), - http.StatusBadRequest, - ) - return - } - search, err := url.QueryUnescape(q.Get("search")) - if len(search) > 100 || err != nil { - http.Error( - w, "search must be a string between 0 and 100 characters long", - http.StatusBadRequest, - ) - return - } - desc := q.Get("desc") == "true" - n, res, err := index.performSearchQuery(limit, i, search, desc) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - } - writeAPIPayload(w, &struct { - Count int `json:"count"` - Values []searchResult `json:"values"` - }{n, res}) -} - -// apiVersion is the name of the current API revision, as part of the pattern. -const apiVersion = "v1" - -// registerAPI registers API handler functions. -func (index *packageIndex) registerAPI(mux *http.ServeMux) { - mux.HandleFunc("GET /api/"+apiVersion+"/info", handleInfo) - mux.HandleFunc("GET /api/"+apiVersion+"/get", index.handleGet) - mux.HandleFunc("GET /api/"+apiVersion+"/search", index.handleSearch) - mux.HandleFunc("GET /api/"+apiVersion+"/status/", index.newStatusHandler(false)) - mux.HandleFunc("GET /status/", index.newStatusHandler(true)) -} - -// Register arranges for mux to service API requests. -func Register(ctx context.Context, mux *http.ServeMux, report *rosa.Report) error { - var index packageIndex - index.search = make(searchCache) - if err := index.populate(report); err != nil { - return err - } - ticker := time.NewTicker(1 * time.Minute) - go func() { - for { - select { - case <-ctx.Done(): - ticker.Stop() - return - case <-ticker.C: - index.search.clean() - } - } - }() - index.registerAPI(mux) - return nil -} - -// writeAPIPayload sets headers common to API responses and encodes payload as -// JSON for the response body. -func writeAPIPayload(w http.ResponseWriter, payload any) { - w.Header().Set("Content-Type", "application/json; charset=utf-8") - w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") - w.Header().Set("Pragma", "no-cache") - w.Header().Set("Expires", "0") - - if err := json.NewEncoder(w).Encode(payload); err != nil { - log.Println(err) - http.Error( - w, "cannot encode payload, contact maintainers", - http.StatusInternalServerError, - ) - } -} -- cgit v1.3.1