use std::{
any::TypeId,
sync::Arc
};
use anthill_di::{
*,
types::*
};
use botx_api::{bot::models::*, api::result::ExpressResult};
use log::*;
use regex::Regex;
use crate::{
results::*,
handlers::{
command::*,
message::*,
button::*,
chat_created::*,
added_to_chat::*,
deleted_from_chat::*,
left_from_chat::*,
cts_login::*,
cts_logout::*,
internal_bot_notification::*,
smartapp_event::*,
notification_result::*,
status::*
},
};
use super::RequestContext;
pub struct BotXApiFrameworkContextSettings {
pub use_default_button_handler_if_format_or_setup_error: bool,
}
impl Default for BotXApiFrameworkContextSettings {
fn default() -> Self {
Self {
use_default_button_handler_if_format_or_setup_error: false
}
}
}
pub struct BotXApiFrameworkContext {
di_container: DependencyContext,
settings: Arc<BotXApiFrameworkContextSettings>,
}
#[async_trait_with_sync::async_trait(Sync)]
impl Constructor for BotXApiFrameworkContext {
async fn ctor(ctx: DependencyContext) -> BuildDependencyResult<Self> {
Ok( Self::from_di_container(ctx).await )
}
}
impl BotXApiFrameworkContext {
pub const BUTTON_HANDLER_NOT_FOUND_RESPONSE: &str = "Кнопка не обработана. Для команды не найден обработчик.";
pub const COMMAND_HANDLER_NOT_FOUND_RESPONSE: &str = "Команда не обработана. Нет обработчиков с подходящим регулярным выражением. Для команды не зарегистрирован дефолтный обработчик.";
pub const MESSAGE_HANDLER_NOT_FOUND_RESPONSE: &str = "Сообщение не обработано. Для сообщения не найден обработчик.";
pub const CHAT_CREATED_HANDLER_NOT_FOUND_RESPONSE: &str = "Событие создания чата не обработано. Для события не найден обработчик.";
pub const ADDED_TO_CHAT_HANDLER_NOT_FOUND_RESPONSE: &str = "Событие добавления участника в чат не обработано. Для события не найден обработчик.";
pub const DELETED_FROM_CHAT_HANDLER_NOT_FOUND_RESPONSE: &str = "Событие удаления участника из чата не обработано. Для события не найден обработчик.";
pub const LEFT_FROM_CHAT_HANDLER_NOT_FOUND_RESPONSE: &str = "Событие выхода участника из чата не обработано. Для события не найден обработчик.";
pub const INTERNAL_BOT_NOTIFICATION_HANDLER_NOT_FOUND_RESPONSE: &str = "Событие внутренней бот нотификации не обработано. Для события не найден обработчик.";
pub const SMARTAPP_EVENT_HANDLER_NOT_FOUND_RESPONSE: &str = "Событие смартап не обработано. Для события не найден обработчик.";
pub const CTS_LOGIN_HANDLER_NOT_FOUND_RESPONSE: &str = "Событие входа участника в cts не обработано. Для события не найден обработчик.";
pub const CTS_LOGOUT_HANDLER_NOT_FOUND_RESPONSE: &str = "Событие выхода участника из cts не обработано. Для события не найден обработчик.";
pub const NOTIFICATION_CALLBACK_HANDLER_NOT_FOUND_RESPONSE: &str = "Обратный вызов с результатом нотификации не обработан. Для события не найден обработчик.";
pub const STATUS_HANDLER_NOT_FOUND_RESPONSE: &str = "Запрос статуса не обработан. Для события не найден обработчик.";
pub fn new() -> Self {
Self {
di_container: DependencyContext::new_root(),
settings: Arc::new(BotXApiFrameworkContextSettings::default()),
}
}
pub async fn from_di_container(di_container: DependencyContext) -> Self {
let settings = di_container.resolve().await.unwrap_or(Arc::new(BotXApiFrameworkContextSettings::default()));
Self {
di_container,
settings,
}
}
pub fn di_container(&self) -> &DependencyContext {
&self.di_container
}
pub async fn process_command(&self, request: CommandRequest<serde_json::Value, serde_json::Value>) -> CommandResult {
let request_ctx = RequestContext {
sync_id: request.sync_id,
source_sync_id: request.source_sync_id,
attachments: request.attachments,
from: request.from,
async_files: request.async_files,
bot_id: request.bot_id,
proto_version: request.proto_version,
entities: request.entities,
};
match request.command {
botx_api::bot::models::Command::Message(msg) => {
let is_button = request.source_sync_id.is_some();
if is_button {
return self.process_button(msg, request_ctx).await;
}
let is_bot_command = self.di_container.resolve::<CommandDetectionRegex>().await
.unwrap_or(Regex::new("^/").unwrap().into())
.is_match(&*msg.body);
if is_bot_command {
self.process_bot_command(msg, request_ctx).await
} else {
self.process_message(msg, request_ctx).await
}
},
botx_api::bot::models::Command::ChatCreated(event)
=> self.process_chat_created_event(event, request_ctx).await,
botx_api::bot::models::Command::AddedToChat(event)
=> self.process_added_to_chat_event(event, request_ctx).await,
botx_api::bot::models::Command::DeletedFromChat(event)
=> self.process_deleted_from_chat_event(event, request_ctx).await,
botx_api::bot::models::Command::LeftFromChat(event)
=> self.process_left_from_chat_event(event, request_ctx).await,
botx_api::bot::models::Command::SmartappEvent(event)
=> self.process_smartapp_event(event, request_ctx).await,
botx_api::bot::models::Command::InternalBotNotification(event)
=> self.process_internal_bot_notification_event(event, request_ctx).await,
botx_api::bot::models::Command::CtsLogin(event)
=> self.process_cts_login_event(event, request_ctx).await,
botx_api::bot::models::Command::CtsLogout(event)
=> self.process_cts_logout_event(event, request_ctx).await,
}
}
async fn process_button(&self, msg: MessageCommand<serde_json::Value, serde_json::Value>, request: RequestContext) -> CommandResult {
let data_type_id = msg.data.get("type_id");
let Some(data_type_id) = data_type_id else {
warn!("Не найдено поле type_id в объекте data сообщения. Текст кнопки {}", msg.body);
return self.process_default_button(msg, request).await;
};
let Ok(data_type_id) = serde_json::from_value::<String>(data_type_id.clone()) else {
error!("Не удается преобразовать поле type_id data в u64. Текст кнопки {}. type_id:[{}]", msg.body, data_type_id);
return if self.settings.use_default_button_handler_if_format_or_setup_error {
self.process_default_button(msg, request).await
} else {
CommandResult::Ok(CommandOk::new("Неверный формат поля type_id"))
};
};
let meta_data_type_id = msg.metadata.get("type_id");
let Some(meta_data_type_id) = meta_data_type_id else {
warn!("Не найдено поле type_id в объекте metadata сообщения. Текст кнопки {}", msg.body);
return if self.settings.use_default_button_handler_if_format_or_setup_error {
self.process_default_button(msg, request).await
} else {
CommandResult::Ok(CommandOk::new("Не найдено поле type_id в объекте metadata сообщения"))
};
};
let Ok(meta_data_type_id) = serde_json::from_value::<String>(meta_data_type_id.clone()) else {
error!("Не удается преобразовать поле type_id metadata в u64. Текст кнопки {}. type_id:[{}]", msg.body, meta_data_type_id);
return if self.settings.use_default_button_handler_if_format_or_setup_error {
self.process_default_button(msg, request).await
} else {
CommandResult::Ok(CommandOk::new("Неверный формат поля type_id"))
};
};
let matching_rules = self.di_container.resolve_collection::<Box<dyn IButtonHandlerMatchingRule>>().await;
let Ok(matching_rules) = matching_rules else {
debug!("Не удалось получить список сопоставлений обработчиков кнопок. Текст кнопки {}. Ошибка: {:#?}", msg.body, matching_rules.err().unwrap());
return if self.settings.use_default_button_handler_if_format_or_setup_error {
self.process_default_button(msg, request).await
} else {
CommandResult::Ok(CommandOk::new("Не удалось получить список сопоставлений обработчиков кнопок"))
};
};
for matching_rule in matching_rules.iter() {
debug!("Проверка правилу соответствия обработчика кнопки. Претендент data type_id[{:?}] meta data type_id[{:?}]", matching_rule.get_data_type_id(), matching_rule.get_metadata_type_id());
if *matching_rule.get_data_type_id() == data_type_id && *matching_rule.get_metadata_type_id() == meta_data_type_id {
let handler = self.di_container.resolve_by_type_id::<Box<dyn IButtonHandlerCallProducer>>(*matching_rule.get_handler_type_id()).await;
let Ok(mut handler) = handler else {
error!("Кнопка не обработана. Было найдено сопоставление для обработчика кнопки, но обработчик не зарегистрирован в ioc. Текст кнопки {}. Ошибка: {:#?}", msg.body, handler.err().unwrap());
return if self.settings.use_default_button_handler_if_format_or_setup_error {
self.process_default_button(msg, request).await
} else {
CommandResult::Ok(CommandOk::new("Кнопка не обработана. Было найдено сопоставление для обработчика кнопки, но обработчик не зарегистрирован в ioc"))
};
};
return handler.handle(msg.body, msg.data, msg.metadata, request).await;
}
}
self.process_default_button(msg, request).await
}
async fn process_default_button(&self, msg: MessageCommand<serde_json::Value, serde_json::Value>, request: RequestContext) -> CommandResult {
let default_handler = self.di_container.resolve::<Box<dyn IButtonHandler<TData = serde_json::Value, TMetaData = serde_json::Value>>>().await;
let Ok(mut default_handler) = default_handler else {
debug!("{} Сообщение: {:#?}. Ошибка: {:#?}", Self::BUTTON_HANDLER_NOT_FOUND_RESPONSE, msg, default_handler.err().unwrap());
return CommandResult::Ok(CommandOk::new(Self::BUTTON_HANDLER_NOT_FOUND_RESPONSE));
};
default_handler.handle(msg.body, msg.data, msg.metadata, request).await
}
async fn process_bot_command(&self, msg: MessageCommand<serde_json::Value, serde_json::Value>, request: RequestContext) -> CommandResult {
let matching_rules = self.di_container.resolve_collection::<Box<dyn ICommandHandlerMatchingRule>>().await;
let Ok(matching_rules) = matching_rules else {
debug!("Не удалось получить список сопоставлений обработчиков команд. Текст команды {}. Ошибка: {:#?}", msg.body, matching_rules.err().unwrap());
return CommandResult::Ok(CommandOk::new("Не удалось получить список сопоставлений обработчиков команд"));
};
for command_match_rule in matching_rules.iter() {
if command_match_rule.get_command_regex().is_match(&*msg.body) {
let handler = self.di_container.resolve_by_type_id::<Box<dyn ICommandHandler>>(*command_match_rule.get_command_handler_id()).await;
let Ok(mut handler) = handler else {
error!("Команда не обработана. Было найдено сопоставление для обработчика команды, но обработчик не зарегистрирован в ioc. Текст команды {}. Ошибка: {:#?}", msg.body, handler.err().unwrap());
return CommandResult::Ok(CommandOk::new("Команда не обработана. Было найдено сопоставление для обработчика команды, но обработчик не зарегистрирован в ioc"));
};
return handler.handle(msg.body, request).await;
}
}
let default_command_handler_id = self.di_container.resolve::<DefaultCommandHandlerId>().await;
let Ok(default_command_handler_id) = default_command_handler_id else {
debug!("{} Текст команды {}. Ошибка: {:#?}", Self::COMMAND_HANDLER_NOT_FOUND_RESPONSE, msg.body, default_command_handler_id.err().unwrap());
return CommandResult::Ok(CommandOk::new(Self::COMMAND_HANDLER_NOT_FOUND_RESPONSE));
};
let handler = self.di_container.resolve_by_type_id::<Box<dyn ICommandHandler>>(*default_command_handler_id).await;
let Ok(mut handler) = handler else {
error!("Команда не обработана. Дефолтный обработчик задан, но обработчик не зарегистрирован в ioc. Текст команды {}. Ошибка: {:#?}", msg.body, handler.err().unwrap());
return CommandResult::Ok(CommandOk::new("Команда не обработана. Дефолтный обработчик задан, но обработчик не зарегистрирован в ioc"));
};
handler.handle(msg.body, request).await
}
async fn process_message(&self, msg: MessageCommand<serde_json::Value, serde_json::Value>, request: RequestContext) -> CommandResult {
let handler = self.di_container.resolve::<Box<dyn IMessageHandler>>().await;
let Ok(mut handler) = handler else {
debug!("{} Текст сообщения {}. Ошибка: {:#?}", Self::MESSAGE_HANDLER_NOT_FOUND_RESPONSE, msg.body, handler.err().unwrap());
return CommandResult::Ok(CommandOk::new(Self::MESSAGE_HANDLER_NOT_FOUND_RESPONSE));
};
handler.handle(msg.body, request).await
}
async fn process_chat_created_event(&self, event: ChatCreatedCommand<serde_json::Value>, request: RequestContext) -> CommandResult {
let handler = self.di_container.resolve::<Box<dyn IChatCreatedHandler>>().await;
let Ok(mut handler) = handler else {
debug!("{} Информация о событии {:#?}. Ошибка: {:#?}", Self::CHAT_CREATED_HANDLER_NOT_FOUND_RESPONSE, event.data, handler.err().unwrap());
return CommandResult::Ok(CommandOk::new(Self::CHAT_CREATED_HANDLER_NOT_FOUND_RESPONSE));
};
handler.handle(event, request).await
}
async fn process_added_to_chat_event(&self, event: AddedToChatCommand<serde_json::Value>, request: RequestContext) -> CommandResult {
let handler = self.di_container.resolve::<Box<dyn IAddedToChatHandler>>().await;
let Ok(mut handler) = handler else {
debug!("{} Информация о событии {:#?}. Ошибка: {:#?}", Self::ADDED_TO_CHAT_HANDLER_NOT_FOUND_RESPONSE, event.data, handler.err().unwrap());
return CommandResult::Ok(CommandOk::new(Self::ADDED_TO_CHAT_HANDLER_NOT_FOUND_RESPONSE));
};
handler.handle(event, request).await
}
async fn process_deleted_from_chat_event(&self, event: DeletedFromChatCommand<serde_json::Value>, request: RequestContext) -> CommandResult {
let handler = self.di_container.resolve::<Box<dyn IDeletedFromChatHandler>>().await;
let Ok(mut handler) = handler else {
debug!("{}. Информация о событии {:#?}. Ошибка: {:#?}", Self::DELETED_FROM_CHAT_HANDLER_NOT_FOUND_RESPONSE, event.data, handler.err().unwrap());
return CommandResult::Ok(CommandOk::new(Self::DELETED_FROM_CHAT_HANDLER_NOT_FOUND_RESPONSE));
};
handler.handle(event, request).await
}
async fn process_left_from_chat_event(&self, event: LeftFromChatCommand<serde_json::Value>, request: RequestContext) -> CommandResult {
let handler = self.di_container.resolve::<Box<dyn ILeftFromChatHandler>>().await;
let Ok(mut handler) = handler else {
debug!("{} Информация о событии {:#?}. Ошибка: {:#?}", Self::LEFT_FROM_CHAT_HANDLER_NOT_FOUND_RESPONSE, event.data, handler.err().unwrap());
return CommandResult::Ok(CommandOk::new(Self::LEFT_FROM_CHAT_HANDLER_NOT_FOUND_RESPONSE));
};
handler.handle(event, request).await
}
async fn process_smartapp_event(&self, event: SmartappEventCommand<serde_json::Value>, request: RequestContext) -> CommandResult {
let data_processors = self.di_container.resolve_collection::<Box<dyn ISmartappEventDataProcessor>>().await;
let Ok(data_processors) = data_processors else {
debug!("Не удалось получить список обработчиков данных для обработчиков смартап событий. Пытаемся обработать дефолтным обработчиком. Событие: {:#?}. Ошибка: {:#?}", event, data_processors.err().unwrap());
return self.process_smartapp_event_default_handler(event, request).await;
};
for data_processor in data_processors {
let Some(data) = data_processor.get_data(&event.data.data) else {
continue;
};
let Some(options) = data_processor.get_options(&event.data.opts) else {
continue;
};
let handler_call_producer = self.di_container.resolve_by_type_id::<Box<dyn ISmartappEventCallProducer>>(*data_processor.get_handler_type_id()).await;
let Ok(mut handler_call_producer) = handler_call_producer else {
error!("Для обработчика зарегистрирован обработчик данных внутренних смартап события, но не удалось получить не типизированный обработчик. Пробуем найти другой обработчик.");
continue;
};
return handler_call_producer.handle(event.data.request_ref, event.data.smartapp_id, event.data.smartapp_api_version, data, options, request).await;
}
self.process_smartapp_event_default_handler(event, request).await
}
async fn process_smartapp_event_default_handler(&self, event: SmartappEventCommand<serde_json::Value>, request: RequestContext) -> CommandResult {
let default_handler = self.di_container.resolve::<Box<dyn ISmartappEventHandler<TData = serde_json::Value, TOptions = serde_json::Value>>>().await;
let Ok(mut default_handler) = default_handler else {
debug!("{} Событие: {:#?}. Ошибка: {:#?}", Self::SMARTAPP_EVENT_HANDLER_NOT_FOUND_RESPONSE, event, default_handler.err().unwrap());
return CommandResult::Ok(CommandOk::new(Self::SMARTAPP_EVENT_HANDLER_NOT_FOUND_RESPONSE));
};
return default_handler.handle(event.data.request_ref, event.data.smartapp_id, event.data.smartapp_api_version, event.data.data, event.data.opts, request).await
}
async fn process_internal_bot_notification_event(&self, event: InternalBotNotificationCommand<serde_json::Value>, request: RequestContext) -> CommandResult {
let data_processors = self.di_container.resolve_collection::<Box<dyn IInternalBotNotificationDataProcessor>>().await;
let Ok(data_processors) = data_processors else {
debug!("Не удалось получить список обработчиков данных для обработчиков событий внутренней бот нотификации. Пытаемся обработать дефолтным обработчиком. Событие: {:#?}. Ошибка: {:#?}", event, data_processors.err().unwrap());
return self.process_internal_bot_notification_event_default_handler(event, request).await;
};
for data_processor in data_processors {
let Some(data) = data_processor.get_data(&event.data.data) else {
continue;
};
let Some(options) = data_processor.get_options(&event.data.opts) else {
continue;
};
let handler_call_producer = self.di_container.resolve_by_type_id::<Box<dyn IInternalBotNotificationCallProducer>>(*data_processor.get_handler_type_id()).await;
let Ok(mut handler_call_producer) = handler_call_producer else {
error!("Для обработчика зарегистрирован обработчик данных внутренней бот нотификации, но не удалось получить не типизированный обработчик. Пробуем найти другой обработчик.");
continue;
};
return handler_call_producer.handle(data, options, request).await;
}
self.process_internal_bot_notification_event_default_handler(event, request).await
}
async fn process_internal_bot_notification_event_default_handler(&self, event: InternalBotNotificationCommand<serde_json::Value>, request: RequestContext) -> CommandResult {
let default_handler = self.di_container.resolve::<Box<dyn IInternalBotNotificationHandler<TData = serde_json::Value, TOptions = serde_json::Value>>>().await;
let Ok(mut default_handler) = default_handler else {
debug!("{} Событие: {:#?}. Ошибка: {:#?}", Self::INTERNAL_BOT_NOTIFICATION_HANDLER_NOT_FOUND_RESPONSE, event, default_handler.err().unwrap());
return CommandResult::Ok(CommandOk::new(Self::INTERNAL_BOT_NOTIFICATION_HANDLER_NOT_FOUND_RESPONSE));
};
return default_handler.handle(event.data.data, event.data.opts, request).await
}
async fn process_cts_login_event(&self, event: CtsLoginCommand<serde_json::Value>, request: RequestContext) -> CommandResult {
let handler = self.di_container.resolve::<Box<dyn ICtsLoginHandler>>().await;
let Ok(mut handler) = handler else {
debug!("{} Информация о событии {:#?}. Ошибка: {:#?}", Self::CTS_LOGIN_HANDLER_NOT_FOUND_RESPONSE, event.data, handler.err().unwrap());
return CommandResult::Ok(CommandOk::new(Self::CTS_LOGIN_HANDLER_NOT_FOUND_RESPONSE));
};
handler.handle(event, request).await
}
async fn process_cts_logout_event(&self, event: CtsLogoutCommand<serde_json::Value>, request: RequestContext) -> CommandResult {
let handler = self.di_container.resolve::<Box<dyn ICtsLogoutHandler>>().await;
let Ok(mut handler) = handler else {
debug!("{} Информация о событии {:#?}. Ошибка: {:#?}", Self::CTS_LOGOUT_HANDLER_NOT_FOUND_RESPONSE, event.data, handler.err().unwrap());
return CommandResult::Ok(CommandOk::new(Self::CTS_LOGOUT_HANDLER_NOT_FOUND_RESPONSE));
};
handler.handle(event, request).await
}
pub async fn process_notification_result(&self, request: ExpressResult<NotificationCallbackRequestOk, NotificationCallbackRequestError>) {
let handler = self.di_container.resolve::<Box<dyn INotificationResultHandler>>().await;
let Ok(mut handler) = handler else {
debug!("{} Информация об обратном вызове {:#?}. Ошибка: {:#?}", Self::NOTIFICATION_CALLBACK_HANDLER_NOT_FOUND_RESPONSE, request, handler.err().unwrap());
return;
};
handler.handle(request).await
}
pub async fn process_status_result(&self, request: StatusRequest) -> Option<StatusResponse> {
let handler = self.di_container.resolve::<Box<dyn IStatusHandler>>().await;
let Ok(mut handler) = handler else {
debug!("{} Информация об событии запроса состояния {:#?}. Ошибка: {:#?}", Self::STATUS_HANDLER_NOT_FOUND_RESPONSE, request, handler.err().unwrap());
return None;
};
Some(handler.handle(request).await)
}
}