whatsapp_rust/handlers/
notification.rs

1use super::traits::StanzaHandler;
2use crate::client::Client;
3use crate::types::events::Event;
4use async_trait::async_trait;
5use log::{info, warn};
6use std::sync::Arc;
7use wacore_binary::{jid::SERVER_JID, node::Node};
8
9/// Handler for `<notification>` stanzas.
10///
11/// Processes various notification types including:
12/// - Encrypt notifications (key upload requests)
13/// - Server sync notifications
14/// - Account sync notifications (push name updates)
15#[derive(Default)]
16pub struct NotificationHandler;
17
18impl NotificationHandler {
19    pub fn new() -> Self {
20        Self
21    }
22}
23
24#[async_trait]
25impl StanzaHandler for NotificationHandler {
26    fn tag(&self) -> &'static str {
27        "notification"
28    }
29
30    async fn handle(&self, client: Arc<Client>, node: &Node, _cancelled: &mut bool) -> bool {
31        handle_notification_impl(&client, node).await;
32        true
33    }
34}
35
36async fn handle_notification_impl(client: &Arc<Client>, node: &Node) {
37    let notification_type = node.attrs.get("type").cloned().unwrap_or_default();
38
39    match notification_type.as_str() {
40        "encrypt" => {
41            if let Some(from) = node.attrs.get("from")
42                && from == SERVER_JID
43            {
44                let client_clone = client.clone();
45                tokio::spawn(async move {
46                    if let Err(e) = client_clone.upload_pre_keys().await {
47                        warn!("Failed to upload pre-keys after notification: {:?}", e);
48                    }
49                });
50            }
51        }
52        "server_sync" => {
53            info!(target: "Client", "Received `server_sync` notification, scheduling app state sync(s).");
54            for collection_node in node.get_children_by_tag("collection") {
55                let name = collection_node
56                    .attrs
57                    .get("name")
58                    .cloned()
59                    .unwrap_or_default();
60                let version = collection_node
61                    .attrs
62                    .get("version")
63                    .and_then(|v| v.parse::<u64>().ok())
64                    .unwrap_or(0);
65                info!(
66                    target: "Client/AppState",
67                    "scheduling sync for collection '{name}' from version {version}."
68                );
69            }
70        }
71        "account_sync" => {
72            if let Some(push_name_attr) = node.attrs.get("pushname") {
73                let new_push_name = push_name_attr.clone();
74                client
75                    .clone()
76                    .update_push_name_and_notify(new_push_name)
77                    .await;
78            } else {
79                warn!(target: "Client", "TODO: Implement full handler for <notification type='account_sync'>, for now dispatching generic event.");
80                client
81                    .core
82                    .event_bus
83                    .dispatch(&Event::Notification(node.clone()));
84            }
85        }
86        _ => {
87            warn!(target: "Client", "TODO: Implement handler for <notification type='{notification_type}'>");
88            client
89                .core
90                .event_bus
91                .dispatch(&Event::Notification(node.clone()));
92        }
93    }
94}