pithos/core/paths.js
Local Dev 6b8eeaf82b Pithos: a control panel for s3d, the Sia S3 gateway
s3d is driven entirely by a CLI and a two-route admin API, which keeps
Sia storage out of reach for anyone who does not live in a terminal.
Pithos wraps it: install the pinned s3d release (checksum verified),
start/stop and logs, indexer login, users and access keys, a bucket and
object browser with share links and public-read policies, and the
upload pipeline stats.

One control server (core/) serves one UI (ui/), and three hosts run it:
a web console, an Electron desktop window and a Theseus add-on, so a
feature lands everywhere at once. The server binds loopback, rejects
foreign Host headers, and signs views in with a one-time secret that
becomes a SameSite=Strict cookie. s3d login reads the recovery phrase
with term.ReadPassword, so it is driven through a pty, with a console
window fallback where the pty module is not shipped.
2026-10-03 19:02:50 +02:00

49 lines
2 KiB
JavaScript

// Where s3d keeps its config and data on each OS, mirroring the lookup in
// s3d's cmd/s3d/main.go (configSearchPaths / applicationDirectoryOS) so the
// GUI and a hand-run `s3d` always agree on which instance they are touching.
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
export function defaultDataDir() {
switch (process.platform) {
case 'win32': return path.join(process.env.APPDATA || path.join(os.homedir(), 'AppData', 'Roaming'), 's3d');
case 'darwin': return path.join(os.homedir(), 'Library', 'Application Support', 's3d');
default: return '/var/lib/s3d';
}
}
export function configSearchPaths() {
const paths = [];
if (process.env.S3D_DATA_DIR) paths.push(path.join(process.env.S3D_DATA_DIR, 's3d.yml'));
switch (process.platform) {
case 'win32': paths.push(path.join(defaultDataDir(), 's3d.yml')); break;
case 'darwin': paths.push(path.join(defaultDataDir(), 's3d.yml')); break;
default: paths.push('/etc/s3d/s3d.yml', '/var/lib/s3d/s3d.yml');
}
return paths;
}
// The config file this GUI manages: an explicit S3D_CONFIG_FILE wins, then the
// first existing search path, then the first search path (created on save).
export function resolveConfigPath(explicit) {
if (explicit) return path.resolve(explicit);
if (process.env.S3D_CONFIG_FILE) return path.resolve(process.env.S3D_CONFIG_FILE);
const candidates = configSearchPaths();
return candidates.find((p) => fs.existsSync(p)) || candidates[0];
}
const EXE = process.platform === 'win32' ? 's3d.exe' : 's3d';
// Binary lookup: explicit path, S3D_BIN, the vendored copy next to Pithos, then PATH.
export function resolveBinary(explicit, vendorDir) {
const tries = [explicit, process.env.S3D_BIN, vendorDir && path.join(vendorDir, EXE)].filter(Boolean);
for (const p of tries) if (fs.existsSync(p)) return path.resolve(p);
for (const dir of (process.env.PATH || '').split(path.delimiter)) {
if (!dir) continue;
const p = path.join(dir, EXE);
if (fs.existsSync(p)) return p;
}
return null;
}