Skip to main content

whatsapp_rust/handlers/
chatstate.rs

1//! Handler for incoming `<chatstate>` stanzas (typing indicators).
2
3use super::traits::StanzaHandler;
4use crate::client::Client;
5use async_trait::async_trait;
6use log::debug;
7use std::sync::Arc;
8use wacore::iq::chatstate::{
9    ChatstateParseError, ChatstateSource, ChatstateStanza, ReceivedChatState,
10};
11use wacore_binary::jid::Jid;
12use wacore_binary::node::Node;
13
14/// Event for incoming chatstate (`<chatstate/>`) stanzas.
15///
16/// Contains the chat JID, optional participant (for groups), and the parsed state.
17/// State values align with WhatsApp Web's `WAChatState` constants.
18#[derive(Debug, Clone)]
19pub struct ChatStateEvent {
20    /// The chat where the event occurred (user JID for 1:1, group JID for groups)
21    pub chat: Jid,
22    /// For group chats, the participant who triggered the event
23    pub participant: Option<Jid>,
24    /// The chat state (typing, recording_audio, or idle)
25    pub state: ReceivedChatState,
26}
27
28impl ChatStateEvent {
29    /// Create a `ChatStateEvent` from a parsed `ChatstateStanza`.
30    pub fn from_stanza(stanza: ChatstateStanza) -> Self {
31        let (chat, participant) = match stanza.source {
32            ChatstateSource::User { from } => (from, None),
33            ChatstateSource::Group { from, participant } => (from, Some(participant)),
34        };
35        Self {
36            chat,
37            participant,
38            state: stanza.state,
39        }
40    }
41}
42
43/// Handler for `<chatstate>` stanzas.
44///
45/// Parses incoming chatstate stanzas using the `ProtocolNode` pattern
46/// and dispatches events to registered handlers.
47#[derive(Default)]
48pub struct ChatstateHandler;
49
50#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
51#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
52impl StanzaHandler for ChatstateHandler {
53    fn tag(&self) -> &'static str {
54        "chatstate"
55    }
56
57    async fn handle(&self, client: Arc<Client>, node: Arc<Node>, _cancelled: &mut bool) -> bool {
58        match ChatstateStanza::parse(&node) {
59            Ok(stanza) => {
60                debug!(
61                    target: "ChatstateHandler",
62                    "Received chatstate: {:?} from {:?}",
63                    stanza.state,
64                    stanza.source
65                );
66                client.dispatch_chatstate_event(stanza).await;
67            }
68            Err(ChatstateParseError::SelfEcho) => {
69                debug!(
70                    target: "ChatstateHandler",
71                    "Ignoring self-echo chatstate"
72                );
73            }
74            Err(e) => {
75                log::warn!(
76                    target: "ChatstateHandler",
77                    "Failed to parse chatstate stanza: {e}"
78                );
79            }
80        }
81        true
82    }
83}