-
-
Notifications
You must be signed in to change notification settings - Fork 57
Expand file tree
/
Copy pathprotocol.js
More file actions
100 lines (90 loc) · 3.12 KB
/
protocol.js
File metadata and controls
100 lines (90 loc) · 3.12 KB
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
import * as Y from '@y/y'
import * as encoding from 'lib0/encoding'
import * as awarenessProtocol from '@y/protocols/awareness'
import * as array from 'lib0/array'
export const messageSync = 0
export const messageAwareness = 1
export const messageAuth = 2
export const messageQueryAwareness = 3
export const messageSyncStep1 = 0
export const messageSyncStep2 = 1
export const messageSyncUpdate = 2
/**
* Merge a batch of raw awareness updates into a single wire-format awareness message.
*
* Encodes from `aw.meta.keys()` rather than `aw.states.keys()` so that clients removed
* via a `state=null` entry are still emitted (with `state=null`). Using `states.keys()`
* would silently drop disconnect signals, leaving ghost cursors on receiving pods.
*
* @param {Array<Uint8Array>} ms
*/
export const mergeAwarenessUpdates = ms => {
const aw = new awarenessProtocol.Awareness(new Y.Doc())
// The Awareness constructor seeds `setLocalState({})` for its own clientID,
// which would leak as a phantom client to every consumer of the merged bytes.
// Strip it so the merged update reflects only the input messages.
aw.states.delete(aw.clientID)
aw.meta.delete(aw.clientID)
ms.forEach(m => {
awarenessProtocol.applyAwarenessUpdate(aw, m, null)
})
const awBin = encodeAwareness(aw, array.from(aw.meta.keys()))
aw.doc.destroy()
aw.destroy()
return awBin
}
/**
* @param {Uint8Array} sv
*/
export const encodeSyncStep1 = sv => encoding.encode(encoder => {
encoding.writeVarUint(encoder, messageSync)
encoding.writeVarUint(encoder, messageSyncStep1)
encoding.writeVarUint8Array(encoder, sv)
})
/**
* @param {Uint8Array} diff
*/
export const encodeSyncStep2 = diff => encoding.encode(encoder => {
encoding.writeVarUint(encoder, messageSync)
encoding.writeVarUint(encoder, messageSyncStep2)
encoding.writeVarUint8Array(encoder, diff)
})
/**
* @param {encoding.Encoder} encoder
* @param {Uint8Array} update
*/
export const writeSyncUpdate = (encoder, update) => {
encoding.writeVarUint(encoder, messageSync)
encoding.writeVarUint(encoder, messageSyncUpdate)
encoding.writeVarUint8Array(encoder, update)
}
/**
* @param {Uint8Array} update
*/
export const encodeSyncUpdate = update => encoding.encode(encoder => writeSyncUpdate(encoder, update))
/**
* @param {encoding.Encoder} encoder
* @param {Uint8Array} awUpdate
*/
export const writeAwarenessUpdate = (encoder, awUpdate) => {
encoding.writeVarUint(encoder, messageAwareness)
encoding.writeVarUint8Array(encoder, awUpdate)
}
/**
* @param {awarenessProtocol.Awareness} awareness
* @param {Array<number>} clients
*/
export const encodeAwareness = (awareness, clients) => encoding.encode(encoder => {
writeAwarenessUpdate(encoder, awarenessProtocol.encodeAwarenessUpdate(awareness, clients))
})
/**
* @param {number} clientid
* @param {number} lastClock
*/
export const encodeAwarenessUserDisconnected = (clientid, lastClock) =>
encoding.encode(encoder => {
encoding.writeVarUint(encoder, 1) // one change
encoding.writeVarUint(encoder, clientid)
encoding.writeVarUint(encoder, lastClock + 1)
encoding.writeVarString(encoder, JSON.stringify(null))
})