1
0
Fork 0
mirror of https://github.com/Zedfrigg/ironbar.git synced 2025-08-19 07:41:04 +02:00

fix: avoid creating loads of sway/mpd clients

This commit is contained in:
Jake Stanger 2022-08-25 21:53:42 +01:00
parent 649b0efb19
commit 6dcae66570
No known key found for this signature in database
GPG key ID: C51FC8F9CB0BEA61
9 changed files with 254 additions and 136 deletions

View file

@ -1,17 +1,22 @@
use color_eyre::{Report, Result};
use crossbeam_channel::Receiver;
use ksway::{Error, IpcCommand, IpcEvent};
use lazy_static::lazy_static;
use serde::Deserialize;
use std::sync::{Arc, Mutex};
use tokio::spawn;
use tracing::{debug, info, trace};
pub mod node;
#[derive(Deserialize, Debug)]
#[derive(Deserialize, Debug, Clone)]
pub struct WorkspaceEvent {
pub change: String,
pub old: Option<Workspace>,
pub current: Option<Workspace>,
}
#[derive(Deserialize, Debug)]
#[derive(Deserialize, Debug, Clone)]
pub struct Workspace {
pub name: String,
pub focused: bool,
@ -19,13 +24,13 @@ pub struct Workspace {
pub output: String,
}
#[derive(Debug, Deserialize)]
#[derive(Debug, Deserialize, Clone)]
pub struct WindowEvent {
pub change: String,
pub container: SwayNode,
}
#[derive(Debug, Deserialize)]
#[derive(Debug, Deserialize, Clone)]
pub struct SwayNode {
#[serde(rename = "type")]
pub node_type: String,
@ -40,7 +45,7 @@ pub struct SwayNode {
pub window_properties: Option<WindowProperties>,
}
#[derive(Debug, Deserialize)]
#[derive(Debug, Deserialize, Clone)]
pub struct WindowProperties {
pub class: Option<String>,
}
@ -52,25 +57,79 @@ pub struct SwayOutput {
pub struct SwayClient {
client: ksway::Client,
workspace_bc: Arc<Mutex<UnboundedBroadcast<WorkspaceEvent>>>,
window_bc: Arc<Mutex<UnboundedBroadcast<WindowEvent>>>,
}
impl SwayClient {
pub(crate) fn run(&mut self, cmd: String) -> Result<Vec<u8>> {
match self.client.run(cmd) {
Ok(res) => Ok(res),
Err(err) => Err(get_client_error(err)),
}
}
}
impl SwayClient {
pub fn connect() -> Result<Self> {
fn connect() -> Result<Self> {
let client = match ksway::Client::connect() {
Ok(client) => Ok(client),
Err(err) => Err(get_client_error(err)),
}?;
info!("Sway IPC client connected");
Ok(Self { client })
let workspace_bc = Arc::new(Mutex::new(UnboundedBroadcast::new()));
let window_bc = Arc::new(Mutex::new(UnboundedBroadcast::new()));
let workspace_bc2 = workspace_bc.clone();
let window_bc2 = window_bc.clone();
spawn(async move {
let mut sub_client = match ksway::Client::connect() {
Ok(client) => Ok(client),
Err(err) => Err(get_client_error(err)),
}
.expect("Failed to connect to Sway IPC server");
info!("Sway IPC subscription client connected");
let event_types = vec![IpcEvent::Window, IpcEvent::Workspace];
let rx = match sub_client.subscribe(event_types) {
Ok(res) => Ok(res),
Err(err) => Err(get_client_error(err)),
}
.expect("Failed to subscribe to Sway IPC server");
loop {
while let Ok((ev_type, payload)) = rx.try_recv() {
debug!("Received sway event {:?}", ev_type);
match ev_type {
IpcEvent::Workspace => {
let json = serde_json::from_slice::<WorkspaceEvent>(&payload).expect(
"Received invalid workspace event payload from Sway IPC server",
);
workspace_bc
.lock()
.expect("Failed to get lock on workspace event bus")
.send(json)
.expect("Failed to broadcast workspace event");
}
IpcEvent::Window => {
let json = serde_json::from_slice::<WindowEvent>(&payload).expect(
"Received invalid window event payload from Sway IPC server",
);
window_bc
.lock()
.expect("Failed to get lock on window event bus")
.send(json)
.expect("Failed to broadcast window event");
}
_ => {}
}
}
match sub_client.poll() {
Ok(()) => Ok(()),
Err(err) => Err(get_client_error(err)),
}
.expect("Failed to poll Sway IPC client");
}
});
Ok(Self {
client,
workspace_bc: workspace_bc2,
window_bc: window_bc2,
})
}
pub fn ipc(&mut self, command: IpcCommand) -> Result<Vec<u8>> {
@ -80,21 +139,28 @@ impl SwayClient {
}
}
pub fn subscribe(
&mut self,
event_types: Vec<IpcEvent>,
) -> Result<crossbeam_channel::Receiver<(IpcEvent, Vec<u8>)>> {
match self.client.subscribe(event_types) {
pub(crate) fn run(&mut self, cmd: String) -> Result<Vec<u8>> {
debug!("Sending command: {}", cmd);
match self.client.run(cmd) {
Ok(res) => Ok(res),
Err(err) => Err(get_client_error(err)),
}
}
pub fn poll(&mut self) -> Result<()> {
match self.client.poll() {
Ok(()) => Ok(()),
Err(err) => Err(get_client_error(err)),
}
pub fn subscribe_workspace(&mut self) -> Receiver<WorkspaceEvent> {
trace!("Adding new workspace subscriber");
self.workspace_bc
.lock()
.expect("Failed to get lock on workspace event bus")
.subscribe()
}
pub fn subscribe_window(&mut self) -> Receiver<WindowEvent> {
trace!("Adding new window subscriber");
self.window_bc
.lock()
.expect("Failed to get lock on window event bus")
.subscribe()
}
}
@ -107,3 +173,43 @@ pub fn get_client_error(error: Error) -> Report {
Error::Io(err) => Report::new(err),
}
}
lazy_static! {
static ref CLIENT: Arc<Mutex<SwayClient>> = {
let client = SwayClient::connect();
match client {
Ok(client) => Arc::new(Mutex::new(client)),
Err(err) => panic!("{:?}", err),
}
};
}
pub fn get_client() -> Arc<Mutex<SwayClient>> {
Arc::clone(&CLIENT)
}
pub struct UnboundedBroadcast<T> {
channels: Vec<crossbeam_channel::Sender<T>>,
}
impl<T: 'static + Clone + Send + Sync> UnboundedBroadcast<T> {
pub const fn new() -> Self {
Self { channels: vec![] }
}
pub fn subscribe(&mut self) -> Receiver<T> {
let (tx, rx) = crossbeam_channel::unbounded();
self.channels.push(tx);
rx
}
pub fn send(&self, message: T) -> Result<(), crossbeam_channel::SendError<T>> {
for c in &self.channels {
c.send(message.clone())?;
}
Ok(())
}
}