Experimental command socket support

Introduces "start-or-kill" and "toggle-visible" commands. How the
command socket is used will likely change soon.
This commit is contained in:
Kenny Levinsen
2019-08-27 15:09:19 +02:00
parent 1cadf43d49
commit 6deffa91bb
6 changed files with 169 additions and 59 deletions
+103 -15
View File
@@ -1,7 +1,8 @@
use std::io::{Read, Write};
use std::io::{Read, Write, BufRead, BufReader};
use std::os::unix::io::AsRawFd;
use std::sync::mpsc::channel;
use std::env;
use std::os::unix::net::{UnixStream, UnixListener};
use nix::poll::{poll, PollFd, PollFlags};
use os_pipe::pipe;
@@ -11,31 +12,114 @@ mod color;
mod draw;
mod modules;
mod app;
mod cmd;
use app::{App, Cmd};
use app::{App, OutputMode};
use cmd::Cmd;
enum Mode {
Start,
StartOrKill,
ToggleVisible,
}
fn main() {
let (mut rx_pipe, mut tx_pipe) = pipe().unwrap();
let (tx_draw, rx_draw) = channel();
let all_outputs = match env::var("WLDASH_ALL_OUTPUTS") {
Ok(_) => true,
Err(_) => false,
let socket_path = match env::var("XDG_RUNTIME_DIR") {
Ok(dir) => dir + "/wldash",
Err(_) => "/tmp/wldash".to_string(),
};
let mut app = App::new(tx_draw, all_outputs);
let args: Vec<String> = env::args().collect();
let mode = match args.len() {
1 => Mode::Start,
2 => match args[1].as_str() {
"start" => Mode::Start,
"start-or-kill" => Mode::StartOrKill,
"toggle-visible" => Mode::ToggleVisible,
s => {
eprintln!("unsupported sub-command {}", s);
std::process::exit(1);
}
},
v => {
eprintln!("expected 0 or 1 arguments, got {}", v);
std::process::exit(1);
}
};
match mode {
Mode::ToggleVisible => {
if let Ok(mut socket) = UnixStream::connect(socket_path.clone()) {
socket.write_all(b"toggle_visible\n").unwrap();
return;
};
eprintln!("wldash is not running");
std::process::exit(1);
}
Mode::StartOrKill => {
if let Ok(mut socket) = UnixStream::connect(socket_path.clone()) {
socket.write_all(b"kill\n").unwrap();
return;
};
}
Mode::Start => {
if let Ok(_) = UnixStream::connect(socket_path.clone()) {
eprintln!("wldash is already running");
std::process::exit(1);
};
}
}
let _ = std::fs::remove_file(socket_path.clone());
let listener = UnixListener::bind(socket_path.clone()).unwrap();
let (mut rx_pipe, mut tx_pipe) = pipe().unwrap();
let ipc_pipe = tx_pipe.try_clone().unwrap();
let (tx_draw, rx_draw) = channel();
let output_mode = match env::var("WLDASH_ALL_OUTPUTS") {
Ok(_) => OutputMode::All,
Err(_) => OutputMode::Active,
};
let mut app = App::new(tx_draw, output_mode);
app.wipe();
let worker_queue = app.cmd_queue();
std::thread::spawn(move || loop {
if rx_draw.recv().unwrap() {
worker_queue.lock().unwrap().push_back(Cmd::Draw);
} else {
worker_queue.lock().unwrap().push_back(Cmd::ForceDraw);
}
let cmd = rx_draw.recv().unwrap();
worker_queue.lock().unwrap().push_back(cmd);
tx_pipe.write_all(&[0x1]).unwrap();
});
let ipc_queue = app.cmd_queue();
std::thread::spawn(move || loop {
for stream in listener.incoming() {
match stream {
Ok(stream) => {
let client_queue = ipc_queue.clone();
let mut client_pipe = ipc_pipe.try_clone().unwrap();
std::thread::spawn(move || {
let r = BufReader::new(stream);
for line in r.lines() {
match line {
Ok(v) => match v.as_str() {
"kill" => client_queue.lock().unwrap().push_back(Cmd::Exit),
"toggle_visible" => client_queue.lock().unwrap().push_back(Cmd::ToggleVisible),
v => eprintln!("unknown command: {}", v),
},
Err(_) => return,
}
client_pipe.write_all(&[0x1]).unwrap();
}
});
}
Err(_) => break,
}
}
});
let mut fds = [
PollFd::new(app.event_queue().get_connection_fd(), PollFlags::POLLIN),
PollFd::new(rx_pipe.as_raw_fd(), PollFlags::POLLIN),
@@ -70,8 +154,12 @@ fn main() {
});
q.lock().unwrap().push_back(Cmd::Draw);
}
Cmd::ToggleVisible => {
app.toggle_visible();
}
Cmd::Exit => {
std::process::exit(0);
let _ = std::fs::remove_file(socket_path);
return;
}
},
None => {