diff --git a/backend/api.go b/backend/api.go index 7256b87..7feb062 100644 --- a/backend/api.go +++ b/backend/api.go @@ -8,14 +8,15 @@ func (w *Webapp) initApi() { http_api := w.Engine.Group("/api") http_api.GET("/priority", w.GetPriority) - http_api.GET("/load", w.LoadHeats) http_api.POST("/priority", w.SetPriority) - http_api.POST("/start", w.StartTimer) // SSE http_api.GET("/sse", HeadersMiddleware(), stream.serveHTTP(), stream.retvalSSE()) - http_api.POST("/setup", w.SetupHeat) + http_api.POST("/startheat", w.StartHeat) + http_api.POST("/saveheat", w.SaveHeat) + http_api.POST("/deleteheat", w.DeleteHeat) + http_api.GET("/loadheats", w.LoadHeats) // // Surfers // http_api.GET("/surfers", w.GetSurfers) diff --git a/backend/backend b/backend/backend index 1dd975c..8e417d3 100755 Binary files a/backend/backend and b/backend/backend differ diff --git a/backend/heats.go b/backend/heats.go new file mode 100644 index 0000000..bed59db --- /dev/null +++ b/backend/heats.go @@ -0,0 +1,179 @@ +package main + +import ( + "encoding/json" + "fmt" + "log" + "net/http" + "time" + + "github.com/gin-gonic/gin" + scribble "github.com/nanobox-io/golang-scribble" +) + +type Surfer struct { + Name string `json:"name"` + Color string `json:"color"` + Priority string `json:"priority"` + Score string `json:"score"` +} + +type Heat struct { + Name string `json:"name"` + Category string `json:"category"` + Number int `json:"number"` + Timer int `json:"timer"` + Status string `json:"status"` + Surfers []Surfer `json:"surfers"` +} + +func heatName(heat Heat) string { + return fmt.Sprintf("%s.%d.%s", heat.Name, heat.Number, heat.Category) +} + +func (w *Webapp) SaveHeat(c *gin.Context) { + var heat Heat + + err := c.ShouldBind(&heat) + + if err != nil { + log.Printf("req error: %+v", err) + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + log.Printf("heat: %+v", heat) + + heat.Status = "idle" + + err = w.DB.Write("Heat", heatName(heat), heat) + if err != nil { + log.Printf("set error: %+v", err) + c.JSON(http.StatusInternalServerError, gin.H{"status": fmt.Sprintf("Error: %+v", err)}) + return + } + + c.JSON(http.StatusOK, gin.H{"status": "saved"}) +} + +func (w *Webapp) DeleteHeat(c *gin.Context) { + var heat Heat + + err := c.ShouldBind(&heat) + + if err != nil { + log.Printf("req error: %+v", err) + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + log.Printf("heat: %+v", heat) + + err = w.DB.Delete("Heat", heatName(heat)) + if err != nil { + log.Printf("set error: %+v", err) + c.JSON(http.StatusInternalServerError, gin.H{"status": fmt.Sprintf("Error: %+v", err)}) + return + } + + c.JSON(http.StatusOK, gin.H{"status": "deleted"}) +} + +func (w *Webapp) LoadRunning(c *gin.Context) { + heats := loadHeats(w.DB) + + for _, heat := range heats { + if heat.Status == "running" { + c.JSON(http.StatusOK, heat) + return + } + } +} + +func (w *Webapp) LoadHeats(c *gin.Context) { + heats := loadHeats(w.DB) + + c.JSON(http.StatusOK, heats) + + log.Printf("heats: %+v", heats) +} + +func (w *Webapp) StartHeatTimer(c *gin.Context) { + var msg Message + var err error + var timer time.Duration + + if w.Stream.Start { + c.JSON(http.StatusOK, w.Stream.Duration) + return + } + + err = c.ShouldBind(&msg) + if err != nil { + log.Printf("req error: %+v", err) + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + timer, err = time.ParseDuration(msg.Duration) + if err != nil { + log.Printf("req error: %+v", err) + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + w.Stream.Duration = timer + w.Stream.Start = true + + startHeat(w.DB, *w.Stream.Heat) + + log.Printf("start timer %s - received %s", w.Stream.Duration, msg.Duration) + c.JSON(http.StatusOK, w.Stream.Duration) +} + +func loadHeats(db *scribble.Driver) []Heat { + records, err := db.ReadAll("Heat") + if err != nil { + fmt.Printf("read error: %+v", err) + } + + heats := make([]Heat, 0) + for _, record := range records { + var heat Heat + err = json.Unmarshal([]byte(record), &heat) + if err != nil { + fmt.Printf("decode error: %+v", err) + } + heats = append(heats, heat) + } + + return heats +} + +func startHeat(db *scribble.Driver, heat Heat) error { + log.Printf("heat: %+v", heat) + + heat.Status = "running" + + err := db.Write("Heat", heatName(heat), heat) + if err != nil { + log.Printf("set error: %+v", err) + return err + } + + return nil +} + +func stopHeat(db *scribble.Driver, heat Heat) error { + + log.Printf("heat: %+v", heat) + + heat.Status = "ended" + + err := db.Write("Heat", heatName(heat), heat) + if err != nil { + log.Printf("set error: %+v", err) + return err + } + + return nil +} diff --git a/backend/priority.go b/backend/priority.go index efdb01f..81c48e3 100644 --- a/backend/priority.go +++ b/backend/priority.go @@ -1,8 +1,6 @@ package main import ( - "encoding/json" - "fmt" "log" "net/http" "time" @@ -37,27 +35,6 @@ func (w *Webapp) StartTimer(c *gin.Context) { c.JSON(http.StatusOK, w.Stream.Duration) } -func (w *Webapp) LoadHeats(c *gin.Context) { - records, err := w.DB.ReadAll("Heat") - if err != nil { - fmt.Printf("read error: %+v", err) - } - - heats := make([]Heat, 0) - for _, record := range records { - var heat Heat - err = json.Unmarshal([]byte(record), &heat) - if err != nil { - fmt.Printf("decode error: %+v", err) - } - heats = append(heats, heat) - } - - c.JSON(http.StatusOK, heats) - - log.Printf("heats: %+v", heats) -} - func (w *Webapp) GetPriority(c *gin.Context) { log.Printf("send priority %s", w.Stream.StatusPriority) diff --git a/backend/setup.go b/backend/setup.go deleted file mode 100644 index 0716334..0000000 --- a/backend/setup.go +++ /dev/null @@ -1,45 +0,0 @@ -package main - -import ( - "fmt" - "log" - "net/http" - - "github.com/gin-gonic/gin" -) - -type Surfer struct { - Name string `json:"name"` - Color string `json:"color"` - Priority string `json:"priority"` - Score string `json:"score"` -} - -type Heat struct { - Name string `json:"name"` - Category string `json:"category"` - Number int `json:"number"` - Timer int `json:"timer"` - Surfers []Surfer `json:"surfers"` -} - -func (w *Webapp) SetupHeat(c *gin.Context) { - var heat Heat - - err := c.ShouldBind(&heat) - - if err != nil { - log.Printf("req error: %+v", err) - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - - log.Printf("heat: %+v", heat) - - c.JSON(http.StatusOK, gin.H{"status": "added"}) - - err = w.DB.Write("Heat", fmt.Sprintf("%s.%s.%d", heat.Name, heat.Category, heat.Number), heat) - if err != nil { - log.Printf("set error: %+v", err) - } -} diff --git a/backend/sse.go b/backend/sse.go index b387967..bc72e21 100644 --- a/backend/sse.go +++ b/backend/sse.go @@ -20,6 +20,7 @@ type SurferLive struct { type Message struct { Surfers []SurferLive `json:"surfers"` Priority []string `json:"priority"` + Heat Heat `json:"heat"` Duration string `json:"duration"` Source string `json:"source"` Msg string `json:"msg"` @@ -36,7 +37,7 @@ type ClientChan chan Message type IPAddress string -type PriorityStream struct { +type SseStream struct { // Events are pushed to this channel by the main events-gathering routine Message chan Message @@ -52,16 +53,18 @@ type PriorityStream struct { StatusPriority []string Duration time.Duration Start bool + Heat *Heat } // Initialize event and Start procnteessing requests -func NewServer() (sse *PriorityStream) { - sse = &PriorityStream{ +func NewServer() (sse *SseStream) { + sse = &SseStream{ Message: make(chan Message), NewClients: make(chan Client), ClosedClients: make(chan ClientChan), TotalClients: make(map[ClientChan]IPAddress), Start: false, + Heat: &Heat{}, } go sse.listen() @@ -73,7 +76,7 @@ func NewServer() (sse *PriorityStream) { // It Listens all incoming requests from clients. // Handles addition and removal of clients and broadcast messages to clients. -func (stream *PriorityStream) listen() { +func (stream *SseStream) listen() { for { select { // Add new available client @@ -108,7 +111,7 @@ func HeadersMiddleware() gin.HandlerFunc { } } -func (stream *PriorityStream) serveHTTP() gin.HandlerFunc { +func (stream *SseStream) serveHTTP() gin.HandlerFunc { return func(c *gin.Context) { // Initialize client channel clientChan := make(ClientChan) @@ -132,7 +135,7 @@ func (stream *PriorityStream) serveHTTP() gin.HandlerFunc { } } -func (stream *PriorityStream) retvalSSE() gin.HandlerFunc { +func (stream *SseStream) retvalSSE() gin.HandlerFunc { return func(c *gin.Context) { if len(stream.StatusPriority) > 0 { @@ -159,14 +162,14 @@ func (stream *PriorityStream) retvalSSE() gin.HandlerFunc { } } -func (stream *PriorityStream) SendPriority(pri []string) { +func (stream *SseStream) SendPriority(pri []string) { stream.Message <- Message{ Priority: pri, Mode: Priority.String(), } } -func (stream *PriorityStream) timer() { +func (stream *SseStream) timer() { for { if stream.Start { timer := time.NewTimer(stream.Duration) @@ -180,6 +183,7 @@ func (stream *PriorityStream) timer() { } stream.Message <- msg log.Printf("stop timer %+v", stream.Duration) + stream.Heat.Status = "ended" continue default: if len(stream.TotalClients) > 0 { diff --git a/backend/static/_app/version.json b/backend/static/_app/version.json index f1898ad..40ca200 100644 --- a/backend/static/_app/version.json +++ b/backend/static/_app/version.json @@ -1 +1 @@ -{"version":"1702477632110"} \ No newline at end of file +{"version":"1702551352225"} \ No newline at end of file diff --git a/backend/static/_app/version.json.br b/backend/static/_app/version.json.br index df0519c..b214681 100644 Binary files a/backend/static/_app/version.json.br and b/backend/static/_app/version.json.br differ diff --git a/backend/static/_app/version.json.gz b/backend/static/_app/version.json.gz index 49bc444..9175675 100644 Binary files a/backend/static/_app/version.json.gz and b/backend/static/_app/version.json.gz differ diff --git a/backend/static/index.html b/backend/static/index.html index 7938ce7..8d017d3 100644 --- a/backend/static/index.html +++ b/backend/static/index.html @@ -5,17 +5,17 @@ - + - - + +
+ {heat.name} ({heat.number}) {heat.category} + | + {:else if heat.status === 'ended'} ++ {heat.name} ({heat.number}) {heat.category} + | + {:else} ++ {heat.name} ({heat.number}) {heat.category} + | + {/if} +|||
---|---|---|---|---|---|
+ {surfer.name} + | ++ {surfer.color} + | +