/* Copyright © 2023 Seednode */ package cmd import ( "encoding/json" "fmt" "io" "net/http" "sort" "strconv" "strings" "time" "github.com/julienschmidt/httprouter" "github.com/yosssi/gohtml" "seedno.de/seednode/roulette/types" ) func paginate(page int, fileCount int, ending bool) string { var html strings.Builder var firstPage int = 1 var lastPage int if fileCount%PageLength == 0 { lastPage = fileCount / PageLength } else { lastPage = (fileCount / PageLength) + 1 } var prevStatus, nextStatus string = "", "" if page <= 1 { prevStatus = " disabled" } if page >= lastPage { nextStatus = " disabled" } prevPage := page - 1 if prevPage < 1 { prevPage = 1 } nextPage := page + 1 if nextPage > lastPage { nextPage = fileCount / PageLength } if ending { html.WriteString("") } else { html.WriteString("") } html.WriteString(fmt.Sprintf("", firstPage)) html.WriteString(fmt.Sprintf("", prevPage, prevStatus)) html.WriteString(fmt.Sprintf("", nextPage, nextStatus)) html.WriteString(fmt.Sprintf("", lastPage)) html.WriteString("\n") return html.String() } func serveIndexHtml(args []string, index *fileIndex, shouldPaginate bool) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { w.Header().Set("Content-Type", "text/html") startTime := time.Now() indexDump := index.List() fileCount := len(indexDump) var startIndex, stopIndex int page, err := strconv.Atoi(p.ByName("page")) if err != nil || page <= 0 { startIndex = 0 stopIndex = fileCount } else { startIndex = ((page - 1) * PageLength) stopIndex = (startIndex + PageLength) } if startIndex > (fileCount - 1) { indexDump = []string{} } if stopIndex > fileCount { stopIndex = fileCount } sort.SliceStable(indexDump, func(p, q int) bool { return strings.ToLower(indexDump[p]) < strings.ToLower(indexDump[q]) }) var htmlBody strings.Builder htmlBody.WriteString(``) htmlBody.WriteString(faviconHtml) htmlBody.WriteString(``) htmlBody.WriteString(fmt.Sprintf("Index contains %d files", fileCount)) if shouldPaginate { htmlBody.WriteString(paginate(page, fileCount, false)) } if len(indexDump) > 0 { for _, v := range indexDump[startIndex:stopIndex] { var shouldSort = "" if Sorting { shouldSort = "?sort=asc" } htmlBody.WriteString(fmt.Sprintf("\n", Prefix, mediaPrefix, v, shouldSort, v)) } } if shouldPaginate { htmlBody.WriteString(paginate(page, fileCount, true)) } htmlBody.WriteString(`
%s
`) b, err := io.WriteString(w, gohtml.Format(htmlBody.String())) if err != nil { return } if Verbose { fmt.Printf("%s | SERVE: HTML index page (%s) to %s in %s\n", startTime.Format(logDate), humanReadableSize(b), realIP(r), time.Since(startTime).Round(time.Microsecond), ) } } } func serveIndexJson(args []string, index *fileIndex, errorChannel chan<- error) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { w.Header().Set("Content-Type", "application/json") startTime := time.Now() indexedFiles := index.List() fileCount := len(indexedFiles) sort.SliceStable(indexedFiles, func(p, q int) bool { return strings.ToLower(indexedFiles[p]) < strings.ToLower(indexedFiles[q]) }) var startIndex, stopIndex int page, err := strconv.Atoi(p.ByName("page")) if err != nil || page <= 0 { startIndex = 0 stopIndex = fileCount } else { startIndex = ((page - 1) * PageLength) stopIndex = (startIndex + PageLength) } if startIndex > (fileCount - 1) { indexedFiles = []string{} } if stopIndex > fileCount { stopIndex = fileCount } response, err := json.MarshalIndent(indexedFiles[startIndex:stopIndex], "", " ") if err != nil { errorChannel <- err serverError(w, r, nil) return } w.Write(response) if Verbose { fmt.Printf("%s | SERVE: JSON index page (%s) to %s in %s\n", startTime.Format(logDate), humanReadableSize(len(response)), realIP(r), time.Since(startTime).Round(time.Microsecond), ) } } } func serveAvailableExtensions() httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { w.Header().Set("Content-Type", "text/plain") startTime := time.Now() response := []byte(types.SupportedFormats.GetExtensions()) w.Write(response) if Verbose { fmt.Printf("%s | SERVE: Available extension list (%s) to %s in %s\n", startTime.Format(logDate), humanReadableSize(len(response)), realIP(r), time.Since(startTime).Round(time.Microsecond), ) } } } func serveEnabledExtensions(formats *types.Types) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { w.Header().Set("Content-Type", "text/plain") startTime := time.Now() response := []byte(formats.GetExtensions()) w.Write(response) if Verbose { fmt.Printf("%s | SERVE: Registered extension list (%s) to %s in %s\n", startTime.Format(logDate), humanReadableSize(len(response)), realIP(r), time.Since(startTime).Round(time.Microsecond), ) } } } func serveAvailableMimeTypes() httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { w.Header().Set("Content-Type", "text/plain") startTime := time.Now() response := []byte(types.SupportedFormats.GetMimeTypes()) w.Write(response) if Verbose { fmt.Printf("%s | SERVE: Available MIME type list (%s) to %s in %s\n", startTime.Format(logDate), humanReadableSize(len(response)), realIP(r), time.Since(startTime).Round(time.Microsecond), ) } } } func serveEnabledMimeTypes(formats *types.Types) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { w.Header().Set("Content-Type", "text/plain") startTime := time.Now() response := []byte(formats.GetMimeTypes()) w.Write(response) if Verbose { fmt.Printf("%s | SERVE: Registered MIME type list (%s) to %s in %s\n", startTime.Format(logDate), humanReadableSize(len(response)), realIP(r), time.Since(startTime).Round(time.Microsecond), ) } } } func registerInfoHandlers(mux *httprouter.Router, args []string, index *fileIndex, formats *types.Types, errorChannel chan<- error) { if Index { registerHandler(mux, Prefix+"/html", serveIndexHtml(args, index, false)) if PageLength != 0 { registerHandler(mux, Prefix+"/html/:page", serveIndexHtml(args, index, true)) } registerHandler(mux, Prefix+"/json", serveIndexJson(args, index, errorChannel)) if PageLength != 0 { registerHandler(mux, Prefix+"/json/:page", serveIndexJson(args, index, errorChannel)) } } registerHandler(mux, Prefix+"/available_extensions", serveAvailableExtensions()) registerHandler(mux, Prefix+"/enabled_extensions", serveEnabledExtensions(formats)) registerHandler(mux, Prefix+"/available_mime_types", serveAvailableMimeTypes()) registerHandler(mux, Prefix+"/enabled_mime_types", serveEnabledMimeTypes(formats)) }