172 lines
3.6 KiB
Go
172 lines
3.6 KiB
Go
package server
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"code.thetadev.de/TSGRain/SEBRAUC/src/rauc"
|
|
"code.thetadev.de/TSGRain/SEBRAUC/src/sysinfo"
|
|
"code.thetadev.de/TSGRain/SEBRAUC/src/util"
|
|
"code.thetadev.de/TSGRain/SEBRAUC/ui"
|
|
"github.com/gofiber/fiber/v2"
|
|
"github.com/gofiber/fiber/v2/middleware/compress"
|
|
"github.com/gofiber/fiber/v2/middleware/cors"
|
|
"github.com/gofiber/fiber/v2/middleware/filesystem"
|
|
"github.com/gofiber/fiber/v2/middleware/logger"
|
|
"github.com/gofiber/websocket/v2"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type SEBRAUCServer struct {
|
|
address string
|
|
raucUpdater *rauc.Rauc
|
|
hub *MessageHub
|
|
tmpdir string
|
|
}
|
|
|
|
type statusMessage struct {
|
|
Success bool `json:"success"`
|
|
Msg string `json:"msg"`
|
|
}
|
|
|
|
func NewServer(address string) *SEBRAUCServer {
|
|
hub := NewHub()
|
|
|
|
raucUpdater := rauc.NewRauc(hub.Broadcast)
|
|
|
|
tmpdir, err := util.GetTmpdir()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return &SEBRAUCServer{
|
|
address: address,
|
|
raucUpdater: raucUpdater,
|
|
hub: hub,
|
|
tmpdir: tmpdir,
|
|
}
|
|
}
|
|
|
|
func (srv *SEBRAUCServer) Run() error {
|
|
app := fiber.New(fiber.Config{
|
|
AppName: "SEBRAUC",
|
|
BodyLimit: 1024 * 1024 * 1024,
|
|
ErrorHandler: errorHandler,
|
|
DisableStartupMessage: true,
|
|
})
|
|
|
|
app.Use(logger.New())
|
|
|
|
app.Use(compress.New(compress.Config{
|
|
Next: func(c *fiber.Ctx) bool {
|
|
return strings.HasPrefix(c.Path(), "/api")
|
|
},
|
|
}))
|
|
|
|
// just for testing
|
|
app.Use("/api", cors.New())
|
|
|
|
app.Use("/api/ws", func(c *fiber.Ctx) error {
|
|
// IsWebSocketUpgrade returns true if the client
|
|
// requested upgrade to the WebSocket protocol.
|
|
if websocket.IsWebSocketUpgrade(c) {
|
|
c.Locals("allowed", true)
|
|
return c.Next()
|
|
}
|
|
return fiber.ErrUpgradeRequired
|
|
})
|
|
|
|
app.Use("/", filesystem.New(filesystem.Config{
|
|
Root: http.FS(ui.Assets),
|
|
PathPrefix: ui.AssetsDir,
|
|
MaxAge: 7200,
|
|
}))
|
|
|
|
// ROUTES
|
|
app.Get("/api/ws", websocket.New(srv.hub.Handler))
|
|
app.Post("/api/update", srv.controllerUpdate)
|
|
app.Get("/api/status", srv.controllerStatus)
|
|
app.Get("/api/info", srv.controllerInfo)
|
|
app.Post("/api/reboot", srv.controllerReboot)
|
|
|
|
// Start messaging hub
|
|
go srv.hub.Run()
|
|
|
|
return app.Listen(srv.address)
|
|
}
|
|
|
|
func (srv *SEBRAUCServer) controllerUpdate(c *fiber.Ctx) error {
|
|
file, err := c.FormFile("updateFile")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
uid, err := uuid.NewRandom()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
updateFile := fmt.Sprintf("%s/update_%s.raucb", srv.tmpdir, uid.String())
|
|
|
|
err = c.SaveFile(file, updateFile)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = srv.raucUpdater.RunRauc(updateFile)
|
|
if err == nil {
|
|
writeStatus(c, true, "Update started")
|
|
} else if errors.Is(err, util.ErrAlreadyRunning) {
|
|
return fiber.NewError(fiber.StatusConflict, "already running")
|
|
} else {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (srv *SEBRAUCServer) controllerStatus(c *fiber.Ctx) error {
|
|
c.Context().SetStatusCode(200)
|
|
_ = c.JSON(srv.raucUpdater.GetStatus())
|
|
return nil
|
|
}
|
|
|
|
func (srv *SEBRAUCServer) controllerInfo(c *fiber.Ctx) error {
|
|
info, err := sysinfo.GetSysinfo()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
c.Context().SetStatusCode(200)
|
|
_ = c.JSON(info)
|
|
return nil
|
|
}
|
|
|
|
func (srv *SEBRAUCServer) controllerReboot(c *fiber.Ctx) error {
|
|
go util.Reboot(5 * time.Second)
|
|
|
|
writeStatus(c, true, "System is rebooting")
|
|
return nil
|
|
}
|
|
|
|
func errorHandler(c *fiber.Ctx, err error) error {
|
|
// API error handling
|
|
if strings.HasPrefix(c.Path(), "/api") {
|
|
writeStatus(c, false, err.Error())
|
|
}
|
|
return err
|
|
}
|
|
|
|
func writeStatus(c *fiber.Ctx, success bool, msg string) {
|
|
_ = c.JSON(statusMessage{
|
|
Success: success,
|
|
Msg: msg,
|
|
})
|
|
|
|
if success {
|
|
c.Context().SetStatusCode(200)
|
|
}
|
|
}
|