package web import ( "errors" "git.timovolkmann.de/gyrogpsc/core" "github.com/gofiber/fiber/v2" "github.com/gofiber/template/html" "github.com/gofiber/websocket/v2" "github.com/sirupsen/logrus" ) func CreateServer(s core.Service, sub core.Subscriber, c *core.Configuration) { app := fiber.New(fiber.Config{ Views: fiberTemplateEngine(c), }) app.Static("/static", "static") // Application Main Page app.Get("/", fiberHomeHandler) // Websocket app.Get("/ws", websocket.New(createFiberWebsocketHandler(sub))) // TODO: Get all SerialPorts // app.Get("/serialports") // Tracking persistence controls HTTP JSON RPC API trackings := app.Group("/trackings") trackings.Get("/", allTrackingsHandler(s, c)) // Get all trackings Metadata trackings.Post("/", startPipelineHandler(s, c)) // Initialize new tracking, open websocket and prepare for automatic recording. Toggle ?serial=true and ?tcp=true. Returns trackingId trackings.Patch("/", startRecordingHandler(s, c)) // Starts recording trackings.Put("/", stopRecordingHandler(s, c)) // Stops current recording. Returns trackingId if record was successful trackings.Delete("/", stopAllHandler(s, c)) // Stops websocket connection, pipelines and collectors trackings.Get("/:trackingId", stubhander()) // Gets Tracking Metadata and loads sensorRecords from storage. trackings.Delete("/:trackingId", stubhander()) // Deletes Tracking from storage trackings.Post("/current", stubhander()) // Starts Replay. trackings.Patch("/current", stubhander()) // Pauses Replay. trackings.Put("/current", stubhander()) // Stops Replay. logrus.Fatal(app.Listen(c.Webserver.Port)) } func stubhander() fiber.Handler { return func(ctx *fiber.Ctx) error { return nil } } func allTrackingsHandler(s core.Service, c *core.Configuration) fiber.Handler { return func(ctx *fiber.Ctx) error { trackings, err := s.AllTrackings() if err != nil { //ctx.Status(500).JSON(err) //return err } prepres := map[string]interface{}{} prepres["data"] = trackings if err != nil { prepres["error"] = err.Error() } err2 := ctx.JSON(prepres) if err2 != nil { ctx.Status(500).JSON(err2) return err2 } return nil } } func startPipelineHandler(s core.Service, c *core.Configuration) fiber.Handler { return func(ctx *fiber.Ctx) error { var collecs []core.CollectorType ser := ctx.Query("serial", "true") if ser == "true" { collecs = append(collecs, core.SERIAL) } else if ser != "false" && ser != "" { collecs = append(collecs, core.CollectorType(ser)) // TODO: allow passing serial port as url parameter } tcp := ctx.Query("tcp", "true") logrus.Debugln("query values: serial/tcp", ser, tcp) if tcp == "true" { collecs = append(collecs, core.TCP) } res, err := s.StartPipeline(collecs...) if err != nil { //ctx.Status(500).JSON(err) //return err } prepres := map[string]interface{}{} prepres["tracking_state"] = res prepres["data"] = collecs if err != nil { prepres["error"] = err.Error() } if len(collecs) == 0 { e := errors.New("attention! no collectors running. start a new pipeline") prepres["error"] = e.Error() } err2 := ctx.JSON(prepres) if err2 != nil { ctx.Status(500).JSON(err2) return err2 } return nil } } func startRecordingHandler(s core.Service, c *core.Configuration) fiber.Handler { return func(ctx *fiber.Ctx) error { rec, err := s.StartRecord() if err != nil { //ctx.Status(500).JSON(err) //return err } prepres := map[string]interface{}{} prepres["tracking_state"] = "RECORD" prepres["data"] = rec if err != nil { prepres["error"] = err.Error() } err2 := ctx.JSON(prepres) if err2 != nil { ctx.Status(500).JSON(err2) return err2 } return nil } } func stopRecordingHandler(s core.Service, c *core.Configuration) fiber.Handler { return func(ctx *fiber.Ctx) error { rec, err := s.StopRecord() if err != nil { //ctx.Status(500).JSON(err) //return err } prepres := map[string]interface{}{} prepres["tracking_state"] = "LIVE" prepres["data"] = rec if err != nil { prepres["error"] = err.Error() } err2 := ctx.JSON(prepres) if err2 != nil { ctx.Status(500).JSON(err2) return err2 } return nil } } func stopAllHandler(s core.Service, c *core.Configuration) fiber.Handler { return func(ctx *fiber.Ctx) error { rec, err := s.StopAll() if err != nil { //ctx.Status(500).JSON(err) //return err } prepres := map[string]interface{}{} prepres["tracking_state"] = "STOPPED" prepres["data"] = rec if err != nil { prepres["error"] = err.Error() } err2 := ctx.JSON(prepres) if err2 != nil { ctx.Status(500).JSON(err2) return err2 } return nil } } func createFiberWebsocketHandler(s core.Subscriber) func(conn *websocket.Conn) { return func(c *websocket.Conn) { logrus.Info("new websocket client") // Handle and discard inbound messages go func() { for { if _, _, err := c.NextReader(); err != nil { c.Close() break } } }() dispatcherId, channel := s.Subscribe() defer s.Unsubscribe(dispatcherId) for { cmsg := <-channel err := c.WriteMessage(websocket.TextMessage, []byte(cmsg)) if err != nil { logrus.Info("close websocket connection") c.Close() break } } } } func fiberTemplateEngine(c *core.Configuration) *html.Engine { // Create a new engine by passing the template folder // and template extension using .New(dir, ext string) engine := html.New("./templates", ".html") // We also support the http.FileSystem interface // See examples below to load templates from embedded files // engine := html.NewFileSystem(http.Dir("./views"), ".html") // Reload the templates on each render, good for development //engine.Reload(strings.ToLower(c.Debuglevel) == "debug") // Optional. Default: false engine.Reload(true) // Optional. Default: false // Debug will print each template that is parsed, good for debugging //engine.Debug(strings.ToLower(c.Debuglevel) == "debug") // Optional. Default: false engine.Debug(true) // Optional. Default: false // Layout defines the variable name that is used to yield templates within layouts //engine.Layout("embed") // Optional. Default: "embed" // Delims sets the action delimiters to the specified strings //engine.Delims("{{", "}}") // Optional. Default: engine delimiters // AddFunc adds a function to the template's global function map. //engine.AddFunc("greet", func(name string) string { // return "Hello, " + name + "!" //}) return engine } func fiberHomeHandler(c *fiber.Ctx) error { // Render index template return c.Render("index", "ws://"+c.Hostname()+"/ws") }