1
+ /*
2
+ * Copyright (c) 2021-2023 Datalayer, Inc.
3
+ *
4
+ * MIT License
5
+ */
6
+
7
+ import { WebsocketProvider as YWebsocketProvider } from 'y-websocket' ;
8
+ import {
9
+ ICollaborationProviderImpl ,
10
+ ICollaborationOptions ,
11
+ collaborationProviderRegistry
12
+ } from '../../index' ;
13
+
14
+ /**
15
+ * Example custom collaboration provider demonstrating how to extend
16
+ * the generic collaboration system without any Datalayer dependencies.
17
+ *
18
+ * This provider can be used with any WebSocket-based collaboration server.
19
+ */
20
+ export class CustomCollaborationProvider implements ICollaborationProviderImpl {
21
+ readonly name = 'custom-example' ;
22
+
23
+ /**
24
+ * Create a custom WebSocket provider for collaboration
25
+ * @param options - Collaboration options containing ydoc, awareness, path, etc.
26
+ * @returns Promise that resolves to a configured YWebsocketProvider
27
+ */
28
+ async createProvider ( options : ICollaborationOptions ) : Promise < YWebsocketProvider > {
29
+ const { ydoc, awareness, path, token } = options ;
30
+
31
+ if ( ! path ) {
32
+ throw new Error ( 'Path is required for custom collaboration' ) ;
33
+ }
34
+
35
+ // Example: Connect to a custom collaboration server
36
+ // You would replace this with your actual server configuration
37
+ const wsUrl = options . wsUrl || 'ws://localhost:1234/collaboration' ;
38
+ const roomName = `custom-room-${ path . replace ( / \/ / g, '-' ) } ` ;
39
+
40
+ console . log ( `Creating custom collaboration provider for room: ${ roomName } ` ) ;
41
+
42
+ // Create the WebSocket provider with custom configuration
43
+ const provider = new YWebsocketProvider (
44
+ wsUrl ,
45
+ roomName ,
46
+ ydoc ,
47
+ {
48
+ awareness,
49
+ params : {
50
+ // Custom parameters for your collaboration server
51
+ path,
52
+ token : token || '' ,
53
+ timestamp : Date . now ( ) . toString ( ) ,
54
+ // Add any custom parameters your server needs
55
+ customParam : 'example-value'
56
+ } ,
57
+ // Custom WebSocket options
58
+ connect : true ,
59
+ // Disable broadcasting to other browser tabs (optional)
60
+ disableBc : false ,
61
+ // Custom protocols (optional)
62
+ protocols : [ ] ,
63
+ }
64
+ ) ;
65
+
66
+ // Optional: Add custom event handlers
67
+ provider . on ( 'status' , ( event : any ) => {
68
+ console . log ( `Custom provider status: ${ event . status } ` ) ;
69
+ } ) ;
70
+
71
+ provider . on ( 'sync' , ( isSynced : boolean ) => {
72
+ console . log ( `Custom provider synced: ${ isSynced } ` ) ;
73
+ } ) ;
74
+
75
+ // Optional: Custom authentication or initialization
76
+ await this . authenticate ( token ) ;
77
+
78
+ return provider ;
79
+ }
80
+
81
+ /**
82
+ * Example authentication method
83
+ * Replace with your actual authentication logic
84
+ */
85
+ private async authenticate ( token ?: string ) : Promise < void > {
86
+ if ( ! token ) {
87
+ console . log ( 'No token provided, using anonymous mode' ) ;
88
+ return ;
89
+ }
90
+
91
+ // Simulate authentication
92
+ return new Promise ( ( resolve ) => {
93
+ setTimeout ( ( ) => {
94
+ console . log ( 'Custom provider authenticated' ) ;
95
+ resolve ( ) ;
96
+ } , 100 ) ;
97
+ } ) ;
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Alternative simple collaboration provider for local development
103
+ */
104
+ export class LocalCollaborationProvider implements ICollaborationProviderImpl {
105
+ readonly name = 'local-dev' ;
106
+
107
+ async createProvider ( options : ICollaborationOptions ) : Promise < YWebsocketProvider > {
108
+ const { ydoc, awareness, path } = options ;
109
+
110
+ // Use a local WebSocket server for development
111
+ const provider = new YWebsocketProvider (
112
+ 'ws://localhost:1234' ,
113
+ `local-${ path } ` ,
114
+ ydoc ,
115
+ {
116
+ awareness,
117
+ connect : false , // Don't connect automatically
118
+ }
119
+ ) ;
120
+
121
+ // For local development, we might not have a real server
122
+ // So we can work in offline mode
123
+ console . log ( 'LocalCollaborationProvider created in offline mode' ) ;
124
+
125
+ return provider ;
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Mock collaboration provider for testing
131
+ */
132
+ export class MockCollaborationProvider implements ICollaborationProviderImpl {
133
+ readonly name = 'mock' ;
134
+
135
+ async createProvider ( options : ICollaborationOptions ) : Promise < YWebsocketProvider > {
136
+ const { ydoc, awareness } = options ;
137
+
138
+ // Create a provider that doesn't actually connect anywhere
139
+ const provider = new YWebsocketProvider (
140
+ 'ws://mock-server' ,
141
+ 'mock-room' ,
142
+ ydoc ,
143
+ {
144
+ awareness,
145
+ connect : false , // Never actually connect
146
+ }
147
+ ) ;
148
+
149
+ // Simulate successful connection
150
+ setTimeout ( ( ) => {
151
+ ( provider as any ) . wsconnected = true ;
152
+ provider . emit ( 'status' , [ { status : 'connected' } ] ) ;
153
+ } , 500 ) ;
154
+
155
+ return provider ;
156
+ }
157
+ }
158
+
159
+ /**
160
+ * Register all custom providers when this module is imported
161
+ * This demonstrates the auto-registration pattern
162
+ */
163
+ export function registerCustomProviders ( ) : void {
164
+ console . log ( 'Registering custom collaboration providers...' ) ;
165
+
166
+ // Register the custom provider
167
+ collaborationProviderRegistry . register ( 'custom-example' , new CustomCollaborationProvider ( ) ) ;
168
+
169
+ // Register the local development provider
170
+ collaborationProviderRegistry . register ( 'local-dev' , new LocalCollaborationProvider ( ) ) ;
171
+
172
+ // Register the mock provider for testing
173
+ collaborationProviderRegistry . register ( 'mock' , new MockCollaborationProvider ( ) ) ;
174
+
175
+ console . log ( 'Custom providers registered:' , collaborationProviderRegistry . getProviderNames ( ) ) ;
176
+ }
177
+
178
+ // Auto-register on import (optional)
179
+ // Uncomment this line to auto-register when the module is imported
180
+ // registerCustomProviders();
181
+
182
+ export default CustomCollaborationProvider ;
0 commit comments