2021-12-31 21:38:26 +00:00
|
|
|
//@template-ignore
|
2022-01-02 22:02:47 +00:00
|
|
|
import { VerificationError } from "./ts_base";
|
|
|
|
//@template-ignore
|
2023-11-29 23:16:53 +00:00
|
|
|
import { type RequestObject, type ResponseObject, ErrorCodes, Logging } from "./ts_service_base";
|
2021-12-31 21:38:26 +00:00
|
|
|
|
|
|
|
|
|
|
|
export class Service<T> {
|
|
|
|
public name: string = null as any;
|
|
|
|
public functions = new Set<string>();
|
|
|
|
|
2023-11-29 23:16:53 +00:00
|
|
|
constructor() { }
|
2021-12-31 21:38:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type ISendMessageCB = (data: any, catchedErr?: Error) => void;
|
|
|
|
|
|
|
|
export class ServiceProvider<T = any> {
|
|
|
|
services = new Map<string, Service<T>>();
|
|
|
|
addService(service: Service<T>) {
|
|
|
|
this.services.set(service.name, service);
|
|
|
|
Logging.log("SERVER: Adding Service to provider:", service.name);
|
|
|
|
Logging.log("SERVER: Service provides:", [...service.functions.keys()])
|
|
|
|
}
|
|
|
|
|
|
|
|
getSession(send: ISendMessageCB, ctx?: Partial<T>): Session<T> {
|
|
|
|
return new Session(this, send, ctx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class Session<T> {
|
|
|
|
ctx: Partial<T>;
|
|
|
|
|
|
|
|
constructor(
|
|
|
|
private provider: ServiceProvider,
|
|
|
|
private _send: ISendMessageCB,
|
|
|
|
ctx?: Partial<T>
|
|
|
|
) {
|
|
|
|
this.ctx = ctx || {};
|
|
|
|
}
|
|
|
|
|
2023-11-29 23:16:53 +00:00
|
|
|
send(data: any, catchedErr?: Error) {
|
2021-12-31 21:38:26 +00:00
|
|
|
Logging.log("SERVER: Sending Message", data)
|
|
|
|
this._send(data, catchedErr);
|
|
|
|
}
|
|
|
|
|
|
|
|
async onMessage(data: RequestObject) {
|
|
|
|
Logging.log("SERVER: Received Message", data);
|
|
|
|
try {
|
|
|
|
if (!data.method) {
|
|
|
|
if (data.id) {
|
|
|
|
this.send({
|
|
|
|
jsonrpc: "2.0",
|
|
|
|
id: data.id,
|
|
|
|
error: {
|
|
|
|
code: ErrorCodes.InvalidRequest,
|
|
|
|
message: "No method defined!",
|
|
|
|
},
|
|
|
|
} as ResponseObject);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const [srvName, fncName] = data.method.split(".");
|
|
|
|
Logging.log("SERVER: Message for", srvName, fncName);
|
|
|
|
|
|
|
|
const service = this.provider.services.get(srvName);
|
|
|
|
if (!service) {
|
|
|
|
Logging.log("SERVER: Did not find Service");
|
|
|
|
if (data.id) {
|
|
|
|
this.send({
|
|
|
|
jsonrpc: "2.0",
|
|
|
|
id: data.id,
|
|
|
|
error: {
|
|
|
|
code: ErrorCodes.MethodNotFound,
|
|
|
|
message: "Service not found!",
|
|
|
|
},
|
|
|
|
} as ResponseObject);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const fnc = service.functions.has(fncName);
|
|
|
|
if (!fnc) {
|
|
|
|
Logging.log("SERVER: Did not find Function");
|
|
|
|
if (data.id) {
|
|
|
|
this.send({
|
|
|
|
jsonrpc: "2.0",
|
|
|
|
id: data.id,
|
|
|
|
error: {
|
|
|
|
code: ErrorCodes.MethodNotFound,
|
|
|
|
message: "Function not found!",
|
|
|
|
},
|
|
|
|
} as ResponseObject);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let result = await (service as any)["_" + fncName](data.params, this.ctx);
|
2023-11-29 23:16:53 +00:00
|
|
|
if (data.id) { //Request
|
2021-12-31 21:38:26 +00:00
|
|
|
this.send({
|
|
|
|
jsonrpc: "2.0",
|
|
|
|
id: data.id,
|
|
|
|
result: result,
|
|
|
|
} as ResponseObject);
|
|
|
|
} //else Notification and response is ignored
|
|
|
|
} catch (err) {
|
|
|
|
if (data.id) {
|
|
|
|
this.send(
|
|
|
|
{
|
|
|
|
jsonrpc: "2.0",
|
|
|
|
id: data.id,
|
|
|
|
error: {
|
|
|
|
code: ErrorCodes.InternalError,
|
|
|
|
message: err.message,
|
2022-01-02 22:02:47 +00:00
|
|
|
data: err instanceof VerificationError ? {
|
|
|
|
$: "verification_error",
|
|
|
|
type: err.type,
|
|
|
|
field: err.field,
|
|
|
|
value: err.value
|
|
|
|
} : {
|
|
|
|
$: "unknown_error"
|
|
|
|
},
|
2021-12-31 21:38:26 +00:00
|
|
|
},
|
|
|
|
} as ResponseObject,
|
|
|
|
err
|
|
|
|
);
|
|
|
|
}
|
|
|
|
//TODO: Think about else case
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|