mirror of
https://github.com/sp-tarkov/server.git
synced 2025-02-12 15:50:42 -05:00
Add MongoID validation to databaseService
- Validate that quests, traders, items and customizations all have MongoID IDs - If any validation fails, output an error and stop server startup
This commit is contained in:
parent
8e8b97ac26
commit
9a8cf9a8a9
@ -66,6 +66,7 @@
|
||||
"customisation-unable_to_find_suit_with_id": "Unable to find suit with offer id: %s",
|
||||
"customisation-unable_to_get_trader_suits": "Unable to get suits from trader: %s",
|
||||
"database-data_at_path_missing": "The database was unable to retrieve data from: [%s] Please ensure your configs are valid and the data at the location exists",
|
||||
"database-invalid_data": "Invalid data detected in database, please remove any outdated mods. See previous error for invalid data. Server stopped.",
|
||||
"database-no_location_found_with_id": "No location found with an Id of: %s in database",
|
||||
"database-no_trader_found_with_id": "Unable to find trader: %s in database",
|
||||
"dialog-chatbot_id_already_exists": "Chat bot: %s being registered already exists, unable to register bot",
|
||||
|
@ -6,11 +6,11 @@ import { ConfigTypes } from "@spt/models/enums/ConfigTypes";
|
||||
import { IHttpConfig } from "@spt/models/spt/config/IHttpConfig";
|
||||
import { ILogger } from "@spt/models/spt/utils/ILogger";
|
||||
import { ConfigServer } from "@spt/servers/ConfigServer";
|
||||
import { DatabaseServer } from "@spt/servers/DatabaseServer";
|
||||
import { WebSocketServer } from "@spt/servers/WebSocketServer";
|
||||
import { IHttpListener } from "@spt/servers/http/IHttpListener";
|
||||
import { LocalisationService } from "@spt/services/LocalisationService";
|
||||
import { inject, injectAll, injectable } from "tsyringe";
|
||||
import { DatabaseService } from "@spt/services/DatabaseService";
|
||||
|
||||
@injectable()
|
||||
export class HttpServer {
|
||||
@ -19,7 +19,7 @@ export class HttpServer {
|
||||
|
||||
constructor(
|
||||
@inject("PrimaryLogger") protected logger: ILogger,
|
||||
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
||||
@inject("DatabaseService") protected databaseService: DatabaseService,
|
||||
@inject("HttpServerHelper") protected httpServerHelper: HttpServerHelper,
|
||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||
@injectAll("HttpListener") protected httpListeners: IHttpListener[],
|
||||
@ -36,6 +36,12 @@ export class HttpServer {
|
||||
public load(): void {
|
||||
this.started = false;
|
||||
|
||||
// If the database couldn't be validated, don't start the server
|
||||
if (!this.databaseService.isDatabaseValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* create server */
|
||||
const httpServer: Server = http.createServer();
|
||||
|
||||
|
@ -21,16 +21,19 @@ import { ITemplates } from "@spt/models/spt/templates/ITemplates";
|
||||
import { ILogger } from "@spt/models/spt/utils/ILogger";
|
||||
import { DatabaseServer } from "@spt/servers/DatabaseServer";
|
||||
import { LocalisationService } from "@spt/services/LocalisationService";
|
||||
import { HashUtil } from "@spt/utils/HashUtil";
|
||||
import { inject, injectable } from "tsyringe";
|
||||
|
||||
@injectable()
|
||||
export class DatabaseService {
|
||||
protected locationConfig: ILocationConfig;
|
||||
protected isDataValid: boolean;
|
||||
|
||||
constructor(
|
||||
@inject("PrimaryLogger") protected logger: ILogger,
|
||||
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||
@inject("HashUtil") protected hashUtil: HashUtil,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@ -322,4 +325,53 @@ export class DatabaseService {
|
||||
|
||||
return this.databaseServer.getTables().templates.locationServices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that the database doesn't contain invalid ID data
|
||||
*/
|
||||
public validateDatabase(): void {
|
||||
const start = performance.now();
|
||||
|
||||
this.isDataValid =
|
||||
this.validateTable(this.getQuests(), 'quest') &&
|
||||
this.validateTable(this.getTraders(), 'trader') &&
|
||||
this.validateTable(this.getItems(), 'item') &&
|
||||
this.validateTable(this.getCustomization(), 'customization');
|
||||
|
||||
if (!this.isDataValid)
|
||||
{
|
||||
this.logger.error(this.localisationService.getText("database-invalid_data"));
|
||||
}
|
||||
|
||||
const validateTime = performance.now() - start
|
||||
this.logger.debug(`ID validation took: ${validateTime.toFixed(2)}ms`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the given table only contains valid MongoIDs
|
||||
* @param table Table to validate for MongoIDs
|
||||
* @param tableType The type of table, used in output message
|
||||
* @returns True if the table only contains valid data
|
||||
*/
|
||||
private validateTable(table: Record<string, any>, tableType: string): boolean
|
||||
{
|
||||
for (const tableId in table)
|
||||
{
|
||||
if (!this.hashUtil.isValidMongoId(tableId))
|
||||
{
|
||||
this.logger.error(`Invalid ${tableType} ID: '${tableId}'`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the database is valid
|
||||
* @returns True if the database contains valid data, false otherwise
|
||||
*/
|
||||
public isDatabaseValid(): boolean {
|
||||
return this.isDataValid;
|
||||
}
|
||||
}
|
||||
|
@ -57,6 +57,15 @@ export class PostDbLoadService {
|
||||
// add items gets left out,causing warnings
|
||||
this.itemBaseClassService.hydrateItemBaseClassCache();
|
||||
|
||||
// Validate that only mongoIds exist in items, quests, and traders
|
||||
// Kill the startup if not.
|
||||
// TODO: We can probably remove this in a couple versions
|
||||
this.databaseService.validateDatabase();
|
||||
if (!this.databaseService.isDatabaseValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.addCustomLooseLootPositions();
|
||||
|
||||
this.adjustMinReserveRaiderSpawnChance();
|
||||
|
@ -10,6 +10,7 @@ import { LocalisationService } from "@spt/services/LocalisationService";
|
||||
import { EncodingUtil } from "@spt/utils/EncodingUtil";
|
||||
import { TimeUtil } from "@spt/utils/TimeUtil";
|
||||
import { inject, injectAll, injectable } from "tsyringe";
|
||||
import { DatabaseService } from "@spt/services/DatabaseService";
|
||||
|
||||
@injectable()
|
||||
export class App {
|
||||
@ -23,6 +24,7 @@ export class App {
|
||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||
@inject("EncodingUtil") protected encodingUtil: EncodingUtil,
|
||||
@inject("HttpServer") protected httpServer: HttpServer,
|
||||
@inject("DatabaseService") protected databaseService: DatabaseService,
|
||||
@injectAll("OnLoad") protected onLoadComponents: OnLoad[],
|
||||
@injectAll("OnUpdate") protected onUpdateComponents: OnUpdate[],
|
||||
) {
|
||||
@ -58,7 +60,7 @@ export class App {
|
||||
|
||||
protected async update(onUpdateComponents: OnUpdate[]): Promise<void> {
|
||||
// If the server has failed to start, skip any update calls
|
||||
if (!this.httpServer.isStarted()) {
|
||||
if (!this.httpServer.isStarted() || !this.databaseService.isDatabaseValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user