@@ -114,10 +114,10 @@ const setupWS = (provider: YSweetProvider) => {
114
114
}
115
115
}
116
116
websocket . onerror = ( event ) => {
117
- provider . observable . emit ( 'connection-error' , [ event , provider ] )
117
+ provider . emit ( 'connection-error' , [ event , provider ] )
118
118
}
119
119
websocket . onclose = ( event ) => {
120
- provider . observable . emit ( 'connection-close' , [ event , provider ] )
120
+ provider . emit ( 'connection-close' , [ event , provider ] )
121
121
provider . ws = null
122
122
provider . wsconnecting = false
123
123
if ( provider . wsconnected ) {
@@ -131,7 +131,7 @@ const setupWS = (provider: YSweetProvider) => {
131
131
) ,
132
132
provider ,
133
133
)
134
- provider . observable . emit ( 'status' , [
134
+ provider . emit ( 'status' , [
135
135
{
136
136
status : 'disconnected' ,
137
137
} ,
@@ -161,7 +161,7 @@ const setupWS = (provider: YSweetProvider) => {
161
161
provider . wsconnecting = false
162
162
provider . wsconnected = true
163
163
provider . wsUnsuccessfulReconnects = 0
164
- provider . observable . emit ( 'status' , [
164
+ provider . emit ( 'status' , [
165
165
{
166
166
status : 'connected' ,
167
167
} ,
@@ -182,7 +182,7 @@ const setupWS = (provider: YSweetProvider) => {
182
182
websocket . send ( encoding . toUint8Array ( encoderAwarenessState ) )
183
183
}
184
184
}
185
- provider . observable . emit ( 'status' , [
185
+ provider . emit ( 'status' , [
186
186
{
187
187
status : 'connecting' ,
188
188
} ,
@@ -224,7 +224,6 @@ export type YSweetProviderParams = {
224
224
resyncInterval ?: number
225
225
maxBackoffTime ?: number
226
226
disableBc ?: boolean
227
- observable ?: Observable < string >
228
227
}
229
228
230
229
/**
@@ -238,14 +237,13 @@ export type YSweetProviderParams = {
238
237
* const doc = new Y.Doc()
239
238
* const provider = new YSweetProvider('http://localhost:1234', 'my-document-name', doc)
240
239
*/
241
- export class YSweetProvider {
240
+ export class YSweetProvider extends Observable < string > {
242
241
onFailureHandlers : Array < ( ) => void > = [ ]
243
242
maxBackoffTime : number
244
243
bcChannel : string
245
244
url : string
246
245
roomname : string
247
246
doc : Y . Doc
248
- observable : Observable < string >
249
247
_WS : WebSocketPolyfillType
250
248
awareness : awarenessProtocol . Awareness
251
249
wsconnected : boolean
@@ -277,7 +275,6 @@ export class YSweetProvider {
277
275
* @param opts.resyncInterval - resync interval
278
276
* @param opts.maxBackoffTime - maximum backoff time
279
277
* @param opts.disableBc - disable broadcast channel
280
- * @param opts.observable - an observable instance to emit events on
281
278
*/
282
279
constructor (
283
280
serverUrl : string ,
@@ -291,15 +288,14 @@ export class YSweetProvider {
291
288
resyncInterval = - 1 ,
292
289
maxBackoffTime = 2500 ,
293
290
disableBc = false ,
294
- observable = new Observable < string > ( ) ,
295
291
} : YSweetProviderParams = { } ,
296
292
) {
293
+ super ( )
297
294
// ensure that url is always ends with /
298
295
while ( serverUrl [ serverUrl . length - 1 ] === '/' ) {
299
296
serverUrl = serverUrl . slice ( 0 , serverUrl . length - 1 )
300
297
}
301
298
const encodedParams = url . encodeQueryParams ( params )
302
- this . observable = observable
303
299
this . maxBackoffTime = maxBackoffTime
304
300
this . bcChannel = serverUrl + '/' + roomname
305
301
this . url = serverUrl + '/' + roomname + ( encodedParams . length === 0 ? '' : '?' + encodedParams )
@@ -407,8 +403,8 @@ export class YSweetProvider {
407
403
set synced ( state ) {
408
404
if ( this . _synced !== state ) {
409
405
this . _synced = state
410
- this . observable . emit ( 'synced' , [ state ] )
411
- this . observable . emit ( 'sync' , [ state ] )
406
+ this . emit ( 'synced' , [ state ] )
407
+ this . emit ( 'sync' , [ state ] )
412
408
}
413
409
}
414
410
@@ -425,6 +421,7 @@ export class YSweetProvider {
425
421
}
426
422
this . awareness . off ( 'update' , this . _awarenessUpdateHandler )
427
423
this . doc . off ( 'update' , this . _updateHandler )
424
+ super . destroy ( )
428
425
}
429
426
430
427
connectBc ( ) {
@@ -531,9 +528,15 @@ export async function ySweetProviderWrapper(
531
528
doc : Y . Doc ,
532
529
providerParams : YSweetProviderParams = { } ,
533
530
) : Promise < YSweetProviderWithClientToken > {
534
- const observable = providerParams . observable ?? new Observable < string > ( )
531
+ // we use an observable that lives outside the provider to store event listeners
532
+ // so that we can re-subscribe to events when the provider is re-created
533
+ const observable = new Observable < string > ( )
534
+ // keep track of which events have been subscribed to on the local observable
535
+ // so we can re-subscribe to them when the provider is re-created
536
+ const subscribedEvents = new Set < string > ( )
537
+
535
538
const awareness = providerParams . awareness ?? new awarenessProtocol . Awareness ( doc )
536
- providerParams = { ...providerParams , observable , awareness }
539
+ providerParams = { ...providerParams , awareness }
537
540
538
541
let _clientToken = await getClientToken ( authEndpoint , roomname )
539
542
let _provider = new YSweetProvider ( _clientToken . url , roomname , doc , {
@@ -548,10 +551,33 @@ export async function ySweetProviderWrapper(
548
551
connect : true ,
549
552
} )
550
553
_provider . addOnFailureHandler ( recreateProvider )
554
+ // the previous provider's destroy() method should have been called before
555
+ // recreateProvider() is called, so we don't need to unsubscribe from events
556
+ // before re-subscribing to events here
557
+ for ( const event of subscribedEvents ) {
558
+ subscribeToEvent ( event )
559
+ }
560
+ }
561
+
562
+ // for each event that is subscribed to on the local observable, make sure to
563
+ // subscribe to it on the provider
564
+ function subscribeToEvent ( name : string ) {
565
+ _provider . on ( name , ( ...args : any [ ] ) => observable . emit ( name , args ) )
566
+ subscribedEvents . add ( name )
551
567
}
552
568
553
569
return {
554
- observable,
570
+ on : ( name : string , f : ( ...args : any [ ] ) => void ) => {
571
+ if ( ! subscribedEvents . has ( name ) ) subscribeToEvent ( name )
572
+ observable . on ( name , f )
573
+ } ,
574
+ once : ( name : string , f : ( ...args : any [ ] ) => void ) => {
575
+ if ( ! subscribedEvents . has ( name ) ) subscribeToEvent ( name )
576
+ observable . once ( name , f )
577
+ } ,
578
+ off : ( name : string , f : ( ...args : any [ ] ) => void ) => {
579
+ observable . off ( name , f )
580
+ } ,
555
581
awareness,
556
582
get clientToken ( ) {
557
583
return _clientToken
@@ -619,5 +645,5 @@ export async function ySweetProviderWrapper(
619
645
get shouldConnect ( ) {
620
646
return _provider . shouldConnect
621
647
} ,
622
- } as YSweetProviderWithClientToken
648
+ } as unknown as YSweetProviderWithClientToken
623
649
}
0 commit comments