0
0
mirror of https://github.com/sp-tarkov/server.git synced 2025-02-13 09:50:43 -05:00

Formatting for servers.

This commit is contained in:
Refringe 2023-11-13 11:12:51 -05:00
parent b90fb8c8b9
commit ca9ab9bcc8
No known key found for this signature in database
GPG Key ID: 64E03E5F892C6F9E
9 changed files with 87 additions and 75 deletions

View File

@ -7,7 +7,7 @@ import { JsonUtil } from "@spt-aki/utils/JsonUtil";
import { VFS } from "@spt-aki/utils/VFS"; import { VFS } from "@spt-aki/utils/VFS";
@injectable() @injectable()
export class ConfigServer export class ConfigServer
{ {
protected configs: Record<string, any> = {}; protected configs: Record<string, any> = {};
protected readonly acceptableFileExtensions: string[] = ["json", "jsonc"]; protected readonly acceptableFileExtensions: string[] = ["json", "jsonc"];
@ -15,7 +15,7 @@ export class ConfigServer
constructor( constructor(
@inject("WinstonLogger") protected logger: ILogger, @inject("WinstonLogger") protected logger: ILogger,
@inject("VFS") protected vfs: VFS, @inject("VFS") protected vfs: VFS,
@inject("JsonUtil") protected jsonUtil: JsonUtil @inject("JsonUtil") protected jsonUtil: JsonUtil,
) )
{ {
this.initialize(); this.initialize();
@ -36,9 +36,9 @@ export class ConfigServer
this.logger.debug("Importing configs..."); this.logger.debug("Importing configs...");
// Get all filepaths // Get all filepaths
const filepath = (globalThis.G_RELEASE_CONFIGURATION) const filepath = (globalThis.G_RELEASE_CONFIGURATION) ?
? "Aki_Data/Server/configs/" "Aki_Data/Server/configs/" :
: "./assets/configs/"; "./assets/configs/";
const files = this.vfs.getFiles(filepath); const files = this.vfs.getFiles(filepath);
// Add file content to result // Add file content to result
@ -48,10 +48,13 @@ export class ConfigServer
{ {
const fileName = this.vfs.stripExtension(file); const fileName = this.vfs.stripExtension(file);
const filePathAndName = `${filepath}${file}`; const filePathAndName = `${filepath}${file}`;
this.configs[`aki-${fileName}`] = this.jsonUtil.deserializeJsonC<any>(this.vfs.readFile(filePathAndName), filePathAndName); this.configs[`aki-${fileName}`] = this.jsonUtil.deserializeJsonC<any>(
this.vfs.readFile(filePathAndName),
filePathAndName,
);
} }
} }
this.logger.info(`Commit hash: ${(this.configs[ConfigTypes.CORE] as ICoreConfig).commit || "DEBUG"}`); this.logger.info(`Commit hash: ${(this.configs[ConfigTypes.CORE] as ICoreConfig).commit || "DEBUG"}`);
this.logger.info(`Build date: ${(this.configs[ConfigTypes.CORE] as ICoreConfig).buildTime || "DEBUG"}`); this.logger.info(`Build date: ${(this.configs[ConfigTypes.CORE] as ICoreConfig).buildTime || "DEBUG"}`);
} }

View File

@ -16,7 +16,7 @@ export class DatabaseServer
traders: undefined, traders: undefined,
globals: undefined, globals: undefined,
server: undefined, server: undefined,
settings: undefined settings: undefined,
}; };
public getTables(): IDatabaseTables public getTables(): IDatabaseTables

View File

