From 402513b11d4ac6ada445ece359e2412e8415d5d0 Mon Sep 17 00:00:00 2001 From: Lucas Schwiderski Date: Thu, 13 Apr 2023 20:06:50 +0200 Subject: [PATCH] feat: Implement config file --- src/client.rs | 4 ++-- src/config.rs | 51 +++++++++++++++++++++++++++++++++++++++++++++++ src/daemon/mod.rs | 11 ++++++++-- src/main.rs | 18 +++++++++-------- 4 files changed, 72 insertions(+), 12 deletions(-) create mode 100644 src/config.rs diff --git a/src/client.rs b/src/client.rs index 1be1a10..14440a7 100644 --- a/src/client.rs +++ b/src/client.rs @@ -7,7 +7,7 @@ use color_eyre::Result; use crate::Request; -pub fn handle(runtime_dir: PathBuf) -> Result<()> { +pub fn handle(runtime_dir: PathBuf, session: String) -> Result<()> { let mut buf = String::new(); stdin() .read_to_string(&mut buf) @@ -17,7 +17,7 @@ pub fn handle(runtime_dir: PathBuf) -> Result<()> { tracing::trace!("Received request: {:?}", req); - let path = runtime_dir.join(&req.session).with_extension("s"); + let path = runtime_dir.join(session).with_extension("s"); tracing::debug!(path = %path.display()); let mut socket = UnixStream::connect(&path) diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..bc42e94 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,51 @@ +use std::io::ErrorKind; +use std::path::PathBuf; +use std::{env, fs}; + +use color_eyre::eyre::Context; +use color_eyre::Result; +use serde::Deserialize; + +#[derive(Copy, Clone, Debug, Deserialize)] +pub struct Config { + /// The number of worker threads to spawn + pub workers: u8, +} + +impl Config { + pub fn load(path: Option) -> Result { + let buf = if let Some(path) = path { + tracing::debug!("Reading config file '{}'", path.display()); + fs::read(&path).wrap_err_with(|| format!("Failed to read file '{}'", path.display()))? + } else { + let path = default_config_path(); + tracing::debug!("Reading config file '{}'", path.display()); + match fs::read(&path) { + Ok(data) => data, + Err(err) if err.kind() == ErrorKind::NotFound => { + tracing::debug!("Default config file does not exist, using default values"); + return Ok(Config::default()); + } + Err(err) => { + return Err(err) + .wrap_err_with(|| format!("Failed to read file '{}'", path.display())) + } + } + }; + let buf = String::from_utf8_lossy(&buf); + toml::from_str(&buf).wrap_err("Failed to deserialize config") + } +} + +impl Default for Config { + fn default() -> Self { + Self { workers: 2 } + } +} + +fn default_config_path() -> PathBuf { + env::var("XDG_CONFIG_HOME") + .map(PathBuf::from) + .unwrap_or_else(|_| PathBuf::from(env::var("HOME").unwrap()).join(".config")) + .join("kak-highlight.toml") +} diff --git a/src/daemon/mod.rs b/src/daemon/mod.rs index 9ffd5e1..ead177d 100644 --- a/src/daemon/mod.rs +++ b/src/daemon/mod.rs @@ -11,6 +11,7 @@ use signal_hook::consts::{SIGINT, TERM_SIGNALS}; use signal_hook::flag; use signal_hook::iterator::Signals; +use crate::config::Config; use crate::daemon::worker::TaskScheduler; use self::listener::Listener; @@ -19,7 +20,7 @@ mod listener; mod worker; #[tracing::instrument] -pub fn handle(runtime_dir: PathBuf, session: String, workers: u8) -> Result<()> { +pub fn handle(runtime_dir: PathBuf, config_path: Option, session: String) -> Result<()> { // Ensure that sending a termination signal twice will immediately kill { let term_now = Arc::new(AtomicBool::new(false)); @@ -29,6 +30,9 @@ pub fn handle(runtime_dir: PathBuf, session: String, workers: u8) -> Result<()> } } + let config = Config::load(config_path).wrap_err("Failed to load config")?; + tracing::debug!(?config); + let rx_signals = { let mut signals = Signals::new([SIGINT])?; let (tx, rx) = bounded(1); @@ -42,10 +46,13 @@ pub fn handle(runtime_dir: PathBuf, session: String, workers: u8) -> Result<()> }) .wrap_err("Failed to start signal handler")?; + tracing::trace!("Started signal handler"); + rx }; - let mut scheduler = TaskScheduler::new(workers).wrap_err("Failed to create task scheduler")?; + let mut scheduler = + TaskScheduler::new(config.workers).wrap_err("Failed to create task scheduler")?; let listener = Listener::new(runtime_dir, session).wrap_err("Failed to create listener")?; loop { diff --git a/src/main.rs b/src/main.rs index cad939e..5d5cd06 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,6 +12,7 @@ use tracing_subscriber::fmt; use tracing_subscriber::prelude::*; mod client; +mod config; mod daemon; mod kakoune; @@ -24,6 +25,9 @@ struct Cli { /// File to write log events to #[arg(long, value_name = "FILENAME")] log: Option, + /// Config file. Defaults to `$XDG_CONFIG_HOME/kak-highlight.toml`. + #[arg(short, long, value_name = "FILENAME")] + config: Option, /// The command to run #[command(subcommand)] command: Command, @@ -32,21 +36,19 @@ struct Cli { #[derive(Subcommand)] enum Command { /// Send a request payload to a running daemon and wait for the response - Request, + Request { + /// The Kakoune session this daemon belongs to + session: String, + }, /// Start a daemon Daemon { /// The Kakoune session this daemon belongs to session: String, - /// The number of worker threads to spawn - #[arg(short = 'n', long, default_value = "2", action = clap::ArgAction::Count)] - workers: u8, }, } #[derive(Clone, Debug, Deserialize)] struct Request { - /// The Kakoune session this request came from - session: String, /// The command FIFO provided by Kakoune fifo: String, } @@ -91,7 +93,7 @@ fn main() -> Result<()> { .join("kak-highlight"); match cli.command { - Command::Daemon { session, workers } => daemon::handle(runtime_dir, session, workers), - Command::Request => client::handle(runtime_dir), + Command::Daemon { session } => daemon::handle(runtime_dir, cli.config, session), + Command::Request { session } => client::handle(runtime_dir, session), } }