package http import ( "io/ioutil" "net/http" "strings" "sync" "forge.cadoles.com/arcad/edge/pkg/app" "forge.cadoles.com/arcad/edge/pkg/bundle" "forge.cadoles.com/arcad/edge/pkg/bus" "forge.cadoles.com/arcad/edge/pkg/sdk" "github.com/igm/sockjs-go/v3/sockjs" "github.com/pkg/errors" ) const ( sockJSPathPrefix = "/sock" clientJSPath = "/client.js" serverMainScript = "server/main.js" ) type Handler struct { bundle bundle.Bundle public http.Handler sockjs http.Handler bus bus.Bus sockjsOpts sockjs.Options server *app.Server serverModuleFactories []app.ServerModuleFactory mutex sync.RWMutex } func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { h.mutex.RLock() defer h.mutex.RUnlock() switch { case r.URL.Path == clientJSPath: serveFile(w, r, &sdk.FS, "client/dist/client.js") case r.URL.Path == clientJSPath+".map": serveFile(w, r, &sdk.FS, "client/dist/client.js.map") case strings.HasPrefix(r.URL.Path, sockJSPathPrefix): h.sockjs.ServeHTTP(w, r) default: h.public.ServeHTTP(w, r) } } func (h *Handler) Load(bdle bundle.Bundle) error { 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") } mainScript, err := ioutil.ReadAll(file) if err != nil { return errors.Wrap(err, "could not read server main script") } server := app.NewServer(h.serverModuleFactories...) if err := server.Load(serverMainScript, string(mainScript)); err != nil { return errors.WithStack(err) } fs := bundle.NewFileSystem("public", bdle) public := http.FileServer(fs) sockjs := sockjs.NewHandler(sockJSPathPrefix, h.sockjsOpts, h.handleSockJSSession) if h.server != nil { h.server.Stop() } if err := server.Start(); err != nil { 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) } handler := &Handler{ sockjsOpts: opts.SockJS, serverModuleFactories: opts.ServerModuleFactories, bus: opts.Bus, } return handler }