Formatting for utils.
This commit is contained in:
parent
8576929404
commit
4479f68388
@ -19,9 +19,9 @@ export class App
|
|||||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||||
@inject("EncodingUtil") protected encodingUtil: EncodingUtil,
|
@inject("EncodingUtil") protected encodingUtil: EncodingUtil,
|
||||||
@injectAll("OnLoad") protected onLoadComponents: OnLoad[],
|
@injectAll("OnLoad") protected onLoadComponents: OnLoad[],
|
||||||
@injectAll("OnUpdate") protected onUpdateComponents: OnUpdate[]
|
@injectAll("OnUpdate") protected onUpdateComponents: OnUpdate[],
|
||||||
)
|
)
|
||||||
{ }
|
{}
|
||||||
|
|
||||||
public async load(): Promise<void>
|
public async load(): Promise<void>
|
||||||
{
|
{
|
||||||
@ -73,7 +73,9 @@ export class App
|
|||||||
|
|
||||||
if (success === void 0 && !(secondsSinceLastRun % warnTime))
|
if (success === void 0 && !(secondsSinceLastRun % warnTime))
|
||||||
{
|
{
|
||||||
this.logger.debug(this.localisationService.getText("route_onupdate_no_response", updateable.getRoute()));
|
this.logger.debug(
|
||||||
|
this.localisationService.getText("route_onupdate_no_response", updateable.getRoute()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82,13 +84,13 @@ export class App
|
|||||||
protected logUpdateException(err: any, updateable: OnUpdate): void
|
protected logUpdateException(err: any, updateable: OnUpdate): void
|
||||||
{
|
{
|
||||||
this.logger.error(this.localisationService.getText("scheduled_event_failed_to_run", updateable.getRoute()));
|
this.logger.error(this.localisationService.getText("scheduled_event_failed_to_run", updateable.getRoute()));
|
||||||
if (err.message)
|
if (err.message)
|
||||||
{
|
{
|
||||||
this.logger.error(err.message);
|
this.logger.error(err.message);
|
||||||
}
|
}
|
||||||
if (err.stack)
|
if (err.stack)
|
||||||
{
|
{
|
||||||
this.logger.error(err.stack);
|
this.logger.error(err.stack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,21 +12,21 @@ export class AsyncQueue implements IAsyncQueue
|
|||||||
|
|
||||||
// Wait for the right command to execute
|
// Wait for the right command to execute
|
||||||
// This ensures that the commands execute in the right order, thus no data corruption
|
// This ensures that the commands execute in the right order, thus no data corruption
|
||||||
public async waitFor(command: ICommand): Promise<any>
|
public async waitFor(command: ICommand): Promise<any>
|
||||||
{
|
{
|
||||||
// Add to the queue
|
// Add to the queue
|
||||||
this.commandsQueue.push(command);
|
this.commandsQueue.push(command);
|
||||||
|
|
||||||
// eslint-disable-next-line no-constant-condition
|
// eslint-disable-next-line no-constant-condition
|
||||||
while (this.commandsQueue[0].uuid !== command.uuid)
|
while (this.commandsQueue[0].uuid !== command.uuid)
|
||||||
{
|
{
|
||||||
await new Promise<void>(resolve =>
|
await new Promise<void>((resolve) =>
|
||||||
{
|
{
|
||||||
setTimeout(resolve, 100);
|
setTimeout(resolve, 100);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// When the command is ready, execute it
|
// When the command is ready, execute it
|
||||||
return this.commandsQueue.shift().cmd();
|
return this.commandsQueue.shift().cmd();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ export class DatabaseImporter implements OnLoad
|
|||||||
@inject("EncodingUtil") protected encodingUtil: EncodingUtil,
|
@inject("EncodingUtil") protected encodingUtil: EncodingUtil,
|
||||||
@inject("HashUtil") protected hashUtil: HashUtil,
|
@inject("HashUtil") protected hashUtil: HashUtil,
|
||||||
@inject("ImporterUtil") protected importerUtil: ImporterUtil,
|
@inject("ImporterUtil") protected importerUtil: ImporterUtil,
|
||||||
@inject("ConfigServer") protected configServer: ConfigServer
|
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this.httpConfig = this.configServer.getConfig(ConfigTypes.HTTP);
|
this.httpConfig = this.configServer.getConfig(ConfigTypes.HTTP);
|
||||||
@ -45,25 +45,28 @@ export class DatabaseImporter implements OnLoad
|
|||||||
*/
|
*/
|
||||||
public getSptDataPath(): string
|
public getSptDataPath(): string
|
||||||
{
|
{
|
||||||
return (globalThis.G_RELEASE_CONFIGURATION)
|
return (globalThis.G_RELEASE_CONFIGURATION) ?
|
||||||
? "Aki_Data/Server/"
|
"Aki_Data/Server/" :
|
||||||
: "./assets/";
|
"./assets/";
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onLoad(): Promise<void>
|
public async onLoad(): Promise<void>
|
||||||
{
|
{
|
||||||
this.filepath = this.getSptDataPath();
|
this.filepath = this.getSptDataPath();
|
||||||
|
|
||||||
if (globalThis.G_RELEASE_CONFIGURATION)
|
if (globalThis.G_RELEASE_CONFIGURATION)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Reading the dynamic SHA1 file
|
// Reading the dynamic SHA1 file
|
||||||
const file = "checks.dat";
|
const file = "checks.dat";
|
||||||
const fileWithPath = `${this.filepath}${file}`;
|
const fileWithPath = `${this.filepath}${file}`;
|
||||||
if (this.vfs.exists(fileWithPath))
|
if (this.vfs.exists(fileWithPath))
|
||||||
{
|
{
|
||||||
this.hashedFile = this.jsonUtil.deserialize(this.encodingUtil.fromBase64(this.vfs.readFile(fileWithPath)), file);
|
this.hashedFile = this.jsonUtil.deserialize(
|
||||||
|
this.encodingUtil.fromBase64(this.vfs.readFile(fileWithPath)),
|
||||||
|
file,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -88,7 +91,7 @@ export class DatabaseImporter implements OnLoad
|
|||||||
"/files/Hideout/",
|
"/files/Hideout/",
|
||||||
"/files/launcher/",
|
"/files/launcher/",
|
||||||
"/files/quest/icon/",
|
"/files/quest/icon/",
|
||||||
"/files/trader/avatar/"
|
"/files/trader/avatar/",
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,42 +102,50 @@ export class DatabaseImporter implements OnLoad
|
|||||||
protected async hydrateDatabase(filepath: string): Promise<void>
|
protected async hydrateDatabase(filepath: string): Promise<void>
|
||||||
{
|
{
|
||||||
this.logger.info(this.localisationService.getText("importing_database"));
|
this.logger.info(this.localisationService.getText("importing_database"));
|
||||||
|
|
||||||
const dataToImport = await this.importerUtil.loadAsync<IDatabaseTables>(
|
const dataToImport = await this.importerUtil.loadAsync<IDatabaseTables>(
|
||||||
`${filepath}database/`,
|
`${filepath}database/`,
|
||||||
this.filepath,
|
this.filepath,
|
||||||
(fileWithPath: string, data: string) => this.onReadValidate(fileWithPath, data)
|
(fileWithPath: string, data: string) => this.onReadValidate(fileWithPath, data),
|
||||||
);
|
);
|
||||||
|
|
||||||
const validation = (this.valid === VaildationResult.FAILED || this.valid === VaildationResult.NOT_FOUND) ? "." : "";
|
const validation = (this.valid === VaildationResult.FAILED || this.valid === VaildationResult.NOT_FOUND) ?
|
||||||
|
"." :
|
||||||
|
"";
|
||||||
this.logger.info(`${this.localisationService.getText("importing_database_finish")}${validation}`);
|
this.logger.info(`${this.localisationService.getText("importing_database_finish")}${validation}`);
|
||||||
this.databaseServer.setTables(dataToImport);
|
this.databaseServer.setTables(dataToImport);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected onReadValidate(fileWithPath: string, data: string): void
|
protected onReadValidate(fileWithPath: string, data: string): void
|
||||||
{
|
{
|
||||||
// Validate files
|
// Validate files
|
||||||
if (globalThis.G_RELEASE_CONFIGURATION && this.hashedFile && !this.validateFile(fileWithPath, data))
|
if (globalThis.G_RELEASE_CONFIGURATION && this.hashedFile && !this.validateFile(fileWithPath, data))
|
||||||
|
{
|
||||||
this.valid = VaildationResult.FAILED;
|
this.valid = VaildationResult.FAILED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public getRoute(): string
|
public getRoute(): string
|
||||||
{
|
{
|
||||||
return "aki-database";
|
return "aki-database";
|
||||||
}
|
}
|
||||||
|
|
||||||
protected validateFile(filePathAndName: string, fileData: any): boolean
|
protected validateFile(filePathAndName: string, fileData: any): boolean
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
const finalPath = filePathAndName.replace(this.filepath, "").replace(".json", "");
|
const finalPath = filePathAndName.replace(this.filepath, "").replace(".json", "");
|
||||||
let tempObject;
|
let tempObject;
|
||||||
for (const prop of finalPath.split("/"))
|
for (const prop of finalPath.split("/"))
|
||||||
{
|
{
|
||||||
if (!tempObject)
|
if (!tempObject)
|
||||||
|
{
|
||||||
tempObject = this.hashedFile[prop];
|
tempObject = this.hashedFile[prop];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
tempObject = tempObject[prop];
|
tempObject = tempObject[prop];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tempObject !== this.hashUtil.generateSha1ForData(fileData))
|
if (tempObject !== this.hashUtil.generateSha1ForData(fileData))
|
||||||
@ -196,9 +207,9 @@ export class DatabaseImporter implements OnLoad
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum VaildationResult
|
enum VaildationResult
|
||||||
{
|
{
|
||||||
SUCCESS = 0,
|
SUCCESS = 0,
|
||||||
FAILED = 1,
|
FAILED = 1,
|
||||||
NOT_FOUND = 2,
|
NOT_FOUND = 2,
|
||||||
UNDEFINED = 3
|
UNDEFINED = 3,
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ import { injectable } from "tsyringe";
|
|||||||
@injectable()
|
@injectable()
|
||||||
export class EncodingUtil
|
export class EncodingUtil
|
||||||
{
|
{
|
||||||
|
|
||||||
public encode(value: string, encode: EncodeType): string
|
public encode(value: string, encode: EncodeType): string
|
||||||
{
|
{
|
||||||
return Buffer.from(value).toString(encode);
|
return Buffer.from(value).toString(encode);
|
||||||
@ -33,14 +32,13 @@ export class EncodingUtil
|
|||||||
{
|
{
|
||||||
return this.encode(value, EncodeType.HEX);
|
return this.encode(value, EncodeType.HEX);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum EncodeType
|
export enum EncodeType
|
||||||
{
|
{
|
||||||
BASE64 = "base64",
|
BASE64 = "base64",
|
||||||
HEX = "hex",
|
HEX = "hex",
|
||||||
ASCII = "ascii",
|
ASCII = "ascii",
|
||||||
BINARY = "binary",
|
BINARY = "binary",
|
||||||
UTF8 = "utf8"
|
UTF8 = "utf8",
|
||||||
}
|
}
|
||||||
|
@ -7,9 +7,9 @@ import { TimeUtil } from "@spt-aki/utils/TimeUtil";
|
|||||||
export class HashUtil
|
export class HashUtil
|
||||||
{
|
{
|
||||||
constructor(
|
constructor(
|
||||||
@inject("TimeUtil") protected timeUtil: TimeUtil
|
@inject("TimeUtil") protected timeUtil: TimeUtil,
|
||||||
)
|
)
|
||||||
{ }
|
{}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a 24 character id using the sha256 algorithm + current timestamp
|
* Create a 24 character id using the sha256 algorithm + current timestamp
|
||||||
|
@ -8,7 +8,7 @@ import { HttpServerHelper } from "@spt-aki/helpers/HttpServerHelper";
|
|||||||
export class HttpFileUtil
|
export class HttpFileUtil
|
||||||
{
|
{
|
||||||
constructor(
|
constructor(
|
||||||
@inject("HttpServerHelper") protected httpServerHelper: HttpServerHelper
|
@inject("HttpServerHelper") protected httpServerHelper: HttpServerHelper,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -16,13 +16,14 @@ export class HttpFileUtil
|
|||||||
public sendFile(resp: ServerResponse, file: any): void
|
public sendFile(resp: ServerResponse, file: any): void
|
||||||
{
|
{
|
||||||
const pathSlic = file.split("/");
|
const pathSlic = file.split("/");
|
||||||
const type = this.httpServerHelper.getMimeText(pathSlic[pathSlic.length - 1].split(".").at(-1)) || this.httpServerHelper.getMimeText("txt");
|
const type = this.httpServerHelper.getMimeText(pathSlic[pathSlic.length - 1].split(".").at(-1)) ||
|
||||||
|
this.httpServerHelper.getMimeText("txt");
|
||||||
const fileStream = fs.createReadStream(file);
|
const fileStream = fs.createReadStream(file);
|
||||||
|
|
||||||
fileStream.on("open", function ()
|
fileStream.on("open", function()
|
||||||
{
|
{
|
||||||
resp.setHeader("Content-Type", type);
|
resp.setHeader("Content-Type", type);
|
||||||
fileStream.pipe(resp);
|
fileStream.pipe(resp);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,12 +10,11 @@ import { JsonUtil } from "@spt-aki/utils/JsonUtil";
|
|||||||
@injectable()
|
@injectable()
|
||||||
export class HttpResponseUtil
|
export class HttpResponseUtil
|
||||||
{
|
{
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@inject("JsonUtil") protected jsonUtil: JsonUtil,
|
@inject("JsonUtil") protected jsonUtil: JsonUtil,
|
||||||
@inject("LocalisationService") protected localisationService: LocalisationService
|
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||||
)
|
)
|
||||||
{ }
|
{}
|
||||||
|
|
||||||
protected clearString(s: string): any
|
protected clearString(s: string): any
|
||||||
{
|
{
|
||||||
@ -29,8 +28,8 @@ export class HttpResponseUtil
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Return passed in data as JSON string
|
* Return passed in data as JSON string
|
||||||
* @param data
|
* @param data
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
public noBody(data: any): any
|
public noBody(data: any): any
|
||||||
{
|
{
|
||||||
@ -47,7 +46,7 @@ export class HttpResponseUtil
|
|||||||
return this.jsonUtil.serialize({
|
return this.jsonUtil.serialize({
|
||||||
err: err,
|
err: err,
|
||||||
errmsg: errmsg,
|
errmsg: errmsg,
|
||||||
data: data
|
data: data,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,12 +65,16 @@ export class HttpResponseUtil
|
|||||||
return this.getBody([]);
|
return this.getBody([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public appendErrorToOutput(output: IItemEventRouterResponse, message = this.localisationService.getText("http-unknown_error"), errorCode = BackendErrorCodes.NONE): IItemEventRouterResponse
|
public appendErrorToOutput(
|
||||||
|
output: IItemEventRouterResponse,
|
||||||
|
message = this.localisationService.getText("http-unknown_error"),
|
||||||
|
errorCode = BackendErrorCodes.NONE,
|
||||||
|
): IItemEventRouterResponse
|
||||||
{
|
{
|
||||||
output.warnings = [{
|
output.warnings = [{
|
||||||
index: 0,
|
index: 0,
|
||||||
errmsg: message,
|
errmsg: message,
|
||||||
code: errorCode.toString()
|
code: errorCode.toString(),
|
||||||
}];
|
}];
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
|
@ -11,7 +11,7 @@ export class ImporterUtil
|
|||||||
{
|
{
|
||||||
constructor(
|
constructor(
|
||||||
@inject("VFS") protected vfs: VFS,
|
@inject("VFS") protected vfs: VFS,
|
||||||
@inject("JsonUtil") protected jsonUtil: JsonUtil
|
@inject("JsonUtil") protected jsonUtil: JsonUtil,
|
||||||
)
|
)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@ -22,8 +22,10 @@ export class ImporterUtil
|
|||||||
*/
|
*/
|
||||||
public async loadRecursiveAsync<T>(
|
public async loadRecursiveAsync<T>(
|
||||||
filepath: string,
|
filepath: string,
|
||||||
onReadCallback: (fileWithPath: string, data: string) => void = () => {},
|
onReadCallback: (fileWithPath: string, data: string) => void = () =>
|
||||||
onObjectDeserialized: (fileWithPath: string, object: any) => void = () => {}
|
{},
|
||||||
|
onObjectDeserialized: (fileWithPath: string, object: any) => void = () =>
|
||||||
|
{},
|
||||||
): Promise<T>
|
): Promise<T>
|
||||||
{
|
{
|
||||||
const result = {} as T;
|
const result = {} as T;
|
||||||
@ -39,7 +41,7 @@ export class ImporterUtil
|
|||||||
{
|
{
|
||||||
const filename = this.vfs.stripExtension(file);
|
const filename = this.vfs.stripExtension(file);
|
||||||
const filePathAndName = `${filepath}${file}`;
|
const filePathAndName = `${filepath}${file}`;
|
||||||
await this.vfs.readFileAsync(filePathAndName).then(fileData =>
|
await this.vfs.readFileAsync(filePathAndName).then((fileData) =>
|
||||||
{
|
{
|
||||||
onReadCallback(filePathAndName, fileData);
|
onReadCallback(filePathAndName, fileData);
|
||||||
const fileDeserialized = this.jsonUtil.deserializeWithCacheCheck(fileData, filePathAndName);
|
const fileDeserialized = this.jsonUtil.deserializeWithCacheCheck(fileData, filePathAndName);
|
||||||
@ -57,7 +59,7 @@ export class ImporterUtil
|
|||||||
|
|
||||||
// set all loadRecursive to be executed asynchronously
|
// set all loadRecursive to be executed asynchronously
|
||||||
const resEntries = Object.entries(result);
|
const resEntries = Object.entries(result);
|
||||||
const resResolved = await Promise.all(resEntries.map(ent => ent[1]));
|
const resResolved = await Promise.all(resEntries.map((ent) => ent[1]));
|
||||||
for (let resIdx = 0; resIdx < resResolved.length; resIdx++)
|
for (let resIdx = 0; resIdx < resResolved.length; resIdx++)
|
||||||
{
|
{
|
||||||
resEntries[resIdx][1] = resResolved[resIdx];
|
resEntries[resIdx][1] = resResolved[resIdx];
|
||||||
@ -67,16 +69,17 @@ export class ImporterUtil
|
|||||||
return Object.fromEntries(resEntries) as T;
|
return Object.fromEntries(resEntries) as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load files into js objects recursively (synchronous)
|
* Load files into js objects recursively (synchronous)
|
||||||
* @param filepath Path to folder with files
|
* @param filepath Path to folder with files
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
public loadRecursive<T>(
|
public loadRecursive<T>(
|
||||||
filepath: string,
|
filepath: string,
|
||||||
onReadCallback: (fileWithPath: string, data: string) => void = () => {},
|
onReadCallback: (fileWithPath: string, data: string) => void = () =>
|
||||||
onObjectDeserialized: (fileWithPath: string, object: any) => void = () => {}
|
{},
|
||||||
|
onObjectDeserialized: (fileWithPath: string, object: any) => void = () =>
|
||||||
|
{},
|
||||||
): T
|
): T
|
||||||
{
|
{
|
||||||
const result = {} as T;
|
const result = {} as T;
|
||||||
@ -112,8 +115,10 @@ export class ImporterUtil
|
|||||||
public async loadAsync<T>(
|
public async loadAsync<T>(
|
||||||
filepath: string,
|
filepath: string,
|
||||||
strippablePath = "",
|
strippablePath = "",
|
||||||
onReadCallback: (fileWithPath: string, data: string) => void = () => {},
|
onReadCallback: (fileWithPath: string, data: string) => void = () =>
|
||||||
onObjectDeserialized: (fileWithPath: string, object: any) => void = () => {}
|
{},
|
||||||
|
onObjectDeserialized: (fileWithPath: string, object: any) => void = () =>
|
||||||
|
{},
|
||||||
): Promise<T>
|
): Promise<T>
|
||||||
{
|
{
|
||||||
const directoriesToRead = new Queue<string>();
|
const directoriesToRead = new Queue<string>();
|
||||||
@ -125,15 +130,15 @@ export class ImporterUtil
|
|||||||
|
|
||||||
const files = this.vfs.getFiles(filepath);
|
const files = this.vfs.getFiles(filepath);
|
||||||
const directories = this.vfs.getDirs(filepath);
|
const directories = this.vfs.getDirs(filepath);
|
||||||
|
|
||||||
directoriesToRead.enqueueAll(directories.map(d => `${filepath}${d}`));
|
directoriesToRead.enqueueAll(directories.map((d) => `${filepath}${d}`));
|
||||||
filesToProcess.enqueueAll(files.map(f => new VisitNode(filepath, f)));
|
filesToProcess.enqueueAll(files.map((f) => new VisitNode(filepath, f)));
|
||||||
|
|
||||||
while (!directoriesToRead.isEmpty())
|
while (!directoriesToRead.isEmpty())
|
||||||
{
|
{
|
||||||
const directory = directoriesToRead.dequeue();
|
const directory = directoriesToRead.dequeue();
|
||||||
filesToProcess.enqueueAll(this.vfs.getFiles(directory).map(f => new VisitNode(`${directory}/`, f)));
|
filesToProcess.enqueueAll(this.vfs.getFiles(directory).map((f) => new VisitNode(`${directory}/`, f)));
|
||||||
directoriesToRead.enqueueAll(this.vfs.getDirs(directory).map(d => `${directory}/${d}`));
|
directoriesToRead.enqueueAll(this.vfs.getDirs(directory).map((d) => `${directory}/${d}`));
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!filesToProcess.isEmpty())
|
while (!filesToProcess.isEmpty())
|
||||||
@ -144,25 +149,28 @@ export class ImporterUtil
|
|||||||
const filePathAndName = `${fileNode.filePath}${fileNode.fileName}`;
|
const filePathAndName = `${fileNode.filePath}${fileNode.fileName}`;
|
||||||
promises.push(
|
promises.push(
|
||||||
this.vfs.readFileAsync(filePathAndName)
|
this.vfs.readFileAsync(filePathAndName)
|
||||||
.then(async fileData => {
|
.then(async (fileData) =>
|
||||||
|
{
|
||||||
onReadCallback(filePathAndName, fileData);
|
onReadCallback(filePathAndName, fileData);
|
||||||
return this.jsonUtil.deserializeWithCacheCheckAsync<any>(fileData, filePathAndName);
|
return this.jsonUtil.deserializeWithCacheCheckAsync<any>(fileData, filePathAndName);
|
||||||
})
|
})
|
||||||
.then(async fileDeserialized => {
|
.then(async (fileDeserialized) =>
|
||||||
|
{
|
||||||
onObjectDeserialized(filePathAndName, fileDeserialized);
|
onObjectDeserialized(filePathAndName, fileDeserialized);
|
||||||
const strippedFilePath = this.vfs.stripExtension(filePathAndName).replace(filepath, "");
|
const strippedFilePath = this.vfs.stripExtension(filePathAndName).replace(filepath, "");
|
||||||
this.placeObject(fileDeserialized, strippedFilePath, result, strippablePath);
|
this.placeObject(fileDeserialized, strippedFilePath, result, strippablePath);
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await Promise.all(promises).catch(e => console.error(e));
|
await Promise.all(promises).catch((e) => console.error(e));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected placeObject<T>(fileDeserialized: any, strippedFilePath: string, result: T, strippablePath: string):void {
|
protected placeObject<T>(fileDeserialized: any, strippedFilePath: string, result: T, strippablePath: string): void
|
||||||
|
{
|
||||||
const strippedFinalPath = strippedFilePath.replace(strippablePath, "");
|
const strippedFinalPath = strippedFilePath.replace(strippablePath, "");
|
||||||
let temp = result;
|
let temp = result;
|
||||||
const propertiesToVisit = strippedFinalPath.split("/");
|
const propertiesToVisit = strippedFinalPath.split("/");
|
||||||
@ -177,7 +185,9 @@ export class ImporterUtil
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!temp[property])
|
if (!temp[property])
|
||||||
|
{
|
||||||
temp[property] = {};
|
temp[property] = {};
|
||||||
|
}
|
||||||
temp = temp[property];
|
temp = temp[property];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -188,7 +198,7 @@ class VisitNode
|
|||||||
{
|
{
|
||||||
constructor(
|
constructor(
|
||||||
public filePath: string,
|
public filePath: string,
|
||||||
public fileName: string
|
public fileName: string,
|
||||||
){}
|
)
|
||||||
|
{}
|
||||||
}
|
}
|
||||||
|
@ -18,9 +18,9 @@ export class JsonUtil
|
|||||||
constructor(
|
constructor(
|
||||||
@inject("VFS") protected vfs: VFS,
|
@inject("VFS") protected vfs: VFS,
|
||||||
@inject("HashUtil") protected hashUtil: HashUtil,
|
@inject("HashUtil") protected hashUtil: HashUtil,
|
||||||
@inject("WinstonLogger") protected logger: ILogger
|
@inject("WinstonLogger") protected logger: ILogger,
|
||||||
)
|
)
|
||||||
{ }
|
{}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* From object to string
|
* From object to string
|
||||||
@ -47,23 +47,27 @@ export class JsonUtil
|
|||||||
* @param space Adds indentation, white space, and line break characters to the return-value JSON text to make it easier to read.
|
* @param space Adds indentation, white space, and line break characters to the return-value JSON text to make it easier to read.
|
||||||
* @returns string
|
* @returns string
|
||||||
*/
|
*/
|
||||||
public serializeAdvanced(data: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string
|
public serializeAdvanced(
|
||||||
|
data: any,
|
||||||
|
replacer?: (this: any, key: string, value: any) => any,
|
||||||
|
space?: string | number,
|
||||||
|
): string
|
||||||
{
|
{
|
||||||
|
|
||||||
return JSON.stringify(data, replacer, space);
|
return JSON.stringify(data, replacer, space);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* From object to string
|
* From object to string
|
||||||
* @param data object to turn into JSON
|
* @param data object to turn into JSON
|
||||||
* @param filename Name of file being serialized
|
* @param filename Name of file being serialized
|
||||||
* @param options Stringify options or a replacer.
|
* @param options Stringify options or a replacer.
|
||||||
* @returns The string converted from the JavaScript value
|
* @returns The string converted from the JavaScript value
|
||||||
*/
|
*/
|
||||||
public serializeJsonC(
|
public serializeJsonC(
|
||||||
data: any,
|
data: any,
|
||||||
filename?: string | null,
|
filename?: string | null,
|
||||||
options?: IStringifyOptions | Reviver): string
|
options?: IStringifyOptions | Reviver,
|
||||||
|
): string
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -71,14 +75,17 @@ export class JsonUtil
|
|||||||
}
|
}
|
||||||
catch (error)
|
catch (error)
|
||||||
{
|
{
|
||||||
this.logger.error(`unable to stringify jsonC file: ${filename} message: ${error.message}, stack: ${error.stack}`);
|
this.logger.error(
|
||||||
|
`unable to stringify jsonC file: ${filename} message: ${error.message}, stack: ${error.stack}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public serializeJson5(
|
public serializeJson5(
|
||||||
data: any,
|
data: any,
|
||||||
filename?: string | null,
|
filename?: string | null,
|
||||||
prettify = false): string
|
prettify = false,
|
||||||
|
): string
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -93,7 +100,9 @@ export class JsonUtil
|
|||||||
}
|
}
|
||||||
catch (error)
|
catch (error)
|
||||||
{
|
{
|
||||||
this.logger.error(`unable to stringify json5 file: ${filename} message: ${error.message}, stack: ${error.stack}`);
|
this.logger.error(
|
||||||
|
`unable to stringify json5 file: ${filename} message: ${error.message}, stack: ${error.stack}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,7 +120,9 @@ export class JsonUtil
|
|||||||
}
|
}
|
||||||
catch (error)
|
catch (error)
|
||||||
{
|
{
|
||||||
this.logger.error(`unable to parse json file: ${filename} message: ${error.message}, stack: ${error.stack}`);
|
this.logger.error(
|
||||||
|
`unable to parse json file: ${filename} message: ${error.message}, stack: ${error.stack}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,7 +141,9 @@ export class JsonUtil
|
|||||||
}
|
}
|
||||||
catch (error)
|
catch (error)
|
||||||
{
|
{
|
||||||
this.logger.error(`unable to parse jsonC file: ${filename} message: ${error.message}, stack: ${error.stack}`);
|
this.logger.error(
|
||||||
|
`unable to parse jsonC file: ${filename} message: ${error.message}, stack: ${error.stack}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,13 +155,15 @@ export class JsonUtil
|
|||||||
}
|
}
|
||||||
catch (error)
|
catch (error)
|
||||||
{
|
{
|
||||||
this.logger.error(`unable to parse json file: ${filename} message: ${error.message}, stack: ${error.stack}`);
|
this.logger.error(
|
||||||
|
`unable to parse json file: ${filename} message: ${error.message}, stack: ${error.stack}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async deserializeWithCacheCheckAsync<T>(jsonString: string, filePath: string): Promise<T>
|
public async deserializeWithCacheCheckAsync<T>(jsonString: string, filePath: string): Promise<T>
|
||||||
{
|
{
|
||||||
return new Promise((resolve) =>
|
return new Promise((resolve) =>
|
||||||
{
|
{
|
||||||
resolve(this.deserializeWithCacheCheck<T>(jsonString, filePath));
|
resolve(this.deserializeWithCacheCheck<T>(jsonString, filePath));
|
||||||
});
|
});
|
||||||
@ -174,9 +189,9 @@ export class JsonUtil
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
const { data, changed } = fixJson(jsonString);
|
const {data, changed} = fixJson(jsonString);
|
||||||
if (changed) // data invalid, return it
|
if (changed)
|
||||||
{
|
{ // data invalid, return it
|
||||||
this.logger.error(`${filePath} - Detected faulty json, please fix your json file using VSCodium`);
|
this.logger.error(`${filePath} - Detected faulty json, please fix your json file using VSCodium`);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -206,7 +221,6 @@ export class JsonUtil
|
|||||||
return this.deserialize<T>(jsonString);
|
return this.deserialize<T>(jsonString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create file if nothing found
|
* Create file if nothing found
|
||||||
* @param jsonCachePath path to cache
|
* @param jsonCachePath path to cache
|
||||||
@ -228,7 +242,7 @@ export class JsonUtil
|
|||||||
* Read contents of json cache and add to class field
|
* Read contents of json cache and add to class field
|
||||||
* @param jsonCachePath Path to cache
|
* @param jsonCachePath Path to cache
|
||||||
*/
|
*/
|
||||||
protected hydrateJsonCache(jsonCachePath: string) : void
|
protected hydrateJsonCache(jsonCachePath: string): void
|
||||||
{
|
{
|
||||||
// Get all file hashes
|
// Get all file hashes
|
||||||
if (!this.fileHashes)
|
if (!this.fileHashes)
|
||||||
|
@ -5,9 +5,9 @@ export class MathUtil
|
|||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Helper to create the sum of all array elements
|
* Helper to create the sum of all array elements
|
||||||
* @param {array} values The array with numbers of which to calculate the sum
|
* @param {array} values The array with numbers of which to calculate the sum
|
||||||
* @return {number} sum(values)
|
* @return {number} sum(values)
|
||||||
*/
|
*/
|
||||||
public arraySum(values: number[]): number
|
public arraySum(values: number[]): number
|
||||||
{
|
{
|
||||||
// sum with initial value being 0
|
// sum with initial value being 0
|
||||||
@ -24,7 +24,7 @@ export class MathUtil
|
|||||||
{
|
{
|
||||||
// curried function for cumulative sum: (cum, x) => cum += x
|
// curried function for cumulative sum: (cum, x) => cum += x
|
||||||
// and 0 being the initial value for the map
|
// and 0 being the initial value for the map
|
||||||
return values.map((cum => x => cum += x)(0));
|
return values.map(((cum) => (x) => cum += x)(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -34,7 +34,7 @@ export class MathUtil
|
|||||||
*/
|
*/
|
||||||
public arrayProd(values: number[], factor: number): number[]
|
public arrayProd(values: number[], factor: number): number[]
|
||||||
{
|
{
|
||||||
return values.map(x => x * factor);
|
return values.map((x) => x * factor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -44,7 +44,7 @@ export class MathUtil
|
|||||||
*/
|
*/
|
||||||
public arrayAdd(values: number[], summand: number): number[]
|
public arrayAdd(values: number[], summand: number): number[]
|
||||||
{
|
{
|
||||||
return values.map(x => x + summand);
|
return values.map((x) => x + summand);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -72,14 +72,14 @@ export class MathUtil
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Linear interpolation
|
* Linear interpolation
|
||||||
* e.g. used to do a continuous integration for quest rewards which are defined for specific support centers of pmcLevel
|
* e.g. used to do a continuous integration for quest rewards which are defined for specific support centers of pmcLevel
|
||||||
*
|
*
|
||||||
* @param {string} xp the point of x at which to interpolate
|
* @param {string} xp the point of x at which to interpolate
|
||||||
* @param {array} x support points in x (of same length as y)
|
* @param {array} x support points in x (of same length as y)
|
||||||
* @param {array} y support points in y (of same length as x)
|
* @param {array} y support points in y (of same length as x)
|
||||||
* @return {number} y(xp)
|
* @return {number} y(xp)
|
||||||
*/
|
*/
|
||||||
public interp1(xp: number, x: number[], y: number[]): number
|
public interp1(xp: number, x: number[], y: number[]): number
|
||||||
{
|
{
|
||||||
if (xp > x[x.length - 1])
|
if (xp > x[x.length - 1])
|
||||||
@ -101,4 +101,4 @@ export class MathUtil
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,9 +7,9 @@ import { TimeUtil } from "@spt-aki/utils/TimeUtil";
|
|||||||
export class ObjectId
|
export class ObjectId
|
||||||
{
|
{
|
||||||
constructor(
|
constructor(
|
||||||
@inject("TimeUtil") protected timeUtil: TimeUtil
|
@inject("TimeUtil") protected timeUtil: TimeUtil,
|
||||||
)
|
)
|
||||||
{ }
|
{}
|
||||||
|
|
||||||
protected randomBytes = crypto.randomBytes(5);
|
protected randomBytes = crypto.randomBytes(5);
|
||||||
protected constglobalCounter = 0;
|
protected constglobalCounter = 0;
|
||||||
@ -58,4 +58,4 @@ export class ObjectId
|
|||||||
|
|
||||||
return this.toHexString(objectIdBinary);
|
return this.toHexString(objectIdBinary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ export class RagfairOfferHolder
|
|||||||
this.removeOffer(offer);
|
this.removeOffer(offer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeOfferByTrader(traderId: string): void
|
public removeOfferByTrader(traderId: string): void
|
||||||
{
|
{
|
||||||
if (this.offersByTrader.has(traderId))
|
if (this.offersByTrader.has(traderId))
|
||||||
@ -99,7 +99,7 @@ export class RagfairOfferHolder
|
|||||||
*/
|
*/
|
||||||
public getStaleOffers(time: number): Array<IRagfairOffer>
|
public getStaleOffers(time: number): Array<IRagfairOffer>
|
||||||
{
|
{
|
||||||
return this.getOffers().filter(o => this.isStale(o, time));
|
return this.getOffers().filter((o) => this.isStale(o, time));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected addOfferByTemplates(template: string, offer: IRagfairOffer): void
|
protected addOfferByTemplates(template: string, offer: IRagfairOffer): void
|
||||||
@ -134,4 +134,4 @@ export class RagfairOfferHolder
|
|||||||
{
|
{
|
||||||
return offer.endTime < time || offer.items[0].upd.StackObjectsCount < 1;
|
return offer.endTime < time || offer.items[0].upd.StackObjectsCount < 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,32 +5,35 @@ import { JsonUtil } from "@spt-aki/utils/JsonUtil";
|
|||||||
import { MathUtil } from "@spt-aki/utils/MathUtil";
|
import { MathUtil } from "@spt-aki/utils/MathUtil";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Array of ProbabilityObjectArray which allow to randomly draw of the contained objects
|
* Array of ProbabilityObjectArray which allow to randomly draw of the contained objects
|
||||||
* based on the relative probability of each of its elements.
|
* based on the relative probability of each of its elements.
|
||||||
* The probabilities of the contained element is not required to be normalized.
|
* The probabilities of the contained element is not required to be normalized.
|
||||||
*
|
*
|
||||||
* Example:
|
* Example:
|
||||||
* po = new ProbabilityObjectArray(
|
* po = new ProbabilityObjectArray(
|
||||||
* new ProbabilityObject("a", 5),
|
* new ProbabilityObject("a", 5),
|
||||||
* new ProbabilityObject("b", 1),
|
* new ProbabilityObject("b", 1),
|
||||||
* new ProbabilityObject("c", 1)
|
* new ProbabilityObject("c", 1)
|
||||||
* );
|
* );
|
||||||
* res = po.draw(10000);
|
* res = po.draw(10000);
|
||||||
* // count the elements which should be distributed according to the relative probabilities
|
* // count the elements which should be distributed according to the relative probabilities
|
||||||
* res.filter(x => x==="b").reduce((sum, x) => sum + 1 , 0)
|
* res.filter(x => x==="b").reduce((sum, x) => sum + 1 , 0)
|
||||||
*/
|
*/
|
||||||
export class ProbabilityObjectArray<K, V=undefined> extends Array<ProbabilityObject<K, V>>
|
export class ProbabilityObjectArray<K, V = undefined> extends Array<ProbabilityObject<K, V>>
|
||||||
{
|
{
|
||||||
constructor(
|
constructor(
|
||||||
private mathUtil: MathUtil,
|
private mathUtil: MathUtil,
|
||||||
private jsonUtil: JsonUtil,
|
private jsonUtil: JsonUtil,
|
||||||
...items: ProbabilityObject<K, V>[])
|
...items: ProbabilityObject<K, V>[]
|
||||||
|
)
|
||||||
{
|
{
|
||||||
super();
|
super();
|
||||||
this.push(...items);
|
this.push(...items);
|
||||||
}
|
}
|
||||||
|
|
||||||
filter(callbackfn: (value: ProbabilityObject<K, V>, index: number, array: ProbabilityObject<K, V>[]) => any): ProbabilityObjectArray<K, V>
|
filter(
|
||||||
|
callbackfn: (value: ProbabilityObject<K, V>, index: number, array: ProbabilityObject<K, V>[]) => any,
|
||||||
|
): ProbabilityObjectArray<K, V>
|
||||||
{
|
{
|
||||||
return new ProbabilityObjectArray(this.mathUtil, this.jsonUtil, ...super.filter(callbackfn));
|
return new ProbabilityObjectArray(this.mathUtil, this.jsonUtil, ...super.filter(callbackfn));
|
||||||
}
|
}
|
||||||
@ -56,7 +59,7 @@ export class ProbabilityObjectArray<K, V=undefined> extends Array<ProbabilityObj
|
|||||||
{
|
{
|
||||||
const clone = this.jsonUtil.clone(this);
|
const clone = this.jsonUtil.clone(this);
|
||||||
const probabliltyObjects = new ProbabilityObjectArray<K, V>(this.mathUtil, this.jsonUtil);
|
const probabliltyObjects = new ProbabilityObjectArray<K, V>(this.mathUtil, this.jsonUtil);
|
||||||
for (const ci of clone)
|
for (const ci of clone)
|
||||||
{
|
{
|
||||||
probabliltyObjects.push(new ProbabilityObject(ci.key, ci.relativeProbability, ci.data));
|
probabliltyObjects.push(new ProbabilityObject(ci.key, ci.relativeProbability, ci.data));
|
||||||
}
|
}
|
||||||
@ -71,7 +74,7 @@ export class ProbabilityObjectArray<K, V=undefined> extends Array<ProbabilityObj
|
|||||||
*/
|
*/
|
||||||
drop(key: K): ProbabilityObjectArray<K, V>
|
drop(key: K): ProbabilityObjectArray<K, V>
|
||||||
{
|
{
|
||||||
return this.filter(r => r.key !== key);
|
return this.filter((r) => r.key !== key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -81,7 +84,7 @@ export class ProbabilityObjectArray<K, V=undefined> extends Array<ProbabilityObj
|
|||||||
*/
|
*/
|
||||||
data(key: K): V
|
data(key: K): V
|
||||||
{
|
{
|
||||||
return this.filter(r => r.key === key)[0]?.data;
|
return this.filter((r) => r.key === key)[0]?.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -96,7 +99,7 @@ export class ProbabilityObjectArray<K, V=undefined> extends Array<ProbabilityObj
|
|||||||
*/
|
*/
|
||||||
probability(key: K): number
|
probability(key: K): number
|
||||||
{
|
{
|
||||||
return this.filter(r => r.key === key)[0].relativeProbability;
|
return this.filter((r) => r.key === key)[0].relativeProbability;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -110,7 +113,7 @@ export class ProbabilityObjectArray<K, V=undefined> extends Array<ProbabilityObj
|
|||||||
*/
|
*/
|
||||||
maxProbability(): number
|
maxProbability(): number
|
||||||
{
|
{
|
||||||
return Math.max(...this.map(x => x.relativeProbability));
|
return Math.max(...this.map((x) => x.relativeProbability));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -124,7 +127,7 @@ export class ProbabilityObjectArray<K, V=undefined> extends Array<ProbabilityObj
|
|||||||
*/
|
*/
|
||||||
minProbability(): number
|
minProbability(): number
|
||||||
{
|
{
|
||||||
return Math.min(...this.map(x => x.relativeProbability));
|
return Math.min(...this.map((x) => x.relativeProbability));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -146,17 +149,17 @@ export class ProbabilityObjectArray<K, V=undefined> extends Array<ProbabilityObj
|
|||||||
let probCumsum = this.cumulativeProbability(probArray);
|
let probCumsum = this.cumulativeProbability(probArray);
|
||||||
|
|
||||||
const drawnKeys = [];
|
const drawnKeys = [];
|
||||||
for (let i = 0; i < count; i++)
|
for (let i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
const rand = Math.random();
|
const rand = Math.random();
|
||||||
const randomIndex = probCumsum.findIndex(x => x > rand);
|
const randomIndex = probCumsum.findIndex((x) => x > rand);
|
||||||
// We cannot put Math.random() directly in the findIndex because then it draws anew for each of its iteration
|
// We cannot put Math.random() directly in the findIndex because then it draws anew for each of its iteration
|
||||||
if (replacement || locklist.includes(keyArray[randomIndex]))
|
if (replacement || locklist.includes(keyArray[randomIndex]))
|
||||||
{
|
{
|
||||||
// Add random item from possible value into return array
|
// Add random item from possible value into return array
|
||||||
drawnKeys.push(keyArray[randomIndex]);
|
drawnKeys.push(keyArray[randomIndex]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// We draw without replacement -> remove the key and its probability from array
|
// We draw without replacement -> remove the key and its probability from array
|
||||||
const key = keyArray.splice(randomIndex, 1)[0];
|
const key = keyArray.splice(randomIndex, 1)[0];
|
||||||
@ -164,7 +167,7 @@ export class ProbabilityObjectArray<K, V=undefined> extends Array<ProbabilityObj
|
|||||||
drawnKeys.push(key);
|
drawnKeys.push(key);
|
||||||
probCumsum = this.cumulativeProbability(probArray);
|
probCumsum = this.cumulativeProbability(probArray);
|
||||||
// If we draw without replacement and the ProbabilityObjectArray is exhausted we need to break
|
// If we draw without replacement and the ProbabilityObjectArray is exhausted we need to break
|
||||||
if (keyArray.length < 1)
|
if (keyArray.length < 1)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -176,20 +179,20 @@ export class ProbabilityObjectArray<K, V=undefined> extends Array<ProbabilityObj
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A ProbabilityObject which is use as an element to the ProbabilityObjectArray array
|
* A ProbabilityObject which is use as an element to the ProbabilityObjectArray array
|
||||||
* It contains a key, the relative probability as well as optional data.
|
* It contains a key, the relative probability as well as optional data.
|
||||||
*/
|
*/
|
||||||
export class ProbabilityObject<K,V=undefined>
|
export class ProbabilityObject<K, V = undefined>
|
||||||
{
|
{
|
||||||
key: K;
|
key: K;
|
||||||
relativeProbability: number;
|
relativeProbability: number;
|
||||||
data: V;
|
data: V;
|
||||||
/**
|
/**
|
||||||
* Constructor for the ProbabilityObject
|
* Constructor for the ProbabilityObject
|
||||||
* @param {string} key The key of the element
|
* @param {string} key The key of the element
|
||||||
* @param {number} relativeProbability The relative probability of this element
|
* @param {number} relativeProbability The relative probability of this element
|
||||||
* @param {any} data Optional data attached to the element
|
* @param {any} data Optional data attached to the element
|
||||||
*/
|
*/
|
||||||
constructor(key: K, relativeProbability: number, data: V = null)
|
constructor(key: K, relativeProbability: number, data: V = null)
|
||||||
{
|
{
|
||||||
this.key = key;
|
this.key = key;
|
||||||
@ -201,9 +204,9 @@ export class ProbabilityObject<K,V=undefined>
|
|||||||
@injectable()
|
@injectable()
|
||||||
export class RandomUtil
|
export class RandomUtil
|
||||||
{
|
{
|
||||||
constructor (
|
constructor(
|
||||||
@inject("JsonUtil") protected jsonUtil: JsonUtil,
|
@inject("JsonUtil") protected jsonUtil: JsonUtil,
|
||||||
@inject("WinstonLogger") protected logger: ILogger
|
@inject("WinstonLogger") protected logger: ILogger,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -261,7 +264,7 @@ export class RandomUtil
|
|||||||
return this.getArrayValue(Object.keys(node));
|
return this.getArrayValue(Object.keys(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
public getKeyValue(node: { [x: string]: any; }): any
|
public getKeyValue(node: {[x: string]: any;}): any
|
||||||
{
|
{
|
||||||
return node[this.getKey(node)];
|
return node[this.getKey(node)];
|
||||||
}
|
}
|
||||||
@ -276,8 +279,14 @@ export class RandomUtil
|
|||||||
{
|
{
|
||||||
let u = 0;
|
let u = 0;
|
||||||
let v = 0;
|
let v = 0;
|
||||||
while (u === 0) u = Math.random(); //Converting [0,1) to (0,1)
|
while (u === 0)
|
||||||
while (v === 0) v = Math.random();
|
{
|
||||||
|
u = Math.random(); // Converting [0,1) to (0,1)
|
||||||
|
}
|
||||||
|
while (v === 0)
|
||||||
|
{
|
||||||
|
v = Math.random();
|
||||||
|
}
|
||||||
const w = Math.sqrt(-2.0 * Math.log(u)) * Math.cos(2.0 * Math.PI * v);
|
const w = Math.sqrt(-2.0 * Math.log(u)) * Math.cos(2.0 * Math.PI * v);
|
||||||
return mu + w * sigma;
|
return mu + w * sigma;
|
||||||
}
|
}
|
||||||
@ -291,11 +300,11 @@ export class RandomUtil
|
|||||||
*/
|
*/
|
||||||
public randInt(low: number, high?: number): number
|
public randInt(low: number, high?: number): number
|
||||||
{
|
{
|
||||||
if (high)
|
if (high)
|
||||||
{
|
{
|
||||||
return low + Math.floor(Math.random() * (high - low));
|
return low + Math.floor(Math.random() * (high - low));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return Math.floor(Math.random() * low);
|
return Math.floor(Math.random() * low);
|
||||||
}
|
}
|
||||||
@ -311,20 +320,20 @@ export class RandomUtil
|
|||||||
*/
|
*/
|
||||||
public drawRandomFromList<T>(list: Array<T>, count = 1, replacement = true): Array<T>
|
public drawRandomFromList<T>(list: Array<T>, count = 1, replacement = true): Array<T>
|
||||||
{
|
{
|
||||||
if (!replacement)
|
if (!replacement)
|
||||||
{
|
{
|
||||||
list = this.jsonUtil.clone(list);
|
list = this.jsonUtil.clone(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
const results = [];
|
const results = [];
|
||||||
for (let i = 0; i < count; i++)
|
for (let i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
const randomIndex = this.randInt(list.length);
|
const randomIndex = this.randInt(list.length);
|
||||||
if (replacement)
|
if (replacement)
|
||||||
{
|
{
|
||||||
results.push(list[randomIndex]);
|
results.push(list[randomIndex]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
results.push(list.splice(randomIndex, 1)[0]);
|
results.push(list.splice(randomIndex, 1)[0]);
|
||||||
}
|
}
|
||||||
@ -366,7 +375,7 @@ export class RandomUtil
|
|||||||
{
|
{
|
||||||
throw {
|
throw {
|
||||||
name: "Invalid arguments",
|
name: "Invalid arguments",
|
||||||
message: `Bounded random number generation max is smaller than min (${max} < ${min})`
|
message: `Bounded random number generation max is smaller than min (${max} < ${min})`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,7 +383,7 @@ export class RandomUtil
|
|||||||
{
|
{
|
||||||
throw {
|
throw {
|
||||||
name: "Invalid argument",
|
name: "Invalid argument",
|
||||||
message: `'n' must be 1 or greater (received ${n})`
|
message: `'n' must be 1 or greater (received ${n})`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -390,7 +399,9 @@ export class RandomUtil
|
|||||||
* A shift that is equal to the available range only has a 50% chance of rolling correctly, theoretically halving performance.
|
* A shift that is equal to the available range only has a 50% chance of rolling correctly, theoretically halving performance.
|
||||||
* Shifting even further drops the success chance very rapidly - so we want to warn against that */
|
* Shifting even further drops the success chance very rapidly - so we want to warn against that */
|
||||||
|
|
||||||
this.logger.warning("Bias shift for random number generation is greater than the range of available numbers.\nThis can have a very severe performance impact!");
|
this.logger.warning(
|
||||||
|
"Bias shift for random number generation is greater than the range of available numbers.\nThis can have a very severe performance impact!",
|
||||||
|
);
|
||||||
this.logger.info(`min -> ${min}; max -> ${max}; shift -> ${shift}`);
|
this.logger.info(`min -> ${min}; max -> ${max}; shift -> ${shift}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -433,19 +444,21 @@ export class RandomUtil
|
|||||||
{
|
{
|
||||||
let currentIndex = array.length;
|
let currentIndex = array.length;
|
||||||
let randomIndex: number;
|
let randomIndex: number;
|
||||||
|
|
||||||
// While there remain elements to shuffle.
|
// While there remain elements to shuffle.
|
||||||
while (currentIndex !== 0)
|
while (currentIndex !== 0)
|
||||||
{
|
{
|
||||||
// Pick a remaining element.
|
// Pick a remaining element.
|
||||||
randomIndex = Math.floor(Math.random() * currentIndex);
|
randomIndex = Math.floor(Math.random() * currentIndex);
|
||||||
currentIndex--;
|
currentIndex--;
|
||||||
|
|
||||||
// And swap it with the current element.
|
// And swap it with the current element.
|
||||||
[array[currentIndex], array[randomIndex]] = [
|
[array[currentIndex], array[randomIndex]] = [
|
||||||
array[randomIndex], array[currentIndex]];
|
array[randomIndex],
|
||||||
|
array[currentIndex],
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { injectable } from "tsyringe";
|
|
||||||
import { formatInTimeZone } from "date-fns-tz";
|
import { formatInTimeZone } from "date-fns-tz";
|
||||||
|
import { injectable } from "tsyringe";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility class to handle time related operations.
|
* Utility class to handle time related operations.
|
||||||
|
@ -1,30 +1,33 @@
|
|||||||
import "reflect-metadata";
|
import "reflect-metadata";
|
||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import fs from "node:fs";
|
|
||||||
import crypto from "node:crypto";
|
|
||||||
import { promisify } from "node:util";
|
|
||||||
import path, { resolve } from "node:path";
|
|
||||||
import { writeFileSync } from "atomically";
|
|
||||||
import lockfile from "proper-lockfile";
|
|
||||||
import { IAsyncQueue } from "@spt-aki/models/spt/utils/IAsyncQueue";
|
import { IAsyncQueue } from "@spt-aki/models/spt/utils/IAsyncQueue";
|
||||||
|
import { writeFileSync } from "atomically";
|
||||||
|
import crypto from "node:crypto";
|
||||||
|
import fs from "node:fs";
|
||||||
|
import path, { resolve } from "node:path";
|
||||||
|
import { promisify } from "node:util";
|
||||||
|
import lockfile from "proper-lockfile";
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export class VFS
|
export class VFS
|
||||||
{
|
{
|
||||||
accessFilePromisify: (path: fs.PathLike, mode?: number) => Promise<void>;
|
accessFilePromisify: (path: fs.PathLike, mode?: number) => Promise<void>;
|
||||||
copyFilePromisify: (src: fs.PathLike, dst: fs.PathLike, flags?: number) => Promise<void>;
|
copyFilePromisify: (src: fs.PathLike, dst: fs.PathLike, flags?: number) => Promise<void>;
|
||||||
mkdirPromisify: (path: fs.PathLike, options: fs.MakeDirectoryOptions & { recursive: true; }) => Promise<string>;
|
mkdirPromisify: (path: fs.PathLike, options: fs.MakeDirectoryOptions & {recursive: true;}) => Promise<string>;
|
||||||
readFilePromisify: (path: fs.PathLike) => Promise<Buffer>;
|
readFilePromisify: (path: fs.PathLike) => Promise<Buffer>;
|
||||||
writeFilePromisify: (path: fs.PathLike, data: string, options?: any) => Promise<void>;
|
writeFilePromisify: (path: fs.PathLike, data: string, options?: any) => Promise<void>;
|
||||||
readdirPromisify: (path: fs.PathLike, options?: BufferEncoding | { encoding: BufferEncoding; withFileTypes?: false; }) => Promise<string[]>;
|
readdirPromisify: (
|
||||||
statPromisify: (path: fs.PathLike, options?: fs.StatOptions & { bigint?: false; }) => Promise<fs.Stats>;
|
path: fs.PathLike,
|
||||||
|
options?: BufferEncoding | {encoding: BufferEncoding; withFileTypes?: false;},
|
||||||
|
) => Promise<string[]>;
|
||||||
|
statPromisify: (path: fs.PathLike, options?: fs.StatOptions & {bigint?: false;}) => Promise<fs.Stats>;
|
||||||
unlinkPromisify: (path: fs.PathLike) => Promise<void>;
|
unlinkPromisify: (path: fs.PathLike) => Promise<void>;
|
||||||
rmdirPromisify: (path: fs.PathLike) => Promise<void>;
|
rmdirPromisify: (path: fs.PathLike) => Promise<void>;
|
||||||
renamePromisify: (oldPath: fs.PathLike, newPath: fs.PathLike) => Promise<void>;
|
renamePromisify: (oldPath: fs.PathLike, newPath: fs.PathLike) => Promise<void>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@inject("AsyncQueue") protected asyncQueue: IAsyncQueue
|
@inject("AsyncQueue") protected asyncQueue: IAsyncQueue,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this.accessFilePromisify = promisify(fs.access);
|
this.accessFilePromisify = promisify(fs.access);
|
||||||
@ -51,7 +54,7 @@ export class VFS
|
|||||||
// Create the command to add to the queue
|
// Create the command to add to the queue
|
||||||
const command = {
|
const command = {
|
||||||
uuid: crypto.randomUUID(),
|
uuid: crypto.randomUUID(),
|
||||||
cmd: async () => await this.accessFilePromisify(filepath)
|
cmd: async () => await this.accessFilePromisify(filepath),
|
||||||
};
|
};
|
||||||
// Wait for the command completion
|
// Wait for the command completion
|
||||||
await this.asyncQueue.waitFor(command);
|
await this.asyncQueue.waitFor(command);
|
||||||
@ -75,21 +78,22 @@ export class VFS
|
|||||||
{
|
{
|
||||||
const command = {
|
const command = {
|
||||||
uuid: crypto.randomUUID(),
|
uuid: crypto.randomUUID(),
|
||||||
cmd: async () => await this.copyFilePromisify(filepath, target)
|
cmd: async () => await this.copyFilePromisify(filepath, target),
|
||||||
};
|
};
|
||||||
await this.asyncQueue.waitFor(command);
|
await this.asyncQueue.waitFor(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
public createDir(filepath: string): void
|
public createDir(filepath: string): void
|
||||||
{
|
{
|
||||||
fs.mkdirSync(filepath.substr(0, filepath.lastIndexOf("/")), { recursive: true });
|
fs.mkdirSync(filepath.substr(0, filepath.lastIndexOf("/")), {recursive: true});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async createDirAsync(filepath: string): Promise<void>
|
public async createDirAsync(filepath: string): Promise<void>
|
||||||
{
|
{
|
||||||
const command = {
|
const command = {
|
||||||
uuid: crypto.randomUUID(),
|
uuid: crypto.randomUUID(),
|
||||||
cmd: async () => await this.mkdirPromisify(filepath.substr(0, filepath.lastIndexOf("/")), { recursive: true })
|
cmd: async () =>
|
||||||
|
await this.mkdirPromisify(filepath.substr(0, filepath.lastIndexOf("/")), {recursive: true}),
|
||||||
};
|
};
|
||||||
await this.asyncQueue.waitFor(command);
|
await this.asyncQueue.waitFor(command);
|
||||||
}
|
}
|
||||||
@ -148,7 +152,9 @@ export class VFS
|
|||||||
{
|
{
|
||||||
const read = fs.readFileSync(...args);
|
const read = fs.readFileSync(...args);
|
||||||
if (this.isBuffer(read))
|
if (this.isBuffer(read))
|
||||||
|
{
|
||||||
return read.toString();
|
return read.toString();
|
||||||
|
}
|
||||||
return read;
|
return read;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,7 +162,9 @@ export class VFS
|
|||||||
{
|
{
|
||||||
const read = await this.readFilePromisify(path);
|
const read = await this.readFilePromisify(path);
|
||||||
if (this.isBuffer(read))
|
if (this.isBuffer(read))
|
||||||
|
{
|
||||||
return read.toString();
|
return read.toString();
|
||||||
|
}
|
||||||
return read;
|
return read;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,7 +175,7 @@ export class VFS
|
|||||||
|
|
||||||
public writeFile(filepath: any, data = "", append = false, atomic = true): void
|
public writeFile(filepath: any, data = "", append = false, atomic = true): void
|
||||||
{
|
{
|
||||||
const options = append ? { flag: "a" } : { flag: "w" };
|
const options = append ? {flag: "a"} : {flag: "w"};
|
||||||
|
|
||||||
if (!this.exists(filepath))
|
if (!this.exists(filepath))
|
||||||
{
|
{
|
||||||
@ -194,7 +202,7 @@ export class VFS
|
|||||||
|
|
||||||
public async writeFileAsync(filepath: any, data = "", append = false, atomic = true): Promise<void>
|
public async writeFileAsync(filepath: any, data = "", append = false, atomic = true): Promise<void>
|
||||||
{
|
{
|
||||||
const options = append ? { flag: "a" } : { flag: "w" };
|
const options = append ? {flag: "a"} : {flag: "w"};
|
||||||
|
|
||||||
if (!await this.exists(filepath))
|
if (!await this.exists(filepath))
|
||||||
{
|
{
|
||||||
@ -230,7 +238,6 @@ export class VFS
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public getDirs(filepath: string): string[]
|
public getDirs(filepath: string): string[]
|
||||||
{
|
{
|
||||||
return fs.readdirSync(filepath).filter((item) =>
|
return fs.readdirSync(filepath).filter((item) =>
|
||||||
@ -377,7 +384,7 @@ export class VFS
|
|||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
const dirents = fs.readdirSync(directory, { encoding: "utf-8", withFileTypes: true });
|
const dirents = fs.readdirSync(directory, {encoding: "utf-8", withFileTypes: true});
|
||||||
for (const dirent of dirents)
|
for (const dirent of dirents)
|
||||||
{
|
{
|
||||||
const res = resolve(directory, dirent.name);
|
const res = resolve(directory, dirent.name);
|
||||||
|
@ -15,7 +15,7 @@ export class WatermarkLocale
|
|||||||
protected modding: string[];
|
protected modding: string[];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@inject("LocalisationService") protected localisationService: LocalisationService
|
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this.description = [
|
this.description = [
|
||||||
@ -23,7 +23,7 @@ export class WatermarkLocale
|
|||||||
"",
|
"",
|
||||||
this.localisationService.getText("watermark-free_of_charge"),
|
this.localisationService.getText("watermark-free_of_charge"),
|
||||||
this.localisationService.getText("watermark-paid_scammed"),
|
this.localisationService.getText("watermark-paid_scammed"),
|
||||||
this.localisationService.getText("watermark-commercial_use_prohibited")
|
this.localisationService.getText("watermark-commercial_use_prohibited"),
|
||||||
];
|
];
|
||||||
this.warning = [
|
this.warning = [
|
||||||
"",
|
"",
|
||||||
@ -33,14 +33,14 @@ export class WatermarkLocale
|
|||||||
`${this.localisationService.getText("watermark-report_issues_to")}:`,
|
`${this.localisationService.getText("watermark-report_issues_to")}:`,
|
||||||
this.localisationService.getText("watermark-issue_tracker_url"),
|
this.localisationService.getText("watermark-issue_tracker_url"),
|
||||||
"",
|
"",
|
||||||
this.localisationService.getText("watermark-use_at_own_risk")
|
this.localisationService.getText("watermark-use_at_own_risk"),
|
||||||
];
|
];
|
||||||
this.modding = [
|
this.modding = [
|
||||||
"",
|
"",
|
||||||
this.localisationService.getText("watermark-modding_disabled"),
|
this.localisationService.getText("watermark-modding_disabled"),
|
||||||
"",
|
"",
|
||||||
this.localisationService.getText("watermark-not_an_issue"),
|
this.localisationService.getText("watermark-not_an_issue"),
|
||||||
this.localisationService.getText("watermark-do_not_report")
|
this.localisationService.getText("watermark-do_not_report"),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,7 +71,7 @@ export class Watermark
|
|||||||
@inject("WinstonLogger") protected logger: ILogger,
|
@inject("WinstonLogger") protected logger: ILogger,
|
||||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||||
@inject("WatermarkLocale") protected watermarkLocale?: WatermarkLocale
|
@inject("WatermarkLocale") protected watermarkLocale?: WatermarkLocale,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this.akiConfig = this.configServer.getConfig<ICoreConfig>(ConfigTypes.CORE);
|
this.akiConfig = this.configServer.getConfig<ICoreConfig>(ConfigTypes.CORE);
|
||||||
@ -110,9 +110,9 @@ export class Watermark
|
|||||||
*/
|
*/
|
||||||
public getVersionTag(withEftVersion = false): string
|
public getVersionTag(withEftVersion = false): string
|
||||||
{
|
{
|
||||||
const versionTag = (globalThis.G_DEBUG_CONFIGURATION)
|
const versionTag = (globalThis.G_DEBUG_CONFIGURATION) ?
|
||||||
? `${this.akiConfig.akiVersion} - ${this.localisationService.getText("bleeding_edge_build")}`
|
`${this.akiConfig.akiVersion} - ${this.localisationService.getText("bleeding_edge_build")}` :
|
||||||
: this.akiConfig.akiVersion;
|
this.akiConfig.akiVersion;
|
||||||
|
|
||||||
if (withEftVersion)
|
if (withEftVersion)
|
||||||
{
|
{
|
||||||
@ -130,9 +130,9 @@ export class Watermark
|
|||||||
*/
|
*/
|
||||||
public getInGameVersionLabel(): string
|
public getInGameVersionLabel(): string
|
||||||
{
|
{
|
||||||
const versionTag = (globalThis.G_DEBUG_CONFIGURATION)
|
const versionTag = (globalThis.G_DEBUG_CONFIGURATION) ?
|
||||||
? `${this.akiConfig.akiVersion} - BLEEDINGEDGE`
|
`${this.akiConfig.akiVersion} - BLEEDINGEDGE` :
|
||||||
: this.akiConfig.akiVersion;
|
this.akiConfig.akiVersion;
|
||||||
|
|
||||||
return `${this.akiConfig.projectName} ${versionTag}`;
|
return `${this.akiConfig.projectName} ${versionTag}`;
|
||||||
}
|
}
|
||||||
|
@ -3,19 +3,19 @@ export class LinkedList<T>
|
|||||||
private head: LinkedListNode<T>;
|
private head: LinkedListNode<T>;
|
||||||
private tail: LinkedListNode<T>;
|
private tail: LinkedListNode<T>;
|
||||||
|
|
||||||
public add(t: T): void
|
public add(t: T): void
|
||||||
{
|
{
|
||||||
if (!this.head)
|
if (!this.head)
|
||||||
{
|
{
|
||||||
const node = new LinkedListNode(t);
|
const node = new LinkedListNode(t);
|
||||||
this.head = node;
|
this.head = node;
|
||||||
this.tail = node;
|
this.tail = node;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
let ref = this.head;
|
let ref = this.head;
|
||||||
let next = this.head.getNextNode();
|
let next = this.head.getNextNode();
|
||||||
while (next)
|
while (next)
|
||||||
{
|
{
|
||||||
ref = next;
|
ref = next;
|
||||||
next = ref.getNextNode();
|
next = ref.getNextNode();
|
||||||
@ -26,34 +26,34 @@ export class LinkedList<T>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public addRange(list: T[]): void
|
public addRange(list: T[]): void
|
||||||
{
|
{
|
||||||
for (const item of list)
|
for (const item of list)
|
||||||
{
|
{
|
||||||
this.add(item);
|
this.add(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public getHead(): LinkedListNode<T>
|
public getHead(): LinkedListNode<T>
|
||||||
{
|
{
|
||||||
return this.head;
|
return this.head;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getTail(): LinkedListNode<T>
|
public getTail(): LinkedListNode<T>
|
||||||
{
|
{
|
||||||
return this.tail;
|
return this.tail;
|
||||||
}
|
}
|
||||||
|
|
||||||
public isEmpty(): boolean
|
public isEmpty(): boolean
|
||||||
{
|
{
|
||||||
return this.head === undefined || this.head === null;
|
return this.head === undefined || this.head === null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSize(): number
|
public getSize(): number
|
||||||
{
|
{
|
||||||
let size = 0;
|
let size = 0;
|
||||||
let next = this.head;
|
let next = this.head;
|
||||||
while (next)
|
while (next)
|
||||||
{
|
{
|
||||||
size++;
|
size++;
|
||||||
next = next.getNextNode();
|
next = next.getNextNode();
|
||||||
@ -61,41 +61,47 @@ export class LinkedList<T>
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeFirst(): LinkedListNode<T>
|
public removeFirst(): LinkedListNode<T>
|
||||||
{
|
{
|
||||||
if (!this.head) return undefined;
|
if (!this.head)
|
||||||
|
{
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
const node = this.head;
|
const node = this.head;
|
||||||
if (this.head.getNextNode())
|
if (this.head.getNextNode())
|
||||||
{
|
{
|
||||||
this.head = this.head.getNextNode();
|
this.head = this.head.getNextNode();
|
||||||
this.head.setPreviousNode(undefined);
|
this.head.setPreviousNode(undefined);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this.head = undefined;
|
this.head = undefined;
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeLast(): LinkedListNode<T>
|
public removeLast(): LinkedListNode<T>
|
||||||
{
|
{
|
||||||
if (!this.tail) return undefined;
|
if (!this.tail)
|
||||||
|
{
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
const node = this.tail;
|
const node = this.tail;
|
||||||
if (this.tail.getPreviousNode())
|
if (this.tail.getPreviousNode())
|
||||||
{
|
{
|
||||||
this.tail = this.tail.getPreviousNode();
|
this.tail = this.tail.getPreviousNode();
|
||||||
this.tail.setNextNode(undefined);
|
this.tail.setNextNode(undefined);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this.tail = undefined;
|
this.tail = undefined;
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
public indexOf(func: (t:T) => boolean): number
|
public indexOf(func: (t: T) => boolean): number
|
||||||
{
|
{
|
||||||
const node = this.head;
|
const node = this.head;
|
||||||
let index = 0;
|
let index = 0;
|
||||||
@ -110,7 +116,7 @@ export class LinkedList<T>
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
public contains(func: (t:T) => boolean): boolean
|
public contains(func: (t: T) => boolean): boolean
|
||||||
{
|
{
|
||||||
let node = this.head;
|
let node = this.head;
|
||||||
while (node)
|
while (node)
|
||||||
@ -124,7 +130,7 @@ export class LinkedList<T>
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public forEachNode(func: (t:LinkedListNode<T>) => void): void
|
public forEachNode(func: (t: LinkedListNode<T>) => void): void
|
||||||
{
|
{
|
||||||
let node = this.head;
|
let node = this.head;
|
||||||
while (node)
|
while (node)
|
||||||
@ -134,7 +140,7 @@ export class LinkedList<T>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public forEachValue(func: (t:T) => void): void
|
public forEachValue(func: (t: T) => void): void
|
||||||
{
|
{
|
||||||
let node = this.head;
|
let node = this.head;
|
||||||
while (node)
|
while (node)
|
||||||
@ -144,7 +150,7 @@ export class LinkedList<T>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public findFirstNode(func: (t:LinkedListNode<T>) => boolean): LinkedListNode<T>
|
public findFirstNode(func: (t: LinkedListNode<T>) => boolean): LinkedListNode<T>
|
||||||
{
|
{
|
||||||
let node = this.head;
|
let node = this.head;
|
||||||
while (node)
|
while (node)
|
||||||
@ -158,7 +164,7 @@ export class LinkedList<T>
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
public findFirstValue(func: (t:T) => boolean): T
|
public findFirstValue(func: (t: T) => boolean): T
|
||||||
{
|
{
|
||||||
let node = this.head;
|
let node = this.head;
|
||||||
while (node)
|
while (node)
|
||||||
@ -191,35 +197,35 @@ export class LinkedListNode<T>
|
|||||||
private value: T;
|
private value: T;
|
||||||
private next: LinkedListNode<T>;
|
private next: LinkedListNode<T>;
|
||||||
|
|
||||||
constructor(value: T, previous: LinkedListNode<T> = undefined, next: LinkedListNode<T> = undefined)
|
constructor(value: T, previous: LinkedListNode<T> = undefined, next: LinkedListNode<T> = undefined)
|
||||||
{
|
{
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.previous = previous;
|
this.previous = previous;
|
||||||
this.next = next;
|
this.next = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getValue(): T
|
public getValue(): T
|
||||||
{
|
{
|
||||||
return this.value;
|
return this.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getNextNode(): LinkedListNode<T>
|
public getNextNode(): LinkedListNode<T>
|
||||||
{
|
{
|
||||||
return this.next;
|
return this.next;
|
||||||
}
|
}
|
||||||
|
|
||||||
public setNextNode(node: LinkedListNode<T>): void
|
public setNextNode(node: LinkedListNode<T>): void
|
||||||
{
|
{
|
||||||
this.next = node;
|
this.next = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getPreviousNode(): LinkedListNode<T>
|
public getPreviousNode(): LinkedListNode<T>
|
||||||
{
|
{
|
||||||
return this.previous;
|
return this.previous;
|
||||||
}
|
}
|
||||||
|
|
||||||
public setPreviousNode(node: LinkedListNode<T>): void
|
public setPreviousNode(node: LinkedListNode<T>): void
|
||||||
{
|
{
|
||||||
this.previous = node;
|
this.previous = node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,21 +3,20 @@ export class Queue<T>
|
|||||||
private elements: Record<number, T>;
|
private elements: Record<number, T>;
|
||||||
private head: number;
|
private head: number;
|
||||||
private tail: number;
|
private tail: number;
|
||||||
constructor()
|
constructor()
|
||||||
|
|
||||||
{
|
{
|
||||||
this.elements = {};
|
this.elements = {};
|
||||||
this.head = 0;
|
this.head = 0;
|
||||||
this.tail = 0;
|
this.tail = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public enqueue(element: T): void
|
public enqueue(element: T): void
|
||||||
{
|
{
|
||||||
this.elements[this.tail] = element;
|
this.elements[this.tail] = element;
|
||||||
this.tail++;
|
this.tail++;
|
||||||
}
|
}
|
||||||
|
|
||||||
public enqueueAll(elements: T[]): void
|
public enqueueAll(elements: T[]): void
|
||||||
{
|
{
|
||||||
for (const element of elements)
|
for (const element of elements)
|
||||||
{
|
{
|
||||||
@ -25,7 +24,7 @@ export class Queue<T>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public dequeue(): T
|
public dequeue(): T
|
||||||
{
|
{
|
||||||
const item = this.elements[this.head];
|
const item = this.elements[this.head];
|
||||||
delete this.elements[this.head];
|
delete this.elements[this.head];
|
||||||
@ -33,11 +32,11 @@ export class Queue<T>
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
public peek():T
|
public peek(): T
|
||||||
{
|
{
|
||||||
return this.elements[this.head];
|
return this.elements[this.head];
|
||||||
}
|
}
|
||||||
public getLength(): number
|
public getLength(): number
|
||||||
{
|
{
|
||||||
return this.tail - this.head;
|
return this.tail - this.head;
|
||||||
}
|
}
|
||||||
@ -46,4 +45,4 @@ export class Queue<T>
|
|||||||
{
|
{
|
||||||
return this.getLength() === 0;
|
return this.getLength() === 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import fs from "node:fs";
|
|
||||||
import crypto from "node:crypto";
|
import crypto from "node:crypto";
|
||||||
|
import fs from "node:fs";
|
||||||
import { promisify } from "node:util";
|
import { promisify } from "node:util";
|
||||||
import winston, { createLogger, format, transports } from "winston";
|
import winston, { createLogger, format, transports } from "winston";
|
||||||
import DailyRotateFile from "winston-daily-rotate-file";
|
import DailyRotateFile from "winston-daily-rotate-file";
|
||||||
@ -23,7 +23,7 @@ export abstract class AbstractWinstonLogger implements ILogger
|
|||||||
succ: 2,
|
succ: 2,
|
||||||
info: 3,
|
info: 3,
|
||||||
custom: 4,
|
custom: 4,
|
||||||
debug: 5
|
debug: 5,
|
||||||
},
|
},
|
||||||
colors: {
|
colors: {
|
||||||
error: "red",
|
error: "red",
|
||||||
@ -31,7 +31,7 @@ export abstract class AbstractWinstonLogger implements ILogger
|
|||||||
succ: "green",
|
succ: "green",
|
||||||
info: "white",
|
info: "white",
|
||||||
custom: "black",
|
custom: "black",
|
||||||
debug: "gray"
|
debug: "gray",
|
||||||
},
|
},
|
||||||
bgColors: {
|
bgColors: {
|
||||||
default: "",
|
default: "",
|
||||||
@ -42,14 +42,14 @@ export abstract class AbstractWinstonLogger implements ILogger
|
|||||||
blueBG: "blueBG",
|
blueBG: "blueBG",
|
||||||
magentaBG: "magentaBG",
|
magentaBG: "magentaBG",
|
||||||
cyanBG: "cyanBG",
|
cyanBG: "cyanBG",
|
||||||
whiteBG: "whiteBG"
|
whiteBG: "whiteBG",
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
protected logger: winston.Logger & SptLogger;
|
protected logger: winston.Logger & SptLogger;
|
||||||
protected writeFilePromisify: (path: fs.PathLike, data: string, options?: any) => Promise<void>;
|
protected writeFilePromisify: (path: fs.PathLike, data: string, options?: any) => Promise<void>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected asyncQueue: IAsyncQueue
|
protected asyncQueue: IAsyncQueue,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this.filePath = `${this.getFilePath()}${this.getFileName()}`;
|
this.filePath = `${this.getFilePath()}${this.getFileName()}`;
|
||||||
@ -57,7 +57,7 @@ export abstract class AbstractWinstonLogger implements ILogger
|
|||||||
this.showDebugInConsole = globalThis.G_DEBUG_CONFIGURATION;
|
this.showDebugInConsole = globalThis.G_DEBUG_CONFIGURATION;
|
||||||
if (!fs.existsSync(this.getFilePath()))
|
if (!fs.existsSync(this.getFilePath()))
|
||||||
{
|
{
|
||||||
fs.mkdirSync(this.getFilePath(), { recursive: true });
|
fs.mkdirSync(this.getFilePath(), {recursive: true});
|
||||||
}
|
}
|
||||||
|
|
||||||
const transportsList: winston.transport[] = [];
|
const transportsList: winston.transport[] = [];
|
||||||
@ -68,13 +68,13 @@ export abstract class AbstractWinstonLogger implements ILogger
|
|||||||
new transports.Console({
|
new transports.Console({
|
||||||
level: this.showDebugInConsole ? "debug" : "custom",
|
level: this.showDebugInConsole ? "debug" : "custom",
|
||||||
format: format.combine(
|
format: format.combine(
|
||||||
format.colorize({ all: true, colors: this.logLevels.colors }),
|
format.colorize({all: true, colors: this.logLevels.colors}),
|
||||||
format.printf(({ message }) =>
|
format.printf(({message}) =>
|
||||||
{
|
{
|
||||||
return `${message}`;
|
return `${message}`;
|
||||||
})
|
}),
|
||||||
)
|
),
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (this.isLogToFile())
|
if (this.isLogToFile())
|
||||||
@ -91,19 +91,19 @@ export abstract class AbstractWinstonLogger implements ILogger
|
|||||||
format.timestamp(),
|
format.timestamp(),
|
||||||
format.align(),
|
format.align(),
|
||||||
format.json(),
|
format.json(),
|
||||||
format.printf(({ timestamp, level, message }) =>
|
format.printf(({timestamp, level, message}) =>
|
||||||
{
|
{
|
||||||
return `[${timestamp}] ${level}: ${message}`;
|
return `[${timestamp}] ${level}: ${message}`;
|
||||||
})
|
}),
|
||||||
)
|
),
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
winston.addColors(this.logLevels.colors);
|
winston.addColors(this.logLevels.colors);
|
||||||
this.logger = createLogger({
|
this.logger = createLogger({
|
||||||
levels: this.logLevels.levels,
|
levels: this.logLevels.levels,
|
||||||
transports: [...transportsList]
|
transports: [...transportsList],
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.isLogExceptions())
|
if (this.isLogExceptions())
|
||||||
@ -140,39 +140,41 @@ export abstract class AbstractWinstonLogger implements ILogger
|
|||||||
{
|
{
|
||||||
const command: ICommand = {
|
const command: ICommand = {
|
||||||
uuid: crypto.randomUUID(),
|
uuid: crypto.randomUUID(),
|
||||||
cmd: async () => await this.writeFilePromisify(this.filePath, `${data}\n`, true)
|
cmd: async () => await this.writeFilePromisify(this.filePath, `${data}\n`, true),
|
||||||
};
|
};
|
||||||
await this.asyncQueue.waitFor(command);
|
await this.asyncQueue.waitFor(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async log(data: string | Error | Record<string, unknown>, color: string, backgroundColor = "" ): Promise<void>
|
public async log(data: string | Error | Record<string, unknown>, color: string, backgroundColor = ""): Promise<void>
|
||||||
{
|
{
|
||||||
const textColor = `${color} ${backgroundColor}`.trimEnd();
|
const textColor = `${color} ${backgroundColor}`.trimEnd();
|
||||||
const tmpLogger = createLogger({
|
const tmpLogger = createLogger({
|
||||||
levels: { custom: 0 },
|
levels: {custom: 0},
|
||||||
level: "custom",
|
level: "custom",
|
||||||
transports: [new transports.Console({
|
transports: [
|
||||||
format: format.combine(
|
new transports.Console({
|
||||||
format.colorize({ all: true, colors: { custom: textColor } }),
|
format: format.combine(
|
||||||
format.printf(({ message }) => message)
|
format.colorize({all: true, colors: {custom: textColor}}),
|
||||||
)
|
format.printf(({message}) => message),
|
||||||
})]
|
),
|
||||||
|
}),
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
let command: ICommand;
|
let command: ICommand;
|
||||||
|
|
||||||
if (typeof (data) === "string")
|
if (typeof data === "string")
|
||||||
{
|
{
|
||||||
command = {
|
command = {
|
||||||
uuid: crypto.randomUUID(),
|
uuid: crypto.randomUUID(),
|
||||||
cmd: async () => await tmpLogger.log("custom", data)
|
cmd: async () => await tmpLogger.log("custom", data),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
command = {
|
command = {
|
||||||
uuid: crypto.randomUUID(),
|
uuid: crypto.randomUUID(),
|
||||||
cmd: async () => await tmpLogger.log("custom", JSON.stringify(data, null, 4))
|
cmd: async () => await tmpLogger.log("custom", JSON.stringify(data, null, 4)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,7 +185,7 @@ export abstract class AbstractWinstonLogger implements ILogger
|
|||||||
{
|
{
|
||||||
const command: ICommand = {
|
const command: ICommand = {
|
||||||
uuid: crypto.randomUUID(),
|
uuid: crypto.randomUUID(),
|
||||||
cmd: async () => await this.logger.error(data)
|
cmd: async () => await this.logger.error(data),
|
||||||
};
|
};
|
||||||
await this.asyncQueue.waitFor(command);
|
await this.asyncQueue.waitFor(command);
|
||||||
}
|
}
|
||||||
@ -192,7 +194,7 @@ export abstract class AbstractWinstonLogger implements ILogger
|
|||||||
{
|
{
|
||||||
const command: ICommand = {
|
const command: ICommand = {
|
||||||
uuid: crypto.randomUUID(),
|
uuid: crypto.randomUUID(),
|
||||||
cmd: async () => await this.logger.warn(data)
|
cmd: async () => await this.logger.warn(data),
|
||||||
};
|
};
|
||||||
await this.asyncQueue.waitFor(command);
|
await this.asyncQueue.waitFor(command);
|
||||||
}
|
}
|
||||||
@ -201,7 +203,7 @@ export abstract class AbstractWinstonLogger implements ILogger
|
|||||||
{
|
{
|
||||||
const command: ICommand = {
|
const command: ICommand = {
|
||||||
uuid: crypto.randomUUID(),
|
uuid: crypto.randomUUID(),
|
||||||
cmd: async () => await this.logger.succ(data)
|
cmd: async () => await this.logger.succ(data),
|
||||||
};
|
};
|
||||||
await this.asyncQueue.waitFor(command);
|
await this.asyncQueue.waitFor(command);
|
||||||
}
|
}
|
||||||
@ -210,7 +212,7 @@ export abstract class AbstractWinstonLogger implements ILogger
|
|||||||
{
|
{
|
||||||
const command: ICommand = {
|
const command: ICommand = {
|
||||||
uuid: crypto.randomUUID(),
|
uuid: crypto.randomUUID(),
|
||||||
cmd: async () => await this.logger.info(data)
|
cmd: async () => await this.logger.info(data),
|
||||||
};
|
};
|
||||||
await this.asyncQueue.waitFor(command);
|
await this.asyncQueue.waitFor(command);
|
||||||
}
|
}
|
||||||
@ -221,11 +223,15 @@ export abstract class AbstractWinstonLogger implements ILogger
|
|||||||
* @param textColor color of text
|
* @param textColor color of text
|
||||||
* @param backgroundColor color of background
|
* @param backgroundColor color of background
|
||||||
*/
|
*/
|
||||||
public async logWithColor(data: string | Record<string, unknown>, textColor: LogTextColor, backgroundColor = LogBackgroundColor.DEFAULT): Promise<void>
|
public async logWithColor(
|
||||||
|
data: string | Record<string, unknown>,
|
||||||
|
textColor: LogTextColor,
|
||||||
|
backgroundColor = LogBackgroundColor.DEFAULT,
|
||||||
|
): Promise<void>
|
||||||
{
|
{
|
||||||
const command: ICommand = {
|
const command: ICommand = {
|
||||||
uuid: crypto.randomUUID(),
|
uuid: crypto.randomUUID(),
|
||||||
cmd: async () => await this.log(data, textColor.toString(), backgroundColor.toString())
|
cmd: async () => await this.log(data, textColor.toString(), backgroundColor.toString()),
|
||||||
};
|
};
|
||||||
|
|
||||||
await this.asyncQueue.waitFor(command);
|
await this.asyncQueue.waitFor(command);
|
||||||
@ -239,14 +245,14 @@ export abstract class AbstractWinstonLogger implements ILogger
|
|||||||
{
|
{
|
||||||
command = {
|
command = {
|
||||||
uuid: crypto.randomUUID(),
|
uuid: crypto.randomUUID(),
|
||||||
cmd: async () => await this.log(data, this.logLevels.colors.debug)
|
cmd: async () => await this.log(data, this.logLevels.colors.debug),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
command = {
|
command = {
|
||||||
uuid: crypto.randomUUID(),
|
uuid: crypto.randomUUID(),
|
||||||
cmd: async () => await this.logger.debug(data)
|
cmd: async () => await this.logger.debug(data),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import { AbstractWinstonLogger } from "@spt-aki/utils/logging/AbstractWinstonLog
|
|||||||
export class WinstonMainLogger extends AbstractWinstonLogger
|
export class WinstonMainLogger extends AbstractWinstonLogger
|
||||||
{
|
{
|
||||||
constructor(
|
constructor(
|
||||||
@inject("AsyncQueue") protected asyncQueue: IAsyncQueue
|
@inject("AsyncQueue") protected asyncQueue: IAsyncQueue,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
super(asyncQueue);
|
super(asyncQueue);
|
||||||
|
@ -7,7 +7,7 @@ import { AbstractWinstonLogger } from "@spt-aki/utils/logging/AbstractWinstonLog
|
|||||||
export class WinstonRequestLogger extends AbstractWinstonLogger
|
export class WinstonRequestLogger extends AbstractWinstonLogger
|
||||||
{
|
{
|
||||||
constructor(
|
constructor(
|
||||||
@inject("AsyncQueue") protected asyncQueue: IAsyncQueue
|
@inject("AsyncQueue") protected asyncQueue: IAsyncQueue,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
super(asyncQueue);
|
super(asyncQueue);
|
||||||
|
Loading…
Reference in New Issue
Block a user