Documentation
¶
Index ¶
- Constants
- Variables
- func ExampleProtocol()
- func GenerateSessionID() string
- func ParseOperationData(data interface{}) ([]interface{}, error)
- func TestEditSession(t *testing.T)
- func TestParseOperationData(t *testing.T)
- func TestProtocolMessages(t *testing.T)
- func TestSessionManager(t *testing.T)
- func TestSessionRefCount(t *testing.T)
- type AckData
- type ApplyPatchResult
- type BaseTransport
- type ClientInfo
- type ContentStorage
- type CursorData
- type DocumentSubscription
- func (s *DocumentSubscription) OnError(handler func(*ErrorData))
- func (s *DocumentSubscription) OnOperation(handler func(*RemoteOperationData))
- func (s *DocumentSubscription) OnRemoteOperation(handler func(*RemoteOperationData))
- func (s *DocumentSubscription) OnSessionInfo(handler func(*SessionInfoData))
- func (s *DocumentSubscription) OnSnapshot(handler func(*SnapshotData))
- func (s *DocumentSubscription) OnUserJoined(handler func(*UserJoinedData))
- func (s *DocumentSubscription) OnUserLeft(handler func(*UserLeftData))
- func (s *DocumentSubscription) StartMessageHandler(transport *MultiDocWebSocketTransport)
- type EditSession
- func (es *EditSession) AddClient(clientID string, client *SessionClient)
- func (es *EditSession) AddOperation(operation interface{}, clientID string) error
- func (es *EditSession) GetClient(clientID string) *SessionClient
- func (es *EditSession) GetClientInfos() []ClientInfo
- func (es *EditSession) GetContent() string
- func (es *EditSession) GetCurrentVersion() int64
- func (es *EditSession) GetRecentOperations() []interface{}
- func (es *EditSession) GetSessionInfo() *SessionInfo
- func (es *EditSession) GetSnapshotInfo() *SnapshotInfo
- func (es *EditSession) GetSnapshotVersion() int64
- func (es *EditSession) RemoveClient(clientID string) *SessionClient
- func (es *EditSession) SetContent(content string)
- func (es *EditSession) SetHistoryListener(listener HistoryListener)
- func (es *EditSession) SetMaxChangesBeforeSnapshot(max int)
- func (es *EditSession) SetMaxSnapshotInterval(interval int64)
- type ErrorData
- type HeartbeatData
- type HistoryEvent
- type HistoryListener
- type HistoryOptions
- type HistoryService
- type LegacyMessageType
- type MemoryHistoryService
- func (s *MemoryHistoryService) Close() error
- func (s *MemoryHistoryService) GetSessionHistory(ctx context.Context, sessionID string, limit int64) ([]*HistoryEvent, error)
- func (s *MemoryHistoryService) GetSnapshot(ctx context.Context, sessionID string, versionID int64) (*HistoryEvent, error)
- func (s *MemoryHistoryService) ListSnapshots(ctx context.Context, sessionID string) ([]*SnapshotInfo, error)
- func (s *MemoryHistoryService) OnOperation(event *HistoryEvent) error
- func (s *MemoryHistoryService) OnSnapshot(event *HistoryEvent) error
- func (s *MemoryHistoryService) ReconstructSnapshot(ctx context.Context, sessionID string, targetVersionID int64) (string, error)
- type MemoryTransport
- type Message
- func NewAckMessage(docID, clientID string) *Message
- func NewErrorMessage(docID string, err error) *Message
- func NewOperationMessage(docID, clientID string, op *ot.Operation) *Message
- func NewSyncAckMessage(docID string, content string, version int64) *Message
- func NewSyncMessage(docID, clientID string, version int64) *Message
- type MessageType
- type MiniRedis
- func (m *MiniRedis) Close() error
- func (m *MiniRedis) Get(key string) (string, error)
- func (m *MiniRedis) GetData() map[string]string
- func (m *MiniRedis) GetLists() map[string][]string
- func (m *MiniRedis) LPush(key string, values ...interface{}) error
- func (m *MiniRedis) LRange(key string, start, stop int64) ([]string, error)
- func (m *MiniRedis) Publish(channel string, message interface{}) error
- func (m *MiniRedis) Set(key string, value interface{}, ttl time.Duration) error
- func (m *MiniRedis) Subscribe(channel string) <-chan string
- type MultiDocWebSocketTransport
- func (t *MultiDocWebSocketTransport) Close() error
- func (t *MultiDocWebSocketTransport) Connect(ctx context.Context) error
- func (t *MultiDocWebSocketTransport) GetSubscription(docPath string) (*DocumentSubscription, bool)
- func (t *MultiDocWebSocketTransport) IsConnected() bool
- func (t *MultiDocWebSocketTransport) ListSubscriptions() []string
- func (t *MultiDocWebSocketTransport) SendHeartbeat(sessionIDs []string) error
- func (t *MultiDocWebSocketTransport) SendOperation(docPath string, operation []interface{}) error
- func (t *MultiDocWebSocketTransport) SendOperationWithContext(ctx context.Context, docPath string, operation []interface{}) error
- func (t *MultiDocWebSocketTransport) SetMessageHandler(handler TransportMessageHandler)
- func (t *MultiDocWebSocketTransport) Subscribe(docPath string) (*DocumentSubscription, error)
- func (t *MultiDocWebSocketTransport) Unsubscribe(docPath string) error
- type OperationData
- type PatchManager
- func (pm *PatchManager) ApplyPatch(oldText, patchText string) *ApplyPatchResult
- func (pm *PatchManager) ComputeDiff(oldText, newText string) []diffmatchpatch.Diff
- func (pm *PatchManager) ComputeDiffCleanup(oldText, newText string, cleanup bool) []diffmatchpatch.Diff
- func (pm *PatchManager) ComputePatch(oldText, newText string) *PatchResult
- func (pm *PatchManager) CreateRollbackPatch(originalText, appliedPatchText string) string
- func (pm *PatchManager) GetPatchStats(patchText string) *PatchStats
- func (pm *PatchManager) PrettyPrintDiff(diffs []diffmatchpatch.Diff) string
- type PatchResult
- type PatchStats
- type ProtocolHandler
- type ProtocolMessage
- type RedisClient
- type RedisHistoryService
- func (s *RedisHistoryService) Close() error
- func (s *RedisHistoryService) GetSessionHistory(ctx context.Context, sessionID string, limit int64) ([]*HistoryEvent, error)
- func (s *RedisHistoryService) GetSnapshot(ctx context.Context, sessionID string, versionID int64) (*HistoryEvent, error)
- func (s *RedisHistoryService) ListSnapshots(ctx context.Context, sessionID string) ([]*SnapshotInfo, error)
- func (s *RedisHistoryService) OnOperation(event *HistoryEvent) error
- func (s *RedisHistoryService) OnSnapshot(event *HistoryEvent) error
- func (s *RedisHistoryService) ReconstructSnapshot(ctx context.Context, sessionID string, targetVersionID int64) (string, error)
- type RemoteOperationData
- type SSEClient
- type SSEServer
- type SSETransport
- type SessionClient
- type SessionInfo
- type SessionInfoData
- type SessionManager
- func (sm *SessionManager) DestroySession(sessionID string)
- func (sm *SessionManager) GetOrCreateSession(filePath string) (*EditSession, bool)
- func (sm *SessionManager) GetSession(sessionID string) *EditSession
- func (sm *SessionManager) GetSessionByPath(filePath string) *EditSession
- func (sm *SessionManager) ListSessions() []*EditSession
- func (sm *SessionManager) SetContentStorage(storage ContentStorage)
- func (sm *SessionManager) SetHistoryListener(listener HistoryListener)
- type SessionRefCount
- type SnapshotCreatedData
- type SnapshotData
- type SnapshotInfo
- type StartEditingData
- type StopEditingData
- type SubscribeData
- type TCPServer
- type TCPTransport
- type Transport
- type TransportError
- type TransportMessageHandler
- type UnsubscribeData
- type UserJoinedData
- type UserLeftData
- type WebSocketConn
- type WebSocketServer
- func (s *WebSocketServer) Broadcast(msg *Message)
- func (s *WebSocketServer) Close() error
- func (s *WebSocketServer) RegisterHandler(mux *http.ServeMux)
- func (s *WebSocketServer) Send(clientID string, msg *Message) error
- func (s *WebSocketServer) SendJSON(clientID string, data []byte) error
- func (s *WebSocketServer) SetMessageHandler(handler func(*Message))
- func (s *WebSocketServer) SetRawMessageHandler(handler func(clientID string, message []byte))
- func (s *WebSocketServer) Start(ctx context.Context) error
- type WebSocketTransport
- type WelcomeData
Constants ¶
const ( // DefaultMaxChangesBeforeSnapshot is the default max changes before creating a new snapshot. DefaultMaxChangesBeforeSnapshot = 200 // DefaultMaxSnapshotInterval is the default max time between snapshots (5 minutes) DefaultMaxSnapshotInterval = 300 // 5 minutes = 300 seconds )
Variables ¶
var ( // ErrTransportClosed is returned when the transport is closed. ErrTransportClosed = &TransportError{Code: "closed", Message: "transport closed"} // ErrSendFailed is returned when sending a message fails. ErrSendFailed = &TransportError{Code: "send_failed", Message: "failed to send message"} // ErrReceiveFailed is returned when receiving a message fails. ErrReceiveFailed = &TransportError{Code: "receive_failed", Message: "failed to receive message"} )
Functions ¶
func ExampleProtocol ¶
func ExampleProtocol()
ExampleProtocol demonstrates the WebSocket protocol usage.
func GenerateSessionID ¶
func GenerateSessionID() string
GenerateSessionID generates a new UUID for edit session.
func ParseOperationData ¶
func ParseOperationData(data interface{}) ([]interface{}, error)
ParseOperationData parses OT operation from JSON.
func TestEditSession ¶
TestEditSession tests edit session operations.
func TestParseOperationData ¶
TestParseOperationData tests parsing OT operations from different formats.
func TestProtocolMessages ¶
TestProtocolMessages tests protocol message creation.
func TestSessionManager ¶
TestSessionManager tests session management.
func TestSessionRefCount ¶
TestSessionRefCount tests reference counting logic.
Types ¶
type AckData ¶
type AckData struct {
SessionID string `json:"session_id"` // Edit session UUID
Revision int64 `json:"revision"` // Acknowledged revision
Timestamp int64 `json:"timestamp"`
}
AckData represents acknowledgment data.
type ApplyPatchResult ¶
type ApplyPatchResult struct {
Content string // Reconstructed content
Success bool // Whether patch application succeeded
PatchesApplied int // Number of patches applied
}
ApplyPatchResult represents the result of applying a patch.
type BaseTransport ¶
type BaseTransport struct {
// contains filtered or unexported fields
}
BaseTransport provides common functionality for transport implementations.
func NewBaseTransport ¶
func NewBaseTransport(id, clientID, docID string) *BaseTransport
NewBaseTransport creates a new base transport.
func (*BaseTransport) IsConnected ¶
func (t *BaseTransport) IsConnected() bool
IsConnected returns true if the transport is connected.
func (*BaseTransport) Receive ¶
func (t *BaseTransport) Receive() <-chan *Message
Receive returns a channel for receiving messages.
type ClientInfo ¶
type ClientInfo struct {
ClientID string `json:"client_id"`
Name string `json:"name,omitempty"`
Color string `json:"color,omitempty"`
IsEditing bool `json:"is_editing"` // Whether this client is editing (vs just viewing)
Selection *CursorData `json:"selection,omitempty"`
UpdatedAt int64 `json:"updated_at"`
}
ClientInfo represents information about a connected client.
type ContentStorage ¶
type ContentStorage interface {
Get(ctx context.Context, contentPath string, options *session.GetOptions) (*session.ContentModel, error)
}
ContentStorage interface for loading file contents.
type CursorData ¶
CursorData represents cursor/selection data.
type DocumentSubscription ¶
type DocumentSubscription struct {
DocPath string
SessionID string
ReadOnly bool
// contains filtered or unexported fields
}
DocumentSubscription represents a subscription to a document.
func (*DocumentSubscription) OnError ¶
func (s *DocumentSubscription) OnError(handler func(*ErrorData))
OnError sets a handler for errors.
func (*DocumentSubscription) OnOperation ¶
func (s *DocumentSubscription) OnOperation(handler func(*RemoteOperationData))
OnOperation sets a handler for operations from the current client.
func (*DocumentSubscription) OnRemoteOperation ¶
func (s *DocumentSubscription) OnRemoteOperation(handler func(*RemoteOperationData))
OnRemoteOperation sets a handler for operations from other clients.
func (*DocumentSubscription) OnSessionInfo ¶
func (s *DocumentSubscription) OnSessionInfo(handler func(*SessionInfoData))
OnSessionInfo sets a handler for session info updates.
func (*DocumentSubscription) OnSnapshot ¶
func (s *DocumentSubscription) OnSnapshot(handler func(*SnapshotData))
OnSnapshot sets a handler for snapshot updates.
func (*DocumentSubscription) OnUserJoined ¶
func (s *DocumentSubscription) OnUserJoined(handler func(*UserJoinedData))
OnUserJoined sets a handler for user joined events.
func (*DocumentSubscription) OnUserLeft ¶
func (s *DocumentSubscription) OnUserLeft(handler func(*UserLeftData))
OnUserLeft sets a handler for user left events.
func (*DocumentSubscription) StartMessageHandler ¶
func (s *DocumentSubscription) StartMessageHandler(transport *MultiDocWebSocketTransport)
StartMessageHandler starts a goroutine to handle messages for this subscription.
type EditSession ¶
type EditSession struct {
SessionID string // UUID
FilePath string // File path
RefCount *SessionRefCount // Reader/Writer counts
CreatedAt int64 // Session creation time
UpdatedAt int64 // Last update time
Clients map[string]*SessionClient // Connected clients (clientID -> client)
// contains filtered or unexported fields
}
EditSession represents an active editing session for a file. Only keeps: 1 snapshot + recent changes (older history forwarded to Redis).
func NewEditSession ¶
func NewEditSession(sessionID, filePath string, initialContent string) *EditSession
NewEditSession creates a new edit session with snapshot + changes structure.
func (*EditSession) AddClient ¶
func (es *EditSession) AddClient(clientID string, client *SessionClient)
AddClient adds a client to the session.
func (*EditSession) AddOperation ¶
func (es *EditSession) AddOperation(operation interface{}, clientID string) error
AddOperation adds an operation to recent changes and forwards to history listener.
func (*EditSession) GetClient ¶
func (es *EditSession) GetClient(clientID string) *SessionClient
GetClient retrieves a client by ID.
func (*EditSession) GetClientInfos ¶
func (es *EditSession) GetClientInfos() []ClientInfo
GetClientInfos returns information about all connected clients.
func (*EditSession) GetContent ¶
func (es *EditSession) GetContent() string
GetContent returns the current document content (from snapshot).
func (*EditSession) GetCurrentVersion ¶
func (es *EditSession) GetCurrentVersion() int64
GetCurrentVersion returns the current version number.
func (*EditSession) GetRecentOperations ¶
func (es *EditSession) GetRecentOperations() []interface{}
GetRecentOperations returns recent operations since last snapshot.
func (*EditSession) GetSessionInfo ¶
func (es *EditSession) GetSessionInfo() *SessionInfo
GetSessionInfo returns information about the session.
func (*EditSession) GetSnapshotInfo ¶
func (es *EditSession) GetSnapshotInfo() *SnapshotInfo
GetSnapshotInfo returns information about snapshot status.
func (*EditSession) GetSnapshotVersion ¶
func (es *EditSession) GetSnapshotVersion() int64
GetSnapshotVersion returns the current snapshot version ID.
func (*EditSession) RemoveClient ¶
func (es *EditSession) RemoveClient(clientID string) *SessionClient
RemoveClient removes a client from the session.
func (*EditSession) SetContent ¶
func (es *EditSession) SetContent(content string)
SetContent sets the current document content and updates snapshot.
func (*EditSession) SetHistoryListener ¶
func (es *EditSession) SetHistoryListener(listener HistoryListener)
SetHistoryListener sets the history listener for forwarding to Redis.
func (*EditSession) SetMaxChangesBeforeSnapshot ¶
func (es *EditSession) SetMaxChangesBeforeSnapshot(max int)
SetMaxChangesBeforeSnapshot sets the max changes before creating a new snapshot.
func (*EditSession) SetMaxSnapshotInterval ¶
func (es *EditSession) SetMaxSnapshotInterval(interval int64)
SetMaxSnapshotInterval sets the max time interval between snapshots (in seconds).
type ErrorData ¶
type ErrorData struct {
SessionID string `json:"session_id,omitempty"`
Code string `json:"code"` // Error code
Message string `json:"message"` // Human-readable message
Details map[string]interface{} `json:"details,omitempty"`
}
ErrorData represents error data.
type HeartbeatData ¶
type HeartbeatData struct {
SessionIDs []string `json:"session_ids"` // All sessions client is subscribed to
}
HeartbeatData represents heartbeat data.
type HistoryEvent ¶
type HistoryEvent struct {
SessionID string `json:"session_id"`
FilePath string `json:"file_path"`
EventType string `json:"event_type"` // "snapshot" or "operation"
VersionID int64 `json:"version_id"`
Content string `json:"content,omitempty"` // Full content for snapshot
Operations []interface{} `json:"operations,omitempty"` // OT operations
CreatedAt int64 `json:"created_at"`
CreatedBy string `json:"created_by"`
Metadata map[string]interface{} `json:"metadata,omitempty"` // Additional metadata (patches, etc.)
}
HistoryEvent represents a history event that can be sent to Redis/History service.
type HistoryListener ¶
type HistoryListener interface {
// OnSnapshot is called when a new snapshot is created.
OnSnapshot(event *HistoryEvent) error
// OnOperation is called when a new operation is applied.
OnOperation(event *HistoryEvent) error
// Close closes the history listener.
Close() error
}
HistoryListener listens to edit session events and forwards to Redis/History service.
type HistoryOptions ¶
type HistoryOptions struct {
// UsePatchMode enables diff-match-patch for efficient storage.
// When true, stores only patches between versions (like HedgeDoc).
// When false, stores full content for each version (simpler, more storage).
UsePatchMode bool
// MaxChangesBeforeSnapshot triggers snapshot creation after N operations.
// Default: 200 operations.
MaxChangesBeforeSnapshot int
// MaxSnapshotInterval triggers snapshot creation after N seconds of inactivity.
// Default: 300 seconds (5 minutes).
MaxSnapshotInterval int64
// StorageBackend specifies which storage backend to use.
// Options: "redis", "memory", "database"
StorageBackend string
// RedisAddr specifies Redis server address (if using Redis backend).
RedisAddr string
// RedisPassword specifies Redis password (if required).
RedisPassword string
// RedisDB specifies Redis database number.
RedisDB int
}
HistoryOptions specifies options for creating a history service.
type HistoryService ¶
type HistoryService interface {
// OnSnapshot handles snapshot events from edit sessions.
// Called when a new snapshot is created (either by operation count or timeout).
OnSnapshot(event *HistoryEvent) error
// OnOperation handles operation events from edit sessions.
// Called for each OT operation applied to a document.
OnOperation(event *HistoryEvent) error
// GetSnapshot retrieves a specific snapshot from storage.
// Returns the HistoryEvent with content and metadata for the given version.
GetSnapshot(ctx context.Context, sessionID string, versionID int64) (*HistoryEvent, error)
// GetSessionHistory retrieves history for a session from storage.
// Returns up to `limit` most recent events (snapshots and operations).
GetSessionHistory(ctx context.Context, sessionID string, limit int64) ([]*HistoryEvent, error)
// ReconstructSnapshot reconstructs the content of a specific version.
// Necessary when using patch mode, where only the first snapshot has full content.
// Starting from version 0, applies all patches up to the target version.
ReconstructSnapshot(ctx context.Context, sessionID string, targetVersionID int64) (string, error)
// ListSnapshots lists all snapshots for a session.
// Returns metadata for each snapshot (version, time, creator).
ListSnapshots(ctx context.Context, sessionID string) ([]*SnapshotInfo, error)
// Close closes the history service and releases resources.
Close() error
}
HistoryService provides version history storage and retrieval. Similar to Jupyter's checkpoint mechanism and HedgeDoc's revision history.
Implementations can use different storage backends: - Redis: For distributed systems - Memory: For testing and single-instance deployments - Database: For persistent storage (PostgreSQL, MySQL, etc.)
The interface supports two storage modes: 1. Full content: Stores complete content for each version (simple, more storage) 2. Patch mode: Stores only diffs using diff-match-patch (efficient, less storage)
func NewHistoryService ¶
func NewHistoryService(opts *HistoryOptions) HistoryService
NewHistoryService creates a new history service based on options. Factory function that returns the appropriate implementation.
type LegacyMessageType ¶
type LegacyMessageType int
LegacyMessageType represents the type of legacy transport message.
const ( LegacyMsgOperation LegacyMessageType = iota LegacyMsgSync LegacyMsgSyncAck LegacyMsgAck LegacyMsgError LegacyMsgHello LegacyMsgWelcome )
type MemoryHistoryService ¶
type MemoryHistoryService struct {
// contains filtered or unexported fields
}
MemoryHistoryService provides an in-memory history service implementation. Useful for testing and single-instance deployments.
func NewMemoryHistoryService ¶
func NewMemoryHistoryService(usePatchMode bool) *MemoryHistoryService
NewMemoryHistoryService creates a new in-memory history service.
func (*MemoryHistoryService) Close ¶
func (s *MemoryHistoryService) Close() error
Close closes the history service.
func (*MemoryHistoryService) GetSessionHistory ¶
func (s *MemoryHistoryService) GetSessionHistory(ctx context.Context, sessionID string, limit int64) ([]*HistoryEvent, error)
GetSessionHistory retrieves history for a session.
func (*MemoryHistoryService) GetSnapshot ¶
func (s *MemoryHistoryService) GetSnapshot(ctx context.Context, sessionID string, versionID int64) (*HistoryEvent, error)
GetSnapshot retrieves a specific snapshot.
func (*MemoryHistoryService) ListSnapshots ¶
func (s *MemoryHistoryService) ListSnapshots(ctx context.Context, sessionID string) ([]*SnapshotInfo, error)
ListSnapshots lists all snapshots for a session.
func (*MemoryHistoryService) OnOperation ¶
func (s *MemoryHistoryService) OnOperation(event *HistoryEvent) error
OnOperation handles operation events.
func (*MemoryHistoryService) OnSnapshot ¶
func (s *MemoryHistoryService) OnSnapshot(event *HistoryEvent) error
OnSnapshot handles snapshot events.
func (*MemoryHistoryService) ReconstructSnapshot ¶
func (s *MemoryHistoryService) ReconstructSnapshot(ctx context.Context, sessionID string, targetVersionID int64) (string, error)
ReconstructSnapshot reconstructs the content of a specific version.
type MemoryTransport ¶
type MemoryTransport struct {
*BaseTransport
// contains filtered or unexported fields
}
MemoryTransport is an in-memory transport for testing.
func NewMemoryTransport ¶
func NewMemoryTransport(id, clientID, docID string) *MemoryTransport
NewMemoryTransport creates a new in-memory transport.
func (*MemoryTransport) Connect ¶
func (t *MemoryTransport) Connect(ctx context.Context) error
Connect establishes the connection (no-op for memory transport).
func (*MemoryTransport) ConnectTo ¶
func (t *MemoryTransport) ConnectTo(other *MemoryTransport)
ConnectTo connects this transport to another transport.
func (*MemoryTransport) Send ¶
func (t *MemoryTransport) Send(ctx context.Context, msg *Message) error
Send sends a message to connected peers.
func (*MemoryTransport) Start ¶
func (t *MemoryTransport) Start(ctx context.Context)
Start starts the message processing loop.
type Message ¶
type Message struct {
Type LegacyMessageType
DocID string
ClientID string
Timestamp int64
Operation *ot.Operation
Content string // For sync messages
Version int64 // Document version
SeqNum int64 // Sequence number
Error string
Metadata map[string]interface{}
}
Message represents a message sent over the transport layer.
func NewAckMessage ¶
NewAckMessage creates a new acknowledgment message.
func NewErrorMessage ¶
NewErrorMessage creates a new error message.
func NewOperationMessage ¶
NewOperationMessage creates a new operation message.
func NewSyncAckMessage ¶
NewSyncAckMessage creates a new sync acknowledgment message.
func NewSyncMessage ¶
NewSyncMessage creates a new sync message.
type MessageType ¶
type MessageType string
MessageType represents the type of WebSocket message.
const ( // Client → Server messages MessageTypeSubscribe MessageType = "subscribe" // 关注文件 MessageTypeUnsubscribe MessageType = "unsubscribe" // 取消关注 MessageTypeStartEditing MessageType = "start_editing" // 开始编辑 MessageTypeStopEditing MessageType = "stop_editing" // 停止编辑 MessageTypeOperation MessageType = "operation" // 发送 OT 操作 MessageTypeCursor MessageType = "cursor" // 光标位置 MessageTypeHeartbeat MessageType = "heartbeat" // 心跳 // Server → Client messages MessageTypeWelcome MessageType = "welcome" // 连接成功 MessageTypeSnapshot MessageType = "snapshot" // 文档快照 MessageTypeSnapshotCreated MessageType = "snapshot_created" // 快照已创建(通知Redis) MessageTypeRemoteOperation MessageType = "remote_operation" // 远程操作 MessageTypeAck MessageType = "ack" // 操作确认 MessageTypeError MessageType = "error" // 错误 MessageTypeUserJoined MessageType = "user_joined" // 用户加入 MessageTypeUserLeft MessageType = "user_left" // 用户离开 MessageTypeSessionInfo MessageType = "session_info" // 会话信息 )
type MiniRedis ¶
type MiniRedis struct {
// contains filtered or unexported fields
}
MiniRedis is an in-memory implementation of RedisClient for testing/fallback.
type MultiDocWebSocketTransport ¶
type MultiDocWebSocketTransport struct {
// contains filtered or unexported fields
}
MultiDocWebSocketTransport handles multiple documents over a single WebSocket connection. This is more efficient than creating separate connections for each document.
Example usage:
transport := NewMultiDocWebSocketTransport("client-1", "ws://localhost:8080/ws")
transport.Connect(ctx)
// Subscribe to documents
transport.Subscribe("/doc1.txt", doc1Handler)
transport.Subscribe("/doc2.txt", doc2Handler)
// Send operation for specific document
transport.SendOperation("/doc1.txt", operation)
func NewMultiDocWebSocketTransport ¶
func NewMultiDocWebSocketTransport(clientID, endpoint string) *MultiDocWebSocketTransport
NewMultiDocWebSocketTransport creates a new multi-document WebSocket transport.
func (*MultiDocWebSocketTransport) Close ¶
func (t *MultiDocWebSocketTransport) Close() error
Close closes the transport and all subscriptions.
func (*MultiDocWebSocketTransport) Connect ¶
func (t *MultiDocWebSocketTransport) Connect(ctx context.Context) error
Connect establishes a single WebSocket connection for all documents.
func (*MultiDocWebSocketTransport) GetSubscription ¶
func (t *MultiDocWebSocketTransport) GetSubscription(docPath string) (*DocumentSubscription, bool)
GetSubscription returns the subscription for a document.
func (*MultiDocWebSocketTransport) IsConnected ¶
func (t *MultiDocWebSocketTransport) IsConnected() bool
IsConnected returns whether the WebSocket is connected.
func (*MultiDocWebSocketTransport) ListSubscriptions ¶
func (t *MultiDocWebSocketTransport) ListSubscriptions() []string
ListSubscriptions returns all subscribed documents.
func (*MultiDocWebSocketTransport) SendHeartbeat ¶
func (t *MultiDocWebSocketTransport) SendHeartbeat(sessionIDs []string) error
SendHeartbeat sends heartbeat for multiple sessions.
func (*MultiDocWebSocketTransport) SendOperation ¶
func (t *MultiDocWebSocketTransport) SendOperation(docPath string, operation []interface{}) error
SendOperation sends an OT operation for a specific document.
func (*MultiDocWebSocketTransport) SendOperationWithContext ¶
func (t *MultiDocWebSocketTransport) SendOperationWithContext(ctx context.Context, docPath string, operation []interface{}) error
SendOperationWithContext sends an OT operation with context.
func (*MultiDocWebSocketTransport) SetMessageHandler ¶
func (t *MultiDocWebSocketTransport) SetMessageHandler(handler TransportMessageHandler)
SetMessageHandler sets a global message handler.
func (*MultiDocWebSocketTransport) Subscribe ¶
func (t *MultiDocWebSocketTransport) Subscribe(docPath string) (*DocumentSubscription, error)
Subscribe subscribes to a document and sets up message handlers. Returns the DocumentSubscription for further configuration.
func (*MultiDocWebSocketTransport) Unsubscribe ¶
func (t *MultiDocWebSocketTransport) Unsubscribe(docPath string) error
Unsubscribe unsubscribes from a document.
type OperationData ¶
type OperationData struct {
SessionID string `json:"session_id"` // Edit session UUID
Revision int64 `json:"revision"` // Document version
Operation interface{} `json:"operation"` // OT operation: [5, "Hello", 10, -3]
Selection *CursorData `json:"selection,omitempty"`
}
OperationData represents OT operation data.
type PatchManager ¶
type PatchManager struct {
// contains filtered or unexported fields
}
PatchManager handles diff-match-patch operations for version history. Uses Google's diff-match-patch algorithm for efficient text patching.
func NewPatchManager ¶
func NewPatchManager() *PatchManager
NewPatchManager creates a new patch manager.
func (*PatchManager) ApplyPatch ¶
func (pm *PatchManager) ApplyPatch(oldText, patchText string) *ApplyPatchResult
ApplyPatch applies a patch to oldText to reconstruct newText. Returns ApplyPatchResult with the reconstructed content.
func (*PatchManager) ComputeDiff ¶
func (pm *PatchManager) ComputeDiff(oldText, newText string) []diffmatchpatch.Diff
ComputeDiff computes differences between two texts (for debugging/analysis). Returns a list of Diff objects: Equal, Insert, Delete.
func (*PatchManager) ComputeDiffCleanup ¶
func (pm *PatchManager) ComputeDiffCleanup(oldText, newText string, cleanup bool) []diffmatchpatch.Diff
ComputeDiffCleanup computes diffs with cleanup for more readable output. The cleanup parameter merges nearby diffs for more compact representation.
func (*PatchManager) ComputePatch ¶
func (pm *PatchManager) ComputePatch(oldText, newText string) *PatchResult
ComputePatch computes a patch from oldText to newText. Returns a PatchResult containing the patch in compact text format.
func (*PatchManager) CreateRollbackPatch ¶
func (pm *PatchManager) CreateRollbackPatch(originalText, appliedPatchText string) string
CreateRollbackPatch creates a patch that can rollback a change. Given original text and the applied patch, creates a reverse patch.
func (*PatchManager) GetPatchStats ¶
func (pm *PatchManager) GetPatchStats(patchText string) *PatchStats
GetPatchStats analyzes a patch and returns statistics. Note: This computes stats from the patch text length as a simple metric. For detailed diff statistics, use ComputeDiff directly.
func (*PatchManager) PrettyPrintDiff ¶
func (pm *PatchManager) PrettyPrintDiff(diffs []diffmatchpatch.Diff) string
PrettyPrintDiff converts diffs to a human-readable string.
type PatchResult ¶
type PatchResult struct {
Patch string // Patch in text format (compact)
PatchSize int // Size of patch in bytes
OldSize int // Size of old text in bytes
NewSize int // Size of new text in bytes
SavedBytes int // Bytes saved by using patch instead of full content
}
PatchResult represents the result of computing a patch between two texts.
type PatchStats ¶
type PatchStats struct {
TotalDiffs int // Total number of patch operations
}
PatchStats returns statistics about a patch.
type ProtocolHandler ¶
type ProtocolHandler struct {
// contains filtered or unexported fields
}
ProtocolHandler handles WebSocket protocol messages.
func NewProtocolHandler ¶
func NewProtocolHandler(storage session.ContentStorage, auth session.Authenticator) *ProtocolHandler
NewProtocolHandler creates a new protocol handler.
func (*ProtocolHandler) SetServer ¶
func (h *ProtocolHandler) SetServer(server *WebSocketServer)
SetServer sets the WebSocket server.
type ProtocolMessage ¶
type ProtocolMessage struct {
Type MessageType `json:"type"`
SessionID string `json:"session_id,omitempty"` // Edit session UUID
Timestamp int64 `json:"timestamp"`
Data json.RawMessage `json:"data,omitempty"`
Metadata map[string]interface{} `json:"metadata,omitempty"`
}
ProtocolMessage is the base structure for all WebSocket messages.
func NewProtocolMessage ¶
func NewProtocolMessage(msgType MessageType, sessionID string, data interface{}) (*ProtocolMessage, error)
NewProtocolMessage creates a new protocol message.
type RedisClient ¶
type RedisClient interface {
// Set stores a key-value pair with optional TTL.
Set(key string, value interface{}, ttl time.Duration) error
// Get retrieves a value by key.
Get(key string) (string, error)
// LPush adds an element to the left of a list.
LPush(key string, values ...interface{}) error
// LRange retrieves a range of elements from a list.
LRange(key string, start, stop int64) ([]string, error)
// Publish publishes a message to a channel.
Publish(channel string, message interface{}) error
// Close closes the Redis connection.
Close() error
}
RedisClient defines the interface for Redis operations.
type RedisHistoryService ¶
type RedisHistoryService struct {
// contains filtered or unexported fields
}
RedisHistoryService implements HistoryService and forwards events to Redis. Falls back to MiniRedis if Redis is not available.
func NewRedisHistoryService ¶
func NewRedisHistoryService(redisClient RedisClient) *RedisHistoryService
NewRedisHistoryService creates a new Redis history service. If redisClient is nil, uses MiniRedis as fallback. By default, does NOT use patch mode (stores full content for simplicity). To enable patch mode, use NewRedisHistoryServiceWithOpts().
func NewRedisHistoryServiceWithOpts ¶
func NewRedisHistoryServiceWithOpts(redisClient RedisClient, usePatchMode bool) *RedisHistoryService
NewRedisHistoryServiceWithOpts creates a new Redis history service with options.
func (*RedisHistoryService) Close ¶
func (s *RedisHistoryService) Close() error
Close closes the history service.
func (*RedisHistoryService) GetSessionHistory ¶
func (s *RedisHistoryService) GetSessionHistory(ctx context.Context, sessionID string, limit int64) ([]*HistoryEvent, error)
GetSessionHistory retrieves history for a session from Redis.
func (*RedisHistoryService) GetSnapshot ¶
func (s *RedisHistoryService) GetSnapshot(ctx context.Context, sessionID string, versionID int64) (*HistoryEvent, error)
GetSnapshot retrieves a specific snapshot from Redis.
func (*RedisHistoryService) ListSnapshots ¶
func (s *RedisHistoryService) ListSnapshots(ctx context.Context, sessionID string) ([]*SnapshotInfo, error)
ListSnapshots lists all snapshots for a session.
func (*RedisHistoryService) OnOperation ¶
func (s *RedisHistoryService) OnOperation(event *HistoryEvent) error
OnOperation handles operation events from edit sessions.
func (*RedisHistoryService) OnSnapshot ¶
func (s *RedisHistoryService) OnSnapshot(event *HistoryEvent) error
OnSnapshot handles snapshot events from edit sessions.
func (*RedisHistoryService) ReconstructSnapshot ¶
func (s *RedisHistoryService) ReconstructSnapshot(ctx context.Context, sessionID string, targetVersionID int64) (string, error)
ReconstructSnapshot reconstructs the content of a specific version by applying patches. This is necessary when using patch mode, where only the first snapshot has full content. Starting from version 0, it applies all patches up to the target version.
type RemoteOperationData ¶
type RemoteOperationData struct {
SessionID string `json:"session_id"` // Edit session UUID
ClientID string `json:"client_id"` // Who sent this operation
Revision int64 `json:"revision"` // New document version
Operation interface{} `json:"operation"` // OT operation: [5, "Hello", 10, -3]
Selection *CursorData `json:"selection,omitempty"`
}
RemoteOperationData represents remote operation data.
type SSEClient ¶
type SSEClient struct {
// contains filtered or unexported fields
}
SSEClient represents an SSE client connection.
type SSEServer ¶
type SSEServer struct {
// contains filtered or unexported fields
}
SSEServer handles SSE connections.
func NewSSEServer ¶
NewSSEServer creates a new SSE server.
type SSETransport ¶
type SSETransport struct {
*BaseTransport
// contains filtered or unexported fields
}
SSETransport implements Transport using Server-Sent Events.
func NewSSETransport ¶
func NewSSETransport(id, clientID, docID string) *SSETransport
NewSSETransport creates a new SSE transport.
func (*SSETransport) Connect ¶
func (t *SSETransport) Connect(ctx context.Context) error
Connect establishes SSE connection (client mode).
func (*SSETransport) Send ¶
func (t *SSETransport) Send(ctx context.Context, msg *Message) error
Send sends a message via HTTP POST (client mode).
func (*SSETransport) SetEndpoint ¶
func (t *SSETransport) SetEndpoint(endpoint string)
SetEndpoint sets the SSE endpoint URL.
type SessionClient ¶
type SessionClient struct {
ClientID string // Client ID
FilePath string // File path
ReadOnly bool // Whether client is read-only
IsEditing bool // Whether client is actively editing
Connected bool // Whether client is connected
Selection *CursorData // Current cursor/selection
LastSeen int64 // Last activity timestamp
}
SessionClient represents a client in an edit session.
func (*SessionClient) GetID ¶
func (sc *SessionClient) GetID() string
GetClientID returns the client ID.
type SessionInfo ¶
type SessionInfo struct {
SessionID string `json:"session_id"`
FilePath string `json:"file_path"`
Content string `json:"content"`
Revision int64 `json:"revision"`
SnapshotVersion int64 `json:"snapshot_version"`
RecentChangeCount int `json:"recent_change_count"`
ReaderCount int `json:"reader_count"`
WriterCount int `json:"writer_count"`
CreatedAt int64 `json:"created_at"`
UpdatedAt int64 `json:"updated_at"`
}
SessionInfo contains session information.
type SessionInfoData ¶
type SessionInfoData struct {
SessionID string `json:"session_id"`
FilePath string `json:"file_path"`
ReaderCount int `json:"reader_count"` // Number of read-only subscribers
WriterCount int `json:"writer_count"` // Number of editors
Clients []ClientInfo `json:"clients"` // All connected clients
IsEditing bool `json:"is_editing"` // Whether this file is being edited
}
SessionInfoData represents session information.
type SessionManager ¶
type SessionManager struct {
// contains filtered or unexported fields
}
SessionManager manages multiple edit sessions.
func NewSessionManager ¶
func NewSessionManager() *SessionManager
NewSessionManager creates a new session manager.
func NewSessionManagerWithHistory ¶
func NewSessionManagerWithHistory(history HistoryListener) *SessionManager
NewSessionManagerWithHistory creates a new session manager with a history service. This is the preferred way to create a session manager with history support.
Example:
// Using Redis history service with patch mode
historySvc := NewRedisHistoryServiceWithOpts(redisClient, true)
sm := NewSessionManagerWithHistory(historySvc)
// Using in-memory history service
historySvc := NewMemoryHistoryService(false)
sm := NewSessionManagerWithHistory(historySvc)
// Using history service factory
historySvc := NewHistoryService(&HistoryOptions{
StorageBackend: "redis",
UsePatchMode: true,
})
sm := NewSessionManagerWithHistory(historySvc)
func (*SessionManager) DestroySession ¶
func (sm *SessionManager) DestroySession(sessionID string)
DestroySession destroys a session.
func (*SessionManager) GetOrCreateSession ¶
func (sm *SessionManager) GetOrCreateSession(filePath string) (*EditSession, bool)
GetOrCreateSession gets an existing session or creates a new one.
func (*SessionManager) GetSession ¶
func (sm *SessionManager) GetSession(sessionID string) *EditSession
GetSession retrieves a session by ID.
func (*SessionManager) GetSessionByPath ¶
func (sm *SessionManager) GetSessionByPath(filePath string) *EditSession
GetSessionByPath retrieves a session by file path.
func (*SessionManager) ListSessions ¶
func (sm *SessionManager) ListSessions() []*EditSession
ListSessions returns all active sessions.
func (*SessionManager) SetContentStorage ¶
func (sm *SessionManager) SetContentStorage(storage ContentStorage)
SetContentStorage sets the content storage for loading files.
func (*SessionManager) SetHistoryListener ¶
func (sm *SessionManager) SetHistoryListener(listener HistoryListener)
SetHistoryListener sets the history listener for all sessions.
type SessionRefCount ¶
type SessionRefCount struct {
SessionID string `json:"session_id"`
FilePath string `json:"file_path"`
ReaderCount int `json:"reader_count"` // Read-only subscribers
WriterCount int `json:"writer_count"` // Active editors
CreatedAt int64 `json:"created_at"`
UpdatedAt int64 `json:"updated_at"`
}
SessionRefCount manages reference counts for edit sessions.
func (*SessionRefCount) AddReader ¶
func (rc *SessionRefCount) AddReader()
AddReader adds a read-only subscriber.
func (*SessionRefCount) AddWriter ¶
func (rc *SessionRefCount) AddWriter()
AddWriter adds an editor.
func (*SessionRefCount) HasWriters ¶
func (rc *SessionRefCount) HasWriters() bool
HasWriters returns true if there are active editors.
func (*SessionRefCount) IsActive ¶
func (rc *SessionRefCount) IsActive() bool
IsActive returns true if there are any readers or writers.
func (*SessionRefCount) RemoveReader ¶
func (rc *SessionRefCount) RemoveReader()
RemoveReader removes a read-only subscriber.
func (*SessionRefCount) RemoveWriter ¶
func (rc *SessionRefCount) RemoveWriter()
RemoveWriter removes an editor.
func (*SessionRefCount) ShouldDestroy ¶
func (rc *SessionRefCount) ShouldDestroy() bool
ShouldDestroy returns true if session should be destroyed.
type SnapshotCreatedData ¶
type SnapshotCreatedData struct {
SessionID string `json:"session_id"` // Edit session UUID
FilePath string `json:"file_path"` // File path
VersionID int64 `json:"version_id"` // Snapshot version ID
Content string `json:"content"` // Full text content at snapshot
Operations []interface{} `json:"operations"` // Operations since last snapshot
CreatedAt int64 `json:"created_at"` // Creation timestamp
CreatedBy string `json:"created_by"` // Client ID who triggered snapshot
}
SnapshotCreatedData represents snapshot creation notification (sent to Redis/History service).
type SnapshotData ¶
type SnapshotData struct {
SessionID string `json:"session_id"` // Edit session UUID
FilePath string `json:"file_path"`
Content string `json:"content"` // Current document content
Revision int64 `json:"revision"` // Current version
CreatedAt int64 `json:"created_at"`
UpdatedAt int64 `json:"updated_at"`
Operations interface{} `json:"operations,omitempty"` // Recent OT operations since last sync
Clients []ClientInfo `json:"clients"` // Other clients in this session
ReadOnly bool `json:"read_only"` // Whether client has write permission
}
SnapshotData represents document snapshot data.
type SnapshotInfo ¶
type SnapshotInfo struct {
SnapshotVersion int64 `json:"snapshot_version"`
LastSnapshotTime int64 `json:"last_snapshot_time"`
RecentChangeCount int `json:"recent_change_count"`
MaxChangesBeforeSnapshot int `json:"max_changes_before_snapshot"`
MaxSnapshotInterval int64 `json:"max_snapshot_interval"` // seconds
TimeUntilSnapshot int64 `json:"time_until_snapshot"` // seconds
}
SnapshotInfo contains information about a snapshot.
type StartEditingData ¶
type StartEditingData struct {
FilePath string `json:"file_path"`
ContentType string `json:"content_type,omitempty"` // "text", "markdown", etc.
InitialText string `json:"initial_text,omitempty"` // 如果文件不存在,创建时的初始内容
ClientID string `json:"client_id,omitempty"`
}
StartEditingData represents start editing request data.
type StopEditingData ¶
type StopEditingData struct {
SessionID string `json:"session_id"` // Edit session UUID
}
StopEditingData represents stop editing request data.
type SubscribeData ¶
type SubscribeData struct {
FilePath string `json:"file_path"`
ReadOnly bool `json:"read_only"` // true = 只读(可用SSE)
UseSSE bool `json:"use_sse"` // true = 优先使用SSE推送
ClientID string `json:"client_id,omitempty"`
}
SubscribeData represents subscribe request data.
type TCPServer ¶
type TCPServer struct {
// contains filtered or unexported fields
}
TCPServer handles incoming TCP connections.
func NewTCPServer ¶
NewTCPServer creates a new TCP server.
type TCPTransport ¶
type TCPTransport struct {
*BaseTransport
// contains filtered or unexported fields
}
TCPTransport implements Transport over TCP.
func DialTCP ¶
func DialTCP(addr string) (*TCPTransport, error)
DialTCP creates a TCP transport by connecting to an address.
func NewTCPTransport ¶
func NewTCPTransport(id, clientID, docID string) *TCPTransport
NewTCPTransport creates a new TCP transport.
func (*TCPTransport) Connect ¶
func (t *TCPTransport) Connect(ctx context.Context) error
Connect establishes a TCP connection.
func (*TCPTransport) Send ¶
func (t *TCPTransport) Send(ctx context.Context, msg *Message) error
Send sends a message over TCP.
func (*TCPTransport) SetConnection ¶
func (t *TCPTransport) SetConnection(conn net.Conn)
SetConnection sets the underlying TCP connection (for server mode).
type Transport ¶
type Transport interface {
// ID returns the unique identifier for this transport.
ID() string
// Send sends a message over the transport.
Send(ctx context.Context, msg *Message) error
// Receive returns a channel for receiving messages.
Receive() <-chan *Message
// Close closes the transport.
Close() error
// Connect establishes the connection.
Connect(ctx context.Context) error
// IsConnected returns true if the transport is connected.
IsConnected() bool
}
Transport represents a bidirectional transport for collaborative editing.
type TransportError ¶
TransportError represents a transport-related error.
func (*TransportError) Error ¶
func (e *TransportError) Error() string
type TransportMessageHandler ¶
type TransportMessageHandler interface {
// HandleMessage is called when a message is received
HandleMessage(msg *Message) error
}
TransportMessageHandler handles messages for a transport.
type UnsubscribeData ¶
type UnsubscribeData struct {
SessionID string `json:"session_id"` // Edit session UUID
FilePath string `json:"file_path,omitempty"`
}
UnsubscribeData represents unsubscribe request data.
type UserJoinedData ¶
type UserJoinedData struct {
SessionID string `json:"session_id"`
ClientID string `json:"client_id"`
Client ClientInfo `json:"client"`
}
UserJoinedData represents user joined notification.
type UserLeftData ¶
type UserLeftData struct {
SessionID string `json:"session_id"`
ClientID string `json:"client_id"`
}
UserLeftData represents user left notification.
type WebSocketConn ¶
type WebSocketConn struct {
// contains filtered or unexported fields
}
WebSocketConn represents a WebSocket client connection.
type WebSocketServer ¶
type WebSocketServer struct {
// contains filtered or unexported fields
}
WebSocketServer handles WebSocket connections.
func NewWebSocketServer ¶
func NewWebSocketServer(addr string) *WebSocketServer
NewWebSocketServer creates a new WebSocket server.
func (*WebSocketServer) Broadcast ¶
func (s *WebSocketServer) Broadcast(msg *Message)
Broadcast sends a message to all connected clients.
func (*WebSocketServer) Close ¶
func (s *WebSocketServer) Close() error
Close closes the WebSocket server.
func (*WebSocketServer) RegisterHandler ¶
func (s *WebSocketServer) RegisterHandler(mux *http.ServeMux)
RegisterHandler registers the WebSocket handler with the given mux.
func (*WebSocketServer) Send ¶
func (s *WebSocketServer) Send(clientID string, msg *Message) error
Send sends a message to a specific client.
func (*WebSocketServer) SendJSON ¶
func (s *WebSocketServer) SendJSON(clientID string, data []byte) error
SendJSON sends raw JSON data to a specific client.
func (*WebSocketServer) SetMessageHandler ¶
func (s *WebSocketServer) SetMessageHandler(handler func(*Message))
SetMessageHandler sets the message handler for incoming messages.
func (*WebSocketServer) SetRawMessageHandler ¶
func (s *WebSocketServer) SetRawMessageHandler(handler func(clientID string, message []byte))
SetRawMessageHandler sets the raw message handler for incoming messages.
type WebSocketTransport ¶
type WebSocketTransport struct {
*BaseTransport
// contains filtered or unexported fields
}
WebSocketTransport implements Transport using WebSocket.
func NewWebSocketTransport ¶
func NewWebSocketTransport(id, clientID, docID string) *WebSocketTransport
NewWebSocketTransport creates a new WebSocket transport.
func (*WebSocketTransport) Close ¶
func (t *WebSocketTransport) Close() error
Close closes the WebSocket transport.
func (*WebSocketTransport) Connect ¶
func (t *WebSocketTransport) Connect(ctx context.Context) error
Connect establishes WebSocket connection (client mode).
func (*WebSocketTransport) Send ¶
func (t *WebSocketTransport) Send(ctx context.Context, msg *Message) error
Send sends a message via WebSocket (client mode).
func (*WebSocketTransport) SetEndpoint ¶
func (t *WebSocketTransport) SetEndpoint(endpoint string)
SetEndpoint sets the WebSocket endpoint URL.
type WelcomeData ¶
type WelcomeData struct {
ClientID string `json:"client_id"`
ServerID string `json:"server_id"`
Timestamp int64 `json:"timestamp"`
}
WelcomeData represents welcome message data.