Files
kandev/apps/backend/pkg/websocket/message.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

132 lines
3.4 KiB
Go

// Package websocket provides WebSocket message types and protocol definitions.
package websocket
import (
"encoding/json"
"time"
)
// MessageType represents the type of WebSocket message
type MessageType string
const (
MessageTypeRequest MessageType = "request"
MessageTypeResponse MessageType = "response"
MessageTypeNotification MessageType = "notification"
MessageTypeError MessageType = "error"
)
// Message is the base envelope for all WebSocket messages
type Message struct {
ID string `json:"id,omitempty"`
Type MessageType `json:"type"`
Action string `json:"action"`
Payload json.RawMessage `json:"payload"`
Timestamp time.Time `json:"timestamp"`
}
// Request represents a client request message
type Request struct {
ID string `json:"id"`
Type MessageType `json:"type"`
Action string `json:"action"`
Payload json.RawMessage `json:"payload"`
}
// Response represents a server response message
type Response struct {
ID string `json:"id"`
Type MessageType `json:"type"`
Action string `json:"action"`
Payload json.RawMessage `json:"payload,omitempty"`
Timestamp time.Time `json:"timestamp"`
}
// Notification represents a server push notification
type Notification struct {
Type MessageType `json:"type"`
Action string `json:"action"`
Payload json.RawMessage `json:"payload"`
Timestamp time.Time `json:"timestamp"`
}
// ErrorPayload represents an error response payload
type ErrorPayload struct {
Code string `json:"code"`
Message string `json:"message"`
Details map[string]interface{} `json:"details,omitempty"`
}
// NewRequest creates a new request message
func NewRequest(id, action string, payload interface{}) (*Message, error) {
data, err := json.Marshal(payload)
if err != nil {
return nil, err
}
return &Message{
ID: id,
Type: MessageTypeRequest,
Action: action,
Payload: data,
Timestamp: time.Now().UTC(),
}, nil
}
// NewResponse creates a new response message
func NewResponse(id, action string, payload interface{}) (*Message, error) {
data, err := json.Marshal(payload)
if err != nil {
return nil, err
}
return &Message{
ID: id,
Type: MessageTypeResponse,
Action: action,
Payload: data,
Timestamp: time.Now().UTC(),
}, nil
}
// NewNotification creates a new notification message
func NewNotification(action string, payload interface{}) (*Message, error) {
data, err := json.Marshal(payload)
if err != nil {
return nil, err
}
return &Message{
Type: MessageTypeNotification,
Action: action,
Payload: data,
Timestamp: time.Now().UTC(),
}, nil
}
// NewError creates a new error response message
func NewError(id, action, code, message string, details map[string]interface{}) (*Message, error) {
payload := ErrorPayload{
Code: code,
Message: message,
Details: details,
}
data, err := json.Marshal(payload)
if err != nil {
return nil, err
}
return &Message{
ID: id,
Type: MessageTypeError,
Action: action,
Payload: data,
Timestamp: time.Now().UTC(),
}, nil
}
// ParsePayload parses the payload into the given struct
func (m *Message) ParsePayload(v interface{}) error {
if m.Payload == nil {
return nil
}
return json.Unmarshal(m.Payload, v)
}