azalea_shell/service/dbus/notification/
mod.rs

1pub mod service;
2
3use std::collections::HashMap;
4
5use azalea_service::StaticServiceManager;
6use tokio::sync::{broadcast, oneshot};
7
8#[derive(azalea_derive::StaticServiceManager)]
9pub struct Service {
10    notifications: HashMap<u32, service::Notification>,
11    conn: Option<zbus::Connection>,
12    rx: flume::Receiver<service::Event>,
13}
14
15pub struct Streams {}
16
17#[derive(Default, Clone)]
18pub struct Init {}
19
20#[derive(Clone, Debug)]
21pub enum Input {
22    Close,
23}
24
25pub enum Event {
26    Notifications(service::Event),
27}
28
29#[derive(Clone, Debug)]
30pub enum Output {
31    Notification(service::Notification),
32}
33
34impl azalea_service::Service for Service {
35    type Init = Init;
36    type Input = Input;
37    type Event = Event;
38    type Output = Output;
39
40    fn handler(init: Self::Init) -> azalea_service::ServiceManager<Self> {
41        azalea_service::ServiceManager::new(init, 16, 16)
42    }
43
44    async fn new(
45        _init: Self::Init,
46        _input: flume::Sender<Self::Input>,
47        _output_sender: broadcast::Sender<Self::Output>,
48    ) -> Self {
49        let (tx, rx) = flume::unbounded();
50        let (discovery_tx, discovery_rx) = oneshot::channel();
51
52        super::discovery::Service::send(super::discovery::Input::QueryServiceExists(
53            format!("org.freedesktop.StatusNotifierWatcher"),
54            discovery_tx,
55        ));
56
57        let conn = match discovery_rx.await {
58            Ok(true) => None,
59            Ok(false) => {
60                let notifications = service::Notifications::new(tx);
61
62                if let Ok(conn) = zbus::conn::Builder::session()
63                    .and_then(|conn| conn.name("org.freedesktop.Notifications"))
64                    .and_then(|conn| conn.serve_at("/org/freedesktop/Notifications", notifications))
65                    .map(|conn| conn.build())
66                {
67                    conn.await.ok()
68                } else {
69                    azalea_log::warning!("There's already a notification server running!");
70                    None
71                }
72            }
73            Err(e) => {
74                azalea_log::warning!("Failed to query for other notification servers: {e}");
75                None
76            }
77        };
78
79        Self {
80            notifications: Default::default(),
81            conn,
82            rx,
83        }
84    }
85
86    async fn message(
87        &mut self,
88        input: Self::Input,
89        _output_sender: &broadcast::Sender<Self::Output>,
90    ) {
91        match input {
92            Input::Close => todo!(),
93        }
94    }
95
96    async fn event_generator(&mut self) -> Self::Event {
97        loop {
98            if self.conn.is_none() {
99                // TODO: Try to recreate?
100                tokio::time::sleep(std::time::Duration::from_secs(100)).await;
101            } else {
102                if let Ok(event) = self.rx.recv_async().await {
103                    return Event::Notifications(event);
104                }
105            }
106        }
107    }
108
109    async fn event_handler(
110        &mut self,
111        event: Self::Event,
112        output_sender: &tokio::sync::broadcast::Sender<Self::Output>,
113    ) -> azalea_service::Result<()> {
114        match event {
115            Event::Notifications(event) => match event {
116                service::Event::Notify(notification) => {
117                    self.notifications
118                        .insert(notification.id, notification.clone());
119                    drop(output_sender.send(Output::Notification(notification)))
120                }
121            },
122        }
123        Ok(())
124    }
125}