From 716f7549fd73427a90aa2df6541c55986329a567 Mon Sep 17 00:00:00 2001 From: Tsiry Sandratraina Date: Sun, 26 Jan 2025 19:26:55 +0300 Subject: [PATCH] feat: add systemd service commands --- README.md | 21 +++++++ src/main.rs | 26 +++++++++ src/server/mod.rs | 11 ++++ src/service.rs | 111 +++++++++++++++++++++++++++++++++++++ src/systemd/tunein.service | 10 ++++ 5 files changed, 179 insertions(+) create mode 100644 src/service.rs create mode 100644 src/systemd/tunein.service diff --git a/README.md b/README.md index 2e0b733..be04cac 100644 --- a/README.md +++ b/README.md @@ -146,6 +146,27 @@ tunein play "alternativeradio.us" tunein play s221580 ``` +## 🧙 Systemd Service + +Tunein daemon can be started as a systemd service. To enable and start the service, run the following command: + +```bash +tunein service install +``` + +To disable and stop the service, run the following command: + +```bash +tunein service uninstall +``` + +To check the status of the service, run the following command: + +```bash +tunein service status +``` + + ## API Documentation [https://buf.build/tsiry/tuneinserverapis/docs/main:tunein.v1alpha1](https://buf.build/tsiry/tuneinserverapis/docs/main:tunein.v1alpha1) diff --git a/src/main.rs b/src/main.rs index 75c9255..844a0c0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,6 +13,7 @@ mod player; mod provider; mod search; mod server; +mod service; mod tags; mod tui; mod types; @@ -58,6 +59,22 @@ A simple CLI to listen to radio stations"#, .about("Start the server") .arg(arg!([port] "The port to listen on").default_value("8090")), ) + .subcommand( + Command::new("service") + .about("Manage systemd service for tunein-cli server") + .subcommand( + Command::new("install") + .about("Install systemd service for tunein-cli server") + ) + .subcommand( + Command::new("uninstall") + .about("Uninstall systemd service for tunein-cli server") + ) + .subcommand( + Command::new("status") + .about("Check status of tunein-cli systemd service") + ) + ) } #[tokio::main] @@ -93,6 +110,15 @@ async fn main() -> Result<(), Error> { let port = port.parse::().unwrap(); server::exec(port).await?; } + Some(("service", sub_m)) => match sub_m.subcommand() { + Some(("install", _)) => service::install()?, + Some(("uninstall", _)) => service::uninstall()?, + Some(("status", _)) => service::status()?, + _ => { + println!("Invalid subcommand. Use `tunein service --help` for more information"); + std::process::exit(1); + } + }, _ => unreachable!(), } diff --git a/src/server/mod.rs b/src/server/mod.rs index 88b399c..ffc6cf2 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -15,6 +15,17 @@ pub mod playback; pub async fn exec(port: u16) -> Result<(), Error> { let addr: SocketAddr = format!("0.0.0.0:{}", port).parse().unwrap(); + println!( + "{}", + r#" + ______ ____ _______ ____ + /_ __/_ _____ ___ / _/__ / ___/ / / _/ + / / / // / _ \/ -_)/ // _ \ / /__/ /___/ / + /_/ \_,_/_//_/\__/___/_//_/ \___/____/___/ + + "# + .bright_green() + ); println!("Listening on {}", addr.cyan()); Server::builder() .accept_http1(true) diff --git a/src/service.rs b/src/service.rs new file mode 100644 index 0000000..d22f85e --- /dev/null +++ b/src/service.rs @@ -0,0 +1,111 @@ +use std::{path::Path, process::Command}; + +use anyhow::Error; + +const SERVICE_TEMPLATE: &str = include_str!("./systemd/tunein.service"); + +pub fn install() -> Result<(), Error> { + if cfg!(not(target_os = "linux")) { + println!("This command is only supported on Linux"); + std::process::exit(1); + } + + let home = std::env::var("HOME")?; + let service_path: &str = &format!("{}/.config/systemd/user/tunein.service", home); + std::fs::create_dir_all(format!("{}/.config/systemd/user", home)) + .expect("Failed to create systemd user directory"); + + if Path::new(service_path).exists() { + println!("Service file already exists. Nothing to install."); + return Ok(()); + } + + let tunein_path = std::env::current_exe()?; + + let service_template: &str = &SERVICE_TEMPLATE.replace( + "ExecStart=/usr/bin/tunein", + &format!("ExecStart={}", tunein_path.display()), + ); + + std::fs::write(service_path, service_template).expect("Failed to write service file"); + + Command::new("systemctl") + .arg("--user") + .arg("daemon-reload") + .status()?; + + Command::new("systemctl") + .arg("--user") + .arg("enable") + .arg("tunein") + .status()?; + + Command::new("systemctl") + .arg("--user") + .arg("start") + .arg("tunein") + .status()?; + + println!("✅ Tunein service installed successfully!"); + + Ok(()) +} + +pub fn uninstall() -> Result<(), Error> { + if cfg!(not(target_os = "linux")) { + println!("This command is only supported on Linux"); + std::process::exit(1); + } + + let home = std::env::var("HOME")?; + let service_path: &str = &format!("{}/.config/systemd/user/tunein.service", home); + + if Path::new(service_path).exists() { + Command::new("systemctl") + .arg("--user") + .arg("stop") + .arg("tunein") + .status()?; + + Command::new("systemctl") + .arg("--user") + .arg("disable") + .arg("tunein") + .status()?; + + std::fs::remove_file(service_path).expect("Failed to remove service file"); + + Command::new("systemctl") + .arg("--user") + .arg("daemon-reload") + .status()?; + + println!("✅ Tunein service uninstalled successfully!"); + } else { + println!("Service file does not exist. Nothing to uninstall."); + } + + Ok(()) +} + +pub fn status() -> Result<(), Error> { + if cfg!(not(target_os = "linux")) { + println!("This command is only supported on Linux"); + std::process::exit(1); + } + + let home = std::env::var("HOME")?; + let service_path: &str = &format!("{}/.config/systemd/user/tunein.service", home); + + if Path::new(service_path).exists() { + Command::new("systemctl") + .arg("--user") + .arg("status") + .arg("tunein") + .status()?; + } else { + println!("Service file does not exist. Tunein service is not installed."); + } + + Ok(()) +} diff --git a/src/systemd/tunein.service b/src/systemd/tunein.service new file mode 100644 index 0000000..f4c252b --- /dev/null +++ b/src/systemd/tunein.service @@ -0,0 +1,10 @@ +[Unit] +Description=TuneIn Server Daemon +After=network.target + +[Service] +ExecStart=/usr/bin/tunein server +Restart=always + +[Install] +WantedBy=default.target