Make daemon startup explicit

This commit is contained in:
elkowar 2021-01-03 18:50:52 +01:00
parent 84cce399d0
commit 018bfee24c
4 changed files with 47 additions and 66 deletions

View file

@ -20,7 +20,7 @@ pub fn handle_client_only_action(action: ActionClientOnly) -> Result<()> {
Ok(()) Ok(())
} }
pub fn forward_command_to_server(mut stream: UnixStream, action: opts::ActionWithServer) -> Result<()> { pub fn do_server_call(mut stream: UnixStream, action: opts::ActionWithServer) -> Result<Option<String>> {
log::info!("Forwarding options to server"); log::info!("Forwarding options to server");
stream stream
.set_nonblocking(false) .set_nonblocking(false)
@ -43,8 +43,6 @@ pub fn forward_command_to_server(mut stream: UnixStream, action: opts::ActionWit
stream stream
.read_to_string(&mut buf) .read_to_string(&mut buf)
.context("Error reading response from server")?; .context("Error reading response from server")?;
if !buf.is_empty() {
println!("{}", buf); Ok(if buf.is_empty() { None } else { Some(buf) })
}
Ok(())
} }

View file

@ -53,16 +53,31 @@ fn main() {
} }
opts::Action::WithServer(action) => { opts::Action::WithServer(action) => {
log::info!("Trying to find server process"); log::info!("Trying to find server process");
if let Some(stream) = try_connect(&*IPC_SOCKET_PATH) { match net::UnixStream::connect(&*IPC_SOCKET_PATH) {
log::info!("Connected to eww server."); Ok(stream) => {
client::forward_command_to_server(stream, action).context("Error while forwarding command to server")?; log::info!("Connected to Eww server.");
} else if action.needs_server_running() { let response =
println!("No eww server running"); client::do_server_call(stream, action).context("Error while forwarding command to server")?;
if let Some(response) = response {
println!("{}", response);
}
}
Err(_) => {
println!("Failed to connect to the eww daemon.");
println!("Make sure to start the eww daemon process by running `eww daemon` first.");
}
}
}
opts::Action::Daemon => {
// make sure that there isn't already a Eww daemon running.
if check_server_running(&*IPC_SOCKET_PATH) {
eprintln!("Eww server already running.");
std::process::exit(1); std::process::exit(1);
} else { } else {
log::info!("No server running, initializing server..."); log::info!("Initializing Eww server.");
let _ = std::fs::remove_file(&*crate::IPC_SOCKET_PATH); let _ = std::fs::remove_file(&*crate::IPC_SOCKET_PATH);
server::initialize_server(opts.should_detach, action)?; server::initialize_server()?;
} }
} }
} }
@ -70,16 +85,14 @@ fn main() {
if let Err(e) = result { if let Err(e) = result {
eprintln!("{:?}", e); eprintln!("{:?}", e);
std::process::exit(1);
} }
} }
fn try_connect(path: &std::path::PathBuf) -> Option<net::UnixStream> { /// Check if a eww server is currently running by trying to send a ping message to it.
if path.exists() { fn check_server_running(socket_path: &std::path::PathBuf) -> bool {
for _ in 0..5 { let response = net::UnixStream::connect(socket_path)
if let Ok(stream) = net::UnixStream::connect(&*IPC_SOCKET_PATH) { .ok()
return Some(stream); .and_then(|stream| client::do_server_call(stream, opts::ActionWithServer::Ping).ok());
} response.is_some()
}
}
return None;
} }

View file

