2023-02-09 12:16:36 +01:00
|
|
|
package http
|
|
|
|
|
|
|
|
import (
|
2023-10-19 20:05:59 +02:00
|
|
|
"context"
|
|
|
|
"io"
|
2023-02-09 12:16:36 +01:00
|
|
|
"net/http"
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
"forge.cadoles.com/arcad/edge/pkg/app"
|
|
|
|
"forge.cadoles.com/arcad/edge/pkg/bundle"
|
|
|
|
"forge.cadoles.com/arcad/edge/pkg/bus"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
|
|
"github.com/igm/sockjs-go/v3/sockjs"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
sockJSPathPrefix = "/edge/sock"
|
|
|
|
serverMainScript = "server/main.js"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Handler struct {
|
|
|
|
bundle bundle.Bundle
|
|
|
|
public http.Handler
|
|
|
|
router chi.Router
|
|
|
|
|
2023-11-28 16:35:49 +01:00
|
|
|
sockjs http.Handler
|
|
|
|
bus bus.Bus
|
|
|
|
sockjsOpts sockjs.Options
|
2023-02-09 12:16:36 +01:00
|
|
|
|
|
|
|
server *app.Server
|
|
|
|
serverModuleFactories []app.ServerModuleFactory
|
|
|
|
|
2023-04-02 17:59:33 +02:00
|
|
|
httpClient *http.Client
|
|
|
|
|
2023-02-09 12:16:36 +01:00
|
|
|
mutex sync.RWMutex
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
|
|
h.router.ServeHTTP(w, r)
|
|
|
|
}
|
|
|
|
|
2023-10-19 20:05:59 +02:00
|
|
|
func (h *Handler) Load(ctx context.Context, bdle bundle.Bundle) error {
|
2023-02-09 12:16:36 +01:00
|
|
|
h.mutex.Lock()
|
|
|
|
defer h.mutex.Unlock()
|
|
|
|
|
|
|
|
file, _, err := bdle.File(serverMainScript)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "could not open server main script")
|
|
|
|
}
|
|
|
|
|
2023-10-19 20:05:59 +02:00
|
|
|
mainScript, err := io.ReadAll(file)
|
2023-02-09 12:16:36 +01:00
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "could not read server main script")
|
|
|
|
}
|
|
|
|
|
|
|
|
server := app.NewServer(h.serverModuleFactories...)
|
|
|
|
|
|
|
|
fs := bundle.NewFileSystem("public", bdle)
|
2023-03-01 14:39:36 +01:00
|
|
|
public := HTML5Fileserver(fs)
|
2023-02-09 12:16:36 +01:00
|
|
|
sockjs := sockjs.NewHandler(sockJSPathPrefix, h.sockjsOpts, h.handleSockJSSession)
|
|
|
|
|
|
|
|
if h.server != nil {
|
|
|
|
h.server.Stop()
|
|
|
|
}
|
|
|
|
|
2023-11-28 16:35:49 +01:00
|
|
|
if err := server.Start(ctx, serverMainScript, string(mainScript)); err != nil {
|
2023-02-09 12:16:36 +01:00
|
|
|
return errors.WithStack(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
h.bundle = bdle
|
|
|
|
h.server = server
|
|
|
|
h.public = public
|
|
|
|
h.sockjs = sockjs
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewHandler(funcs ...HandlerOptionFunc) *Handler {
|
|
|
|
opts := defaultHandlerOptions()
|
|
|
|
for _, fn := range funcs {
|
|
|
|
fn(opts)
|
|
|
|
}
|
|
|
|
|
|
|
|
router := chi.NewRouter()
|
|
|
|
|
|
|
|
handler := &Handler{
|
|
|
|
sockjsOpts: opts.SockJS,
|
|
|
|
router: router,
|
|
|
|
serverModuleFactories: opts.ServerModuleFactories,
|
2023-04-02 17:59:33 +02:00
|
|
|
httpClient: opts.HTTPClient,
|
2023-02-09 12:16:36 +01:00
|
|
|
bus: opts.Bus,
|
|
|
|
}
|
|
|
|
|
2023-09-20 17:23:53 +02:00
|
|
|
for _, middleware := range opts.HTTPMiddlewares {
|
|
|
|
router.Use(middleware)
|
|
|
|
}
|
|
|
|
|
2023-02-09 12:16:36 +01:00
|
|
|
router.Route("/edge", func(r chi.Router) {
|
|
|
|
r.Route("/sdk", func(r chi.Router) {
|
|
|
|
r.Get("/client.js", handler.handleSDKClient)
|
|
|
|
r.Get("/client.js.map", handler.handleSDKClientMap)
|
|
|
|
})
|
|
|
|
|
2023-11-28 16:35:49 +01:00
|
|
|
r.Group(func(r chi.Router) {
|
|
|
|
r.Use(handler.contextMiddleware)
|
|
|
|
for _, fn := range opts.HTTPMounts {
|
|
|
|
r.Group(func(r chi.Router) {
|
|
|
|
fn(r)
|
|
|
|
})
|
|
|
|
}
|
2023-02-09 12:16:36 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
r.HandleFunc("/sock/*", handler.handleSockJS)
|
|
|
|
})
|
|
|
|
|
|
|
|
router.Get("/*", handler.handleAppFiles)
|
|
|
|
|
|
|
|
return handler
|
|
|
|
}
|