Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions packages/apps/chainweaver-pact-console-plugin/src/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ export const hostUrlGenerator = (networks: INetwork[]) => {
checkNetworks().catch((er) =>
console.log('Error while checking networks', er),
);
return ({ networkId, chainId }: INetworkOptions) => {
return ({ networkId, chainId, type }: INetworkOptions) => {
// TODO: for the devnet we should consider rate limiting as well and pause the process for some time
if (Date.now() - lastCheckTime > 30000) {
checkNetworks().catch((er) =>
console.log('Error while checking networks', er),
Expand All @@ -75,6 +76,6 @@ export const hostUrlGenerator = (networks: INetwork[]) => {
if (!host) {
throw new Error('No healthy host found');
}
return getHostUrl(host.url)({ networkId, chainId });
return getHostUrl(host.url)({ networkId, chainId, type });
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export const hostUrlGenerator = (networks: INetwork[]) => {
checkNetworks().catch((er) =>
console.log('Error while checking networks', er),
);
return ({ networkId, chainId }: INetworkOptions) => {
return ({ networkId, chainId, type }: INetworkOptions) => {
if (Date.now() - lastCheckTime > 10000) {
checkNetworks().catch((er) =>
console.log('Error while checking networks', er),
Expand All @@ -59,6 +59,6 @@ export const hostUrlGenerator = (networks: INetwork[]) => {
if (!host) {
throw new Error('No healthy host found');
}
return getHostUrl(host.url)({ networkId, chainId });
return getHostUrl(host.url)({ networkId, chainId, type });
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ export const WalletProvider: FC<PropsWithChildren> = ({ children }) => {
const hostUrl = networkHostFunctionRef.current;
if (hostUrl && ctx.activeNetwork) {
try {
hostUrl({ networkId: ctx.activeNetwork.networkId, chainId: '0' });
hostUrl({ networkId: ctx.activeNetwork.networkId, chainId: '0', type: 'local' });
if (ctx.activeNetwork.isHealthy === true) return ctx;
return {
...ctx,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,5 @@ export async function pollRequestsAndWaitForEachPromiseExample(): Promise<void>
});

// await for each individual request
await Promise.all(
Object.entries(results.requests).map(([requestKey, promise]) =>
promise
.then((data) => {
console.log('the request ', requestKey, 'result:', data);
})
.catch((error) => {
console.log(
'error while getting the status of ',
requestKey,
'error:',
error,
);
}),
),
);
console.log('waiting for results', await results);
}
20 changes: 11 additions & 9 deletions packages/libs/client/etc/client.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export interface IClient extends IBaseClient {
getPoll: (transactionDescriptors: ITransactionDescriptor[] | ITransactionDescriptor, options?: ClientRequestInit) => Promise<IPollResponse>;
pollOne: (transactionDescriptor: ITransactionDescriptor, options?: IPollOptions) => Promise<ICommandResult>;
preflight: (transaction: ICommand | IUnsignedCommand, options?: ClientRequestInit) => Promise<ILocalCommandResult>;
runPact: (code: string, data: Record<string, unknown>, option: ClientRequestInit & INetworkOptions) => Promise<ICommandResult>;
runPact: (code: string, data: Record<string, unknown>, option: ClientRequestInit & Omit<INetworkOptions, 'type'>) => Promise<ICommandResult>;
// @deprecated
send: ISubmit;
signatureVerification: (transaction: ICommand, options?: ClientRequestInit) => Promise<ICommandResult>;
Expand Down Expand Up @@ -171,16 +171,18 @@ export interface ICreateClient {
(hostUrl: string, defaults?: {
confirmationDepth?: number;
}): IClient;
(hostAddressGenerator?: (options: {
chainId: ChainId;
networkId: string;
type?: 'local' | 'send' | 'poll' | 'listen' | 'spv';
}) => string | {
(hostAddressGenerator?: (options: INetworkOptions) => string | {
hostUrl: string;
requestInit: ClientRequestInit;
}, defaults?: {
confirmationDepth?: number;
}): IClient;
(hostAddressGenerator?: (options: INetworkOptions) => Promise<string | {
hostUrl: string;
requestInit: ClientRequestInit;
}>, defaults?: {
confirmationDepth?: number;
}): IClient;
}

// @public
Expand Down Expand Up @@ -230,6 +232,8 @@ export interface INetworkOptions {
chainId: ChainId;
// (undocumented)
networkId: string;
// (undocumented)
type: 'local' | 'send' | 'poll' | 'listen' | 'spv';
}

// @public
Expand Down Expand Up @@ -307,9 +311,7 @@ export interface IPollOptions extends ClientRequestInit {
}

// @public (undocumented)
export type IPollRequestPromise<T> = Promise<Record<string, T>> & {
requests: Record<string, Promise<T>>;
};
export type IPollRequestPromise<T> = Promise<Record<string, T>>;

export { IPollResponse }

Expand Down
78 changes: 45 additions & 33 deletions packages/libs/client/src/client/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ export interface IClient extends IBaseClient {
runPact: (
code: string,
data: Record<string, unknown>,
option: ClientRequestInit & INetworkOptions,
option: ClientRequestInit & Omit<INetworkOptions,'type'>,
) => Promise<ICommandResult>;

/**
Expand Down Expand Up @@ -286,11 +286,23 @@ export interface ICreateClient {
* @param defaults - default options for the client it includes confirmationDepth that is used for polling
*/
(
hostAddressGenerator?: (options: {
chainId: ChainId;
networkId: string;
type?: 'local' | 'send' | 'poll' | 'listen' | 'spv';
}) => string | { hostUrl: string; requestInit: ClientRequestInit },
hostAddressGenerator?: (options: INetworkOptions) => string | { hostUrl: string; requestInit: ClientRequestInit },
defaults?: { confirmationDepth?: number },
): IClient;

/**
* Generates a client instance by passing async hostUrlGenerator function.
* this function will be called for each request to get the latest host URL.
* You also can use this for more advanced use cases like load balancing or
* failover between multiple hosts or control rate limiting.
*
* Note: The default hostUrlGenerator creates a Kadena testnet or mainnet URL based on networkId.
* @param hostAddressGenerator - the function that generates the URL based on `chainId` and `networkId` from the transaction
* @param defaults - default options for the client it includes confirmationDepth that is used for polling
*/

(
hostAddressGenerator?: (options: INetworkOptions) => Promise<string | { hostUrl: string; requestInit: ClientRequestInit }>,
defaults?: { confirmationDepth?: number },
): IClient;
}
Expand All @@ -317,11 +329,12 @@ export const createClient: ICreateClient = (
const getHost = typeof host === 'string' ? () => host : host;

const client: IBaseClient = {
local(body, options) {
async local(body, options) {
const cmd: IPactCommand = JSON.parse(body.cmd);
const hostObject = getHost({
const hostObject = await getHost({
chainId: cmd.meta.chainId,
networkId: cmd.networkId,
type: 'local',
});
const { hostUrl, requestInit } = getHostData(hostObject);
return local(body, hostUrl, mergeOptions(requestInit, options));
Expand All @@ -334,9 +347,10 @@ export const createClient: ICreateClient = (
throw new Error('EMPTY_COMMAND_LIST');
}
const cmd: IPactCommand = JSON.parse(first.cmd);
const hostObject = getHost({
const hostObject = await getHost({
chainId: cmd.meta.chainId,
networkId: cmd.networkId,
type: 'send',
});

const { hostUrl, requestInit } = getHostData(hostObject);
Expand Down Expand Up @@ -364,18 +378,17 @@ export const createClient: ICreateClient = (
: [transactionDescriptors];
const results = groupByHost(
requestsList.map(({ requestKey, chainId, networkId }) => {
const hostObject = getHost({ chainId, networkId, type: 'poll' });
const { hostUrl, requestInit } = getHostData(hostObject);
return {
requestKey,
host: hostUrl,
requestInit,
host: JSON.stringify({ chainId, networkId}),
};
}),
).map(([host, requestKeys]) => {
const requestInit = requestKeys[0].requestInit;
).map( async ([host, requestKeys]) => {
const { chainId, networkId} = JSON.parse(host)
const hostObject = await getHost({ chainId, networkId, type: 'poll' });
const { hostUrl, requestInit } = getHostData(hostObject)
return pollStatus(
host,
hostUrl,
requestKeys.map((r) => r.requestKey),
{
confirmationDepth,
Expand All @@ -396,17 +409,16 @@ export const createClient: ICreateClient = (

const results = await Promise.all(
groupByHost(
requestsList.map(({ requestKey, chainId, networkId }) => {
const hostObject = getHost({ chainId, networkId, type: 'poll' });
const { hostUrl, requestInit } = getHostData(hostObject);
return {
requestKey,
host: hostUrl,
requestInit,
};
}),
).map(([hostUrl, requestKeys]) => {
const requestInit = requestKeys[0].requestInit;
requestsList.map(({ requestKey, chainId, networkId }) => {
return {
requestKey,
host: JSON.stringify({ chainId, networkId}),
};
}),
).map(async ([host, requestKeys]) => {
const { chainId, networkId} = JSON.parse(host)
const hostObject = await getHost({ chainId, networkId, type: 'poll' });
const { hostUrl, requestInit } = getHostData(hostObject)

return poll(
{ requestKeys: requestKeys.map((r) => r.requestKey) },
Expand All @@ -424,7 +436,7 @@ export const createClient: ICreateClient = (
},

async listen({ requestKey, chainId, networkId }, options) {
const hostObject = getHost({ chainId, networkId, type: 'listen' });
const hostObject = await getHost({ chainId, networkId, type: 'listen' });
const { hostUrl, requestInit } = getHostData(hostObject);
const result = await listen(
{ listen: requestKey },
Expand All @@ -435,8 +447,8 @@ export const createClient: ICreateClient = (
return result;
},

pollCreateSpv({ requestKey, chainId, networkId }, targetChainId, options) {
const hostObject = getHost({ chainId, networkId, type: 'spv' });
async pollCreateSpv({ requestKey, chainId, networkId }, targetChainId, options) {
const hostObject = await getHost({ chainId, networkId, type: 'spv' });
const { hostUrl, requestInit } = getHostData(hostObject);
return pollSpv(
hostUrl,
Expand All @@ -451,7 +463,7 @@ export const createClient: ICreateClient = (
targetChainId,
options,
) {
const hostObject = getHost({ chainId, networkId, type: 'spv' });
const hostObject = await getHost({ chainId, networkId, type: 'spv' });
const { hostUrl, requestInit } = getHostData(hostObject);
return getSpv(
hostUrl,
Expand Down Expand Up @@ -486,8 +498,8 @@ export const createClient: ICreateClient = (
signatureVerification: false,
});
},
runPact: (code, data, options) => {
const hostObject = getHost(options);
runPact: async (code, data, options) => {
const hostObject = await getHost({...options, type: 'local'});
const { hostUrl, requestInit } = getHostData(hostObject);
if (hostUrl === '') throw new Error('NO_HOST_URL');

Expand Down
8 changes: 2 additions & 6 deletions packages/libs/client/src/client/interfaces/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type { ChainId } from '@kadena/types';
export interface INetworkOptions {
networkId: string;
chainId: ChainId;
type: 'local' | 'send' | 'poll' | 'listen' | 'spv';
}

/**
Expand All @@ -32,9 +33,4 @@ export interface IPollOptions extends ClientRequestInit {
/**
* @public
*/
export type IPollRequestPromise<T> = Promise<Record<string, T>> & {
/**
* @deprecated pass callback to {@link IPollOptions.onResult} instead
*/
requests: Record<string, Promise<T>>;
};
export type IPollRequestPromise<T> = Promise<Record<string, T>>
27 changes: 8 additions & 19 deletions packages/libs/client/src/client/utils/tests/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,26 +56,26 @@ describe('client utils', () => {
describe('kadenaHostGenerator', () => {
it('returns mainnet url with the correct chainId', () => {
expect(
kadenaHostGenerator({ networkId: 'mainnet01', chainId: '14' }),
kadenaHostGenerator({ networkId: 'mainnet01', chainId: '14', type: 'local' }),
).toBe('https://api.chainweb.com/chainweb/0.0/mainnet01/chain/14/pact');
});

it('returns testnet url with the correct chainId', () => {
expect(
kadenaHostGenerator({ networkId: 'testnet04', chainId: '14' }),
kadenaHostGenerator({ networkId: 'testnet04', chainId: '14',type: 'local' }),
).toBe(
'https://api.testnet.chainweb.com/chainweb/0.0/testnet04/chain/14/pact',
);
expect(
kadenaHostGenerator({ networkId: 'testnet05', chainId: '14' }),
kadenaHostGenerator({ networkId: 'testnet05', chainId: '14', type: 'local' }),
).toBe(
'https://api.testnet05.chainweb.com/chainweb/0.0/testnet05/chain/14/pact',
);
});

it('throes exception if networkId is not either mainnet01 nor testnet04 ', () => {
expect(() =>
kadenaHostGenerator({ networkId: 'incorrect-network', chainId: '14' }),
kadenaHostGenerator({ networkId: 'incorrect-network', chainId: '14', type: 'local' }),
).toThrowError(Error(`UNKNOWN_NETWORK_ID: incorrect-network`));
});
});
Expand All @@ -84,14 +84,14 @@ describe('client utils', () => {
it('returns a function that generates host url based on the networkId and chainId', () => {
const hostUrl = 'http://localhost:8080';
const getLocalHostUrl = getHostUrl(hostUrl);
expect(getLocalHostUrl({ networkId: 'mainnet01', chainId: '14' })).toBe(
expect(getLocalHostUrl({ networkId: 'mainnet01', chainId: '14', type:'local' })).toBe(
'http://localhost:8080/chainweb/0.0/mainnet01/chain/14/pact',
);
});
it("removes the last '/' from the host url", () => {
const hostUrl = 'http://localhost:8080/';
const getLocalHostUrl = getHostUrl(hostUrl);
expect(getLocalHostUrl({ networkId: 'mainnet01', chainId: '14' })).toBe(
expect(getLocalHostUrl({ networkId: 'mainnet01', chainId: '14', type:'local' })).toBe(
'http://localhost:8080/chainweb/0.0/mainnet01/chain/14/pact',
);
});
Expand Down Expand Up @@ -199,23 +199,12 @@ describe('client utils', () => {
requests: { key2: Promise.resolve('r2') },
},
);
const mergedPr = mergeAllPollRequestPromises([pr1, pr2]);
const mergedPr = await mergeAllPollRequestPromises([pr1, pr2]);

expect(Object.keys(mergedPr.requests)).toEqual(['key1', 'key2']);

const res = await Promise.all([
mergedPr,
mergedPr.requests.key1,
mergedPr.requests.key2,
]);

expect(res[0]).toEqual({
expect(mergedPr).toEqual({
key1: 'r1',
key2: 'r2',
});

expect(res[1]).toEqual('r1');
expect(res[2]).toEqual('r2');
});
});

Expand Down
Loading
Loading