Session serialization will use gob encoding instead of json. Binary size will likely be reduced. General backend code refactoring.
94 lines
1.8 KiB
Go
94 lines
1.8 KiB
Go
package middlewares
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"io/fs"
|
|
"mime"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
type SpaHandler struct {
|
|
Entrypoint string
|
|
Filesystem fs.FS
|
|
routes []string
|
|
}
|
|
|
|
func NewSpaHandler(index string, fs fs.FS) *SpaHandler {
|
|
return &SpaHandler{
|
|
Entrypoint: index,
|
|
Filesystem: fs,
|
|
}
|
|
}
|
|
|
|
func (s *SpaHandler) AddClientRoute(route string) *SpaHandler {
|
|
s.routes = append(s.routes, route)
|
|
return s
|
|
}
|
|
|
|
// Handler for serving a compiled react frontend
|
|
// each client-side routes must be provided
|
|
func (s *SpaHandler) Handler() http.HandlerFunc {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodGet {
|
|
http.Error(
|
|
w,
|
|
http.StatusText(http.StatusMethodNotAllowed),
|
|
http.StatusMethodNotAllowed,
|
|
)
|
|
return
|
|
}
|
|
|
|
path := filepath.Clean(r.URL.Path)
|
|
|
|
// basically all frontend routes are needed :/
|
|
hasRoute := false
|
|
for _, route := range s.routes {
|
|
hasRoute = strings.HasPrefix(path, route)
|
|
if hasRoute {
|
|
break
|
|
}
|
|
}
|
|
|
|
if path == "/" || hasRoute {
|
|
path = s.Entrypoint
|
|
}
|
|
|
|
path = strings.TrimPrefix(path, "/")
|
|
|
|
file, err := s.Filesystem.Open(path)
|
|
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
http.NotFound(w, r)
|
|
return
|
|
}
|
|
http.Error(
|
|
w,
|
|
http.StatusText(http.StatusInternalServerError),
|
|
http.StatusInternalServerError,
|
|
)
|
|
return
|
|
}
|
|
|
|
contentType := mime.TypeByExtension(filepath.Ext(path))
|
|
w.Header().Set("Content-Type", contentType)
|
|
|
|
if strings.HasPrefix(path, "assets/") {
|
|
w.Header().Set("Cache-Control", "public, max-age=2592000")
|
|
}
|
|
|
|
stat, err := file.Stat()
|
|
if err == nil && stat.Size() > 0 {
|
|
w.Header().Set("Content-Length", fmt.Sprintf("%d", stat.Size()))
|
|
}
|
|
|
|
w.WriteHeader(http.StatusOK)
|
|
|
|
io.Copy(w, file)
|
|
})
|
|
}
|