@nxtedition/deepstream.io-client-js 31.2.17 → 31.2.19
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/record/record-handler.js +82 -73
- package/src/record/record.js +74 -12
package/package.json
CHANGED
|
@@ -35,7 +35,7 @@ const GET2_DEFAULTS = {
|
|
|
35
35
|
|
|
36
36
|
function onSync(subscription) {
|
|
37
37
|
subscription.synced = true
|
|
38
|
-
onUpdate(
|
|
38
|
+
onUpdate(null, subscription)
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
function onUpdate(record, subscription) {
|
|
@@ -128,7 +128,7 @@ class RecordHandler {
|
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
this._syncQueue = []
|
|
131
|
-
this._syncMap =
|
|
131
|
+
this._syncMap = new Map()
|
|
132
132
|
|
|
133
133
|
this.set = this.set.bind(this)
|
|
134
134
|
this.get = this.get.bind(this)
|
|
@@ -228,13 +228,18 @@ class RecordHandler {
|
|
|
228
228
|
* @returns {Record}
|
|
229
229
|
*/
|
|
230
230
|
getRecord(name) {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
231
|
+
if (typeof name !== 'string' || name.length === 0) {
|
|
232
|
+
throw new Error('invalid argument: name')
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (name.startsWith('null') || name.startsWith('undefined') || name === '[object Object]') {
|
|
236
|
+
this._client._$onError(
|
|
237
|
+
C.TOPIC.RECORD,
|
|
238
|
+
C.EVENT.USER_ERROR,
|
|
239
|
+
'name should not start with null or undefined',
|
|
240
|
+
name,
|
|
241
|
+
)
|
|
242
|
+
}
|
|
238
243
|
|
|
239
244
|
let record = this._records.get(name)
|
|
240
245
|
|
|
@@ -561,78 +566,78 @@ class RecordHandler {
|
|
|
561
566
|
* @returns {rxjs.Observable}
|
|
562
567
|
*/
|
|
563
568
|
_observe(defaults, name, ...args) {
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
let sync = defaults?.sync ?? false
|
|
571
|
-
|
|
572
|
-
let idx = 0
|
|
573
|
-
|
|
574
|
-
if (
|
|
575
|
-
idx < args.length &&
|
|
576
|
-
(args[idx] == null ||
|
|
577
|
-
typeof args[idx] === 'string' ||
|
|
578
|
-
Array.isArray(args[idx]) ||
|
|
579
|
-
typeof args[idx] === 'function')
|
|
580
|
-
) {
|
|
581
|
-
path = args[idx++]
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
if (idx < args.length && (args[idx] == null || typeof args[idx] === 'number')) {
|
|
585
|
-
state = args[idx++]
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
if (idx < args.length && (args[idx] == null || typeof args[idx] === 'object')) {
|
|
589
|
-
const options = args[idx++] || {}
|
|
590
|
-
|
|
591
|
-
if (options.signal !== undefined) {
|
|
592
|
-
signal = options.signal
|
|
593
|
-
}
|
|
569
|
+
let path
|
|
570
|
+
let state = defaults?.state ?? C.RECORD_STATE.CLIENT
|
|
571
|
+
let signal = null
|
|
572
|
+
let timeout = defaults?.timeout ?? 0
|
|
573
|
+
let dataOnly = defaults?.dataOnly ?? false
|
|
574
|
+
let sync = defaults?.sync ?? false
|
|
594
575
|
|
|
595
|
-
|
|
596
|
-
timeout = options.timeout
|
|
597
|
-
}
|
|
576
|
+
let idx = 0
|
|
598
577
|
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
578
|
+
if (
|
|
579
|
+
idx < args.length &&
|
|
580
|
+
(args[idx] == null ||
|
|
581
|
+
typeof args[idx] === 'string' ||
|
|
582
|
+
Array.isArray(args[idx]) ||
|
|
583
|
+
typeof args[idx] === 'function')
|
|
584
|
+
) {
|
|
585
|
+
path = args[idx++]
|
|
586
|
+
}
|
|
602
587
|
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
588
|
+
if (idx < args.length && (args[idx] == null || typeof args[idx] === 'number')) {
|
|
589
|
+
state = args[idx++]
|
|
590
|
+
}
|
|
606
591
|
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
}
|
|
592
|
+
if (idx < args.length && (args[idx] == null || typeof args[idx] === 'object')) {
|
|
593
|
+
const options = args[idx++] || {}
|
|
610
594
|
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
}
|
|
595
|
+
if (options.signal !== undefined) {
|
|
596
|
+
signal = options.signal
|
|
614
597
|
}
|
|
615
598
|
|
|
616
|
-
if (
|
|
617
|
-
|
|
599
|
+
if (options.timeout !== undefined) {
|
|
600
|
+
timeout = options.timeout
|
|
618
601
|
}
|
|
619
602
|
|
|
620
|
-
if (
|
|
621
|
-
|
|
603
|
+
if (options.path !== undefined) {
|
|
604
|
+
path = options.path
|
|
622
605
|
}
|
|
623
606
|
|
|
624
|
-
if (
|
|
625
|
-
|
|
607
|
+
if (options.state !== undefined) {
|
|
608
|
+
state = options.state
|
|
626
609
|
}
|
|
627
610
|
|
|
628
|
-
if (
|
|
629
|
-
|
|
611
|
+
if (options.dataOnly !== undefined) {
|
|
612
|
+
dataOnly = options.dataOnly
|
|
630
613
|
}
|
|
631
614
|
|
|
632
|
-
if (
|
|
633
|
-
|
|
615
|
+
if (options.sync !== undefined) {
|
|
616
|
+
sync = options.sync
|
|
634
617
|
}
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
if (typeof state === 'string') {
|
|
621
|
+
state = C.RECORD_STATE[state.toUpperCase()]
|
|
622
|
+
}
|
|
635
623
|
|
|
624
|
+
if (!Number.isInteger(state) || state < 0) {
|
|
625
|
+
throw new Error('invalid argument: state')
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
if (!Number.isInteger(timeout) || timeout < 0) {
|
|
629
|
+
throw new Error('invalid argument: timeout')
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
if (typeof dataOnly !== 'boolean') {
|
|
633
|
+
throw new Error('invalid argument: dataOnly')
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
if (typeof sync !== 'boolean') {
|
|
637
|
+
throw new Error('invalid argument: sync')
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
return new rxjs.Observable((subscriber) => {
|
|
636
641
|
// TODO (perf): Make a class
|
|
637
642
|
const subscription = {
|
|
638
643
|
/** @readonly @type {unknown} */
|
|
@@ -658,6 +663,9 @@ class RecordHandler {
|
|
|
658
663
|
data: kEmpty,
|
|
659
664
|
/** @type {boolean} */
|
|
660
665
|
synced: false,
|
|
666
|
+
|
|
667
|
+
index: -1,
|
|
668
|
+
onUpdate,
|
|
661
669
|
}
|
|
662
670
|
|
|
663
671
|
subscriber.add(() => {
|
|
@@ -673,7 +681,7 @@ class RecordHandler {
|
|
|
673
681
|
}
|
|
674
682
|
|
|
675
683
|
if (subscription.record) {
|
|
676
|
-
subscription.record.
|
|
684
|
+
subscription.record._unobserve(subscription)
|
|
677
685
|
subscription.record.unref()
|
|
678
686
|
subscription.record = null
|
|
679
687
|
}
|
|
@@ -684,10 +692,11 @@ class RecordHandler {
|
|
|
684
692
|
utils.addAbortListener(subscription.signal, subscription.abort)
|
|
685
693
|
}
|
|
686
694
|
|
|
687
|
-
subscription.record = this.getRecord(name)
|
|
695
|
+
subscription.record = this.getRecord(name)
|
|
696
|
+
subscription.record._observe(subscription)
|
|
688
697
|
|
|
689
698
|
if (sync) {
|
|
690
|
-
this._sync(onSync, sync
|
|
699
|
+
this._sync(onSync, sync, subscription)
|
|
691
700
|
} else {
|
|
692
701
|
onSync(subscription)
|
|
693
702
|
}
|
|
@@ -708,8 +717,8 @@ class RecordHandler {
|
|
|
708
717
|
return true
|
|
709
718
|
}
|
|
710
719
|
|
|
711
|
-
const sync = this._syncMap
|
|
712
|
-
|
|
720
|
+
const sync = this._syncMap.get(token)
|
|
721
|
+
this._syncMap.delete(token)
|
|
713
722
|
|
|
714
723
|
if (!sync) {
|
|
715
724
|
return true
|
|
@@ -752,10 +761,10 @@ class RecordHandler {
|
|
|
752
761
|
this._connection.sendMsg(C.TOPIC.RECORD, C.ACTIONS.PUT, update)
|
|
753
762
|
}
|
|
754
763
|
|
|
755
|
-
const syncMap =
|
|
756
|
-
for (const sync of
|
|
764
|
+
const syncMap = new Map()
|
|
765
|
+
for (const sync of this._syncMap.values()) {
|
|
757
766
|
const token = xuid()
|
|
758
|
-
syncMap
|
|
767
|
+
syncMap.set(token, sync)
|
|
759
768
|
this._connection.sendMsg(
|
|
760
769
|
C.TOPIC.RECORD,
|
|
761
770
|
C.ACTIONS.SYNC,
|
|
@@ -790,7 +799,7 @@ class RecordHandler {
|
|
|
790
799
|
const token = xuid()
|
|
791
800
|
const queue = this._syncQueue.splice(0)
|
|
792
801
|
|
|
793
|
-
this._syncMap
|
|
802
|
+
this._syncMap.set(token, { queue, type })
|
|
794
803
|
this._connection.sendMsg(C.TOPIC.RECORD, C.ACTIONS.SYNC, type ? [token, type] : [token])
|
|
795
804
|
}, 1)
|
|
796
805
|
}
|
package/src/record/record.js
CHANGED
|
@@ -20,7 +20,13 @@ class Record {
|
|
|
20
20
|
this._state = C.RECORD_STATE.VOID
|
|
21
21
|
this._refs = 0
|
|
22
22
|
this._subscriptions = []
|
|
23
|
-
|
|
23
|
+
|
|
24
|
+
/** @type {Array|null} */
|
|
25
|
+
this._emittingArr = null
|
|
26
|
+
/** @type {number} */
|
|
27
|
+
this._emittingIndex = -1
|
|
28
|
+
|
|
29
|
+
this._observers = []
|
|
24
30
|
|
|
25
31
|
/** @type Map? */ this._updating = null
|
|
26
32
|
/** @type Array? */ this._patching = null
|
|
@@ -88,9 +94,8 @@ class Record {
|
|
|
88
94
|
* @returns {Record}
|
|
89
95
|
*/
|
|
90
96
|
subscribe(fn, opaque = null) {
|
|
91
|
-
if (this.
|
|
97
|
+
if (this._emittingArr == this._subscriptions) {
|
|
92
98
|
this._subscriptions = this._subscriptions.slice()
|
|
93
|
-
this._emitting = false
|
|
94
99
|
}
|
|
95
100
|
|
|
96
101
|
this._subscriptions.push(fn, opaque)
|
|
@@ -105,9 +110,8 @@ class Record {
|
|
|
105
110
|
* @returns {Record}
|
|
106
111
|
*/
|
|
107
112
|
unsubscribe(fn, opaque = null) {
|
|
108
|
-
if (this.
|
|
113
|
+
if (this._emittingArr == this._subscriptions) {
|
|
109
114
|
this._subscriptions = this._subscriptions.slice()
|
|
110
|
-
this._emitting = false
|
|
111
115
|
}
|
|
112
116
|
|
|
113
117
|
let idx = -1
|
|
@@ -128,6 +132,41 @@ class Record {
|
|
|
128
132
|
return this
|
|
129
133
|
}
|
|
130
134
|
|
|
135
|
+
/**
|
|
136
|
+
* @note Subscribers are unordered.
|
|
137
|
+
* @param {{ index: number, onUpdate: (Record) => void}} subscription
|
|
138
|
+
*/
|
|
139
|
+
_observe(subscription) {
|
|
140
|
+
if (subscription.index != null && subscription.index !== -1) {
|
|
141
|
+
throw new Error('already observing')
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
subscription.index = this._observers.push(subscription) - 1
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* @param {{ index: number, onUpdate: (Record) => void}} subscription
|
|
149
|
+
*/
|
|
150
|
+
_unobserve(subscription) {
|
|
151
|
+
if (subscription.index == null || subscription.index === -1) {
|
|
152
|
+
throw new Error('not observing')
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (this._emittingArr === this._observers) {
|
|
156
|
+
// TODO (perf): Shift from start if emitting?
|
|
157
|
+
this._observers = this._observers.slice()
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const idx = subscription.index
|
|
161
|
+
const tmp = this._observers.pop()
|
|
162
|
+
subscription.index = -1
|
|
163
|
+
|
|
164
|
+
if (tmp !== subscription) {
|
|
165
|
+
this._observers[idx] = tmp
|
|
166
|
+
this._observers[idx].index = idx
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
131
170
|
get(path) {
|
|
132
171
|
if (!path) {
|
|
133
172
|
return this._data
|
|
@@ -515,18 +554,41 @@ class Record {
|
|
|
515
554
|
}
|
|
516
555
|
|
|
517
556
|
_emitUpdate() {
|
|
518
|
-
this.
|
|
557
|
+
if (this._emittingArr != null) {
|
|
558
|
+
throw new Error('cannot reenter emitUpdate')
|
|
559
|
+
}
|
|
519
560
|
|
|
520
|
-
|
|
521
|
-
|
|
561
|
+
try {
|
|
562
|
+
const arr = this._subscriptions
|
|
563
|
+
const len = arr.length
|
|
522
564
|
|
|
523
|
-
|
|
524
|
-
|
|
565
|
+
this._emittingArr = arr
|
|
566
|
+
for (let n = 0; n < len; n += 2) {
|
|
567
|
+
this._emittingIndex = n
|
|
568
|
+
// TODO (fix): What if this throws?
|
|
569
|
+
arr[n + 0](this, arr[n + 1])
|
|
570
|
+
}
|
|
571
|
+
} finally {
|
|
572
|
+
this._emittingArr = null
|
|
573
|
+
this._emittingIndex = -1
|
|
525
574
|
}
|
|
526
575
|
|
|
527
|
-
|
|
576
|
+
try {
|
|
577
|
+
const arr = this._observers
|
|
578
|
+
const len = arr.length
|
|
528
579
|
|
|
529
|
-
|
|
580
|
+
this._emittingArr = arr
|
|
581
|
+
for (let n = 0; n < len; n++) {
|
|
582
|
+
this._emittingIndex = n
|
|
583
|
+
// TODO (fix): What if this throws?
|
|
584
|
+
arr[n].onUpdate(this, arr[n])
|
|
585
|
+
}
|
|
586
|
+
} finally {
|
|
587
|
+
this._emittingArr = null
|
|
588
|
+
this._emittingIndex = -1
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
this._handler._client.emit('recordUpdated', this)
|
|
530
592
|
}
|
|
531
593
|
}
|
|
532
594
|
|