@xyo-network/bridge-pub-sub 5.3.20 → 5.3.24
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 +52 -29
- package/src/AbstractModuleHost/AbstractModuleHost.ts +0 -12
- package/src/AbstractModuleHost/index.ts +0 -1
- package/src/AsyncQueryBus/AsyncQueryBusBase.ts +0 -163
- package/src/AsyncQueryBus/AsyncQueryBusClient.ts +0 -190
- package/src/AsyncQueryBus/AsyncQueryBusHost.ts +0 -305
- package/src/AsyncQueryBus/ModuleHost/ModuleHost.ts +0 -30
- package/src/AsyncQueryBus/ModuleHost/index.ts +0 -1
- package/src/AsyncQueryBus/ModuleProxy/ModuleProxy.ts +0 -104
- package/src/AsyncQueryBus/ModuleProxy/index.ts +0 -1
- package/src/AsyncQueryBus/index.ts +0 -5
- package/src/AsyncQueryBus/model/BaseConfig.ts +0 -17
- package/src/AsyncQueryBus/model/ClientConfig.ts +0 -11
- package/src/AsyncQueryBus/model/HostConfig.ts +0 -29
- package/src/AsyncQueryBus/model/IntersectConfig.ts +0 -13
- package/src/AsyncQueryBus/model/Params.ts +0 -18
- package/src/AsyncQueryBus/model/QueryStatus.ts +0 -2
- package/src/AsyncQueryBus/model/index.ts +0 -6
- package/src/Config.ts +0 -22
- package/src/Params.ts +0 -9
- package/src/PubSubBridge.ts +0 -287
- package/src/PubSubBridgeModuleResolver.ts +0 -78
- package/src/Schema.ts +0 -4
- package/src/index.ts +0 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xyo-network/bridge-pub-sub",
|
|
3
|
-
"version": "5.3.
|
|
3
|
+
"version": "5.3.24",
|
|
4
4
|
"description": "Primary SDK for using XYO Protocol 2.0",
|
|
5
5
|
"homepage": "https://xyo.network",
|
|
6
6
|
"bugs": {
|
|
@@ -30,48 +30,71 @@
|
|
|
30
30
|
"types": "dist/neutral/index.d.ts",
|
|
31
31
|
"files": [
|
|
32
32
|
"dist",
|
|
33
|
-
"src",
|
|
34
33
|
"!**/*.bench.*",
|
|
35
34
|
"!**/*.spec.*",
|
|
36
|
-
"!**/*.test.*"
|
|
35
|
+
"!**/*.test.*",
|
|
36
|
+
"README.md"
|
|
37
37
|
],
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@xyo-network/account": "~5.3.20",
|
|
40
|
-
"@xyo-network/archivist-model": "~5.3.20",
|
|
41
|
-
"@xyo-network/boundwitness-model": "~5.3.20",
|
|
42
|
-
"@xyo-network/bridge-abstract": "~5.3.20",
|
|
43
|
-
"@xyo-network/bridge-model": "~5.3.20",
|
|
44
|
-
"@xyo-network/config-payload-plugin": "~5.3.20",
|
|
45
|
-
"@xyo-network/diviner-boundwitness-model": "~5.3.20",
|
|
46
|
-
"@xyo-network/diviner-model": "~5.3.20",
|
|
47
|
-
"@xyo-network/module-abstract": "~5.3.20",
|
|
48
|
-
"@xyo-network/module-model": "~5.3.20",
|
|
49
|
-
"@xyo-network/node-model": "~5.3.20",
|
|
50
|
-
"@xyo-network/payload-builder": "~5.3.20",
|
|
51
|
-
"@xyo-network/payload-model": "~5.3.20",
|
|
52
39
|
"async-mutex": "~0.5.0",
|
|
53
|
-
"lru-cache": "
|
|
40
|
+
"lru-cache": "~11.2.7",
|
|
41
|
+
"@xyo-network/account": "~5.3.24",
|
|
42
|
+
"@xyo-network/archivist-model": "~5.3.24",
|
|
43
|
+
"@xyo-network/boundwitness-model": "~5.3.24",
|
|
44
|
+
"@xyo-network/bridge-model": "~5.3.24",
|
|
45
|
+
"@xyo-network/bridge-abstract": "~5.3.24",
|
|
46
|
+
"@xyo-network/config-payload-plugin": "~5.3.24",
|
|
47
|
+
"@xyo-network/module-model": "~5.3.24",
|
|
48
|
+
"@xyo-network/diviner-boundwitness-model": "~5.3.24",
|
|
49
|
+
"@xyo-network/node-model": "~5.3.24",
|
|
50
|
+
"@xyo-network/payload-model": "~5.3.24",
|
|
51
|
+
"@xyo-network/module-abstract": "~5.3.24",
|
|
52
|
+
"@xyo-network/payload-builder": "~5.3.24",
|
|
53
|
+
"@xyo-network/diviner-model": "~5.3.24"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@
|
|
57
|
-
"@
|
|
58
|
-
"@xylabs/
|
|
59
|
-
"@xylabs/
|
|
60
|
-
"@xylabs/
|
|
61
|
-
"@
|
|
62
|
-
"@
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
56
|
+
"@opentelemetry/api": "^1.9.1",
|
|
57
|
+
"@types/node": "^25.5.0",
|
|
58
|
+
"@xylabs/sdk-js": "^5.0.93",
|
|
59
|
+
"@xylabs/ts-scripts-common": "~7.6.16",
|
|
60
|
+
"@xylabs/ts-scripts-pnpm": "~7.6.16",
|
|
61
|
+
"@xylabs/tsconfig": "~7.6.16",
|
|
62
|
+
"@xylabs/vitest-extended": "~5.0.93",
|
|
63
|
+
"acorn": "^8.16.0",
|
|
64
|
+
"async-mutex": "~0.5.0",
|
|
65
|
+
"axios": "^1.14.0",
|
|
66
|
+
"esbuild": "^0.28.0",
|
|
67
|
+
"ethers": "^6.16.0",
|
|
68
|
+
"lru-cache": "~11.2.7",
|
|
69
|
+
"tslib": "^2.8.1",
|
|
66
70
|
"typescript": "~5.9.3",
|
|
71
|
+
"vite": "^8.0.3",
|
|
67
72
|
"vitest": "~4.1.2",
|
|
68
|
-
"zod": "^4.3.6"
|
|
73
|
+
"zod": "^4.3.6",
|
|
74
|
+
"@xyo-network/account": "~5.3.24",
|
|
75
|
+
"@xyo-network/archivist-memory": "~5.3.24",
|
|
76
|
+
"@xyo-network/archivist-model": "~5.3.24",
|
|
77
|
+
"@xyo-network/boundwitness-model": "~5.3.24",
|
|
78
|
+
"@xyo-network/bridge-model": "~5.3.24",
|
|
79
|
+
"@xyo-network/bridge-abstract": "~5.3.24",
|
|
80
|
+
"@xyo-network/config-payload-plugin": "~5.3.24",
|
|
81
|
+
"@xyo-network/diviner-boundwitness-memory": "~5.3.24",
|
|
82
|
+
"@xyo-network/diviner-model": "~5.3.24",
|
|
83
|
+
"@xyo-network/diviner-boundwitness-model": "~5.3.24",
|
|
84
|
+
"@xyo-network/node-model": "~5.3.24",
|
|
85
|
+
"@xyo-network/node-memory": "~5.3.24",
|
|
86
|
+
"@xyo-network/module-model": "~5.3.24",
|
|
87
|
+
"@xyo-network/module-abstract": "~5.3.24",
|
|
88
|
+
"@xyo-network/payload-builder": "~5.3.24",
|
|
89
|
+
"@xyo-network/payload-model": "~5.3.24",
|
|
90
|
+
"@xyo-network/payload-wrapper": "~5.3.24"
|
|
69
91
|
},
|
|
70
92
|
"peerDependencies": {
|
|
71
93
|
"@xylabs/sdk-js": "^5",
|
|
94
|
+
"ethers": "^6",
|
|
72
95
|
"tslib": "^2.8.1"
|
|
73
96
|
},
|
|
74
97
|
"publishConfig": {
|
|
75
98
|
"access": "public"
|
|
76
99
|
}
|
|
77
|
-
}
|
|
100
|
+
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { BaseParams, Promisable } from '@xylabs/sdk-js'
|
|
2
|
-
import { Base } from '@xylabs/sdk-js'
|
|
3
|
-
import type { ModuleInstance } from '@xyo-network/module-model'
|
|
4
|
-
|
|
5
|
-
export type ModuleHostParams<THostedInstance extends ModuleInstance = ModuleInstance> = BaseParams<{
|
|
6
|
-
mod: THostedInstance
|
|
7
|
-
}>
|
|
8
|
-
|
|
9
|
-
export abstract class AbstractModuleHost<TParams extends ModuleHostParams = ModuleHostParams> extends Base<TParams> {
|
|
10
|
-
abstract start(): Promisable<void>
|
|
11
|
-
abstract stop(): Promisable<void>
|
|
12
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './AbstractModuleHost.ts'
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
import type { Address, TypeCheck } from '@xylabs/sdk-js'
|
|
2
|
-
import { assertEx, Base } from '@xylabs/sdk-js'
|
|
3
|
-
import type { ArchivistInstance } from '@xyo-network/archivist-model'
|
|
4
|
-
import { isArchivistInstance } from '@xyo-network/archivist-model'
|
|
5
|
-
import type { BoundWitness, QueryBoundWitness } from '@xyo-network/boundwitness-model'
|
|
6
|
-
import type { BoundWitnessDivinerParams, BoundWitnessDivinerQueryPayload } from '@xyo-network/diviner-boundwitness-model'
|
|
7
|
-
import type { DivinerInstance } from '@xyo-network/diviner-model'
|
|
8
|
-
import { isDivinerInstance } from '@xyo-network/diviner-model'
|
|
9
|
-
import type {
|
|
10
|
-
ModuleConfig, ModuleIdentifier, ModuleInstance,
|
|
11
|
-
} from '@xyo-network/module-model'
|
|
12
|
-
import { ResolveHelper } from '@xyo-network/module-model'
|
|
13
|
-
import type { Sequence } from '@xyo-network/payload-model'
|
|
14
|
-
import { SequenceConstants } from '@xyo-network/payload-model'
|
|
15
|
-
import { Mutex } from 'async-mutex'
|
|
16
|
-
import { LRUCache } from 'lru-cache'
|
|
17
|
-
|
|
18
|
-
import type { AsyncQueryBusParams } from './model/index.ts'
|
|
19
|
-
|
|
20
|
-
const POLLING_FREQUENCY_MIN = 100 as const
|
|
21
|
-
const POLLING_FREQUENCY_MAX = 60_000 as const
|
|
22
|
-
const POLLING_FREQUENCY_DEFAULT = 1000 as const
|
|
23
|
-
|
|
24
|
-
export class AsyncQueryBusBase<TParams extends AsyncQueryBusParams = AsyncQueryBusParams> extends Base<TParams> {
|
|
25
|
-
protected _lastState?: LRUCache<Address, Sequence>
|
|
26
|
-
protected _targetConfigs: Record<Address, ModuleConfig> = {}
|
|
27
|
-
protected _targetQueries: Record<Address, string[]> = {}
|
|
28
|
-
|
|
29
|
-
private _lastResolveFailure: Record<ModuleIdentifier, number> = {}
|
|
30
|
-
private _queriesArchivist?: ArchivistInstance
|
|
31
|
-
private _queriesDiviner?: DivinerInstance<BoundWitnessDivinerParams, BoundWitnessDivinerQueryPayload, QueryBoundWitness>
|
|
32
|
-
private _reResolveDelay = 1000 * 5 // 5 seconds
|
|
33
|
-
private _resolveMutex = new Mutex()
|
|
34
|
-
private _responsesArchivist?: ArchivistInstance
|
|
35
|
-
private _responsesDiviner?: DivinerInstance<BoundWitnessDivinerParams, BoundWitnessDivinerQueryPayload, BoundWitness>
|
|
36
|
-
|
|
37
|
-
constructor(params: TParams) {
|
|
38
|
-
super(params)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
get config(): TParams['config'] {
|
|
42
|
-
return this.params.config
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
get pollFrequency(): number {
|
|
46
|
-
const frequency = this.config?.pollFrequency ?? POLLING_FREQUENCY_DEFAULT
|
|
47
|
-
if (frequency < POLLING_FREQUENCY_MIN || frequency > POLLING_FREQUENCY_MAX) {
|
|
48
|
-
return POLLING_FREQUENCY_DEFAULT
|
|
49
|
-
}
|
|
50
|
-
return frequency
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
get rootModule() {
|
|
54
|
-
return this.params.rootModule
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* A cache of the last offset of the Diviner process per address
|
|
59
|
-
*/
|
|
60
|
-
protected get lastState(): LRUCache<Address, Sequence> {
|
|
61
|
-
const requiredConfig = { max: 1000, ttl: 0 }
|
|
62
|
-
this._lastState = this._lastState ?? new LRUCache<Address, Sequence>(requiredConfig)
|
|
63
|
-
return this._lastState
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
async queriesArchivist() {
|
|
67
|
-
return await this._resolveMutex.runExclusive(async () => {
|
|
68
|
-
this._queriesArchivist
|
|
69
|
-
= this._queriesArchivist
|
|
70
|
-
?? (await this.resolve(
|
|
71
|
-
assertEx(this.config?.intersect?.queries?.archivist, () => 'No queries Archivist defined'),
|
|
72
|
-
isArchivistInstance,
|
|
73
|
-
))
|
|
74
|
-
return this._queriesArchivist
|
|
75
|
-
})
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
async queriesDiviner() {
|
|
79
|
-
return await this._resolveMutex.runExclusive(async () => {
|
|
80
|
-
this._queriesDiviner
|
|
81
|
-
= this._queriesDiviner
|
|
82
|
-
?? ((await this.resolve(
|
|
83
|
-
assertEx(this.config?.intersect?.queries?.boundWitnessDiviner, () => 'No queries Diviner defined'),
|
|
84
|
-
isDivinerInstance,
|
|
85
|
-
)) as DivinerInstance<BoundWitnessDivinerParams, BoundWitnessDivinerQueryPayload, QueryBoundWitness>)
|
|
86
|
-
return this._queriesDiviner
|
|
87
|
-
})
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
async responsesArchivist() {
|
|
91
|
-
return await this._resolveMutex.runExclusive(async () => {
|
|
92
|
-
this._responsesArchivist
|
|
93
|
-
= this._responsesArchivist
|
|
94
|
-
?? (await this.resolve(
|
|
95
|
-
assertEx(this.config?.intersect?.responses?.archivist, () => 'No responses Archivist defined'),
|
|
96
|
-
isArchivistInstance,
|
|
97
|
-
))
|
|
98
|
-
return this._responsesArchivist
|
|
99
|
-
})
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
async responsesDiviner() {
|
|
103
|
-
return await this._resolveMutex.runExclusive(async () => {
|
|
104
|
-
this._responsesDiviner
|
|
105
|
-
= this._responsesDiviner
|
|
106
|
-
?? ((await this.resolve(
|
|
107
|
-
assertEx(this.config?.intersect?.responses?.boundWitnessDiviner, () => 'No responses Diviner defined'),
|
|
108
|
-
isDivinerInstance,
|
|
109
|
-
)) as DivinerInstance<BoundWitnessDivinerParams, BoundWitnessDivinerQueryPayload, BoundWitness>)
|
|
110
|
-
return this._responsesDiviner
|
|
111
|
-
})
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Commit the internal state of the process. This is similar
|
|
116
|
-
* to a transaction completion in a database and should only be called
|
|
117
|
-
* when results have been successfully persisted to the appropriate
|
|
118
|
-
* external stores.
|
|
119
|
-
* @param address The module address to commit the state for
|
|
120
|
-
* @param nextState The state to commit
|
|
121
|
-
*/
|
|
122
|
-
protected async commitState(address: Address, nextState: Sequence) {
|
|
123
|
-
await Promise.resolve()
|
|
124
|
-
// TODO: Offload to Archivist/Diviner instead of in-memory
|
|
125
|
-
const lastState = this.lastState.get(address)
|
|
126
|
-
if (lastState && lastState >= nextState) return
|
|
127
|
-
this.lastState.set(address, nextState)
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Retrieves the last state of the process. Used to recover state after
|
|
132
|
-
* preemptions, reboots, etc.
|
|
133
|
-
*/
|
|
134
|
-
protected async retrieveState(address: Address): Promise<Sequence> {
|
|
135
|
-
await Promise.resolve()
|
|
136
|
-
const state = this.lastState.get(address)
|
|
137
|
-
if (state === undefined) {
|
|
138
|
-
const newState = SequenceConstants.minLocalSequence
|
|
139
|
-
this.lastState.set(address, newState)
|
|
140
|
-
return newState
|
|
141
|
-
} else {
|
|
142
|
-
return state
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
private async resolve<T extends ModuleInstance>(id: ModuleIdentifier, typeCheck: TypeCheck<T>): Promise<T | undefined> {
|
|
147
|
-
if (Date.now() - (this._lastResolveFailure[id] ?? 0) < this._reResolveDelay) {
|
|
148
|
-
return
|
|
149
|
-
}
|
|
150
|
-
this._lastResolveFailure[id] = Date.now()
|
|
151
|
-
const resolved = await ResolveHelper.resolveModuleIdentifier(this.rootModule, id)
|
|
152
|
-
if (resolved) {
|
|
153
|
-
if (typeCheck(resolved)) {
|
|
154
|
-
delete this._lastResolveFailure[id]
|
|
155
|
-
return resolved
|
|
156
|
-
} else {
|
|
157
|
-
this.logger?.warn(`Unable to resolve responsesDiviner as correct type [${id}][${resolved?.constructor?.name}]: ${resolved.id}`)
|
|
158
|
-
}
|
|
159
|
-
} else {
|
|
160
|
-
this.logger?.debug(`Unable to resolve queriesArchivist [${id}] [${await ResolveHelper.traceModuleIdentifier(this.rootModule, id)}]`)
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
import type { Address, Hash } from '@xylabs/sdk-js'
|
|
2
|
-
import {
|
|
3
|
-
assertEx, clearTimeoutEx, delay, forget, setTimeoutEx,
|
|
4
|
-
} from '@xylabs/sdk-js'
|
|
5
|
-
import type { QueryBoundWitness } from '@xyo-network/boundwitness-model'
|
|
6
|
-
import { isBoundWitness } from '@xyo-network/boundwitness-model'
|
|
7
|
-
import type { BoundWitnessDivinerQueryPayload } from '@xyo-network/diviner-boundwitness-model'
|
|
8
|
-
import { BoundWitnessDivinerQuerySchema } from '@xyo-network/diviner-boundwitness-model'
|
|
9
|
-
import type { CacheConfig, ModuleQueryResult } from '@xyo-network/module-model'
|
|
10
|
-
import { PayloadBuilder } from '@xyo-network/payload-builder'
|
|
11
|
-
import {
|
|
12
|
-
asSchema,
|
|
13
|
-
type ModuleError, type Payload, type WithSources,
|
|
14
|
-
} from '@xyo-network/payload-model'
|
|
15
|
-
import { LRUCache } from 'lru-cache'
|
|
16
|
-
|
|
17
|
-
import { AsyncQueryBusBase } from './AsyncQueryBusBase.ts'
|
|
18
|
-
import type { AsyncQueryBusClientParams } from './model/index.ts'
|
|
19
|
-
import { Pending } from './model/index.ts'
|
|
20
|
-
|
|
21
|
-
export class AsyncQueryBusClient<TParams extends AsyncQueryBusClientParams = AsyncQueryBusClientParams> extends AsyncQueryBusBase<TParams> {
|
|
22
|
-
protected _queryCache?: LRUCache<Hash, Pending | ModuleQueryResult>
|
|
23
|
-
private _pollCount = 0
|
|
24
|
-
private _pollId?: string
|
|
25
|
-
|
|
26
|
-
constructor(params: TParams) {
|
|
27
|
-
super(params)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
get queryCacheConfig(): LRUCache.Options<Hash, Pending | ModuleQueryResult, unknown> {
|
|
31
|
-
const queryCacheConfig: CacheConfig | undefined = this.config?.queryCache === true ? {} : this.config?.queryCache
|
|
32
|
-
return {
|
|
33
|
-
max: 100, ttl: 1000 * 60, ...queryCacheConfig,
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
get started() {
|
|
38
|
-
return !!this._pollId
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* A cache of queries that have been issued
|
|
43
|
-
*/
|
|
44
|
-
protected get queryCache(): LRUCache<Hash, Pending | ModuleQueryResult> {
|
|
45
|
-
const config = this.queryCacheConfig
|
|
46
|
-
const requiredConfig = { noUpdateTTL: false, ttlAutopurge: true }
|
|
47
|
-
this._queryCache = this._queryCache ?? new LRUCache<Hash, Pending | ModuleQueryResult>({ ...config, ...requiredConfig })
|
|
48
|
-
return this._queryCache
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
listeningAddresses() {
|
|
52
|
-
return this._queryCache?.keys()
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
async send(address: Address, query: QueryBoundWitness, payloads?: Payload[] | undefined): Promise<ModuleQueryResult> {
|
|
56
|
-
this.logger?.debug(`Begin issuing query to: ${address}`)
|
|
57
|
-
const routedQuery = { ...query, $destination: [address] }
|
|
58
|
-
// console.log('queryArchivist - calling')
|
|
59
|
-
const queryArchivist = assertEx(
|
|
60
|
-
await this.queriesArchivist(),
|
|
61
|
-
() => `Unable to contact queriesArchivist [${this.config?.intersect?.queries?.archivist}]`,
|
|
62
|
-
)
|
|
63
|
-
// console.log('queryArchivist')
|
|
64
|
-
|
|
65
|
-
// TODO: Should we always re-hash to true up timestamps? We can't
|
|
66
|
-
// re-sign correctly so we would lose that information if we did and
|
|
67
|
-
// would also be replying to consumers with a different query hash than
|
|
68
|
-
// they sent us (which might be OK since it reflect the chain of custody)
|
|
69
|
-
// Revisit this once we have proxy module support as they are another
|
|
70
|
-
// intermediary to consider.
|
|
71
|
-
const routedQueryHash = await PayloadBuilder.dataHash(routedQuery)
|
|
72
|
-
this.logger?.debug(`Issuing query: ${routedQueryHash} to: ${address}`)
|
|
73
|
-
// If there was data associated with the query, add it to the insert
|
|
74
|
-
const data = payloads ? [routedQuery, ...payloads] : [routedQuery]
|
|
75
|
-
const insertResult = await queryArchivist.insert?.(data)
|
|
76
|
-
this.logger?.debug(`Issued query: ${routedQueryHash} to: ${address}`)
|
|
77
|
-
this.queryCache.set(routedQueryHash, Pending)
|
|
78
|
-
if (!insertResult) throw new Error('Unable to issue query to queryArchivist')
|
|
79
|
-
return new Promise<ModuleQueryResult>((resolve, reject) => {
|
|
80
|
-
this.logger?.debug(`Polling for response to query: ${routedQueryHash}`)
|
|
81
|
-
let nextDelay = 100
|
|
82
|
-
const pollForResponse = async () => {
|
|
83
|
-
try {
|
|
84
|
-
this.start()
|
|
85
|
-
let response = this.queryCache.get(routedQueryHash)
|
|
86
|
-
// Poll for response until cache key expires (response timed out)
|
|
87
|
-
while (response !== undefined) {
|
|
88
|
-
// console.log('polling...')
|
|
89
|
-
// Wait a bit
|
|
90
|
-
await delay(nextDelay)
|
|
91
|
-
// Check the status of the response
|
|
92
|
-
response = this.queryCache.get(routedQueryHash)
|
|
93
|
-
// If status is no longer pending that means we received a response
|
|
94
|
-
if (response && response !== Pending) {
|
|
95
|
-
this.logger?.log(`Returning response to query: ${routedQueryHash}`)
|
|
96
|
-
resolve(response)
|
|
97
|
-
return
|
|
98
|
-
}
|
|
99
|
-
// back off the polling frequency
|
|
100
|
-
nextDelay = Math.floor(nextDelay * 1.2)
|
|
101
|
-
// cap it at 1000ms
|
|
102
|
-
if (nextDelay > 1000) nextDelay = 1000
|
|
103
|
-
}
|
|
104
|
-
// If we got here waiting for a response timed out
|
|
105
|
-
this.logger?.error('Timeout waiting for query response')
|
|
106
|
-
// Resolve with error to match what a local module would do if it were to error
|
|
107
|
-
// TODO: BW Builder/Sign result as this module?
|
|
108
|
-
const error: WithSources<ModuleError> = {
|
|
109
|
-
message: 'Timeout waiting for query response',
|
|
110
|
-
query: asSchema('network.xyo.boundwitness', true),
|
|
111
|
-
schema: asSchema('network.xyo.error.module', true),
|
|
112
|
-
$sources: [routedQueryHash],
|
|
113
|
-
}
|
|
114
|
-
reject(error)
|
|
115
|
-
return
|
|
116
|
-
} finally {
|
|
117
|
-
this.stop()
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
forget(pollForResponse())
|
|
121
|
-
})
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Runs the background divine process on a loop with a delay
|
|
126
|
-
* specified by the `config.pollFrequency`
|
|
127
|
-
*/
|
|
128
|
-
private poll() {
|
|
129
|
-
this._pollId = setTimeoutEx(async () => {
|
|
130
|
-
try {
|
|
131
|
-
await this.processIncomingResponses()
|
|
132
|
-
} catch (e) {
|
|
133
|
-
this.logger?.error?.(`Error in main loop: ${e}`)
|
|
134
|
-
} finally {
|
|
135
|
-
if (this._pollId) clearTimeoutEx(this._pollId)
|
|
136
|
-
this._pollId = undefined
|
|
137
|
-
this.poll()
|
|
138
|
-
}
|
|
139
|
-
}, this.pollFrequency)
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Background process for processing incoming responses to previously issued queries
|
|
144
|
-
*/
|
|
145
|
-
private processIncomingResponses = async () => {
|
|
146
|
-
const responseArchivist = await this.responsesArchivist()
|
|
147
|
-
if (responseArchivist) {
|
|
148
|
-
const responseBoundWitnessDiviner = await this.responsesDiviner()
|
|
149
|
-
if (responseBoundWitnessDiviner) {
|
|
150
|
-
const pendingCommands = [...this.queryCache.entries()].filter(([_, status]) => status === Pending)
|
|
151
|
-
// TODO: Do in throttled batches
|
|
152
|
-
await Promise.allSettled(
|
|
153
|
-
pendingCommands.map(async ([sourceQuery, status]) => {
|
|
154
|
-
if (status === Pending) {
|
|
155
|
-
const divinerQuery: BoundWitnessDivinerQueryPayload = {
|
|
156
|
-
limit: 1, order: 'desc', schema: BoundWitnessDivinerQuerySchema, sourceQuery,
|
|
157
|
-
}
|
|
158
|
-
const result = await responseBoundWitnessDiviner.divine([divinerQuery])
|
|
159
|
-
if (result && result.length > 0) {
|
|
160
|
-
const response = result.find(isBoundWitness)
|
|
161
|
-
if (response && (response as unknown as { $sourceQuery: string })?.$sourceQuery === sourceQuery) {
|
|
162
|
-
this.logger?.debug(`Found response to query: ${sourceQuery}`)
|
|
163
|
-
// Get any payloads associated with the response
|
|
164
|
-
const payloads: Payload[] = response.payload_hashes?.length > 0 ? await responseArchivist.get(response.payload_hashes) : []
|
|
165
|
-
this.queryCache.set(sourceQuery, [response, payloads, []])
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}),
|
|
170
|
-
)
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
private start() {
|
|
176
|
-
if (this._pollCount === 0) {
|
|
177
|
-
this.poll()
|
|
178
|
-
}
|
|
179
|
-
this._pollCount++
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
private stop() {
|
|
183
|
-
this._pollCount--
|
|
184
|
-
if (this._pollCount <= 0) {
|
|
185
|
-
if (this._pollId) clearTimeoutEx(this._pollId)
|
|
186
|
-
this._pollId = undefined
|
|
187
|
-
this._pollCount = 0
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|