Skip to content

Commit e69dad8

Browse files
committed
fix a collaboration bug where a collaborator resyncing after timeout would cause the project to duplicate
1 parent 255bab9 commit e69dad8

2 files changed

Lines changed: 42 additions & 3 deletions

File tree

‎src/addons/addons/collaboration/helpers/helper.js‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,24 @@ export function reconcileExtensionsToYjs() {
778778
}, constants.LOCAL_EVENT_SYNC_ORIGIN);
779779
}
780780

781+
/*
782+
* How many stages the document describes.
783+
*
784+
* A project has exactly one. A document with two is two projects laid on top of each other,
785+
* this is used as a canary to prevent a really rare edge case (revolving around timeout and yjs resync behavior)
786+
*/
787+
export function stagesDescribed() {
788+
const sharedSprites = constants.mutableRefs.sharedSprites;
789+
const sharedSpriteData = constants.mutableRefs.sharedSpriteData;
790+
if (!sharedSprites || !sharedSpriteData) return 0;
791+
let stages = 0;
792+
for (const id of new Set(sharedSprites.toArray())) {
793+
const meta = sharedSpriteData.get(id);
794+
if (meta && meta.get('isStage')) stages++;
795+
}
796+
return stages;
797+
}
798+
781799
export function remapTargetIdsFromYjs() {
782800
const vm = constants.mutableRefs.vm;
783801
const sharedSprites = constants.mutableRefs.sharedSprites;

‎src/addons/addons/collaboration/userscript.js‎

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,10 +153,25 @@ function attachYjsProvider() {
153153

154154
constants.mutableRefs.provider.connect();
155155

156+
let rejoinScheduled = false;
157+
const describedTwice = where => {
158+
const stages = helper.stagesDescribed();
159+
if (stages <= 1) return false;
160+
if (!rejoinScheduled) {
161+
rejoinScheduled = true;
162+
console.warn(`[collaboration] the room's document describes ${stages} stages (${where}): ` +
163+
'this tab holds a room that was put away while it was idle. Rejoining with an empty document');
164+
recorder.record('session.described-twice', {where, stages});
165+
setTimeout(() => restartWithoutSnapshot(), 0);
166+
}
167+
return true;
168+
};
169+
156170
const applySpriteListFromYjs = () => {
157171
const vm = constants.mutableRefs.vm;
158172
const runtime = vm.runtime;
159173
const sharedSpriteData = constants.mutableRefs.sharedSpriteData;
174+
if (describedTwice('sprite list')) return;
160175

161176
const remoteIds = [...new Set(constants.mutableRefs.sharedSprites.toArray())];
162177
const remoteIdSet = new Set(remoteIds);
@@ -892,6 +907,7 @@ function attachYjsProvider() {
892907
constants.mutableRefs.vm.on('COLLABORATION_EXTENSION_ADDED', handleExtensionAdded);
893908
runInitialSync = () => {
894909
if (!constants.mutableRefs.ydoc) return;
910+
if (describedTwice('initial sync')) return;
895911
constants.mutableRefs.isInitialRoomSync = true;
896912
cancelPendingSpritePublishes();
897913
try {
@@ -925,6 +941,12 @@ function attachYjsProvider() {
925941
type: 'scratch-gui/collaboration/SET_COLLAB_ACTIVE',
926942
payload: true
927943
});
944+
// The cleanup that precedes a rejoin raises the "please reload" modal, this tab is
945+
// back in the room, so it comes down again.
946+
constants.mutableRefs.addon.tab.redux.dispatch({
947+
type: 'scratch-gui/collaboration/SET_DISCONNECTED',
948+
payload: false
949+
});
928950
}
929951
};
930952

@@ -953,6 +975,8 @@ function attachYjsProvider() {
953975

954976
recorder.record('provider.synced', {first: !hasSynced, generation: heldGeneration});
955977

978+
if (describedTwice(hasSynced ? 'reconnect' : 'first sync')) return;
979+
956980
if (!hasSynced) {
957981
const seeded = collabSnapshot.getSnapshot();
958982
const roomGeneration = constants.mutableRefs.ydoc.getMap('meta').get('roomGeneration');
@@ -1533,9 +1557,6 @@ function attachYjsProvider() {
15331557
constants.mutableRefs.isUiTransition = false;
15341558
constants.mutableRefs.roomUUID = null;
15351559
scheduler.reset();
1536-
1537-
if (window.collab) delete window.collab;
1538-
15391560
};
15401561

15411562
const handleBeforeUnload = () => {

0 commit comments

Comments
 (0)