forked from we-miks/collaborative-editor
-
Notifications
You must be signed in to change notification settings - Fork 0
/
synchronizer.js
120 lines (85 loc) · 2.95 KB
/
synchronizer.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import EditorEvents from "./editor-events";
import ReconnectingWebSocket from "reconnecting-websocket";
import ShareDB from "sharedb/lib/client";
class Synchronizer {
constructor (editor, composition) {
this.editor = editor;
this.doc = null;
this.debug = false;
this.composition = composition;
this.heartbeat = null;
this.socket = null;
}
submitDeltaToUpstream(delta) {
this.doc.submitOp(delta, {source: 'user'});
}
syncThroughWebsocket(endpoint, collection, docId) {
this.close();
this.socket = new ReconnectingWebSocket(endpoint);
let connection = new ShareDB.Connection(this.socket);
this.syncShareDBDocument(connection.get(collection, docId));
// Send heartbeat message to keep websocket connection alive
let self = this;
this.socket.addEventListener("open", () => {
self.heartbeat = setInterval(() => {
self.socket.send('{"a":"hs"}');
}, 5000);
});
this.socket.addEventListener("close", () => {
clearInterval(self.heartbeat);
});
return this.socket;
}
syncShareDBDocument(shareDBDocument) {
this.doc = shareDBDocument;
let self = this;
shareDBDocument.subscribe(function(err) {
if (err) {
self.log(err);
throw err;
}
if(self.doc.type === null) {
throw new Error("doc does not exist.");
}
self.editor.dispatchEvent(EditorEvents.beforeSync, shareDBDocument);
self.composition.setEditorContent(self.doc.data);
shareDBDocument.on('op', function(delta, source) {
if(source === 'user')
return;
if(!delta.ops || delta.ops.length === 0)
return;
self.composition.submitToEditor(delta);
});
shareDBDocument.on('del', function() {
// The doc has been deleted.
// Local session should be terminated.
self.close();
self.editor.dispatchEvent(EditorEvents.documentDeleted, shareDBDocument);
});
shareDBDocument.on('error', function(err) {
self.editor.dispatchEvent(EditorEvents.synchronizationError, err);
});
// Initialize history recording
self.editor.quill.getModule("history").init(self.editor);
self.editor.dispatchEvent(EditorEvents.documentLoaded, shareDBDocument);
});
}
close() {
if(this.doc) {
this.doc.destroy();
this.doc = null;
}
if(this.socket) {
this.socket.close();
this.socket = null;
}
}
log(msg){
if(!this.debug)
{
return;
}
console.log(msg);
}
}
export default Synchronizer;