@cuboapp/crdt 1.0.20 → 1.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/client/index.ts +46 -35
- package/src/server/document/index.ts +30 -22
- package/src/server/index.ts +4 -0
package/package.json
CHANGED
package/src/client/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { keyBy, pick, uuid } from '@cuboapp/utils'
|
|
2
2
|
import { WsClientEvent } from '@cuboapp/ws'
|
|
3
|
-
import { computed, reactive } from 'vue'
|
|
3
|
+
import { computed, reactive, shallowReactive } from 'vue'
|
|
4
4
|
import { applyAwarenessUpdate, Awareness, encodeAwarenessUpdate, removeAwarenessStates } from 'y-protocols/awareness'
|
|
5
5
|
import { applyUpdate, Doc } from 'yjs'
|
|
6
6
|
|
|
@@ -234,8 +234,8 @@ export class CuboCrdtClient<M> {
|
|
|
234
234
|
|
|
235
235
|
this.store[storeKey] = {
|
|
236
236
|
state,
|
|
237
|
-
docs: new Map(),
|
|
238
|
-
awarenesses: new Map()
|
|
237
|
+
docs: shallowReactive(new Map()),
|
|
238
|
+
awarenesses: shallowReactive(new Map())
|
|
239
239
|
}
|
|
240
240
|
}
|
|
241
241
|
|
|
@@ -551,6 +551,47 @@ export class CuboCrdtClient<M> {
|
|
|
551
551
|
}
|
|
552
552
|
}
|
|
553
553
|
|
|
554
|
+
private ensureDocumentAwareness(
|
|
555
|
+
ctx: CuboCrdtClientSubscribeEvent,
|
|
556
|
+
opts: CuboCrdtClientDocUpdateOptions,
|
|
557
|
+
doc: Doc,
|
|
558
|
+
entity_id: number
|
|
559
|
+
) {
|
|
560
|
+
if (!opts.awareness) {
|
|
561
|
+
return
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
let awareness = this.store[opts.storeKey]?.awarenesses.get(entity_id)
|
|
565
|
+
|
|
566
|
+
if (awareness) {
|
|
567
|
+
return
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
awareness = new Awareness(doc)
|
|
571
|
+
|
|
572
|
+
awareness.on('update', ({ added, updated, removed }, origin) => {
|
|
573
|
+
if (origin === 'remote') {
|
|
574
|
+
return
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
const changed = added.concat(updated).concat(removed)
|
|
578
|
+
const update = encodeAwarenessUpdate(awareness!, changed)
|
|
579
|
+
|
|
580
|
+
this.ws.request({
|
|
581
|
+
method: CUBO_CRDT_EVENT.EVENT,
|
|
582
|
+
data: {
|
|
583
|
+
action: 'awareness',
|
|
584
|
+
entity: ctx.entity,
|
|
585
|
+
entity_id,
|
|
586
|
+
data: Array.from(update),
|
|
587
|
+
origin: { expose: 'other', subscribe_id: opts.subscribe_id }
|
|
588
|
+
}
|
|
589
|
+
})
|
|
590
|
+
})
|
|
591
|
+
|
|
592
|
+
this.store[opts.storeKey]?.awarenesses.set(entity_id, awareness)
|
|
593
|
+
}
|
|
594
|
+
|
|
554
595
|
private async onDocumentCreate(ctx: CuboCrdtClientSubscribeEvent, opts: CuboCrdtClientDocUpdateOptions) {
|
|
555
596
|
const entity_id = ctx.entity_id
|
|
556
597
|
if (entity_id === undefined) {
|
|
@@ -568,6 +609,7 @@ export class CuboCrdtClient<M> {
|
|
|
568
609
|
|
|
569
610
|
applyUpdate(existing, new Uint8Array(ctx.data as any), { react: false })
|
|
570
611
|
this.applyRowJson(opts.storeKey, entity_id, existing)
|
|
612
|
+
this.ensureDocumentAwareness(ctx, opts, existing, entity_id)
|
|
571
613
|
return
|
|
572
614
|
}
|
|
573
615
|
|
|
@@ -630,38 +672,7 @@ export class CuboCrdtClient<M> {
|
|
|
630
672
|
await opts.onAfterCreate(doc, update, ctx, opts)
|
|
631
673
|
}
|
|
632
674
|
|
|
633
|
-
|
|
634
|
-
let awareness = this.store[opts.storeKey]?.awarenesses.get(entity_id)
|
|
635
|
-
|
|
636
|
-
if (!awareness) {
|
|
637
|
-
awareness = new Awareness(doc)
|
|
638
|
-
|
|
639
|
-
awareness.on('update', ({ added, updated, removed }, origin) => {
|
|
640
|
-
// console.log('[CRDT] awarness update', origin)
|
|
641
|
-
|
|
642
|
-
if (origin === 'remote') {
|
|
643
|
-
return
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
const changed = added.concat(updated).concat(removed)
|
|
647
|
-
const update = encodeAwarenessUpdate(awareness, changed)
|
|
648
|
-
|
|
649
|
-
this.ws.request({
|
|
650
|
-
method: CUBO_CRDT_EVENT.EVENT,
|
|
651
|
-
data: {
|
|
652
|
-
action: 'awareness',
|
|
653
|
-
entity: ctx.entity,
|
|
654
|
-
entity_id,
|
|
655
|
-
data: Array.from(update),
|
|
656
|
-
// 'other' — не шлём свой же курсор обратно исходной подписке
|
|
657
|
-
origin: { expose: 'other', subscribe_id: opts.subscribe_id }
|
|
658
|
-
}
|
|
659
|
-
})
|
|
660
|
-
})
|
|
661
|
-
|
|
662
|
-
this.store[opts.storeKey]?.awarenesses.set(entity_id, awareness)
|
|
663
|
-
}
|
|
664
|
-
}
|
|
675
|
+
this.ensureDocumentAwareness(ctx, opts, doc, entity_id)
|
|
665
676
|
}
|
|
666
677
|
|
|
667
678
|
private async onDocumentUpdate(ctx: CuboCrdtClientSubscribeEvent, opts: CuboCrdtClientDocUpdateOptions) {
|
|
@@ -19,28 +19,7 @@ export class CuboCrdtServerDocument {
|
|
|
19
19
|
})
|
|
20
20
|
|
|
21
21
|
if (opts.awareness) {
|
|
22
|
-
this.
|
|
23
|
-
this.awareness.setLocalState(null)
|
|
24
|
-
|
|
25
|
-
this.awareness.on('update', ({ added, updated, removed }, origin: CuboCrdtServerDocumentOrigin) => {
|
|
26
|
-
const subId = origin?.subscribe_id
|
|
27
|
-
|
|
28
|
-
if (subId) {
|
|
29
|
-
let set = this.awarenessBySubscribe.get(subId)
|
|
30
|
-
if (!set) {
|
|
31
|
-
set = new Set()
|
|
32
|
-
this.awarenessBySubscribe.set(subId, set)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
added.concat(updated).forEach((id) => set!.add(id))
|
|
36
|
-
removed.forEach((id) => set!.delete(id))
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const changed = added.concat(updated).concat(removed)
|
|
40
|
-
const update = encodeAwarenessUpdate(this.awareness!, changed)
|
|
41
|
-
|
|
42
|
-
this.opts?.onAwarenessUpdate?.(update, origin)
|
|
43
|
-
})
|
|
22
|
+
this.enableAwareness()
|
|
44
23
|
}
|
|
45
24
|
|
|
46
25
|
this.persistedState = cloneDeep(opts.initialState ?? {})
|
|
@@ -72,6 +51,35 @@ export class CuboCrdtServerDocument {
|
|
|
72
51
|
})
|
|
73
52
|
}
|
|
74
53
|
|
|
54
|
+
public enableAwareness() {
|
|
55
|
+
if (this.awareness) {
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
this.awareness = new Awareness(this.ydoc)
|
|
60
|
+
this.awareness.setLocalState(null)
|
|
61
|
+
|
|
62
|
+
this.awareness.on('update', ({ added, updated, removed }, origin: CuboCrdtServerDocumentOrigin) => {
|
|
63
|
+
const subId = origin?.subscribe_id
|
|
64
|
+
|
|
65
|
+
if (subId) {
|
|
66
|
+
let set = this.awarenessBySubscribe.get(subId)
|
|
67
|
+
if (!set) {
|
|
68
|
+
set = new Set()
|
|
69
|
+
this.awarenessBySubscribe.set(subId, set)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
added.concat(updated).forEach((id) => set!.add(id))
|
|
73
|
+
removed.forEach((id) => set!.delete(id))
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const changed = added.concat(updated).concat(removed)
|
|
77
|
+
const update = encodeAwarenessUpdate(this.awareness!, changed)
|
|
78
|
+
|
|
79
|
+
this.opts?.onAwarenessUpdate?.(update, origin)
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
|
+
|
|
75
83
|
public get name() {
|
|
76
84
|
return this.opts.name
|
|
77
85
|
}
|
package/src/server/index.ts
CHANGED
|
@@ -605,6 +605,10 @@ export class CuboCrdtServer<M, A = {}, E extends Extract<keyof M, string> = Extr
|
|
|
605
605
|
|
|
606
606
|
let document = this.documents.get(documentName)
|
|
607
607
|
if (document) {
|
|
608
|
+
if (awareness) {
|
|
609
|
+
document.enableAwareness()
|
|
610
|
+
}
|
|
611
|
+
|
|
608
612
|
// Освежаем существующий документ строкой из БД.
|
|
609
613
|
//
|
|
610
614
|
// Раньше документ возвращался как есть, а подписка отправляла клиенту его
|