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

View File

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

View File

@ -1,5 +1,5 @@
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 { 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 { ConfigServer } from "@spt-aki/servers/ConfigServer";
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
import { WebSocketServer } from "@spt-aki/servers/WebSocketServer";
import { IHttpListener } from "@spt-aki/servers/http/IHttpListener";
import { WebSocketServer } from "@spt-aki/servers/WebSocketServer";
import { LocalisationService } from "@spt-aki/services/LocalisationService";
@injectable()
@ -26,7 +26,7 @@ export class HttpServer
@injectAll("HttpListener") protected httpListeners: IHttpListener[],
@inject("ConfigServer") protected configServer: ConfigServer,
@inject("ApplicationContext") protected applicationContext: ApplicationContext,
@inject("WebSocketServer") protected webSocketServer: WebSocketServer
@inject("WebSocketServer") protected webSocketServer: WebSocketServer,
)
{
this.httpConfig = this.configServer.getConfig(ConfigTypes.HTTP);
@ -49,7 +49,9 @@ export class HttpServer
/* Config server to listen on a port */
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) =>
@ -76,11 +78,11 @@ export class HttpServer
this.applicationContext.addValue(ContextVariableType.SESSION_ID, sessionId);
// 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));
}
for (const listener of this.httpListeners)
{
if (listener.canHandle(sessionId, req))
@ -108,4 +110,4 @@ export class HttpServer
return found;
}
}
}

View File

@ -28,7 +28,7 @@ export class RagfairServer
@inject("LocalisationService") protected localisationService: LocalisationService,
@inject("TraderHelper") protected traderHelper: TraderHelper,
@inject("TraderAssortHelper") protected traderAssortHelper: TraderAssortHelper,
@inject("ConfigServer") protected configServer: ConfigServer
@inject("ConfigServer") protected configServer: ConfigServer,
)
{
this.ragfairConfig = this.configServer.getConfig(ConfigTypes.RAGFAIR);
@ -79,7 +79,7 @@ export class RagfairServer
*/
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>
@ -99,7 +99,7 @@ export class RagfairServer
public hideOffer(offerId: string): void
{
const offers = this.ragfairOfferService.getOffers();
const offer = offers.find(x => x._id === offerId);
const offer = offers.find((x) => x._id === offerId);
if (!offer)
{
@ -135,4 +135,4 @@ export class RagfairServer
{
this.ragfairOfferService.addPlayerOffers();
}
}
}

View File

@ -23,9 +23,9 @@ export class SaveServer
@inject("JsonUtil") protected jsonUtil: JsonUtil,
@inject("HashUtil") protected hashUtil: HashUtil,
@inject("LocalisationService") protected localisationService: LocalisationService,
@inject("WinstonLogger") protected logger: ILogger
@inject("WinstonLogger") protected logger: ILogger,
)
{ }
{}
/**
* Add callback to occur prior to saving profile changes
@ -144,7 +144,7 @@ export class SaveServer
this.profiles[profileInfo.id] = {
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
* @param sessionID profile id (user/profiles/id.json)
*/
public saveProfile(sessionID: string): void
{
const filePath = `${this.profileFilepath}${sessionID}.json`;
// run callbacks
for (const callback in this.onBeforeSaveCallbacks)
{
@ -198,14 +198,14 @@ export class SaveServer
}
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;
}
}
const jsonProfile = this.jsonUtil.serialize(this.profiles[sessionID], true);
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);
// save profile to disk

View File

