Basics actually work still

This commit is contained in:
elkowar 2021-01-02 23:22:14 +01:00 committed by ElKowar
parent 19681a0db8
commit 542dd62d7b
5 changed files with 87 additions and 2419 deletions

2311
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -46,9 +46,12 @@ simple-signal = "1.1"
dashmap = "3.11" dashmap = "3.11"
unescape = "0.1" unescape = "0.1"
tokio = { version = "1.0", features = ["full"] } tokio = { version = "0.3", features = ["full"] }
tokio-stream = "0.1"
async-stream = "0.3" async-stream = "0.3"
futures-core = "0.3" futures-core = "0.3"
futures-util = "0.3"
inotify = "0.9"
[dev-dependencies] [dev-dependencies]
pretty_assertions = "0.6.1" pretty_assertions = "0.6.1"

View file

@ -12,6 +12,7 @@ use gdk::WindowExt;
use gtk::{ContainerExt, CssProviderExt, GtkWindowExt, StyleContextExt, WidgetExt}; use gtk::{ContainerExt, CssProviderExt, GtkWindowExt, StyleContextExt, WidgetExt};
use itertools::Itertools; use itertools::Itertools;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use tokio::sync::mpsc::UnboundedSender;
#[derive(Debug)] #[derive(Debug)]
pub enum EwwCommand { pub enum EwwCommand {
@ -53,7 +54,7 @@ pub struct App {
pub eww_config: config::EwwConfig, pub eww_config: config::EwwConfig,
pub windows: HashMap<WindowName, EwwWindow>, pub windows: HashMap<WindowName, EwwWindow>,
pub css_provider: gtk::CssProvider, pub css_provider: gtk::CssProvider,
pub app_evt_send: glib::Sender<EwwCommand>, pub app_evt_send: UnboundedSender<EwwCommand>,
#[debug_stub = "ScriptVarHandler(...)"] #[debug_stub = "ScriptVarHandler(...)"]
pub script_var_handler: ScriptVarHandler, pub script_var_handler: ScriptVarHandler,
} }

View file

@ -15,6 +15,7 @@ use dashmap::DashMap;
use std::io::BufRead; use std::io::BufRead;
use self::script_var_process::ScriptVarProcess; use self::script_var_process::ScriptVarProcess;
use tokio::sync::mpsc::UnboundedSender;
/// Handler that manages running and updating [ScriptVar]s /// Handler that manages running and updating [ScriptVar]s
pub struct ScriptVarHandler { pub struct ScriptVarHandler {
@ -23,7 +24,7 @@ pub struct ScriptVarHandler {
} }
impl ScriptVarHandler { impl ScriptVarHandler {
pub fn new(evt_send: glib::Sender<EwwCommand>) -> Result<Self> { pub fn new(evt_send: UnboundedSender<EwwCommand>) -> Result<Self> {
Ok(ScriptVarHandler { Ok(ScriptVarHandler {
tail_handler: TailVarHandler::new(evt_send.clone())?, tail_handler: TailVarHandler::new(evt_send.clone())?,
poll_handler: PollVarHandler::new(evt_send)?, poll_handler: PollVarHandler::new(evt_send)?,
@ -60,13 +61,13 @@ impl Drop for ScriptVarHandler {
} }
struct PollVarHandler { struct PollVarHandler {
evt_send: glib::Sender<EwwCommand>, evt_send: UnboundedSender<EwwCommand>,
poll_handles: HashMap<VarName, scheduled_executor::executor::TaskHandle>, poll_handles: HashMap<VarName, scheduled_executor::executor::TaskHandle>,
poll_executor: scheduled_executor::CoreExecutor, poll_executor: scheduled_executor::CoreExecutor,
} }
impl PollVarHandler { impl PollVarHandler {
fn new(evt_send: glib::Sender<EwwCommand>) -> Result<Self> { fn new(evt_send: UnboundedSender<EwwCommand>) -> Result<Self> {
Ok(PollVarHandler { Ok(PollVarHandler {
evt_send, evt_send,
poll_handles: HashMap::new(), poll_handles: HashMap::new(),
@ -103,14 +104,14 @@ impl PollVarHandler {
} }
struct TailVarHandler { struct TailVarHandler {
evt_send: glib::Sender<EwwCommand>, evt_send: UnboundedSender<EwwCommand>,
tail_handler_thread: Option<stoppable_thread::StoppableHandle<()>>, tail_handler_thread: Option<stoppable_thread::StoppableHandle<()>>,
tail_process_handles: Arc<DashMap<VarName, script_var_process::ScriptVarProcess>>, tail_process_handles: Arc<DashMap<VarName, script_var_process::ScriptVarProcess>>,
tail_sources: Arc<RwLock<popol::Sources<VarName>>>, tail_sources: Arc<RwLock<popol::Sources<VarName>>>,
} }
impl TailVarHandler { impl TailVarHandler {
fn new(evt_send: glib::Sender<EwwCommand>) -> Result<Self> { fn new(evt_send: UnboundedSender<EwwCommand>) -> Result<Self> {
let mut handler = TailVarHandler { let mut handler = TailVarHandler {
evt_send, evt_send,
tail_handler_thread: None, tail_handler_thread: None,

View file

@ -1,11 +1,7 @@
use crate::{app, config, eww_state::*, opts, script_var_handler, try_logging_errors, util}; use crate::{app, config, eww_state::*, opts, script_var_handler, try_logging_errors, util};
use anyhow::*; use anyhow::*;
use std::{ use futures_util::StreamExt;
collections::HashMap, use std::{collections::HashMap, os::unix::io::AsRawFd, path::Path};
io::Write,
os::unix::{io::AsRawFd, net},
path::{Path, PathBuf},
};
use tokio::{ use tokio::{
io::{AsyncReadExt, AsyncWriteExt}, io::{AsyncReadExt, AsyncWriteExt},
sync::mpsc::*, sync::mpsc::*,
@ -35,8 +31,7 @@ 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 (evt_send, evt_recv) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); let (ui_send, mut ui_recv) = tokio::sync::mpsc::unbounded_channel();
let (ui_send, ui_recv) = tokio::sync::mpsc::unbounded_channel();
let glib_context = glib::MainContext::default(); let glib_context = glib::MainContext::default();
log::info!("Initializing script var handler"); log::info!("Initializing script var handler");
@ -70,15 +65,21 @@ pub fn initialize_server(should_detach: bool, action: opts::ActionWithServer) ->
println!("{}", response); println!("{}", response);
} }
} }
// run_server_thread(ui_send.clone())?;
// let _hotwatch = run_filewatch_thread(&config_file_path, &scss_file_path, evt_send.clone())?;
std::thread::spawn(move || { std::thread::spawn(move || {
let rt = tokio::runtime::Runtime::new().expect("REEEEEEEEE"); let rt = tokio::runtime::Builder::new_multi_thread()
.build()
.expect("Failed to initialize tokio runtime");
rt.block_on(async { rt.block_on(async {
// let _ = tokio::try_join!(async_part(evt_send)); let filewatch_join_handle = {
let _ = async_part(ui_send.clone()).await; let ui_send = ui_send.clone();
tokio::spawn(async move { run_filewatch_thingy(config_file_path, scss_file_path, ui_send).await })
};
let ipc_server_join_handle = tokio::spawn(async move { async_server(ui_send.clone()).await });
let result = tokio::try_join!(filewatch_join_handle, ipc_server_join_handle);
if let Err(e) = result {
eprintln!("Eww exiting with error: {:?}", e);
}
}); });
}); });
@ -88,94 +89,81 @@ pub fn initialize_server(should_detach: bool, action: opts::ActionWithServer) ->
} }
}); });
// evt_recv.attach(None, move |msg| {
// app.handle_command(msg);
// glib::Continue(true)
//});
gtk::main(); gtk::main();
Ok(()) Ok(())
} }
async fn async_part(evt_send: UnboundedSender<app::EwwCommand>) -> Result<()> {
Ok(())
}
// async fn async_server_accept() -> Result<impl futures_core::stream::Stream<Item = tokio::net::UnixStream>> {
// let listener = tokio::net::UnixListener::bind(&*crate::IPC_SOCKET_PATH)?;
// let stream = async_stream::stream! {
// loop {
// match listener.accept().await {
// Ok((mut stream, _addr)) => yield stream,
// Err(e) => {
// eprintln!("Failed to connect to client: {:?}", e);
//};
// Ok(stream)
//}
async fn async_server(evt_send: UnboundedSender<app::EwwCommand>) -> Result<()> { async fn async_server(evt_send: UnboundedSender<app::EwwCommand>) -> Result<()> {
let listener = tokio::net::UnixListener::bind(&*crate::IPC_SOCKET_PATH)?; let listener = tokio::net::UnixListener::bind(&*crate::IPC_SOCKET_PATH)?;
loop { loop {
match listener.accept().await { tokio::select! {
Ok((mut stream, _addr)) => { connection = listener.accept() => match connection {
try_logging_errors!("handling message from IPC client" => { Ok((stream, _addr)) => handle_connection(stream, evt_send.clone()).await?,
let (mut stream_read, mut stream_write) = stream.split(); Err(e) => eprintln!("Failed to connect to client: {:?}", e),
let action: opts::ActionWithServer = {
let mut raw_message = Vec::<u8>::new();
stream_read.read_to_end(&mut raw_message);
bincode::deserialize(&raw_message).context("Failed to parse client message")?
};
log::info!("received command from IPC: {:?}", &action);
// TODO clean up the maybe_response_recv
let (command, maybe_response_recv) = action.into_eww_command();
evt_send.send(command)?;
if let Some(response_recv) = maybe_response_recv {
if let Ok(response) = response_recv.recv_timeout(std::time::Duration::from_millis(100)) {
let result = &stream_write.write_all(response.as_bytes()).await;
crate::print_result_err!("Sending text response to ipc client", &result);
}
}
});
}
Err(e) => {
eprintln!("Failed to connect to client: {:?}", e);
} }
} }
} }
} }
fn run_filewatch_thread<P: AsRef<Path>>( async fn handle_connection(mut stream: tokio::net::UnixStream, evt_send: UnboundedSender<app::EwwCommand>) -> Result<()> {
let (mut stream_read, mut stream_write) = stream.split();
let action: opts::ActionWithServer = {
let mut raw_message = Vec::<u8>::new();
stream_read.read_to_end(&mut raw_message).await?;
bincode::deserialize(&raw_message).context("Failed to parse client message")?
};
log::info!("received command from IPC: {:?}", &action);
// TODO clean up the maybe_response_recv
let (command, maybe_response_recv) = action.into_eww_command();
evt_send.send(command)?;
if let Some(response_recv) = maybe_response_recv {
if let Ok(response) = response_recv.recv_timeout(std::time::Duration::from_millis(100)) {
let result = &stream_write.write_all(response.as_bytes()).await;
crate::print_result_err!("Sending text response to ipc client", &result);
}
}
Ok(())
}
async fn run_filewatch_thingy<P: AsRef<Path>>(
config_file_path: P, config_file_path: P,
scss_file_path: P, scss_file_path: P,
evt_send: glib::Sender<app::EwwCommand>, evt_send: UnboundedSender<app::EwwCommand>,
) -> Result<hotwatch::Hotwatch> { ) -> Result<()> {
log::info!("Initializing config file watcher"); let mut inotify = inotify::Inotify::init().context("Failed to initialize inotify")?;
let mut hotwatch = hotwatch::Hotwatch::new_with_custom_delay(std::time::Duration::from_millis(500))?; let config_file_descriptor = inotify
.add_watch(config_file_path.as_ref(), inotify::WatchMask::MODIFY)
.context("Failed to add inotify watch for config file")?;
let scss_file_descriptor = inotify
.add_watch(scss_file_path.as_ref(), inotify::WatchMask::MODIFY)
.context("Failed to add inotify watch for scss file")?;
let config_file_change_send = evt_send.clone(); let mut buffer = [0; 1024];
hotwatch.watch_file_changes(config_file_path, move |path| { let mut event_stream = inotify.event_stream(&mut buffer)?;
try_logging_errors!("handling change of config file" => { while let Some(Ok(event)) = event_stream.next().await {
log::info!("Reloading eww configuration"); if event.wd == config_file_descriptor {
let new_eww_config = config::EwwConfig::read_from_file(path)?; try_logging_errors!("handling change of config file" => {
config_file_change_send.send(app::EwwCommand::ReloadConfig(new_eww_config))?; log::info!("Reloading eww configuration");
}); let new_eww_config = config::EwwConfig::read_from_file(config_file_path.as_ref())?;
})?; evt_send.send(app::EwwCommand::ReloadConfig(new_eww_config))?;
});
let result = hotwatch.watch_file_changes(scss_file_path, move |path| { } else if event.wd == scss_file_descriptor {
try_logging_errors!("handling change of scss file" => { try_logging_errors!("handling change of scss file" => {
log::info!("reloading eww css file"); log::info!("reloading eww css file");
let eww_css = util::parse_scss_from_file(path)?; let eww_css = util::parse_scss_from_file(scss_file_path.as_ref())?;
evt_send.send(app::EwwCommand::ReloadCss(eww_css))?; evt_send.send(app::EwwCommand::ReloadCss(eww_css))?;
}) });
}); } else {
crate::print_result_err!("while loading CSS file for hot-reloading", &result); eprintln!("Got inotify event for unknown thing: {:?}", event);
Ok(hotwatch) }
}
Ok(())
} }
/// detach the process from the terminal, also redirecting stdout and stderr to /// detach the process from the terminal, also redirecting stdout and stderr to
@ -208,17 +196,3 @@ fn do_detach() -> Result<()> {
Ok(()) Ok(())
} }
#[extend::ext(pub)]
impl hotwatch::Hotwatch {
fn watch_file_changes<P, F>(&mut self, file_path: P, callback: F) -> Result<()>
where
P: AsRef<Path>,
F: 'static + Fn(PathBuf) + Send,
{
Ok(self.watch(file_path, move |evt| match evt {
hotwatch::Event::Write(path) | hotwatch::Event::NoticeWrite(path) => callback(path),
_ => {}
})?)
}
}