Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/upstream-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ jobs:
snapraid-daemon [v$newest](https://github.com/amadvance/snapraid-daemon/tree/v$newest) is out, the SnapRAID engine was last compared with v$reviewed.

- [ ] Compare the API: [snapraidd.yaml v$reviewed...v$newest](https://github.com/amadvance/snapraid-daemon/compare/v$reviewed...v$newest) and the [HISTORY](https://github.com/amadvance/snapraid-daemon/blob/v$newest/HISTORY)
- [ ] An endpoint for something CLI-only today (\`dup\`, \`list\`, \`devices\`, config, ...)? Add a method to \`SnapRaidEngine\` in \`apps/server/src/engine/engine.ts\`, implement it in \`cli-engine.ts\`, move the callers and extend \`apps/server/src/__tests__/engine-contract.ts\`
- [ ] An endpoint for something CLI-only today (\`dup\`, \`list\`, \`devices\`, config, ...)? Add a method to \`SnapRaidEngine\` in \`apps/server/src/engine/engine.ts\`, implement it in \`cli-engine.ts\`, move the callers and extend \`apps/server/src/engine/__tests__/engine-contract.ts\`
- [ ] Update the tables in [docs/architecture.md](https://github.com/${{ github.repository }}/blob/master/docs/architecture.md#snapraid-engine)
- [ ] Put $newest into \`apps/server/src/engine/REVIEWED_DAEMON_VERSION\`
- [ ] The end-to-end tests build and run against that version; if it needs a newer SnapRAID, raise \`SNAPRAID15_REF\` in \`e2e/scripts/setup-tools.sh\`
Expand Down
6 changes: 3 additions & 3 deletions apps/server/scripts/seed-demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import { readdir, readFile, rm, utimes, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { Cron } from "croner";
import type { MaintenanceSettings, Schedule, UsagePoint } from "@shared/types.ts";
import { parseSnapRaidConfig } from "../src/config-parser.ts";
import { demoDataDiskUsage } from "../src/demo.ts";
import { parseSnapRaidConfig } from "../src/config/config-parser.ts";
import { demoDataDiskUsage } from "../src/system/demo.ts";

const sandbox = process.argv[2];
if (!sandbox) throw new Error("Usage: seed-demo.ts <sandbox>");
Expand Down Expand Up @@ -123,7 +123,7 @@ const schedules: Schedule[] = [
];
await writeFile(join(sandbox, "schedules.json"), JSON.stringify({ schedules }, null, 2));

// The demo answers for Docker itself (apps/server/src/demo.ts), spindown watches the demo disks
// The demo answers for Docker itself (apps/server/src/system/demo.ts), spindown watches the demo disks
// The rest (metrics, MCP) takes its defaults when the backend loads the file
const maintenance: Pick<MaintenanceSettings, "dockerPause" | "spindown"> = {
dockerPause: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { expect, test } from "bun:test";
import { assertThrows } from "./assert-error.ts";
import { assertThrows } from "../../__tests__/assert-error.ts";
import { join } from "node:path";
import type { Server } from "bun";
import { Hono } from "hono";
import { createAuth, SESSION_COOKIE } from "../auth.ts";
import { type CredentialStore, hashPassword, loadCredentials, verifyPassword } from "../credentials.ts";
import { AuthError, createPasskeys, relyingParty } from "../passkeys.ts";
import { broadcast, closeAllClients, handleWebSocketUpgrade, websocket } from "../websocket.ts";
import { setEngine } from "../engine/engine.ts";
import { broadcast, closeAllClients, handleWebSocketUpgrade, websocket } from "../../http/websocket.ts";
import { setEngine } from "../../engine/engine.ts";
import { mkdtemp, readFile, rm, stat, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";

Expand Down
4 changes: 2 additions & 2 deletions apps/server/src/auth.ts → apps/server/src/auth/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import { sign, verify } from "hono/jwt";
import type { AuthenticationResponseJSON, RegistrationResponseJSON } from "@simplewebauthn/server";
import type { AuthSession, PasskeyInfo } from "@shared/types.ts";
import { msg } from "@shared/i18n.ts";
import { BASE_PATH, resolveFromBase } from "./config.ts";
import { BASE_PATH, resolveFromBase } from "../config/config.ts";
import { type CredentialStore, hashPassword, verifyPassword } from "./credentials.ts";
import { AuthError, createPasskeys } from "./passkeys.ts";
import { mkdir, readFile } from "node:fs/promises";
import { writeTextFile } from "./fs.ts";
import { writeTextFile } from "../system/fs.ts";

export const SESSION_COOKIE = "snapraid_session";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
// SNAPRAID_UI_USERNAME or SNAPRAID_UI_PASSWORD change, the file is dropped at startup: the
// password from the environment applies again and the passkeys are gone. That is the way back
// in after a forgotten password, and it removes a passkey someone else added.
import { writeTextFileAtomic } from "./atomic-write.ts";
import { writeTextFileAtomic } from "../system/atomic-write.ts";
import { readFile } from "node:fs/promises";
import { isNotFound, remove } from "./fs.ts";
import { isNotFound, remove } from "../system/fs.ts";

export interface StoredPasskey {
id: string;
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion apps/server/src/bin-cli.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// The command line of the standalone binary (bin.ts): --version and --help, and the data directory
// when none is set, before main.ts's modules read the environment
import { join } from "node:path";
import { APP_VERSION } from "./version.ts";
import { APP_VERSION } from "./system/version.ts";

const HELP = `SnapRAID UI ${APP_VERSION}, web interface for SnapRAID

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { expect, test } from "bun:test";
import { assertThrows } from "./assert-error.ts";
import { assertThrows } from "../../__tests__/assert-error.ts";
import { BackupError, planRestore } from "../backup.ts";

const configJson = JSON.stringify({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { existsSync } from "./fs.ts";
import { existsSync } from "../system/fs.ts";
import { dirname, isAbsolute, normalize } from "node:path";
import type { AppConfig, SettingsBackup } from "@shared/types.ts";
import { msg } from "@shared/i18n.ts";
import { resolveFromBase } from "./config.ts";
import { writeTextFileAtomic } from "./atomic-write.ts";
import { writeTextFileAtomic } from "../system/atomic-write.ts";
import { mkdir, readFile, writeFile } from "node:fs/promises";

// Settings and history next to config.json; logs and replacement runs stay behind
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { basename, dirname, join } from "node:path";
import type { AppConfig, ParityLevel, ParsedSnapRaidConfig } from "@shared/types.ts";
import { resolveFromBase } from "./config.ts";
import { effectiveSmartIgnore, parseSmartIgnoreLine } from "./smart-ignore.ts";
import { writeTextFileAtomic } from "./atomic-write.ts";
import { effectiveSmartIgnore, parseSmartIgnoreLine } from "../smart/smart-ignore.ts";
import { writeTextFileAtomic } from "../system/atomic-write.ts";
import { mkdir, readFile } from "node:fs/promises";
import { isNotFound } from "./fs.ts";
import { isNotFound } from "../system/fs.ts";

export const MAX_PARITY_LEVEL = 6;

Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { existsSync } from "./fs.ts";
import { existsSync } from "../system/fs.ts";
import type { MaintenanceSettings, SnapRaidCommand } from "@shared/types.ts";
import { resolveFromBase } from "./config.ts";
import { writeTextFileAtomic } from "./atomic-write.ts";
import { writeTextFileAtomic } from "../system/atomic-write.ts";
import { readFile } from "node:fs/promises";

const SETTINGS_FILE = "maintenance.json";
Expand Down
4 changes: 2 additions & 2 deletions apps/server/src/setup.ts → apps/server/src/config/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import type { MountCandidate } from "@shared/types.ts";
import { loadAppConfig, saveAppConfig } from "./config-parser.ts";
import { BASE_PATH, resolveFromBase } from "./config.ts";
import { readdir, stat, writeFile } from "node:fs/promises";
import { isAlreadyExists } from "./fs.ts";
import { runCommand } from "./command.ts";
import { isAlreadyExists } from "../system/fs.ts";
import { runCommand } from "../system/command.ts";

// Filesystems that never hold data disks
const VIRTUAL_FS = new Set([
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { expect, test } from "bun:test";
import { assertRejects, assertThrows } from "./assert-error.ts";
import { assertRejects, assertThrows } from "../../__tests__/assert-error.ts";
import { join } from "node:path";
import {
DiskRemovalError,
ensureEmptyDir,
finalizeDataDiskRemoval,
prepareDataDiskRemoval,
} from "../disk-removal.ts";
import { parseSnapRaidConfig } from "../config-parser.ts";
import { parseSnapRaidConfig } from "../../config/config-parser.ts";
import { mkdtemp, rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { expect, test } from "bun:test";
import { assertThrows } from "./assert-error.ts";
import { assertThrows } from "../../__tests__/assert-error.ts";
import { applyReplacementPath, DiskReplacementError, requiredDirectory } from "../disk-replacement.ts";

const CONFIG = `parity /mnt/parity1/snapraid.parity
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
// An unmounted disk leaves an empty mount point behind; SnapRAID then sees all its
// files as deleted, and a sync would drop them from parity.
import type { DiskIssue } from "@shared/types.ts";
import { parseLogTags, toInt, unescapeTagValue } from "./parsers/structured-log.ts";
import { parseLogTags, toInt, unescapeTagValue } from "../parsers/structured-log.ts";
import { readdir, stat } from "node:fs/promises";
import { isNotFound } from "./fs.ts";
import { isNotFound } from "../system/fs.ts";

// Parity levels in the structured log, split parity files (`parity/1`) are not tag lines
const PARITY_LEVEL = /^(?:[2-6]-)?parity(?:\/\d+)?$|^z-parity(?:\/\d+)?$/;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Spin disks up or down by hand, with SnapRAID's `up` and `down` (smartctl and hdparm under the
// hood). Like the automatic spindown this calls SnapRAID directly, also in daemon mode.
import { deviceCommandSucceeded, executeSnapraidCommand } from "./executors/command-executor.ts";
import { DEMO_MODE } from "./demo.ts";
import { deviceCommandSucceeded, executeSnapraidCommand } from "../executors/command-executor.ts";
import { DEMO_MODE } from "../system/demo.ts";

export type PowerAction = "up" | "down";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { dirname, join } from "node:path";
import { isPendingRemoval, parseParityLine, REMOVAL_DIR } from "./config-parser.ts";
import { isPendingRemoval, parseParityLine, REMOVAL_DIR } from "../config/config-parser.ts";
import { msg } from "@shared/i18n.ts";
import { mkdir, readdir } from "node:fs/promises";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { dirname } from "node:path";
import { existsSync } from "./fs.ts";
import { existsSync } from "../system/fs.ts";
import type { DiskReplacement, ReplacementStep, ReplacementStepResult } from "@shared/types.ts";
import { parseParityLine } from "./config-parser.ts";
import { resolveFromBase } from "./config.ts";
import { parseParityLine } from "../config/config-parser.ts";
import { resolveFromBase } from "../config/config.ts";
import { msg } from "@shared/i18n.ts";
import { writeTextFileAtomic } from "./atomic-write.ts";
import { writeTextFileAtomic } from "../system/atomic-write.ts";
import { readFile } from "node:fs/promises";

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import type {
ParityLevelUsage,
ParsedSnapRaidConfig,
} from "@shared/types.ts";
import { type FsUsage, parseDfOutput } from "./parsers/df-parser.ts";
import { DEMO_MODE, demoDataDiskUsage, demoParityUsage } from "./demo.ts";
import { type FsUsage, parseDfOutput } from "../parsers/df-parser.ts";
import { DEMO_MODE, demoDataDiskUsage, demoParityUsage } from "../system/demo.ts";
import { stat } from "node:fs/promises";
import { runCommand } from "./command.ts";
import { runCommand } from "../system/command.ts";

const toGB = (bytes: number): number => Math.round(bytes / 1e9 * 10) / 10;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
// are preferred: SMART reads and power state probes count as I/O of the whole disk only,
// they would otherwise keep it awake forever.
import type { DeviceInfo, SpindownDisk, SpindownStatus } from "@shared/types.ts";
import { loadAppConfig } from "./config-parser.ts";
import { resolveFromBase } from "./config.ts";
import { executeSnapraidCommand } from "./executors/command-executor.ts";
import { parseDevicesOutput } from "./parsers/devices-parser.ts";
import { loadMaintenanceSettings } from "./maintenance-settings.ts";
import { DEMO_MODE, demoDevices, demoDiskstats } from "./demo.ts";
import { selfTestRunning } from "./smart-selftest.ts";
import { loadAppConfig } from "../config/config-parser.ts";
import { resolveFromBase } from "../config/config.ts";
import { executeSnapraidCommand } from "../executors/command-executor.ts";
import { parseDevicesOutput } from "../parsers/devices-parser.ts";
import { loadMaintenanceSettings } from "../config/maintenance-settings.ts";
import { DEMO_MODE, demoDevices, demoDiskstats } from "../system/demo.ts";
import { selfTestRunning } from "../smart/smart-selftest.ts";
import { readFile } from "node:fs/promises";

const TICK_MS = 60_000;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// The daemon engine against a stand-in for snapraid-daemon 2.0. The responses follow
// what a real daemon answered (fields trimmed); a task advances one step per poll.
import { expect, test } from "bun:test";
import { assertRejects } from "./assert-error.ts";
import { assertRejects } from "../../__tests__/assert-error.ts";
import type { JobProgress } from "@shared/types.ts";
import { EngineBusyError } from "../engine/engine.ts";
import { EngineBusyError } from "../engine.ts";
import {
createDaemonEngine,
type DaemonArray,
Expand All @@ -17,7 +17,7 @@ import {
toRunReport,
toSmartDisks,
toStatus,
} from "../engine/daemon-engine.ts";
} from "../daemon-engine.ts";
import { assessSmart } from "@shared/smart-health.ts";
import { createFakeEngine } from "./fake-engine.ts";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { join } from "node:path";
import { runCommand } from "../command.ts";
import { SNAPRAID_BIN, SNAPRAID_EXTRA_ARGS } from "../config.ts";
import { createCliEngine } from "../engine/cli-engine.ts";
import { createDaemonEngine } from "../engine/daemon-engine.ts";
import { parseSnapRaidConfig } from "../config-parser.ts";
import { createLogManager } from "../log-manager.ts";
import { runCommand } from "../../system/command.ts";
import { SNAPRAID_BIN, SNAPRAID_EXTRA_ARGS } from "../../config/config.ts";
import { createCliEngine } from "../cli-engine.ts";
import { createDaemonEngine } from "../daemon-engine.ts";
import { parseSnapRaidConfig } from "../../config/config-parser.ts";
import { createLogManager } from "../../snapraid/log-manager.ts";
import { engineContract } from "./engine-contract.ts";
import { createFakeEngine } from "./fake-engine.ts";
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
// the fake one always, the CLI one when a SnapRAID binary is available.
// A new engine, e.g. one on snapraid-daemon's REST API, gets the same tests.
import { expect, test } from "bun:test";
import { assertRejects } from "./assert-error.ts";
import { EngineBusyError, type SnapRaidEngine } from "../engine/engine.ts";
import { assertRejects } from "../../__tests__/assert-error.ts";
import { EngineBusyError, type SnapRaidEngine } from "../engine.ts";

export interface ContractSetup {
engine: SnapRaidEngine;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
DEFAULT_ENGINE_SETTINGS,
maskEngineSecrets,
normalizeEngineSettings,
} from "../engine/engine-settings.ts";
} from "../engine-settings.ts";
import { createFakeEngine } from "./fake-engine.ts";

const target = (changes = {}) => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import type {
SnapRaidCommand,
SnapRaidStatus,
} from "@shared/types.ts";
import { EngineBusyError, type JobOutcome, type SnapRaidEngine } from "../engine/engine.ts";
import { EngineBusyError, type JobOutcome, type SnapRaidEngine } from "../engine.ts";

export interface FakeEngineOptions {
disks?: string[];
Expand Down
14 changes: 7 additions & 7 deletions apps/server/src/engine/cli-engine.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// The engine that runs the SnapRAID CLI itself and reads its structured log
import type { CommandOutput, SnapRaidCommand } from "@shared/types.ts";
import { msg } from "@shared/i18n.ts";
import { snapraidCommand } from "../config.ts";
import { runCommand } from "../command.ts";
import { snapraidCommand } from "../config/config.ts";
import { runCommand } from "../system/command.ts";
import {
abortCommand,
deviceCommandSucceeded,
Expand All @@ -13,11 +13,11 @@ import {
setLogManager,
setProgressListener,
} from "../executors/command-executor.ts";
import type { LogManager } from "../log-manager.ts";
import { readRunReport } from "../run-report.ts";
import { findDiskIssues } from "../disk-check.ts";
import { DEMO_MODE, demoProbeLog, demoSmartLog, demoStatusLog } from "../demo.ts";
import { parseSnapRaidConfig } from "../config-parser.ts";
import type { LogManager } from "../snapraid/log-manager.ts";
import { readRunReport } from "../snapraid/run-report.ts";
import { findDiskIssues } from "../disks/disk-check.ts";
import { DEMO_MODE, demoProbeLog, demoSmartLog, demoStatusLog } from "../system/demo.ts";
import { parseSnapRaidConfig } from "../config/config-parser.ts";
import { parseDiffOutput } from "../parsers/diff-parser.ts";
import { parseDegradedDisks, parseProbeOutput } from "../parsers/probe-parser.ts";
import { parseSmartArrayFailure, parseSmartOutput } from "../parsers/smart-parser.ts";
Expand Down
2 changes: 1 addition & 1 deletion apps/server/src/engine/daemon-engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import type {
SnapRaidCommand,
SnapRaidStatus,
} from "@shared/types.ts";
import { parseRunReport, type RunReport } from "../run-report.ts";
import { parseRunReport, type RunReport } from "../snapraid/run-report.ts";
import {
EngineBusyError,
type JobOutcome,
Expand Down
6 changes: 3 additions & 3 deletions apps/server/src/engine/engine-settings.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// Which engine runs SnapRAID (engine.json), and the engine built from it
import { existsSync } from "../fs.ts";
import { existsSync } from "../system/fs.ts";
import { type DaemonCheck, type DaemonTarget, type DaemonWarning, type EngineSettings, SECRET_MASK } from "@shared/types.ts";
import { resolveFromBase } from "../config.ts";
import { resolveFromBase } from "../config/config.ts";
import { createDaemonClient, createDaemonEngine, type DaemonArray, DaemonError } from "./daemon-engine.ts";
import type { SnapRaidEngine } from "./engine.ts";
import { writeTextFileAtomic } from "../atomic-write.ts";
import { writeTextFileAtomic } from "../system/atomic-write.ts";
import { readFile } from "node:fs/promises";

const SETTINGS_FILE = "engine.json";
Expand Down
2 changes: 1 addition & 1 deletion apps/server/src/engine/engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import type {
SnapRaidCommand,
SnapRaidStatus,
} from "@shared/types.ts";
import type { RunReport } from "../run-report.ts";
import type { RunReport } from "../snapraid/run-report.ts";

export interface JobRequest {
command: SnapRaidCommand;
Expand Down
8 changes: 4 additions & 4 deletions apps/server/src/executors/command-executor.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import type { SnapRaidCommand, CommandOutput, RunningJob, FinishedJob, JobProgress } from "@shared/types.ts";
import { detectForceOption } from "@shared/force-option.ts";
import type { LogManager } from "../log-manager.ts";
import type { LogManager } from "../snapraid/log-manager.ts";
import { basename } from "node:path";
import type { Subprocess } from "bun";
import { snapraidCommand } from "../config.ts";
import { runCommand } from "../command.ts";
import { snapraidCommand } from "../config/config.ts";
import { runCommand } from "../system/command.ts";
import { parseRunPos } from "../parsers/progress-parser.ts";
import { createLogTail } from "./log-tail.ts";
import { holdContainers } from "../container-pause.ts";
import { holdContainers } from "../system/container-pause.ts";

// A running SnapRAID with its output piped
type SnapraidProcess = Subprocess<"inherit", "pipe", "pipe">;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// port next to /api and /ws, so the UI runs as a single process without a proxy in front.

import { stat } from "node:fs/promises";
import { appFile } from "./app-files.ts";
import { appFile } from "../system/app-files.ts";

export type FetchHandler = (request: Request) => Response | Promise<Response>;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Server, ServerWebSocket, WebSocketHandler } from "bun";
import { getEngine } from "./engine/engine.ts";
import { getEngine } from "../engine/engine.ts";

// WebSocket connection management
const wsClients = new Set<ServerWebSocket<undefined>>();
Expand Down
Loading
Loading