From 83cbcdaa4208fe4223f5f2ec085fe6ee3b5f24e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Z=C3=BCrcher?= Date: Tue, 29 Apr 2025 09:16:27 +0200 Subject: [PATCH] updated --- auth/auth.go | 8 +++ driver/artNet.go | 7 +-- driver/bus.go | 126 +++++++++++++++++++++------------------ driver/webSocket.go | 90 ++++++++++++---------------- main.go | 24 +++++--- models/bus.go | 27 +++++++++ server/models/clients.go | 75 +++++++++++------------ server/server.go | 14 ++++- 8 files changed, 207 insertions(+), 164 deletions(-) diff --git a/auth/auth.go b/auth/auth.go index fc47c39..6cf5cd3 100644 --- a/auth/auth.go +++ b/auth/auth.go @@ -13,3 +13,11 @@ func GetIDFromAuth(c *gin.Context) (string, error) { } return "", errors.New("authorization token missing") } + +func GetIDFromQuery(c *gin.Context) (string, error) { + auth, exists := c.GetQuery("id") + if !exists { + return "", errors.New("id missing") + } + return auth, nil +} diff --git a/driver/artNet.go b/driver/artNet.go index c3343e8..2d404d9 100644 --- a/driver/artNet.go +++ b/driver/artNet.go @@ -14,9 +14,9 @@ type ArtNetDriver struct { Name string `yaml:"driver" json:"driver"` Buses map[string]*models.Bus `yaml:"buses,omitempty" json:"buses,omitempty"` cfgHandler *cfg.Cfg `yaml:"-" json:"-"` - Conn *client.Client `yaml:"-"` - Subscriptions models.Subscriptions `yaml:"-"` - Log *logging.Logger `yaml:"-"` + Conn *client.Client `yaml:"-" json:"-"` + Subscriptions models.Subscriptions `yaml:"-" json:"-"` + Log *logging.Logger `yaml:"-" json:"-"` } // initialize new Art-Net driver @@ -72,7 +72,6 @@ func (d *ArtNetDriver) LoadCfg() error { // adds new Art-Net bus/interface to driver port 0 = 6454 (default art-net) func (d *ArtNetDriver) NewBus(name, ip string, port int) *models.Bus { b := models.NewBus(name, ip, port) - b.Start(d.Log) d.Buses[name] = b return b } diff --git a/driver/bus.go b/driver/bus.go index 02361a9..380a407 100644 --- a/driver/bus.go +++ b/driver/bus.go @@ -8,6 +8,7 @@ import ( "net/http" "github.com/gin-gonic/gin" + json_data "github.com/tecamino/tecamino-json_data" json_dataModels "github.com/tecamino/tecamino-json_data/models" ) @@ -26,123 +27,132 @@ func (d *ArtNetDriver) GetAllBuses(c *gin.Context) { } func (d *ArtNetDriver) CreateBus(c *gin.Context) { - _, err := auth.GetIDFromAuth(c) + _, err := auth.GetIDFromQuery(c) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "id: " + err.Error()}) + r := json_data.NewResponse() + r.SendError(err.Error()) + c.JSON(http.StatusBadRequest, r) return } - var payload models.Bus - - if err := c.BindJSON(&payload); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "json: " + err.Error()}) + busPayload := models.Bus{} + if err := busPayload.ParsePayload(c); err != nil { return } - if payload.Name == "" { - c.JSON(http.StatusBadRequest, gin.H{"error": "bus name missing"}) - return - } else if addr := net.ParseIP(payload.Ip); addr == nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "wrong ip '" + payload.Ip + "'"}) + if addr := net.ParseIP(busPayload.Ip); addr == nil { + r := json_data.NewResponse() + r.SendError("wrong ip '" + busPayload.Ip + "'") + c.JSON(http.StatusBadRequest, r) return } - if _, ok := d.Buses[payload.Name]; ok { - c.JSON(http.StatusOK, gin.H{"message": "bus " + payload.Name + " exists already"}) + if _, ok := d.Buses[busPayload.Name]; ok { + r := json_data.NewResponse() + r.SendError("bus " + busPayload.Name + " exists already") + c.JSON(http.StatusOK, r) return } - bus := d.NewBus(payload.Name, payload.Ip, payload.GetPort()) + bus := d.NewBus(busPayload.Name, busPayload.Ip, busPayload.GetPort()) - c.JSON(http.StatusOK, gin.H{ - "message": fmt.Sprintf("bus '%s' successfully created with ip: %s and on port: %d", bus.Name, bus.Ip, bus.GetPort()), - }) + r := json_data.NewResponse() + r.SendMessage(fmt.Sprintf("bus '%s' successfully created with ip: %s and on port: %d", bus.Name, bus.Ip, bus.GetPort())) + c.JSON(http.StatusOK, r) d.cfgHandler.SaveCfg(*d) } func (d *ArtNetDriver) RemoveBus(c *gin.Context) { - _, err := auth.GetIDFromAuth(c) + _, err := auth.GetIDFromQuery(c) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "id: " + err.Error()}) + r := json_data.NewResponse() + r.SendError("id: " + err.Error()) + c.JSON(http.StatusBadRequest, r) return } - var payload models.Bus - - if err := c.BindJSON(&payload); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "json: " + err.Error()}) + busPayload := models.Bus{} + if err := busPayload.ParsePayload(c); err != nil { return } - if payload.Name == "" { - c.JSON(http.StatusBadRequest, gin.H{"error": "bus name missing"}) - return - } - - if _, ok := d.Buses[payload.Name]; !ok { + if _, ok := d.Buses[busPayload.Name]; !ok { r := json_dataModels.NewResponse() - r.SendMessage("bus " + payload.Name + " not found") + r.SendMessage("bus " + busPayload.Name + " not found") c.JSON(http.StatusOK, r) return } else { - delete(d.Buses, payload.Name) + delete(d.Buses, busPayload.Name) } r := json_dataModels.NewResponse() - r.SendMessage(fmt.Sprintf("bus '%s' successfully removed", payload.Name)) + r.SendMessage(fmt.Sprintf("bus '%s' successfully removed", busPayload.Name)) c.JSON(http.StatusOK, r) d.cfgHandler.SaveCfg(*d) } func (d *ArtNetDriver) Start(c *gin.Context) { - _, err := auth.GetIDFromAuth(c) + _, err := auth.GetIDFromQuery(c) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "id: " + err.Error()}) + r := json_data.NewResponse() + r.SendError("id: " + err.Error()) + c.JSON(http.StatusBadRequest, r) return } - var payload models.Bus - - if err := c.BindJSON(&payload); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "json: " + err.Error()}) + busPayload := models.Bus{} + if busPayload.ParsePayload(c); err != nil { return } - if payload.Name == "" { - c.JSON(http.StatusBadRequest, gin.H{"error": "bus name missing"}) - return - } - - d.Buses[payload.Name].Start(d.Log) + d.Buses[busPayload.Name].Start(d.Log) r := json_dataModels.NewResponse() - r.SendMessage(fmt.Sprintf("bus '%s' running", payload.Name)) + r.SendMessage(fmt.Sprintf("bus '%s' running", busPayload.Name)) c.JSON(http.StatusOK, r) d.cfgHandler.SaveCfg(*d) } func (d *ArtNetDriver) Stop(c *gin.Context) { - _, err := auth.GetIDFromAuth(c) + _, err := auth.GetIDFromQuery(c) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "id: " + err.Error()}) + r := json_data.NewResponse() + r.SendError("id: " + err.Error()) + c.JSON(http.StatusBadRequest, r) return } - var payload models.Bus - - if err := c.BindJSON(&payload); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "json: " + err.Error()}) + busPayload := models.Bus{} + if err := busPayload.ParsePayload(c); err != nil { return } - if payload.Name == "" { - c.JSON(http.StatusBadRequest, gin.H{"error": "bus name missing"}) - return - } - - d.Buses[payload.Name].Stop() + d.Buses[busPayload.Name].Stop() r := json_dataModels.NewResponse() - r.SendMessage(fmt.Sprintf("bus '%s' stopped", payload.Name)) + r.SendMessage(fmt.Sprintf("bus '%s' stopped", busPayload.Name)) c.JSON(http.StatusOK, r) d.cfgHandler.SaveCfg(*d) } + +func (d *ArtNetDriver) Status(c *gin.Context) { + _, err := auth.GetIDFromQuery(c) + if err != nil { + r := json_data.NewResponse() + r.SendError("id: " + err.Error()) + c.JSON(http.StatusBadRequest, r) + return + } + + busPayload := models.Bus{} + if err := busPayload.ParsePayload(c); err != nil { + return + } + + r := json_dataModels.NewResponse() + state := "stopped" + if d.Buses[busPayload.Name].Status() { + state = "running" + } + r.SendMessage(fmt.Sprintf("bus '%s' %s", busPayload.Name, state)) + c.JSON(http.StatusOK, r) +} diff --git a/driver/webSocket.go b/driver/webSocket.go index cf0f02e..9f5695b 100644 --- a/driver/webSocket.go +++ b/driver/webSocket.go @@ -1,63 +1,49 @@ package driver -import ( - "context" - "log" - "time" - - "artNet/auth" - "artNet/models" - - "github.com/coder/websocket" - "github.com/coder/websocket/wsjson" - "github.com/gin-gonic/gin" -) - const ( OnCreate = "onCreate" OnChange = "onChange" OnDelete = "onDelete" ) -func (d *ArtNetDriver) Websocket(c *gin.Context) { - id, err := auth.GetIDFromAuth(c) - if err != nil { - d.Log.Error("artNet.webSocket.Websocket", "error GetIDFromAuth: "+err.Error()) - log.Println("error id:", err) - return - } - d.Log.Debug("artNet.webSocket.Websocket", "authorization id token: "+id) +//func (d *ArtNetDriver) Websocket(c *gin.Context) { +// id, err := auth.GetIDFromQuery(c) +// if err != nil { +// d.Log.Error("artNet.webSocket.Websocket", "error GetIDFromAuth: "+err.Error()) +// return +// } +// d.Log.Debug("artNet.webSocket.Websocket", "authorization id token: "+id) - ctx, cancel := context.WithTimeout(c.Request.Context(), 10*time.Minute) - defer cancel() - conn, err := d.Connections.ConnectRecievingWsConnection(id, c) - if err != nil { - d.Log.Error("artNet.webSocket.Websocket", "error connecting recieving websocket conection: "+err.Error()) - return - } - defer d.Connections.DisconnectRecievingWsConnection(id, websocket.StatusInternalError, "Internal error") +// ctx, cancel := context.WithTimeout(c.Request.Context(), 10*time.Minute) +// defer cancel() +// conn, err := d.Connections.ConnectRecievingWsConnection(id, c) +// if err != nil { +// d.Log.Error("artNet.webSocket.Websocket", "error connecting recieving websocket conection: "+err.Error()) +// return +// } +// defer d.Connections.DisconnectRecievingWsConnection(id, websocket.StatusInternalError, "Internal error") - var request models.JsonData - //Read loop - for { +// var request any +// //Read loop +// for { - err := wsjson.Read(ctx, conn, &request) - if err != nil { - d.Log.Error("artNet.webSocket.Websocket", "read error:"+err.Error()) - log.Println("WebSocket read error:", err) - break - } - - // Set - if request.Set != nil { - for _, set := range *request.Set { - if err = d.SetValue(set); err != nil { - d.Log.Error("artNet.webSocket.Websocket", "set value error"+err.Error()) - log.Println(err) - continue - } - time.Sleep(23 * time.Millisecond) - } - } - } -} +// err := wsjson.Read(ctx, conn, &request) +// if err != nil { +// d.Log.Error("artNet.webSocket.Websocket", "read error:"+err.Error()) +// log.Println("WebSocket read error:", err) +// break +// } +// fmt.Println(request) +// Set +// if request.Set != nil { +// for _, set := range *request.Set { +// if err = d.SetValue(set); err != nil { +// d.Log.Error("artNet.webSocket.Websocket", "set value error"+err.Error()) +// log.Println(err) +// continue +// } +// time.Sleep(23 * time.Millisecond) +// } +// } +// } +// } diff --git a/main.go b/main.go index 2668782..374ea8a 100644 --- a/main.go +++ b/main.go @@ -6,6 +6,7 @@ import ( "flag" "fmt" "os" + "time" "github.com/gin-gonic/gin" ) @@ -14,9 +15,11 @@ const DriverName string = "ArtNetDriver" func main() { // cli flags - port := flag.Uint("port-http", 8110, "http server listening port") cfgDir := flag.String("cfg", "./cfg", "config directory") workingDir := flag.String("workingDirectory", ".", "current working directory") + serverIp := flag.String("serverIp", "127.0.0.1", "ip address of server") + serverPort := flag.Uint("serverPort", 8100, "port of server") + wsPort := flag.Uint("port", 8200, "websocket port") debug := flag.Bool("debug", false, "debug logging") flag.Parse() @@ -38,21 +41,28 @@ func main() { //set routes artNetDriver.Log.Debug("main", "setting routes") - s.Routes.GET("/ws", artNetDriver.Websocket) s.Routes.GET("/buses/all", artNetDriver.GetAllBuses) s.Routes.POST("/buses/create", artNetDriver.CreateBus) s.Routes.POST("/buses/remove", artNetDriver.RemoveBus) s.Routes.POST("/buses/start", artNetDriver.Start) + s.Routes.POST("/buses/status", artNetDriver.Status) s.Routes.POST("/buses/stop", artNetDriver.Stop) s.Routes.GET("/", func(c *gin.Context) { c.String(200, "ArtNet Driver WebSocket Server is running!") }) - artNetDriver.Log.Info("main", fmt.Sprintf("listen on %d", *port)) - // start http server - if err := s.ServeHttp(*port); err != nil { - artNetDriver.Log.Error("main", "error http server "+err.Error()) - panic(err) + go func() { + if err := s.ServeHttp(*wsPort); err != nil { + artNetDriver.Log.Error("main", err.Error()) + } + }() + + artNetDriver.Log.Info("main", fmt.Sprintf("connect to server ws://%s:%d with id %s", *serverIp, serverPort, DriverName)) + // connect to server + for { + artNetDriver.Log.Error("main", artNetDriver.Connect(*serverIp, DriverName, *serverPort)) + time.Sleep(10 * time.Second) } + } diff --git a/models/bus.go b/models/bus.go index 3db2ee6..de3ef6c 100644 --- a/models/bus.go +++ b/models/bus.go @@ -2,11 +2,15 @@ package models import ( "context" + "errors" "fmt" "net" + "net/http" "time" + "github.com/gin-gonic/gin" "github.com/tatsushid/go-fastping" + json_data "github.com/tecamino/tecamino-json_data" "github.com/tecamino/tecamino-logger/logging" ) @@ -135,6 +139,11 @@ func (b *Bus) Stop() { } } +// status bus +func (b *Bus) Status() bool { + return b.Watchdog != nil +} + // send dmx data func (b *Bus) SendData() error { if !b.Reachable { @@ -156,6 +165,24 @@ func (b *Bus) SendData() error { return err } +func (b *Bus) ParsePayload(c *gin.Context) error { + + if err := c.BindJSON(b); err != nil { + r := json_data.NewResponse() + r.SendError("json: " + err.Error()) + c.JSON(http.StatusBadRequest, r) + return err + } + + if b.Name == "" { + r := json_data.NewResponse() + r.SendError("bus name missing") + c.JSON(http.StatusBadRequest, r) + return errors.New("bus name missing") + } + return nil +} + func isUDPReachable(ip string) (recieved bool, err error) { p := fastping.NewPinger() ra, err := net.ResolveIPAddr("ip4:icmp", ip) diff --git a/server/models/clients.go b/server/models/clients.go index 465d04c..7fb1588 100644 --- a/server/models/clients.go +++ b/server/models/clients.go @@ -1,51 +1,44 @@ package models -import ( - "fmt" +// type Clients map[string]Client - "github.com/coder/websocket" - "github.com/gin-gonic/gin" -) +// type Client struct { +// Connected *bool `json:"connected"` +// SndConn *websocket.Conn `json:"-"` //sending connection +// RvcConn *websocket.Conn `json:"-"` // revieving connection +// } -type Clients map[string]Client +// func NewClients() Clients { +// return make(Clients) +// } -type Client struct { - Connected *bool `json:"connected"` - SndConn *websocket.Conn `json:"-"` //sending connection - RvcConn *websocket.Conn `json:"-"` // revieving connection -} +// // Connect a recieving websocket connection +// func (c *Clients) ConnectRecievingWsConnection(id string, ctx *gin.Context) (*websocket.Conn, error) { +// conn, err := websocket.Accept(ctx.Writer, ctx.Request, &websocket.AcceptOptions{ +// OriginPatterns: []string{"*"}, +// }) -func NewClients() Clients { - return make(Clients) -} +// if err != nil { +// return nil, fmt.Errorf("error accept websocket client: %s", err) +// } -// Connect a recieving websocket connection -func (c *Clients) ConnectRecievingWsConnection(id string, ctx *gin.Context) (*websocket.Conn, error) { - conn, err := websocket.Accept(ctx.Writer, ctx.Request, &websocket.AcceptOptions{ - OriginPatterns: []string{"*"}, - }) +// b := true +// (*c)[id] = Client{ +// Connected: &b, +// RvcConn: conn, +// } +// return conn, nil +// } - if err != nil { - return nil, fmt.Errorf("error accept websocket client: %s", err) - } +// func (c *Clients) RemoveClient(id string) { +// delete(*c, id) +// } - b := true - (*c)[id] = Client{ - Connected: &b, - RvcConn: conn, - } - return conn, nil -} +// func (c *Clients) GetClientPointer(id string) *bool { +// return (*c)[id].Connected +// } -func (c *Clients) RemoveClient(id string) { - delete(*c, id) -} - -func (c *Clients) GetClientPointer(id string) *bool { - return (*c)[id].Connected -} - -func (c *Clients) DisconnectRecievingWsConnection(id string, code websocket.StatusCode, reason string) { - *(*c)[id].Connected = false - (*c)[id].RvcConn.Close(code, reason) -} +// func (c *Clients) DisconnectRecievingWsConnection(id string, code websocket.StatusCode, reason string) { +// *(*c)[id].Connected = false +// (*c)[id].RvcConn.Close(code, reason) +// } diff --git a/server/server.go b/server/server.go index 0d11f44..edcb799 100644 --- a/server/server.go +++ b/server/server.go @@ -1,9 +1,8 @@ package server import ( - "fmt" - "artNet/cert" + "fmt" "github.com/gin-gonic/gin" ) @@ -12,6 +11,17 @@ type Server struct { Routes *gin.Engine } +type Send struct { + Set []Set `json:"subscribe"` +} + +type Set struct { + Path string `json:"path"` + OnChange bool `json:"onChange"` + Depth int `json:"depth"` + Driver string `json:"driver"` +} + // Initialize new websocket server func NewServer() *Server { return &Server{