package main import ( "fmt" "github.com/gin-gonic/gin" "github.com/google/uuid" ) func initApi() { gin.SetMode(gin.ReleaseMode) router := gin.Default() router.SetTrustedProxies(nil) router.GET("/api/ports", func(c *gin.Context) { c.JSON(200, portConfig) }) router.GET("/api/port", handleGetPort) router.POST("/api/ports", handleCreatePort) router.DELETE("/api/ports", handleDeletePort) router.GET("/api/state", handleGetState) router.PUT("/api/state", handleSetState) router.POST("/api/routes", handleCreateRoute) router.PUT("/api/routes", handleSetRoute) router.DELETE("/api/routes", handleDeleteRoute) router.Run(fmt.Sprintf("%s:%d", config.Web.Bind, config.Web.Port)) } func handleGetPort(c *gin.Context) { id := c.Query("UUID") if id == "" { c.JSON(400, gin.H{"success": false, "error": "`UUID` parameter missing!"}) return } port, portIndex, _ := findPort(id) if portIndex < 0 { c.JSON(400, gin.H{"success": false, "error": "Port with provided UUID does not exist!"}) return } c.JSON(200, port) } type CreatePortRequest struct { Name string Backend string Channels uint8 Type string } func handleCreatePort(c *gin.Context) { var body CreatePortRequest if err := c.BindJSON(&body); err != nil { c.JSON(500, gin.H{"success": false, "error": "Parsing request body failed!"}) return } if body.Name == "" || body.Backend == "" || body.Channels == 0 || body.Type == "" { c.JSON(400, gin.H{"success": false, "error": "Required parameters missing!"}) return } if body.Type != "input" && body.Type != "output" { c.JSON(400, gin.H{"success": false, "error": "`Type` must either be `input` or `output`"}) return } id := uuid.New() newPort := Port{ UUID: id.String(), Name: body.Name, Properties: PortProperties{ Backend: body.Backend, Channels: body.Channels, }, State: PortState{ Mute: false, Volume: 0, Balance: 0, }, Route: []PortRoute{}, } if body.Type == "input" { registerPort(&newPort, "input") portConfig.Input = append(portConfig.Input, newPort) } else { registerPort(&newPort, "output") portConfig.Output = append(portConfig.Output, newPort) } saveConfig("ports", &portConfig) c.JSON(200, gin.H{"success": true, "UUID": newPort.UUID}) } type DeletePortRequest struct { UUID string } func handleDeletePort(c *gin.Context) { var body DeletePortRequest if err := c.BindJSON(&body); err != nil { c.JSON(500, gin.H{"success": false, "error": "Parsing request body failed!"}) return } if body.UUID == "" { c.JSON(400, gin.H{"success": false, "error": "Required parameters missing!"}) return } port, portIndex, portType := findPort(body.UUID) if portIndex < 0 { c.JSON(400, gin.H{"success": false, "error": "Port with provided UUID does not exist!"}) return } // Remove the port from the configuration if portType == "output" { portConfig.Output = append(portConfig.Output[:portIndex], portConfig.Output[portIndex+1:]...) } else { portConfig.Input = append(portConfig.Input[:portIndex], portConfig.Input[portIndex+1:]...) } // Unregister port unregisterPort(port) saveConfig("ports", &portConfig) } func handleGetState(c *gin.Context) { id := c.Query("UUID") if id == "" { c.JSON(400, gin.H{"success": false, "error": "`UUID` parameter missing!"}) return } port, portIndex, _ := findPort(id) if portIndex < 0 { c.JSON(400, gin.H{"success": false, "error": "Port with provided UUID does not exist!"}) return } c.JSON(200, port.State) } type SetPortRequest struct { Mute *bool Volume *float32 Balance *float32 } func handleSetState(c *gin.Context) { var body SetPortRequest err := c.BindJSON(&body) if err != nil { c.JSON(500, gin.H{"success": false, "error": "Parsing request body failed!"}) return } id := c.Query("UUID") if id == "" { c.JSON(400, gin.H{"success": false, "error": "`UUID` parameter missing!"}) return } port, portIndex, _ := findPort(id) if portIndex < 0 { c.JSON(400, gin.H{"success": false, "error": "Port with provided UUID does not exist!"}) return } if body.Mute != nil { port.State.Mute = *body.Mute } if body.Volume != nil { port.State.Volume = *body.Volume } if body.Balance != nil { port.State.Balance = *body.Balance } c.JSON(200, gin.H{"success": true, "state": port.State}) saveConfig("ports", &portConfig) } type CreateRouteRequest struct { To string } func handleCreateRoute(c *gin.Context) { var body CreateRouteRequest err := c.BindJSON(&body) if err != nil { c.JSON(500, gin.H{"success": false, "error": "Parsing request body failed!"}) return } id := c.Query("UUID") if id == "" || body.To == "" { c.JSON(400, gin.H{"success": false, "error": "Required parameters missing!"}) return } from, fromIndex, fromType := findPort(id) _, toIndex, toType := findPort(body.To) if fromIndex < 0 || toIndex < 0 { c.JSON(400, gin.H{"success": false, "error": "One of `UUID` or `To` does not exist!"}) return } if fromType != "input" || toType != "output" { c.JSON(400, gin.H{"success": false, "error": "`UUID` needs to be an input and `To` an output port!"}) return } from.Route = append(from.Route, PortRoute{ToUUID: body.To, Mute: true, Volume: 0, Balance: 0}) saveConfig("ports", &portConfig) c.JSON(200, gin.H{"success": true}) } type SetRouteRequest struct { Mute *bool Volume *float32 Balance *float32 } func handleSetRoute(c *gin.Context) { var body SetRouteRequest err := c.BindJSON(&body) if err != nil { c.JSON(500, gin.H{"success": false, "error": "Parsing request body failed!"}) return } fromId := c.Query("UUID") toId := c.Query("To") if fromId == "" || toId == "" { c.JSON(400, gin.H{"success": false, "error": "Required parameters missing!"}) return } from, fromIndex, _ := findPort(fromId) if fromIndex < 0 { c.JSON(400, gin.H{"success": false, "error": "Port with provided UUID does not exist!"}) return } for i, r := range from.Route { if r.ToUUID != toId { continue } if body.Mute != nil { from.Route[i].Mute = *body.Mute } if body.Volume != nil { from.Route[i].Volume = *body.Volume } if body.Balance != nil { from.Route[i].Balance = *body.Balance } saveConfig("ports", &portConfig) c.JSON(200, gin.H{"success": true}) return } c.JSON(200, gin.H{"success": false, "error": "No such route exists!"}) } func handleDeleteRoute(c *gin.Context) { fromId := c.Query("UUID") toId := c.Query("To") if fromId == "" || toId == "" { c.JSON(400, gin.H{"success": false, "error": "Required parameters missing!"}) return } from, fromIndex, _ := findPort(fromId) if fromIndex < 0 { c.JSON(400, gin.H{"success": false, "error": "Port with provided UUID does not exist!"}) return } for i, r := range from.Route { if r.ToUUID != toId { continue } from.Route = append(from.Route[:i], from.Route[i+1:]...) saveConfig("ports", &portConfig) c.JSON(200, gin.H{"success": true}) return } c.JSON(200, gin.H{"success": false, "error": "No such route exists!"}) }