@xyo-network/bridge-pub-sub 5.3.22 → 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 +41 -45
- 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
|
@@ -1,305 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
assertEx, clearTimeoutEx, containsAll, setTimeoutEx,
|
|
3
|
-
} from '@xylabs/sdk-js'
|
|
4
|
-
import {
|
|
5
|
-
type Address, hexFromBigInt, hexToBigInt,
|
|
6
|
-
} from '@xylabs/sdk-js'
|
|
7
|
-
import type { QueryBoundWitness } from '@xyo-network/boundwitness-model'
|
|
8
|
-
import { isQueryBoundWitnessWithStorageMeta } from '@xyo-network/boundwitness-model'
|
|
9
|
-
import { isBridgeInstance } from '@xyo-network/bridge-model'
|
|
10
|
-
import type { BoundWitnessDivinerQueryPayload } from '@xyo-network/diviner-boundwitness-model'
|
|
11
|
-
import { BoundWitnessDivinerQuerySchema } from '@xyo-network/diviner-boundwitness-model'
|
|
12
|
-
import type {
|
|
13
|
-
ModuleIdentifier,
|
|
14
|
-
ModuleInstance,
|
|
15
|
-
} from '@xyo-network/module-model'
|
|
16
|
-
import {
|
|
17
|
-
asModuleInstance,
|
|
18
|
-
ModuleConfigSchema,
|
|
19
|
-
resolveAddressToInstance,
|
|
20
|
-
ResolveHelper,
|
|
21
|
-
} from '@xyo-network/module-model'
|
|
22
|
-
import { PayloadBuilder } from '@xyo-network/payload-builder'
|
|
23
|
-
import type {
|
|
24
|
-
Schema, Sequence, WithStorageMeta,
|
|
25
|
-
} from '@xyo-network/payload-model'
|
|
26
|
-
import { SequenceConstants } from '@xyo-network/payload-model'
|
|
27
|
-
|
|
28
|
-
import { AsyncQueryBusBase } from './AsyncQueryBusBase.ts'
|
|
29
|
-
import type { AsyncQueryBusHostParams } from './model/index.ts'
|
|
30
|
-
|
|
31
|
-
export interface ExposeOptions {
|
|
32
|
-
allowedQueries?: Schema[]
|
|
33
|
-
failOnAlreadyExposed?: boolean
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const IDLE_POLLING_FREQUENCY_RATIO_MIN = 4 as const
|
|
37
|
-
const IDLE_POLLING_FREQUENCY_RATIO_MAX = 64 as const
|
|
38
|
-
const IDLE_POLLING_FREQUENCY_RATIO_DEFAULT = 16 as const
|
|
39
|
-
|
|
40
|
-
const IDLE_THRESHOLD_RATIO_MIN = 4 as const
|
|
41
|
-
const IDLE_THRESHOLD_RATIO_MAX = 64 as const
|
|
42
|
-
const IDLE_THRESHOLD_RATIO_DEFAULT = 16 as const
|
|
43
|
-
|
|
44
|
-
function bigintMax(...args: bigint[]): bigint {
|
|
45
|
-
if (args.length === 0) throw new Error('No values provided to bigintMax')
|
|
46
|
-
// eslint-disable-next-line unicorn/prefer-math-min-max, unicorn/no-array-reduce
|
|
47
|
-
return args.reduce((max, val) => (val > max ? val : max))
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export class AsyncQueryBusHost<TParams extends AsyncQueryBusHostParams = AsyncQueryBusHostParams> extends AsyncQueryBusBase<TParams> {
|
|
51
|
-
protected _exposedAddresses = new Set<Address>()
|
|
52
|
-
private _exposeOptions: Record<Address, ExposeOptions> = {}
|
|
53
|
-
private _idle = false
|
|
54
|
-
private _lastQueryTime?: number
|
|
55
|
-
private _pollId?: string
|
|
56
|
-
|
|
57
|
-
constructor(params: TParams) {
|
|
58
|
-
super(params)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
get exposedAddresses() {
|
|
62
|
-
return this._exposedAddresses
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
get idlePollFrequency() {
|
|
66
|
-
const frequency = this.config?.idlePollFrequency ?? IDLE_POLLING_FREQUENCY_RATIO_DEFAULT * this.pollFrequency
|
|
67
|
-
if (frequency < this.pollFrequency * IDLE_POLLING_FREQUENCY_RATIO_MIN) {
|
|
68
|
-
return IDLE_POLLING_FREQUENCY_RATIO_MIN * this.pollFrequency
|
|
69
|
-
}
|
|
70
|
-
if (frequency > this.pollFrequency * IDLE_POLLING_FREQUENCY_RATIO_MAX) {
|
|
71
|
-
return IDLE_POLLING_FREQUENCY_RATIO_MAX * this.pollFrequency
|
|
72
|
-
}
|
|
73
|
-
return frequency
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
get idleThreshold() {
|
|
77
|
-
const threshold = this.config?.idleThreshold ?? IDLE_THRESHOLD_RATIO_DEFAULT * this.idlePollFrequency
|
|
78
|
-
if (threshold < this.idlePollFrequency * IDLE_THRESHOLD_RATIO_MIN) {
|
|
79
|
-
return IDLE_POLLING_FREQUENCY_RATIO_MIN * this.pollFrequency
|
|
80
|
-
}
|
|
81
|
-
if (threshold > this.idlePollFrequency * IDLE_THRESHOLD_RATIO_MAX) {
|
|
82
|
-
return IDLE_POLLING_FREQUENCY_RATIO_MAX * this.pollFrequency
|
|
83
|
-
}
|
|
84
|
-
return threshold
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
get perAddressBatchQueryLimit(): number {
|
|
88
|
-
return this.config?.perAddressBatchQueryLimit ?? 10
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
get started() {
|
|
92
|
-
return !!this._pollId
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
expose(mod: ModuleInstance, options?: ExposeOptions) {
|
|
96
|
-
const { failOnAlreadyExposed } = options ?? {}
|
|
97
|
-
if (isBridgeInstance(mod)) {
|
|
98
|
-
this.logger?.warn(`Attempted to expose a BridgeModule [${mod.id}] - Not exposing`)
|
|
99
|
-
} else {
|
|
100
|
-
assertEx(!failOnAlreadyExposed || !this._exposedAddresses.has(mod.address), () => `Address already exposed: ${mod.id} [${mod.address}]`)
|
|
101
|
-
this._exposedAddresses.add(mod.address)
|
|
102
|
-
this._exposeOptions[mod.address] = { ...options }
|
|
103
|
-
this.logger?.debug(`${mod.id} exposed [${mod.address}]`)
|
|
104
|
-
return mod
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
async listeningModules(): Promise<ModuleInstance[]> {
|
|
109
|
-
const exposedModules = [...(this.config?.listeningModules ?? []), ...this.exposedAddresses.values()]
|
|
110
|
-
return await Promise.all(
|
|
111
|
-
exposedModules.map(async exposedModule =>
|
|
112
|
-
assertEx(
|
|
113
|
-
asModuleInstance(await resolveAddressToInstance(this.rootModule, exposedModule)),
|
|
114
|
-
() => `Unable to resolve listeningModule [${exposedModule}]`,
|
|
115
|
-
)),
|
|
116
|
-
)
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
start() {
|
|
120
|
-
if (this.started) {
|
|
121
|
-
console.warn('AsyncQueryBus starting when already started')
|
|
122
|
-
}
|
|
123
|
-
this.poll()
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
stop() {
|
|
127
|
-
if (!this.started) {
|
|
128
|
-
console.warn('AsyncQueryBus stopping when already stopped')
|
|
129
|
-
}
|
|
130
|
-
if (this._pollId) clearTimeoutEx(this._pollId)
|
|
131
|
-
this._pollId = undefined
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
async unexpose(id: ModuleIdentifier, validate = true) {
|
|
135
|
-
const mod = asModuleInstance(await this.rootModule.resolve(id, { maxDepth: 10 }))
|
|
136
|
-
if (mod) {
|
|
137
|
-
assertEx(!validate || this._exposedAddresses.has(mod.address), () => `Address not exposed [${mod.address}][${mod.id}]`)
|
|
138
|
-
this._exposedAddresses.delete(mod.address)
|
|
139
|
-
delete this._exposeOptions[mod.address]
|
|
140
|
-
this.logger?.debug(`${mod.address} [${mod.id}] unexposed`)
|
|
141
|
-
}
|
|
142
|
-
return mod
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// eslint-disable-next-line complexity
|
|
146
|
-
protected callLocalModule = async (localModule: ModuleInstance, query: WithStorageMeta<QueryBoundWitness>) => {
|
|
147
|
-
this._idle = false
|
|
148
|
-
this._lastQueryTime = Date.now()
|
|
149
|
-
const localModuleName = localModule.id
|
|
150
|
-
const queryArchivist = assertEx(
|
|
151
|
-
await this.queriesArchivist(),
|
|
152
|
-
() => `Unable to contact queriesArchivist [${this.config?.intersect?.queries?.archivist}]`,
|
|
153
|
-
)
|
|
154
|
-
const responsesArchivist = assertEx(
|
|
155
|
-
await this.responsesArchivist(),
|
|
156
|
-
() => `Unable to contact responsesArchivist [${this.config?.intersect?.queries?.archivist}]`,
|
|
157
|
-
)
|
|
158
|
-
const queryDestination = query?.$destination
|
|
159
|
-
if (queryDestination && queryDestination?.includes(localModule.address)) {
|
|
160
|
-
// Find the query
|
|
161
|
-
const queryIndex = query.payload_hashes.indexOf(query.query)
|
|
162
|
-
if (queryIndex !== -1) {
|
|
163
|
-
const querySchema = query.payload_schemas[queryIndex]
|
|
164
|
-
// If the destination can process this type of query
|
|
165
|
-
if (localModule.queries.includes(querySchema)) {
|
|
166
|
-
// Get the associated payloads
|
|
167
|
-
const queryPayloads = await queryArchivist.get(query.payload_hashes)
|
|
168
|
-
this.params.onQueryFulfillStarted?.({ payloads: queryPayloads, query })
|
|
169
|
-
const queryPayloadsDict = await PayloadBuilder.toAllHashMap(queryPayloads)
|
|
170
|
-
const queryHash = await PayloadBuilder.dataHash(query)
|
|
171
|
-
// Check that we have all the arguments for the command
|
|
172
|
-
if (!containsAll(Object.keys(queryPayloadsDict), query.payload_hashes)) {
|
|
173
|
-
this.logger?.error(`Error processing command ${queryHash} for module ${localModuleName}, missing payloads`)
|
|
174
|
-
return
|
|
175
|
-
}
|
|
176
|
-
try {
|
|
177
|
-
// Issue the query against module
|
|
178
|
-
const querySchema = queryPayloadsDict[query.query].schema
|
|
179
|
-
this.logger?.debug(`Issuing query ${querySchema} (${queryHash}) addressed to module: ${localModuleName}`)
|
|
180
|
-
const result = await localModule.query(query, queryPayloads, {
|
|
181
|
-
allowedQueries: this._exposeOptions[localModule.address]?.allowedQueries,
|
|
182
|
-
schema: ModuleConfigSchema,
|
|
183
|
-
})
|
|
184
|
-
const [bw, payloads, errors] = result
|
|
185
|
-
this.logger?.debug(`Replying to query ${queryHash} addressed to module: ${localModuleName}`)
|
|
186
|
-
const insertResult = await responsesArchivist.insert([bw, ...payloads, ...errors])
|
|
187
|
-
// If all archivists support the contract that numPayloads inserted === numPayloads returned we can
|
|
188
|
-
// do some deeper assertions here like lenIn === lenOut, but for now this should be good enough since BWs
|
|
189
|
-
// should always be unique causing at least one insertion
|
|
190
|
-
if (insertResult.length === 0) {
|
|
191
|
-
this.logger?.error(`Error replying to query ${queryHash} addressed to module: ${localModuleName}`)
|
|
192
|
-
}
|
|
193
|
-
if (query?._sequence) {
|
|
194
|
-
// TODO: This needs to be thought through as we can't use a distributed timestamp
|
|
195
|
-
// because of collisions. We need to ensure we are using the timestamp of the store
|
|
196
|
-
// so there's no chance of multiple commands at the same time
|
|
197
|
-
await this.commitState(localModule.address, query._sequence)
|
|
198
|
-
}
|
|
199
|
-
this.params.onQueryFulfillFinished?.({
|
|
200
|
-
payloads: queryPayloads, query, result, status: 'success',
|
|
201
|
-
})
|
|
202
|
-
} catch (error) {
|
|
203
|
-
this.params.onQueryFulfillFinished?.({
|
|
204
|
-
payloads: queryPayloads, query, status: 'failure',
|
|
205
|
-
})
|
|
206
|
-
this.logger?.error(`Error processing query ${queryHash} for module ${localModuleName}: ${error}`)
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* Finds unprocessed commands addressed to the supplied address
|
|
215
|
-
* @param address The address to find commands for
|
|
216
|
-
*/
|
|
217
|
-
protected findQueriesToAddress = async (address: Address) => {
|
|
218
|
-
const queriesDivinerId = assertEx(this.config?.intersect?.queries?.boundWitnessDiviner, () => 'No queries Diviner defined')
|
|
219
|
-
const queriesBoundWitnessDiviner = await this.queriesDiviner()
|
|
220
|
-
if (queriesBoundWitnessDiviner) {
|
|
221
|
-
// Retrieve last offset from state store
|
|
222
|
-
const prevState = await this.retrieveState(address)
|
|
223
|
-
const destination = [address]
|
|
224
|
-
const limit = this.perAddressBatchQueryLimit
|
|
225
|
-
// Filter for commands to us by destination address
|
|
226
|
-
const divinerQuery: BoundWitnessDivinerQueryPayload = {
|
|
227
|
-
destination,
|
|
228
|
-
limit,
|
|
229
|
-
order: 'asc',
|
|
230
|
-
schema: BoundWitnessDivinerQuerySchema,
|
|
231
|
-
cursor: prevState,
|
|
232
|
-
}
|
|
233
|
-
const result = await queriesBoundWitnessDiviner.divine([divinerQuery])
|
|
234
|
-
const queries = result.filter(isQueryBoundWitnessWithStorageMeta)
|
|
235
|
-
// eslint-disable-next-line unicorn/no-array-reduce
|
|
236
|
-
const highestQuerySequence = queries.reduce(
|
|
237
|
-
(acc, query) => (hexFromBigInt(bigintMax(hexToBigInt(query._sequence), hexToBigInt(acc)))) as Sequence,
|
|
238
|
-
SequenceConstants.minLocalSequence as Sequence,
|
|
239
|
-
)
|
|
240
|
-
const nextState = queries.length > 0 ? highestQuerySequence : SequenceConstants.minLocalSequence
|
|
241
|
-
// TODO: This needs to be thought through as we can't use a distributed timestamp
|
|
242
|
-
// because of collisions. We need to use the timestamp of the store so there's no
|
|
243
|
-
// chance of multiple commands at the same time
|
|
244
|
-
await this.commitState(address, nextState)
|
|
245
|
-
this.logger?.debug('findQueriesToAddress', address, prevState, nextState)
|
|
246
|
-
return queries
|
|
247
|
-
} else {
|
|
248
|
-
this.logger?.warn(
|
|
249
|
-
`Unable to resolve queriesBoundWitnessDiviner [${queriesDivinerId}] [${await ResolveHelper.traceModuleIdentifier(this.rootModule, queriesDivinerId)}]`,
|
|
250
|
-
)
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
/**
|
|
255
|
-
* Runs the background divine process on a loop with a delay
|
|
256
|
-
* specified by the `config.pollFrequency`
|
|
257
|
-
*/
|
|
258
|
-
private poll() {
|
|
259
|
-
this._pollId = setTimeoutEx(
|
|
260
|
-
async () => {
|
|
261
|
-
try {
|
|
262
|
-
await this.processIncomingQueries()
|
|
263
|
-
} catch (e) {
|
|
264
|
-
this.logger?.error?.(`Error in main loop: ${e}`)
|
|
265
|
-
} finally {
|
|
266
|
-
if (this._pollId) clearTimeoutEx(this._pollId)
|
|
267
|
-
this._pollId = undefined
|
|
268
|
-
this.poll()
|
|
269
|
-
}
|
|
270
|
-
const now = Date.now()
|
|
271
|
-
if (this.idleThreshold < now - (this._lastQueryTime ?? now)) {
|
|
272
|
-
this._idle = true
|
|
273
|
-
}
|
|
274
|
-
},
|
|
275
|
-
this._idle ? this.idlePollFrequency : this.pollFrequency,
|
|
276
|
-
)
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
/**
|
|
280
|
-
* Background process for checking for inbound queries
|
|
281
|
-
*/
|
|
282
|
-
private processIncomingQueries = async () => {
|
|
283
|
-
this.logger?.debug('Checking for inbound queries')
|
|
284
|
-
// Check for any queries that have been issued and have not been responded to
|
|
285
|
-
const localModules = await this.listeningModules()
|
|
286
|
-
|
|
287
|
-
// TODO: Do in throttled batches
|
|
288
|
-
await Promise.allSettled(
|
|
289
|
-
localModules.map(async (localModule) => {
|
|
290
|
-
try {
|
|
291
|
-
const localModuleName = localModule.id
|
|
292
|
-
this.logger?.debug(`Checking for inbound queries to ${localModuleName} [${localModule.address}]`)
|
|
293
|
-
const queries = (await this.findQueriesToAddress(localModule.address)) ?? []
|
|
294
|
-
if (queries.length === 0) return
|
|
295
|
-
this.logger?.debug(`Found queries addressed to local module: ${localModuleName}`)
|
|
296
|
-
for (const query of queries) {
|
|
297
|
-
await this.callLocalModule(localModule, query)
|
|
298
|
-
}
|
|
299
|
-
} catch (error) {
|
|
300
|
-
this.logger?.error(`Error processing queries for address ${localModule.address}: ${error}`)
|
|
301
|
-
}
|
|
302
|
-
}),
|
|
303
|
-
)
|
|
304
|
-
}
|
|
305
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import type { ModuleHostParams } from '../../AbstractModuleHost/index.ts'
|
|
2
|
-
import { AbstractModuleHost } from '../../AbstractModuleHost/index.ts'
|
|
3
|
-
import { AsyncQueryBusHost } from '../AsyncQueryBusHost.ts'
|
|
4
|
-
import type { AsyncQueryBusHostConfig } from '../model/index.ts'
|
|
5
|
-
|
|
6
|
-
export type AsyncQueryBusModuleHostParams = ModuleHostParams & {
|
|
7
|
-
config: AsyncQueryBusHostConfig
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export class AsyncQueryBusModuleHost extends AbstractModuleHost<AsyncQueryBusModuleHostParams> {
|
|
11
|
-
private _busHost?: AsyncQueryBusHost
|
|
12
|
-
|
|
13
|
-
constructor(params: AsyncQueryBusModuleHostParams) {
|
|
14
|
-
super(params)
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
override async start(): Promise<void> {
|
|
18
|
-
const listeningModules = this.params.config.listeningModules ?? (await this.params.mod.resolve('*', { direction: 'down' })).map(m => m.address)
|
|
19
|
-
this._busHost = new AsyncQueryBusHost({
|
|
20
|
-
config: { ...this.params.config, listeningModules },
|
|
21
|
-
logger: this.params.logger,
|
|
22
|
-
rootModule: this.params.mod,
|
|
23
|
-
})
|
|
24
|
-
this._busHost?.start()
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
override stop() {
|
|
28
|
-
this._busHost?.stop()
|
|
29
|
-
}
|
|
30
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './ModuleHost.ts'
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
assertEx,
|
|
3
|
-
CreatableInstance, exists,
|
|
4
|
-
forget,
|
|
5
|
-
isAddress, isString,
|
|
6
|
-
} from '@xylabs/sdk-js'
|
|
7
|
-
import type { QueryBoundWitness } from '@xyo-network/boundwitness-model'
|
|
8
|
-
import type { ModuleProxyParams } from '@xyo-network/bridge-abstract'
|
|
9
|
-
import { AbstractModuleProxy } from '@xyo-network/bridge-abstract'
|
|
10
|
-
import { AbstractModule } from '@xyo-network/module-abstract'
|
|
11
|
-
import type {
|
|
12
|
-
ModuleFilterOptions,
|
|
13
|
-
ModuleIdentifier,
|
|
14
|
-
ModuleInstance,
|
|
15
|
-
ModuleName,
|
|
16
|
-
ModuleQueryResult,
|
|
17
|
-
ResolveHelperConfig,
|
|
18
|
-
} from '@xyo-network/module-model'
|
|
19
|
-
import { creatableModule, ResolveHelper } from '@xyo-network/module-model'
|
|
20
|
-
import type { Payload } from '@xyo-network/payload-model'
|
|
21
|
-
|
|
22
|
-
import type { AsyncQueryBusClient } from '../AsyncQueryBusClient.ts'
|
|
23
|
-
|
|
24
|
-
export interface AsyncQueryBusModuleProxyParams extends ModuleProxyParams {
|
|
25
|
-
busClient: AsyncQueryBusClient
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
@creatableModule()
|
|
29
|
-
export class AsyncQueryBusModuleProxy<
|
|
30
|
-
TWrappedModule extends ModuleInstance = ModuleInstance,
|
|
31
|
-
>
|
|
32
|
-
extends AbstractModuleProxy<TWrappedModule, AsyncQueryBusModuleProxyParams & TWrappedModule['params']> {
|
|
33
|
-
override get id(): ModuleIdentifier {
|
|
34
|
-
return this.address
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
override get modName(): ModuleName | undefined {
|
|
38
|
-
return undefined
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
static override async createHandler<T extends CreatableInstance>(
|
|
42
|
-
inInstance: T,
|
|
43
|
-
) {
|
|
44
|
-
const instance: T & AbstractModule = (await super.createHandler(inInstance))
|
|
45
|
-
return instance
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
async proxyQueryHandler<T extends QueryBoundWitness = QueryBoundWitness>(query: T, payloads?: Payload[]): Promise<ModuleQueryResult> {
|
|
49
|
-
if (this.archiving && this.isAllowedArchivingQuery(query.schema)) {
|
|
50
|
-
forget(this.storeToArchivists([query, ...(payloads ?? [])]))
|
|
51
|
-
}
|
|
52
|
-
const result = await this.params.busClient.send(this.address, query, payloads)
|
|
53
|
-
if (this.archiving && this.isAllowedArchivingQuery(query.schema)) {
|
|
54
|
-
forget(this.storeToArchivists(result.flat()))
|
|
55
|
-
}
|
|
56
|
-
return result
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
override async publicChildren(): Promise<ModuleInstance[]> {
|
|
60
|
-
return (
|
|
61
|
-
await Promise.all(
|
|
62
|
-
Object.keys(await this.childAddressMap())
|
|
63
|
-
.filter(exists)
|
|
64
|
-
.map(address => this.resolve(address)),
|
|
65
|
-
)
|
|
66
|
-
).filter(exists)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/** @deprecated do not pass undefined. If trying to get all, pass '*' */
|
|
70
|
-
override async resolve(): Promise<ModuleInstance[]>
|
|
71
|
-
override async resolve<T extends ModuleInstance = ModuleInstance>(all: '*', options?: ModuleFilterOptions<T>): Promise<T[]>
|
|
72
|
-
override async resolve<T extends ModuleInstance = ModuleInstance>(id: ModuleIdentifier, options?: ModuleFilterOptions<T>): Promise<T | undefined>
|
|
73
|
-
override async resolve<T extends ModuleInstance = ModuleInstance>(
|
|
74
|
-
id: ModuleIdentifier = '*',
|
|
75
|
-
options: ModuleFilterOptions<T> = {},
|
|
76
|
-
): Promise<T | T[] | undefined> {
|
|
77
|
-
const config: ResolveHelperConfig = {
|
|
78
|
-
address: this.address,
|
|
79
|
-
dead: this.dead,
|
|
80
|
-
downResolver: this.downResolver,
|
|
81
|
-
logger: this.logger,
|
|
82
|
-
mod: this,
|
|
83
|
-
transformers: this.moduleIdentifierTransformers,
|
|
84
|
-
upResolver: this.upResolver,
|
|
85
|
-
}
|
|
86
|
-
if (id === '*') {
|
|
87
|
-
return (await this.publicChildren()) as T[]
|
|
88
|
-
}
|
|
89
|
-
switch (typeof id) {
|
|
90
|
-
case 'string': {
|
|
91
|
-
const parts = id.split(':')
|
|
92
|
-
const first = assertEx(parts.shift(), () => 'Missing first')
|
|
93
|
-
const remainingPath = parts.length > 0 ? parts.join(':') : undefined
|
|
94
|
-
const address = isAddress(first) ? first : this.childAddressByName(first)
|
|
95
|
-
if (!isAddress(address)) return undefined
|
|
96
|
-
const firstInstance = (await this.params.host.resolve(address)) as ModuleInstance | undefined
|
|
97
|
-
return (isString(remainingPath) ? await firstInstance?.resolve(remainingPath) : firstInstance) as T | undefined
|
|
98
|
-
}
|
|
99
|
-
default: {
|
|
100
|
-
return (await ResolveHelper.resolve(config, id, options)).filter(mod => mod.address !== this.address)
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './ModuleProxy.ts'
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type { SearchableStorage } from '@xyo-network/diviner-model'
|
|
2
|
-
|
|
3
|
-
import type { AsyncQueryBusIntersectConfig } from './IntersectConfig.ts'
|
|
4
|
-
|
|
5
|
-
export interface AsyncQueryBusBaseConfig {
|
|
6
|
-
intersect?: AsyncQueryBusIntersectConfig
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* How often to poll for new queries/responses
|
|
10
|
-
*/
|
|
11
|
-
pollFrequency?: number
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Where the archivist should persist its internal state
|
|
15
|
-
*/
|
|
16
|
-
stateStore?: SearchableStorage
|
|
17
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { BridgeClientConfig } from '@xyo-network/bridge-model'
|
|
2
|
-
import type { CacheConfig } from '@xyo-network/module-model'
|
|
3
|
-
|
|
4
|
-
import type { AsyncQueryBusBaseConfig } from './BaseConfig.ts'
|
|
5
|
-
|
|
6
|
-
export interface AsyncQueryBusClientConfig extends AsyncQueryBusBaseConfig, BridgeClientConfig {
|
|
7
|
-
/**
|
|
8
|
-
* Configuration for intermediary response storage
|
|
9
|
-
*/
|
|
10
|
-
queryCache?: CacheConfig | true
|
|
11
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import type { Address } from '@xylabs/sdk-js'
|
|
2
|
-
|
|
3
|
-
import type { AsyncQueryBusBaseConfig } from './BaseConfig.ts'
|
|
4
|
-
|
|
5
|
-
export interface AsyncQueryBusHostConfig extends AsyncQueryBusBaseConfig {
|
|
6
|
-
/**
|
|
7
|
-
* The frequency at which the host should poll for new queries when no new queries have been received for a while
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
idlePollFrequency?: number
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* The threshold at which the host should consider itself idle and switch to the idle poll frequency
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
idleThreshold?: number
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Modules that should be exposed via this host
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
listeningModules?: Address[]
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* How many queries to process at once when retrieving queries
|
|
26
|
-
* for an address
|
|
27
|
-
*/
|
|
28
|
-
perAddressBatchQueryLimit?: number
|
|
29
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { SearchableStorage } from '@xyo-network/diviner-model'
|
|
2
|
-
|
|
3
|
-
export interface AsyncQueryBusIntersectConfig {
|
|
4
|
-
/**
|
|
5
|
-
* Configuration for intermediary query storage
|
|
6
|
-
*/
|
|
7
|
-
queries?: SearchableStorage
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Configuration for intermediary response storage
|
|
11
|
-
*/
|
|
12
|
-
responses?: SearchableStorage
|
|
13
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { BaseParams } from '@xylabs/sdk-js'
|
|
2
|
-
import type { QueryFulfillFinishedEventArgs, QueryFulfillStartedEventArgs } from '@xyo-network/bridge-model'
|
|
3
|
-
import type { ModuleInstance } from '@xyo-network/module-model'
|
|
4
|
-
|
|
5
|
-
import type { AsyncQueryBusBaseConfig } from './BaseConfig.ts'
|
|
6
|
-
import type { AsyncQueryBusClientConfig } from './ClientConfig.ts'
|
|
7
|
-
import type { AsyncQueryBusHostConfig } from './HostConfig.ts'
|
|
8
|
-
|
|
9
|
-
export type AsyncQueryBusParams<TConfig extends AsyncQueryBusBaseConfig = AsyncQueryBusBaseConfig> = BaseParams<{
|
|
10
|
-
config?: TConfig
|
|
11
|
-
rootModule: ModuleInstance
|
|
12
|
-
}>
|
|
13
|
-
|
|
14
|
-
export type AsyncQueryBusClientParams = AsyncQueryBusParams<AsyncQueryBusClientConfig>
|
|
15
|
-
export type AsyncQueryBusHostParams = AsyncQueryBusParams<AsyncQueryBusHostConfig> & {
|
|
16
|
-
onQueryFulfillFinished?: (args: Omit<QueryFulfillFinishedEventArgs, 'mod'>) => void
|
|
17
|
-
onQueryFulfillStarted?: (args: Omit<QueryFulfillStartedEventArgs, 'mod'>) => void
|
|
18
|
-
}
|
package/src/Config.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import type { Address, EmptyObject } from '@xylabs/sdk-js'
|
|
2
|
-
import type { BridgeConfig } from '@xyo-network/bridge-model'
|
|
3
|
-
import type { Schema } from '@xyo-network/payload-model'
|
|
4
|
-
import { asSchema } from '@xyo-network/payload-model'
|
|
5
|
-
|
|
6
|
-
import type { AsyncQueryBusClientConfig, AsyncQueryBusHostConfig } from './AsyncQueryBus/index.ts'
|
|
7
|
-
import { PubSubBridgeSchema } from './Schema.ts'
|
|
8
|
-
|
|
9
|
-
export const PubSubBridgeConfigSchema = asSchema(`${PubSubBridgeSchema}.config`, true)
|
|
10
|
-
export type PubSubBridgeConfigSchema = typeof PubSubBridgeConfigSchema
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Configuration for the PubSubBridge
|
|
14
|
-
*/
|
|
15
|
-
export type PubSubBridgeConfig<TConfig extends EmptyObject = EmptyObject, TSchema extends string | void = void> = BridgeConfig<
|
|
16
|
-
{
|
|
17
|
-
client?: AsyncQueryBusClientConfig
|
|
18
|
-
host?: AsyncQueryBusHostConfig
|
|
19
|
-
roots?: Address[]
|
|
20
|
-
} & TConfig,
|
|
21
|
-
TSchema extends Schema ? TSchema : PubSubBridgeConfigSchema
|
|
22
|
-
>
|
package/src/Params.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { BridgeParams } from '@xyo-network/bridge-model'
|
|
2
|
-
import type { AnyConfigSchema } from '@xyo-network/module-model'
|
|
3
|
-
|
|
4
|
-
import type { PubSubBridgeConfig } from './Config.ts'
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* The parameters for the PubSubBridge
|
|
8
|
-
*/
|
|
9
|
-
export type PubSubBridgeParams<TConfig extends AnyConfigSchema<PubSubBridgeConfig> = AnyConfigSchema<PubSubBridgeConfig>> = BridgeParams<TConfig>
|