lazybar_core/
ipc.rs

1use std::{fs::DirBuilder, path::PathBuf};
2
3use anyhow::Result;
4use tokio::{
5    net::UnixListener,
6    sync::mpsc::{UnboundedReceiver, UnboundedSender},
7};
8use tokio_stream::wrappers::UnixListenerStream;
9
10use crate::IpcStream;
11
12/// The directory in which IPC sockets are created
13pub const IPC_DIR: &str = "/tmp/lazybar-ipc/";
14
15/// Initialize IPC for a given bar
16pub fn init(enabled: bool, bar_name: &str) -> (Result<IpcStream>, String) {
17    let mut final_name = bar_name.to_string();
18    (
19        if enabled && DirBuilder::new().recursive(true).create(IPC_DIR).is_ok()
20        {
21            let (path, idx) = find_path(bar_name);
22
23            if idx > 0 {
24                final_name = format!("{bar_name}({idx})");
25            }
26
27            // map_or_else is invalid here due to type coercion issues
28            #[allow(clippy::option_if_let_else)]
29            if let Ok(listener) = UnixListener::bind(path) {
30                let stream = UnixListenerStream::new(listener);
31
32                Ok(Box::pin(stream))
33            } else {
34                Ok(Box::pin(tokio_stream::pending()))
35            }
36        } else {
37            Ok(Box::pin(tokio_stream::pending()))
38        },
39        final_name,
40    )
41}
42
43fn find_path(bar_name: &str) -> (PathBuf, i32) {
44    let mut fmt = format!("{IPC_DIR}{bar_name}");
45    let mut path = PathBuf::from(fmt);
46    let mut idx = 0;
47    while path.exists() {
48        idx += 1;
49        fmt = format!("{IPC_DIR}{bar_name}({idx})");
50        path = PathBuf::from(fmt.as_str());
51    }
52
53    (path, idx)
54}
55
56/// A sender and a receiver bundled together for two-way communication
57#[derive(Debug)]
58pub struct ChannelEndpoint<T, U> {
59    /// The sender
60    pub send: UnboundedSender<T>,
61    /// The receiver
62    pub recv: UnboundedReceiver<U>,
63}
64
65impl<T, U> ChannelEndpoint<T, U> {
66    /// create a new endpoint from a sender and a receiver
67    #[must_use]
68    pub const fn new(
69        send: UnboundedSender<T>,
70        recv: UnboundedReceiver<U>,
71    ) -> Self {
72        Self { send, recv }
73    }
74}
75
76impl<T, U> AsRef<UnboundedSender<T>> for ChannelEndpoint<T, U> {
77    fn as_ref(&self) -> &UnboundedSender<T> {
78        &self.send
79    }
80}
81
82impl<T, U> AsMut<UnboundedSender<T>> for ChannelEndpoint<T, U> {
83    fn as_mut(&mut self) -> &mut UnboundedSender<T> {
84        &mut self.send
85    }
86}
87
88impl<T, U> AsRef<UnboundedReceiver<U>> for ChannelEndpoint<T, U> {
89    fn as_ref(&self) -> &UnboundedReceiver<U> {
90        &self.recv
91    }
92}
93
94impl<T, U> AsMut<UnboundedReceiver<U>> for ChannelEndpoint<T, U> {
95    fn as_mut(&mut self) -> &mut UnboundedReceiver<U> {
96        &mut self.recv
97    }
98}