silverbullet/web/cm_plugins/collab.ts

86 lines
2.6 KiB
TypeScript
Raw Normal View History

2023-05-29 23:05:20 +08:00
import { Extension, HocuspocusProvider, Y, yCollab } from "../deps.ts";
2023-06-02 19:43:49 +08:00
import { SyncService } from "../sync_service.ts";
2022-10-26 00:50:07 +08:00
const userColors = [
{ color: "#30bced", light: "#30bced33" },
{ color: "#6eeb83", light: "#6eeb8333" },
{ color: "#ffbc42", light: "#ffbc4233" },
{ color: "#ecd444", light: "#ecd44433" },
{ color: "#ee6352", light: "#ee635233" },
{ color: "#9ac2c9", light: "#9ac2c933" },
{ color: "#8acb88", light: "#8acb8833" },
{ color: "#1be7ff", light: "#1be7ff33" },
];
export class CollabState {
2023-05-29 23:05:20 +08:00
public ytext: Y.Text;
2023-06-02 19:13:54 +08:00
collabProvider: HocuspocusProvider;
2023-05-29 23:05:20 +08:00
private yundoManager: Y.UndoManager;
2023-06-02 19:13:54 +08:00
constructor(
2023-06-02 19:43:49 +08:00
private serverUrl: string,
private pageName: string,
private token: string,
private username: string,
private syncService: SyncService,
2023-06-02 19:13:54 +08:00
) {
2023-05-29 23:05:20 +08:00
this.collabProvider = new HocuspocusProvider({
url: serverUrl,
2023-06-02 19:43:49 +08:00
name: token,
// 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);
}
}
},
2023-05-29 23:05:20 +08:00
});
2022-10-26 00:50:07 +08:00
this.collabProvider.on("status", (e: any) => {
console.log("Collab status change", e);
});
2023-05-29 23:05:20 +08:00
this.ytext = this.collabProvider.document.getText("codemirror");
2022-10-26 00:50:07 +08:00
this.yundoManager = new Y.UndoManager(this.ytext);
const randomColor =
userColors[Math.floor(Math.random() * userColors.length)];
this.collabProvider.awareness.setLocalStateField("user", {
name: username,
color: randomColor.color,
colorLight: randomColor.light,
});
}
stop() {
2023-05-30 22:28:52 +08:00
console.log("[COLLAB] Destroying collab provider");
2022-10-26 00:50:07 +08:00
this.collabProvider.destroy();
2023-05-30 22:28:52 +08:00
// 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.destroy();
2023-06-02 19:43:49 +08:00
// 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,
);
2022-10-26 00:50:07 +08:00
}
collabExtension(): Extension {
return yCollab(this.ytext, this.collabProvider.awareness, {
undoManager: this.yundoManager,
});
}
}