Skip to main content

Config

Struct Config 

Source
pub struct Config {
Show 96 fields pub database_url: String, pub data_dir: PathBuf, pub recordings_dir: PathBuf, pub clips_dir: PathBuf, pub snapshots_dir: PathBuf, pub frames_dir: PathBuf, pub playback_dir: PathBuf, pub ffmpeg_bin: String, pub ffprobe_bin: String, pub mediamtx_api_url: String, pub mediamtx_hls_base: String, pub mediamtx_rtsp_base: String, pub mediamtx_webrtc_base: String, pub db_max_connections: u32, pub recorder_enabled: bool, pub mirror_recordings_dir: Option<PathBuf>, pub anr_enabled: bool, pub anr_interval_s: u64, pub anr_max_gap_hours: i64, pub anr_max_attempts: i64, pub default_segment_seconds: i64, pub default_retention_hours: i64, pub default_camera_quota_bytes: u64, pub default_record_audio: bool, pub default_pre_roll_seconds: i64, pub default_post_roll_seconds: i64, pub indexer_interval_s: u64, pub health_interval_s: u64, pub retention_interval_s: u64, pub api_host: String, pub api_port: u16, pub cors_origins: Vec<String>, pub max_recordings_bytes: u64, pub min_free_disk_bytes: u64, pub notifier_interval_s: u64, pub ai_enabled: bool, pub ai_max_total_fps: f64, pub default_ai_fps: f64, pub default_ai_width: i64, pub detection_retention_hours: i64, pub snapshot_scheduler_enabled: bool, pub snapshot_scheduler_interval_s: u64, pub snapshot_retention_hours: i64, pub schedule_check_interval_s: u64, pub playback_session_ttl_minutes: i64, pub max_playback_seconds: f64, pub auth_enabled: bool, pub session_ttl_hours: i64, pub auth_cookie_secure: bool, pub bootstrap_admin_user: Option<String>, pub bootstrap_admin_password: Option<String>, pub audit_retention_days: i64, pub overlay_enabled: bool, pub overlay_kind: String, pub overlay_iface: Option<String>, pub rclone_bin: String, pub backup_enabled: bool, pub backup_scheduler_interval_s: u64, pub backup_job_timeout_s: u64, pub backup_max_concurrent_jobs: usize, pub archive_dir: PathBuf, pub archive_max_bytes: u64, pub archive_retention_hours: i64, pub onvif_discovery_timeout_ms: u64, pub onvif_request_timeout_ms: u64, pub isapi_request_timeout_ms: u64, pub smart_check_enabled: bool, pub smart_devices: Vec<String>, pub mdstat_check_enabled: bool, pub smart_check_interval_s: u64, pub readyz_min_recording_percent: f64, pub live_transcode_engine: String, pub vaapi_device: String, pub site_id: Option<String>, pub cp_url: Option<String>, pub public_base_url: Option<String>, pub cp_token: String, pub cp_register_interval_s: u64, pub cp_tls: Option<CpTlsCfg>, pub registry_enabled: bool, pub registry_urls: Vec<String>, pub registry_refresh_s: u64, pub registry_fetch_timeout_s: u64, pub registry_trusted_keys: Vec<(String, String)>, pub registry_allow_unverified: bool, pub registry_allow_private: bool, pub web_dir: Option<PathBuf>, pub smtp_host: Option<String>, pub smtp_port: u16, pub smtp_username: Option<String>, pub smtp_password: Option<String>, pub smtp_from: Option<String>, pub smtp_tls: String, pub smtp_recipients: Vec<String>, pub smtp_min_severity: String, pub smtp_interval_s: u64,
}
Expand description

Runtime configuration, loaded from environment (see .env.example).

Fields§

§database_url: String§data_dir: PathBuf§recordings_dir: PathBuf§clips_dir: PathBuf§snapshots_dir: PathBuf§frames_dir: PathBuf§playback_dir: PathBuf

