From ad30bb7aedf6b2e959a0ed90e90e2b991a69f6dc Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 20 Sep 2024 21:24:32 +0200 Subject: Write dabmux config, add README --- README.md | 15 ++++++++++++ src/config.rs | 18 +++++++++++---- src/ui.rs | 51 ++++++++--------------------------------- static/settings.js | 1 + static/style.css | 18 ++++----------- templates/dashboard.html | 6 +---- templates/head.html | 3 ++- templates/settings.html | 7 +++++- templates/settings_applied.html | 12 ---------- 9 files changed, 53 insertions(+), 78 deletions(-) create mode 100644 README.md delete mode 100644 templates/settings_applied.html diff --git a/README.md b/README.md new file mode 100644 index 0000000..923a33e --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +## A control UI for ODR-DabMux + +Goals of this Web User Interface: + + * Simplify creating basic ODR-DabMux DAB Ensemble configurations + * Interact with the ODR-DabMux Remote Control through a web UI + +Complilation prerequisites + + * Install Rust, most probably through [rustup](https://rustup.rs/) + * Type `cargo run` + * Navigate to http://localhost:3000 + * Create a new Ensemble configuration in the Settings page, and specify where to write the odr-dabmux json config file + * Execute `odr-dabmux` with one argument: the configuration file + * Check in the Dashboard page that you see RC values diff --git a/src/config.rs b/src/config.rs index 64f3c09..68b5f44 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,5 +1,6 @@ use std::{collections::HashMap, fs}; use anyhow::Context; +use log::error; use serde::{Deserialize, Serialize}; use serde_json::json; @@ -54,6 +55,7 @@ impl Service { #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Config { pub instance_name: String, + pub dabmux_config_location: String, pub tist: bool, pub tist_offset: i32, // TODO tai_clock_bulletins @@ -79,6 +81,7 @@ impl Default for Config { fn default() -> Self { Config { instance_name: "CHANGEME".to_owned(), + dabmux_config_location: "/etc/odr-dabmux.json".to_owned(), tist: true, tist_offset: 0, ensemble_id: 0x4FFF, @@ -108,7 +111,11 @@ impl Config { pub fn load() -> anyhow::Result { if std::path::Path::new(CONFIGFILE).exists() { let file_contents = fs::read_to_string(CONFIGFILE)?; - toml::from_str(&file_contents).context("parsing config file") + toml::from_str(&file_contents) + .or_else(|e| { + error!("Failed to read existing config file: {}", e); + Ok(Default::default()) + }) } else { Ok(Default::default()) @@ -120,7 +127,7 @@ impl Config { .context("writing config file") } - pub fn dump_to_json(&self) -> serde_json::Value { + pub fn write_dabmux_json(&self) -> anyhow::Result<()> { let now = chrono::Utc::now().to_rfc3339(); let mut services = HashMap::new(); @@ -150,7 +157,7 @@ impl Config { })); } - json!({ + let new_conf = json!({ "_comment": format!("Generated at {} by odr-dabmux-gui", now), "general": { "dabmode": 1, @@ -186,6 +193,9 @@ impl Config { } } } - }) + }); + + fs::write(&self.dabmux_config_location, serde_json::to_string_pretty(&new_conf)?) + .context("writing dabmux config file") } } diff --git a/src/ui.rs b/src/ui.rs index a5be6a5..4a73ba4 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -9,7 +9,6 @@ use axum::{ }; use serde::Deserialize; -use log::info; use tower_http::services::ServeDir; use crate::config; @@ -35,7 +34,6 @@ pub async fn serve(port: u16, shared_state: SharedState) { enum ActivePage { Dashboard, Settings, - None, } impl ActivePage { @@ -44,7 +42,6 @@ impl ActivePage { match self { ActivePage::Dashboard => vec!["dashboard.js", "main.js"], ActivePage::Settings => vec!["settings.js", "main.js"], - ActivePage::None => vec![], } } } @@ -95,7 +92,7 @@ struct SetRc { async fn post_rc( State(state): State, - Json(set_rc): Json) -> (StatusCode, Json) { + Json(set_rc): Json) -> (StatusCode, String) { let set_rc_result = { let mut st = state.lock().unwrap(); @@ -103,11 +100,8 @@ async fn post_rc( }; match set_rc_result { - Ok(v) => (StatusCode::OK, Json(v)), - Err(e) => { - let e_str = serde_json::Value::String(e.to_string()); - (StatusCode::BAD_REQUEST, Json(e_str)) - }, + Ok(v) => (StatusCode::OK, v.as_str().or(Some("")).unwrap().to_owned()), + Err(e) => (StatusCode::BAD_REQUEST, e.to_string()), } } @@ -127,45 +121,20 @@ async fn show_settings(State(state): State) -> SettingsTemplate<'st } } -#[derive(Template)] -#[template(path = "settings_applied.html")] -struct SettingsAppliedTemplate<'a> { - title: &'a str, - page: ActivePage, - conf: config::Config, - ok: bool, - error_message: &'a str, - error_reason: String, -} - async fn post_settings( State(state): State, - Json(conf): Json) -> (StatusCode, SettingsAppliedTemplate<'static>) { + Json(conf): Json) -> (StatusCode, String) { match conf.store() { Ok(()) => { state.lock().unwrap().conf.clone_from(&conf); - info!("{}", conf.dump_to_json()); - - (StatusCode::OK, SettingsAppliedTemplate { - title: "Settings", - conf, - page: ActivePage::None, - ok: true, - error_message: "", - error_reason: "".to_owned(), - }) + match conf.write_dabmux_json() { + Ok(()) => (StatusCode::OK, "".to_owned()), + Err(e) => (StatusCode::INTERNAL_SERVER_ERROR, + format!("Failed to write odr-dabmux config: {}", e.to_string())) + } } - Err(e) => { - (StatusCode::INTERNAL_SERVER_ERROR, SettingsAppliedTemplate { - title: "Settings", - conf, - page: ActivePage::None, - ok: false, - error_message: "Failed to store config", - error_reason: e.to_string(), - }) - }, + Err(e) => (StatusCode::INTERNAL_SERVER_ERROR, format!("Failed to write UI config: {}", e.to_string())) } } diff --git a/static/settings.js b/static/settings.js index 7f5a067..4b917ae 100644 --- a/static/settings.js +++ b/static/settings.js @@ -12,6 +12,7 @@ async function btn_settings_remove_service(element_clicked) { async function btn_settings_send() { let data = { 'instance_name': document.getElementById('instance_name').value, + 'dabmux_config_location': document.getElementById('dabmux_config_location').value, 'tist': document.getElementById('tist').checked, 'tist_offset': parseInt(document.getElementById('tist_offset').value, 10), 'ensemble_id': parseInt(document.getElementById('ensemble_id').value, 16), diff --git a/static/style.css b/static/style.css index 39ca359..c7ab14f 100644 --- a/static/style.css +++ b/static/style.css @@ -1,7 +1,6 @@ :root { --main-color:rgb(7 89 133); --bg-color:rgb(224 242 254); - --title-color:rgb(224 242 254); --title-bg-color:rgb(125 211 252); --divide-color:rgb(125 211 252); --active-bg-color:rgb(12 74 110); @@ -95,8 +94,9 @@ ul { } .text-lg { - font-size: 1.125rem; - line-height: 1.75rem; + font-size: 1.4rem; + line-height: 2rem; + font-weight: bold; } .head-nav-topdiv { @@ -114,7 +114,7 @@ ul { border-radius: 0.5rem; margin-top: 0.5rem; background-color: var(--title-bg-color); - color: var(--title-color); + color: var(--main-color); } main { @@ -122,16 +122,6 @@ main { flex: 1 1 auto; } -h1 { - font-size: 1.2rem; - line-height: 1.75rem; - font-weight: 700; -} - -h2 { - font-weight: 700; -} - a { color: inherit; text-decoration: none; diff --git a/templates/dashboard.html b/templates/dashboard.html index 040538c..a60d6a1 100644 --- a/templates/dashboard.html +++ b/templates/dashboard.html @@ -1,10 +1,6 @@ {% include "head.html" %}
-

Dashboard

-
-

ODR-DabMux

-

www.opendigitalradio.org

-
+

ODR-DabMux Dashboard

Remote control

diff --git a/templates/head.html b/templates/head.html index 7a2e5bb..c835d6e 100644 --- a/templates/head.html +++ b/templates/head.html @@ -16,7 +16,8 @@
diff --git a/templates/settings.html b/templates/settings.html index 74843fb..713947f 100644 --- a/templates/settings.html +++ b/templates/settings.html @@ -4,7 +4,12 @@

General

- + + +
+
+ +
diff --git a/templates/settings_applied.html b/templates/settings_applied.html deleted file mode 100644 index 214b8fd..0000000 --- a/templates/settings_applied.html +++ /dev/null @@ -1,12 +0,0 @@ -{% include "head.html" %} -
- {% if ok %} -

Configuration updated

- {% else %} -

Configuration update failed

-

{{ error_message }}:

-

{{ error_reason }}:

- {% endif %} -
-{% include "foot.html" %} -{# vi:set et sw=2 ts=2: #} -- cgit v1.2.3