Files
kandev/apps/backend/internal/gateway/websocket/handler.go
T
jcfs 35915ff0cb refactor: Replace REST API with WebSocket-only architecture
- Remove all REST endpoints, replace with WebSocket message-based API
- Add WebSocket gateway with Hub and Client for connection management
- Add WebSocket handlers for Task, Agent, and Orchestrator services
- Add task subscription support for real-time ACP notifications
- Update all documentation to reflect WebSocket-first architecture
- Replace docs/openapi.yaml with docs/asyncapi.yaml
- Update e2e tests to use WebSocket via websocat

WebSocket endpoint: ws://localhost:8080/ws
Message format: {id, type, action, payload, timestamp}

Available actions:
- Board: board.list, board.create, board.get, board.update, board.delete
- Column: column.list, column.create, column.get
- Task: task.list, task.create, task.get, task.update, task.delete,
        task.move, task.state, task.subscribe, task.unsubscribe
- Agent: agent.list, agent.launch, agent.status, agent.logs, agent.stop,
         agent.prompt, agent.cancel, agent.session, agent.types
- Orchestrator: orchestrator.status, orchestrator.queue, orchestrator.trigger,
                orchestrator.start, orchestrator.stop, orchestrator.prompt,
                orchestrator.complete
- Health: health.check
2026-01-10 23:01:05 +00:00

94 lines
2.2 KiB
Go

package websocket
import (
"context"
"net/http"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
gorillaws "github.com/gorilla/websocket"
"go.uber.org/zap"
"github.com/kandev/kandev/internal/common/logger"
ws "github.com/kandev/kandev/pkg/websocket"
)
var upgrader = gorillaws.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool {
// TODO: In production, validate origin
return true
},
}
// Handler handles WebSocket connections
type Handler struct {
hub *Hub
logger *logger.Logger
}
// NewHandler creates a new WebSocket handler
func NewHandler(hub *Hub, log *logger.Logger) *Handler {
return &Handler{
hub: hub,
logger: log.WithFields(zap.String("component", "ws_handler")),
}
}
// HandleConnection upgrades HTTP to WebSocket and handles messages
func (h *Handler) HandleConnection(c *gin.Context) {
// Validate token (optional for now)
token := c.Query("token")
if token == "" {
token = c.GetHeader("Authorization")
}
// TODO: Implement proper JWT validation
_ = token
// Upgrade connection to WebSocket
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
h.logger.Error("Failed to upgrade connection", zap.Error(err))
return
}
// Create a unique client ID
clientID := uuid.New().String()
h.logger.Info("WebSocket connection established",
zap.String("client_id", clientID),
zap.String("remote_addr", c.Request.RemoteAddr),
)
// Create client and register with hub
client := NewClient(clientID, conn, h.hub, h.logger)
// Register client with hub
h.hub.Register(client)
// Start read and write pumps
go client.WritePump()
client.ReadPump(c.Request.Context())
}
// SetupRoutes adds the WebSocket route to the router
func SetupRoutes(router *gin.Engine, hub *Hub, log *logger.Logger) {
handler := NewHandler(hub, log)
// Main WebSocket endpoint
router.GET("/ws", handler.HandleConnection)
}
// RegisterHealthHandler registers the health check handler
func RegisterHealthHandler(d *ws.Dispatcher) {
d.RegisterFunc(ws.ActionHealthCheck, func(ctx context.Context, msg *ws.Message) (*ws.Message, error) {
return ws.NewResponse(msg.ID, msg.Action, map[string]interface{}{
"status": "ok",
"service": "kandev",
"mode": "unified",
})
})
}