Directory where segment-spanning HLS playback sessions are generated (one subdir per session).

§ffmpeg_bin: String§ffprobe_bin: String§mediamtx_api_url: String§mediamtx_hls_base: String§mediamtx_rtsp_base: String§mediamtx_webrtc_base: String§db_max_connections: u32

Max SQLite pool connections. Tunable per deployment: more absorbs bursts of concurrent requests (WAL serves reads concurrently; writes still serialize), at the cost of memory.

§recorder_enabled: bool§mirror_recordings_dir: Option<PathBuf>

Optional second recordings root for dual/mirror recording. When set, cameras with mirror_enabled get a SECOND ffmpeg pipeline writing byte-identical segments here (a redundant DVR copy on a separate volume). Empty/unset disables mirror recording entirely.

§anr_enabled: bool

Master switch for ANR (Automatic Network Replenishment) edge re-fill: re-fetch missed footage from a camera’s onboard storage to fill recording gaps. Cameras still need anr_enabled.

§anr_interval_s: u64

How often the ANR loop scans for pending gaps to fill (seconds).

§anr_max_gap_hours: i64

Ignore gaps older than this many hours (most cameras only retain recent onboard footage).

§anr_max_attempts: i64

Give up on a gap after this many fill attempts (marked failed).

§default_segment_seconds: i64§default_retention_hours: i64§default_camera_quota_bytes: u64

Default per-camera storage quota (bytes) applied when a camera is created without an explicit storage_quota_bytes. 0 means no default quota (the camera’s quota is stored as NULL).

§default_record_audio: bool

Default audio-recording toggle applied when a camera is created without an explicit record_audio. When false (default) the recorder drops audio (video only).

§default_pre_roll_seconds: i64

Default pre-roll seconds applied when a camera is created without an explicit pre_roll_seconds (event / scheduled_event recording). Clamped to 0..300 in handlers.

§default_post_roll_seconds: i64

Default post-roll seconds (the trigger recording window) applied when a camera is created without an explicit post_roll_seconds. Clamped to 0..3600 in handlers.

§indexer_interval_s: u64§health_interval_s: u64§retention_interval_s: u64§api_host: String§api_port: u16§cors_origins: Vec<String>§max_recordings_bytes: u64

Soft cap on total recording footprint; oldest unlocked segments are pruned above this.

§min_free_disk_bytes: u64

Hard floor on free disk space; when free space drops below this, oldest unlocked segments are pruned regardless of age/size policy (protects the host from a full disk).

§notifier_interval_s: u64

How often the alert notifier polls for new events to deliver.

§ai_enabled: bool

Master switch for AI frame sampling (Stage 2). Cameras still need an enabled AI task.

§ai_max_total_fps: f64

Global frame-sampling budget (frames/sec summed across all cameras); per-camera fps is reduced proportionally above this so adding AI cameras degrades fps instead of overloading.

§default_ai_fps: f64§default_ai_width: i64§detection_retention_hours: i64

How long detection rows are kept before the retention sweeper prunes them.

§snapshot_scheduler_enabled: bool

Master switch for the background snapshot scheduler (interval live-frame captures).

§snapshot_scheduler_interval_s: u64

How often the scheduler ticks to look for due schedules (seconds).

§snapshot_retention_hours: i64

How long captured snapshots are kept before the retention sweeper prunes them. 0 = no pruning.

§schedule_check_interval_s: u64

How often the schedule watcher ticks to open/close recording windows for scheduled / scheduled_event cameras (seconds). Windows are evaluated against the SERVER’s LOCAL timezone.

§playback_session_ttl_minutes: i64

How long a generated playback session (its HLS dir + the segment read-locks it holds) is retained before the cleanup sweeper removes the dir and releases its locks. Server time.

§max_playback_seconds: f64

Maximum playback session span (seconds); a longer requested range is rejected (HTTP 400).

§auth_enabled: bool

