whatsapp_rust/features/
tctoken.rs1use crate::client::Client;
16use crate::request::IqError;
17use wacore::iq::tctoken::{IssuePrivacyTokensSpec, ReceivedTcToken, tc_token_expiration_cutoff};
18use wacore::store::traits::TcTokenEntry;
19use wacore_binary::jid::Jid;
20
21pub struct TcToken<'a> {
23 client: &'a Client,
24}
25
26impl<'a> TcToken<'a> {
27 pub(crate) fn new(client: &'a Client) -> Self {
28 Self { client }
29 }
30
31 pub async fn issue_tokens(&self, jids: &[Jid]) -> Result<Vec<ReceivedTcToken>, IqError> {
36 if jids.is_empty() {
37 return Ok(Vec::new());
38 }
39
40 let spec = IssuePrivacyTokensSpec::new(jids);
41 let response = self.client.execute(spec).await?;
42 let backend = self.client.persistence_manager.backend();
43 let now = wacore::time::now_secs();
44
45 for received in &response.tokens {
46 let entry = TcTokenEntry {
47 token: received.token.clone(),
48 token_timestamp: received.timestamp,
49 sender_timestamp: Some(now),
50 };
51
52 if let Err(e) = backend.put_tc_token(&received.jid.user, &entry).await {
53 log::warn!(target: "Client/TcToken", "Failed to store issued tc_token for {}: {e}", received.jid);
54 }
55 }
56
57 Ok(response.tokens)
58 }
59
60 pub async fn prune_expired(&self) -> Result<u32, anyhow::Error> {
65 let backend = self.client.persistence_manager.backend();
66 let cutoff = tc_token_expiration_cutoff();
67 let deleted = backend.delete_expired_tc_tokens(cutoff).await?;
68
69 if deleted > 0 {
70 log::info!(target: "Client/TcToken", "Pruned {} expired tc_tokens", deleted);
71 }
72
73 Ok(deleted)
74 }
75
76 pub async fn get(&self, jid: &str) -> Result<Option<TcTokenEntry>, anyhow::Error> {
78 let backend = self.client.persistence_manager.backend();
79 Ok(backend.get_tc_token(jid).await?)
80 }
81
82 pub async fn get_all_jids(&self) -> Result<Vec<String>, anyhow::Error> {
84 let backend = self.client.persistence_manager.backend();
85 Ok(backend.get_all_tc_token_jids().await?)
86 }
87}
88
89impl Client {
90 pub fn tc_token(&self) -> TcToken<'_> {
92 TcToken::new(self)
93 }
94}