144 lines
4.0 KiB
Rust
144 lines
4.0 KiB
Rust
use std::collections::HashMap;
|
|
use std::future::pending;
|
|
use std::path::PathBuf;
|
|
|
|
use async_std::channel::{unbounded, Sender};
|
|
use async_std::os::unix::net::UnixStream;
|
|
use canary_magpie::protocol::*;
|
|
use canary_notifications::Contents;
|
|
use zbus::{dbus_interface, zvariant::Value, ConnectionBuilder, SignalContext};
|
|
|
|
pub type MagpieClient = ClientMessenger<UnixStream>;
|
|
|
|
pub struct Notifications {
|
|
module_path: PathBuf,
|
|
magpie_sender: Sender<MagpieServerMsg>,
|
|
next_id: u32,
|
|
}
|
|
|
|
#[dbus_interface(name = "org.freedesktop.Notifications")]
|
|
impl Notifications {
|
|
fn get_capabilities(&self) -> Vec<String> {
|
|
vec!["body", "body-markup", "actions", "icon-static"]
|
|
.into_iter()
|
|
.map(ToString::to_string)
|
|
.collect()
|
|
}
|
|
|
|
#[dbus_interface(out_args("name", "vendor", "version", "spec_version"))]
|
|
fn get_server_information(&self) -> zbus::fdo::Result<(String, String, String, String)> {
|
|
Ok((
|
|
"canary-notifications".to_string(),
|
|
"Canary Development Team".to_string(),
|
|
"0.1.0".to_string(),
|
|
"1.2".to_string(),
|
|
))
|
|
}
|
|
|
|
async fn notify(
|
|
&mut self,
|
|
app_name: String,
|
|
replaces_id: u32,
|
|
app_icon: String,
|
|
summary: String,
|
|
body: String,
|
|
actions: Vec<String>,
|
|
hints: HashMap<String, Value<'_>>,
|
|
timeout: i32,
|
|
) -> u32 {
|
|
let timeout = match timeout {
|
|
-1 => Some(5000), // default timeout
|
|
0 => None,
|
|
t => Some(t),
|
|
};
|
|
|
|
let contents = Contents {
|
|
app_name: Some(app_name).filter(|s| !s.is_empty()),
|
|
summary,
|
|
body: Some(body).filter(|s| !s.is_empty()),
|
|
timeout,
|
|
};
|
|
|
|
let id = self.next_id;
|
|
self.next_id += 1;
|
|
|
|
let msg = CreatePanel {
|
|
id,
|
|
protocol: "tebibyte-media.desktop.notification".to_string(),
|
|
script: self.module_path.to_owned(),
|
|
init_msg: serde_json::to_vec(&contents).unwrap(),
|
|
};
|
|
|
|
if let Some(delay_ms) = contents.timeout.clone() {
|
|
let delay = std::time::Duration::from_millis(delay_ms as _);
|
|
let magpie_sender = self.magpie_sender.to_owned();
|
|
async_std::task::spawn(async move {
|
|
async_std::task::sleep(delay).await;
|
|
magpie_sender
|
|
.send(MagpieServerMsg::ClosePanel(ClosePanel { id }))
|
|
.await
|
|
.unwrap();
|
|
});
|
|
}
|
|
|
|
self.magpie_sender
|
|
.send(MagpieServerMsg::CreatePanel(msg))
|
|
.await
|
|
.unwrap();
|
|
|
|
id
|
|
}
|
|
|
|
fn close_notification(&self, id: u32) {}
|
|
|
|
#[dbus_interface(signal)]
|
|
async fn notification_closed(ctx: &SignalContext<'_>, id: u32, reason: u32)
|
|
-> zbus::Result<()>;
|
|
|
|
#[dbus_interface(signal)]
|
|
async fn action_invoked(
|
|
ctx: &SignalContext<'_>,
|
|
id: u32,
|
|
action_key: String,
|
|
) -> zbus::Result<()>;
|
|
}
|
|
|
|
#[async_std::main]
|
|
async fn main() {
|
|
let args: Vec<String> = std::env::args().collect();
|
|
let module_path = args
|
|
.get(1)
|
|
.expect("Please pass a path to a Canary script!")
|
|
.to_owned()
|
|
.into();
|
|
|
|
let sock_path = find_socket();
|
|
let socket = UnixStream::connect(sock_path).await.unwrap();
|
|
let mut magpie = MagpieClient::new(socket);
|
|
let (magpie_sender, magpie_receiver) = unbounded();
|
|
|
|
let notifications = Notifications {
|
|
magpie_sender,
|
|
next_id: 0,
|
|
module_path,
|
|
};
|
|
|
|
let _ = ConnectionBuilder::session()
|
|
.unwrap()
|
|
.name("org.freedesktop.Notifications")
|
|
.unwrap()
|
|
.serve_at("/org/freedesktop/Notifications", notifications)
|
|
.unwrap()
|
|
.build()
|
|
.await
|
|
.unwrap();
|
|
|
|
async_std::task::spawn(async move {
|
|
while let Ok(msg) = magpie_receiver.recv().await {
|
|
magpie.send_async(&msg).await.unwrap();
|
|
}
|
|
});
|
|
|
|
pending::<()>().await;
|
|
}
|