use std::io::{BufRead, BufReader};
use std::os::unix::net::UnixListener;
use std::path::PathBuf;
use std::sync::Arc;
use waybar_dynamic_core::protocol::IpcMessage;
use crate::state::SharedState;
pub fn spawn_listener(
socket_path: PathBuf,
state: SharedState,
on_update: Arc<dyn Fn() + Send + Sync + 'static>,
) {
let _ = std::fs::remove_file(&socket_path);
let listener = match UnixListener::bind(&socket_path) {
Ok(l) => l,
Err(e) => {
eprintln!(
"waybar-dynamic: failed to bind IPC socket at {}: {}",
socket_path.display(),
e
);
return;
}
};
eprintln!(
"waybar-dynamic: listening on {}",
socket_path.display()
);
std::thread::spawn(move || {
for stream in listener.incoming() {
let stream = match stream {
Ok(s) => s,
Err(e) => {
eprintln!("waybar-dynamic: accept error: {}", e);
continue;
}
};
let state = state.clone();
let on_update = Arc::clone(&on_update);
std::thread::spawn(move || {
let reader = BufReader::new(stream);
for line in reader.lines() {
let line = match line {
Ok(l) => l,
Err(e) => {
eprintln!("waybar-dynamic: read error: {}", e);
return;
}
};
let line = line.trim().to_string();
if line.is_empty() {
continue;
}
let msg: IpcMessage = match serde_json::from_str(&line) {
Ok(m) => m,
Err(e) => {
eprintln!("waybar-dynamic: invalid message: {}", e);
continue;
}
};
let widget_count = match &msg {
IpcMessage::SetAll { widgets } => widgets.len(),
IpcMessage::Patch { upsert, .. } => upsert.len(),
IpcMessage::Clear => 0,
};
match msg {
IpcMessage::SetAll { widgets } => state.set_all(widgets),
IpcMessage::Patch { upsert, remove } => state.patch(upsert, remove),
IpcMessage::Clear => state.clear(),
}
eprintln!(
"waybar-dynamic: received message, state now has {} widget(s)",
widget_count
);
let cb = Arc::clone(&on_update);
cb();
}
});
}
});
}