=setup: add heats
=priority: load heats
This commit is contained in:
Miki 2023-12-14 12:17:23 +01:00
parent 50a1d74e65
commit c6f4800273
16 changed files with 436 additions and 146 deletions

View file

@ -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)

Binary file not shown.

179
backend/heats.go Normal file
View file

@ -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
}

View file

@ -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)

View file

@ -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)
}
}

View file

@ -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 {

View file

@ -1 +1 @@
{"version":"1702477632110"}
{"version":"1702551352225"}

Binary file not shown.

Binary file not shown.

View file

@ -5,17 +5,17 @@
<link rel="icon" href="/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="modulepreload" href="/_app/immutable/entry/start.f2f23bb5.js">
<link rel="modulepreload" href="/_app/immutable/entry/start.99d6dd70.js">
<link rel="modulepreload" href="/_app/immutable/chunks/scheduler.d1a939e8.js">
<link rel="modulepreload" href="/_app/immutable/chunks/singletons.f3cb4e26.js">
<link rel="modulepreload" href="/_app/immutable/entry/app.c3a1467b.js">
<link rel="modulepreload" href="/_app/immutable/chunks/singletons.2b3a0a27.js">
<link rel="modulepreload" href="/_app/immutable/entry/app.3faab5fc.js">
<link rel="modulepreload" href="/_app/immutable/chunks/index.994dd985.js">
</head>
<body data-sveltekit-preload-data="hover">
<div style="display: contents">
<script>
{
__sveltekit_1cx8eia = {
__sveltekit_1lbm7l = {
base: "",
env: {}
};
@ -23,8 +23,8 @@
const element = document.currentScript.parentElement;
Promise.all([
import("/_app/immutable/entry/start.f2f23bb5.js"),
import("/_app/immutable/entry/app.c3a1467b.js")
import("/_app/immutable/entry/start.99d6dd70.js"),
import("/_app/immutable/entry/app.3faab5fc.js")
]).then(([kit, app]) => {
kit.start(app, element);
});

Binary file not shown.

Binary file not shown.

View file

@ -10,7 +10,7 @@ import (
type Webapp struct {
Engine *gin.Engine
Stream *PriorityStream
Stream *SseStream
DB *scribble.Driver
}
@ -44,6 +44,9 @@ func InitHttp(d *scribble.Driver) *Webapp {
setup := router.Group("/setup")
setup.Static("/", "./static/setup")
draws := router.Group("/draws")
draws.Static("/", "./static/draws")
sapp := router.Group("/_app")
sapp.Static("/", "./static/_app")