feat: Support instance context [fixes DXJ-541] (#392)

* Support context

* Update doc

* Refactor

* Cover by doc

* Fix lint
This commit is contained in:
Akim 2023-12-06 22:03:20 +07:00 committed by GitHub
parent 44eb1493b3
commit 1578b791ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 220 additions and 325 deletions

View File

@ -164,6 +164,18 @@ localStorage.debug = "fluence:*";
In Chromium-based web browsers (e.g. Brave, Chrome, and Electron), the JavaScript console will be default—only to show In Chromium-based web browsers (e.g. Brave, Chrome, and Electron), the JavaScript console will be default—only to show
messages logged by debug if the "Verbose" log level is enabled. messages logged by debug if the "Verbose" log level is enabled.
## Low level usage
JS client also has an API for low level interaction with AVM and Marine JS.
It could be handy in advanced scenarios when a user fetches AIR dynamically or generates AIR without default Aqua compiler.
`callAquaFunction` Allows to call aqua function without schema.
`registerService` Gives an ability to register service without schema. Passed `service` could be
- Plain object. In this case all function properties will be registered as AIR service functions.
- Class instance. All class methods without inherited ones will be registered as AIR service functions.
## Development ## Development
To hack on the Fluence JS Client itself, please refer to the [development page](./DEVELOPING.md). To hack on the Fluence JS Client itself, please refer to the [development page](./DEVELOPING.md).

View File

@ -0,0 +1,16 @@
service Calc("calc"):
add(n: f32)
subtract(n: f32)
multiply(n: f32)
divide(n: f32)
reset()
getResult() -> f32
func demoCalc() -> f32:
Calc.add(10)
Calc.multiply(5)
Calc.subtract(8)
Calc.divide(6)
res <- Calc.getResult()
<- res

View File

@ -0,0 +1,84 @@
/**
* Copyright 2023 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { fileURLToPath } from "url";
import { compileFromPath } from "@fluencelabs/aqua-api";
import { ServiceDef } from "@fluencelabs/interfaces";
import { describe, expect, it } from "vitest";
import { v5_registerService } from "./api.js";
import { callAquaFunction } from "./compilerSupport/callFunction.js";
import { withPeer } from "./util/testUtils.js";
class CalcParent {
protected _state: number = 0;
add(n: number) {
this._state += n;
}
subtract(n: number) {
this._state -= n;
}
}
class Calc extends CalcParent {
multiply(n: number) {
this._state *= n;
}
divide(n: number) {
this._state /= n;
}
reset() {
this._state = 0;
}
getResult() {
return this._state;
}
}
describe("User API methods", () => {
it("registers user class service and calls own and inherited methods correctly", async () => {
await withPeer(async (peer) => {
const calcService: Record<never, unknown> = new Calc();
const { functions, services } = await compileFromPath({
filePath: fileURLToPath(new URL("../aqua/calc.aqua", import.meta.url)),
});
const typedServices: Record<string, ServiceDef> = services;
const { script } = functions["demoCalc"];
v5_registerService([peer, "calc", calcService], {
defaultServiceId: "calc",
functions: typedServices["Calc"].functions,
});
const res = await callAquaFunction({
args: {},
peer,
script,
});
expect(res).toBe(7);
});
});
});

View File

@ -202,10 +202,16 @@ export const v5_registerService = (
// Schema for every function in service // Schema for every function in service
const serviceSchema = def.functions.tag === "nil" ? {} : def.functions.fields; const serviceSchema = def.functions.tag === "nil" ? {} : def.functions.fields;
// Wrapping service impl to convert their args ts -> aqua and backwards // Wrapping service functions, selecting only those listed in schema, to convert their args js -> aqua and backwards
const wrappedServiceImpl = Object.fromEntries( const wrappedServiceImpl = Object.fromEntries(
Object.entries(serviceImpl).map(([name, func]) => { Object.keys(serviceSchema).map((schemaKey) => {
return [name, wrapJsFunction(func, serviceSchema[name])]; return [
schemaKey,
wrapJsFunction(
serviceImpl[schemaKey].bind(serviceImpl),
serviceSchema[schemaKey],
),
] as const;
}), }),
); );

View File

@ -46,7 +46,7 @@ const log = logger("aqua");
export type CallAquaFunctionArgs = { export type CallAquaFunctionArgs = {
script: string; script: string;
config: CallAquaFunctionConfig | undefined; config?: CallAquaFunctionConfig | undefined;
peer: FluencePeer; peer: FluencePeer;
args: { [key: string]: JSONValue | ArgCallbackFunction }; args: { [key: string]: JSONValue | ArgCallbackFunction };
}; };

View File

@ -28,27 +28,22 @@ interface RegisterServiceArgs {
service: ServiceImpl; service: ServiceImpl;
} }
// This function iterates on plain object or class instance functions ignoring inherited functions and prototype chain.
const findAllPossibleRegisteredServiceFunctions = ( const findAllPossibleRegisteredServiceFunctions = (
service: ServiceImpl, service: ServiceImpl,
): Set<string> => { ): Array<string> => {
let prototype: Record<string, unknown> = service; // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
const serviceMethods = new Set<string>(); const prototype = Object.getPrototypeOf(service) as ServiceImpl;
do { const isClassInstance = prototype.constructor !== Object;
Object.getOwnPropertyNames(prototype)
.filter((prop) => {
return typeof prototype[prop] === "function" && prop !== "constructor";
})
.forEach((prop) => {
return serviceMethods.add(prop);
});
// coercing 'any' type to 'Record' bcs object prototype is actually an object if (isClassInstance) {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions service = prototype;
prototype = Object.getPrototypeOf(prototype) as Record<string, unknown>; }
} while (prototype.constructor !== Object);
return serviceMethods; return Object.getOwnPropertyNames(service).filter((prop) => {
return typeof service[prop] === "function" && prop !== "constructor";
});
}; };
export const registerService = ({ export const registerService = ({

View File

@ -14,13 +14,15 @@
* limitations under the License. * limitations under the License.
*/ */
import { it, describe, expect, beforeEach, afterEach } from "vitest"; import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { DEFAULT_CONFIG, FluencePeer } from "../../jsPeer/FluencePeer.js"; import { DEFAULT_CONFIG, FluencePeer } from "../../jsPeer/FluencePeer.js";
import { ResultCodes } from "../../jsServiceHost/interfaces.js"; import { ResultCodes } from "../../jsServiceHost/interfaces.js";
import { KeyPair } from "../../keypair/index.js"; import { KeyPair } from "../../keypair/index.js";
import { loadMarineDeps } from "../../marine/loader.js";
import { MarineBackgroundRunner } from "../../marine/worker/index.js";
import { EphemeralNetworkClient } from "../client.js"; import { EphemeralNetworkClient } from "../client.js";
import { EphemeralNetwork, defaultConfig } from "../network.js"; import { defaultConfig, EphemeralNetwork } from "../network.js";
let en: EphemeralNetwork; let en: EphemeralNetwork;
let client: FluencePeer; let client: FluencePeer;
@ -33,7 +35,11 @@ describe.skip("Ephemeral networks tests", () => {
await en.up(); await en.up();
const kp = await KeyPair.randomEd25519(); const kp = await KeyPair.randomEd25519();
client = new EphemeralNetworkClient(DEFAULT_CONFIG, kp, en, relay);
const marineDeps = await loadMarineDeps("/");
const marine = new MarineBackgroundRunner(...marineDeps);
client = new EphemeralNetworkClient(DEFAULT_CONFIG, kp, marine, en, relay);
await client.start(); await client.start();
}); });

