Fixed tweaks and mods, added localization, added antivirus walkthrough
Build check / build (push) Has been cancelled
Build check / build (push) Has been cancelled
This commit is contained in:
@@ -3,6 +3,7 @@ import path from 'path';
|
||||
import fs from 'fs-extra';
|
||||
import { type z } from 'zod';
|
||||
import { app } from 'electron';
|
||||
import Logger from 'electron-log/main';
|
||||
|
||||
import { PreferencesSchema } from '~common/schemas';
|
||||
import { omit } from '~common/utils';
|
||||
@@ -11,6 +12,7 @@ const portableDir = process.env.PORTABLE_EXECUTABLE_DIR;
|
||||
|
||||
abstract class Preferences {
|
||||
static #data: z.infer<typeof PreferencesSchema>;
|
||||
static #writeChain: Promise<void> = Promise.resolve();
|
||||
|
||||
static readonly userDataDir = process.env.PORTABLE_EXECUTABLE_DIR
|
||||
? path.join(process.env.PORTABLE_EXECUTABLE_DIR, '.launcher')
|
||||
@@ -18,21 +20,44 @@ abstract class Preferences {
|
||||
|
||||
static async load() {
|
||||
await fs.ensureDir(this.userDataDir);
|
||||
const settingsPath = path.join(this.userDataDir, 'settings.json');
|
||||
|
||||
const userDataPath = path.join(this.userDataDir, 'settings.json');
|
||||
let json: Record<string, unknown>;
|
||||
try {
|
||||
const json = await fs.readJSON(userDataPath);
|
||||
return PreferencesSchema.parse({
|
||||
...json,
|
||||
isPortable: !!portableDir,
|
||||
clientDir: portableDir ?? json.clientDir
|
||||
});
|
||||
} catch (e) {
|
||||
json = await fs.readJSON(settingsPath);
|
||||
} catch {
|
||||
return PreferencesSchema.parse({
|
||||
isPortable: !!portableDir,
|
||||
clientDir: portableDir
|
||||
});
|
||||
}
|
||||
|
||||
const merged = {
|
||||
...json,
|
||||
isPortable: !!portableDir,
|
||||
clientDir: portableDir ?? json.clientDir
|
||||
};
|
||||
|
||||
const parsed = PreferencesSchema.safeParse(merged);
|
||||
if (parsed.success) return parsed.data;
|
||||
|
||||
Logger.warn(
|
||||
'settings.json failed validation; salvaging valid fields',
|
||||
parsed.error
|
||||
);
|
||||
await fs.copy(settingsPath, `${settingsPath}.corrupt`).catch(() => {});
|
||||
|
||||
const salvaged: Record<string, unknown> = {
|
||||
isPortable: !!portableDir,
|
||||
clientDir: portableDir ?? json.clientDir
|
||||
};
|
||||
const shape = PreferencesSchema.shape;
|
||||
for (const key of Object.keys(shape) as (keyof typeof shape)[]) {
|
||||
if (!(key in merged)) continue;
|
||||
const value = (merged as Record<string, unknown>)[key];
|
||||
if (shape[key].safeParse(value).success) salvaged[key] = value;
|
||||
}
|
||||
return PreferencesSchema.parse(salvaged);
|
||||
}
|
||||
|
||||
static get data(): PreferencesSchema {
|
||||
@@ -41,14 +66,38 @@ abstract class Preferences {
|
||||
|
||||
static set data(newData: Partial<Omit<PreferencesSchema, 'portableDir'>>) {
|
||||
this.#data = { ...this.#data, ...newData };
|
||||
fs.writeJSON(
|
||||
path.join(this.userDataDir, 'settings.json'),
|
||||
omit(
|
||||
this.#data,
|
||||
portableDir ? ['isPortable', 'clientDir'] : ['isPortable']
|
||||
),
|
||||
{ spaces: 2 }
|
||||
|
||||
const settingsPath = path.join(this.userDataDir, 'settings.json');
|
||||
const delta = omit(
|
||||
newData,
|
||||
portableDir ? ['isPortable', 'clientDir'] : ['isPortable']
|
||||
);
|
||||
const snapshot = omit(
|
||||
this.#data,
|
||||
portableDir ? ['isPortable', 'clientDir'] : ['isPortable']
|
||||
);
|
||||
this.#writeChain = this.#writeChain
|
||||
.then(async () => {
|
||||
let onDisk: unknown = null;
|
||||
try {
|
||||
onDisk = await fs.readJSON(settingsPath);
|
||||
} catch {
|
||||
onDisk = null;
|
||||
}
|
||||
const base =
|
||||
!!onDisk && typeof onDisk === 'object' && !Array.isArray(onDisk)
|
||||
? (onDisk as Record<string, unknown>)
|
||||
: null;
|
||||
const merged = base ? { ...base, ...delta } : snapshot;
|
||||
const tmp = `${settingsPath}.tmp`;
|
||||
await fs.writeJSON(tmp, merged, { spaces: 2 });
|
||||
await fs.move(tmp, settingsPath, { overwrite: true });
|
||||
})
|
||||
.catch(e => Logger.error('Failed to persist settings.json', e));
|
||||
}
|
||||
|
||||
static save() {
|
||||
return this.#writeChain;
|
||||
}
|
||||
|
||||
static async isValidClientDir(clientDir?: string) {
|
||||
|
||||
Reference in New Issue
Block a user