Skip to content
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

Web3ApiClient adding default config should extend interface implementations #766

Merged
merged 7 commits into from
Mar 22, 2022
64 changes: 61 additions & 3 deletions packages/js/client/src/Web3ApiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ export class Web3ApiClient implements Client {

this._validateConfig();

this._sanitizeConfig();

Tracer.setAttribute("config", this._config);
} catch (error) {
Tracer.recordException(error);
Expand Down Expand Up @@ -362,9 +364,7 @@ export class Web3ApiClient implements Client {
if (freq && (freq.ms || freq.sec || freq.min || freq.hours)) {
frequency =
(freq.ms ?? 0) +
((freq.hours ?? 0) * 3600 +
(freq.min ?? 0) * 60 +
(freq.sec ?? 0)) *
((freq.hours ?? 0) * 3600 + (freq.min ?? 0) * 60 + (freq.sec ?? 0)) *
1000;
} else {
frequency = 60000;
Expand Down Expand Up @@ -525,6 +525,64 @@ export class Web3ApiClient implements Client {
}
}

@Tracer.traceMethod("Web3ApiClient: sanitizeConfig")
private _sanitizeConfig(): void {
this._sanitizeInterfacesAndImplementations();
}

// Make sure interface URIs are unique and that all of their implementation URIs are unique
// If not, then merge them
@Tracer.traceMethod("Web3ApiClient: sanitizeInterfacesAndImplementations")
private _sanitizeInterfacesAndImplementations(): void {
const interfaces = this._config.interfaces;
// Interface hash map used to keep track of interfaces with same URI
// A set is used to keep track of unique implementation URIs
const addedInterfacesHashMap = new Map<string, Set<string>>();

for (const interfaceImplementations of interfaces) {
const interfaceUri = interfaceImplementations.interface.uri;

if (!addedInterfacesHashMap.has(interfaceUri)) {
// If the interface is not added yet then just add it along with its implementations
addedInterfacesHashMap.set(
interfaceUri,
new Set(interfaceImplementations.implementations.map((x) => x.uri))
);
} else {
const existingInterfaceImplementations = addedInterfacesHashMap.get(
interfaceUri
) as Set<string>;

// Get implementations to add to existing set of implementations
const newImplementationUris = interfaceImplementations.implementations.map(
(x) => x.uri
);

// Add new implementations to existing set
newImplementationUris.forEach(
existingInterfaceImplementations.add,
existingInterfaceImplementations
);
}
}

// Collection of unique interfaces with implementations merged
const sanitizedInterfaces: InterfaceImplementations<Uri>[] = [];

// Go through the unique hash map of interfaces and implementations and add them to the sanitized interfaces
for (const [
interfaceUri,
implementationSet,
] of addedInterfacesHashMap.entries()) {
sanitizedInterfaces.push({
interface: new Uri(interfaceUri),
implementations: [...implementationSet].map((x) => new Uri(x)),
});
}

this._config.interfaces = sanitizedInterfaces;
}

@Tracer.traceMethod("Web3ApiClient: validateConfig")
private _validateConfig(): void {
// Require plugins to use non-interface URIs
Expand Down
73 changes: 70 additions & 3 deletions packages/js/client/src/__tests__/Web3ApiClient.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2810,7 +2810,10 @@ enum Logger_LogLevel @imported(
it("e2e Interface invoke method", async () => {
const interfaceUri = "w3://ens/interface.eth";
// Build interface polywrapper
await runCLI({ args: ["build"], cwd: `${GetPathToTestApis()}/interface-invoke/test-interface`});
await runCLI({
args: ["build"],
cwd: `${GetPathToTestApis()}/interface-invoke/test-interface`,
});

const implementationApi = await buildAndDeployApi(
`${GetPathToTestApis()}/interface-invoke/test-implementation`,
Expand All @@ -2824,7 +2827,7 @@ enum Logger_LogLevel @imported(
{
interface: interfaceUri,
implementations: [implementationUri],
}
},
],
});

Expand Down Expand Up @@ -2864,12 +2867,76 @@ enum Logger_LogLevel @imported(
mutationMethod(
arg: 1
)
}`
}`,
});

expect(mutation.errors).toBeFalsy();
expect(mutation.data).toBeTruthy();
expect(mutation.data?.mutationMethod).toBe(1);
});

it("merge user-defined interface implementations with each other", async () => {
const interfaceUri = "w3://ens/interface.eth";
const implementationUri1 = "w3://ens/implementation1.eth";
const implementationUri2 = "w3://ens/implementation2.eth";

const client = new Web3ApiClient({
interfaces: [
{
interface: interfaceUri,
implementations: [implementationUri1],
},
{
interface: interfaceUri,
implementations: [implementationUri2],
},
],
});

const interfaces = client
.getInterfaces()
.filter((x) => x.interface.uri === interfaceUri);
expect(interfaces.length).toEqual(1);

const implementationUris = interfaces[0].implementations;

expect(implementationUris).toEqual([
new Uri(implementationUri1),
new Uri(implementationUri2),
]);
});

it("merge user-defined interface implementations with defaults", async () => {
const interfaceUri = coreInterfaceUris.uriResolver.uri;
const implementationUri1 = "w3://ens/implementation1.eth";
const implementationUri2 = "w3://ens/implementation2.eth";

const client = new Web3ApiClient({
interfaces: [
{
interface: interfaceUri,
implementations: [implementationUri1],
},
{
interface: interfaceUri,
implementations: [implementationUri2],
},
],
});

const interfaces = client
.getInterfaces()
.filter((x) => x.interface.uri === interfaceUri);
expect(interfaces.length).toEqual(1);

const implementationUris = interfaces[0].implementations;

expect(implementationUris).toEqual([
new Uri(implementationUri1),
new Uri(implementationUri2),
...getDefaultClientConfig().interfaces.find(
(x) => x.interface.uri === interfaceUri
)!.implementations,
]);
});
});
Loading