146 lines
4.2 KiB
TypeScript
146 lines
4.2 KiB
TypeScript
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
|
import path from 'path';
|
|
import { logger } from '../util/logger.js';
|
|
import type { LinkMode, PostAction } from '../types.js';
|
|
|
|
export interface SavedLink {
|
|
url: string;
|
|
name: string;
|
|
active: boolean;
|
|
mode: LinkMode;
|
|
postAction?: PostAction;
|
|
addedAt: string;
|
|
}
|
|
|
|
export interface SavedSettings {
|
|
paused: boolean;
|
|
links: SavedLink[];
|
|
poe2LogPath: string;
|
|
poe2WindowTitle: string;
|
|
browserUserDataDir: string;
|
|
travelTimeoutMs: number;
|
|
stashScanTimeoutMs: number;
|
|
waitForMoreItemsMs: number;
|
|
betweenTradesDelayMs: number;
|
|
dashboardPort: number;
|
|
}
|
|
|
|
const DEFAULTS: SavedSettings = {
|
|
paused: false,
|
|
links: [],
|
|
poe2LogPath: 'C:\\Program Files (x86)\\Steam\\steamapps\\common\\Path of Exile 2\\logs\\Client.txt',
|
|
poe2WindowTitle: 'Path of Exile 2',
|
|
browserUserDataDir: './browser-data',
|
|
travelTimeoutMs: 15000,
|
|
stashScanTimeoutMs: 10000,
|
|
waitForMoreItemsMs: 20000,
|
|
betweenTradesDelayMs: 5000,
|
|
dashboardPort: 3000,
|
|
};
|
|
|
|
export class ConfigStore {
|
|
private filePath: string;
|
|
private data: SavedSettings;
|
|
|
|
constructor(configPath?: string) {
|
|
this.filePath = configPath || path.resolve('config.json');
|
|
this.data = this.load();
|
|
}
|
|
|
|
private load(): SavedSettings {
|
|
if (!existsSync(this.filePath)) {
|
|
logger.info({ path: this.filePath }, 'No config.json found, using defaults');
|
|
return { ...DEFAULTS };
|
|
}
|
|
|
|
try {
|
|
const raw = readFileSync(this.filePath, 'utf-8');
|
|
const parsed = JSON.parse(raw) as Partial<SavedSettings>;
|
|
const merged = { ...DEFAULTS, ...parsed };
|
|
// Migrate old links: add name/active fields, strip /live from URLs, default postAction
|
|
merged.links = merged.links.map((l: any) => {
|
|
const mode: LinkMode = l.mode || 'live';
|
|
return {
|
|
url: l.url.replace(/\/live\/?$/, ''),
|
|
name: l.name || '',
|
|
active: l.active !== undefined ? l.active : true,
|
|
mode,
|
|
postAction: l.postAction || (mode === 'scrap' ? 'salvage' : 'stash'),
|
|
addedAt: l.addedAt || new Date().toISOString(),
|
|
};
|
|
});
|
|
logger.info({ path: this.filePath, linkCount: merged.links.length }, 'Loaded config.json');
|
|
return merged;
|
|
} catch (err) {
|
|
logger.warn({ err, path: this.filePath }, 'Failed to read config.json, using defaults');
|
|
return { ...DEFAULTS };
|
|
}
|
|
}
|
|
|
|
save(): void {
|
|
try {
|
|
writeFileSync(this.filePath, JSON.stringify(this.data, null, 2), 'utf-8');
|
|
} catch (err) {
|
|
logger.error({ err, path: this.filePath }, 'Failed to save config.json');
|
|
}
|
|
}
|
|
|
|
get settings(): SavedSettings {
|
|
return this.data;
|
|
}
|
|
|
|
get links(): SavedLink[] {
|
|
return this.data.links;
|
|
}
|
|
|
|
addLink(url: string, name: string = '', mode: LinkMode = 'live', postAction?: PostAction): void {
|
|
url = url.replace(/\/live\/?$/, '');
|
|
if (this.data.links.some((l) => l.url === url)) return;
|
|
this.data.links.push({
|
|
url,
|
|
name,
|
|
active: true,
|
|
mode,
|
|
postAction: postAction || (mode === 'scrap' ? 'salvage' : 'stash'),
|
|
addedAt: new Date().toISOString(),
|
|
});
|
|
this.save();
|
|
}
|
|
|
|
removeLink(url: string): void {
|
|
this.data.links = this.data.links.filter((l) => l.url !== url);
|
|
this.save();
|
|
}
|
|
|
|
removeLinkById(id: string): void {
|
|
this.data.links = this.data.links.filter((l) => {
|
|
const parts = l.url.split('/');
|
|
return parts[parts.length - 1] !== id;
|
|
});
|
|
this.save();
|
|
}
|
|
|
|
updateLinkById(id: string, updates: { name?: string; active?: boolean; mode?: LinkMode; postAction?: PostAction }): SavedLink | null {
|
|
const link = this.data.links.find((l) => {
|
|
const parts = l.url.split('/');
|
|
return parts[parts.length - 1] === id;
|
|
});
|
|
if (!link) return null;
|
|
if (updates.name !== undefined) link.name = updates.name;
|
|
if (updates.active !== undefined) link.active = updates.active;
|
|
if (updates.mode !== undefined) link.mode = updates.mode;
|
|
if (updates.postAction !== undefined) link.postAction = updates.postAction;
|
|
this.save();
|
|
return link;
|
|
}
|
|
|
|
setPaused(paused: boolean): void {
|
|
this.data.paused = paused;
|
|
this.save();
|
|
}
|
|
|
|
updateSettings(partial: Record<string, unknown>): void {
|
|
Object.assign(this.data, partial);
|
|
this.save();
|
|
}
|
|
}
|