Master switch for authentication + RBAC. When false, the API is open (dev/single-tenant LAN appliance default) and a synthetic admin principal is used. When true, the auth/admin surface requires a valid bearer token (session or API key) and enforces roles.

§session_ttl_hours: i64

Lifetime of an issued login session token.

§auth_cookie_secure: bool

Add Secure to the session cookie (require HTTPS). Default false for HTTP LAN/overlay appliances; set true when the deployment is served over TLS.

§bootstrap_admin_user: Option<String>

Optional first-run admin bootstrap (only used when no users exist yet).

§bootstrap_admin_password: Option<String>§audit_retention_days: i64

How long kernel audit-log + generic-event rows are kept before retention prunes them.

§overlay_enabled: bool

Whether this deployment is reached through a WireGuard overlay (Tailscale / NetBird / wireguard) running as an external daemon on the host. The kernel does not manage the overlay; it only reports whether the configured interface is present + up so the dashboard can surface remote-access health. When false, the deployment is LAN-only.

§overlay_kind: String

Label for the overlay in use: tailscale | netbird | wireguard | none.

§overlay_iface: Option<String>

The overlay’s network interface to probe (e.g. tailscale0, wt0, wg0).

§rclone_bin: String

Path to the rclone binary used for sftp/ftp/s3 remote backups. Local/NAS-mount backups use std fs copy and never need it; remote backups degrade to a clear job error when it is missing.

§backup_enabled: bool

Master switch for the background backup scheduler (scheduled policy jobs). On-demand archive export still works when this is false.

§backup_scheduler_interval_s: u64

How often the backup scheduler ticks to look for due policies (seconds).

§backup_job_timeout_s: u64

Hard timeout for a single backup job’s transfer (seconds); a job exceeding it is marked error.

§backup_max_concurrent_jobs: usize

Maximum number of backup jobs running concurrently (a tokio Semaphore bounds the scheduler + manual triggers).

§archive_dir: PathBuf

Where on-demand archive (.zip) exports are written; also served at /media/archives.

§archive_max_bytes: u64

Maximum total source footprint (sum of segment sizes) for a single archive export; a larger selection is rejected (HTTP 400).

§archive_retention_hours: i64

How long archive exports + finished backup-job rows are kept before retention prunes them.

§onvif_discovery_timeout_ms: u64

How long the WS-Discovery probe listens for ProbeMatch replies (milliseconds).

§onvif_request_timeout_ms: u64

Per-request timeout for an ONVIF SOAP call (GetDeviceInformation, PTZ, etc.) in milliseconds.

§isapi_request_timeout_ms: u64

Per-request timeout for a HikVision ISAPI camera-config call (HTTP Digest) in milliseconds.

§smart_check_enabled: bool

Run periodic SMART self-assessment checks (smartctl -H) inside the health loop. Off by default; needs smartmontools on PATH. Missing binary degrades to a one-time log + skip.

§smart_devices: Vec<String>

Block devices to query when SMART checks are enabled (e.g. /dev/sda,/dev/sdb).

§mdstat_check_enabled: bool

Watch /proc/mdstat (Linux md/RAID) and emit raid_degraded when an array shows a down member.

§smart_check_interval_s: u64

Cadence of the disk-health (SMART/RAID) check inside the health loop (seconds).

§readyz_min_recording_percent: f64

When > 0, /readyz also requires at least this percent of enabled cameras to be actively recording (503 insufficient_recorders otherwise). 0 (default) keeps DB-connectivity-only.

§live_transcode_engine: String

Encoder engine for the live preview transcode path: software (libx264, default), vaapi, or nvenc. Unknown values warn and fall back to software.

§vaapi_device: String

VAAPI render node used when live_transcode_engine = vaapi.

§site_id: Option<String>

Optional site identifier stamped onto outbox rows and surfaced at GET /api/v1/site for the edge->cloud fleet uplink. Empty/unset = a single unnamed site.

§cp_url: Option<String>

