Skip to content

Commit 2c87ed6

Browse files
Sbussisoclaude
andcommitted
fix(node): always use paths::data_dir() for I/O, not config.storage.path
THE actual root cause of "binary exits after setup completes" — the single thread connecting every failure mode in the v0.1.20-v0.1.38 saga. Node::new at runner.rs:57 was constructing the storage_path from `config.storage.path`, which defaults to `"./data"` (relative). When fed to PathBuf::from + create_dir_all, that resolves relative to the process's cwd: - Start menu shortcut launch → cwd = `C:\Program Files\SourceBox Sentry CloudNode\` → tries to create `Program Files\...\data\` → ERROR_ACCESS_DENIED for non-admin token (UAC-filtered admin can't write to Program Files even when in the Administrators group). This is what made the binary exit immediately every time the user clicked the Start menu shortcut. - PowerShell launch from System32 → cwd = `C:\Windows\System32` → tries to create `System32\data\` → admin can write so it works BUT writes to the wrong location entirely. This is why the user had a `C:\Windows\System32\data\node.db` file showing up in earlier diagnostic output. - cwd = anywhere with a coincidentally-named `data` folder → silently writes to the wrong place. (This is what caused the Desktop\data pollution from yesterday's debugging.) The diagnostic finally surfaced today thanks to v0.1.38's pause-on-error: the user got a clean look at the error message, then ran the binary as admin from PowerShell which succeeded but streamed segments to: "./data\hls\57db1eac_USB_Webcam\segment_00000.ts" — relative path, working from System32 cwd. The `./data\` prefix in that log line was the smoking gun. Fix: stop trusting `config.storage.path` for I/O. Always use `crate::paths::data_dir()` which already does correct absolute resolution (env var → ProgramData on Windows / ./data on non-Windows). The Node's filesystem layout is now independent of how the binary was launched. `config.storage.path` stays in the config struct because it's exposed in the dashboard's settings page. Updated `build_settings_info` to surface the actual absolute path (`paths::data_dir().display().to_string()`) instead of the legacy config field, so operators see WHERE their data actually lives. This fixes: - The Start-menu-shortcut "binary exits with Access denied" - The "ran as admin from PowerShell so it works but writes to System32\data" wrong-location problem - The whole class of relative-path bugs that paths::data_dir was supposed to insulate against but couldn't because Node wasn't using paths::data_dir at all Bumps version to 0.1.39. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent a65a7f9 commit 2c87ed6

3 files changed

Lines changed: 27 additions & 4 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# should reflect that. Going from `opensentry-cloudnode` to
66
# `sourcebox-sentry-cloudnode` keeps the binary name explicit + branded.
77
name = "sourcebox-sentry-cloudnode"
8-
version = "0.1.38"
8+
version = "0.1.39"
99
edition = "2021"
1010
authors = ["SourceBox LLC"]
1111
description = "SourceBox Sentry CloudNode — turns a USB webcam into a cloud-connected security camera."

src/node/runner.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,27 @@ struct RunningStream {
5454
impl Node {
5555
pub async fn new(config: Config) -> Result<Self> {
5656
let api_client = ApiClient::new(&config.cloud.api_url, &config.cloud.api_key)?;
57-
let storage_path = PathBuf::from(&config.storage.path);
57+
// CRITICAL: ignore `config.storage.path` for I/O. That field
58+
// defaults to the relative `./data` and is never overridden in
59+
// practice — using it with `PathBuf::from` resolves relative
60+
// to cwd, which on a Start-menu-shortcut launch is the
61+
// Program Files install dir (read-only for non-admin users)
62+
// and on an admin PowerShell launch from System32 is
63+
// C:\Windows\System32 (admin can write but it's the wrong
64+
// location). Either way, segments / node.db / recordings
65+
// end up somewhere unexpected.
66+
//
67+
// `paths::data_dir()` is the canonical absolute resolver: env
68+
// var → platform default (`%ProgramData%\SourceBoxSentry` on
69+
// Windows, `./data` on non-Windows where cwd is predictable).
70+
// Using it here makes the Node's filesystem layout
71+
// independent of how the binary was launched.
72+
//
73+
// `config.storage.path` is still surfaced via
74+
// `build_settings_info` for the dashboard's settings page so
75+
// operators see WHERE their data lives — but that's a
76+
// display string now, not an I/O path.
77+
let storage_path = crate::paths::data_dir();
5878
std::fs::create_dir_all(&storage_path)?;
5979
let db = NodeDatabase::new(&storage_path.join("node.db"))?;
6080
let hls_output_dir = storage_path.join("hls");
@@ -71,7 +91,10 @@ impl Node {
7191
fn build_settings_info(&self) -> crate::dashboard::SettingsInfo {
7292
crate::dashboard::SettingsInfo {
7393
node_name: self.config.node.name.clone(),
74-
storage_path: self.config.storage.path.clone(),
94+
// Show the actual absolute storage path (where the I/O really
95+
// lands) instead of the legacy `config.storage.path` value
96+
// (which is now ignored by Node::new).
97+
storage_path: crate::paths::data_dir().display().to_string(),
7598
max_size_gb: self.config.storage.max_size_gb,
7699
segment_duration: self.config.streaming.hls.segment_duration,
77100
fps: self.config.streaming.fps,

0 commit comments

Comments
 (0)