@ -13,17 +13,16 @@ import { JsonUtil } from "@spt-aki/utils/JsonUtil";
import { RandomUtil } from "@spt-aki/utils/RandomUtil";
@injectable()
export class WebSocketServer
export class WebSocketServer
{
constructor(
@inject("WinstonLogger") protected logger: ILogger,
@inject("RandomUtil") protected randomUtil: RandomUtil,
@inject("ConfigServer") protected configServer: ConfigServer,
@inject("LocalisationService") protected localisationService: LocalisationService,
@inject("JsonUtil") protected jsonUtil: JsonUtil,
@inject("HttpServerHelper") protected httpServerHelper: HttpServerHelper
)
@inject("HttpServerHelper") protected httpServerHelper: HttpServerHelper,
)
{
this.httpConfig = this.configServer.getConfig(ConfigTypes.HTTP);
}
@ -31,22 +30,26 @@ export class WebSocketServer
protected httpConfig: IHttpConfig;
protected defaultNotification: INotification = {
type: NotificationType.PING,
eventId: "ping"
eventId: "ping",
};
protected webSockets: Record<string, WebSocket.WebSocket> = {};
protected websocketPingHandler = null;
public setupWebSocket(httpServer: http.Server): void
public setupWebSocket(httpServer: http.Server): void
{
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.localisationService.getText("server_running")}, ${this.getRandomisedMessage()}!`);
this.logger.success(
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));
@ -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 (globalThis.G_RELEASE_CONFIGURATION)
? `${this.localisationService.getText("server_start_success")}!`
: this.localisationService.getText("server_start_success");
return (globalThis.G_RELEASE_CONFIGURATION) ?
`${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;
}
protected wsOnConnection(ws: WebSocket.WebSocket, req: IncomingMessage): void
protected wsOnConnection(ws: WebSocket.WebSocket, req: IncomingMessage): void
{
// Strip request and break it into sections
const splitUrl = req.url.substring(0, req.url.indexOf("?")).split("/");
@ -99,27 +102,27 @@ export class WebSocketServer
const logger = this.logger;
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}`);
});
this.webSockets[sessionID] = ws;
if (this.websocketPingHandler)
if (this.websocketPingHandler)
{
clearInterval(this.websocketPingHandler);
}
this.websocketPingHandler = setInterval(() =>
this.websocketPingHandler = setInterval(() =>
{
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));
}
else
else
{
this.logger.debug(this.localisationService.getText("websocket-socket_lost_deleting_handle"));
clearInterval(this.websocketPingHandler);
@ -127,4 +130,4 @@ export class WebSocketServer
}
}, this.httpConfig.webSocketPingDelayMs);
}
}
}

View File

@ -1,6 +1,6 @@
import { IncomingHttpHeaders, IncomingMessage, ServerResponse } from "node:http";
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 { ILogger } from "@spt-aki/models/spt/utils/ILogger";
@ -13,7 +13,6 @@ import { JsonUtil } from "@spt-aki/utils/JsonUtil";
@injectable()
export class AkiHttpListener implements IHttpListener
{
constructor(
@inject("HttpRouter") protected httpRouter: HttpRouter, // TODO: delay required
@injectAll("Serializer") protected serializers: Serializer[],
@ -21,7 +20,7 @@ export class AkiHttpListener implements IHttpListener
@inject("RequestsLogger") protected requestsLogger: ILogger,
@inject("JsonUtil") protected jsonUtil: JsonUtil,
@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);
let written = 0;
req.on("data", (data: any) =>
req.on("data", (data: any) =>
{
data.copy(buffer, written, 0);
written += data.length;
@ -96,7 +95,13 @@ export class AkiHttpListener implements IHttpListener
* @param body Buffer
* @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);
let handled = false;
@ -136,9 +141,9 @@ export class AkiHttpListener implements IHttpListener
if (globalThis.G_LOG_REQUESTS)
{
// Parse quest info into object
const data = (typeof info === "object")
? info
: this.jsonUtil.deserialize(info);
const data = (typeof info === "object") ?
info :
this.jsonUtil.deserialize(info);
const log = new Request(req.method, new RequestData(req.url, req.headers, data));
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.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;
}
protected getBodyInfo(body: Buffer, requestUrl = null): any
protected getBodyInfo(body: Buffer, requestUrl = null): any
{
const text = (body) ? body.toString() : "{}";
const info = (text) ? this.jsonUtil.deserialize<any>(text, requestUrl) : {};
const text = body ? body.toString() : "{}";
const info = text ? this.jsonUtil.deserialize<any>(text, requestUrl) : {};
return info;
}
public sendJson(resp: ServerResponse, output: string, sessionID: string): void
{
// 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);
}
public sendZlibJson(resp: ServerResponse, output: string, sessionID: string): void
{
// 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));
}
}
class RequestData
@ -183,7 +187,7 @@ class RequestData
constructor(
public url: string,
public headers: IncomingHttpHeaders,
public data?: any
public data?: any,
)
{}
}
@ -192,7 +196,7 @@ class Request
{
constructor(
public type: string,
public req: RequestData
public req: RequestData,
)
{}
}
@ -201,7 +205,7 @@ class Response
{
constructor(
public type: string,
public response: any
public response: any,
)
{}
}
}

View File

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

View File

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