@ -11,7 +11,6 @@ use crate::{
#[derive(Debug, Serialize, Deserialize, PartialEq)] #[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct Opt { pub struct Opt {
pub action: Action, pub action: Action,
pub should_detach: bool,
} }
/// Helper struct that will be normalized into instance of [Opt] /// Helper struct that will be normalized into instance of [Opt]
@ -23,6 +22,10 @@ struct RawOpt {
#[derive(StructOpt, Debug, Serialize, Deserialize, PartialEq)] #[derive(StructOpt, Debug, Serialize, Deserialize, PartialEq)]
pub enum Action { pub enum Action {
/// Start the Eww daemon.
#[structopt(name = "daemon")]
Daemon,
#[structopt(flatten)] #[structopt(flatten)]
ClientOnly(ActionClientOnly), ClientOnly(ActionClientOnly),
@ -39,10 +42,6 @@ pub enum ActionClientOnly {
#[derive(StructOpt, Debug, Serialize, Deserialize, PartialEq)] #[derive(StructOpt, Debug, Serialize, Deserialize, PartialEq)]
pub enum ActionWithServer { pub enum ActionWithServer {
/// Start the eww daemon.
#[structopt(name = "daemon")]
Daemon,
/// Ping the eww server, checking if it is reachable. /// Ping the eww server, checking if it is reachable.
#[structopt(name = "ping")] #[structopt(name = "ping")]
Ping, Ping,
@ -113,10 +112,7 @@ 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 } = other; let RawOpt { action } = other;
Opt { Opt { action }
should_detach: action == Action::WithServer(ActionWithServer::Daemon),
action,
}
} }
} }
@ -130,7 +126,11 @@ fn parse_var_update_arg(s: &str) -> Result<(VarName, PrimitiveValue)> {
impl ActionWithServer { impl ActionWithServer {
pub fn into_eww_command(self) -> (app::EwwCommand, Option<tokio::sync::mpsc::UnboundedReceiver<String>>) { pub fn into_eww_command(self) -> (app::EwwCommand, Option<tokio::sync::mpsc::UnboundedReceiver<String>>) {
let command = match self { let command = match self {
ActionWithServer::Daemon | ActionWithServer::Ping => app::EwwCommand::NoOp, ActionWithServer::Ping => {
let (send, recv) = tokio::sync::mpsc::unbounded_channel();
let _ = send.send("pong".to_owned());
return (app::EwwCommand::NoOp, Some(recv));
}
ActionWithServer::Update { mappings } => app::EwwCommand::UpdateVars(mappings.into_iter().collect()), ActionWithServer::Update { mappings } => app::EwwCommand::UpdateVars(mappings.into_iter().collect()),
ActionWithServer::OpenMany { windows } => app::EwwCommand::OpenMany(windows), ActionWithServer::OpenMany { windows } => app::EwwCommand::OpenMany(windows),
ActionWithServer::OpenWindow { ActionWithServer::OpenWindow {
@ -158,12 +158,4 @@ impl ActionWithServer {
}; };
(command, None) (command, None)
} }
/// returns true if this command requires a server to already be running
pub fn needs_server_running(&self) -> bool {
match self {
ActionWithServer::OpenWindow { .. } | ActionWithServer::Daemon => false,
_ => true,
}
}
} }

View file

@ -12,10 +12,8 @@ use tokio::{
sync::mpsc::*, sync::mpsc::*,
}; };
pub fn initialize_server(should_detach: bool, action: opts::ActionWithServer) -> Result<()> { pub fn initialize_server() -> Result<()> {
if should_detach { do_detach()?;
do_detach()?;
}
simple_signal::set_handler(&[simple_signal::Signal::Int, simple_signal::Signal::Term], move |_| { simple_signal::set_handler(&[simple_signal::Signal::Int, simple_signal::Signal::Term], move |_| {
println!("Shutting down eww daemon..."); println!("Shutting down eww daemon...");
@ -24,6 +22,7 @@ pub fn initialize_server(should_detach: bool, action: opts::ActionWithServer) ->
std::process::exit(1); std::process::exit(1);
} }
}); });
let (ui_send, mut ui_recv) = tokio::sync::mpsc::unbounded_channel();
let config_file_path = crate::CONFIG_DIR.join("eww.xml"); let config_file_path = crate::CONFIG_DIR.join("eww.xml");
let config_dir = config_file_path let config_dir = config_file_path
@ -36,7 +35,6 @@ pub fn initialize_server(should_detach: bool, action: opts::ActionWithServer) ->
let eww_config = config::EwwConfig::read_from_file(&config_file_path)?; let eww_config = config::EwwConfig::read_from_file(&config_file_path)?;
gtk::init()?; gtk::init()?;
let (ui_send, mut ui_recv) = tokio::sync::mpsc::unbounded_channel();
log::info!("Initializing script var handler"); log::info!("Initializing script var handler");
let script_var_handler = script_var_handler::init(ui_send.clone()); let script_var_handler = script_var_handler::init(ui_send.clone());
@ -58,13 +56,8 @@ pub fn initialize_server(should_detach: bool, action: opts::ActionWithServer) ->
app.load_css(&eww_css)?; app.load_css(&eww_css)?;
} }
// run the command that eww was started with
log::info!("running command: {:?}", &action);
let (command, maybe_response_recv) = action.into_eww_command();
app.handle_command(command);
// initialize all the handlers and tasks running asyncronously // initialize all the handlers and tasks running asyncronously
init_async_part(config_file_path, scss_file_path, maybe_response_recv, ui_send); init_async_part(config_file_path, scss_file_path, ui_send);
glib::MainContext::default().spawn_local(async move { glib::MainContext::default().spawn_local(async move {
while let Some(event) = ui_recv.recv().await { while let Some(event) = ui_recv.recv().await {
@ -78,28 +71,13 @@ pub fn initialize_server(should_detach: bool, action: opts::ActionWithServer) ->
Ok(()) Ok(())
} }
fn init_async_part( fn init_async_part(config_file_path: PathBuf, scss_file_path: PathBuf, ui_send: UnboundedSender<app::EwwCommand>) {
config_file_path: PathBuf,
scss_file_path: PathBuf,
maybe_response_recv: Option<UnboundedReceiver<String>>,
ui_send: UnboundedSender<app::EwwCommand>,
) {
std::thread::spawn(move || { std::thread::spawn(move || {
let rt = tokio::runtime::Builder::new_multi_thread() let rt = tokio::runtime::Builder::new_multi_thread()
.enable_all() .enable_all()
.build() .build()
.expect("Failed to initialize tokio runtime"); .expect("Failed to initialize tokio runtime");
rt.block_on(async { rt.block_on(async {
// TODO This really does not belong here at all :<
// print out the response of this initial command, if there is any
tokio::spawn(async {
if let Some(mut response_recv) = maybe_response_recv {
if let Ok(Some(response)) = tokio::time::timeout(Duration::from_millis(100), response_recv.recv()).await {
println!("{}", response);
}
}
});
let filewatch_join_handle = { let filewatch_join_handle = {
let ui_send = ui_send.clone(); let ui_send = ui_send.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 })