mirror of
https://github.com/sp-tarkov/server.git
synced 2025-02-13 09:50:43 -05:00
Refactor SaveServer and the things that interact with it to be async (#1064)
Changes: - Adds a map for `profiles` - Changes `onBeforeSaveCallbacks` to be Promises - Changes `SaveMD5` into `saveSHA1` as the async method for `saveSHA1` isn't blocking - Changes all routes and callbacks directly interacting with SaveServer to be async --------- Co-authored-by: Chomp <27521899+chompDev@users.noreply.github.com>
This commit is contained in:
parent
9612ca2834
commit
1d1104a1e8
@ -69,12 +69,12 @@ export class GameCallbacks implements OnLoad {
|
|||||||
* Save profiles on game close
|
* Save profiles on game close
|
||||||
* @returns IGameLogoutResponseData
|
* @returns IGameLogoutResponseData
|
||||||
*/
|
*/
|
||||||
public gameLogout(
|
public async gameLogout(
|
||||||
url: string,
|
url: string,
|
||||||
info: IEmptyRequestData,
|
info: IEmptyRequestData,
|
||||||
sessionID: string,
|
sessionID: string,
|
||||||
): IGetBodyResponseData<IGameLogoutResponseData> {
|
): Promise<IGetBodyResponseData<IGameLogoutResponseData>> {
|
||||||
this.saveServer.save();
|
await this.saveServer.saveProfile(sessionID);
|
||||||
return this.httpResponse.getBody({ status: "ok" });
|
return this.httpResponse.getBody({ status: "ok" });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,8 +27,8 @@ export class LauncherCallbacks {
|
|||||||
return !output ? "FAILED" : output;
|
return !output ? "FAILED" : output;
|
||||||
}
|
}
|
||||||
|
|
||||||
public register(url: string, info: IRegisterData, sessionID: string): "FAILED" | "OK" {
|
public async register(url: string, info: IRegisterData, sessionID: string): Promise<"FAILED" | "OK"> {
|
||||||
const output = this.launcherController.register(info);
|
const output = await this.launcherController.register(info);
|
||||||
return !output ? "FAILED" : "OK";
|
return !output ? "FAILED" : "OK";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,8 +60,8 @@ export class LauncherCallbacks {
|
|||||||
return this.httpResponse.noBody("pong!");
|
return this.httpResponse.noBody("pong!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeProfile(url: string, info: IRemoveProfileData, sessionID: string): string {
|
public async removeProfile(url: string, info: IRemoveProfileData, sessionID: string): Promise<string> {
|
||||||
return this.httpResponse.noBody(this.saveServer.removeProfile(sessionID));
|
return this.httpResponse.noBody(await this.saveServer.removeProfile(sessionID));
|
||||||
}
|
}
|
||||||
|
|
||||||
public getCompatibleTarkovVersion(): string {
|
public getCompatibleTarkovVersion(): string {
|
||||||
|
@ -33,13 +33,12 @@ export class ProfileCallbacks {
|
|||||||
/**
|
/**
|
||||||
* Handle client/game/profile/create
|
* Handle client/game/profile/create
|
||||||
*/
|
*/
|
||||||
public createProfile(
|
public async createProfile(
|
||||||
url: string,
|
url: string,
|
||||||
info: IProfileCreateRequestData,
|
info: IProfileCreateRequestData,
|
||||||
sessionID: string,
|
sessionID: string,
|
||||||
): IGetBodyResponseData<ICreateProfileResponse> {
|
): Promise<IGetBodyResponseData<ICreateProfileResponse>> {
|
||||||
const id = this.profileController.createProfile(info, sessionID);
|
return this.httpResponse.getBody({ uid: await this.profileController.createProfile(info, sessionID) });
|
||||||
return this.httpResponse.getBody({ uid: id });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -20,8 +20,8 @@ export class SaveCallbacks implements OnLoad, OnUpdate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async onLoad(): Promise<void> {
|
public async onLoad(): Promise<void> {
|
||||||
this.backupService.init();
|
await this.backupService.init();
|
||||||
this.saveServer.load();
|
await this.saveServer.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
public getRoute(): string {
|
public getRoute(): string {
|
||||||
@ -31,7 +31,7 @@ export class SaveCallbacks implements OnLoad, OnUpdate {
|
|||||||
public async onUpdate(secondsSinceLastRun: number): Promise<boolean> {
|
public async onUpdate(secondsSinceLastRun: number): Promise<boolean> {
|
||||||
// run every 15 seconds
|
// run every 15 seconds
|
||||||
if (secondsSinceLastRun > this.coreConfig.profileSaveIntervalSeconds) {
|
if (secondsSinceLastRun > this.coreConfig.profileSaveIntervalSeconds) {
|
||||||
this.saveServer.save();
|
await this.saveServer.save();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -88,17 +88,17 @@ export class LauncherController {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
public register(info: IRegisterData): string {
|
public async register(info: IRegisterData): Promise<string> {
|
||||||
for (const sessionID in this.saveServer.getProfiles()) {
|
for (const sessionID in this.saveServer.getProfiles()) {
|
||||||
if (info.username === this.saveServer.getProfile(sessionID).info.username) {
|
if (info.username === this.saveServer.getProfile(sessionID).info.username) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.createAccount(info);
|
return await this.createAccount(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected createAccount(info: IRegisterData): string {
|
protected async createAccount(info: IRegisterData): Promise<string> {
|
||||||
const profileId = this.generateProfileId();
|
const profileId = this.generateProfileId();
|
||||||
const scavId = this.generateProfileId();
|
const scavId = this.generateProfileId();
|
||||||
const newProfileDetails: Info = {
|
const newProfileDetails: Info = {
|
||||||
@ -112,8 +112,8 @@ export class LauncherController {
|
|||||||
};
|
};
|
||||||
this.saveServer.createProfile(newProfileDetails);
|
this.saveServer.createProfile(newProfileDetails);
|
||||||
|
|
||||||
this.saveServer.loadProfile(profileId);
|
await this.saveServer.loadProfile(profileId);
|
||||||
this.saveServer.saveProfile(profileId);
|
await this.saveServer.saveProfile(profileId);
|
||||||
|
|
||||||
return profileId;
|
return profileId;
|
||||||
}
|
}
|
||||||
|
@ -99,8 +99,8 @@ export class ProfileController {
|
|||||||
* @param sessionID Player id
|
* @param sessionID Player id
|
||||||
* @returns Profiles _id value
|
* @returns Profiles _id value
|
||||||
*/
|
*/
|
||||||
public createProfile(info: IProfileCreateRequestData, sessionID: string): string {
|
public async createProfile(info: IProfileCreateRequestData, sessionID: string): Promise<string> {
|
||||||
return this.createProfileService.createProfile(sessionID, info);
|
return await this.createProfileService.createProfile(sessionID, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -75,7 +75,7 @@ export class ItemEventRouterDefinition extends Router {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class SaveLoadRouter extends Router {
|
export class SaveLoadRouter extends Router {
|
||||||
public handleLoad(profile: ISptProfile): ISptProfile {
|
public async handleLoad(profile: ISptProfile): Promise<ISptProfile> {
|
||||||
throw new Error("This method needs to be overrode by the router classes");
|
throw new Error("This method needs to be overrode by the router classes");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ export class HealthSaveLoadRouter extends SaveLoadRouter {
|
|||||||
return [new HandledRoute("spt-health", false)];
|
return [new HandledRoute("spt-health", false)];
|
||||||
}
|
}
|
||||||
|
|
||||||
public override handleLoad(profile: ISptProfile): ISptProfile {
|
public override async handleLoad(profile: ISptProfile): Promise<ISptProfile> {
|
||||||
if (!profile.vitality) {
|
if (!profile.vitality) {
|
||||||
// Occurs on newly created profiles
|
// Occurs on newly created profiles
|
||||||
profile.vitality = { health: undefined, effects: undefined };
|
profile.vitality = { health: undefined, effects: undefined };
|
||||||
|
@ -8,7 +8,7 @@ export class InraidSaveLoadRouter extends SaveLoadRouter {
|
|||||||
return [new HandledRoute("spt-inraid", false)];
|
return [new HandledRoute("spt-inraid", false)];
|
||||||
}
|
}
|
||||||
|
|
||||||
public override handleLoad(profile: ISptProfile): ISptProfile {
|
public override async handleLoad(profile: ISptProfile): Promise<ISptProfile> {
|
||||||
if (profile.inraid === undefined) {
|
if (profile.inraid === undefined) {
|
||||||
profile.inraid = { location: "none", character: "none" };
|
profile.inraid = { location: "none", character: "none" };
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ export class InsuranceSaveLoadRouter extends SaveLoadRouter {
|
|||||||
return [new HandledRoute("spt-insurance", false)];
|
return [new HandledRoute("spt-insurance", false)];
|
||||||
}
|
}
|
||||||
|
|
||||||
public override handleLoad(profile: ISptProfile): ISptProfile {
|
public override async handleLoad(profile: ISptProfile): Promise<ISptProfile> {
|
||||||
if (profile.insurance === undefined) {
|
if (profile.insurance === undefined) {
|
||||||
profile.insurance = [];
|
profile.insurance = [];
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ export class ProfileSaveLoadRouter extends SaveLoadRouter {
|
|||||||
return [new HandledRoute("spt-profile", false)];
|
return [new HandledRoute("spt-profile", false)];
|
||||||
}
|
}
|
||||||
|
|
||||||
public override handleLoad(profile: ISptProfile): ISptProfile {
|
public override async handleLoad(profile: ISptProfile): Promise<ISptProfile> {
|
||||||
if (!profile.characters) {
|
if (!profile.characters) {
|
||||||
profile.characters = { pmc: {} as IPmcData, scav: {} as IPmcData };
|
profile.characters = { pmc: {} as IPmcData, scav: {} as IPmcData };
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,7 @@ export class GameStaticRouter extends StaticRouter {
|
|||||||
sessionID: string,
|
sessionID: string,
|
||||||
output: string,
|
output: string,
|
||||||
): Promise<IGetBodyResponseData<IGameLogoutResponseData>> => {
|
): Promise<IGetBodyResponseData<IGameLogoutResponseData>> => {
|
||||||
return this.gameCallbacks.gameLogout(url, info, sessionID);
|
return await this.gameCallbacks.gameLogout(url, info, sessionID);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
new RouteAction(
|
new RouteAction(
|
||||||
|
@ -27,7 +27,7 @@ export class LauncherStaticRouter extends StaticRouter {
|
|||||||
new RouteAction(
|
new RouteAction(
|
||||||
"/launcher/profile/register",
|
"/launcher/profile/register",
|
||||||
async (url: string, info: any, sessionID: string, output: string): Promise<string> => {
|
async (url: string, info: any, sessionID: string, output: string): Promise<string> => {
|
||||||
return this.launcherCallbacks.register(url, info, sessionID);
|
return await this.launcherCallbacks.register(url, info, sessionID);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
new RouteAction(
|
new RouteAction(
|
||||||
@ -57,7 +57,7 @@ export class LauncherStaticRouter extends StaticRouter {
|
|||||||
new RouteAction(
|
new RouteAction(
|
||||||
"/launcher/profile/remove",
|
"/launcher/profile/remove",
|
||||||
async (url: string, info: any, sessionID: string, output: string): Promise<string> => {
|
async (url: string, info: any, sessionID: string, output: string): Promise<string> => {
|
||||||
return this.launcherCallbacks.removeProfile(url, info, sessionID);
|
return await this.launcherCallbacks.removeProfile(url, info, sessionID);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
new RouteAction(
|
new RouteAction(
|
||||||
|
@ -5,7 +5,7 @@ import { ICoreConfig } from "@spt/models/spt/config/ICoreConfig";
|
|||||||
import type { ILogger } from "@spt/models/spt/utils/ILogger";
|
import type { ILogger } from "@spt/models/spt/utils/ILogger";
|
||||||
import { ConfigServer } from "@spt/servers/ConfigServer";
|
import { ConfigServer } from "@spt/servers/ConfigServer";
|
||||||
import { LocalisationService } from "@spt/services/LocalisationService";
|
import { LocalisationService } from "@spt/services/LocalisationService";
|
||||||
import { FileSystemSync } from "@spt/utils/FileSystemSync";
|
import { FileSystem } from "@spt/utils/FileSystem";
|
||||||
import { HashUtil } from "@spt/utils/HashUtil";
|
import { HashUtil } from "@spt/utils/HashUtil";
|
||||||
import { JsonUtil } from "@spt/utils/JsonUtil";
|
import { JsonUtil } from "@spt/utils/JsonUtil";
|
||||||
import { Timer } from "@spt/utils/Timer";
|
import { Timer } from "@spt/utils/Timer";
|
||||||
@ -14,13 +14,12 @@ import { inject, injectAll, injectable } from "tsyringe";
|
|||||||
@injectable()
|
@injectable()
|
||||||
export class SaveServer {
|
export class SaveServer {
|
||||||
protected profileFilepath = "user/profiles/";
|
protected profileFilepath = "user/profiles/";
|
||||||
protected profiles = {};
|
protected profiles: Map<string, ISptProfile> = new Map();
|
||||||
// onLoad = require("../bindings/SaveLoad");
|
protected onBeforeSaveCallbacks: Map<string, (profile: ISptProfile) => Promise<ISptProfile>> = new Map();
|
||||||
protected onBeforeSaveCallbacks = {};
|
protected saveSHA1: { [key: string]: string } = {};
|
||||||
protected saveMd5 = {};
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@inject("FileSystemSync") protected fileSystemSync: FileSystemSync,
|
@inject("FileSystem") protected fileSystem: FileSystem,
|
||||||
@injectAll("SaveLoadRouter") protected saveLoadRouters: SaveLoadRouter[],
|
@injectAll("SaveLoadRouter") protected saveLoadRouters: SaveLoadRouter[],
|
||||||
@inject("JsonUtil") protected jsonUtil: JsonUtil,
|
@inject("JsonUtil") protected jsonUtil: JsonUtil,
|
||||||
@inject("HashUtil") protected hashUtil: HashUtil,
|
@inject("HashUtil") protected hashUtil: HashUtil,
|
||||||
@ -34,8 +33,8 @@ export class SaveServer {
|
|||||||
* @param id Id for save callback
|
* @param id Id for save callback
|
||||||
* @param callback Callback to execute prior to running SaveServer.saveProfile()
|
* @param callback Callback to execute prior to running SaveServer.saveProfile()
|
||||||
*/
|
*/
|
||||||
public addBeforeSaveCallback(id: string, callback: (profile: Partial<ISptProfile>) => Partial<ISptProfile>): void {
|
public addBeforeSaveCallback(id: string, callback: (profile: ISptProfile) => Promise<ISptProfile>): void {
|
||||||
this.onBeforeSaveCallbacks[id] = callback;
|
this.onBeforeSaveCallbacks.set(id, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -43,22 +42,23 @@ export class SaveServer {
|
|||||||
* @param id Id of callback to remove
|
* @param id Id of callback to remove
|
||||||
*/
|
*/
|
||||||
public removeBeforeSaveCallback(id: string): void {
|
public removeBeforeSaveCallback(id: string): void {
|
||||||
this.onBeforeSaveCallbacks[id] = undefined;
|
this.onBeforeSaveCallbacks.delete(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load all profiles in /user/profiles folder into memory (this.profiles)
|
* Load all profiles in /user/profiles folder into memory (this.profiles)
|
||||||
|
* @returns A promise that resolves when loading all profiles is completed.
|
||||||
*/
|
*/
|
||||||
public load(): void {
|
public async load(): Promise<void> {
|
||||||
this.fileSystemSync.ensureDir(this.profileFilepath);
|
await this.fileSystem.ensureDir(this.profileFilepath);
|
||||||
|
|
||||||
// get files to load
|
// get files to load
|
||||||
const files = this.fileSystemSync.getFiles(this.profileFilepath, false, ["json"]);
|
const files = await this.fileSystem.getFiles(this.profileFilepath, false, ["json"]);
|
||||||
|
|
||||||
// load profiles
|
// load profiles
|
||||||
const timer = new Timer();
|
const timer = new Timer();
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
this.loadProfile(FileSystemSync.getFileName(file));
|
await this.loadProfile(FileSystem.getFileName(file));
|
||||||
}
|
}
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
`Loading ${files.length} profile${files.length > 1 ? "s" : ""} took ${timer.getTime("ms")}ms`,
|
`Loading ${files.length} profile${files.length > 1 ? "s" : ""} took ${timer.getTime("ms")}ms`,
|
||||||
@ -67,13 +67,14 @@ export class SaveServer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Save changes for each profile from memory into user/profiles json
|
* Save changes for each profile from memory into user/profiles json
|
||||||
|
* @returns A promise that resolves when saving all profiles is completed.
|
||||||
*/
|
*/
|
||||||
public save(): void {
|
public async save(): Promise<void> {
|
||||||
const timer = new Timer();
|
const timer = new Timer();
|
||||||
for (const sessionID in this.profiles) {
|
for (const sessionID in this.profiles) {
|
||||||
this.saveProfile(sessionID);
|
await this.saveProfile(sessionID);
|
||||||
}
|
}
|
||||||
const profileCount = Object.keys(this.profiles).length;
|
const profileCount = this.profiles.size;
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
`Saving ${profileCount} profile${profileCount > 1 ? "s" : ""} took ${timer.getTime("ms")}ms`,
|
`Saving ${profileCount} profile${profileCount > 1 ? "s" : ""} took ${timer.getTime("ms")}ms`,
|
||||||
false,
|
false,
|
||||||
@ -94,33 +95,35 @@ export class SaveServer {
|
|||||||
throw new Error(`no profiles found in saveServer with id: ${sessionId}`);
|
throw new Error(`no profiles found in saveServer with id: ${sessionId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.profiles[sessionId]) {
|
const profile = this.profiles.get(sessionId);
|
||||||
|
|
||||||
|
if (!profile) {
|
||||||
throw new Error(`no profile found for sessionId: ${sessionId}`);
|
throw new Error(`no profile found for sessionId: ${sessionId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.profiles[sessionId];
|
return profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
public profileExists(id: string): boolean {
|
public profileExists(id: string): boolean {
|
||||||
return !!this.profiles[id];
|
return !!this.profiles.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all profiles from memory
|
* Gets all profiles from memory
|
||||||
* @returns Dictionary of ISptProfile
|
* @returns Dictionary of ISptProfile
|
||||||
*/
|
*/
|
||||||
public getProfiles(): Record<string, ISptProfile> {
|
public getProfiles(): Record<string, ISptProfile> {
|
||||||
return this.profiles;
|
return Object.fromEntries(this.profiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a profile by id
|
* Delete a profile by id (Does not remove the profile file!)
|
||||||
* @param sessionID Id of profile to remove
|
* @param sessionID Id of profile to remove
|
||||||
* @returns true when deleted, false when profile not found
|
* @returns true when deleted, false when profile not found
|
||||||
*/
|
*/
|
||||||
public deleteProfileById(sessionID: string): boolean {
|
public deleteProfileById(sessionID: string): boolean {
|
||||||
if (this.profiles[sessionID]) {
|
if (this.profiles.get(sessionID)) {
|
||||||
delete this.profiles[sessionID];
|
this.profiles.delete(sessionID);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,11 +135,14 @@ export class SaveServer {
|
|||||||
* @param profileInfo Basic profile data
|
* @param profileInfo Basic profile data
|
||||||
*/
|
*/
|
||||||
public createProfile(profileInfo: Info): void {
|
public createProfile(profileInfo: Info): void {
|
||||||
if (this.profiles[profileInfo.id]) {
|
if (this.profiles.get(profileInfo.id)) {
|
||||||
throw new Error(`profile already exists for sessionId: ${profileInfo.id}`);
|
throw new Error(`profile already exists for sessionId: ${profileInfo.id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.profiles[profileInfo.id] = { info: profileInfo, characters: { pmc: {}, scav: {} } };
|
this.profiles.set(profileInfo.id, {
|
||||||
|
info: profileInfo,
|
||||||
|
characters: { pmc: {}, scav: {} },
|
||||||
|
} as ISptProfile); // Cast to ISptProfile so the errors of having empty pmc and scav data disappear
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -144,25 +150,26 @@ export class SaveServer {
|
|||||||
* @param profileDetails Profile to save
|
* @param profileDetails Profile to save
|
||||||
*/
|
*/
|
||||||
public addProfile(profileDetails: ISptProfile): void {
|
public addProfile(profileDetails: ISptProfile): void {
|
||||||
this.profiles[profileDetails.info.id] = profileDetails;
|
this.profiles.set(profileDetails.info.id, profileDetails);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Look up profile json in user/profiles by id and store in memory
|
* Look up profile json in user/profiles by id and store in memory
|
||||||
* Execute saveLoadRouters callbacks after being loaded into memory
|
* Execute saveLoadRouters callbacks after being loaded into memory
|
||||||
* @param sessionID Id of profile to store in memory
|
* @param sessionID Id of profile to store in memory
|
||||||
|
* @returns A promise that resolves when loading is completed.
|
||||||
*/
|
*/
|
||||||
public loadProfile(sessionID: string): void {
|
public async loadProfile(sessionID: string): Promise<void> {
|
||||||
const filename = `${sessionID}.json`;
|
const filename = `${sessionID}.json`;
|
||||||
const filePath = `${this.profileFilepath}${filename}`;
|
const filePath = `${this.profileFilepath}${filename}`;
|
||||||
if (this.fileSystemSync.exists(filePath)) {
|
if (await this.fileSystem.exists(filePath)) {
|
||||||
// File found, store in profiles[]
|
// File found, store in profiles[]
|
||||||
this.profiles[sessionID] = this.fileSystemSync.readJson(filePath);
|
this.profiles.set(sessionID, await this.fileSystem.readJson(filePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run callbacks
|
// Run callbacks
|
||||||
for (const callback of this.saveLoadRouters) {
|
for (const callback of this.saveLoadRouters) {
|
||||||
this.profiles[sessionID] = callback.handleLoad(this.getProfile(sessionID));
|
this.profiles.set(sessionID, await callback.handleLoad(this.getProfile(sessionID)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,46 +177,50 @@ export class SaveServer {
|
|||||||
* Save changes from in-memory profile to user/profiles json
|
* Save changes from in-memory profile to user/profiles json
|
||||||
* Execute onBeforeSaveCallbacks callbacks prior to being saved to json
|
* Execute onBeforeSaveCallbacks callbacks prior to being saved to json
|
||||||
* @param sessionID profile id (user/profiles/id.json)
|
* @param sessionID profile id (user/profiles/id.json)
|
||||||
* @returns void
|
* @returns A promise that resolves when saving is completed.
|
||||||
*/
|
*/
|
||||||
public saveProfile(sessionID: string): void {
|
public async saveProfile(sessionID: string): Promise<void> {
|
||||||
|
if (!this.profiles.get(sessionID)) {
|
||||||
|
throw new Error(`Profile ${sessionID} does not exist! Unable to save this profile!`);
|
||||||
|
}
|
||||||
|
|
||||||
const filePath = `${this.profileFilepath}${sessionID}.json`;
|
const filePath = `${this.profileFilepath}${sessionID}.json`;
|
||||||
|
|
||||||
// Run pre-save callbacks before we save into json
|
// Run pre-save callbacks before we save into json
|
||||||
for (const callback in this.onBeforeSaveCallbacks) {
|
for (const [id, callback] of this.onBeforeSaveCallbacks) {
|
||||||
const previous = this.profiles[sessionID];
|
const previous = this.profiles.get(sessionID) as ISptProfile; // Cast as ISptProfile here since there should be no reason we're getting an undefined profile
|
||||||
try {
|
try {
|
||||||
this.profiles[sessionID] = this.onBeforeSaveCallbacks[callback](this.profiles[sessionID]);
|
this.profiles.set(sessionID, await callback(this.profiles.get(sessionID) as ISptProfile)); // Cast as ISptProfile here since there should be no reason we're getting an undefined profile
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.error(this.localisationService.getText("profile_save_callback_error", { callback, error }));
|
this.logger.error(this.localisationService.getText("profile_save_callback_error", { callback, error }));
|
||||||
this.profiles[sessionID] = previous;
|
this.profiles.set(sessionID, previous);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const jsonProfile = this.jsonUtil.serialize(
|
const jsonProfile = this.jsonUtil.serialize(
|
||||||
this.profiles[sessionID],
|
this.profiles.get(sessionID),
|
||||||
!this.configServer.getConfig<ICoreConfig>(ConfigTypes.CORE).features.compressProfile,
|
!this.configServer.getConfig<ICoreConfig>(ConfigTypes.CORE).features.compressProfile,
|
||||||
);
|
);
|
||||||
const fmd5 = this.hashUtil.generateMd5ForData(jsonProfile);
|
const sha1 = await this.hashUtil.generateSha1ForDataAsync(jsonProfile);
|
||||||
if (typeof this.saveMd5[sessionID] !== "string" || this.saveMd5[sessionID] !== fmd5) {
|
if (typeof this.saveSHA1[sessionID] !== "string" || this.saveSHA1[sessionID] !== sha1) {
|
||||||
this.saveMd5[sessionID] = String(fmd5);
|
this.saveSHA1[sessionID] = sha1;
|
||||||
// save profile to disk
|
// save profile to disk
|
||||||
this.fileSystemSync.write(filePath, jsonProfile);
|
await this.fileSystem.write(filePath, jsonProfile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a physical profile json from user/profiles
|
* Remove a physical profile json from user/profiles
|
||||||
* @param sessionID Profile id to remove
|
* @param sessionID Profile id to remove
|
||||||
* @returns true if file no longer exists
|
* @returns A promise that is true if the file no longer exists
|
||||||
*/
|
*/
|
||||||
public removeProfile(sessionID: string): boolean {
|
public async removeProfile(sessionID: string): Promise<boolean> {
|
||||||
const file = `${this.profileFilepath}${sessionID}.json`;
|
const file = `${this.profileFilepath}${sessionID}.json`;
|
||||||
|
|
||||||
delete this.profiles[sessionID];
|
this.profiles.delete(sessionID);
|
||||||
|
|
||||||
this.fileSystemSync.remove(file);
|
await this.fileSystem.remove(file);
|
||||||
|
|
||||||
return !this.fileSystemSync.exists(file);
|
return !this.fileSystem.exists(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ export class CreateProfileService {
|
|||||||
@inject("EventOutputHolder") protected eventOutputHolder: EventOutputHolder,
|
@inject("EventOutputHolder") protected eventOutputHolder: EventOutputHolder,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public createProfile(sessionID: string, info: IProfileCreateRequestData): string {
|
public async createProfile(sessionID: string, info: IProfileCreateRequestData): Promise<string> {
|
||||||
const account = this.saveServer.getProfile(sessionID).info;
|
const account = this.saveServer.getProfile(sessionID).info;
|
||||||
const profileTemplateClone: ITemplateSide = this.cloner.clone(
|
const profileTemplateClone: ITemplateSide = this.cloner.clone(
|
||||||
this.databaseService.getProfiles()[account.edition][info.side.toLowerCase()],
|
this.databaseService.getProfiles()[account.edition][info.side.toLowerCase()],
|
||||||
@ -145,12 +145,12 @@ export class CreateProfileService {
|
|||||||
this.saveServer.getProfile(sessionID).characters.scav = this.playerScavGenerator.generate(sessionID);
|
this.saveServer.getProfile(sessionID).characters.scav = this.playerScavGenerator.generate(sessionID);
|
||||||
|
|
||||||
// Store minimal profile and reload it
|
// Store minimal profile and reload it
|
||||||
this.saveServer.saveProfile(sessionID);
|
await this.saveServer.saveProfile(sessionID);
|
||||||
this.saveServer.loadProfile(sessionID);
|
await this.saveServer.loadProfile(sessionID);
|
||||||
|
|
||||||
// Completed account creation
|
// Completed account creation
|
||||||
this.saveServer.getProfile(sessionID).info.wipe = false;
|
this.saveServer.getProfile(sessionID).info.wipe = false;
|
||||||
this.saveServer.saveProfile(sessionID);
|
await this.saveServer.saveProfile(sessionID);
|
||||||
|
|
||||||
return pmcData._id;
|
return pmcData._id;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user