Basics actually work still
This commit is contained in:
parent
19681a0db8
commit
542dd62d7b
5 changed files with 87 additions and 2419 deletions
2311
Cargo.lock
generated
2311
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -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"
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
176
src/server.rs
176
src/server.rs
|
@ -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),
|
|
||||||
_ => {}
|
|
||||||
})?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue