Refactoring

deno-express
Zef Hemel 2023-06-02 13:43:49 +02:00
parent 610fe9de6d
commit eebf920a9d
4 changed files with 51 additions and 42 deletions

View File

@ -1,4 +1,5 @@
import { Extension, HocuspocusProvider, Y, yCollab } from "../deps.ts"; import { Extension, HocuspocusProvider, Y, yCollab } from "../deps.ts";
import { SyncService } from "../sync_service.ts";
const userColors = [ const userColors = [
{ color: "#30bced", light: "#30bced33" }, { color: "#30bced", light: "#30bced33" },
@ -17,15 +18,31 @@ export class CollabState {
private yundoManager: Y.UndoManager; private yundoManager: Y.UndoManager;
constructor( constructor(
serverUrl: string, private serverUrl: string,
name: string, private pageName: string,
username: string, private token: string,
onStateless: (data: any) => any, private username: string,
private syncService: SyncService,
) { ) {
this.collabProvider = new HocuspocusProvider({ this.collabProvider = new HocuspocusProvider({
url: serverUrl, url: serverUrl,
name: name, name: token,
onStateless,
// Receive broadcasted messages from the server (right now only "page has been persisted" notifications)
onStateless: (
{ payload },
) => {
const message = JSON.parse(payload);
switch (message.type) {
case "persisted": {
// Received remote persist notification, updating snapshot
syncService.updateRemoteLastModified(
message.path,
message.lastModified,
).catch(console.error);
}
}
},
}); });
this.collabProvider.on("status", (e: any) => { this.collabProvider.on("status", (e: any) => {
@ -46,12 +63,18 @@ export class CollabState {
} }
stop() { stop() {
// this.collabProvider.disconnect();
console.log("[COLLAB] Destroying collab provider"); console.log("[COLLAB] Destroying collab provider");
this.collabProvider.destroy(); this.collabProvider.destroy();
// For whatever reason, destroy() doesn't properly clean up everything so we need to help a bit // For whatever reason, destroy() doesn't properly clean up everything so we need to help a bit
this.collabProvider.configuration.websocketProvider.webSocket = null; this.collabProvider.configuration.websocketProvider.webSocket = null;
this.collabProvider.configuration.websocketProvider.destroy(); this.collabProvider.configuration.websocketProvider.destroy();
// When stopping collaboration, we're going back to sync mode. Make sure we got the latest and greatest remote timestamp to avoid
// conflicts
this.syncService.fetchAndPersistRemoteLastModified(`${this.pageName}.md`)
.catch(
console.error,
);
} }
collabExtension(): Extension { collabExtension(): Extension {

View File

@ -1155,7 +1155,7 @@ export class Editor {
await this.save(true); await this.save(true);
// And stop the collab session // And stop the collab session
if (this.collabState) { if (this.collabState) {
this.stopCollab(previousPage); this.stopCollab();
} }
} }
} }
@ -1525,49 +1525,25 @@ export class Editor {
this.collabState.stop(); this.collabState.stop();
} }
const initialText = this.editorView!.state.sliceDoc(); const initialText = this.editorView!.state.sliceDoc();
this.collabState = new CollabState(serverUrl, token, username, ( this.collabState = new CollabState(
{ payload }, serverUrl,
) => { this.currentPage!,
const message = JSON.parse(payload); token,
switch (message.type) { username,
case "persisted": { this.syncService,
// console.log( );
// "Received remote persist notification, updating snapshot",
// message,
// );
this.syncService.updateRemoteLastModified(
message.path,
message.lastModified,
).catch(console.error);
}
}
});
// this.collabState.collabProvider.on("synced", () => {
// if (this.collabState?.ytext.toString() === "") {
// console.error("Synced value is empty, putting back original text");
// this.collabState?.ytext.insert(0, initialText);
// }
// });
this.rebuildEditorState(); this.rebuildEditorState();
// Don't watch for local changes in this mode // Don't watch for local changes in this mode
this.space.unwatch(); this.space.unwatch();
} }
stopCollab(pageName: string) { stopCollab() {
if (this.collabState) { if (this.collabState) {
this.collabState.stop(); this.collabState.stop();
this.collabState = undefined; this.collabState = undefined;
this.rebuildEditorState(); this.rebuildEditorState();
// Switching off collab mode
this.syncService.remoteSpace.getFileMeta(`${pageName}.md`).then(
(meta) => {
return this.syncService.updateRemoteLastModified(
meta.name,
meta.lastModified,
);
},
).catch(console.error);
} }
// Start file watching again // Start file watching again
this.space.watch(); this.space.watch();

View File

@ -165,6 +165,16 @@ export class SyncService {
await this.registerSyncStop(); await this.registerSyncStop();
} }
// Reach out out to remote space, fetch the latest lastModified time and update the local snapshot
// This is used when exiting collab mode
async fetchAndPersistRemoteLastModified(path: string) {
const meta = await this.remoteSpace.getFileMeta(path);
await this.updateRemoteLastModified(
meta.name,
meta.lastModified,
);
}
// When in collab mode, we delegate the sync to the CDRT engine, to avoid conflicts, we try to keep the lastModified time in sync when local changes happen // When in collab mode, we delegate the sync to the CDRT engine, to avoid conflicts, we try to keep the lastModified time in sync when local changes happen
async updateLocalLastModified(path: string, lastModified: number) { async updateLocalLastModified(path: string, lastModified: number) {
await this.noOngoingSync(); await this.noOngoingSync();

View File

@ -14,7 +14,7 @@ export function collabSyscalls(editor: Editor): SysCallMapping {
"collab.stop": ( "collab.stop": (
_ctx, _ctx,
) => { ) => {
editor.stopCollab(editor.currentPage!); editor.stopCollab();
}, },
"collab.ping": async ( "collab.ping": async (
_ctx, _ctx,