Skip to main content

filthy_rich/
client.rs

1use tokio::sync::{mpsc::Sender, oneshot};
2
3use crate::{
4    errors::PresenceClientError,
5    types::{ActivitySpec, IPCCommand},
6};
7
8/// A client handle for communicating with [`super::PresenceRunner`] and its inner loop.
9#[derive(Debug, Clone)]
10pub struct PresenceClient {
11    pub(crate) tx: Sender<IPCCommand>,
12    pub(crate) client_id: String,
13}
14
15impl PresenceClient {
16    /// Returns the client ID.
17    #[must_use]
18    pub fn client_id(&self) -> &str {
19        &self.client_id
20    }
21
22    /// Sets/updates the Discord Rich presence activity.
23    /// The runner must be started before calling this.
24    ///
25    /// NOTE: This will NOT wait for the activity to finish becoming online.
26    pub async fn set_activity(&self, activity: ActivitySpec) -> Result<(), PresenceClientError> {
27        let activity = Box::new(activity);
28
29        self.tx
30            .send(IPCCommand::SetActivity { activity })
31            .await
32            .map_err(|_| PresenceClientError::ActivitySendError)?;
33
34        Ok(())
35    }
36
37    /// Clears a previously set Discord Rich Presence activity.
38    ///
39    /// NOTE: This will NOT wait for the activity to finish clearing.
40    pub async fn clear_activity(&self) -> Result<(), PresenceClientError> {
41        self.tx
42            .send(IPCCommand::ClearActivity)
43            .await
44            .map_err(|_| PresenceClientError::ActivitySendError)?;
45
46        Ok(())
47    }
48
49    /// Closes the current connection if any.
50    ///
51    /// This is a semi-blocking call and does wait for the runner thread to respond to the signal being sent.
52    pub async fn close(&self) -> Result<(), PresenceClientError> {
53        let (done_tx, done_rx) = oneshot::channel::<()>();
54
55        match self.tx.send(IPCCommand::Close { done_tx }).await {
56            Ok(_) => done_rx.await?,
57            Err(_) => return Ok(()),
58        }
59
60        Ok(())
61    }
62}