make multiple daemons possible and make commands time out
This commit is contained in:
parent
9a8bbf4114
commit
5b3344fc5b
9 changed files with 91 additions and 30 deletions
17
Cargo.lock
generated
17
Cargo.lock
generated
|
@ -100,6 +100,12 @@ version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "beef"
|
name = "beef"
|
||||||
version = "0.4.4"
|
version = "0.4.4"
|
||||||
|
@ -279,6 +285,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-stream",
|
"async-stream",
|
||||||
|
"base64",
|
||||||
"bincode",
|
"bincode",
|
||||||
"debug_stub_derive",
|
"debug_stub_derive",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
|
@ -314,6 +321,7 @@ dependencies = [
|
||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
"unescape",
|
"unescape",
|
||||||
|
"wait-timeout",
|
||||||
"x11rb",
|
"x11rb",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1723,6 +1731,15 @@ version = "0.9.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
|
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wait-timeout"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.9.0+wasi-snapshot-preview1"
|
version = "0.9.0+wasi-snapshot-preview1"
|
||||||
|
|
|
@ -58,6 +58,8 @@ tokio-util = "0.6"
|
||||||
|
|
||||||
nom = "6.1"
|
nom = "6.1"
|
||||||
dyn-clone = "1.0"
|
dyn-clone = "1.0"
|
||||||
|
base64 = "0.13"
|
||||||
|
wait-timeout = "0.2"
|
||||||
|
|
||||||
[target.'cfg(target_os="linux")'.dependencies]
|
[target.'cfg(target_os="linux")'.dependencies]
|
||||||
inotify = "0.9"
|
inotify = "0.9"
|
||||||
|
|
|
@ -64,6 +64,7 @@ impl ScriptVar {
|
||||||
|
|
||||||
/// Run a command and get the output
|
/// Run a command and get the output
|
||||||
fn run_command(cmd: &str) -> Result<PrimitiveValue> {
|
fn run_command(cmd: &str) -> Result<PrimitiveValue> {
|
||||||
|
log::debug!("Running command: {}", cmd);
|
||||||
let output = String::from_utf8(Command::new("/bin/sh").arg("-c").arg(cmd).output()?.stdout)?;
|
let output = String::from_utf8(Command::new("/bin/sh").arg("-c").arg(cmd).output()?.stdout)?;
|
||||||
let output = output.trim_matches('\n');
|
let output = output.trim_matches('\n');
|
||||||
Ok(PrimitiveValue::from(output))
|
Ok(PrimitiveValue::from(output))
|
||||||
|
|
|
@ -6,8 +6,9 @@ use tokio::{
|
||||||
sync::mpsc::*,
|
sync::mpsc::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub async fn run_server(evt_send: UnboundedSender<app::DaemonCommand>) -> Result<()> {
|
pub async fn run_server<P: AsRef<std::path::Path>>(evt_send: UnboundedSender<app::DaemonCommand>, socket_path: P) -> Result<()> {
|
||||||
let listener = tokio::net::UnixListener::bind(&*crate::IPC_SOCKET_PATH)?;
|
let socket_path = socket_path.as_ref();
|
||||||
|
let listener = { tokio::net::UnixListener::bind(socket_path)? };
|
||||||
log::info!("IPC server initialized");
|
log::info!("IPC server initialized");
|
||||||
crate::loop_select_exiting! {
|
crate::loop_select_exiting! {
|
||||||
connection = listener.accept() => match connection {
|
connection = listener.accept() => match connection {
|
||||||
|
|
34
src/main.rs
34
src/main.rs
|
@ -31,7 +31,7 @@ pub mod value;
|
||||||
pub mod widgets;
|
pub mod widgets;
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
pub static ref IPC_SOCKET_PATH: std::path::PathBuf = std::env::var("XDG_RUNTIME_DIR")
|
static ref IPC_SOCKET_PATH: std::path::PathBuf = std::env::var("XDG_RUNTIME_DIR")
|
||||||
.map(std::path::PathBuf::from)
|
.map(std::path::PathBuf::from)
|
||||||
.unwrap_or_else(|_| std::path::PathBuf::from("/tmp"))
|
.unwrap_or_else(|_| std::path::PathBuf::from("/tmp"))
|
||||||
.join("eww-server");
|
.join("eww-server");
|
||||||
|
@ -47,6 +47,21 @@ lazy_static::lazy_static! {
|
||||||
.join("eww.log");
|
.join("eww.log");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Paths {}
|
||||||
|
|
||||||
|
pub fn calculate_socket_path<P: AsRef<std::path::Path>>(config_file_path: P) -> std::path::PathBuf {
|
||||||
|
let daemon_id = base64::encode(format!("{}", config_file_path.as_ref().display()));
|
||||||
|
let socket_filename = format!(
|
||||||
|
"{}_{}",
|
||||||
|
&*crate::IPC_SOCKET_PATH
|
||||||
|
.file_name()
|
||||||
|
.and_then(|x| x.to_str())
|
||||||
|
.expect("Invalid socket path"),
|
||||||
|
daemon_id,
|
||||||
|
);
|
||||||
|
crate::IPC_SOCKET_PATH.with_file_name(socket_filename).to_path_buf()
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let opts: opts::Opt = opts::Opt::from_env();
|
let opts: opts::Opt = opts::Opt::from_env();
|
||||||
|
|
||||||
|
@ -61,15 +76,16 @@ fn main() {
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
let result: Result<_> = try {
|
let result: Result<_> = try {
|
||||||
|
let socket_path = calculate_socket_path(opts.config_path.clone().unwrap_or(CONFIG_DIR.join("eww.xml")));
|
||||||
match opts.action {
|
match opts.action {
|
||||||
opts::Action::ClientOnly(action) => {
|
opts::Action::ClientOnly(action) => {
|
||||||
client::handle_client_only_action(action)?;
|
client::handle_client_only_action(action)?;
|
||||||
}
|
}
|
||||||
opts::Action::WithServer(action) => {
|
opts::Action::WithServer(action) => {
|
||||||
log::info!("Trying to find server process");
|
log::info!("Trying to find server process at socket {}", socket_path.display());
|
||||||
match net::UnixStream::connect(&*IPC_SOCKET_PATH) {
|
match net::UnixStream::connect(&socket_path) {
|
||||||
Ok(stream) => {
|
Ok(stream) => {
|
||||||
log::info!("Connected to Eww server.");
|
log::info!("Connected to Eww server ({}).", &socket_path.display());
|
||||||
let response =
|
let response =
|
||||||
client::do_server_call(stream, action).context("Error while forwarding command to server")?;
|
client::do_server_call(stream, action).context("Error while forwarding command to server")?;
|
||||||
if let Some(response) = response {
|
if let Some(response) = response {
|
||||||
|
@ -87,17 +103,17 @@ fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
opts::Action::Daemon { config } => {
|
opts::Action::Daemon => {
|
||||||
// make sure that there isn't already a Eww daemon running.
|
// make sure that there isn't already a Eww daemon running.
|
||||||
if check_server_running(&*IPC_SOCKET_PATH) {
|
if check_server_running(&socket_path) {
|
||||||
eprintln!("Eww server already running.");
|
eprintln!("Eww server already running.");
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
} else {
|
} else {
|
||||||
log::info!("Initializing Eww server.");
|
log::info!("Initializing Eww server. ({})", socket_path.display());
|
||||||
let _ = std::fs::remove_file(&*crate::IPC_SOCKET_PATH);
|
let _ = std::fs::remove_file(socket_path);
|
||||||
|
|
||||||
println!("Run `eww logs` to see any errors, warnings or information while editing your configuration.");
|
println!("Run `eww logs` to see any errors, warnings or information while editing your configuration.");
|
||||||
server::initialize_server(config)?;
|
server::initialize_server(opts.config_path)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
23
src/opts.rs
23
src/opts.rs
|
@ -12,6 +12,7 @@ use crate::{
|
||||||
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||||
pub struct Opt {
|
pub struct Opt {
|
||||||
pub log_debug: bool,
|
pub log_debug: bool,
|
||||||
|
pub config_path: Option<std::path::PathBuf>,
|
||||||
pub action: Action,
|
pub action: Action,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +22,10 @@ struct RawOpt {
|
||||||
#[structopt(long = "debug", global = true)]
|
#[structopt(long = "debug", global = true)]
|
||||||
log_debug: bool,
|
log_debug: bool,
|
||||||
|
|
||||||
|
/// override config-file path (path to eww.xml)
|
||||||
|
#[structopt(short, long, global = true)]
|
||||||
|
config: Option<std::path::PathBuf>,
|
||||||
|
|
||||||
#[structopt(subcommand)]
|
#[structopt(subcommand)]
|
||||||
action: Action,
|
action: Action,
|
||||||
}
|
}
|
||||||
|
@ -29,11 +34,7 @@ struct RawOpt {
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
/// Start the Eww daemon.
|
/// Start the Eww daemon.
|
||||||
#[structopt(name = "daemon", alias = "d")]
|
#[structopt(name = "daemon", alias = "d")]
|
||||||
Daemon {
|
Daemon,
|
||||||
/// Custom Config Path
|
|
||||||
#[structopt(short, long)]
|
|
||||||
config: Option<std::path::PathBuf>,
|
|
||||||
},
|
|
||||||
|
|
||||||
#[structopt(flatten)]
|
#[structopt(flatten)]
|
||||||
ClientOnly(ActionClientOnly),
|
ClientOnly(ActionClientOnly),
|
||||||
|
@ -128,8 +129,16 @@ impl Opt {
|
||||||
|
|
||||||
impl From<RawOpt> for Opt {
|
impl From<RawOpt> for Opt {
|
||||||
fn from(other: RawOpt) -> Self {
|
fn from(other: RawOpt) -> Self {
|
||||||
let RawOpt { action, log_debug } = other;
|
let RawOpt {
|
||||||
Opt { action, log_debug }
|
action,
|
||||||
|
log_debug,
|
||||||
|
config,
|
||||||
|
} = other;
|
||||||
|
Opt {
|
||||||
|
action,
|
||||||
|
log_debug,
|
||||||
|
config_path: config,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -89,12 +89,14 @@ fn init_async_part(config_file_path: PathBuf, scss_file_path: PathBuf, ui_send:
|
||||||
rt.block_on(async {
|
rt.block_on(async {
|
||||||
let filewatch_join_handle = {
|
let filewatch_join_handle = {
|
||||||
let ui_send = ui_send.clone();
|
let ui_send = ui_send.clone();
|
||||||
|
let config_file_path = config_file_path.clone();
|
||||||
tokio::spawn(async move { run_filewatch(config_file_path, scss_file_path, ui_send).await })
|
tokio::spawn(async move { run_filewatch(config_file_path, scss_file_path, ui_send).await })
|
||||||
};
|
};
|
||||||
|
|
||||||
let ipc_server_join_handle = {
|
let ipc_server_join_handle = {
|
||||||
let ui_send = ui_send.clone();
|
let ui_send = ui_send.clone();
|
||||||
tokio::spawn(async move { ipc_server::run_server(ui_send).await })
|
let socket_path = crate::calculate_socket_path(config_file_path);
|
||||||
|
tokio::spawn(async move { ipc_server::run_server(ui_send, socket_path).await })
|
||||||
};
|
};
|
||||||
|
|
||||||
let forward_exit_to_app_handle = {
|
let forward_exit_to_app_handle = {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{config::window_definition::WindowName, eww_state::*, print_result_err, value::AttrName};
|
use crate::{config::window_definition::WindowName, eww_state::*, value::AttrName};
|
||||||
use anyhow::*;
|
use anyhow::*;
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
@ -13,14 +13,27 @@ const CMD_STRING_PLACEHODLER: &str = "{}";
|
||||||
|
|
||||||
/// Run a command that was provided as an attribute. This command may use a
|
/// Run a command that was provided as an attribute. This command may use a
|
||||||
/// placeholder ('{}') which will be replaced by the value provided as [`arg`]
|
/// placeholder ('{}') which will be replaced by the value provided as [`arg`]
|
||||||
pub(self) fn run_command<T: std::fmt::Display>(cmd: &str, arg: T) {
|
pub(self) fn run_command<T: 'static + std::fmt::Display + Send + Sync>(cmd: &str, arg: T) {
|
||||||
|
use wait_timeout::ChildExt;
|
||||||
|
let cmd = cmd.to_string();
|
||||||
|
std::thread::spawn(move || {
|
||||||
let cmd = cmd.replace(CMD_STRING_PLACEHODLER, &format!("{}", arg));
|
let cmd = cmd.replace(CMD_STRING_PLACEHODLER, &format!("{}", arg));
|
||||||
let command_result = Command::new("/bin/sh")
|
log::debug!("Running command from widget: {}", cmd);
|
||||||
.arg("-c")
|
let child = Command::new("/bin/sh").arg("-c").arg(&cmd).spawn();
|
||||||
.arg(&cmd)
|
match child {
|
||||||
.spawn()
|
Ok(mut child) => match child.wait_timeout(std::time::Duration::from_millis(200)) {
|
||||||
.and_then(|mut child| child.wait());
|
// child timed out
|
||||||
print_result_err!(format!("executing command {}", &cmd), command_result);
|
Ok(None) => {
|
||||||
|
eprintln!("WARNING: command {} timed out", &cmd);
|
||||||
|
let _ = child.kill();
|
||||||
|
let _ = child.wait();
|
||||||
|
}
|
||||||
|
Err(err) => eprintln!("Failed to execute command {}: {}", cmd, err),
|
||||||
|
Ok(Some(_)) => {}
|
||||||
|
},
|
||||||
|
Err(err) => eprintln!("Failed to launch child process: {}", err),
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BuilderArgs<'a, 'b, 'c, 'd> {
|
struct BuilderArgs<'a, 'b, 'c, 'd> {
|
||||||
|
|
|
@ -258,8 +258,8 @@ fn build_gtk_color_chooser(bargs: &mut BuilderArgs) -> Result<gtk::ColorChooserW
|
||||||
// @prop onchange - runs the code when the color was selected
|
// @prop onchange - runs the code when the color was selected
|
||||||
prop(onchange: as_string) {
|
prop(onchange: as_string) {
|
||||||
let old_id = on_change_handler_id.replace(Some(
|
let old_id = on_change_handler_id.replace(Some(
|
||||||
gtk_widget.connect_color_activated(move |_a, gtk_widget| {
|
gtk_widget.connect_color_activated(move |_a, color| {
|
||||||
run_command(&onchange, gtk_widget);
|
run_command(&onchange, color.clone());
|
||||||
})
|
})
|
||||||
));
|
));
|
||||||
old_id.map(|id| gtk_widget.disconnect(id));
|
old_id.map(|id| gtk_widget.disconnect(id));
|
||||||
|
|
Loading…
Add table
Reference in a new issue