Resolve data and binary folders before starting the server (0.1.2)
onvif-dashboard install-video put MediaMTX in ./bin relative to where it was run, but start launches the server from inside the package, so the app looked for it there and reported it missing. serverEnvironment() now settles CAMERAS_DATA_DIR and CAMERAS_BIN_DIR while still in the user's directory, and start passes them on. Checked from an installed tarball: MediaMTX in ./bin is found and the video bridge comes up. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
daaecb7452
commit
731206be8e
@ -6,7 +6,7 @@ import { access } from "node:fs/promises";
|
||||
import { createInterface } from "node:readline/promises";
|
||||
import { parseArgs } from "node:util";
|
||||
import path from "node:path";
|
||||
import { applyEnvironment, firstRun, SECRETS_FILE } from "../dist/lib/first-run.js";
|
||||
import { applyEnvironment, firstRun, SECRETS_FILE, serverEnvironment } from "../dist/lib/first-run.js";
|
||||
import { installMediamtx } from "../dist/lib/mediamtx-install.js";
|
||||
import { adminFilePath, readAdminFile } from "../dist/lib/admin-file.js";
|
||||
|
||||
@ -70,8 +70,9 @@ async function start() {
|
||||
if (!process.env.CAMERA_CREDENTIALS_KEY) {
|
||||
// Never started before: take the defaults quietly rather than refuse to run.
|
||||
await firstRun();
|
||||
await applyEnvironment();
|
||||
}
|
||||
// Settle every path now: the server runs from inside the package, not from here.
|
||||
await serverEnvironment();
|
||||
|
||||
const server = path.join(import.meta.dirname, "..", ".next", "standalone", "server.js");
|
||||
if (!(await access(server).then(() => true, () => false))) {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "onvif-dashboard",
|
||||
"version": "0.1.1",
|
||||
"version": "0.1.2",
|
||||
"description": "Web dashboard for ONVIF cameras (Hikvision, Annke): discovery, live video over WebRTC, motion recording and settings, all on your own network.",
|
||||
"keywords": [
|
||||
"onvif",
|
||||
|
||||
@ -4,6 +4,7 @@ import path from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
applyEnvironment,
|
||||
serverEnvironment,
|
||||
configFile,
|
||||
ensureSecrets,
|
||||
firstRun,
|
||||
@ -188,3 +189,23 @@ describe("applyEnvironment", () => {
|
||||
expect(env.CAMERA_CREDENTIALS_KEY).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("serverEnvironment", () => {
|
||||
it("pins the data and binary folders before the server starts elsewhere", async () => {
|
||||
await writeConfig(work, {}, home);
|
||||
await ensureSecrets(work);
|
||||
const env: Record<string, string | undefined> = {};
|
||||
await serverEnvironment(env, home);
|
||||
|
||||
expect(env.CAMERAS_DATA_DIR).toBe(work);
|
||||
// Resolved from where the command was typed, not from wherever the server will run.
|
||||
expect(env.CAMERAS_BIN_DIR).toBe(path.join(cwd, "bin"));
|
||||
expect(env.CAMERA_CREDENTIALS_KEY).toMatch(/^[0-9a-f]{64}$/);
|
||||
});
|
||||
|
||||
it("leaves anything the environment already set alone", async () => {
|
||||
const env = { CAMERAS_DATA_DIR: "/srv/data", CAMERAS_BIN_DIR: "/opt/bin" };
|
||||
await serverEnvironment(env, home);
|
||||
expect(env).toMatchObject({ CAMERAS_DATA_DIR: "/srv/data", CAMERAS_BIN_DIR: "/opt/bin" });
|
||||
});
|
||||
});
|
||||
|
||||
@ -14,7 +14,7 @@ import { randomBytes } from "node:crypto";
|
||||
import { chmod, mkdir, readFile, writeFile } from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { dataDir as defaultDataDir, mediamtxBinary } from "./paths.ts";
|
||||
import { binDir as defaultBinDir, dataDir as defaultDataDir, mediamtxBinary } from "./paths.ts";
|
||||
|
||||
type Env = Record<string, string | undefined>;
|
||||
|
||||
@ -151,3 +151,15 @@ export async function applyEnvironment(env: Env = process.env, home = os.homedir
|
||||
const stored = parseEnvFile(await readFile(path.join(dir, SECRETS_FILE), "utf8").catch(() => ""));
|
||||
for (const [key, value] of Object.entries(stored)) env[key] ??= value;
|
||||
}
|
||||
|
||||
/**
|
||||
* The environment the server is started with. The server runs from inside the package, so
|
||||
* anything resolved from the working directory has to be settled here, while we are still
|
||||
* in the directory the user typed the command in (vrek iss-9zcawn7).
|
||||
*/
|
||||
export async function serverEnvironment(env: Env = process.env, home = os.homedir()): Promise<Env> {
|
||||
await applyEnvironment(env, home);
|
||||
env.CAMERAS_DATA_DIR ??= defaultDataDir(env);
|
||||
env.CAMERAS_BIN_DIR ??= defaultBinDir(env);
|
||||
return env;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user