From 95fcb6f26a012904fb643ed600e3f4aa1b7e902d Mon Sep 17 00:00:00 2001 From: Chris Frankland-Wright Date: Tue, 12 Aug 2025 15:58:21 +0100 Subject: [PATCH 01/12] feat: Add systemd service for TimeTurner auto-start Co-authored-by: aider (gemini/gemini-2.5-pro) --- timeturner.service | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 timeturner.service diff --git a/timeturner.service b/timeturner.service new file mode 100644 index 0000000..443e99c --- /dev/null +++ b/timeturner.service @@ -0,0 +1,15 @@ +[Unit] +Description=NTP TimeTurner Daemon +After=network.target + +[Service] +Type=forking +ExecStart=/opt/timeturner/timeturner daemon +WorkingDirectory=/opt/timeturner +PIDFile=/opt/timeturner/ntp_timeturner.pid +Restart=always +User=root +Group=root + +[Install] +WantedBy=multi-user.target From af0a5121873828379593b3ad55c4dae563bbeadb Mon Sep 17 00:00:00 2001 From: Chris Frankland-Wright Date: Tue, 12 Aug 2025 16:00:43 +0100 Subject: [PATCH 02/12] docs: Document web interface and clarify API server startup Co-authored-by: aider (gemini/gemini-2.5-pro) --- README.md | 11 +++++++++++ src/main.rs | 15 +++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8a7b357..40c9127 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,17 @@ Created by Chris Frankland-Wright and John Rogers - Broadcasts time via local NTP server - Supports configurable time offsets (hours, minutes, seconds, frames or milliseconds) - Systemd service support for headless operation +- Web-based UI for monitoring and control when running as a daemon + +--- + +## 🖥️ Web Interface & API + +When running as a background daemon, TimeTurner provides a web interface for monitoring and configuration. + +- **Access**: The web UI is available at `http://:8080`. +- **Functionality**: You can view the real-time sync status, see logs, and change all configuration options directly from your browser. +- **API**: A JSON API is also exposed for programmatic access. See `docs/api.md` for full details. --- diff --git a/src/main.rs b/src/main.rs index ab9fa94..8006681 100644 --- a/src/main.rs +++ b/src/main.rs @@ -193,11 +193,13 @@ async fn main() { }); } - // 5️⃣ Spawn UI or setup daemon logging + // 5️⃣ Spawn UI or setup daemon logging. The web service is only started + // when running as a daemon. The TUI is for interactive foreground use. if args.command.is_none() { + // --- Interactive TUI Mode --- log::info!("🔧 Watching config.yml..."); log::info!("🚀 Serial thread launched"); - log::info!("🖥️ UI thread launched"); + log::info!("🖥️ UI thread launched"); let ui_state = ltc_state.clone(); let config_clone = config.clone(); let port = serial_port_path; @@ -205,8 +207,10 @@ async fn main() { start_ui(ui_state, port, config_clone); }); } else { + // --- Daemon Mode --- // In daemon mode, logging is already set up to go to stderr. - // The systemd service will capture it. + // The systemd service will capture it. The web service (API and static files) + // is launched later in the main async block. log::info!("🚀 Starting TimeTurner daemon..."); } @@ -282,7 +286,10 @@ async fn main() { let local = LocalSet::new(); local .run_until(async move { - // 8️⃣ Spawn the API server thread + // 8️⃣ Spawn the API server task. + // This server provides the JSON API and serves the static web UI files + // from the `static/` directory. It runs in both TUI and daemon modes, + // but is primarily for the web UI used in daemon mode. { let api_state = ltc_state.clone(); let config_clone = config.clone(); From 8e369a2e3a7f71043c643f976d5a02655390b254 Mon Sep 17 00:00:00 2001 From: Chris Frankland-Wright Date: Tue, 12 Aug 2025 16:02:25 +0100 Subject: [PATCH 03/12] fix: Ensure static web assets are installed and clarify service config Co-authored-by: aider (gemini/gemini-2.5-pro) --- setup.sh | 8 +++++--- timeturner.service | 3 +++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/setup.sh b/setup.sh index 4dd5685..b8d556f 100644 --- a/setup.sh +++ b/setup.sh @@ -21,11 +21,13 @@ echo "🔧 Creating directories..." sudo mkdir -p $INSTALL_DIR echo "✅ Directory $INSTALL_DIR created." -# 3. Install binary -echo "🚀 Installing timeturner binary..." +# 3. Install binary and static web files +echo "🚀 Installing timeturner binary and web assets..." sudo cp target/release/ntp_timeturner $INSTALL_DIR/timeturner +# The static directory contains the web UI files +sudo cp -r static $INSTALL_DIR/ sudo ln -sf $INSTALL_DIR/timeturner $BIN_DIR/timeturner -echo "✅ Binary installed to $INSTALL_DIR and linked to $BIN_DIR." +echo "✅ Binary and assets installed to $INSTALL_DIR, and binary linked to $BIN_DIR." # 4. Install systemd service file if [[ "$(uname)" == "Linux" ]]; then diff --git a/timeturner.service b/timeturner.service index 443e99c..f3daec8 100644 --- a/timeturner.service +++ b/timeturner.service @@ -4,6 +4,9 @@ After=network.target [Service] Type=forking +# The 'timeturner daemon' command starts the background process. +# It requires 'config.yml' and the 'static/' web assets directory +# to be present in the WorkingDirectory. ExecStart=/opt/timeturner/timeturner daemon WorkingDirectory=/opt/timeturner PIDFile=/opt/timeturner/ntp_timeturner.pid From 1075be6e241dfa6b2653cff66ab2dc09da09230e Mon Sep 17 00:00:00 2001 From: Chris Frankland-Wright Date: Tue, 12 Aug 2025 16:06:38 +0100 Subject: [PATCH 04/12] hide sections --- static/index.html | 120 +++++++++++++++++++++++----------------------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/static/index.html b/static/index.html index 7178fb9..92a02b3 100644 --- a/static/index.html +++ b/static/index.html @@ -62,71 +62,71 @@

Controls

-
- - + +
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + + +
+ +
+ + + + +
-
- - -
-
- -
-
- - +
+ + +
+
+ Logs Icon +

Logs

-
- - -
-
- - -
-
- - -
-
- - +
+

                         
-
- - - -
-
- - - - - -
-
- - - - -
-
-
- - -
-
- Logs Icon -

Logs

-
-
-

-                
-
-