summaryrefslogtreecommitdiff
path: root/internal/api/websocket.go
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-02-08 21:35:45 -1000
committerPeter Stone <thepeterstone@gmail.com>2026-02-08 21:35:45 -1000
commit2e2b2187b957e9af78797a67ec5c6874615fae02 (patch)
tree1181dbb7e43f5d30cb025fa4d50fd4e7a2c893b3 /internal/api/websocket.go
Initial project: task model, executor, API server, CLI, storage, reporter
Claudomator automation toolkit for Claude Code with: - Task model with YAML parsing, validation, state machine (49 tests, 0 races) - SQLite storage for tasks and executions - Executor pool with bounded concurrency, timeout, cancellation - REST API + WebSocket for mobile PWA integration - Webhook/multi-notifier system - CLI: init, run, serve, list, status commands - Console, JSON, HTML reporters with cost tracking Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'internal/api/websocket.go')
-rw-r--r--internal/api/websocket.go72
1 files changed, 72 insertions, 0 deletions
diff --git a/internal/api/websocket.go b/internal/api/websocket.go
new file mode 100644
index 0000000..6bd8c88
--- /dev/null
+++ b/internal/api/websocket.go
@@ -0,0 +1,72 @@
+package api
+
+import (
+ "log/slog"
+ "net/http"
+ "sync"
+
+ "golang.org/x/net/websocket"
+)
+
+// Hub manages WebSocket connections and broadcasts messages.
+type Hub struct {
+ mu sync.RWMutex
+ clients map[*websocket.Conn]bool
+ logger *slog.Logger
+}
+
+func NewHub() *Hub {
+ return &Hub{
+ clients: make(map[*websocket.Conn]bool),
+ logger: slog.Default(),
+ }
+}
+
+// Run is a no-op loop kept for future cleanup/heartbeat logic.
+func (h *Hub) Run() {}
+
+func (h *Hub) Register(ws *websocket.Conn) {
+ h.mu.Lock()
+ h.clients[ws] = true
+ h.mu.Unlock()
+}
+
+func (h *Hub) Unregister(ws *websocket.Conn) {
+ h.mu.Lock()
+ delete(h.clients, ws)
+ h.mu.Unlock()
+}
+
+// Broadcast sends a message to all connected WebSocket clients.
+func (h *Hub) Broadcast(msg []byte) {
+ h.mu.RLock()
+ defer h.mu.RUnlock()
+ for conn := range h.clients {
+ if _, err := conn.Write(msg); err != nil {
+ h.logger.Error("websocket write error", "error", err)
+ }
+ }
+}
+
+// ClientCount returns the number of connected clients.
+func (h *Hub) ClientCount() int {
+ h.mu.RLock()
+ defer h.mu.RUnlock()
+ return len(h.clients)
+}
+
+func (s *Server) handleWebSocket(w http.ResponseWriter, r *http.Request) {
+ handler := websocket.Handler(func(ws *websocket.Conn) {
+ s.hub.Register(ws)
+ defer s.hub.Unregister(ws)
+
+ // Keep connection alive until client disconnects.
+ buf := make([]byte, 1024)
+ for {
+ if _, err := ws.Read(buf); err != nil {
+ break
+ }
+ }
+ })
+ handler.ServeHTTP(w, r)
+}