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"
unescape = "0.1"
tokio = { version = "1.0", features = ["full"] }
tokio = { version = "0.3", features = ["full"] }
tokio-stream = "0.1"
async-stream = "0.3"
futures-core = "0.3"
futures-util = "0.3"
inotify = "0.9"
[dev-dependencies]
pretty_assertions = "0.6.1"

View file

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

View file

@ -15,6 +15,7 @@ use dashmap::DashMap;
use std::io::BufRead;
use self::script_var_process::ScriptVarProcess;
use tokio::sync::mpsc::UnboundedSender;
/// Handler that manages running and updating [ScriptVar]s
pub struct ScriptVarHandler {
@ -23,7 +24,7 @@ pub struct ScriptVarHandler {
}
impl ScriptVarHandler {
pub fn new(evt_send: glib::Sender<EwwCommand>) -> Result<Self> {
pub fn new(evt_send: UnboundedSender<EwwCommand>) -> Result<Self> {
Ok(ScriptVarHandler {
tail_handler: TailVarHandler::new(evt_send.clone())?,
poll_handler: PollVarHandler::new(evt_send)?,
@ -60,13 +61,13 @@ impl Drop for ScriptVarHandler {
}
struct PollVarHandler {
evt_send: glib::Sender<EwwCommand>,
evt_send: UnboundedSender<EwwCommand>,
poll_handles: HashMap<VarName, scheduled_executor::executor::TaskHandle>,
poll_executor: scheduled_executor::CoreExecutor,
}
impl PollVarHandler {
fn new(evt_send: glib::Sender<EwwCommand>) -> Result<Self> {
fn new(evt_send: UnboundedSender<EwwCommand>) -> Result<Self> {
Ok(PollVarHandler {
evt_send,
poll_handles: HashMap::new(),
@ -103,14 +104,14 @@ impl PollVarHandler {
}
struct TailVarHandler {
evt_send: glib::Sender<EwwCommand>,
evt_send: UnboundedSender<EwwCommand>,
tail_handler_thread: Option<stoppable_thread::StoppableHandle<()>>,
tail_process_handles: Arc<DashMap<VarName, script_var_process::ScriptVarProcess>>,
tail_sources: Arc<RwLock<popol::Sources<VarName>>>,
}
impl TailVarHandler {
fn new(evt_send: glib::Sender<EwwCommand>) -> Result<Self> {
fn new(evt_send: UnboundedSender<EwwCommand>) -> Result<Self> {
let mut handler = TailVarHandler {
evt_send,
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 anyhow::*;
use std::{
collections::HashMap,
io::Write,
os::unix::{io::AsRawFd, net},
path::{Path, PathBuf},
};
use futures_util::StreamExt;
use std::{collections::HashMap, os::unix::io::AsRawFd, path::Path};
use tokio::{
io::{AsyncReadExt, AsyncWriteExt},
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)?;
gtk::init()?;
// let (evt_send, evt_recv) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
let (ui_send, ui_recv) = tokio::sync::mpsc::unbounded_channel();
let (ui_send, mut ui_recv) = tokio::sync::mpsc::unbounded_channel();
let glib_context = glib::MainContext::default();
log::info!("Initializing script var handler");
@ -70,15 +65,21 @@ pub fn initialize_server(should_detach: bool, action: opts::ActionWithServer) ->
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 || {
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 {
// let _ = tokio::try_join!(async_part(evt_send));
let _ = async_part(ui_send.clone()).await;
let filewatch_join_handle = {
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();
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<()> {
let listener = tokio::net::UnixListener::bind(&*crate::IPC_SOCKET_PATH)?;
loop {
match listener.accept().await {
Ok((mut stream, _addr)) => {
try_logging_errors!("handling message from IPC client" => {
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);
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);
tokio::select! {
connection = listener.accept() => match connection {
Ok((stream, _addr)) => handle_connection(stream, evt_send.clone()).await?,
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,
scss_file_path: P,
evt_send: glib::Sender<app::EwwCommand>,
) -> Result<hotwatch::Hotwatch> {
log::info!("Initializing config file watcher");
let mut hotwatch = hotwatch::Hotwatch::new_with_custom_delay(std::time::Duration::from_millis(500))?;
evt_send: UnboundedSender<app::EwwCommand>,
) -> Result<()> {
let mut inotify = inotify::Inotify::init().context("Failed to initialize inotify")?;
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();
hotwatch.watch_file_changes(config_file_path, move |path| {
try_logging_errors!("handling change of config file" => {
log::info!("Reloading eww configuration");
let new_eww_config = config::EwwConfig::read_from_file(path)?;
config_file_change_send.send(app::EwwCommand::ReloadConfig(new_eww_config))?;
});
})?;
let result = hotwatch.watch_file_changes(scss_file_path, move |path| {
try_logging_errors!("handling change of scss file" => {
log::info!("reloading eww css file");
let eww_css = util::parse_scss_from_file(path)?;
evt_send.send(app::EwwCommand::ReloadCss(eww_css))?;
})
});
crate::print_result_err!("while loading CSS file for hot-reloading", &result);
Ok(hotwatch)
let mut buffer = [0; 1024];
let mut event_stream = inotify.event_stream(&mut buffer)?;
while let Some(Ok(event)) = event_stream.next().await {
if event.wd == config_file_descriptor {
try_logging_errors!("handling change of config file" => {
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))?;
});
} else if event.wd == scss_file_descriptor {
try_logging_errors!("handling change of scss file" => {
log::info!("reloading eww css file");
let eww_css = util::parse_scss_from_file(scss_file_path.as_ref())?;
evt_send.send(app::EwwCommand::ReloadCss(eww_css))?;
});
} else {
eprintln!("Got inotify event for unknown thing: {:?}", event);
}
}
Ok(())
}
/// detach the process from the terminal, also redirecting stdout and stderr to
@ -208,17 +196,3 @@ fn do_detach() -> Result<()> {
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),
_ => {}
})?)
}
}