parent
e27f3f9ad2
commit
4696c9ee0e
20
package-lock.json
generated
20
package-lock.json
generated
@ -2017,6 +2017,21 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.4.tgz",
|
||||||
"integrity": "sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA=="
|
"integrity": "sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA=="
|
||||||
},
|
},
|
||||||
|
"@types/lodash": {
|
||||||
|
"version": "4.14.150",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.150.tgz",
|
||||||
|
"integrity": "sha512-kMNLM5JBcasgYscD9x/Gvr6lTAv2NVgsKtet/hm93qMyf/D1pt+7jeEZklKJKxMVmXjxbRVQQGfqDSfipYCO6w==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"@types/lodash.throttle": {
|
||||||
|
"version": "4.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/lodash.throttle/-/lodash.throttle-4.1.6.tgz",
|
||||||
|
"integrity": "sha512-/UIH96i/sIRYGC60NoY72jGkCJtFN5KVPhEMMMTjol65effe1gPn0tycJqV5tlSwMTzX8FqzB5yAj0rfGHTPNg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/lodash": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/minimatch": {
|
"@types/minimatch": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
|
||||||
@ -9635,6 +9650,11 @@
|
|||||||
"lodash._reinterpolate": "^3.0.0"
|
"lodash._reinterpolate": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"lodash.throttle": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
|
||||||
|
"integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ="
|
||||||
|
},
|
||||||
"lodash.uniq": {
|
"lodash.uniq": {
|
||||||
"version": "4.5.0",
|
"version": "4.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
|
||||||
|
20
package.json
20
package.json
@ -21,9 +21,18 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sentry/browser": "5.15.5",
|
"@sentry/browser": "5.15.5",
|
||||||
"@sentry/integrations": "5.15.5",
|
"@sentry/integrations": "5.15.5",
|
||||||
|
"@testing-library/jest-dom": "5.5.0",
|
||||||
|
"@testing-library/react": "10.0.4",
|
||||||
|
"@types/jest": "25.2.1",
|
||||||
|
"@types/nanoid": "2.1.0",
|
||||||
|
"@types/react": "16.9.34",
|
||||||
|
"@types/react-dom": "16.9.7",
|
||||||
|
"@types/socket.io-client": "1.4.32",
|
||||||
"browser-nativefs": "0.7.1",
|
"browser-nativefs": "0.7.1",
|
||||||
"i18next-browser-languagedetector": "4.1.1",
|
"i18next-browser-languagedetector": "4.1.1",
|
||||||
|
"lodash.throttle": "4.1.1",
|
||||||
"nanoid": "2.1.11",
|
"nanoid": "2.1.11",
|
||||||
|
"node-sass": "4.14.0",
|
||||||
"open-color": "1.7.0",
|
"open-color": "1.7.0",
|
||||||
"points-on-curve": "0.2.0",
|
"points-on-curve": "0.2.0",
|
||||||
"pwacompat": "2.0.11",
|
"pwacompat": "2.0.11",
|
||||||
@ -32,17 +41,10 @@
|
|||||||
"react-scripts": "3.4.1",
|
"react-scripts": "3.4.1",
|
||||||
"roughjs": "4.2.3",
|
"roughjs": "4.2.3",
|
||||||
"socket.io-client": "2.3.0",
|
"socket.io-client": "2.3.0",
|
||||||
"node-sass": "4.14.0",
|
"typescript": "3.8.3"
|
||||||
"typescript": "3.8.3",
|
|
||||||
"@types/jest": "25.2.1",
|
|
||||||
"@types/nanoid": "2.1.0",
|
|
||||||
"@types/react": "16.9.34",
|
|
||||||
"@types/react-dom": "16.9.7",
|
|
||||||
"@types/socket.io-client": "1.4.32",
|
|
||||||
"@testing-library/jest-dom": "5.5.0",
|
|
||||||
"@testing-library/react": "10.0.4"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/lodash.throttle": "4.1.6",
|
||||||
"asar": "3.0.3",
|
"asar": "3.0.3",
|
||||||
"eslint": "6.8.0",
|
"eslint": "6.8.0",
|
||||||
"eslint-config-prettier": "6.11.0",
|
"eslint-config-prettier": "6.11.0",
|
||||||
|
@ -133,6 +133,8 @@ import {
|
|||||||
saveUsernameToLocalStorage,
|
saveUsernameToLocalStorage,
|
||||||
} from "../data/localStorage";
|
} from "../data/localStorage";
|
||||||
|
|
||||||
|
import throttle from "lodash.throttle";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param func handler taking at most single parameter (event).
|
* @param func handler taking at most single parameter (event).
|
||||||
*/
|
*/
|
||||||
@ -163,11 +165,14 @@ const gesture: Gesture = {
|
|||||||
initialScale: null,
|
initialScale: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const SYNC_FULL_SCENE_INTERVAL_MS = 20000;
|
||||||
|
|
||||||
class App extends React.Component<any, AppState> {
|
class App extends React.Component<any, AppState> {
|
||||||
canvas: HTMLCanvasElement | null = null;
|
canvas: HTMLCanvasElement | null = null;
|
||||||
rc: RoughCanvas | null = null;
|
rc: RoughCanvas | null = null;
|
||||||
portal: Portal = new Portal(this);
|
portal: Portal = new Portal(this);
|
||||||
lastBroadcastedOrReceivedSceneVersion: number = -1;
|
lastBroadcastedOrReceivedSceneVersion: number = -1;
|
||||||
|
broadcastedElementVersions: Map<string, number> = new Map();
|
||||||
removeSceneCallback: SceneStateCallbackRemover | null = null;
|
removeSceneCallback: SceneStateCallbackRemover | null = null;
|
||||||
|
|
||||||
actionManager: ActionManager;
|
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() {
|
componentDidUpdate() {
|
||||||
if (this.state.isCollaborating && !this.portal.socket) {
|
if (this.state.isCollaborating && !this.portal.socket) {
|
||||||
this.initializeSocketClient({ showLoadingState: true });
|
this.initializeSocketClient({ showLoadingState: true });
|
||||||
@ -555,7 +564,8 @@ class App extends React.Component<any, AppState> {
|
|||||||
getDrawingVersion(globalSceneState.getElementsIncludingDeleted()) >
|
getDrawingVersion(globalSceneState.getElementsIncludingDeleted()) >
|
||||||
this.lastBroadcastedOrReceivedSceneVersion
|
this.lastBroadcastedOrReceivedSceneVersion
|
||||||
) {
|
) {
|
||||||
this.broadcastScene(SCENE.UPDATE);
|
this.broadcastScene(SCENE.UPDATE, /* syncAll */ false);
|
||||||
|
this.queueBroadcastAllElements();
|
||||||
}
|
}
|
||||||
|
|
||||||
history.record(this.state, globalSceneState.getElementsIncludingDeleted());
|
history.record(this.state, globalSceneState.getElementsIncludingDeleted());
|
||||||
@ -1020,19 +1030,43 @@ class App extends React.Component<any, AppState> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// maybe should move to Portal
|
// 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] = {
|
const data: SocketUpdateDataSource[typeof sceneType] = {
|
||||||
type: sceneType,
|
type: sceneType,
|
||||||
payload: {
|
payload: {
|
||||||
elements: getSyncableElements(
|
elements: syncableElements,
|
||||||
globalSceneState.getElementsIncludingDeleted(),
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
this.lastBroadcastedOrReceivedSceneVersion = Math.max(
|
this.lastBroadcastedOrReceivedSceneVersion = Math.max(
|
||||||
this.lastBroadcastedOrReceivedSceneVersion,
|
this.lastBroadcastedOrReceivedSceneVersion,
|
||||||
getDrawingVersion(globalSceneState.getElementsIncludingDeleted()),
|
getDrawingVersion(globalSceneState.getElementsIncludingDeleted()),
|
||||||
);
|
);
|
||||||
|
for (const syncableElement of syncableElements) {
|
||||||
|
this.broadcastedElementVersions.set(
|
||||||
|
syncableElement.id,
|
||||||
|
syncableElement.version,
|
||||||
|
);
|
||||||
|
}
|
||||||
return this.portal._broadcastSocketData(data as SocketUpdateData);
|
return this.portal._broadcastSocketData(data as SocketUpdateData);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ class Portal {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.socket.on("new-user", async (_socketID: string) => {
|
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.socket.on("room-user-change", (clients: string[]) => {
|
||||||
this.app.setCollaborators(clients);
|
this.app.setCollaborators(clients);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user