diff --git a/examples/main.go b/examples/main.go index 6cb157a..5b23e2b 100644 --- a/examples/main.go +++ b/examples/main.go @@ -39,15 +39,19 @@ func main() { var wg sync.WaitGroup - // Create a fan-out mechanism for events - eventBroadcaster := make(chan derby.Event, 10) + // Create multiple event channels for fan-out + terminalEvents := make(chan derby.Event, 10) + webEvents := make(chan derby.Event, 10) - // Start the event broadcaster + // Start the event broadcaster with fan-out to multiple channels go func() { for event := range clock.Events() { - eventBroadcaster <- event + // Clone the event to both channels + terminalEvents <- event + webEvents <- event } - close(eventBroadcaster) + close(terminalEvents) + close(webEvents) }() // Create a context for graceful shutdown @@ -59,7 +63,7 @@ func main() { wg.Add(1) go func() { defer wg.Done() - startWebInterface(clock, eventBroadcaster, *webPort, ctx) + startWebInterface(clock, webEvents, *webPort, ctx) }() } @@ -68,7 +72,7 @@ func main() { wg.Add(1) go func() { defer wg.Done() - startTerminalInterface(clock, eventBroadcaster, ctx) + startTerminalInterface(clock, terminalEvents, ctx) }() } diff --git a/web/server.go b/web/server.go index e4156d3..8348778 100644 --- a/web/server.go +++ b/web/server.go @@ -3,6 +3,7 @@ package web import ( "context" "embed" + "encoding/json" "fmt" "io/fs" "net/http" @@ -136,27 +137,52 @@ func (s *Server) forwardEvents() { // broadcastEvent sends an event to all connected clients func (s *Server) broadcastEvent(event derby.Event) { var message string + switch event.Type { case derby.EventRaceStart: - message = "event: race-start\ndata: {\"status\": \"running\"}\n\n" + statusMsg := struct { + Status string `json:"status"` + }{ + Status: "running", + } + statusJSON, _ := json.Marshal(statusMsg) + message = fmt.Sprintf("event: status\ndata: %s", statusJSON) case derby.EventLaneFinish: - result := event.Result - message = fmt.Sprintf("event: lane-finish\ndata: {\"lane\": %d, \"place\": %d, \"time\": %.4f}\n\n", - result.Lane, result.FinishPlace, result.Time) + // Create a message for lane finish + laneData := struct { + Lane int `json:"lane"` + Time float64 `json:"time"` + Place int `json:"place"` + }{ + Lane: event.Result.Lane, + Time: event.Result.Time, + Place: event.Result.FinishPlace, + } + laneJSON, _ := json.Marshal(laneData) + message = fmt.Sprintf("event: lane-finish\ndata: %s", laneJSON) case derby.EventRaceComplete: - message = "event: race-complete\ndata: {\"status\": \"finished\"}\n\n" + statusMsg := struct { + Status string `json:"status"` + }{ + Status: "finished", + } + statusJSON, _ := json.Marshal(statusMsg) + message = fmt.Sprintf("event: status\ndata: %s", statusJSON) + } + + if message == "" { + return } // Send to all clients s.clientsMux.Lock() for clientChan := range s.clients { - // Non-blocking send to avoid slow clients blocking others select { case clientChan <- message: default: - // Client channel is full, could log this or take other action + // Client channel is full, could log this } } s.clientsMux.Unlock() diff --git a/web/templates/index.templ b/web/templates/index.templ index 1bafc1b..e9c2bfd 100644 --- a/web/templates/index.templ +++ b/web/templates/index.templ @@ -45,6 +45,7 @@ templ Index() { const eventSource = new EventSource('/api/events'); eventSource.addEventListener('lane-finish', function(event) { + console.log("Lane finish event received:", event.data); const laneFinishData = JSON.parse(event.data); const lane = document.getElementById(`lane-${laneFinishData.lane}`); if (lane) { diff --git a/web/templates/index_templ.go b/web/templates/index_templ.go index 0debac7..427a0b0 100644 --- a/web/templates/index_templ.go +++ b/web/templates/index_templ.go @@ -37,7 +37,7 @@ func Index() templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "