whatsapp_rust/features/
presence.rs1use crate::client::Client;
2use log::{debug, info, warn};
3use wacore_binary::builder::NodeBuilder;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub enum PresenceStatus {
7 Available,
8 Unavailable,
9}
10
11impl PresenceStatus {
12 fn as_str(&self) -> &'static str {
13 match self {
14 PresenceStatus::Available => "available",
15 PresenceStatus::Unavailable => "unavailable",
16 }
17 }
18}
19
20impl std::fmt::Display for PresenceStatus {
21 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22 write!(f, "{}", self.as_str())
23 }
24}
25
26impl From<crate::types::presence::Presence> for PresenceStatus {
27 fn from(p: crate::types::presence::Presence) -> Self {
28 match p {
29 crate::types::presence::Presence::Available => PresenceStatus::Available,
30 crate::types::presence::Presence::Unavailable => PresenceStatus::Unavailable,
31 }
32 }
33}
34
35pub struct Presence<'a> {
36 client: &'a Client,
37}
38
39impl<'a> Presence<'a> {
40 pub(crate) fn new(client: &'a Client) -> Self {
41 Self { client }
42 }
43
44 pub async fn set(&self, status: PresenceStatus) -> Result<(), anyhow::Error> {
45 let device_snapshot = self
46 .client
47 .persistence_manager()
48 .get_device_snapshot()
49 .await;
50
51 debug!(
52 "send_presence called with push_name: '{}'",
53 device_snapshot.push_name
54 );
55
56 if device_snapshot.push_name.is_empty() {
57 warn!("Cannot send presence: push_name is empty!");
58 return Err(anyhow::anyhow!(
59 "Cannot send presence without a push name set"
60 ));
61 }
62
63 let presence_type = status.as_str();
64
65 let node = NodeBuilder::new("presence")
66 .attr("type", presence_type)
67 .attr("name", &device_snapshot.push_name)
68 .build();
69
70 info!(
71 "Sending presence stanza: <presence type=\"{}\" name=\"{}\"/>",
72 presence_type,
73 node.attrs.get("name").map_or("", |s| s.as_str())
74 );
75
76 self.client.send_node(node).await.map_err(|e| e.into())
77 }
78
79 pub async fn set_available(&self) -> Result<(), anyhow::Error> {
80 self.set(PresenceStatus::Available).await
81 }
82
83 pub async fn set_unavailable(&self) -> Result<(), anyhow::Error> {
84 self.set(PresenceStatus::Unavailable).await
85 }
86}
87
88impl Client {
89 #[allow(clippy::wrong_self_convention)]
90 pub fn presence(&self) -> Presence<'_> {
91 Presence::new(self)
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[test]
100 fn test_presence_status_display() {
101 assert_eq!(PresenceStatus::Available.to_string(), "available");
102 assert_eq!(PresenceStatus::Unavailable.to_string(), "unavailable");
103 }
104
105 #[test]
106 fn test_presence_status_as_str() {
107 assert_eq!(PresenceStatus::Available.as_str(), "available");
108 assert_eq!(PresenceStatus::Unavailable.as_str(), "unavailable");
109 }
110}