35915ff0cb
- 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
94 lines
2.2 KiB
Go
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",
|
|
})
|
|
})
|
|
}
|
|
|