Skip to main content

wi_api/
session.rs

1use crate::{error::WiError, types::*};
2use std::sync::Arc;
3
4/// A client scoped to a single WhatsApp session.
5///
6/// Obtain via [`crate::Wi::session`].
7#[derive(Clone)]
8pub struct Session {
9    pub(crate) id: String,
10    pub(crate) http: Arc<reqwest::Client>,
11    pub(crate) base_url: Arc<String>,
12    pub(crate) api_key: Arc<String>,
13}
14
15impl Session {
16    fn url(&self, path: &str) -> String {
17        format!("{}/sessions/{}{}", self.base_url, self.id, path)
18    }
19
20    async fn post<B: serde::Serialize, R: serde::de::DeserializeOwned>(
21        &self,
22        path: &str,
23        body: &B,
24    ) -> Result<R, WiError> {
25        let res = self
26            .http
27            .post(self.url(path))
28            .header("x-api-key", self.api_key.as_str())
29            .json(body)
30            .send()
31            .await?;
32
33        if !res.status().is_success() {
34            return Err(WiError::from_response(res).await);
35        }
36        Ok(res.json().await?)
37    }
38
39    async fn post_empty(&self, path: &str) -> Result<(), WiError> {
40        let res = self
41            .http
42            .post(self.url(path))
43            .header("x-api-key", self.api_key.as_str())
44            .header("content-length", "0")
45            .send()
46            .await?;
47
48        if !res.status().is_success() {
49            return Err(WiError::from_response(res).await);
50        }
51        Ok(())
52    }
53
54    async fn get<R: serde::de::DeserializeOwned>(&self, path: &str) -> Result<R, WiError> {
55        let res = self
56            .http
57            .get(self.url(path))
58            .header("x-api-key", self.api_key.as_str())
59            .send()
60            .await?;
61
62        if !res.status().is_success() {
63            return Err(WiError::from_response(res).await);
64        }
65        Ok(res.json().await?)
66    }
67
68    // ─── Session lifecycle ────────────────────────────────────────────────────
69
70    pub async fn status(&self) -> Result<SessionStatus, WiError> {
71        self.get("/status").await
72    }
73
74    pub async fn qr(&self) -> Result<QRCode, WiError> {
75        self.get("/qr").await
76    }
77
78    pub async fn connect(&self) -> Result<(), WiError> {
79        self.post_empty("/connect").await
80    }
81
82    pub async fn disconnect(&self) -> Result<(), WiError> {
83        self.post_empty("/disconnect").await
84    }
85
86    pub async fn logout(&self) -> Result<(), WiError> {
87        self.post_empty("/logout").await
88    }
89
90    pub async fn pair_phone(&self, phone: &str) -> Result<PairPhoneResult, WiError> {
91        #[derive(serde::Serialize)]
92        struct Body<'a> {
93            phone: &'a str,
94        }
95        self.post("/pairphone", &Body { phone }).await
96    }
97
98    // ─── Send ─────────────────────────────────────────────────────────────────
99
100    pub async fn send_text(&self, p: SendTextParams) -> Result<MessageResponse, WiError> {
101        self.post("/messages/send-text", &p).await
102    }
103
104    pub async fn send_image(&self, p: SendImageParams) -> Result<MessageResponse, WiError> {
105        self.post("/messages/send-image", &p).await
106    }
107
108    pub async fn send_audio(&self, p: SendAudioParams) -> Result<MessageResponse, WiError> {
109        self.post("/messages/send-audio", &p).await
110    }
111
112    pub async fn send_video(&self, p: SendVideoParams) -> Result<MessageResponse, WiError> {
113        self.post("/messages/send-video", &p).await
114    }
115
116    pub async fn send_document(&self, p: SendDocumentParams) -> Result<MessageResponse, WiError> {
117        self.post("/messages/send-document", &p).await
118    }
119
120    pub async fn send_location(&self, p: SendLocationParams) -> Result<MessageResponse, WiError> {
121        self.post("/messages/send-location", &p).await
122    }
123
124    pub async fn send_contact(&self, p: SendContactParams) -> Result<MessageResponse, WiError> {
125        self.post("/messages/send-contact", &p).await
126    }
127
128    pub async fn send_sticker(&self, p: SendStickerParams) -> Result<MessageResponse, WiError> {
129        self.post("/messages/send-sticker", &p).await
130    }
131
132    pub async fn send_poll(&self, p: SendPollParams) -> Result<MessageResponse, WiError> {
133        self.post("/messages/send-poll", &p).await
134    }
135
136    pub async fn react(&self, p: SendReactionParams) -> Result<(), WiError> {
137        self.post::<_, serde_json::Value>("/chat/react", &p).await?;
138        Ok(())
139    }
140
141    // ─── Chat ─────────────────────────────────────────────────────────────────
142
143    pub async fn mark_read(&self, p: MarkReadParams) -> Result<(), WiError> {
144        self.post::<_, serde_json::Value>("/chat/markread", &p)
145            .await?;
146        Ok(())
147    }
148
149    pub async fn presence(&self, p: PresenceParams) -> Result<(), WiError> {
150        self.post::<_, serde_json::Value>("/chat/presence", &p)
151            .await?;
152        Ok(())
153    }
154}