whatsapp_rust/handlers/
ib.rs

1use super::traits::StanzaHandler;
2use crate::client::Client;
3use crate::types::events::{Event, OfflineSyncCompleted, OfflineSyncPreview};
4use async_trait::async_trait;
5use log::{info, warn};
6use std::sync::Arc;
7use wacore_binary::node::Node;
8
9/// Handler for `<ib>` (information broadcast) stanzas.
10///
11/// Processes various server notifications including:
12/// - Dirty state notifications
13/// - Edge routing information
14/// - Offline sync previews and completion notifications
15/// - Thread metadata
16pub struct IbHandler;
17
18impl Default for IbHandler {
19    fn default() -> Self {
20        Self::new()
21    }
22}
23
24impl IbHandler {
25    pub fn new() -> Self {
26        Self
27    }
28}
29
30#[async_trait]
31impl StanzaHandler for IbHandler {
32    fn tag(&self) -> &'static str {
33        "ib"
34    }
35
36    async fn handle(&self, client: Arc<Client>, node: &Node, _cancelled: &mut bool) -> bool {
37        handle_ib_impl(client, node).await;
38        true
39    }
40}
41
42async fn handle_ib_impl(client: Arc<Client>, node: &Node) {
43    for child in node.children().unwrap_or_default() {
44        match child.tag.as_str() {
45            "dirty" => {
46                let mut attrs = child.attrs();
47                let dirty_type = attrs.string("type");
48
49                info!(
50                    target: "Client",
51                    "Received dirty state notification for type: '{dirty_type}'. Awaiting server_sync notification."
52                );
53            }
54            "edge_routing" => {
55                info!(target: "Client", "Received edge routing info, ignoring for now.");
56            }
57            "offline_preview" => {
58                let mut attrs = child.attrs();
59                let total = attrs.optional_u64("count").unwrap_or(0) as i32;
60                let app_data_changes = attrs.optional_u64("appdata").unwrap_or(0) as i32;
61                let messages = attrs.optional_u64("message").unwrap_or(0) as i32;
62                let notifications = attrs.optional_u64("notification").unwrap_or(0) as i32;
63                let receipts = attrs.optional_u64("receipt").unwrap_or(0) as i32;
64
65                info!(
66                    target: "Client/OfflineSync",
67                    "Offline preview: {} total ({} messages, {} notifications, {} receipts, {} app data changes)",
68                    total, messages, notifications, receipts, app_data_changes,
69                );
70
71                client
72                    .core
73                    .event_bus
74                    .dispatch(&Event::OfflineSyncPreview(OfflineSyncPreview {
75                        total,
76                        app_data_changes,
77                        messages,
78                        notifications,
79                        receipts,
80                    }));
81            }
82            "offline" => {
83                let mut attrs = child.attrs();
84                let count = attrs.optional_u64("count").unwrap_or(0) as i32;
85
86                info!(target: "Client/OfflineSync", "Offline sync completed, received {} items", count);
87                client
88                    .core
89                    .event_bus
90                    .dispatch(&Event::OfflineSyncCompleted(OfflineSyncCompleted { count }));
91            }
92            "thread_metadata" => {
93                // Present in some sessions; safe to ignore for now until feature implemented.
94                info!(target: "Client", "Received thread metadata, ignoring for now.");
95            }
96            _ => {
97                warn!(target: "Client", "Unhandled ib child: <{}>", child.tag);
98            }
99        }
100    }
101}