whatsapp_rust/send/
actions.rs1use super::*;
2
3impl Client {
4 pub async fn revoke_message(
15 &self,
16 to: impl Into<Jid>,
17 message_id: impl Into<String>,
18 revoke_type: RevokeType,
19 ) -> Result<(), SendError> {
20 self.revoke_message_inner(to.into(), message_id.into(), revoke_type)
21 .await
22 }
23
24 #[cfg_attr(feature = "tracing", tracing::instrument(name = "wa.send.revoke", level = "debug", skip_all, fields(to = %to.observe()), err(Debug)))]
25 async fn revoke_message_inner(
26 &self,
27 to: Jid,
28 message_id: String,
29 revoke_type: RevokeType,
30 ) -> Result<(), SendError> {
31 self.require_pn().map_err(SendError::from_anyhow)?;
32
33 let (from_me, participant, edit_attr) = match &revoke_type {
34 RevokeType::Sender => {
35 (true, None, EditAttribute::SenderRevoke)
38 }
39 RevokeType::Admin { original_sender } => {
40 if !to.is_group() {
42 return Err(SendError::InvalidRequest(
43 "admin revoke is only valid for group chats".into(),
44 ));
45 }
46 let participant_str = original_sender.to_non_ad_string();
49 log::debug!(
50 "Admin revoke: using participant {} for MessageKey",
51 participant_str
52 );
53 (false, Some(participant_str), EditAttribute::AdminRevoke)
54 }
55 };
56
57 let revoke_message = build_revoke_message(&to, from_me, message_id, participant);
58
59 let force_skdm = matches!(revoke_type, RevokeType::Admin { .. });
66 self.send_message_impl(
67 to,
68 &revoke_message,
69 SendPipelineOptions {
70 force_key_distribution: force_skdm,
71 edit: Some(edit_attr),
72 ..Default::default()
73 },
74 )
75 .await
76 .map_err(SendError::from_anyhow)?;
77 Ok(())
78 }
79
80 pub async fn keep_message(
88 &self,
89 chat: impl Into<Jid>,
90 key: wa::MessageKey,
91 keep: bool,
92 ) -> Result<SendResult, SendError> {
93 let chat = chat.into();
94 let message = wacore::proto_helpers::build_keep_in_chat_message(
95 key,
96 keep,
97 wacore::time::now_millis(),
98 );
99 self.send_message(chat, message).await
100 }
101
102 pub async fn pin_message(
104 &self,
105 chat: impl Into<Jid>,
106 key: wa::MessageKey,
107 duration: PinDuration,
108 ) -> Result<(), SendError> {
109 self.send_pin(
110 chat.into(),
111 key,
112 wa::message::pin_in_chat_message::Type::PinForAll,
113 duration.as_secs(),
114 )
115 .await
116 }
117
118 pub async fn unpin_message(
120 &self,
121 chat: impl Into<Jid>,
122 key: wa::MessageKey,
123 ) -> Result<(), SendError> {
124 self.send_pin(
125 chat.into(),
126 key,
127 wa::message::pin_in_chat_message::Type::UnpinForAll,
128 0,
129 )
130 .await
131 }
132
133 #[cfg_attr(feature = "tracing", tracing::instrument(name = "wa.send.pin", level = "debug", skip_all, fields(chat = %chat.observe()), err(Debug)))]
134 async fn send_pin(
135 &self,
136 chat: Jid,
137 key: wa::MessageKey,
138 pin_type: wa::message::pin_in_chat_message::Type,
139 duration_secs: u32,
140 ) -> Result<(), SendError> {
141 let message = wa::Message {
142 pin_in_chat_message: buffa::MessageField::some(wa::message::PinInChatMessage {
143 key: buffa::MessageField::some(key),
144 r#type: Some(pin_type),
145 sender_timestamp_ms: Some(wacore::time::now_millis()),
146 }),
147 message_context_info: buffa::MessageField::some(wa::MessageContextInfo {
148 message_add_on_duration_in_secs: Some(duration_secs),
149 ..Default::default()
150 }),
151 ..Default::default()
152 };
153
154 self.send_message_impl(
155 chat,
156 &message,
157 SendPipelineOptions {
158 edit: Some(EditAttribute::PinInChat),
159 ..Default::default()
160 },
161 )
162 .await
163 .map_err(SendError::from_anyhow)?;
164 Ok(())
165 }
166}