whatsapp_rust/
mediaconn.rs1use crate::client::Client;
6use crate::http::{HTTP_STATUS_FORBIDDEN, HTTP_STATUS_UNAUTHORIZED};
7use crate::request::IqError;
8use std::time::Duration;
9use wacore::iq::mediaconn::MediaConnSpec;
10use wacore::time::Instant;
11
12pub use wacore::iq::mediaconn::{HostType, MediaConnHost};
14
15pub(crate) const MEDIA_AUTH_REFRESH_RETRY_ATTEMPTS: usize = 1;
18
19pub(crate) fn is_media_auth_error(status_code: u16) -> bool {
22 matches!(
23 status_code,
24 HTTP_STATUS_UNAUTHORIZED | HTTP_STATUS_FORBIDDEN
25 )
26}
27
28#[derive(Debug, Clone)]
30pub struct MediaConn {
31 pub auth: String,
33 pub ttl: u64,
35 pub auth_ttl: Option<u64>,
37 pub hosts: Vec<MediaConnHost>,
39 pub fetched_at: Instant,
41}
42
43impl MediaConn {
44 pub fn is_expired(&self) -> bool {
47 let effective_ttl = self.auth_ttl.map_or(self.ttl, |at| self.ttl.min(at));
48 self.fetched_at.elapsed() > Duration::from_secs(effective_ttl)
49 }
50}
51
52impl Client {
53 pub(crate) async fn invalidate_media_conn(&self) {
54 *self.media_conn.write().await = None;
55 }
56
57 #[cfg_attr(
58 feature = "tracing",
59 tracing::instrument(
60 name = "wa.media.refresh_conn",
61 level = "debug",
62 skip_all,
63 fields(force),
64 err(Debug)
65 )
66 )]
67 pub async fn refresh_media_conn(&self, force: bool) -> Result<MediaConn, IqError> {
68 {
69 let guard = self.media_conn.read().await;
70 if !force
71 && let Some(conn) = &*guard
72 && !conn.is_expired()
73 {
74 return Ok(conn.clone());
75 }
76 }
77
78 let response = self.execute(MediaConnSpec::new()).await?;
79
80 let new_conn = MediaConn {
81 auth: response.auth,
82 ttl: response.ttl,
83 auth_ttl: response.auth_ttl,
84 hosts: response.hosts,
85 fetched_at: Instant::now(),
86 };
87
88 let mut write_guard = self.media_conn.write().await;
89 *write_guard = Some(new_conn.clone());
90
91 Ok(new_conn)
92 }
93}