Files
hakurei/cmd/pkgserver/main.go

124 lines
2.9 KiB
Go

package main
import (
"context"
"embed"
"fmt"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"hakurei.app/command"
"hakurei.app/container/check"
"hakurei.app/internal/pkg"
"hakurei.app/internal/rosa"
"hakurei.app/message"
)
//go:generate sh -c "sass ui/static/dark.scss ui/static/dark.css && sass ui/static/light.scss ui/static/light.css && tsc ui/static/index.ts"
//go:embed ui/*
var content embed.FS
func serveWebUI(w http.ResponseWriter, r *http.Request) {
fmt.Printf("serveWebUI: %s\n", r.URL.Path)
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
w.Header().Set("Pragma", "no-cache")
w.Header().Set("Expires", "0")
w.Header().Set("X-Content-Type-Options", "nosniff")
w.Header().Set("X-XSS-Protection", "1")
w.Header().Set("X-Frame-Options", "DENY")
http.ServeFileFS(w, r, content, "ui/index.html")
}
func serveStaticContent(w http.ResponseWriter, r *http.Request) {
fmt.Printf("serveStaticContent: %s\n", r.URL.Path)
switch r.URL.Path {
case "/static/style.css":
darkTheme := r.CookiesNamed("dark_theme")
if len(darkTheme) > 0 && darkTheme[0].Value == "true" {
http.ServeFileFS(w, r, content, "ui/static/dark.css")
} else {
http.ServeFileFS(w, r, content, "ui/static/light.css")
}
break
case "/favicon.ico":
http.ServeFileFS(w, r, content, "ui/static/favicon.ico")
break
case "/static/index.js":
http.ServeFileFS(w, r, content, "ui/static/index.js")
break
default:
http.NotFound(w, r)
}
}
func serveAPI(pi *PackageIndex) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {}
}
type SortOrders int
const (
NameAscending SortOrders = iota
NameDescending
)
type PackageIndex struct {
sorts [][]*pkg.Artifact
}
func createPackageIndex(cache *pkg.Cache, report *rosa.Report) *PackageIndex {
return &PackageIndex{}
}
func main() {
log.SetFlags(0)
log.SetPrefix("pkgserver: ")
var (
flagBaseDir string
flagPort uint16
)
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
defer stop()
msg := message.New(log.Default())
c := command.New(os.Stderr, log.Printf, "pkgserver", func(args []string) error {
reportPath := args[0]
baseDir, err := check.NewAbs(flagBaseDir)
if err != nil {
return err
}
cache, err := pkg.Open(ctx, msg, 0, baseDir)
if err != nil {
return err
}
report, err := rosa.OpenReport(reportPath)
if err != nil {
return err
}
pi := createPackageIndex(cache, report)
http.HandleFunc("GET /{$}", serveWebUI)
http.HandleFunc("GET /favicon.ico", serveStaticContent)
http.HandleFunc("GET /static/", serveStaticContent)
http.HandleFunc("GET /api/", serveAPI(pi))
http.ListenAndServe(fmt.Sprintf(":%d", flagPort), nil)
return nil
}).Flag(
&flagBaseDir,
"b", command.StringFlag(""),
"base directory for cache",
).Flag(
&flagPort,
"p", command.IntFlag(8067),
"http listen port",
)
c.MustParse(os.Args[1:], func(e error) {
log.Fatal(e)
})
}