Control-plane base URL for edge-side self-registration (HELDAR_CP_URL). Unset (default) = this node never phones home; the fleet is opt-in. When set together with site_id and public_base_url, the node POSTs its identity to the control plane on boot + on a heartbeat, so the control plane drains it without any static config or restart.

§public_base_url: Option<String>

This node’s externally reachable base URL, as the control plane should address it (HELDAR_PUBLIC_BASE_URL, e.g. its overlay/WireGuard address). Required for self-registration — the node cannot infer it (it binds 0.0.0.0). Unset → self-registration parks.

§cp_token: String

Bearer credential the control plane presents when draining this node’s outbox (HELDAR_CP_TOKEN). Empty (default) when this node runs with auth disabled (the LAN default); when auth is enabled, set it to a valid API key the control plane may use.

§cp_register_interval_s: u64

Heartbeat cadence (seconds) for re-registration with the control plane (HELDAR_CP_REGISTER_INTERVAL_S). Re-registration is idempotent, so the heartbeat also re-teaches a control plane that restarted or lost its registry.

§cp_tls: Option<CpTlsCfg>

Optional mTLS material for talking to the control plane: this node’s client cert + key (to present when registering) and the CA that signed the control plane’s server cert (to verify it). Required as a set when the control plane enforces mTLS; unset = plain HTTP to the control plane (the LAN/overlay default).

§registry_enabled: bool

Master switch for the plugin store’s remote-registry fetching. When false, the store shows only the bundled open catalog + locally installed plugins (fully offline). The bundled catalog is always available regardless.

§registry_urls: Vec<String>

Remote signed-catalog URLs to fetch (comma-separated). Default EMPTY — no phone-home; an operator (or the proprietary build) sets the official Straits-AI registry here to populate the proprietary/community shelves.

§registry_refresh_s: u64

How often the background loop refreshes remote registries (seconds).

§registry_fetch_timeout_s: u64

Per-fetch timeout for a remote catalog (seconds).

§registry_trusted_keys: Vec<(String, String)>

Operator-pinned extra trust anchors, key_id:base64pubkey comma-separated, added to the compile-time pinned keys (for private registries).

§registry_allow_unverified: bool

When true, surface a remote registry’s entries even if its signature does not verify (badged unverified). Default false — fail closed.

§registry_allow_private: bool

When true, allow remote registry URLs that resolve to private/link-local addresses (default false; SSRF guard for the admin-configured fetch).

§web_dir: Option<PathBuf>

Directory holding the built React dashboard (apps/web/dist), served as a static SPA fallback so the whole product is one binary at one URL. Resolved from HELDAR_WEB_DIR; when unset it falls back to apps/web/dist relative to the binary CWD. None when neither path exists — the server then runs API-only (no dashboard).

§smtp_host: Option<String>

SMTP relay host. Unset = email notifications disabled (the notifier parks).

§smtp_port: u16§smtp_username: Option<String>§smtp_password: Option<String>§smtp_from: Option<String>

Envelope/From address (e.g. heldar@site.example). Required to send.

§smtp_tls: String

starttls (587, default) | implicit (465) | none.

§smtp_recipients: Vec<String>

Recipient addresses that receive matching-event emails.

§smtp_min_severity: String

Severity floor for emailed events: info | warning (default) | critical.

§smtp_interval_s: u64

How often the notifier polls for new events to email (seconds).

Implementations§

Source§

impl Config

Source

pub fn from_env() -> Self

Source

pub fn camera_recordings_dir(&self, camera_id: &str) -> PathBuf

Directory where a camera’s segments are stored.

Source

pub fn camera_frames_dir(&self, camera_id: &str) -> PathBuf

Directory where a camera’s sampled AI frames are written.

Trait Implementations§

Source§

impl Clone for Config

Source§

fn clone(&self) -> Config

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Config

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FromRef<T> for T
where T: Clone,

Source§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
Source§

impl<A, B, T> HttpServerConnExec<A, B> for T
where B: Body,

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more