accounting/pkg/frontend/frontend.go

79 lines
1.9 KiB
Go

// Package frontend contains compiled frontend assets and a registration
// for the HTTP listeners
package frontend
import (
"embed"
"errors"
"fmt"
"io"
"io/fs"
"mime"
"net/http"
"path"
"github.com/gorilla/mux"
"github.com/sirupsen/logrus"
)
type (
frontendServer struct {
router *mux.Router
log *logrus.Logger
}
)
//go:embed assets/*
var assets embed.FS
// RegisterHandler takes a Router and registers the frontend onto that
// router
func RegisterHandler(router *mux.Router, logger *logrus.Logger) {
srv := frontendServer{router, logger}
router.
PathPrefix("/assets").
Handler(http.StripPrefix("/assets", http.HandlerFunc(srv.handleAsset))).
Methods(http.MethodGet)
router.NotFoundHandler = http.HandlerFunc(srv.handleIndex)
}
func (f frontendServer) handleAsset(w http.ResponseWriter, r *http.Request) {
asset, err := assets.Open(path.Join("assets", r.URL.Path))
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
http.Error(w, "that's not the file you're looking for", http.StatusNotFound)
return
}
http.Error(w, fmt.Sprintf("opening asset: %s", err), http.StatusInternalServerError)
return
}
defer func() {
if err := asset.Close(); err != nil {
f.log.WithError(err).Error("closing assets file (leaked fd)")
}
}()
w.Header().Set("Content-Type", mime.TypeByExtension(path.Ext(r.URL.Path)))
if _, err = io.Copy(w, asset); err != nil {
f.log.WithError(err).Debug("copying index to browser")
}
}
func (f frontendServer) handleIndex(w http.ResponseWriter, _ *http.Request) {
index, err := assets.Open("assets/index.html")
if err != nil {
http.Error(w, fmt.Sprintf("opening index: %s", err), http.StatusInternalServerError)
return
}
defer func() {
if err := index.Close(); err != nil {
f.log.WithError(err).Error("closing assets file (leaked fd)")
}
}()
if _, err = io.Copy(w, index); err != nil {
f.log.WithError(err).Debug("copying index to browser")
}
}