@ -1,5 +1,5 @@
import http, { IncomingMessage, ServerResponse } from "node:http"; import http, { IncomingMessage, ServerResponse } from "node:http";
import { inject, injectAll, injectable } from "tsyringe"; import { inject, injectable, injectAll } from "tsyringe";
import { ApplicationContext } from "@spt-aki/context/ApplicationContext"; import { ApplicationContext } from "@spt-aki/context/ApplicationContext";
import { ContextVariableType } from "@spt-aki/context/ContextVariableType"; import { ContextVariableType } from "@spt-aki/context/ContextVariableType";
@ -9,8 +9,8 @@ import { IHttpConfig } from "@spt-aki/models/spt/config/IHttpConfig";
import { ILogger } from "@spt-aki/models/spt/utils/ILogger"; import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
import { ConfigServer } from "@spt-aki/servers/ConfigServer"; import { ConfigServer } from "@spt-aki/servers/ConfigServer";
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer"; import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
import { WebSocketServer } from "@spt-aki/servers/WebSocketServer";
import { IHttpListener } from "@spt-aki/servers/http/IHttpListener"; import { IHttpListener } from "@spt-aki/servers/http/IHttpListener";
import { WebSocketServer } from "@spt-aki/servers/WebSocketServer";
import { LocalisationService } from "@spt-aki/services/LocalisationService"; import { LocalisationService } from "@spt-aki/services/LocalisationService";
@injectable() @injectable()
@ -26,7 +26,7 @@ export class HttpServer
@injectAll("HttpListener") protected httpListeners: IHttpListener[], @injectAll("HttpListener") protected httpListeners: IHttpListener[],
@inject("ConfigServer") protected configServer: ConfigServer, @inject("ConfigServer") protected configServer: ConfigServer,
@inject("ApplicationContext") protected applicationContext: ApplicationContext, @inject("ApplicationContext") protected applicationContext: ApplicationContext,
@inject("WebSocketServer") protected webSocketServer: WebSocketServer @inject("WebSocketServer") protected webSocketServer: WebSocketServer,
) )
{ {
this.httpConfig = this.configServer.getConfig(ConfigTypes.HTTP); this.httpConfig = this.configServer.getConfig(ConfigTypes.HTTP);
@ -49,7 +49,9 @@ export class HttpServer
/* Config server to listen on a port */ /* Config server to listen on a port */
httpServer.listen(this.httpConfig.port, this.httpConfig.ip, () => httpServer.listen(this.httpConfig.port, this.httpConfig.ip, () =>
{ {
this.logger.success(this.localisationService.getText("started_webserver_success", this.httpServerHelper.getBackendUrl())); this.logger.success(
this.localisationService.getText("started_webserver_success", this.httpServerHelper.getBackendUrl()),
);
}); });
httpServer.on("error", (e: any) => httpServer.on("error", (e: any) =>
@ -76,11 +78,11 @@ export class HttpServer
this.applicationContext.addValue(ContextVariableType.SESSION_ID, sessionId); this.applicationContext.addValue(ContextVariableType.SESSION_ID, sessionId);
// http.json logRequests boolean option to allow the user/server to choose to not log requests // http.json logRequests boolean option to allow the user/server to choose to not log requests
if (this.httpConfig.logRequests) if (this.httpConfig.logRequests)
{ {
this.logger.info(this.localisationService.getText("client_request", req.url)); this.logger.info(this.localisationService.getText("client_request", req.url));
} }
for (const listener of this.httpListeners) for (const listener of this.httpListeners)
{ {
if (listener.canHandle(sessionId, req)) if (listener.canHandle(sessionId, req))
@ -108,4 +110,4 @@ export class HttpServer
return found; return found;
} }
} }

View File

@ -28,7 +28,7 @@ export class RagfairServer
@inject("LocalisationService") protected localisationService: LocalisationService, @inject("LocalisationService") protected localisationService: LocalisationService,
@inject("TraderHelper") protected traderHelper: TraderHelper, @inject("TraderHelper") protected traderHelper: TraderHelper,
@inject("TraderAssortHelper") protected traderAssortHelper: TraderAssortHelper, @inject("TraderAssortHelper") protected traderAssortHelper: TraderAssortHelper,
@inject("ConfigServer") protected configServer: ConfigServer @inject("ConfigServer") protected configServer: ConfigServer,
) )
{ {
this.ragfairConfig = this.configServer.getConfig(ConfigTypes.RAGFAIR); this.ragfairConfig = this.configServer.getConfig(ConfigTypes.RAGFAIR);
@ -79,7 +79,7 @@ export class RagfairServer
*/ */
protected getUpdateableTraders(): string[] protected getUpdateableTraders(): string[]
{ {
return Object.keys(this.ragfairConfig.traders).filter(x => this.ragfairConfig.traders[x]); return Object.keys(this.ragfairConfig.traders).filter((x) => this.ragfairConfig.traders[x]);
} }
public getAllCategories(): Record<string, number> public getAllCategories(): Record<string, number>
@ -99,7 +99,7 @@ export class RagfairServer
public hideOffer(offerId: string): void public hideOffer(offerId: string): void
{ {
const offers = this.ragfairOfferService.getOffers(); const offers = this.ragfairOfferService.getOffers();
const offer = offers.find(x => x._id === offerId); const offer = offers.find((x) => x._id === offerId);
if (!offer) if (!offer)
{ {
@ -135,4 +135,4 @@ export class RagfairServer
{ {
this.ragfairOfferService.addPlayerOffers(); this.ragfairOfferService.addPlayerOffers();
} }
} }

View File

@ -23,9 +23,9 @@ export class SaveServer
@inject("JsonUtil") protected jsonUtil: JsonUtil, @inject("JsonUtil") protected jsonUtil: JsonUtil,
@inject("HashUtil") protected hashUtil: HashUtil, @inject("HashUtil") protected hashUtil: HashUtil,
@inject("LocalisationService") protected localisationService: LocalisationService, @inject("LocalisationService") protected localisationService: LocalisationService,
@inject("WinstonLogger") protected logger: ILogger @inject("WinstonLogger") protected logger: ILogger,
) )
{ } {}
/** /**
* Add callback to occur prior to saving profile changes * Add callback to occur prior to saving profile changes
@ -144,7 +144,7 @@ export class SaveServer
this.profiles[profileInfo.id] = { this.profiles[profileInfo.id] = {
info: profileInfo, info: profileInfo,
characters: { pmc: {}, scav: {}} characters: {pmc: {}, scav: {}},
}; };
} }
@ -180,14 +180,14 @@ export class SaveServer
} }
/** /**
* Save changes from in-memory profile to user/profiles json * Save changes from in-memory profile to user/profiles json
* Execute onBeforeSaveCallbacks callbacks prior to being saved to json * Execute onBeforeSaveCallbacks callbacks prior to being saved to json
* @param sessionID profile id (user/profiles/id.json) * @param sessionID profile id (user/profiles/id.json)
*/ */
public saveProfile(sessionID: string): void public saveProfile(sessionID: string): void
{ {
const filePath = `${this.profileFilepath}${sessionID}.json`; const filePath = `${this.profileFilepath}${sessionID}.json`;
// run callbacks // run callbacks
for (const callback in this.onBeforeSaveCallbacks) for (const callback in this.onBeforeSaveCallbacks)
{ {
@ -198,14 +198,14 @@ export class SaveServer
} }
catch (error) catch (error)
{ {
this.logger.error(this.localisationService.getText("profile_save_callback_error", { callback, error })); this.logger.error(this.localisationService.getText("profile_save_callback_error", {callback, error}));
this.profiles[sessionID] = previous; this.profiles[sessionID] = previous;
} }
} }
const jsonProfile = this.jsonUtil.serialize(this.profiles[sessionID], true); const jsonProfile = this.jsonUtil.serialize(this.profiles[sessionID], true);
const fmd5 = this.hashUtil.generateMd5ForData(jsonProfile); const fmd5 = this.hashUtil.generateMd5ForData(jsonProfile);
if (typeof(this.saveMd5[sessionID]) !== "string" || this.saveMd5[sessionID] !== fmd5) if (typeof (this.saveMd5[sessionID]) !== "string" || this.saveMd5[sessionID] !== fmd5)
{ {
this.saveMd5[sessionID] = String(fmd5); this.saveMd5[sessionID] = String(fmd5);
// save profile to disk // save profile to disk

View File

@ -13,17 +13,16 @@ import { JsonUtil } from "@spt-aki/utils/JsonUtil";
import { RandomUtil } from "@spt-aki/utils/RandomUtil"; import { RandomUtil } from "@spt-aki/utils/RandomUtil";
@injectable() @injectable()
export class WebSocketServer export class WebSocketServer
{ {
constructor( constructor(
@inject("WinstonLogger") protected logger: ILogger, @inject("WinstonLogger") protected logger: ILogger,
@inject("RandomUtil") protected randomUtil: RandomUtil, @inject("RandomUtil") protected randomUtil: RandomUtil,
@inject("ConfigServer") protected configServer: ConfigServer, @inject("ConfigServer") protected configServer: ConfigServer,
@inject("LocalisationService") protected localisationService: LocalisationService, @inject("LocalisationService") protected localisationService: LocalisationService,
@inject("JsonUtil") protected jsonUtil: JsonUtil, @inject("JsonUtil") protected jsonUtil: JsonUtil,
@inject("HttpServerHelper") protected httpServerHelper: HttpServerHelper @inject("HttpServerHelper") protected httpServerHelper: HttpServerHelper,
) )
{ {
this.httpConfig = this.configServer.getConfig(ConfigTypes.HTTP); this.httpConfig = this.configServer.getConfig(ConfigTypes.HTTP);
} }
@ -31,22 +30,26 @@ export class WebSocketServer
protected httpConfig: IHttpConfig; protected httpConfig: IHttpConfig;
protected defaultNotification: INotification = { protected defaultNotification: INotification = {
type: NotificationType.PING, type: NotificationType.PING,
eventId: "ping" eventId: "ping",
}; };
protected webSockets: Record<string, WebSocket.WebSocket> = {}; protected webSockets: Record<string, WebSocket.WebSocket> = {};
protected websocketPingHandler = null; protected websocketPingHandler = null;
public setupWebSocket(httpServer: http.Server): void public setupWebSocket(httpServer: http.Server): void
{ {
const webSocketServer = new WebSocket.Server({ const webSocketServer = new WebSocket.Server({
server: httpServer server: httpServer,
}); });
webSocketServer.addListener("listening", () => webSocketServer.addListener("listening", () =>
{ {
this.logger.success(this.localisationService.getText("websocket-started", this.httpServerHelper.getWebsocketUrl())); this.logger.success(
this.logger.success(`${this.localisationService.getText("server_running")}, ${this.getRandomisedMessage()}!`); this.localisationService.getText("websocket-started", this.httpServerHelper.getWebsocketUrl()),
);
this.logger.success(
`${this.localisationService.getText("server_running")}, ${this.getRandomisedMessage()}!`,
);
}); });
webSocketServer.addListener("connection", this.wsOnConnection.bind(this)); webSocketServer.addListener("connection", this.wsOnConnection.bind(this));
@ -72,24 +75,24 @@ export class WebSocketServer
} }
} }
protected getRandomisedMessage(): string protected getRandomisedMessage(): string
{ {
if (this.randomUtil.getInt(1, 1000) > 999) if (this.randomUtil.getInt(1, 1000) > 999)
{ {
return this.localisationService.getRandomTextThatMatchesPartialKey("server_start_meme_"); return this.localisationService.getRandomTextThatMatchesPartialKey("server_start_meme_");
} }
return (globalThis.G_RELEASE_CONFIGURATION) return (globalThis.G_RELEASE_CONFIGURATION) ?
? `${this.localisationService.getText("server_start_success")}!` `${this.localisationService.getText("server_start_success")}!` :
: this.localisationService.getText("server_start_success"); this.localisationService.getText("server_start_success");
} }
public isConnectionWebSocket(sessionID: string): boolean public isConnectionWebSocket(sessionID: string): boolean
{ {
return this.webSockets[sessionID] !== undefined && this.webSockets[sessionID].readyState === WebSocket.OPEN; return this.webSockets[sessionID] !== undefined && this.webSockets[sessionID].readyState === WebSocket.OPEN;
} }
protected wsOnConnection(ws: WebSocket.WebSocket, req: IncomingMessage): void protected wsOnConnection(ws: WebSocket.WebSocket, req: IncomingMessage): void
{ {
// Strip request and break it into sections // Strip request and break it into sections
const splitUrl = req.url.substring(0, req.url.indexOf("?")).split("/"); const splitUrl = req.url.substring(0, req.url.indexOf("?")).split("/");
@ -99,27 +102,27 @@ export class WebSocketServer
const logger = this.logger; const logger = this.logger;
const msgToLog = this.localisationService.getText("websocket-received_message", sessionID); const msgToLog = this.localisationService.getText("websocket-received_message", sessionID);
ws.on("message", function message(msg) ws.on("message", function message(msg)
{ {
logger.info(`${msgToLog} ${msg}`); logger.info(`${msgToLog} ${msg}`);
}); });
this.webSockets[sessionID] = ws; this.webSockets[sessionID] = ws;
if (this.websocketPingHandler) if (this.websocketPingHandler)
{ {
clearInterval(this.websocketPingHandler); clearInterval(this.websocketPingHandler);
} }
this.websocketPingHandler = setInterval(() => this.websocketPingHandler = setInterval(() =>
{ {
this.logger.debug(this.localisationService.getText("websocket-pinging_player", sessionID)); this.logger.debug(this.localisationService.getText("websocket-pinging_player", sessionID));
if (ws.readyState === WebSocket.OPEN) if (ws.readyState === WebSocket.OPEN)
{ {
ws.send(this.jsonUtil.serialize(this.defaultNotification)); ws.send(this.jsonUtil.serialize(this.defaultNotification));
} }
else else
{ {
this.logger.debug(this.localisationService.getText("websocket-socket_lost_deleting_handle")); this.logger.debug(this.localisationService.getText("websocket-socket_lost_deleting_handle"));
clearInterval(this.websocketPingHandler); clearInterval(this.websocketPingHandler);
@ -127,4 +130,4 @@ export class WebSocketServer
} }
}, this.httpConfig.webSocketPingDelayMs); }, this.httpConfig.webSocketPingDelayMs);
} }
} }

View File

@ -1,6 +1,6 @@
import { IncomingHttpHeaders, IncomingMessage, ServerResponse } from "node:http"; import { IncomingHttpHeaders, IncomingMessage, ServerResponse } from "node:http";
import zlib from "node:zlib"; import zlib from "node:zlib";
import { inject, injectAll, injectable } from "tsyringe"; import { inject, injectable, injectAll } from "tsyringe";
import { Serializer } from "@spt-aki/di/Serializer"; import { Serializer } from "@spt-aki/di/Serializer";
import { ILogger } from "@spt-aki/models/spt/utils/ILogger"; import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
@ -13,7 +13,6 @@ import { JsonUtil } from "@spt-aki/utils/JsonUtil";
@injectable() @injectable()
export class AkiHttpListener implements IHttpListener export class AkiHttpListener implements IHttpListener
{ {
constructor( constructor(
@inject("HttpRouter") protected httpRouter: HttpRouter, // TODO: delay required @inject("HttpRouter") protected httpRouter: HttpRouter, // TODO: delay required
@injectAll("Serializer") protected serializers: Serializer[], @injectAll("Serializer") protected serializers: Serializer[],
@ -21,7 +20,7 @@ export class AkiHttpListener implements IHttpListener
@inject("RequestsLogger") protected requestsLogger: ILogger, @inject("RequestsLogger") protected requestsLogger: ILogger,
@inject("JsonUtil") protected jsonUtil: JsonUtil, @inject("JsonUtil") protected jsonUtil: JsonUtil,
@inject("HttpResponseUtil") protected httpResponse: HttpResponseUtil, @inject("HttpResponseUtil") protected httpResponse: HttpResponseUtil,
@inject("LocalisationService") protected localisationService: LocalisationService @inject("LocalisationService") protected localisationService: LocalisationService,
) )
{ {
} }
@ -53,7 +52,7 @@ export class AkiHttpListener implements IHttpListener
const buffer = Buffer.alloc(requestLength); const buffer = Buffer.alloc(requestLength);
let written = 0; let written = 0;
req.on("data", (data: any) => req.on("data", (data: any) =>
{ {
data.copy(buffer, written, 0); data.copy(buffer, written, 0);
written += data.length; written += data.length;
@ -96,7 +95,13 @@ export class AkiHttpListener implements IHttpListener
* @param body Buffer * @param body Buffer
* @param output Server generated response data * @param output Server generated response data
*/ */
public sendResponse(sessionID: string, req: IncomingMessage, resp: ServerResponse, body: Buffer, output: string): void public sendResponse(
sessionID: string,
req: IncomingMessage,
resp: ServerResponse,
body: Buffer,
output: string,
): void
{ {
const info = this.getBodyInfo(body); const info = this.getBodyInfo(body);
let handled = false; let handled = false;
@ -136,9 +141,9 @@ export class AkiHttpListener implements IHttpListener
if (globalThis.G_LOG_REQUESTS) if (globalThis.G_LOG_REQUESTS)
{ {
// Parse quest info into object // Parse quest info into object
const data = (typeof info === "object") const data = (typeof info === "object") ?
? info info :
: this.jsonUtil.deserialize(info); this.jsonUtil.deserialize(info);
const log = new Request(req.method, new RequestData(req.url, req.headers, data)); const log = new Request(req.method, new RequestData(req.url, req.headers, data));
this.requestsLogger.info(`REQUEST=${this.jsonUtil.serialize(log)}`); this.requestsLogger.info(`REQUEST=${this.jsonUtil.serialize(log)}`);
@ -150,32 +155,31 @@ export class AkiHttpListener implements IHttpListener
{ {
this.logger.error(this.localisationService.getText("unhandled_response", req.url)); this.logger.error(this.localisationService.getText("unhandled_response", req.url));
this.logger.info(info); this.logger.info(info);
output = <string><unknown> this.httpResponse.getBody(null, 404, `UNHANDLED RESPONSE: ${req.url}`); output = <string><unknown>this.httpResponse.getBody(null, 404, `UNHANDLED RESPONSE: ${req.url}`);
} }
return output; return output;
} }
protected getBodyInfo(body: Buffer, requestUrl = null): any protected getBodyInfo(body: Buffer, requestUrl = null): any
{ {
const text = (body) ? body.toString() : "{}"; const text = body ? body.toString() : "{}";
const info = (text) ? this.jsonUtil.deserialize<any>(text, requestUrl) : {}; const info = text ? this.jsonUtil.deserialize<any>(text, requestUrl) : {};
return info; return info;
} }
public sendJson(resp: ServerResponse, output: string, sessionID: string): void public sendJson(resp: ServerResponse, output: string, sessionID: string): void
{ {
// eslint-disable-next-line @typescript-eslint/naming-convention // eslint-disable-next-line @typescript-eslint/naming-convention
resp.writeHead(200, "OK", { "Content-Type": "application/json", "Set-Cookie": `PHPSESSID=${sessionID}` }); resp.writeHead(200, "OK", {"Content-Type": "application/json", "Set-Cookie": `PHPSESSID=${sessionID}`});
resp.end(output); resp.end(output);
} }
public sendZlibJson(resp: ServerResponse, output: string, sessionID: string): void public sendZlibJson(resp: ServerResponse, output: string, sessionID: string): void
{ {
// eslint-disable-next-line @typescript-eslint/naming-convention // eslint-disable-next-line @typescript-eslint/naming-convention
resp.writeHead(200, "OK", { "Content-Type": "application/json", "Set-Cookie": `PHPSESSID=${sessionID}` }); resp.writeHead(200, "OK", {"Content-Type": "application/json", "Set-Cookie": `PHPSESSID=${sessionID}`});
zlib.deflate(output, (_, buf) => resp.end(buf)); zlib.deflate(output, (_, buf) => resp.end(buf));
} }
} }
class RequestData class RequestData
@ -183,7 +187,7 @@ class RequestData
constructor( constructor(
public url: string, public url: string,
public headers: IncomingHttpHeaders, public headers: IncomingHttpHeaders,
public data?: any public data?: any,
) )
{} {}
} }
@ -192,7 +196,7 @@ class Request
{ {
constructor( constructor(
public type: string, public type: string,
public req: RequestData public req: RequestData,
) )
{} {}
} }
@ -201,7 +205,7 @@ class Response
{ {
constructor( constructor(
public type: string, public type: string,
public response: any public response: any,
) )
{} {}
} }

View File

@ -1,9 +1,9 @@
export enum HttpMethods export enum HttpMethods
{ {
OPTIONS = "OPTIONS", OPTIONS = "OPTIONS",
GET = "GET", GET = "GET",
POST = "POST", POST = "POST",
PUT = "PUT", PUT = "PUT",
PATCH = "PATCH", PATCH = "PATCH",
DELETE = "DELETE" DELETE = "DELETE",
} }

View File

@ -2,6 +2,6 @@ import { IncomingMessage, ServerResponse } from "node:http";
export interface IHttpListener export interface IHttpListener
{ {
canHandle(sessionId: string, req: IncomingMessage): boolean canHandle(sessionId: string, req: IncomingMessage): boolean;
handle(sessionId: string, req: IncomingMessage, resp: ServerResponse): void handle(sessionId: string, req: IncomingMessage, resp: ServerResponse): void;
} }