-
Notifications
You must be signed in to change notification settings - Fork 87
wip - add client middleware stack #227
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| // Copyright (c) Mysten Labs, Inc. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| import { SuiClient } from '../client/index.js'; | ||
| import type { Experimental_SuiClientTypes } from './types.js'; | ||
|
|
||
| type MiddlewareFunction = <Args extends unknown[], Return extends unknown>( | ||
| scope: string, | ||
| method: string, | ||
| args: Args, | ||
| next: (...args: Args) => Promise<Return>, | ||
| ) => Promise<Return>; | ||
|
|
||
| export class ClientMiddlewareStack { | ||
| #middleware: MiddlewareFunction[] = []; | ||
|
|
||
| use(middleware: MiddlewareFunction) { | ||
| if (this.#middleware.includes(middleware)) { | ||
| throw new Error(`Middleware ${middleware.name} is already registered`); | ||
| } | ||
| this.#middleware.push(middleware); | ||
| } | ||
|
|
||
| wrap<Args extends unknown[], Return extends unknown>( | ||
| scope: string, | ||
| name: string, | ||
| fn: (...args: Args) => Promise<Return>, | ||
| ) { | ||
| const stack = this; | ||
| return function <T>(this: T, ...args: Args) { | ||
| return stack.run(scope, name, fn, this, args); | ||
| }; | ||
| } | ||
|
|
||
| run<Args extends unknown[], Return extends unknown>( | ||
| scope: string, | ||
| name: string, | ||
| fn: (...args: Args) => Promise<Return>, | ||
| ctx: unknown, | ||
| args: Args, | ||
| ) { | ||
| const createNext = (i: number) => { | ||
| let calledNext = false; | ||
|
|
||
| return async (...args: Args): Promise<Return> => { | ||
| if (calledNext) { | ||
| throw new Error(`next() was call multiple times`); | ||
| } | ||
|
|
||
| calledNext = true; | ||
|
|
||
| if (i >= this.#middleware.length) { | ||
| return fn.apply(ctx, args); | ||
| } | ||
|
|
||
| const middleware = this.#middleware[i]; | ||
| return middleware(scope, name, args, async (...args) => createNext(i + 1)(...args)); | ||
| }; | ||
| }; | ||
|
|
||
| return createNext(0)(...args); | ||
| } | ||
| } | ||
|
|
||
| new SuiClient({ | ||
|
Check failure on line 65 in packages/typescript/src/experimental/middleware.ts
|
||
| network: 'mainnet', | ||
| url: 'https://fullnode.mainnet.sui.io', | ||
| }).middleware.use(async (scope, name, args, next) => { | ||
| if (scope === 'core' && name === 'getObjects') { | ||
| const [options] = args as unknown as [Experimental_SuiClientTypes.GetObjectsOptions]; | ||
|
|
||
| return next( | ||
| ...([ | ||
| { | ||
| ...options, | ||
| objectIds: await resolveMvrTypes(options.objectIds), | ||
| }, | ||
| ] as never), | ||
| ); | ||
| } | ||
|
|
||
| return next(...args); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,7 +15,7 @@ | |
| import { batch } from '../../transactions/plugins/utils.js'; | ||
| import { Transaction } from '../../transactions/Transaction.js'; | ||
| import { normalizeStructTag } from '../../utils/sui-types.js'; | ||
| import { Experimental_CoreClient } from '../core.js'; | ||
| import { ObjectError } from '../errors.js'; | ||
| import type { Experimental_SuiClientTypes } from '../types.js'; | ||
|
|
||
|
|
@@ -23,37 +23,41 @@ | |
| #jsonRpcClient: SuiClient; | ||
|
|
||
| constructor(jsonRpcClient: SuiClient) { | ||
| super({ network: jsonRpcClient.network }); | ||
| super({ network: jsonRpcClient.network, root: jsonRpcClient.root }); | ||
| this.#jsonRpcClient = jsonRpcClient; | ||
| } | ||
|
|
||
| async getObjects(options: Experimental_SuiClientTypes.GetObjectsOptions) { | ||
| const batches = batch(options.objectIds, 50); | ||
| const results: Experimental_SuiClientTypes.GetObjectsResponse['objects'] = []; | ||
|
|
||
| for (const batch of batches) { | ||
| const objects = await this.#jsonRpcClient.multiGetObjects({ | ||
| ids: batch, | ||
| options: { | ||
| showOwner: true, | ||
| showType: true, | ||
| showBcs: true, | ||
| }, | ||
| }); | ||
| getObjects = this.root.middleware.wrap( | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't love making all of these instance properties... We could also do getObjects(options) {
return this.root.middleware.run('core', 'getObjects', this, [options], (options) => {
// contents
})
}
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah neither do I, I'd probably do it this way |
||
| 'core', | ||
| 'getObjects', | ||
| async (options: Experimental_SuiClientTypes.GetObjectsOptions) => { | ||
| const batches = batch(options.objectIds, 50); | ||
| const results: Experimental_SuiClientTypes.GetObjectsResponse['objects'] = []; | ||
|
|
||
| for (const batch of batches) { | ||
| const objects = await this.#jsonRpcClient.multiGetObjects({ | ||
| ids: batch, | ||
| options: { | ||
| showOwner: true, | ||
| showType: true, | ||
| showBcs: true, | ||
| }, | ||
| }); | ||
|
|
||
| for (const [idx, object] of objects.entries()) { | ||
| if (object.error) { | ||
| results.push(ObjectError.fromResponse(object.error, batch[idx])); | ||
| } else { | ||
| results.push(parseObject(object.data!)); | ||
| for (const [idx, object] of objects.entries()) { | ||
| if (object.error) { | ||
| results.push(ObjectError.fromResponse(object.error, batch[idx])); | ||
| } else { | ||
| results.push(parseObject(object.data!)); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return { | ||
| objects: results, | ||
| }; | ||
| } | ||
| return { | ||
| objects: results, | ||
| }; | ||
| }, | ||
| ); | ||
| async getOwnedObjects(options: Experimental_SuiClientTypes.GetOwnedObjectsOptions) { | ||
| const objects = await this.#jsonRpcClient.getOwnedObjects({ | ||
| owner: options.address, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be the last arg