/* Copyright © 2024 Seednode */ package cmd import ( "encoding/json" "fmt" "net/http" "sort" "strings" "time" "github.com/julienschmidt/httprouter" "github.com/klauspost/compress/zstd" "seedno.de/seednode/roulette/types" ) func serveExtensions(formats types.Types, available bool, errorChannel chan<- error) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { startTime := time.Now() w.Header().Set("Content-Type", "text/plain;charset=UTF-8") var extensions string if available { extensions = types.SupportedFormats.GetExtensions() } else { extensions = formats.GetExtensions() } written, err := w.Write([]byte(extensions)) if err != nil { errorChannel <- err } if Verbose { fmt.Printf("%s | SERVE: Registered extension list (%s) to %s in %s\n", startTime.Format(logDate), humanReadableSize(written), realIP(r), time.Since(startTime).Round(time.Microsecond), ) } } } func serveIndex(args []string, index *fileIndex, errorChannel chan<- error) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { startTime := time.Now() indexDump := index.List() sort.SliceStable(indexDump, func(p, q int) bool { return strings.ToLower(indexDump[p]) < strings.ToLower(indexDump[q]) }) w.Header().Set("Content-Type", "application/json;charset=UTF-8") response, err := json.MarshalIndent(indexDump, "", " ") if err != nil { errorChannel <- err serverError(w, r, nil) return } response = append(response, []byte("\n")...) written, err := w.Write(response) if err != nil { errorChannel <- err } if Verbose { fmt.Printf("%s | SERVE: JSON index page (%s) to %s in %s\n", startTime.Format(logDate), humanReadableSize(written), realIP(r), time.Since(startTime).Round(time.Microsecond), ) } } } func serveIndexRebuild(args []string, index *fileIndex, formats types.Types, encoder *zstd.Encoder, errorChannel chan<- error) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { startTime := time.Now() rebuildIndex(args, index, formats, encoder, errorChannel) w.Header().Set("Content-Type", "text/plain;charset=UTF-8") _, err := w.Write([]byte("Ok\n")) if err != nil { errorChannel <- err return } if Verbose { fmt.Printf("%s | SERVE: Index rebuild requested by %s took %s\n", startTime.Format(logDate), realIP(r), time.Since(startTime).Round(time.Microsecond), ) } } } func serveMediaTypes(formats types.Types, available bool, errorChannel chan<- error) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { startTime := time.Now() w.Header().Set("Content-Type", "text/plain;charset=UTF-8") var mediaTypes string if available { mediaTypes = types.SupportedFormats.GetMediaTypes() } else { mediaTypes = formats.GetMediaTypes() } written, err := w.Write([]byte(mediaTypes)) if err != nil { errorChannel <- err } if Verbose { fmt.Printf("%s | SERVE: Available media type list (%s) to %s in %s\n", startTime.Format(logDate), humanReadableSize(written), realIP(r), time.Since(startTime).Round(time.Microsecond), ) } } } func registerAPIHandlers(mux *httprouter.Router, args []string, index *fileIndex, formats types.Types, encoder *zstd.Encoder, errorChannel chan<- error) { if Index { mux.GET(Prefix+AdminPrefix+"/index", serveIndex(args, index, errorChannel)) mux.POST(Prefix+AdminPrefix+"/index/rebuild", serveIndexRebuild(args, index, formats, encoder, errorChannel)) } mux.GET(Prefix+AdminPrefix+"/extensions/available", serveExtensions(formats, true, errorChannel)) mux.GET(Prefix+AdminPrefix+"/extensions/enabled", serveExtensions(formats, false, errorChannel)) mux.GET(Prefix+AdminPrefix+"/types/available", serveMediaTypes(formats, true, errorChannel)) mux.GET(Prefix+AdminPrefix+"/types/enabled", serveMediaTypes(formats, false, errorChannel)) }