259 lines
7.2 KiB
Go
259 lines
7.2 KiB
Go
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/google/uuid"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
func CreateServer(s *core.TrackingService, sub core.Subscriber, c *core.Configuration) {
|
|
app := fiber.New(fiber.Config{
|
|
Views: fiberTemplateEngine(c),
|
|
})
|
|
app.Static("/static", "static")
|
|
|
|
// Application Main Page
|
|
app.Get("/", fiberHomeHandler)
|
|
app.Get("/tracking", fiberTrackingHandler)
|
|
|
|
// Websocket
|
|
app.Get("/ws", websocket.New(createFiberWebsocketHandler(sub)))
|
|
|
|
// 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", LoadTrackingHandler(s, c)) // Gets Tracking Metadata and loads sensorRecords from storage.
|
|
|
|
logrus.Fatal(app.Listen(c.Webserver.Port))
|
|
}
|
|
|
|
func LoadTrackingHandler(s *core.TrackingService, c *core.Configuration) fiber.Handler {
|
|
return func(ctx *fiber.Ctx) error {
|
|
trackId := ctx.Params("trackingId")
|
|
uid, err := uuid.Parse(trackId)
|
|
if err != nil {
|
|
logrus.Error(err)
|
|
ctx.Status(404).JSON(err)
|
|
return err
|
|
}
|
|
var replay bool
|
|
if ctx.Query("replay", "false") == "true" {
|
|
replay = true
|
|
} else {
|
|
replay = false
|
|
}
|
|
tracking, err := s.LoadTracking(uid, replay)
|
|
if err != nil {
|
|
logrus.Error(err)
|
|
ctx.Status(404).JSON(err)
|
|
return err
|
|
}
|
|
st := struct {
|
|
core.TrackingMetadata
|
|
Data map[string][]core.SensorData
|
|
}{}
|
|
st.TrackingMetadata = tracking.TrackingMetadata
|
|
st.Data = make(map[string][]core.SensorData)
|
|
for _, el := range tracking.Data {
|
|
st.Data[string(el.Source())] = append(st.Data[string(el.Source())], el)
|
|
}
|
|
prepres := make(map[string]interface{})
|
|
prepres["data"] = st
|
|
|
|
err2 := ctx.JSON(prepres)
|
|
if err2 != nil {
|
|
ctx.Status(500).JSON(err2)
|
|
return err2
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
func allTrackingsHandler(s *core.TrackingService, c *core.Configuration) fiber.Handler {
|
|
return func(ctx *fiber.Ctx) error {
|
|
trackings, err := s.AllTrackings()
|
|
|
|
prepres := make(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.TrackingService, 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...)
|
|
|
|
prepres := make(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.TrackingService, c *core.Configuration) fiber.Handler {
|
|
return func(ctx *fiber.Ctx) error {
|
|
rec, err := s.StartRecord()
|
|
|
|
prepres := make(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.TrackingService, c *core.Configuration) fiber.Handler {
|
|
return func(ctx *fiber.Ctx) error {
|
|
rec, err := s.StopRecord()
|
|
|
|
prepres := make(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.TrackingService, c *core.Configuration) fiber.Handler {
|
|
return func(ctx *fiber.Ctx) error {
|
|
rec, err := s.StopAll()
|
|
|
|
prepres := make(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
|
|
logrus.Traceln("write to ws:", cmsg)
|
|
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 <engine>.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")
|
|
}
|
|
|
|
func fiberTrackingHandler(c *fiber.Ctx) error {
|
|
// Render index template
|
|
return c.Render("replayFull", nil)
|
|
}
|