|
|
|
|
@ -2,6 +2,7 @@ package main
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bufio"
|
|
|
|
|
"context"
|
|
|
|
|
"flag"
|
|
|
|
|
"fmt"
|
|
|
|
|
"os"
|
|
|
|
|
@ -49,12 +50,16 @@ func main() {
|
|
|
|
|
close(eventBroadcaster)
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
// Create a context for graceful shutdown
|
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
|
|
// Start web interface if enabled
|
|
|
|
|
if !*noWeb {
|
|
|
|
|
wg.Add(1)
|
|
|
|
|
go func() {
|
|
|
|
|
defer wg.Done()
|
|
|
|
|
startWebInterface(clock, eventBroadcaster, *webPort, sigChan)
|
|
|
|
|
startWebInterface(clock, eventBroadcaster, *webPort, ctx)
|
|
|
|
|
}()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -63,26 +68,30 @@ func main() {
|
|
|
|
|
wg.Add(1)
|
|
|
|
|
go func() {
|
|
|
|
|
defer wg.Done()
|
|
|
|
|
startTerminalInterface(clock, eventBroadcaster, sigChan)
|
|
|
|
|
startTerminalInterface(clock, eventBroadcaster, ctx)
|
|
|
|
|
}()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Wait for signal to exit
|
|
|
|
|
<-sigChan
|
|
|
|
|
fmt.Println("Shutting down...")
|
|
|
|
|
time.Sleep(500 * time.Millisecond) // Give a moment for any pending operations to complete
|
|
|
|
|
|
|
|
|
|
// Cancel context to signal all components to shut down
|
|
|
|
|
cancel()
|
|
|
|
|
|
|
|
|
|
// Give a moment for any pending operations to complete
|
|
|
|
|
time.Sleep(500 * time.Millisecond)
|
|
|
|
|
|
|
|
|
|
// Wait for all interfaces to shut down
|
|
|
|
|
wg.Wait()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// startWebInterface initializes and runs the web interface
|
|
|
|
|
func startWebInterface(clock *derby.DerbyClock, events <-chan derby.Event, webPort int, sigChan chan os.Signal) {
|
|
|
|
|
func startWebInterface(clock *derby.DerbyClock, events <-chan derby.Event, webPort int, ctx context.Context) {
|
|
|
|
|
// Create and start the web server
|
|
|
|
|
server, err := web.NewServer(clock, events, webPort)
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Printf("Error creating web server: %v\n", err)
|
|
|
|
|
sigChan <- syscall.SIGTERM
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -91,18 +100,26 @@ func startWebInterface(clock *derby.DerbyClock, events <-chan derby.Event, webPo
|
|
|
|
|
// Start the web server
|
|
|
|
|
if err := server.Start(); err != nil {
|
|
|
|
|
fmt.Printf("Web server error: %v\n", err)
|
|
|
|
|
sigChan <- syscall.SIGTERM
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Wait for context cancellation
|
|
|
|
|
<-ctx.Done()
|
|
|
|
|
|
|
|
|
|
// Gracefully shut down the server
|
|
|
|
|
fmt.Println("Shutting down web server...")
|
|
|
|
|
if err := server.Stop(); err != nil {
|
|
|
|
|
fmt.Printf("Error shutting down web server: %v\n", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// startTerminalInterface initializes and runs the terminal interface
|
|
|
|
|
func startTerminalInterface(clock *derby.DerbyClock, events <-chan derby.Event, sigChan chan os.Signal) {
|
|
|
|
|
func startTerminalInterface(clock *derby.DerbyClock, events <-chan derby.Event, ctx context.Context) {
|
|
|
|
|
fmt.Println("Terminal interface started")
|
|
|
|
|
|
|
|
|
|
// Reset the clock to start fresh
|
|
|
|
|
if err := clock.Reset(); err != nil {
|
|
|
|
|
fmt.Printf("Error resetting clock: %v\n", err)
|
|
|
|
|
sigChan <- syscall.SIGTERM
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
fmt.Println("Clock reset. Ready to start race.")
|
|
|
|
|
@ -117,7 +134,12 @@ func startTerminalInterface(clock *derby.DerbyClock, events <-chan derby.Event,
|
|
|
|
|
// Process events from the clock
|
|
|
|
|
go func() {
|
|
|
|
|
raceResults := make([]*derby.Result, 0)
|
|
|
|
|
for event := range events {
|
|
|
|
|
for {
|
|
|
|
|
select {
|
|
|
|
|
case event, ok := <-events:
|
|
|
|
|
if !ok {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
switch event.Type {
|
|
|
|
|
case derby.EventRaceStart:
|
|
|
|
|
fmt.Println("\n🏁 Race started!")
|
|
|
|
|
@ -137,12 +159,19 @@ func startTerminalInterface(clock *derby.DerbyClock, events <-chan derby.Event,
|
|
|
|
|
fmt.Println("\nEnter command (r/f/q/?):")
|
|
|
|
|
raceResults = nil
|
|
|
|
|
}
|
|
|
|
|
case <-ctx.Done():
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
// Handle keyboard input
|
|
|
|
|
reader := bufio.NewReader(os.Stdin)
|
|
|
|
|
for {
|
|
|
|
|
select {
|
|
|
|
|
case <-ctx.Done():
|
|
|
|
|
return
|
|
|
|
|
default:
|
|
|
|
|
fmt.Print("Enter command (r/f/q/?): ")
|
|
|
|
|
input, err := reader.ReadString('\n')
|
|
|
|
|
if err != nil {
|
|
|
|
|
@ -170,7 +199,6 @@ func startTerminalInterface(clock *derby.DerbyClock, events <-chan derby.Event,
|
|
|
|
|
|
|
|
|
|
case "q":
|
|
|
|
|
fmt.Println("Quitting...")
|
|
|
|
|
sigChan <- syscall.SIGTERM
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
case "?":
|
|
|
|
|
@ -187,3 +215,4 @@ func startTerminalInterface(clock *derby.DerbyClock, events <-chan derby.Event,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|