2023-02-13 17:41:35 +03:00
|
|
|
/*
|
|
|
|
* Copyright 2022 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 { MarineService } from '@fluencelabs/marine-js/dist/MarineService';
|
2023-08-09 15:38:40 +03:00
|
|
|
import type { Env, MarineModuleConfig, MarineServiceConfig, ModuleDescriptor } from '@fluencelabs/marine-js/dist/config'
|
|
|
|
import type { JSONArray, JSONObject, LogMessage, CallParameters } from '@fluencelabs/marine-js/dist/types';
|
2023-08-25 00:15:49 +07:00
|
|
|
import { Observable, Subject } from 'observable-fns';
|
|
|
|
// @ts-ignore no types provided for package
|
2023-09-29 16:23:06 +07:00
|
|
|
import { expose } from 'threads/worker';
|
2023-02-13 17:41:35 +03:00
|
|
|
|
2023-08-09 15:38:40 +03:00
|
|
|
const createSimpleModuleDescriptor = (name: string, envs?: Env): ModuleDescriptor => {
|
|
|
|
return {
|
|
|
|
import_name: name,
|
|
|
|
config: {
|
|
|
|
logger_enabled: true,
|
|
|
|
logging_mask: 0,
|
|
|
|
wasi: {
|
|
|
|
envs: {...envs},
|
|
|
|
preopened_files: new Set(),
|
|
|
|
mapped_dirs: new Map,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const createSimpleMarineService = (name: string, env? : Env): MarineServiceConfig => {
|
|
|
|
return {
|
|
|
|
modules_config: [createSimpleModuleDescriptor(name, env)],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-25 00:15:49 +07:00
|
|
|
let marineServices = new Map<string, MarineService>();
|
|
|
|
let controlModule: WebAssembly.Module | undefined;
|
2023-02-13 17:41:35 +03:00
|
|
|
const onLogMessage = new Subject<LogMessage>();
|
|
|
|
|
|
|
|
const toExpose = {
|
2023-08-25 00:15:49 +07:00
|
|
|
init: async (controlModuleWasm: ArrayBuffer | SharedArrayBuffer) => {
|
|
|
|
controlModule = new WebAssembly.Module(new Uint8Array(controlModuleWasm));
|
2023-02-13 17:41:35 +03:00
|
|
|
},
|
|
|
|
|
|
|
|
createService: async (
|
2023-08-25 00:15:49 +07:00
|
|
|
wasm: ArrayBuffer | SharedArrayBuffer,
|
2023-02-13 17:41:35 +03:00
|
|
|
serviceId: string,
|
|
|
|
envs?: Env,
|
|
|
|
): Promise<void> => {
|
|
|
|
if (!controlModule) {
|
|
|
|
throw new Error('MarineJS is not initialized. To initialize call `init` function');
|
|
|
|
}
|
|
|
|
|
2023-08-25 00:15:49 +07:00
|
|
|
if (marineServices.has(serviceId)) {
|
|
|
|
throw new Error(`Service with name ${serviceId} already registered`);
|
|
|
|
}
|
|
|
|
|
2023-08-09 15:38:40 +03:00
|
|
|
const marineConfig = createSimpleMarineService(serviceId, envs);
|
|
|
|
const modules = {[serviceId]: new Uint8Array(wasm)}
|
2023-02-13 17:41:35 +03:00
|
|
|
const srv = new MarineService(
|
|
|
|
controlModule,
|
|
|
|
serviceId,
|
|
|
|
onLogMessage.next.bind(onLogMessage),
|
|
|
|
marineConfig,
|
2023-08-09 15:38:40 +03:00
|
|
|
modules,
|
2023-02-13 17:41:35 +03:00
|
|
|
envs,
|
|
|
|
);
|
|
|
|
await srv.init();
|
|
|
|
marineServices.set(serviceId, srv);
|
|
|
|
},
|
|
|
|
|
2023-08-25 00:15:49 +07:00
|
|
|
hasService: async (serviceId: string) => {
|
|
|
|
return marineServices.has(serviceId);
|
|
|
|
},
|
|
|
|
|
|
|
|
removeService: async (serviceId: string) => {
|
|
|
|
if (serviceId === 'avm') {
|
|
|
|
throw new Error('Cannot remove \'avm\' service');
|
|
|
|
}
|
|
|
|
|
|
|
|
marineServices.get(serviceId)?.terminate();
|
|
|
|
return marineServices.delete(serviceId);
|
|
|
|
},
|
|
|
|
|
|
|
|
terminate: async () => {
|
2023-02-13 17:41:35 +03:00
|
|
|
marineServices.forEach((val, key) => {
|
|
|
|
val.terminate();
|
|
|
|
});
|
2023-08-25 00:15:49 +07:00
|
|
|
marineServices.clear();
|
2023-02-13 17:41:35 +03:00
|
|
|
onLogMessage.complete();
|
|
|
|
},
|
|
|
|
|
2023-08-25 00:15:49 +07:00
|
|
|
callService: async (serviceId: string, functionName: string, args: JSONArray | JSONObject, callParams: any) => {
|
2023-02-13 17:41:35 +03:00
|
|
|
const srv = marineServices.get(serviceId);
|
|
|
|
if (!srv) {
|
|
|
|
throw new Error(`service with id=${serviceId} not found`);
|
|
|
|
}
|
|
|
|
|
|
|
|
return srv.call(functionName, args, callParams);
|
|
|
|
},
|
|
|
|
|
|
|
|
onLogMessage(): Observable<LogMessage> {
|
|
|
|
return Observable.from(onLogMessage);
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2023-08-25 00:15:49 +07:00
|
|
|
type ExposedInterface<T extends {[key: string]: (...args: any[]) => unknown}> = {
|
|
|
|
[P in keyof T]: ReturnType<T[P]> extends Observable<unknown>
|
|
|
|
? T[P]
|
|
|
|
: ReturnType<T[P]> extends Promise<unknown>
|
|
|
|
? T[P]
|
|
|
|
: (...args: Parameters<T[P]>) => Promise<ReturnType<T[P]>>
|
|
|
|
};
|
|
|
|
|
|
|
|
export type MarineBackgroundInterface = ExposedInterface<typeof toExpose>;
|
2023-02-13 17:41:35 +03:00
|
|
|
|
|
|
|
expose(toExpose);
|