All checks were successful
Deploy / deploy (push) Successful in 3m58s
- Extract world-parse + packet capture into @albion/shared (reused by server and a new standalone agent workspace). - Migrate the data layer from SQLite/better-sqlite3 to shared Postgres (async pg with a ?->$n helper; economy engine preloads the item/recipe graph so its sync recursion still works). - API-key auth (ALBION_API_KEY) on all /api routes except health; web UI sends it via a fetch wrapper + key-entry gate; server serves the built UI with a path-traversal-safe static handler (drops @fastify/static). - Windows companion agent: pushes world map + captured market orders to /api/ingest/*; runs on the gaming PC where the game traffic lives. - Docker + docker-compose (external proxy + backend networks for Nginx Proxy Manager and shared Postgres) and a Forgejo deploy workflow. - Validated end-to-end against Postgres 16 and a full compose run. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
54 lines
1.8 KiB
TypeScript
54 lines
1.8 KiB
TypeScript
import fs from 'node:fs';
|
|
import os from 'node:os';
|
|
import path from 'node:path';
|
|
|
|
/**
|
|
* Agent config, resolved from (in order): env vars, a config file, defaults.
|
|
* Config file lives at %APPDATA%\albion-agent\config.json (or ALBION_AGENT_CONFIG).
|
|
*/
|
|
export interface AgentConfig {
|
|
serverUrl: string; // e.g. https://albion.example.com
|
|
apiKey: string;
|
|
gamePath: string; // folder containing the "game" directory, e.g. E:\albion
|
|
interfaces: string[]; // tshark interface ids; empty = all
|
|
orderFlushSeconds: number;
|
|
}
|
|
|
|
const DEFAULTS: AgentConfig = {
|
|
serverUrl: 'http://127.0.0.1:4310',
|
|
apiKey: '',
|
|
gamePath: 'E:\\albion',
|
|
interfaces: [],
|
|
orderFlushSeconds: 15,
|
|
};
|
|
|
|
export function configPath(): string {
|
|
if (process.env.ALBION_AGENT_CONFIG) return process.env.ALBION_AGENT_CONFIG;
|
|
const base = process.env.APPDATA ?? path.join(os.homedir(), '.config');
|
|
return path.join(base, 'albion-agent', 'config.json');
|
|
}
|
|
|
|
export function loadConfig(): AgentConfig {
|
|
let fileCfg: Partial<AgentConfig> = {};
|
|
const p = configPath();
|
|
if (fs.existsSync(p)) {
|
|
try {
|
|
fileCfg = JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
} catch {
|
|
console.warn(`Could not parse ${p}, ignoring.`);
|
|
}
|
|
}
|
|
return {
|
|
serverUrl: process.env.ALBION_SERVER_URL ?? fileCfg.serverUrl ?? DEFAULTS.serverUrl,
|
|
apiKey: process.env.ALBION_API_KEY ?? fileCfg.apiKey ?? DEFAULTS.apiKey,
|
|
gamePath: process.env.ALBION_GAME_PATH ?? fileCfg.gamePath ?? DEFAULTS.gamePath,
|
|
interfaces: fileCfg.interfaces ?? DEFAULTS.interfaces,
|
|
orderFlushSeconds: fileCfg.orderFlushSeconds ?? DEFAULTS.orderFlushSeconds,
|
|
};
|
|
}
|
|
|
|
export function saveConfig(cfg: AgentConfig): void {
|
|
const p = configPath();
|
|
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
fs.writeFileSync(p, JSON.stringify(cfg, null, 2));
|
|
}
|