simon 0767ddac38 Big Gotool Refactoring
- Added Event Bus
- Reworked Package Parsing
- Rewokred Frame Parsing
2026-01-27 16:23:51 +01:00

103 lines
2.1 KiB
Go

package frontend
import (
"context"
"embed"
"io/fs"
"log"
"net/http"
"time"
"alox.tool/api"
"alox.tool/eventbus"
"github.com/gorilla/websocket"
)
//go:embed www
var staticFiles embed.FS
var upgrader = websocket.Upgrader{}
type FServer struct {
bus eventbus.EventBus
mux *http.ServeMux
}
func New(bus eventbus.EventBus) *FServer {
fsrv := &FServer{
bus: bus,
mux: http.NewServeMux(),
}
fsrv.routes()
return fsrv
}
func (fsrv *FServer) routes() {
// Statische Dateien aus dem Embed-FS
// "www" Präfix entfernen, damit index.html unter / verfügbar ist
root, _ := fs.Sub(staticFiles, "www")
fsrv.mux.Handle("/", http.FileServer(http.FS(root)))
// WebSocket Endpunkt
fsrv.mux.HandleFunc("/ws", fsrv.handleWS)
}
func (fsrv *FServer) handleWS(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Printf("Upgrade error: %v", err)
return
}
defer conn.Close()
// Kanäle für die Hardware-Events abonnieren
rxChan := fsrv.bus.Subscribe(api.TopicUARTRx)
txChan := fsrv.bus.Subscribe(api.TopicUARTTx)
// Context nutzen, um Goroutinen zu stoppen, wenn die Verbindung abreißt
ctx, cancel := context.WithCancel(r.Context())
defer cancel()
// WRITER: Send Events to Browser
go func() {
for {
select {
case <-ctx.Done():
return
case f := <-rxChan:
if err := conn.WriteJSON(map[string]any{"type": "rx", "frame": f}); err != nil {
return
}
case f := <-txChan:
if err := conn.WriteJSON(map[string]any{"type": "tx", "frame": f}); err != nil {
return
}
}
}
}()
// READER: Commands from Browser
for {
var cmd api.FrontendCmd
if err := conn.ReadJSON(&cmd); err != nil {
log.Printf("WS Read Error: %v", err)
break
}
fsrv.bus.Publish(api.TopicFrontendCmd, cmd)
log.Printf("Browser Action: %s auf ID 0x%02X", cmd.Action, cmd.ID)
}
}
func (fsrv *FServer) Start(addr string) error {
server := &http.Server{
Addr: addr,
Handler: fsrv.mux,
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
}
log.Printf("Frontend Server gestartet auf %s", addr)
return server.ListenAndServe()
}