View File

@ -15,13 +15,11 @@
*/ */
import { PeerIdB58 } from "@fluencelabs/interfaces"; import { PeerIdB58 } from "@fluencelabs/interfaces";
import { fetchResource } from "@fluencelabs/js-client-isomorphic/fetcher";
import { getWorker } from "@fluencelabs/js-client-isomorphic/worker-resolver";
import { FluencePeer, PeerConfig } from "../jsPeer/FluencePeer.js"; import { FluencePeer, PeerConfig } from "../jsPeer/FluencePeer.js";
import { JsServiceHost } from "../jsServiceHost/JsServiceHost.js"; import { JsServiceHost } from "../jsServiceHost/JsServiceHost.js";
import { KeyPair } from "../keypair/index.js"; import { KeyPair } from "../keypair/index.js";
import { MarineBackgroundRunner } from "../marine/worker/index.js"; import { IMarineHost } from "../marine/interfaces.js";
import { EphemeralNetwork } from "./network.js"; import { EphemeralNetwork } from "./network.js";
@ -32,63 +30,12 @@ export class EphemeralNetworkClient extends FluencePeer {
constructor( constructor(
config: PeerConfig, config: PeerConfig,
keyPair: KeyPair, keyPair: KeyPair,
marine: IMarineHost,
network: EphemeralNetwork, network: EphemeralNetwork,
relay: PeerIdB58, relay: PeerIdB58,
) { ) {
const conn = network.getRelayConnection(keyPair.getPeerId(), relay); const conn = network.getRelayConnection(keyPair.getPeerId(), relay);
let marineJsWasm: ArrayBuffer;
let avmWasm: ArrayBuffer;
const marine = new MarineBackgroundRunner(
{
async getValue() {
// TODO: load worker in parallel with avm and marine, test that it works
return getWorker("@fluencelabs/marine-worker", "/");
},
start() {
return Promise.resolve(undefined);
},
stop() {
return Promise.resolve(undefined);
},
},
{
getValue() {
return marineJsWasm;
},
async start(): Promise<void> {
marineJsWasm = await fetchResource(
"@fluencelabs/marine-js",
"/dist/marine-js.wasm",
"/",
).then((res) => {
return res.arrayBuffer();
});
},
stop(): Promise<void> {
return Promise.resolve(undefined);
},
},
{
getValue() {
return avmWasm;
},
async start(): Promise<void> {
avmWasm = await fetchResource(
"@fluencelabs/avm",
"/dist/avm.wasm",
"/",
).then((res) => {
return res.arrayBuffer();
});
},
stop(): Promise<void> {
return Promise.resolve(undefined);
},
},
);
super(config, keyPair, marine, new JsServiceHost(), conn); super(config, keyPair, marine, new JsServiceHost(), conn);
} }
} }

