1use crate::api::VkApi;
2use crate::error::VkResult;
3use crate::keyboard::Keyboard;
4use crate::models::Event;
5use async_trait::async_trait;
6
7#[async_trait]
8pub trait MessageHandler: Send + Sync {
9 async fn handle(&self, event: &Event, api: &VkApi) -> VkResult<()>;
10}
11
12#[derive(Debug, Clone, Default)]
13pub struct DefaultMessageHandler;
14
15#[async_trait]
16impl MessageHandler for DefaultMessageHandler {
17 async fn handle(&self, event: &Event, api: &VkApi) -> VkResult<()> {
18 match event {
19 Event::MessageNew(message) => {
20 let _ = api
21 .messages_mark_as_read(message.peer_id, Some(message.id))
22 .await;
23
24 if message.text.starts_with('/') {
25 self.handle_command(message, api).await?;
26 } else {
27 self.handle_text(message, api).await?;
28 }
29
30 if !message.attachments.is_empty() {
31 self.handle_attachments(message, api).await?;
32 }
33
34 if !message.fwd_messages.is_empty() {
35 self.handle_forwarded(message, api).await?;
36 }
37 }
38
39 Event::MessageEdit(message) => {
40 self.handle_edit(message, api).await?;
41 }
42
43 Event::MessageEvent(event) => {
44 self.handle_message_event(event, api).await?;
45 }
46
47 Event::MessageTypingState(state) => {
48 self.handle_typing(state, api).await?;
49 }
50
51 Event::MessageAllow(allow) => {
52 self.handle_message_allow(allow, api).await?;
53 }
54
55 _ => {}
56 }
57
58 Ok(())
59 }
60}
61
62impl DefaultMessageHandler {
63 async fn handle_command(&self, message: &crate::models::Message, api: &VkApi) -> VkResult<()> {
64 let command = message.text.split_whitespace().next().unwrap_or("");
65
66 match command {
67 "/start" | "/help" => {
68 let keyboard = Keyboard::create_menu();
69 api.messages_send(
70 message.peer_id,
71 "š Welcome! I'm a VK bot built with Rust.\n\nCommands:\n/start - Welcome message\n/help - Show help\n/menu - Show menu\n/info - Bot info",
72 Some(&keyboard),
73 None,
74 None,
75 None,
76 None,
77 false,
78 false,
79 None,
80 ).await?;
81 }
82
83 "/menu" => {
84 let keyboard = Keyboard::create_menu();
85 api.messages_send(
86 message.peer_id,
87 "š± Menu:",
88 Some(&keyboard),
89 None,
90 None,
91 None,
92 None,
93 false,
94 false,
95 None,
96 )
97 .await?;
98 }
99
100 "/info" => {
101 api.messages_send(
102 message.peer_id,
103 "š¤ Bot built with vk-bot-api\nš¦ Powered by Rust\nā” Async/await\nš§ Full VK API support",
104 None,
105 None,
106 None,
107 None,
108 None,
109 false,
110 false,
111 None,
112 ).await?;
113 }
114
115 _ => {
116 api.messages_send(
117 message.peer_id,
118 "ā Unknown command. Use /help",
119 None,
120 None,
121 None,
122 None,
123 None,
124 false,
125 false,
126 None,
127 )
128 .await?;
129 }
130 }
131
132 Ok(())
133 }
134
135 async fn handle_text(&self, message: &crate::models::Message, api: &VkApi) -> VkResult<()> {
136 let response = format!("You said: {}", message.text);
137
138 api.messages_send(
139 message.peer_id,
140 &response,
141 None,
142 None,
143 None,
144 Some(message.id),
145 None,
146 false,
147 false,
148 None,
149 )
150 .await?;
151
152 Ok(())
153 }
154
155 async fn handle_attachments(
156 &self,
157 message: &crate::models::Message,
158 api: &VkApi,
159 ) -> VkResult<()> {
160 let mut types = Vec::new();
161
162 for attachment in &message.attachments {
163 match attachment.attachment_type.as_str() {
164 "photo" => types.push("š· Photo"),
165 "video" => types.push("š„ Video"),
166 "audio" => types.push("šµ Audio"),
167 "doc" => types.push("š Document"),
168 "sticker" => types.push("š Sticker"),
169 _ => types.push("š Attachment"),
170 }
171 }
172
173 if !types.is_empty() {
174 let text = format!("Received attachments: {}", types.join(", "));
175
176 api.messages_send(
177 message.peer_id,
178 &text,
179 None,
180 None,
181 None,
182 Some(message.id),
183 None,
184 false,
185 false,
186 None,
187 )
188 .await?;
189 }
190
191 Ok(())
192 }
193
194 async fn handle_forwarded(
195 &self,
196 message: &crate::models::Message,
197 api: &VkApi,
198 ) -> VkResult<()> {
199 let count = message.fwd_messages.len();
200
201 api.messages_send(
202 message.peer_id,
203 &format!("Forwarded messages: {}", count),
204 None,
205 None,
206 None,
207 Some(message.id),
208 None,
209 false,
210 false,
211 None,
212 )
213 .await?;
214
215 Ok(())
216 }
217
218 async fn handle_edit(&self, message: &crate::models::Message, api: &VkApi) -> VkResult<()> {
219 api.messages_send(
220 message.peer_id,
221 "Message was edited",
222 None,
223 None,
224 None,
225 None,
226 None,
227 true,
228 false,
229 None,
230 )
231 .await?;
232
233 Ok(())
234 }
235
236 async fn handle_message_event(
237 &self,
238 event: &crate::models::MessageEvent,
239 api: &VkApi,
240 ) -> VkResult<()> {
241 let _ = api
242 .messages_send_message_event_answer(
243 &event.event_id,
244 event.user_id,
245 event.peer_id,
246 Some(r#"{"type": "show_snackbar", "text": "Done!"}"#),
247 )
248 .await;
249
250 if let Some(payload) = &event.payload
251 && let Some(command) = payload.get("command").and_then(|c| c.as_str())
252 && command == "help"
253 {
254 api.messages_send(
255 event.peer_id,
256 "Help: Use /commands for available commands",
257 None,
258 None,
259 None,
260 None,
261 None,
262 false,
263 false,
264 None,
265 )
266 .await?;
267 }
268
269 Ok(())
270 }
271
272 async fn handle_typing(
273 &self,
274 _state: &crate::models::MessageTypingState,
275 _api: &VkApi,
276 ) -> VkResult<()> {
277 Ok(())
278 }
279
280 async fn handle_message_allow(
281 &self,
282 allow: &crate::models::MessageAllow,
283 api: &VkApi,
284 ) -> VkResult<()> {
285 api.messages_send(
286 allow.user_id,
287 "Thanks for allowing messages!",
288 None,
289 None,
290 None,
291 None,
292 None,
293 false,
294 false,
295 None,
296 )
297 .await?;
298
299 Ok(())
300 }
301}
302
303#[derive(Debug, Clone)]
304pub struct AdminHandler {
305 admin_ids: Vec<i64>,
306}
307
308impl AdminHandler {
309 pub fn new(admin_ids: Vec<i64>) -> Self {
310 Self { admin_ids }
311 }
312
313 pub fn is_admin(&self, user_id: i64) -> bool {
314 self.admin_ids.contains(&user_id)
315 }
316}
317
318#[async_trait]
319impl MessageHandler for AdminHandler {
320 async fn handle(&self, event: &Event, api: &VkApi) -> VkResult<()> {
321 if let Event::MessageNew(message) = event
322 && self.is_admin(message.from_id)
323 {
324 self.handle_admin_command(message, api).await?;
325 }
326
327 Ok(())
328 }
329}
330
331impl AdminHandler {
332 async fn handle_admin_command(
333 &self,
334 message: &crate::models::Message,
335 api: &VkApi,
336 ) -> VkResult<()> {
337 if message.text.starts_with("/admin") {
338 let keyboard = Keyboard::create_admin_menu();
339
340 api.messages_send(
341 message.peer_id,
342 "š§ Admin panel:",
343 Some(&keyboard),
344 None,
345 None,
346 None,
347 None,
348 false,
349 false,
350 None,
351 )
352 .await?;
353 }
354
355 Ok(())
356 }
357}