1use std::any::Any;
5
6use botkit_core::BotError;
7use botkit_core::action::{
8 AnyChatActionSender, ChatAction, ChatActionFutureBounds, ChatActionSender,
9};
10use botkit_core::{ContextData, OptionValue};
11
12use crate::hub::CliHub;
13use crate::wire::{Inbound, Outbound, OutboundAction};
14
15pub struct CliContextData {
20 pub event: Inbound,
22 hub: CliHub,
23}
24
25impl CliContextData {
26 pub(crate) fn new(event: Inbound, hub: CliHub) -> Self {
28 Self { event, hub }
29 }
30}
31
32impl ContextData for CliContextData {
33 fn channel_id(&self) -> &str {
34 self.event.chat()
35 }
36
37 fn user_id(&self) -> &str {
38 self.event.user().map_or("", |u| u.id.as_str())
39 }
40
41 fn user_name(&self) -> &str {
42 self.event.user().map_or("", |u| u.name.as_str())
43 }
44
45 fn command_name(&self) -> Option<&str> {
46 match &self.event {
47 Inbound::Command(command) => Some(command.name.as_str()),
48 _ => None,
49 }
50 }
51
52 fn command_args(&self) -> Option<&str> {
53 match &self.event {
54 Inbound::Command(command) => Some(command.args.as_str()),
55 _ => None,
56 }
57 }
58
59 fn option(&self, _name: &str) -> Option<OptionValue> {
60 None
61 }
62
63 fn button_id(&self) -> Option<&str> {
64 match &self.event {
65 Inbound::Button(button) => Some(button.data.as_str()),
66 _ => None,
67 }
68 }
69
70 fn message_content(&self) -> Option<&str> {
71 match &self.event {
72 Inbound::Message(message) => message.text.as_deref().or(message.caption.as_deref()),
73 Inbound::Button(button) => button.message_text.as_deref(),
74 Inbound::Edited(edited) => edited.text.as_deref(),
75 _ => None,
76 }
77 }
78
79 fn as_any(&self) -> &dyn Any {
80 self
81 }
82
83 fn action_sender(&self) -> Option<AnyChatActionSender> {
84 Some(AnyChatActionSender::new(CliActionSender {
85 hub: self.hub.clone(),
86 chat: self.event.chat().to_string(),
87 thread_id: self.event.thread_id(),
88 }))
89 }
90}
91
92#[derive(Clone)]
94pub struct CliActionSender {
95 hub: CliHub,
96 chat: String,
97 thread_id: Option<i64>,
98}
99
100impl CliActionSender {
101 pub fn new(hub: CliHub, chat: String, thread_id: Option<i64>) -> Self {
103 Self {
104 hub,
105 chat,
106 thread_id,
107 }
108 }
109
110 fn emit(&self, action: &str, clear: bool) {
111 self.hub.emit(Outbound::Action(OutboundAction {
112 chat: self.chat.clone(),
113 action: action.to_string(),
114 clear,
115 thread_id: self.thread_id,
116 }));
117 }
118}
119
120impl ChatActionSender for CliActionSender {
121 fn send_action(
122 &self,
123 action: ChatAction,
124 ) -> impl ChatActionFutureBounds<Output = Result<(), BotError>> + '_ {
125 let name = match action {
126 ChatAction::Typing => "typing",
127 ChatAction::UploadPhoto => "upload_photo",
128 ChatAction::RecordVideo => "record_video",
129 ChatAction::UploadVideo => "upload_video",
130 ChatAction::RecordVoice => "record_voice",
131 ChatAction::UploadVoice => "upload_voice",
132 ChatAction::UploadDocument => "upload_document",
133 ChatAction::ChooseSticker => "choose_sticker",
134 ChatAction::FindLocation => "find_location",
135 ChatAction::RecordVideoNote => "record_video_note",
136 ChatAction::UploadVideoNote => "upload_video_note",
137 };
138 self.emit(name, false);
139 async { Ok(()) }
140 }
141
142 fn action_expiry(&self) -> std::time::Duration {
143 std::time::Duration::ZERO
146 }
147
148 fn clear_action(&self) -> impl ChatActionFutureBounds<Output = Result<(), BotError>> + '_ {
149 self.emit("typing", true);
150 async { Ok(()) }
151 }
152}