You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
website/services/server/dev/dev.go

170 lines
3.8 KiB
Go

2 years ago
package dev
import (
"bytes"
"fmt"
"io"
2 years ago
"log"
"os"
2 years ago
"path"
"git.phc.dm.unipi.it/phc/website/services/config"
"git.phc.dm.unipi.it/phc/website/services/server/routes"
"git.phc.dm.unipi.it/phc/website/sl"
2 years ago
"github.com/alecthomas/repr"
2 years ago
"github.com/gofiber/fiber/v2"
)
// Logger is the debug logger, in the future this will be disabled and discard by default.
var Logger *log.Logger = log.New(os.Stderr, "[services/server/dev] ", log.Lmsgprefix)
// slot represents a private "write only" service
var slot = sl.NewSlot[*devService]()
// InjectInto a [*sl.ServiceLocator] an instance of the dev service
func InjectInto(l *sl.ServiceLocator) {
sl.InjectLazy(l, slot, Configure)
2 years ago
}
func UseRoutesMetadata(l *sl.ServiceLocator) map[string]any {
dev, err := sl.Use(l, slot)
if err != nil {
Logger.Fatal(err)
}
return map[string]any{
"static": dev.staticRoutes,
"dynamic": dev.dynamicRoutes,
}
}
type Request interface {
Page() []byte
Param(key string) string
Query(key string) string
}
type ResponseWriter interface {
io.Writer
}
// devServerRequest is used when handling request from the dev server where params and queries are parsed by express
type devServerRequest struct {
page []byte
params map[string]string
query map[string]string
}
func (r devServerRequest) Page() []byte {
return r.page
}
func (r devServerRequest) Param(key string) string {
return r.params[key]
}
func (r devServerRequest) Query(key string) string {
return r.query[key]
}
// Handler is a custom routes handler
type Handler func(ResponseWriter, Request) error
type devService struct {
staticRoutes map[string]string
dynamicRoutes map[string]string
dynamicRoutesHandlers map[string]Handler
}
func Configure(l *sl.ServiceLocator) (*devService, error) {
d := &devService{
map[string]string{},
map[string]string{},
map[string]Handler{},
}
2 years ago
r, err := sl.Use(l, routes.Root)
2 years ago
if err != nil {
return nil, err
2 years ago
}
config, _ := sl.Use(l, config.Slot)
if config.Mode != "development" {
return d, nil
}
r.Get("/api/development/routes", func(c *fiber.Ctx) error {
return c.JSON(map[string]any{
"static": d.staticRoutes,
"dynamic": d.dynamicRoutes,
})
2 years ago
})
r.Post("/api/development/render", func(c *fiber.Ctx) error {
var data struct {
Route string `json:"route"`
HtmlPage string `json:"page"`
Request struct {
ParamsMap map[string]string `json:"params"`
QueryMap map[string]string `json:"query"`
} `json:"request"`
}
if err := c.BodyParser(&data); err != nil {
return err
}
Logger.Printf(`server rendering route "%s"`, data.Route)
Logger.Printf(`- params: %s`, repr.String(data.Request.ParamsMap))
Logger.Printf(`- query: %s`, repr.String(data.Request.QueryMap))
handler, ok := d.dynamicRoutesHandlers[data.Route]
if !ok {
return fmt.Errorf(`no handler for "%s"`, data.Route)
}
var buf bytes.Buffer
if err := handler(&buf, devServerRequest{
[]byte(data.HtmlPage),
data.Request.ParamsMap,
data.Request.QueryMap,
}); err != nil {
return err
}
return c.JSON(buf.String())
})
return d, nil
2 years ago
}
// RegisterRoute will register the provided "mountPoint" to the "frontendHtml" page
func RegisterRoute(l *sl.ServiceLocator, mountPoint, frontendFile string) {
dev, err := sl.Use(l, slot)
2 years ago
if err != nil {
Logger.Fatal(err)
2 years ago
}
dev.staticRoutes[mountPoint] = frontendFile
Logger.Printf(`registered vite route "%v" for "%v"`, frontendFile, mountPoint)
}
2 years ago
func RegisterDynamicRoute(l *sl.ServiceLocator, mountPoint, frontendFile string, handler Handler) {
dev, err := sl.Use(l, slot)
if err != nil {
Logger.Fatal(err)
2 years ago
}
dev.dynamicRoutes[mountPoint] = frontendFile
dev.dynamicRoutesHandlers[mountPoint] = handler
Logger.Printf(`registered vite route "%v" for "%v"`, frontendFile, mountPoint)
}
func GetArtifactPath(frontendFile string) string {
return path.Join("./out/frontend/", frontendFile)
2 years ago
}