transport

package
v0.0.0-...-59de1e3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 31, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Index

Constants

View Source
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

View Source
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

func TestEditSession(t *testing.T)

TestEditSession tests edit session operations.

func TestParseOperationData

func TestParseOperationData(t *testing.T)

TestParseOperationData tests parsing OT operations from different formats.

func TestProtocolMessages

func TestProtocolMessages(t *testing.T)

TestProtocolMessages tests protocol message creation.

func TestSessionManager

func TestSessionManager(t *testing.T)

TestSessionManager tests session management.

func TestSessionRefCount

func TestSessionRefCount(t *testing.T)

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) Close

func (t *BaseTransport) Close() error

Close closes the transport.

func (*BaseTransport) ID

func (t *BaseTransport) ID() string

ID returns the transport ID.

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.

func (*BaseTransport) Send

func (t *BaseTransport) Send(ctx context.Context, msg *Message) error

Send sends a message over the transport.

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

type CursorData struct {
	Position     int `json:"position"`
	SelectionEnd int `json:"selection_end"`
}

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) Close

func (t *MemoryTransport) Close() error

Close closes the 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

func NewAckMessage(docID, clientID string) *Message

NewAckMessage creates a new acknowledgment message.

func NewErrorMessage

func NewErrorMessage(docID string, err error) *Message

NewErrorMessage creates a new error message.

func NewOperationMessage

func NewOperationMessage(docID, clientID string, op *ot.Operation) *Message

NewOperationMessage creates a new operation message.

func NewSyncAckMessage

func NewSyncAckMessage(docID string, content string, version int64) *Message

NewSyncAckMessage creates a new sync acknowledgment message.

func NewSyncMessage

func NewSyncMessage(docID, clientID string, version int64) *Message

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.

func NewMiniRedis

func NewMiniRedis() *MiniRedis

NewMiniRedis creates a new MiniRedis instance.

func (*MiniRedis) Close

func (m *MiniRedis) Close() error

Close closes the MiniRedis connection.

func (*MiniRedis) Get

func (m *MiniRedis) Get(key string) (string, error)

Get retrieves a value by key.

func (*MiniRedis) GetData

func (m *MiniRedis) GetData() map[string]string

GetData returns all stored data (for testing).

func (*MiniRedis) GetLists

func (m *MiniRedis) GetLists() map[string][]string

GetLists returns all stored lists (for testing).

func (*MiniRedis) LPush

func (m *MiniRedis) LPush(key string, values ...interface{}) error

LPush adds an element to the left of a list.

func (*MiniRedis) LRange

func (m *MiniRedis) LRange(key string, start, stop int64) ([]string, error)

LRange retrieves a range of elements from a list.

func (*MiniRedis) Publish

func (m *MiniRedis) Publish(channel string, message interface{}) error

Publish publishes a message to a channel.

func (*MiniRedis) Set

func (m *MiniRedis) Set(key string, value interface{}, ttl time.Duration) error

Set stores a key-value pair.

func (*MiniRedis) Subscribe

func (m *MiniRedis) Subscribe(channel string) <-chan string

Subscribe subscribes to a channel (MiniRedis extension).

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

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

func NewSSEServer(addr string) *SSEServer

NewSSEServer creates a new SSE server.

func (*SSEServer) Broadcast

func (s *SSEServer) Broadcast(msg *Message)

Broadcast sends a message to all connected clients.

func (*SSEServer) Close

func (s *SSEServer) Close() error

Close closes the SSE server.

func (*SSEServer) Start

func (s *SSEServer) Start() error

Start starts the 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) Close

func (t *SSETransport) Close() error

Close closes the 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

func NewTCPServer(addr string) *TCPServer

NewTCPServer creates a new TCP server.

func (*TCPServer) Accept

func (s *TCPServer) Accept() (net.Conn, error)

Accept accepts the next connection.

func (*TCPServer) Close

func (s *TCPServer) Close() error

Close closes the server.

func (*TCPServer) Start

func (s *TCPServer) Start() error

Start starts accepting connections.

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) Close

func (t *TCPTransport) Close() error

Close closes the TCP connection.

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

type TransportError struct {
	Code    string
	Message string
}

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.

func (*WebSocketServer) Start

func (s *WebSocketServer) Start(ctx context.Context) error

Start starts the WebSocket server.

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL