|
|
|
package dev
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"log"
|
|
|
|
"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"
|
|
|
|
|
|
|
|
"github.com/alecthomas/repr"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
|
|
)
|
|
|
|
|
|
|
|
// 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)
|
|
|
|
}
|
|
|
|
|
|
|
|
func UseRoutesMetadata(l *sl.ServiceLocator) map[string]any {
|
|
|
|
dev, err := sl.Use(l, slot)
|
|
|
|
if err != nil {
|
|
|
|
log.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{},
|
|
|
|
}
|
|
|
|
|
|
|
|
r, err := sl.Use(l, routes.Root)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
r.Post("/api/development/render", func(c *fiber.Ctx) error {
|
|
|
|
var data struct {
|
|
|
|
Route string `json:"route"`
|
|
|
|
Page 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
|
|
|
|
}
|
|
|
|
|
|
|
|
repr.Print(data)
|
|
|
|
|
|
|
|
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.Page),
|
|
|
|
data.Request.ParamsMap,
|
|
|
|
data.Request.QueryMap,
|
|
|
|
}); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return c.JSON(buf.String())
|
|
|
|
})
|
|
|
|
|
|
|
|
return d, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// RegisterRoute will register the provided "mountPoint" to the "frontendHtml" page
|
|
|
|
func RegisterRoute(l *sl.ServiceLocator, mountPoint, frontendFile string) {
|
|
|
|
log.Printf(`registering vite route %q for %q`, frontendFile, mountPoint)
|
|
|
|
|
|
|
|
dev, err := sl.Use(l, slot)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
dev.staticRoutes[mountPoint] = frontendFile
|
|
|
|
log.Print(dev)
|
|
|
|
}
|
|
|
|
|
|
|
|
func RegisterDynamicRoute(l *sl.ServiceLocator, mountPoint, frontendFile string, handler Handler) {
|
|
|
|
log.Printf(`registering vite route %q for %q`, frontendFile, mountPoint)
|
|
|
|
|
|
|
|
dev, err := sl.Use(l, slot)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
dev.dynamicRoutes[mountPoint] = frontendFile
|
|
|
|
dev.dynamicRoutesHandlers[mountPoint] = handler
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetArtifactPath(frontendFile string) string {
|
|
|
|
return path.Join("./out/frontend/", frontendFile)
|
|
|
|
}
|