Add process-wide Settings model (ticket 008)
Introduces src/settings.rs with a single, process-wide Settings struct
(colour scheme, CSS entries shaped for imported-vs-linked, and a
profiles placeholder for ticket 009), JSON-serialized via serde_json to
keep deps minimal. Default settings path is computed with the
directories crate (ProjectDirs::from("", "", "ottyl")) and overridable
via a new --settings-path CLI arg. Settings::load creates and persists
a default file on first run; Settings::save persists changes.
Wires a single Arc<Mutex<Settings>> into main() and threads it through
api::router as an additive ApiState field for tickets 010/011 to build
on.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
1fb564d06b
commit
22647620fa
+38
-1
@@ -5,12 +5,18 @@ mod engine;
|
||||
mod index_key;
|
||||
mod ingest;
|
||||
mod metric_primitive;
|
||||
mod settings;
|
||||
mod timestamp;
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use clap::Parser;
|
||||
use tokio::net::TcpListener;
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
use settings::Settings;
|
||||
|
||||
/// Observability dashboard from terminal output.
|
||||
#[derive(Parser, Debug)]
|
||||
struct Args {
|
||||
@@ -21,17 +27,28 @@ struct Args {
|
||||
/// Directory containing the built webapp (index.html + assets).
|
||||
#[arg(long, default_value = "webapp/dist")]
|
||||
static_dir: String,
|
||||
|
||||
/// Path to the settings file. Defaults to a per-OS config location
|
||||
/// (e.g. `~/.config/ottyl/settings.json` on Linux).
|
||||
#[arg(long)]
|
||||
settings_path: Option<PathBuf>,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let args = Args::parse();
|
||||
|
||||
let settings_path = args.settings_path.clone().unwrap_or_else(|| {
|
||||
settings::default_settings_path()
|
||||
.expect("could not determine a default settings path; pass --settings-path")
|
||||
});
|
||||
let settings = Arc::new(Mutex::new(Settings::load(&settings_path)));
|
||||
|
||||
let (engine_tx, engine_rx) = mpsc::channel(1024);
|
||||
tokio::spawn(engine::run(engine_rx));
|
||||
tokio::spawn(ingest::run(engine_tx.clone()));
|
||||
|
||||
let app = api::router(engine_tx, &args.static_dir);
|
||||
let app = api::router(engine_tx, &args.static_dir, settings);
|
||||
let listener = TcpListener::bind(("0.0.0.0", args.port))
|
||||
.await
|
||||
.expect("failed to bind listener");
|
||||
@@ -45,3 +62,23 @@ async fn main() {
|
||||
.await
|
||||
.expect("server error");
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn settings_path_defaults_to_none() {
|
||||
let args = Args::parse_from(["ottyl"]);
|
||||
assert_eq!(args.settings_path, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn settings_path_flag_overrides_default() {
|
||||
let args = Args::parse_from(["ottyl", "--settings-path", "/tmp/custom-settings.json"]);
|
||||
assert_eq!(
|
||||
args.settings_path,
|
||||
Some(PathBuf::from("/tmp/custom-settings.json"))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user