mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-06-10 04:10:26 +00:00
bdb60de7ae
- Update go.mod and Dockerfile to Go 1.26 - Apply `go fix ./...` stdlib modernizations across 170+ files - Add `go fix` to post-implementation checklist in CLAUDE.md - Fix go fix misapplied rewrite in loop_history.go
107 lines
3.3 KiB
Go
107 lines
3.3 KiB
Go
// Package protocol defines the wire format for the GoClaw Gateway WebSocket protocol.
|
|
// This package is importable by Service 2 and other clients.
|
|
package protocol
|
|
|
|
import "encoding/json"
|
|
|
|
// Protocol version. Clients must negotiate this during connect handshake.
|
|
const ProtocolVersion = 3
|
|
|
|
// Frame types
|
|
const (
|
|
FrameTypeRequest = "req"
|
|
FrameTypeResponse = "res"
|
|
FrameTypeEvent = "event"
|
|
)
|
|
|
|
// RawFrame is used for initial parsing to determine frame type.
|
|
type RawFrame struct {
|
|
Type string `json:"type"`
|
|
Raw json.RawMessage `json:"-"` // original bytes for re-parsing
|
|
}
|
|
|
|
// RequestFrame is sent by clients to invoke an RPC method.
|
|
type RequestFrame struct {
|
|
Type string `json:"type"` // always "req"
|
|
ID string `json:"id"` // unique request ID (client-generated)
|
|
Method string `json:"method"` // RPC method name
|
|
Params json.RawMessage `json:"params,omitempty"`
|
|
}
|
|
|
|
// ResponseFrame is sent by the server in response to a request.
|
|
type ResponseFrame struct {
|
|
Type string `json:"type"` // always "res"
|
|
ID string `json:"id"` // matches request ID
|
|
OK bool `json:"ok"` // true if success
|
|
Payload any `json:"payload,omitempty"` // response data (when ok=true)
|
|
Error *ErrorShape `json:"error,omitempty"` // error info (when ok=false)
|
|
}
|
|
|
|
// ErrorShape describes a protocol error.
|
|
type ErrorShape struct {
|
|
Code string `json:"code"`
|
|
Message string `json:"message"`
|
|
Details any `json:"details,omitempty"`
|
|
Retryable bool `json:"retryable,omitempty"`
|
|
RetryAfterMs int `json:"retryAfterMs,omitempty"`
|
|
}
|
|
|
|
// EventFrame is pushed from server to client without a preceding request.
|
|
type EventFrame struct {
|
|
Type string `json:"type"` // always "event"
|
|
Event string `json:"event"` // event name
|
|
Payload any `json:"payload,omitempty"` // event data
|
|
Seq int64 `json:"seq,omitempty"` // ordering sequence number
|
|
StateVersion *StateVersion `json:"stateVersion,omitempty"` // version counters for state sync
|
|
}
|
|
|
|
// StateVersion tracks version counters for optimistic state sync.
|
|
type StateVersion struct {
|
|
Presence int64 `json:"presence"`
|
|
Health int64 `json:"health"`
|
|
}
|
|
|
|
// NewOKResponse creates a success response frame.
|
|
func NewOKResponse(id string, payload any) *ResponseFrame {
|
|
return &ResponseFrame{
|
|
Type: FrameTypeResponse,
|
|
ID: id,
|
|
OK: true,
|
|
Payload: payload,
|
|
}
|
|
}
|
|
|
|
// NewErrorResponse creates an error response frame.
|
|
func NewErrorResponse(id string, code, message string) *ResponseFrame {
|
|
return &ResponseFrame{
|
|
Type: FrameTypeResponse,
|
|
ID: id,
|
|
OK: false,
|
|
Error: &ErrorShape{
|
|
Code: code,
|
|
Message: message,
|
|
},
|
|
}
|
|
}
|
|
|
|
// NewEvent creates an event frame.
|
|
func NewEvent(event string, payload any) *EventFrame {
|
|
return &EventFrame{
|
|
Type: FrameTypeEvent,
|
|
Event: event,
|
|
Payload: payload,
|
|
}
|
|
}
|
|
|
|
// ParseFrameType extracts the frame type from raw JSON bytes.
|
|
// Returns the type string and remaining bytes for re-parsing.
|
|
func ParseFrameType(data []byte) (string, error) {
|
|
var raw struct {
|
|
Type string `json:"type"`
|
|
}
|
|
if err := json.Unmarshal(data, &raw); err != nil {
|
|
return "", err
|
|
}
|
|
return raw.Type, nil
|
|
}
|