feat(modules): manual deepen pear, trust, crdt, storage, gossip, network
Trust gate and detached registry helpers, blind handoff cancel, LWW snapshot/compare, fork forceChoose, dedup restore, DHT prune, indexer bus subscribers, inverted hasDoc, similarity listIds. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -104,6 +104,10 @@ class HyperP2PInvertedIndex extends EventEmitter {
|
|||||||
return this._docs.size
|
return this._docs.size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasDoc (docId) {
|
||||||
|
return this._docs.has(String(docId))
|
||||||
|
}
|
||||||
|
|
||||||
topTerms (limit = 10) {
|
topTerms (limit = 10) {
|
||||||
const ranked = [...this._terms.entries()]
|
const ranked = [...this._terms.entries()]
|
||||||
.map(([term, set]) => ({ term, docs: set.size }))
|
.map(([term, set]) => ({ term, docs: set.size }))
|
||||||
|
|||||||
@@ -142,6 +142,14 @@ class HyperP2PSimilarityLsh extends EventEmitter {
|
|||||||
return this._buckets.size
|
return this._buckets.size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
listIds () {
|
||||||
|
return [...this._vectors.keys()]
|
||||||
|
}
|
||||||
|
|
||||||
|
vectorCount () {
|
||||||
|
return this._vectors.size
|
||||||
|
}
|
||||||
|
|
||||||
getStats () {
|
getStats () {
|
||||||
return {
|
return {
|
||||||
...this._stats,
|
...this._stats,
|
||||||
|
|||||||
@@ -151,6 +151,18 @@ class HyperP2PDedupFilter extends EventEmitter {
|
|||||||
return { ids: [...this._seen], at: Date.now(), size: this._seen.size }
|
return { ids: [...this._seen], at: Date.now(), size: this._seen.size }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
restoreSnapshot (snap) {
|
||||||
|
if (!snap || !Array.isArray(snap.ids)) throw new Error('invalid snapshot')
|
||||||
|
this._seen = new Set(snap.ids)
|
||||||
|
this._seenAt = new Map(snap.ids.map((id) => [id, Date.now()]))
|
||||||
|
return this._seen.size
|
||||||
|
}
|
||||||
|
|
||||||
|
unseenFrom (ids) {
|
||||||
|
if (!Array.isArray(ids)) throw new Error('ids must be an array')
|
||||||
|
return ids.filter((id) => !this.seen(id))
|
||||||
|
}
|
||||||
|
|
||||||
getStats () {
|
getStats () {
|
||||||
return {
|
return {
|
||||||
...this._stats,
|
...this._stats,
|
||||||
|
|||||||
@@ -79,6 +79,22 @@ class HyperP2PDhtBootstrapHint extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hintCount () {
|
||||||
|
return this._hints.size
|
||||||
|
}
|
||||||
|
|
||||||
|
pruneStale (maxAgeMs = 3600000) {
|
||||||
|
const cutoff = Date.now() - maxAgeMs
|
||||||
|
let n = 0
|
||||||
|
for (const [key, h] of this._hints) {
|
||||||
|
if (h.lastSeen < cutoff) {
|
||||||
|
this._hints.delete(key)
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
_mergeHint (nodeId, address, from, at) {
|
_mergeHint (nodeId, address, from, at) {
|
||||||
const key = hintKey(nodeId, address)
|
const key = hintKey(nodeId, address)
|
||||||
const entry = this._hints.get(key) || {
|
const entry = this._hints.get(key) || {
|
||||||
|
|||||||
@@ -57,6 +57,19 @@ class HyperP2PUdxMetrics extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resetTotals () {
|
||||||
|
this._sentTotal = 0
|
||||||
|
this._recvTotal = 0
|
||||||
|
this._sentWindow = []
|
||||||
|
this._recvWindow = []
|
||||||
|
}
|
||||||
|
|
||||||
|
setWindowMs (ms) {
|
||||||
|
if (ms < 100) throw new Error('windowMs must be >= 100')
|
||||||
|
this.windowMs = ms | 0
|
||||||
|
return this.windowMs
|
||||||
|
}
|
||||||
|
|
||||||
_trimWindow (samples, now) {
|
_trimWindow (samples, now) {
|
||||||
const cutoff = now - this.windowMs
|
const cutoff = now - this.windowMs
|
||||||
while (samples.length && samples[0].at < cutoff) samples.shift()
|
while (samples.length && samples[0].at < cutoff) samples.shift()
|
||||||
|
|||||||
@@ -71,6 +71,14 @@ class HyperBareAddonResolve extends EventEmitter {
|
|||||||
|
|
||||||
listNames () { return [...this._addons.keys()] }
|
listNames () { return [...this._addons.keys()] }
|
||||||
|
|
||||||
|
hasAddon (name) {
|
||||||
|
return this._addons.has(String(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
unregister (name) {
|
||||||
|
return this._addons.delete(String(name))
|
||||||
|
}
|
||||||
|
|
||||||
getStats () {
|
getStats () {
|
||||||
return platformStats(this._stats, PROTOCOL, {
|
return platformStats(this._stats, PROTOCOL, {
|
||||||
addons: this._addons.size,
|
addons: this._addons.size,
|
||||||
|
|||||||
@@ -75,6 +75,16 @@ class HyperPearDetachedRegistry extends EventEmitter {
|
|||||||
return [...this._instances.values()].filter((i) => i.alive)
|
return [...this._instances.values()].filter((i) => i.alive)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unregister (instanceId) {
|
||||||
|
return this._instances.delete(assertId(instanceId))
|
||||||
|
}
|
||||||
|
|
||||||
|
pruneExpired () {
|
||||||
|
const stale = this.expired()
|
||||||
|
for (const inst of stale) this.markDead(inst.instanceId)
|
||||||
|
return stale.length
|
||||||
|
}
|
||||||
|
|
||||||
getStats () {
|
getStats () {
|
||||||
return platformStats(this._stats, PROTOCOL, {
|
return platformStats(this._stats, PROTOCOL, {
|
||||||
instances: this._instances.size,
|
instances: this._instances.size,
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "hyper-pear-detached-registry",
|
"name": "hyper-pear-detached-registry",
|
||||||
"version": "0.0.0-scaffold",
|
"version": "0.3.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "hyper-pear-detached-registry",
|
"name": "hyper-pear-detached-registry",
|
||||||
"version": "0.0.0-scaffold",
|
"version": "0.3.1",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"b4a": "^1.6.7",
|
"b4a": "^1.6.7",
|
||||||
|
|||||||
@@ -74,6 +74,14 @@ class HyperPearTrustGate extends EventEmitter {
|
|||||||
|
|
||||||
listTrusted () { return [...this._trusted] }
|
listTrusted () { return [...this._trusted] }
|
||||||
|
|
||||||
|
isTrusted (key) {
|
||||||
|
return this._trusted.has(String(key))
|
||||||
|
}
|
||||||
|
|
||||||
|
trustedCount () {
|
||||||
|
return this._trusted.size
|
||||||
|
}
|
||||||
|
|
||||||
getStats () {
|
getStats () {
|
||||||
return platformStats(this._stats, PROTOCOL, { trusted: this._trusted.size })
|
return platformStats(this._stats, PROTOCOL, { trusted: this._trusted.size })
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "hyper-pear-trust-gate",
|
"name": "hyper-pear-trust-gate",
|
||||||
"version": "0.0.0-scaffold",
|
"version": "0.3.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "hyper-pear-trust-gate",
|
"name": "hyper-pear-trust-gate",
|
||||||
"version": "0.0.0-scaffold",
|
"version": "0.3.1",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"b4a": "^1.6.7",
|
"b4a": "^1.6.7",
|
||||||
|
|||||||
@@ -74,6 +74,23 @@ class HyperPearWorkerPipe extends EventEmitter {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
peek (pipeId) {
|
||||||
|
const p = this._pipes.get(assertId(pipeId))
|
||||||
|
return p ? [...p.buffer] : []
|
||||||
|
}
|
||||||
|
|
||||||
|
pipeCount () {
|
||||||
|
return this._pipes.size
|
||||||
|
}
|
||||||
|
|
||||||
|
flushAll () {
|
||||||
|
let n = 0
|
||||||
|
for (const id of this._pipes.keys()) {
|
||||||
|
n += this.drain(id).length
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
getStats () {
|
getStats () {
|
||||||
return platformStats(this._stats, PROTOCOL, { pipes: this._pipes.size })
|
return platformStats(this._stats, PROTOCOL, { pipes: this._pipes.size })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,6 +78,20 @@ class HyperP2PCrdtLwwRegister extends EventEmitter {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
snapshot () {
|
||||||
|
const out = {}
|
||||||
|
for (const [k, e] of this._values) {
|
||||||
|
out[k] = { value: e.value, ts: e.ts, deleted: !!e.deleted }
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
compare (key, ts) {
|
||||||
|
const e = this._values.get(key)
|
||||||
|
if (!e) return ts
|
||||||
|
return ts - e.ts
|
||||||
|
}
|
||||||
|
|
||||||
_onGossip (d) {
|
_onGossip (d) {
|
||||||
if (!d || d.type !== 'crdt-lww-register-sync' || !d.key) return
|
if (!d || d.type !== 'crdt-lww-register-sync' || !d.key) return
|
||||||
this._stats.gossipIn++
|
this._stats.gossipIn++
|
||||||
|
|||||||
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "hyper-p2p-crdt-lww-register",
|
"name": "hyper-p2p-crdt-lww-register",
|
||||||
"version": "0.3.1",
|
"version": "0.3.2",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "hyper-p2p-crdt-lww-register",
|
"name": "hyper-p2p-crdt-lww-register",
|
||||||
"version": "0.3.1",
|
"version": "0.3.2",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"b4a": "^1.6.7",
|
"b4a": "^1.6.7",
|
||||||
|
|||||||
@@ -71,6 +71,16 @@ class HyperP2PCrdtVersionVector extends EventEmitter {
|
|||||||
return this.snapshot()
|
return this.snapshot()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get (peer) {
|
||||||
|
return this._clock.get(assertPeer(peer)) || 0
|
||||||
|
}
|
||||||
|
|
||||||
|
maxClock () {
|
||||||
|
let m = 0
|
||||||
|
for (const v of this._clock.values()) if (v > m) m = v
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
_onGossip (d) {
|
_onGossip (d) {
|
||||||
if (!d || d.type !== 'crdt-version-vector-sync' || !d.peer) return
|
if (!d || d.type !== 'crdt-version-vector-sync' || !d.peer) return
|
||||||
this._stats.gossipIn++
|
this._stats.gossipIn++
|
||||||
|
|||||||
@@ -93,6 +93,18 @@ class HyperP2PAutobaseForkChoice extends EventEmitter {
|
|||||||
return v ? v.weight : null
|
return v ? v.weight : null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viewCount () {
|
||||||
|
return this._views.size
|
||||||
|
}
|
||||||
|
|
||||||
|
forceChoose (forkId) {
|
||||||
|
assertForkId(forkId)
|
||||||
|
if (!this._views.has(forkId)) throw new Error(`unknown fork: ${forkId}`)
|
||||||
|
this._chosen = forkId
|
||||||
|
this._stats.picks++
|
||||||
|
return this._views.get(forkId)
|
||||||
|
}
|
||||||
|
|
||||||
_onGossip (d) {
|
_onGossip (d) {
|
||||||
if (!d || d.type !== 'view-register' || !d.view) return
|
if (!d || d.type !== 'view-register' || !d.view) return
|
||||||
this._stats.gossipIn++
|
this._stats.gossipIn++
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "hyper-p2p-autobase-fork-choice",
|
"name": "hyper-p2p-autobase-fork-choice",
|
||||||
"version": "0.3.1",
|
"version": "0.3.2",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "hyper-p2p-autobase-fork-choice",
|
"name": "hyper-p2p-autobase-fork-choice",
|
||||||
"version": "0.3.1",
|
"version": "0.3.2",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"b4a": "^1.6.7",
|
"b4a": "^1.6.7",
|
||||||
|
|||||||
@@ -98,6 +98,10 @@ class HyperP2PAutobaseIndexerBus extends EventEmitter {
|
|||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
subscriberCount () {
|
||||||
|
return this._subs.size
|
||||||
|
}
|
||||||
|
|
||||||
_onGossip (d) {
|
_onGossip (d) {
|
||||||
if (!d || d.type !== 'index-event' || !d.evt) return
|
if (!d || d.type !== 'index-event' || !d.evt) return
|
||||||
this._stats.gossipIn++
|
this._stats.gossipIn++
|
||||||
|
|||||||
@@ -65,6 +65,25 @@ class HyperP2PBlindPairHandoff extends EventEmitter {
|
|||||||
return this._handoffs.get(sessionId) || null
|
return this._handoffs.get(sessionId) || null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
listHandoffs (state = null) {
|
||||||
|
const all = [...this._handoffs.values()]
|
||||||
|
if (!state) return all
|
||||||
|
return all.filter((h) => h.state === state)
|
||||||
|
}
|
||||||
|
|
||||||
|
cancelHandoff (sessionId) {
|
||||||
|
assertNonEmpty(sessionId, 'sessionId')
|
||||||
|
const h = this._handoffs.get(sessionId)
|
||||||
|
if (!h || h.state === 'completed') return false
|
||||||
|
this._handoffs.delete(sessionId)
|
||||||
|
this.emit('cancelled', { sessionId })
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
pendingCount () {
|
||||||
|
return this.listHandoffs('offered').length + this.listHandoffs('accepted').length
|
||||||
|
}
|
||||||
|
|
||||||
_gossip (data) {
|
_gossip (data) {
|
||||||
if (!this._peerMsgs) return
|
if (!this._peerMsgs) return
|
||||||
gossipSend(this, data)
|
gossipSend(this, data)
|
||||||
|
|||||||
Reference in New Issue
Block a user