Skip to content

Commit

Permalink
Merge pull request #334 from Web3-API/prealpha-dev
Browse files Browse the repository at this point in the history
Prep 0.0.1-prealpha.22
  • Loading branch information
dOrgJelli authored May 13, 2021
2 parents 76871c4 + 346a2ad commit e4ec916
Show file tree
Hide file tree
Showing 28 changed files with 1,954 additions and 1,046 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
# Web3API 0.0.1-prealpha.22
## Feature
* `@web3api/tracing-js`: The `tracing-js` package uses the [OpenTelemetry Standard](https://opentelemetry.io/) for logging trace events. This enables things like:
* Benchmark Timings
* Input Argument + Output Result Logging
* In-Depth Exception Tracing
* `@web3api/core-js`: All functions are now traceable.
* `@web3api/client-js`: All functions are now traceable.

# Web3API 0.0.1-prealpha.21
## Feature
* Sharing code & types between `query` and `mutation` modules is now possible.
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.0.1-prealpha.21
0.0.1-prealpha.22
1 change: 1 addition & 0 deletions packages/js/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"@web3api/ipfs-plugin-js": "0.0.1-prealpha.21",
"@web3api/logger-plugin-js": "0.0.1-prealpha.21",
"@web3api/schema-parse": "0.0.1-prealpha.21",
"@web3api/tracing-js": "0.0.1-prealpha.21",
"graphql": "15.5.0",
"js-yaml": "3.14.0",
"web-worker": "1.0.0"
Expand Down
236 changes: 144 additions & 92 deletions packages/js/client/src/Web3ApiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ import {
Manifest,
sanitizeUriRedirects,
} from "@web3api/core-js";
import { Tracer } from "@web3api/tracing-js";

export interface ClientConfig<TUri = string> {
redirects?: UriRedirect<TUri>[];
tracingEnabled?: boolean;
}

export class Web3ApiClient implements Client {
Expand All @@ -30,28 +32,54 @@ export class Web3ApiClient implements Client {
// and handle cases where the are multiple jumps. For exmaple, if
// A => B => C, then the cache should have A => C, and B => C.
private _apiCache: ApiCache = new Map<string, Api>();
private _config: ClientConfig<Uri>;
private _config: ClientConfig<Uri> = {};

constructor(config?: ClientConfig) {
if (config) {
this._config = {
...config,
redirects: config.redirects
? sanitizeUriRedirects(config.redirects)
: [],
};
} else {
this._config = {
redirects: [],
};
try {
if (!config) {
this._config = {
redirects: [],
tracingEnabled: false,
};
}

this.tracingEnabled(!!config?.tracingEnabled);

Tracer.startSpan("Web3ApiClient: constructor");

if (config) {
this._config = {
...config,
redirects: config.redirects
? sanitizeUriRedirects(config.redirects)
: [],
};
}

if (!this._config.redirects) {
this._config.redirects = [];
}

// Add all default redirects
this._config.redirects.push(...getDefaultRedirects());

Tracer.setAttribute("config", this._config);
} catch (error) {
Tracer.recordException(error);
throw error;
} finally {
Tracer.endSpan();
}
}

if (!this._config.redirects) {
this._config.redirects = [];
public tracingEnabled(enable: boolean): void {
if (enable) {
Tracer.enableTracing("Web3ApiClient");
} else {
Tracer.disableTracing();
}

// Add all default redirects (IPFS, ETH, ENS)
this._config.redirects.push(...getDefaultRedirects());
this._config.tracingEnabled = enable;
}

public redirects(): readonly UriRedirect<Uri>[] {
Expand All @@ -64,103 +92,127 @@ export class Web3ApiClient implements Client {
>(
options: QueryApiOptions<TVariables, string>
): Promise<QueryApiResult<TData>> {
try {
const { uri, query, variables } = options;

// Convert the query string into a query document
const queryDocument =
typeof query === "string" ? createQueryDocument(query) : query;

// Parse the query to understand what's being invoked
const queryInvocations = parseQuery(
new Uri(uri),
queryDocument,
variables
);

// Execute all invocations in parallel
const parallelInvocations: Promise<{
name: string;
result: InvokeApiResult<unknown>;
}>[] = [];

for (const invocationName of Object.keys(queryInvocations)) {
parallelInvocations.push(
this.invoke({
...queryInvocations[invocationName],
uri: queryInvocations[invocationName].uri.uri,
decode: true,
}).then((result) => ({
name: invocationName,
result,
}))
const run = Tracer.traceFunc(
"Web3ApiClient: query",
async (
options: QueryApiOptions<TVariables, string>
): Promise<QueryApiResult<TData>> => {
const { uri, query, variables } = options;

// Convert the query string into a query document
const queryDocument =
typeof query === "string" ? createQueryDocument(query) : query;

// Parse the query to understand what's being invoked
const queryInvocations = parseQuery(
new Uri(uri),
queryDocument,
variables
);
}

// Await the invocations
const invocationResults = await Promise.all(parallelInvocations);
// Execute all invocations in parallel
const parallelInvocations: Promise<{
name: string;
result: InvokeApiResult<unknown>;
}>[] = [];

for (const invocationName of Object.keys(queryInvocations)) {
parallelInvocations.push(
this.invoke({
...queryInvocations[invocationName],
uri: queryInvocations[invocationName].uri.uri,
decode: true,
}).then((result) => ({
name: invocationName,
result,
}))
);
}

// Await the invocations
const invocationResults = await Promise.all(parallelInvocations);

// Aggregate all invocation results
const data: Record<string, unknown> = {};
const errors: Error[] = [];
Tracer.addEvent("invocationResults", invocationResults);

for (const invocation of invocationResults) {
data[invocation.name] = invocation.result.data;
if (invocation.result.error) {
errors.push(invocation.result.error);
// Aggregate all invocation results
const data: Record<string, unknown> = {};
const errors: Error[] = [];

for (const invocation of invocationResults) {
data[invocation.name] = invocation.result.data;
if (invocation.result.error) {
errors.push(invocation.result.error);
}
}

return {
data: data as TData,
errors: errors.length === 0 ? undefined : errors,
};
}
);

return {
data: data as TData,
errors: errors.length === 0 ? undefined : errors,
};
} catch (error) {
return await run(options).catch((error) => {
if (error.length) {
return { errors: error };
} else {
return { errors: [error] };
}
}
});
}

public async invoke<TData = unknown>(
options: InvokeApiOptions<string>
): Promise<InvokeApiResult<TData>> {
try {
const uri = new Uri(options.uri);
const api = await this.loadWeb3Api(uri);
return (await api.invoke(
{
...options,
uri,
},
this
)) as TData;
} catch (error) {
return { error: error };
}
const run = Tracer.traceFunc(
"Web3ApiClient: invoke",
async (
options: InvokeApiOptions<string>
): Promise<InvokeApiResult<TData>> => {
const uri = new Uri(options.uri);
const api = await this.loadWeb3Api(uri);

const result = (await api.invoke(
{
...options,
uri,
},
this
)) as TData;

return result;
}
);

return run(options);
}

public async loadWeb3Api(uri: Uri): Promise<Api> {
let api = this._apiCache.get(uri.uri);

if (!api) {
api = await resolveUri(
uri,
this,
(uri: Uri, plugin: PluginPackage) => new PluginWeb3Api(uri, plugin),
(uri: Uri, manifest: Manifest, apiResolver: Uri) =>
new WasmWeb3Api(uri, manifest, apiResolver)
);

if (!api) {
throw Error(`Unable to resolve Web3API at uri: ${uri}`);
}
const run = Tracer.traceFunc(
"Web3ApiClient: loadWeb3Api",
async (uri: Uri): Promise<Api> => {
let api = this._apiCache.get(uri.uri);

if (!api) {
api = await resolveUri(
uri,
this,
(uri: Uri, plugin: PluginPackage) => new PluginWeb3Api(uri, plugin),
(uri: Uri, manifest: Manifest, apiResolver: Uri) =>
new WasmWeb3Api(uri, manifest, apiResolver)
);

if (!api) {
throw Error(`Unable to resolve Web3API at uri: ${uri}`);
}

this._apiCache.set(uri.uri, api);
}

this._apiCache.set(uri.uri, api);
}
return api;
}
);

return api;
return run(uri);
}
}
Loading

0 comments on commit e4ec916

Please sign in to comment.