This repository has been archived on 2023-04-09. You can view files and clone it, but cannot push or open issues or pull requests.
libkernel-universal/src/index.ts

165 lines
3.8 KiB
TypeScript

type callModule = typeof import("libkmodule").callModule;
type connectModule = typeof import("libkmodule").connectModule;
type logErr = typeof import("libkmodule").logErr;
type log = typeof import("libkmodule").log;
import type { ErrTuple, DataFn } from "@siaweb/libweb";
import EventEmitter from "eventemitter3";
type callModuleBound = (method: string, data?: any) => Promise<ErrTuple>;
type connectModuleBound = (
method: string,
data: any,
receiveUpdate: DataFn
) => [sendUpdate: DataFn, response: Promise<ErrTuple>];
let callModule: callModule;
let connectModule: connectModule;
let log: log;
let logErr: logErr;
export interface ModuleBag {
callModule: callModule;
connectModule: connectModule;
log: log;
logErr: logErr;
}
export interface ModuleBagBound extends ModuleBag {
callModule: callModuleBound;
connectModule: connectModuleBound;
}
export abstract class Client extends EventEmitter {
private _callModule?: callModuleBound;
get callModule(): callModuleBound {
return this._callModule as callModuleBound;
}
private _log?: log;
get log(): log {
return this._log as log;
}
private _logErr?: logErr;
get logErr(): logErr {
return this._logErr as logErr;
}
private _connectModule?: connectModuleBound;
get connectModule(): connectModuleBound {
return this._connectModule as connectModuleBound;
}
public async loadLibs(module: string): Promise<void> {
if (this._callModule && this._connectModule) {
return;
}
const moduleBag = await this.loadBound(module);
this._callModule = async (...args) => {
const ret = await moduleBag.callModule(...args);
this.handleError(ret);
return ret;
};
this._connectModule = moduleBag.connectModule;
this._log = log;
this._logErr = logErr;
}
public async loadBound(module: string): Promise<ModuleBagBound> {
return (await load(module)) as ModuleBagBound;
}
protected handleError(ret: ErrTuple): void {
if (ret[1]) {
throw new Error(ret[1]);
}
}
protected handleErrorOrReturn(ret: ErrTuple): any {
this.handleError(ret);
return ret[0];
}
protected async callModuleReturn(method: string, data?: any): Promise<any> {
const ret = await this.callModule(method, data);
return ret[0];
}
}
export async function load(
module?: string
): Promise<ModuleBag | ModuleBagBound> {
if (callModule && connectModule) {
if (module) {
return {
callModule: callModule.bind(undefined, module),
connectModule: connectModule.bind(undefined, module),
log,
logErr,
} as ModuleBagBound;
}
return {
callModule,
connectModule,
log,
logErr,
} as ModuleBag;
}
const pkg =
typeof window !== "undefined" && window?.document
? await import("libkernel")
: await import("libkmodule");
callModule = pkg.callModule;
connectModule = pkg.connectModule;
// @ts-ignore
log = pkg.log;
// @ts-ignore
logErr = pkg.logErr;
return load(module);
}
type ClientConstructor<U> = new (...args: any[]) => U;
export const factory = function <T extends Client = Client>(
type: ClientConstructor<T>,
module: string
) {
return function (...args: any): T {
return new Proxy<T>(new type(...args), {
get(target: T, property: string) {
let desc = Object.getOwnPropertyDescriptor(
target?.constructor?.prototype,
property
);
if (!desc?.get) {
const prop = target[property as keyof T];
if (typeof prop !== "function") {
return prop;
}
}
return async (...args: any[]): Promise<any> => {
await target.loadLibs(module);
if (desc?.get) {
return target[property as keyof T];
}
return (target[property as keyof T] as Function)(...args);
};
},
});
};
};