use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::borrow::Cow;
use std::sync::Arc;
use crate::client::requests::File;
use crate::structs::keyboard::{self, Keyboard};
use crate::client::api_requests::api_call;
use crate::upload::{
download_files, send_tg_attachment_files, send_tg_attachments, upload_vk_attachments,
Attachment,
};
use super::config::Config;
use super::struct_to_vec::{param, struct_to_vec};
use super::tg::{TGCallbackQuery, TGChosenInlineResult, TGInlineQuery, TGMessage};
use super::tg_api::TGSendMessageOptions;
use super::tg_attachments::TGAttachment;
use super::vk::{VKMessageEvent, VKMessageNew};
use super::vk_api::VKMessagesSendOptions;
use super::vk_attachments::VKAttachment;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Event {
VKMessageNew(VKMessageNew),
VKMessageEvent(VKMessageEvent),
TGMessage(TGMessage),
TGEditedMessage(TGMessage),
TGCallbackQuery(TGCallbackQuery),
TGInlineQuery(TGInlineQuery),
TGChosenInlineResult(TGChosenInlineResult),
Unknown,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum EAttachment {
VK(Vec<VKAttachment>),
Telegram(Box<TGAttachment>),
}
#[derive(Debug, Clone)]
pub struct UnifyedContext {
pub text: String,
pub from_id: i64,
pub peer_id: i64,
pub id: i64,
pub r#type: EventType,
pub platform: Platform,
pub data: String,
pub event: Event,
pub attachments: Option<EAttachment>,
pub config: Arc<Config>,
}
#[derive(Debug, Clone, PartialEq, Default)]
pub enum Platform {
#[default]
VK,
Telegram,
}
#[derive(Debug, Clone, PartialEq)]
pub enum EventType {
MessageNew,
MessageEdit,
InlineQuery,
ChosenInlineResult,
CallbackQuery,
Unknown,
}
pub trait UnifyContext {
fn unify(&self, config: Arc<Config>) -> UnifyedContext;
}
#[derive(Clone, Debug)]
pub struct SendOptions {
pub vk: VKMessagesSendOptions,
pub tg: TGSendMessageOptions,
}
#[derive(Clone, Debug, Default)]
pub struct MessageBuilder {
pub message: String,
pub chat_id: i64,
pub config: Arc<Config>,
pub platform: Platform,
pub vk_options: Option<VKMessagesSendOptions>,
pub tg_options: Option<TGSendMessageOptions>,
pub keyboard: Option<Keyboard>,
pub attachments: Option<Vec<Attachment>>,
pub files: Option<Vec<File>>,
pub parse_mode: Option<String>,
}
impl MessageBuilder {
pub fn vk_options(self, options: VKMessagesSendOptions) -> MessageBuilder {
MessageBuilder {
vk_options: Some(options),
..self
}
}
pub fn tg_options(self, options: TGSendMessageOptions) -> MessageBuilder {
MessageBuilder {
tg_options: Some(options),
..self
}
}
pub fn keyboard(self, keyboard: Keyboard) -> MessageBuilder {
MessageBuilder {
keyboard: Some(keyboard),
..self
}
}
pub fn attachments(self, attachments: Vec<Attachment>) -> MessageBuilder {
MessageBuilder {
attachments: Some(attachments),
..self
}
}
pub fn files(self, files: Vec<File>) -> MessageBuilder {
MessageBuilder {
files: Some(files),
..self
}
}
pub fn parse_mode(self, parse_mode: &str) -> MessageBuilder {
MessageBuilder {
parse_mode: Some(parse_mode.to_owned()),
..self
}
}
pub async fn send(self) {
let peer_id = self.chat_id;
let config = self.config.clone();
match self.platform {
Platform::VK => {
let attachments = self.make_vk_attachments(config.clone(), peer_id).await;
let vk_options = self.vk_options.unwrap_or_default();
let keyboard = self.keyboard;
let attachment = attachments.unwrap_or("".to_string());
tokio::task::spawn(async move {
let mut vk = struct_to_vec(vk_options.clone());
if vk_options.message.is_none() || vk_options.message.unwrap().is_empty() {
vk.push(param("message", self.message));
}
if vk_options.peer_id.is_none() || vk_options.peer_id.unwrap() == 0 {
vk.push(param("peer_id", peer_id.to_string()));
}
vk.push(param("random_id", "0"));
let j;
if keyboard.is_some() && vk_options.keyboard.is_none() {
j = serde_json::to_string(&keyboard.unwrap().vk_buttons).unwrap();
vk.push(param("keyboard", j));
}
if !attachment.is_empty() {
vk.push(param("attachment", attachment));
}
api_call(Platform::VK, "messages.send", vk, &config.clone())
.await
.unwrap()
});
}
Platform::Telegram => {
let tg_options = self.tg_options.unwrap_or_default();
let keyboard = self.keyboard;
let parse_mode = self.parse_mode.unwrap_or("HTML".to_string());
let attachments = self.attachments.unwrap_or_default();
let files = self.files.unwrap_or_default();
tokio::task::spawn(async move {
let mut tg = struct_to_vec(tg_options.clone());
if tg_options.text.is_none() || tg_options.text.unwrap().is_empty() {
tg.push(param("text", self.message.clone()));
}
if tg_options.chat_id.is_none() || tg_options.chat_id.unwrap() == 0 {
tg.push(param("chat_id", peer_id.to_string()));
}
let j: String;
if keyboard.is_some() && tg_options.reply_markup.is_none() {
let keyboard = keyboard.unwrap();
j = if !keyboard.inline {
serde_json::to_string(&keyboard::ReplyKeyboardMarkup {
keyboard: keyboard.tg_buttons.unwrap(),
one_time_keyboard: keyboard.one_time,
})
.unwrap()
} else {
serde_json::to_string(&keyboard::InlineKeyboardMarkup {
inline_keyboard: keyboard.tg_buttons.unwrap(),
})
.unwrap()
};
tg.push(param("reply_markup", j));
}
if parse_mode != "HTML" {
tg.push(param("parse_mode", parse_mode));
}
if attachments.is_empty() && files.is_empty() {
api_call(Platform::Telegram, "sendMessage", tg, &config.clone())
.await
.unwrap();
return;
}
if attachments.is_empty() {
send_tg_attachments(attachments, &config, peer_id, &self.message).await;
return;
}
send_tg_attachment_files(files, &config, peer_id, &self.message).await;
});
}
}
}
async fn make_vk_attachments(&self, config: Arc<Config>, peer_id: i64) -> Option<String> {
let attachments = self.attachments.clone().unwrap_or_default();
let files = self.files.clone().unwrap_or_default();
if attachments.is_empty() && files.is_empty() {
return None;
}
if !attachments.is_empty() {
let attachments = download_files(attachments).await;
return Some(
upload_vk_attachments(attachments, &config, peer_id)
.await
.unwrap(),
);
}
Some(
upload_vk_attachments(files, &config, peer_id)
.await
.unwrap(),
)
}
}
impl UnifyedContext {
pub fn message(&self, message: &str) -> MessageBuilder {
MessageBuilder {
message: message.to_owned(),
chat_id: self.peer_id,
config: self.config.clone(),
platform: self.platform.clone(),
..Default::default()
}
}
pub fn send(&self, message: &str) {
let peer_id = self.peer_id.to_string();
let config = self.config.clone();
let message_str = message.to_owned();
match self.platform {
Platform::VK => {
tokio::task::spawn(async move {
api_call(
Platform::VK,
"messages.send",
vec![
param("peer_id", peer_id),
param("message", message_str),
param("random_id", "0"),
],
&config,
)
.await
.unwrap()
});
}
Platform::Telegram => {
tokio::task::spawn(async move {
api_call(
Platform::Telegram,
"sendMessage",
vec![param("chat_id", peer_id), param("text", message_str)],
&config,
)
.await
.unwrap()
});
}
}
}
pub fn send_with_html(&self, message: &str) {
let peer_id = self.peer_id.to_string();
let config = self.config.clone();
let message_str = message.to_owned();
match self.platform {
Platform::VK => {
tokio::task::spawn(async move {
api_call(
Platform::VK,
"messages.send",
vec![
param("peer_id", peer_id),
param("message", message_str),
param("random_id", "0"),
],
&config,
)
.await
.unwrap()
});
}
Platform::Telegram => {
tokio::task::spawn(async move {
api_call(
Platform::Telegram,
"sendMessage",
vec![
param("chat_id", peer_id),
param("text", message_str),
param("parse_mode", "HTML"),
],
&config,
)
.await
.unwrap()
});
}
}
}
pub fn send_with_keyboard(&self, message: &str, keyboard: Keyboard) {
let peer_id = self.peer_id.to_string();
let config = self.config.clone();
let message_str = message.to_owned();
match self.platform {
Platform::VK => {
let j = serde_json::to_string(&keyboard.vk_buttons).unwrap();
tokio::task::spawn(async move {
api_call(
Platform::VK,
"messages.send",
vec![
param("peer_id", peer_id),
param("message", message_str),
param("random_id", "0"),
param("keyboard", j),
],
&config,
)
.await
.unwrap()
});
}
Platform::Telegram => {
let j: String = if !keyboard.inline {
serde_json::to_string(&keyboard::ReplyKeyboardMarkup {
keyboard: keyboard.tg_buttons.unwrap(),
one_time_keyboard: keyboard.one_time,
})
.unwrap()
} else {
serde_json::to_string(&keyboard::InlineKeyboardMarkup {
inline_keyboard: keyboard.tg_buttons.unwrap(),
})
.unwrap()
};
tokio::task::spawn(async move {
api_call(
Platform::Telegram,
"sendMessage",
vec![
param("chat_id", peer_id),
param("text", message_str),
param("reply_markup", j),
param("parse_mode", "HTML"),
],
&config,
)
.await
.unwrap()
});
}
}
}
pub fn send_with_options(&self, message: &'static str, options: SendOptions) {
let config = self.config.clone();
match self.platform {
Platform::VK => {
let mut vk = struct_to_vec(options.vk);
if !vk.contains(¶m("message", message)) {
vk.push(param("message", message));
}
vk.push(param("random_id", "0"));
tokio::task::spawn(async move {
api_call(Platform::VK, "messages.send", vk, &config)
.await
.unwrap()
});
}
Platform::Telegram => {
let mut tg = struct_to_vec(options.tg);
if !tg.contains(¶m("text", message)) {
tg.push(param("text", message));
}
tokio::task::spawn(async move {
api_call(Platform::Telegram, "sendMessage", tg, &config)
.await
.unwrap()
});
}
}
}
pub async fn send_attachment_files(&self, message: &str, attachments: Vec<File>) {
let peer_id = self.peer_id;
let config = self.config.clone();
let message_str = message.to_owned();
match self.platform {
Platform::VK => {
tokio::task::spawn(async move {
api_call(
Platform::VK,
"messages.send",
vec![
param("peer_id", peer_id.to_string()),
param("message", &message_str),
param("random_id", "0"),
param(
"attachment",
upload_vk_attachments(attachments, &config, peer_id)
.await
.unwrap(),
),
],
&config,
)
.await
.unwrap();
});
}
Platform::Telegram => {
tokio::task::spawn(async move {
send_tg_attachment_files(attachments, &config, peer_id, message_str.as_str())
.await;
});
}
}
}
pub async fn send_attachments(&self, message: &str, attachments: Vec<Attachment>) {
let peer_id = self.peer_id;
let config = self.config.clone();
let message_str = message.to_owned();
match self.platform {
Platform::VK => {
tokio::task::spawn(async move {
let attachments = download_files(attachments).await;
api_call(
Platform::VK,
"messages.send",
vec![
param("peer_id", peer_id.to_string()),
param("message", &message_str),
param("random_id", "0"),
param(
"attachment",
upload_vk_attachments(attachments, &config, peer_id)
.await
.unwrap(),
),
],
&config,
)
.await
.unwrap();
});
}
Platform::Telegram => {
tokio::task::spawn(async move {
send_tg_attachments(attachments, &config, peer_id, message_str.as_str()).await;
});
}
}
}
pub async fn api_call(
&self,
platform: Platform,
method: &str,
params: Vec<(Cow<'_, str>, Cow<'_, str>)>,
) -> Value {
api_call(platform, method, params, &self.config)
.await
.unwrap()
}
pub fn set_data(&mut self, data: String) {
self.data = data;
}
pub fn get_data<T: DeserializeOwned>(&self) -> Option<T> {
serde_json::from_str(&self.data).ok()
}
}