168 lines
5.2 KiB
Rust
168 lines
5.2 KiB
Rust
use crate::{
|
|
message::{DeckMessage, InputMessage, ManagerMessage, ObsMessage},
|
|
store::Store,
|
|
};
|
|
use std::collections::BTreeSet;
|
|
use streamdeck_common::Input;
|
|
use tokio::sync::{
|
|
broadcast::Receiver,
|
|
mpsc::{self, Sender},
|
|
};
|
|
use zbus::SignalContext;
|
|
|
|
mod button;
|
|
mod deck;
|
|
mod obs;
|
|
|
|
pub(crate) const fn daemon_path() -> &'static str {
|
|
"/dog/asonix/git/asonix/StreamdeckDaemon"
|
|
}
|
|
|
|
pub(crate) const fn obs_path() -> &'static str {
|
|
"/dog/asonix/git/asonix/StreamdeckDaemon/obs"
|
|
}
|
|
|
|
pub(crate) fn deck_path(serial_number: &str) -> String {
|
|
String::new() + daemon_path() + "/" + serial_number
|
|
}
|
|
|
|
pub(crate) fn button_path(serial_number: &str, input: &Input) -> String {
|
|
deck_path(serial_number) + "/" + input.to_string().as_str()
|
|
}
|
|
|
|
struct Daemon {
|
|
manager: Sender<ManagerMessage>,
|
|
decks: BTreeSet<String>,
|
|
}
|
|
|
|
fn fail(e: impl std::fmt::Display) -> zbus::fdo::Error {
|
|
zbus::fdo::Error::Failed(e.to_string())
|
|
}
|
|
|
|
#[zbus::dbus_interface(name = "dog.asonix.git.asonix.StreamdeckDaemon")]
|
|
impl Daemon {
|
|
async fn enable_discovery(&self) -> zbus::fdo::Result<()> {
|
|
tracing::debug!("enable_discovery");
|
|
self.manager
|
|
.send(ManagerMessage::EnableDiscovery)
|
|
.await
|
|
.map_err(fail)
|
|
}
|
|
|
|
async fn disable_discovery(&self) -> zbus::fdo::Result<()> {
|
|
tracing::debug!("disable_discovery");
|
|
self.manager
|
|
.send(ManagerMessage::DisableDiscovery)
|
|
.await
|
|
.map_err(fail)
|
|
}
|
|
|
|
async fn get_decks(&self) -> Vec<String> {
|
|
tracing::debug!("get_decks");
|
|
self.decks.iter().cloned().collect()
|
|
}
|
|
|
|
#[dbus_interface(signal)]
|
|
async fn deck_added(ctx: &SignalContext<'_>, serial_number: &str) -> zbus::Result<()>;
|
|
|
|
#[dbus_interface(signal)]
|
|
async fn deck_removed(ctx: &SignalContext<'_>, serial_number: &str) -> zbus::Result<()>;
|
|
}
|
|
|
|
#[tracing::instrument(skip_all)]
|
|
pub(crate) async fn spawn(
|
|
store: Store,
|
|
mut input: Receiver<InputMessage>,
|
|
mut deck_rx: mpsc::Receiver<DeckMessage>,
|
|
obs: Sender<ObsMessage>,
|
|
manager: Sender<ManagerMessage>,
|
|
) -> anyhow::Result<zbus::Connection> {
|
|
let state = Daemon {
|
|
manager: manager.clone(),
|
|
decks: BTreeSet::new(),
|
|
};
|
|
|
|
let conn = zbus::ConnectionBuilder::session()?
|
|
.name("dog.asonix.git.asonix.StreamdeckDaemon")?
|
|
.serve_at(daemon_path(), state)?
|
|
.build()
|
|
.await?;
|
|
|
|
obs::Obs::hydrate(conn.clone(), obs).await?;
|
|
|
|
let conn2 = conn.clone();
|
|
tokio::spawn(async move {
|
|
let conn = conn2;
|
|
while let Some(msg) = deck_rx.recv().await {
|
|
match msg {
|
|
DeckMessage::Open(config) => {
|
|
if let Ok(daemon_ref) = conn
|
|
.object_server()
|
|
.interface::<_, Daemon>(daemon_path())
|
|
.await
|
|
{
|
|
let mut daemon = daemon_ref.get_mut().await;
|
|
if let Err(e) = deck::Deck::hydrate(
|
|
conn.clone(),
|
|
config.serial_number.clone(),
|
|
config.product_name,
|
|
config.port_name,
|
|
store.clone(),
|
|
)
|
|
.await
|
|
{
|
|
tracing::warn!("Error hydrating deck: {}", e);
|
|
continue;
|
|
}
|
|
|
|
daemon.decks.insert(config.serial_number.clone());
|
|
let ctx = daemon_ref.signal_context();
|
|
let _ = Daemon::deck_added(ctx, &config.serial_number).await;
|
|
}
|
|
}
|
|
DeckMessage::Close(serial_number) => {
|
|
let _ = conn
|
|
.object_server()
|
|
.remove::<deck::Deck, _>(deck_path(&serial_number))
|
|
.await;
|
|
if let Ok(daemon_ref) = conn
|
|
.object_server()
|
|
.interface::<_, Daemon>(daemon_path())
|
|
.await
|
|
{
|
|
let mut daemon = daemon_ref.get_mut().await;
|
|
daemon.decks.remove(&serial_number);
|
|
let ctx = daemon_ref.signal_context();
|
|
let _ = Daemon::deck_removed(ctx, &serial_number).await;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
let conn2 = conn.clone();
|
|
tokio::spawn(async move {
|
|
let conn = conn2;
|
|
|
|
while let Ok((serial_number, input)) = input.recv().await {
|
|
if let Ok(deck_ref) = conn
|
|
.object_server()
|
|
.interface::<_, deck::Deck>(deck_path(&serial_number))
|
|
.await
|
|
{
|
|
let _ = deck::Deck::button_pushed(deck_ref.signal_context(), input.clone()).await;
|
|
}
|
|
|
|
if let Ok(button_ref) = conn
|
|
.object_server()
|
|
.interface::<_, button::Button>(button_path(&serial_number, &input))
|
|
.await
|
|
{
|
|
let _ = button::Button::pushed(button_ref.signal_context()).await;
|
|
}
|
|
}
|
|
});
|
|
|
|
Ok(conn)
|
|
}
|