ResolveSpec/pkg/websocketspec/message.go
2025-12-12 16:14:47 +02:00

241 lines
7.5 KiB
Go

package websocketspec
import (
"encoding/json"
"time"
"github.com/bitechdev/ResolveSpec/pkg/common"
)
// MessageType represents the type of WebSocket message
type MessageType string
const (
// MessageTypeRequest is a client request message
MessageTypeRequest MessageType = "request"
// MessageTypeResponse is a server response message
MessageTypeResponse MessageType = "response"
// MessageTypeNotification is a server-initiated notification
MessageTypeNotification MessageType = "notification"
// MessageTypeSubscription is a subscription control message
MessageTypeSubscription MessageType = "subscription"
// MessageTypeError is an error message
MessageTypeError MessageType = "error"
// MessageTypePing is a keepalive ping message
MessageTypePing MessageType = "ping"
// MessageTypePong is a keepalive pong response
MessageTypePong MessageType = "pong"
)
// OperationType represents the operation to perform
type OperationType string
const (
// OperationRead retrieves records
OperationRead OperationType = "read"
// OperationCreate creates a new record
OperationCreate OperationType = "create"
// OperationUpdate updates an existing record
OperationUpdate OperationType = "update"
// OperationDelete deletes a record
OperationDelete OperationType = "delete"
// OperationSubscribe subscribes to entity changes
OperationSubscribe OperationType = "subscribe"
// OperationUnsubscribe unsubscribes from entity changes
OperationUnsubscribe OperationType = "unsubscribe"
// OperationMeta retrieves metadata about an entity
OperationMeta OperationType = "meta"
)
// Message represents a WebSocket message
type Message struct {
// ID is a unique identifier for request/response correlation
ID string `json:"id,omitempty"`
// Type is the message type
Type MessageType `json:"type"`
// Operation is the operation to perform
Operation OperationType `json:"operation,omitempty"`
// Schema is the database schema name
Schema string `json:"schema,omitempty"`
// Entity is the table/model name
Entity string `json:"entity,omitempty"`
// RecordID is the ID for single-record operations (update, delete, read by ID)
RecordID string `json:"record_id,omitempty"`
// Data contains the request/response payload
Data interface{} `json:"data,omitempty"`
// Options contains query options (filters, sorting, pagination, etc.)
Options *common.RequestOptions `json:"options,omitempty"`
// SubscriptionID is the subscription identifier
SubscriptionID string `json:"subscription_id,omitempty"`
// Success indicates if the operation was successful
Success bool `json:"success,omitempty"`
// Error contains error information
Error *ErrorInfo `json:"error,omitempty"`
// Metadata contains additional response metadata
Metadata map[string]interface{} `json:"metadata,omitempty"`
// Timestamp is when the message was created
Timestamp time.Time `json:"timestamp,omitempty"`
}
// ErrorInfo contains error details
type ErrorInfo struct {
// Code is the error code
Code string `json:"code"`
// Message is a human-readable error message
Message string `json:"message"`
// Details contains additional error context
Details map[string]interface{} `json:"details,omitempty"`
}
// RequestMessage represents a client request
type RequestMessage struct {
ID string `json:"id"`
Type MessageType `json:"type"`
Operation OperationType `json:"operation"`
Schema string `json:"schema,omitempty"`
Entity string `json:"entity"`
RecordID string `json:"record_id,omitempty"`
Data interface{} `json:"data,omitempty"`
Options *common.RequestOptions `json:"options,omitempty"`
}
// ResponseMessage represents a server response
type ResponseMessage struct {
ID string `json:"id"`
Type MessageType `json:"type"`
Success bool `json:"success"`
Data interface{} `json:"data,omitempty"`
Error *ErrorInfo `json:"error,omitempty"`
Metadata map[string]interface{} `json:"metadata,omitempty"`
Timestamp time.Time `json:"timestamp"`
}
// NotificationMessage represents a server-initiated notification
type NotificationMessage struct {
Type MessageType `json:"type"`
Operation OperationType `json:"operation"`
SubscriptionID string `json:"subscription_id"`
Schema string `json:"schema"`
Entity string `json:"entity"`
Data interface{} `json:"data"`
Timestamp time.Time `json:"timestamp"`
}
// SubscriptionMessage represents a subscription control message
type SubscriptionMessage struct {
ID string `json:"id"`
Type MessageType `json:"type"`
Operation OperationType `json:"operation"` // subscribe or unsubscribe
Schema string `json:"schema,omitempty"`
Entity string `json:"entity"`
Options *common.RequestOptions `json:"options,omitempty"` // Filters for subscription
SubscriptionID string `json:"subscription_id,omitempty"` // For unsubscribe
}
// NewRequestMessage creates a new request message
func NewRequestMessage(id string, operation OperationType, schema, entity string) *RequestMessage {
return &RequestMessage{
ID: id,
Type: MessageTypeRequest,
Operation: operation,
Schema: schema,
Entity: entity,
}
}
// NewResponseMessage creates a new response message
func NewResponseMessage(id string, success bool, data interface{}) *ResponseMessage {
return &ResponseMessage{
ID: id,
Type: MessageTypeResponse,
Success: success,
Data: data,
Timestamp: time.Now(),
}
}
// NewErrorResponse creates an error response message
func NewErrorResponse(id string, code, message string) *ResponseMessage {
return &ResponseMessage{
ID: id,
Type: MessageTypeResponse,
Success: false,
Error: &ErrorInfo{
Code: code,
Message: message,
},
Timestamp: time.Now(),
}
}
// NewNotificationMessage creates a new notification message
func NewNotificationMessage(subscriptionID string, operation OperationType, schema, entity string, data interface{}) *NotificationMessage {
return &NotificationMessage{
Type: MessageTypeNotification,
Operation: operation,
SubscriptionID: subscriptionID,
Schema: schema,
Entity: entity,
Data: data,
Timestamp: time.Now(),
}
}
// ParseMessage parses a JSON message into a Message struct
func ParseMessage(data []byte) (*Message, error) {
var msg Message
if err := json.Unmarshal(data, &msg); err != nil {
return nil, err
}
return &msg, nil
}
// ToJSON converts a message to JSON bytes
func (m *Message) ToJSON() ([]byte, error) {
return json.Marshal(m)
}
// ToJSON converts a response message to JSON bytes
func (r *ResponseMessage) ToJSON() ([]byte, error) {
return json.Marshal(r)
}
// ToJSON converts a notification message to JSON bytes
func (n *NotificationMessage) ToJSON() ([]byte, error) {
return json.Marshal(n)
}
// IsValid checks if a message is valid
func (m *Message) IsValid() bool {
// Type must be set
if m.Type == "" {
return false
}
// Request messages must have an ID, operation, and entity
if m.Type == MessageTypeRequest {
return m.ID != "" && m.Operation != "" && m.Entity != ""
}
// Subscription messages must have an ID and operation
if m.Type == MessageTypeSubscription {
return m.ID != "" && m.Operation != ""
}
return true
}