forked from security/hakurei
cmd/pkgserver: add status endpoint
This commit is contained in:
@@ -1,17 +1,20 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cmp"
|
||||
"context"
|
||||
"embed"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path"
|
||||
"slices"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unique"
|
||||
|
||||
"hakurei.app/command"
|
||||
"hakurei.app/container/check"
|
||||
@@ -57,68 +60,112 @@ func serveStaticContent(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
}
|
||||
}
|
||||
func serveAPI(pi *PackageIndex) func(w http.ResponseWriter, r *http.Request) {
|
||||
func serveAPI(index *PackageIndex) func(w http.ResponseWriter, r *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {}
|
||||
}
|
||||
|
||||
func serveStatus(index *PackageIndex) func(w http.ResponseWriter, r *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if index == nil {
|
||||
http.Error(w, "index is nil", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
base := path.Base(r.URL.Path)
|
||||
name := strings.TrimSuffix(base, ".log")
|
||||
p, ok := rosa.ResolveName(name)
|
||||
if !ok {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
m := rosa.GetMetadata(p)
|
||||
pk, ok := index.names[m.Name]
|
||||
if !ok {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
if len(pk.status) > 0 {
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, err := io.Copy(w, bytes.NewReader(pk.status))
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
} else {
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type SortOrders int
|
||||
|
||||
const (
|
||||
DeclarationDescending SortOrders = iota
|
||||
DeclarationAscending
|
||||
DeclarationAscending SortOrders = iota
|
||||
DeclarationDescending
|
||||
NameAscending
|
||||
NameDescending
|
||||
limitSortOrders
|
||||
)
|
||||
|
||||
type PackageIndex [limitSortOrders][rosa.PresetUnexportedStart]*PackageIndexEntry
|
||||
type PackageIndex struct {
|
||||
sorts [limitSortOrders][rosa.PresetUnexportedStart]*PackageIndexEntry
|
||||
names map[string]*PackageIndexEntry
|
||||
}
|
||||
|
||||
type PackageIndexEntry struct {
|
||||
id unique.Handle[pkg.ID]
|
||||
name string
|
||||
description string
|
||||
website string
|
||||
version string
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Website string `json:"website"`
|
||||
Version string `json:"version"`
|
||||
status []byte
|
||||
}
|
||||
|
||||
func createPackageIndex(cache *pkg.Cache, report *rosa.Report) *PackageIndex {
|
||||
var index PackageIndex
|
||||
var work []PackageIndexEntry
|
||||
func createPackageIndex(cache *pkg.Cache, report *rosa.Report) (_ *PackageIndex, err error) {
|
||||
index := new(PackageIndex)
|
||||
index.names = make(map[string]*PackageIndexEntry, rosa.PresetUnexportedStart)
|
||||
work := make([]PackageIndexEntry, rosa.PresetUnexportedStart)
|
||||
defer report.HandleAccess(&err)()
|
||||
for p := range rosa.PresetUnexportedStart {
|
||||
m := rosa.GetMetadata(p)
|
||||
v := rosa.Std.Version(p)
|
||||
a := rosa.Std.Load(p)
|
||||
id := cache.Ident(a)
|
||||
status, n := report.ArtifactOf(id)
|
||||
work[p] = PackageIndexEntry{
|
||||
id: id,
|
||||
name: m.Name,
|
||||
description: m.Description,
|
||||
website: m.Website,
|
||||
version: v,
|
||||
status: status[:n],
|
||||
st, n := report.ArtifactOf(id)
|
||||
var status []byte
|
||||
if n < 1 {
|
||||
status = nil
|
||||
} else {
|
||||
status = st
|
||||
}
|
||||
log.Printf("Processing package %s...\n", m.Name)
|
||||
entry := PackageIndexEntry{
|
||||
Name: m.Name,
|
||||
Description: m.Description,
|
||||
Website: m.Website,
|
||||
Version: v,
|
||||
status: status,
|
||||
}
|
||||
work[p] = entry
|
||||
index.names[m.Name] = &entry
|
||||
}
|
||||
for i, p := range work {
|
||||
index[DeclarationAscending][i] = &p
|
||||
index.sorts[DeclarationAscending][i] = &p
|
||||
}
|
||||
slices.Reverse(work)
|
||||
for i, p := range work {
|
||||
index[DeclarationDescending][i] = &p
|
||||
index.sorts[DeclarationDescending][i] = &p
|
||||
}
|
||||
slices.SortFunc(work, func(a PackageIndexEntry, b PackageIndexEntry) int {
|
||||
return cmp.Compare(a.name, b.name)
|
||||
return cmp.Compare(a.Name, b.Name)
|
||||
})
|
||||
for i, p := range work {
|
||||
index[NameAscending][i] = &p
|
||||
index.sorts[NameAscending][i] = &p
|
||||
}
|
||||
slices.Reverse(work)
|
||||
for i, p := range work {
|
||||
index[NameDescending][i] = &p
|
||||
index.sorts[NameDescending][i] = &p
|
||||
}
|
||||
|
||||
return &index
|
||||
return index, err
|
||||
}
|
||||
func main() {
|
||||
log.SetFlags(0)
|
||||
@@ -126,7 +173,7 @@ func main() {
|
||||
|
||||
var (
|
||||
flagBaseDir string
|
||||
flagPort uint16
|
||||
flagPort int
|
||||
)
|
||||
|
||||
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
|
||||
@@ -139,6 +186,7 @@ func main() {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Println("baseDir:", baseDir)
|
||||
cache, err := pkg.Open(ctx, msg, 0, baseDir)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -147,12 +195,19 @@ func main() {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer report.HandleAccess(&err)()
|
||||
index := createPackageIndex(cache, report)
|
||||
log.Println("reportPath:", reportPath)
|
||||
log.Println("indexing packages...")
|
||||
index, err := createPackageIndex(cache, report)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Println("created package index")
|
||||
http.HandleFunc("GET /{$}", serveWebUI)
|
||||
http.HandleFunc("GET /favicon.ico", serveStaticContent)
|
||||
http.HandleFunc("GET /static/", serveStaticContent)
|
||||
http.HandleFunc("GET /api/", serveAPI(index))
|
||||
http.HandleFunc("GET /api/status/", serveStatus(index))
|
||||
log.Println("listening on", flagPort)
|
||||
err = http.ListenAndServe(fmt.Sprintf(":%d", flagPort), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
Reference in New Issue
Block a user