Syncing optimizations (#1554)

* Syncing optimizations

* Add comment
This commit is contained in:
Pete Hunt 2020-05-07 14:13:18 -07:00 committed by GitHub
parent e27f3f9ad2
commit 4696c9ee0e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 71 additions and 15 deletions

View file

@ -133,6 +133,8 @@ import {
saveUsernameToLocalStorage,
} from "../data/localStorage";
import throttle from "lodash.throttle";
/**
* @param func handler taking at most single parameter (event).
*/
@ -163,11 +165,14 @@ const gesture: Gesture = {
initialScale: null,
};
const SYNC_FULL_SCENE_INTERVAL_MS = 20000;
class App extends React.Component<any, AppState> {
canvas: HTMLCanvasElement | null = null;
rc: RoughCanvas | null = null;
portal: Portal = new Portal(this);
lastBroadcastedOrReceivedSceneVersion: number = -1;
broadcastedElementVersions: Map<string, number> = new Map();
removeSceneCallback: SceneStateCallbackRemover | null = null;
actionManager: ActionManager;
@ -474,6 +479,10 @@ class App extends React.Component<any, AppState> {
}
});
queueBroadcastAllElements = throttle(() => {
this.broadcastScene(SCENE.UPDATE, /* syncAll */ true);
}, SYNC_FULL_SCENE_INTERVAL_MS);
componentDidUpdate() {
if (this.state.isCollaborating && !this.portal.socket) {
this.initializeSocketClient({ showLoadingState: true });
@ -555,7 +564,8 @@ class App extends React.Component<any, AppState> {
getDrawingVersion(globalSceneState.getElementsIncludingDeleted()) >
this.lastBroadcastedOrReceivedSceneVersion
) {
this.broadcastScene(SCENE.UPDATE);
this.broadcastScene(SCENE.UPDATE, /* syncAll */ false);
this.queueBroadcastAllElements();
}
history.record(this.state, globalSceneState.getElementsIncludingDeleted());
@ -1020,19 +1030,43 @@ class App extends React.Component<any, AppState> {
};
// maybe should move to Portal
broadcastScene = (sceneType: SCENE.INIT | SCENE.UPDATE) => {
broadcastScene = (sceneType: SCENE.INIT | SCENE.UPDATE, syncAll: boolean) => {
if (sceneType === SCENE.INIT && !syncAll) {
throw new Error("syncAll must be true when sending SCENE.INIT");
}
let syncableElements = getSyncableElements(
globalSceneState.getElementsIncludingDeleted(),
);
if (!syncAll) {
// sync out only the elements we think we need to to save bandwidth.
// periodically we'll resync the whole thing to make sure no one diverges
// due to a dropped message (server goes down etc).
syncableElements = syncableElements.filter(
(syncableElement) =>
!this.broadcastedElementVersions.has(syncableElement.id) ||
syncableElement.version >
this.broadcastedElementVersions.get(syncableElement.id)!,
);
}
const data: SocketUpdateDataSource[typeof sceneType] = {
type: sceneType,
payload: {
elements: getSyncableElements(
globalSceneState.getElementsIncludingDeleted(),
),
elements: syncableElements,
},
};
this.lastBroadcastedOrReceivedSceneVersion = Math.max(
this.lastBroadcastedOrReceivedSceneVersion,
getDrawingVersion(globalSceneState.getElementsIncludingDeleted()),
);
for (const syncableElement of syncableElements) {
this.broadcastedElementVersions.set(
syncableElement.id,
syncableElement.version,
);
}
return this.portal._broadcastSocketData(data as SocketUpdateData);
};

View file

@ -29,7 +29,7 @@ class Portal {
}
});
this.socket.on("new-user", async (_socketID: string) => {
this.app.broadcastScene(SCENE.INIT);
this.app.broadcastScene(SCENE.INIT, /* syncAll */ true);
});
this.socket.on("room-user-change", (clients: string[]) => {
this.app.setCollaborators(clients);