@mblaney/holster 1.0.17 → 1.0.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/build/holster.js +3 -3
- package/build/holster.js.map +3 -3
- package/package.json +1 -1
- package/src/holster.js +13 -19
- package/src/wire.js +64 -44
package/package.json
CHANGED
package/src/holster.js
CHANGED
|
@@ -568,25 +568,19 @@ const Holster = opt => {
|
|
|
568
568
|
if (id) {
|
|
569
569
|
// It's a rel, read the related node. It might not be in the graph
|
|
570
570
|
// yet when the listener fires, so we retry with delays.
|
|
571
|
-
const attemptRead = (retries = 0) => {
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
// Give up after retries
|
|
585
|
-
cb(null)
|
|
586
|
-
}
|
|
587
|
-
},
|
|
588
|
-
_opt,
|
|
589
|
-
)
|
|
571
|
+
const attemptRead = async (retries = 0) => {
|
|
572
|
+
const data = await new Promise(res => {
|
|
573
|
+
const _ctxid = utils.text.random()
|
|
574
|
+
allctx.set(_ctxid, {chain: [{item: null, soul: id}]})
|
|
575
|
+
api(_ctxid).next(null, res, _opt)
|
|
576
|
+
})
|
|
577
|
+
if (data !== null || retries >= 5) {
|
|
578
|
+
cb(data)
|
|
579
|
+
} else {
|
|
580
|
+
// Data not ready, retry after delay
|
|
581
|
+
await new Promise(resolve => setTimeout(resolve, 50))
|
|
582
|
+
attemptRead(retries + 1)
|
|
583
|
+
}
|
|
590
584
|
}
|
|
591
585
|
attemptRead()
|
|
592
586
|
} else {
|
package/src/wire.js
CHANGED
|
@@ -15,7 +15,7 @@ if (typeof globalThis.WebSocket === "undefined") {
|
|
|
15
15
|
// Rate limiting with throttling
|
|
16
16
|
const createRateLimiter = isTestEnv => {
|
|
17
17
|
const clients = new Map()
|
|
18
|
-
const maxRequests =
|
|
18
|
+
const maxRequests = 1000 // requests per minute
|
|
19
19
|
const windowMs = 60000 // 1 minute window
|
|
20
20
|
const disconnectThreshold = 10 // Disconnect after 10 violations
|
|
21
21
|
let cleanupInterval = null
|
|
@@ -277,6 +277,18 @@ const Wire = opt => {
|
|
|
277
277
|
)
|
|
278
278
|
})
|
|
279
279
|
}
|
|
280
|
+
|
|
281
|
+
// Always broadcast original data to other peers even if no local update
|
|
282
|
+
const sendResult = send(
|
|
283
|
+
JSON.stringify({
|
|
284
|
+
"#": dup.track(utils.text.random(9)),
|
|
285
|
+
put: msg.put,
|
|
286
|
+
}),
|
|
287
|
+
)
|
|
288
|
+
if (sendResult && sendResult.err) {
|
|
289
|
+
console.log(`Error broadcasting put: ${sendResult.err}`)
|
|
290
|
+
}
|
|
291
|
+
|
|
280
292
|
if (Object.keys(update.defer).length) {
|
|
281
293
|
setTimeout(() => put({put: update.defer}, send), update.wait)
|
|
282
294
|
}
|
|
@@ -353,30 +365,30 @@ const Wire = opt => {
|
|
|
353
365
|
// used whereas wire spec needs to handle clock skew for updates
|
|
354
366
|
// across the network.
|
|
355
367
|
const update = await Ham.mix(data, graph, opt.secure, listen)
|
|
356
|
-
const none = Object.keys(update.now).length === 0
|
|
357
|
-
if (none) {
|
|
358
|
-
// Nothing to do.
|
|
359
|
-
cb(null)
|
|
360
|
-
return
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
if (!(await check(update.now, send, cb))) return
|
|
364
368
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
369
|
+
if (Object.keys(update.now).length !== 0) {
|
|
370
|
+
if (!(await check(update.now, send, cb))) return
|
|
371
|
+
|
|
372
|
+
// Seed pendingReferences with any new references from API calls
|
|
373
|
+
for (const [soul, node] of Object.entries(update.now)) {
|
|
374
|
+
if (node && typeof node === "object") {
|
|
375
|
+
for (const [key, value] of Object.entries(node)) {
|
|
376
|
+
const soulId = utils.rel.is(value)
|
|
377
|
+
if (soulId) {
|
|
378
|
+
// Add referenced soul to pending list
|
|
379
|
+
pendingReferences.add(soulId)
|
|
380
|
+
}
|
|
373
381
|
}
|
|
374
382
|
}
|
|
375
383
|
}
|
|
384
|
+
|
|
385
|
+
store.put(update.now, cb)
|
|
386
|
+
} else {
|
|
387
|
+
// No local update needed, but still callback
|
|
388
|
+
if (cb) cb(null)
|
|
376
389
|
}
|
|
377
390
|
|
|
378
|
-
|
|
379
|
-
// Also put data on the wire spec.
|
|
391
|
+
// Always put data on the wire spec even if no local update needed
|
|
380
392
|
const sendResult = send(
|
|
381
393
|
JSON.stringify({
|
|
382
394
|
"#": dup.track(utils.text.random(9)),
|
|
@@ -608,44 +620,51 @@ const Wire = opt => {
|
|
|
608
620
|
}
|
|
609
621
|
|
|
610
622
|
// Process next message in queue
|
|
611
|
-
const data = messageQueue
|
|
612
|
-
sendToPeers(data)
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
623
|
+
const data = messageQueue[0]
|
|
624
|
+
const sent = sendToPeers(data)
|
|
625
|
+
|
|
626
|
+
if (sent) {
|
|
627
|
+
// Only remove from queue if successfully sent
|
|
628
|
+
messageQueue.shift()
|
|
629
|
+
|
|
630
|
+
// Start timeout for this message now that it's been sent
|
|
631
|
+
const msg = JSON.parse(data)
|
|
632
|
+
const trackId = msg["#"]
|
|
633
|
+
if (trackId && pendingTimeouts.has(trackId)) {
|
|
634
|
+
const timeoutConfig = pendingTimeouts.get(trackId)
|
|
635
|
+
pendingTimeouts.delete(trackId)
|
|
636
|
+
|
|
637
|
+
// Respond to callback with null if no response.
|
|
638
|
+
timeoutConfig.timeoutId = setTimeout(() => {
|
|
639
|
+
const cb = queue[trackId]
|
|
640
|
+
if (cb) {
|
|
641
|
+
const id = timeoutConfig.lex["#"]
|
|
642
|
+
const ack = {[id]: null}
|
|
643
|
+
if (typeof timeoutConfig.lex["."] === "string") {
|
|
644
|
+
ack[id] = {[timeoutConfig.lex["."]]: null}
|
|
645
|
+
}
|
|
646
|
+
cb({put: ack})
|
|
647
|
+
delete queue[trackId]
|
|
629
648
|
}
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
}
|
|
633
|
-
}, timeoutConfig.wait)
|
|
649
|
+
}, timeoutConfig.wait)
|
|
650
|
+
}
|
|
634
651
|
}
|
|
635
652
|
|
|
636
653
|
// Schedule processing of next message if queue not empty
|
|
637
654
|
if (messageQueue.length > 0) {
|
|
638
|
-
// Add delay between messages to respect rate
|
|
639
|
-
queueProcessor = setTimeout(processQueue,
|
|
655
|
+
// Add delay between messages to respect rate limit
|
|
656
|
+
queueProcessor = setTimeout(processQueue, 100)
|
|
640
657
|
} else {
|
|
641
658
|
queueProcessor = null
|
|
642
659
|
}
|
|
643
660
|
}
|
|
644
661
|
|
|
645
662
|
const sendToPeers = data => {
|
|
663
|
+
let sentToAtLeastOne = false
|
|
646
664
|
peers.forEach(peer => {
|
|
647
665
|
if (peer && peer.readyState === WebSocket.OPEN) {
|
|
648
666
|
peer.send(data)
|
|
667
|
+
sentToAtLeastOne = true
|
|
649
668
|
} else {
|
|
650
669
|
const retryHandler = peer._retryHandler || createRetryHandler()
|
|
651
670
|
peer._retryHandler = retryHandler
|
|
@@ -663,6 +682,7 @@ const Wire = opt => {
|
|
|
663
682
|
}
|
|
664
683
|
}
|
|
665
684
|
})
|
|
685
|
+
return sentToAtLeastOne
|
|
666
686
|
}
|
|
667
687
|
|
|
668
688
|
const send = data => {
|
|
@@ -677,7 +697,7 @@ const Wire = opt => {
|
|
|
677
697
|
messageQueue.push(data)
|
|
678
698
|
// Start queue processor if not already running
|
|
679
699
|
if (!queueProcessor) {
|
|
680
|
-
queueProcessor = setTimeout(processQueue,
|
|
700
|
+
queueProcessor = setTimeout(processQueue, 100)
|
|
681
701
|
}
|
|
682
702
|
}
|
|
683
703
|
if (!(opt.peers instanceof Array)) {
|