unify frontends
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
2024-01-01 20:38:42 -05:00
parent c2ac67aa07
commit 382d3bab61
8 changed files with 48 additions and 598 deletions

View File

@@ -11,21 +11,17 @@ import (
)
type Router struct {
static fs.FS
lib Library
rcol RecordCollection
static fs.FS
lib Library
rcol RecordCollection
ts *tailscale.LocalClient
isAdmin bool
}
type AdminRouter struct {
static fs.FS
lib Library
ts *tailscale.LocalClient
}
type path map[string]func()
type handler map[string]func()
func (h handler) Handle(w http.ResponseWriter, req *http.Request) {
if f, ok := h[req.Method]; ok {
func (h path) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if f, ok := h[r.Method]; ok {
f()
return
}
@@ -50,31 +46,33 @@ func writeJSON(w http.ResponseWriter, b any, status int) {
func (router *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/api/records":
handler{
http.MethodGet: func() { getRecords(router.rcol, w, r) },
}.Handle(w, r)
case "/api/books":
handler{
http.MethodGet: func() { getBooks(router.lib, w, r) },
}.Handle(w, r)
default:
static(router.static).ServeHTTP(w, r)
}
}
func (router *AdminRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/api/mode":
path{
http.MethodGet: func() {
writeJSON(w, struct{ Admin bool }{Admin: router.isAdmin}, http.StatusOK)
},
}.ServeHTTP(w, r)
case "/api/whoami":
handler{
if !router.isAdmin {
http.NotFoundHandler().ServeHTTP(w, r)
return
}
path{
http.MethodGet: func() { getWhoAmI(router.ts, w, r) },
}.Handle(w, r)
}.ServeHTTP(w, r)
case "/api/records":
path{
http.MethodGet: func() { getRecords(router.rcol, w, r) },
}.ServeHTTP(w, r)
case "/api/books":
handler{
http.MethodGet: func() { getBooks(router.lib, w, r) },
http.MethodPost: func() { addBook(router.lib, w, r) },
http.MethodDelete: func() { deleteBook(router.lib, w, r) },
}.Handle(w, r)
p := path{
http.MethodGet: func() { getBooks(router.lib, w, r) },
}
if router.isAdmin {
p[http.MethodPost] = func() { addBook(router.lib, w, r) }
p[http.MethodDelete] = func() { deleteBook(router.lib, w, r) }
}
p.ServeHTTP(w, r)
default:
static(router.static).ServeHTTP(w, r)
}

View File

@@ -55,24 +55,26 @@ func main() {
c.DiscogsToken, time.Hour*24, c.DiscogsUser, c.DiscogsPersist, c.DiscogsCacheFile,
))
frontendRoot := must.Get(frontend.Root())
adminRoot := must.Get(frontend.AdminRoot())
staticRoot := must.Get(frontend.Root())
servers := make(chan (*http.Server), 3)
errGroup := errgroup.Group{}
errGroup.Go(func() error {
return start(servers)(
publicServer(8080, &Router{
static: frontendRoot,
lib: lib,
rcol: discogsCache,
static: staticRoot,
lib: lib,
rcol: discogsCache,
isAdmin: false,
}))
})
errGroup.Go(func() error {
return start(servers)(
tailscaleListener("library-admin", &AdminRouter{
static: adminRoot,
lib: lib,
tailscaleListener("library-admin", &Router{
static: staticRoot,
lib: lib,
rcol: discogsCache,
isAdmin: true,
}))
})
errGroup.Go(func() error {
@@ -143,10 +145,15 @@ func publicServer(port int, handler http.Handler) (*http.Server, net.Listener, e
return server, ln, nil
}
func tailscaleListener(hostname string, handler *AdminRouter) (*http.Server, net.Listener, error) {
func tailscaleListener(hostname string, handler *Router) (*http.Server, net.Listener, error) {
s := &tsnet.Server{
Dir: ".config/" + hostname,
Hostname: hostname,
Logf: func(s string, a ...any) { // silence most tsnet logs
if strings.HasPrefix(s, "To start this tsnet server") {
log.Printf(s, a...)
}
},
}
ln, err := s.Listen("tcp", ":80")
if err != nil {