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