MCPcopy
hub / github.com/tldraw/tldraw / didReconnect

Method didReconnect

packages/sync-core/src/lib/TLSyncClient.ts:692–768  ·  view source on GitHub ↗

* Invoked when the socket connection comes online, either for the first time or as the result of * a reconnect. The goal is to rebase on the server's state and fire off a new push request for * any local changes that were made while offline.

(event: Extract<TLSocketServerSentEvent<R>, { type: 'connect' }>)

Source from the content-addressed store, hash-verified

690 * any local changes that were made while offline.
691 */
692 private didReconnect(event: Extract<TLSocketServerSentEvent<R>, { type: 'connect' }>) {
693 this.debug('did reconnect', event)
694 if (event.connectRequestId !== this.latestConnectRequestId) {
695 // ignore connect events for old connect requests
696 return
697 }
698 this.latestConnectRequestId = null
699
700 if (this.isConnectedToRoom) {
701 console.error('didReconnect called while already connected')
702 this.resetConnection(true)
703 return
704 }
705 if (this.pendingPushRequests.length > 0) {
706 console.error('pendingPushRequests should already be empty when we reconnect')
707 this.resetConnection(true)
708 return
709 }
710 // at the end of this process we want to have at most one pending push request
711 // based on anything inside this.speculativeChanges
712 transact(() => {
713 // Now our goal is to rebase on the server's state.
714 // This means wiping away any peer presence data, which the server will replace in full on every connect.
715 // If the server does not have enough history to give us a partial document state hydration we will
716 // also need to wipe away all of our document state before hydrating with the server's state from scratch.
717 const stashedChanges = this.speculativeChanges
718 this.speculativeChanges = { added: {} as any, updated: {} as any, removed: {} as any }
719
720 this.store.mergeRemoteChanges(() => {
721 // gather records to delete in a NetworkDiff
722 const wipeDiff: NetworkDiff<R> = {}
723 const wipeAll = event.hydrationType === 'wipe_all'
724 if (!wipeAll) {
725 // if we're only wiping presence data, undo the speculative changes first
726 this.store.applyDiff(reverseRecordsDiff(stashedChanges), { runCallbacks: false })
727 }
728
729 // now wipe all presence data and, if needed, all document data
730 for (const [id, record] of objectMapEntries(this.store.serialize('all'))) {
731 if (
732 (wipeAll && this.store.scopedTypes.document.has(record.typeName)) ||
733 record.typeName === this.presenceType
734 ) {
735 wipeDiff[id] = [RecordOpType.Remove]
736 }
737 }
738
739 // then apply the upstream changes
740 this.applyNetworkDiff({ ...wipeDiff, ...event.diff }, true)
741
742 this.isConnectedToRoom = true
743
744 // now re-apply the speculative changes creating a new push request with the
745 // appropriate diff
746 const networkDiff = getNetworkDiff(stashedChanges)
747 if (!networkDiff) return
748 const speculativeChanges = this.store.filterChangesByScope(
749 this.store.extractingChanges(() => {

Callers 1

handleServerEventMethod · 0.95

Calls 15

debugMethod · 0.95
resetConnectionMethod · 0.95
applyNetworkDiffMethod · 0.95
pushMethod · 0.95
pushPresenceMethod · 0.95
transactFunction · 0.90
reverseRecordsDiffFunction · 0.90
objectMapEntriesFunction · 0.90
getNetworkDiffFunction · 0.90
mergeRemoteChangesMethod · 0.80
applyDiffMethod · 0.80
filterChangesByScopeMethod · 0.80

Tested by

no test coverage detected