View File

@ -15,8 +15,6 @@
*/ */
import { PeerIdB58 } from "@fluencelabs/interfaces"; import { PeerIdB58 } from "@fluencelabs/interfaces";
import { fetchResource } from "@fluencelabs/js-client-isomorphic/fetcher";
import { getWorker } from "@fluencelabs/js-client-isomorphic/worker-resolver";
import { Subject } from "rxjs"; import { Subject } from "rxjs";
import { IConnection } from "../connection/interfaces.js"; import { IConnection } from "../connection/interfaces.js";
@ -24,6 +22,7 @@ import { DEFAULT_CONFIG, FluencePeer } from "../jsPeer/FluencePeer.js";
import { JsServiceHost } from "../jsServiceHost/JsServiceHost.js"; import { JsServiceHost } from "../jsServiceHost/JsServiceHost.js";
import { fromBase64Sk, KeyPair } from "../keypair/index.js"; import { fromBase64Sk, KeyPair } from "../keypair/index.js";
import { IMarineHost } from "../marine/interfaces.js"; import { IMarineHost } from "../marine/interfaces.js";
import { loadMarineDeps } from "../marine/loader.js";
import { MarineBackgroundRunner } from "../marine/worker/index.js"; import { MarineBackgroundRunner } from "../marine/worker/index.js";
import { Particle } from "../particle/Particle.js"; import { Particle } from "../particle/Particle.js";
import { logger } from "../util/logger.js"; import { logger } from "../util/logger.js";
@ -233,55 +232,8 @@ export class EphemeralNetwork {
const promises = this.config.peers.map(async (x) => { const promises = this.config.peers.map(async (x) => {
const kp = await fromBase64Sk(x.sk); const kp = await fromBase64Sk(x.sk);
const [marineJsWasm, avmWasm] = await Promise.all([ const marineDeps = await loadMarineDeps("/");
fetchResource( const marine = new MarineBackgroundRunner(...marineDeps);
"@fluencelabs/marine-js",
"/dist/marine-js.wasm",
"/",
).then((res) => {
return res.arrayBuffer();
}),
fetchResource("@fluencelabs/avm", "/dist/avm.wasm", "/").then((res) => {
return res.arrayBuffer();
}),
]);
const marine = new MarineBackgroundRunner(
{
async getValue() {
// TODO: load worker in parallel with avm and marine, test that it works
return getWorker("@fluencelabs/marine-worker", "/");
},
start() {
return Promise.resolve(undefined);
},
stop() {
return Promise.resolve(undefined);
},
},
{
getValue() {
return marineJsWasm;
},
start(): Promise<void> {
return Promise.resolve(undefined);
},
stop(): Promise<void> {
return Promise.resolve(undefined);
},
},
{
getValue() {
return avmWasm;
},
start(): Promise<void> {
return Promise.resolve(undefined);
},
stop(): Promise<void> {
return Promise.resolve(undefined);
},
},
);
const peerId = kp.getPeerId(); const peerId = kp.getPeerId();

View File

@ -14,8 +14,6 @@
* limitations under the License. * limitations under the License.
*/ */
import { fetchResource } from "@fluencelabs/js-client-isomorphic/fetcher";
import { getWorker } from "@fluencelabs/js-client-isomorphic/worker-resolver";
import { ZodError } from "zod"; import { ZodError } from "zod";
import { ClientPeer, makeClientPeerConfig } from "./clientPeer/ClientPeer.js"; import { ClientPeer, makeClientPeerConfig } from "./clientPeer/ClientPeer.js";
@ -28,6 +26,7 @@ import {
} from "./clientPeer/types.js"; } from "./clientPeer/types.js";
import { callAquaFunction } from "./compilerSupport/callFunction.js"; import { callAquaFunction } from "./compilerSupport/callFunction.js";
import { registerService } from "./compilerSupport/registerService.js"; import { registerService } from "./compilerSupport/registerService.js";
import { loadMarineDeps } from "./marine/loader.js";
import { MarineBackgroundRunner } from "./marine/worker/index.js"; import { MarineBackgroundRunner } from "./marine/worker/index.js";
const DEFAULT_CDN_URL = "https://unpkg.com"; const DEFAULT_CDN_URL = "https://unpkg.com";
@ -47,55 +46,8 @@ const createClient = async (
const CDNUrl = config.CDNUrl ?? DEFAULT_CDN_URL; const CDNUrl = config.CDNUrl ?? DEFAULT_CDN_URL;
const [marineJsWasm, avmWasm] = await Promise.all([ const marineDeps = await loadMarineDeps(CDNUrl);
fetchResource( const marine = new MarineBackgroundRunner(...marineDeps);
"@fluencelabs/marine-js",
"/dist/marine-js.wasm",
CDNUrl,
).then((res) => {
return res.arrayBuffer();
}),
fetchResource("@fluencelabs/avm", "/dist/avm.wasm", CDNUrl).then((res) => {
return res.arrayBuffer();
}),
]);
const marine = new MarineBackgroundRunner(
{
async getValue() {
// TODO: load worker in parallel with avm and marine, test that it works
return getWorker("@fluencelabs/marine-worker", CDNUrl);
},
start() {
return Promise.resolve(undefined);
},
stop() {
return Promise.resolve(undefined);
},
},
{
getValue() {
return marineJsWasm;
},
start(): Promise<void> {
return Promise.resolve(undefined);
},
stop(): Promise<void> {
return Promise.resolve(undefined);
},
},
{
getValue() {
return avmWasm;
},
start(): Promise<void> {
return Promise.resolve(undefined);
},
stop(): Promise<void> {
return Promise.resolve(undefined);
},
},
);
const { keyPair, peerConfig, relayConfig } = await makeClientPeerConfig( const { keyPair, peerConfig, relayConfig } = await makeClientPeerConfig(
relay, relay,

View File

@ -16,7 +16,6 @@
import { JSONObject, JSONValue, JSONArray } from "@fluencelabs/interfaces"; import { JSONObject, JSONValue, JSONArray } from "@fluencelabs/interfaces";
import { CallParameters } from "@fluencelabs/marine-worker"; import { CallParameters } from "@fluencelabs/marine-worker";
import type { Worker as WorkerImplementation } from "@fluencelabs/threads/master";
import { IStartable } from "../util/commonTypes.js"; import { IStartable } from "../util/commonTypes.js";
@ -52,24 +51,3 @@ export interface IMarineHost extends IStartable {
callParams?: CallParameters, callParams?: CallParameters,
): Promise<JSONValue>; ): Promise<JSONValue>;
} }
/**
* Interface for something which can hold a value
*/
export interface IValueLoader<T> {
getValue(): T;
}
/**
* Interface for something which can load wasm files
*/
export interface IWasmLoader
extends IValueLoader<ArrayBuffer | SharedArrayBuffer>,
IStartable {}
/**
* Interface for something which can thread.js based worker
*/
export interface IWorkerLoader
extends IValueLoader<WorkerImplementation | Promise<WorkerImplementation>>,
IStartable {}

View File

@ -0,0 +1,47 @@
/**
* Copyright 2023 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { fetchResource } from "@fluencelabs/js-client-isomorphic/fetcher";
import { getWorker } from "@fluencelabs/js-client-isomorphic/worker-resolver";
import { Worker } from "@fluencelabs/threads/master";
type StrategyReturnType = [
marineJsWasm: ArrayBuffer,
avmWasm: ArrayBuffer,
worker: Worker,
];
export const loadMarineDeps = async (
CDNUrl: string,
): Promise<StrategyReturnType> => {
const [marineJsWasm, avmWasm] = await Promise.all([
fetchResource(
"@fluencelabs/marine-js",
"/dist/marine-js.wasm",
CDNUrl,
).then((res) => {
return res.arrayBuffer();
}),
fetchResource("@fluencelabs/avm", "/dist/avm.wasm", CDNUrl).then((res) => {
return res.arrayBuffer();
}),
]);
// TODO: load worker in parallel with avm and marine, test that it works
const worker = await getWorker("@fluencelabs/marine-worker", CDNUrl);
return [marineJsWasm, avmWasm, worker];
};

View File

@ -21,10 +21,15 @@ import type {
JSONValueNonNullable, JSONValueNonNullable,
CallParameters, CallParameters,
} from "@fluencelabs/marine-worker"; } from "@fluencelabs/marine-worker";
import { ModuleThread, Thread, spawn } from "@fluencelabs/threads/master"; import {
ModuleThread,
Thread,
spawn,
Worker,
} from "@fluencelabs/threads/master";
import { MarineLogger, marineLogger } from "../../util/logger.js"; import { MarineLogger, marineLogger } from "../../util/logger.js";
import { IMarineHost, IWasmLoader, IWorkerLoader } from "../interfaces.js"; import { IMarineHost } from "../interfaces.js";
export class MarineBackgroundRunner implements IMarineHost { export class MarineBackgroundRunner implements IMarineHost {
private workerThread?: ModuleThread<MarineBackgroundInterface>; private workerThread?: ModuleThread<MarineBackgroundInterface>;
@ -32,9 +37,9 @@ export class MarineBackgroundRunner implements IMarineHost {
private loggers = new Map<string, MarineLogger>(); private loggers = new Map<string, MarineLogger>();
constructor( constructor(
private workerLoader: IWorkerLoader, private marineJsWasm: ArrayBuffer,
private controlModuleLoader: IWasmLoader, private avmWasm: ArrayBuffer,
private avmWasmLoader: IWasmLoader, private worker: Worker,
) {} ) {}
async hasService(serviceId: string) { async hasService(serviceId: string) {
@ -58,16 +63,8 @@ export class MarineBackgroundRunner implements IMarineHost {
throw new Error("Worker thread already initialized"); throw new Error("Worker thread already initialized");
} }
await this.controlModuleLoader.start();
const wasm = this.controlModuleLoader.getValue();
await this.avmWasmLoader.start();
await this.workerLoader.start();
const worker = await this.workerLoader.getValue();
const workerThread: ModuleThread<MarineBackgroundInterface> = const workerThread: ModuleThread<MarineBackgroundInterface> =
await spawn<MarineBackgroundInterface>(worker); await spawn<MarineBackgroundInterface>(this.worker);
const logfn: LogFunction = (message) => { const logfn: LogFunction = (message) => {
const serviceLogger = this.loggers.get(message.service); const serviceLogger = this.loggers.get(message.service);
@ -80,9 +77,9 @@ export class MarineBackgroundRunner implements IMarineHost {
}; };
workerThread.onLogMessage().subscribe(logfn); workerThread.onLogMessage().subscribe(logfn);
await workerThread.init(wasm); await workerThread.init(this.marineJsWasm);
this.workerThread = workerThread; this.workerThread = workerThread;
await this.createService(this.avmWasmLoader.getValue(), "avm"); await this.createService(this.avmWasm, "avm");
} }
async createService( async createService(

View File

@ -23,8 +23,6 @@ import {
JSONValue, JSONValue,
ServiceDef, ServiceDef,
} from "@fluencelabs/interfaces"; } from "@fluencelabs/interfaces";
import { fetchResource } from "@fluencelabs/js-client-isomorphic/fetcher";
import { getWorker } from "@fluencelabs/js-client-isomorphic/worker-resolver";
import { Subject, Subscribable } from "rxjs"; import { Subject, Subscribable } from "rxjs";
import { ClientPeer, makeClientPeerConfig } from "../clientPeer/ClientPeer.js"; import { ClientPeer, makeClientPeerConfig } from "../clientPeer/ClientPeer.js";
@ -40,6 +38,8 @@ import {
import { JsServiceHost } from "../jsServiceHost/JsServiceHost.js"; import { JsServiceHost } from "../jsServiceHost/JsServiceHost.js";
import { WrapFnIntoServiceCall } from "../jsServiceHost/serviceUtils.js"; import { WrapFnIntoServiceCall } from "../jsServiceHost/serviceUtils.js";
import { KeyPair } from "../keypair/index.js"; import { KeyPair } from "../keypair/index.js";
import { IMarineHost } from "../marine/interfaces.js";
import { loadMarineDeps } from "../marine/loader.js";
import { MarineBackgroundRunner } from "../marine/worker/index.js"; import { MarineBackgroundRunner } from "../marine/worker/index.js";
import { Particle } from "../particle/Particle.js"; import { Particle } from "../particle/Particle.js";
@ -146,61 +146,9 @@ class NoopConnection implements IConnection {
} }
export class TestPeer extends FluencePeer { export class TestPeer extends FluencePeer {
constructor(keyPair: KeyPair, connection: IConnection) { constructor(keyPair: KeyPair, connection: IConnection, marine: IMarineHost) {
const jsHost = new JsServiceHost(); const jsHost = new JsServiceHost();
let marineJsWasm: ArrayBuffer;
let avmWasm: ArrayBuffer;
const marine = new MarineBackgroundRunner(
{
async getValue() {
// TODO: load worker in parallel with avm and marine, test that it works
return getWorker("@fluencelabs/marine-worker", "/");
},
start() {
return Promise.resolve(undefined);
},
stop() {
return Promise.resolve(undefined);
},
},
{
getValue() {
return marineJsWasm;
},
async start(): Promise<void> {
marineJsWasm = await fetchResource(
"@fluencelabs/marine-js",
"/dist/marine-js.wasm",
"/",
).then((res) => {
return res.arrayBuffer();
});
},
stop(): Promise<void> {
return Promise.resolve(undefined);
},
},
{
getValue() {
return avmWasm;
},
async start(): Promise<void> {
avmWasm = await fetchResource(
"@fluencelabs/avm",
"/dist/avm.wasm",
"/",
).then((res) => {
return res.arrayBuffer();
});
},
stop(): Promise<void> {
return Promise.resolve(undefined);
},
},
);
super(DEFAULT_CONFIG, keyPair, marine, jsHost, connection); super(DEFAULT_CONFIG, keyPair, marine, jsHost, connection);
} }
} }
@ -208,7 +156,11 @@ export class TestPeer extends FluencePeer {
export const mkTestPeer = async () => { export const mkTestPeer = async () => {
const kp = await KeyPair.randomEd25519(); const kp = await KeyPair.randomEd25519();
const conn = new NoopConnection(); const conn = new NoopConnection();
return new TestPeer(kp, conn);
const marineDeps = await loadMarineDeps("/");
const marine = new MarineBackgroundRunner(...marineDeps);
return new TestPeer(kp, conn, marine);
}; };
export const withPeer = async (action: (p: FluencePeer) => Promise<void>) => { export const withPeer = async (action: (p: FluencePeer) => Promise<void>) => {
@ -232,57 +184,8 @@ export const withClient = async (
config, config,
); );
let marineJsWasm: ArrayBuffer; const marineDeps = await loadMarineDeps("/");
let avmWasm: ArrayBuffer; const marine = new MarineBackgroundRunner(...marineDeps);
const marine = new MarineBackgroundRunner(
{
async getValue() {
// TODO: load worker in parallel with avm and marine, test that it works
return getWorker("@fluencelabs/marine-worker", "/");
},
start() {
return Promise.resolve(undefined);
},
stop() {
return Promise.resolve(undefined);
},
},
{
getValue() {
return marineJsWasm;
},
async start(): Promise<void> {
marineJsWasm = await fetchResource(
"@fluencelabs/marine-js",
"/dist/marine-js.wasm",
"/",
).then((res) => {
return res.arrayBuffer();
});
},
stop(): Promise<void> {
return Promise.resolve(undefined);
},
},
{
getValue() {
return avmWasm;
},
async start(): Promise<void> {
avmWasm = await fetchResource(
"@fluencelabs/avm",
"/dist/avm.wasm",
"/",
).then((res) => {
return res.arrayBuffer();
});
},
stop(): Promise<void> {
return Promise.resolve(undefined);
},
},
);
const client = new ClientPeer(peerConfig, relayConfig, keyPair, marine); const client = new ClientPeer(peerConfig, relayConfig, keyPair, marine);