use crate::{
client::Bot,
types::{
InputFile, InputMedia, InputPaidMedia, InputSticker, InputStoryContent, ResponseParameters,
},
utils::format_error_report,
};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use tracing::{event, instrument, Level};
pub struct Request<T>
where
T: Serialize,
{
pub method_name: &'static str,
pub data: T,
pub files: Option<Vec<InputFile>>,
}
impl<T> Request<T>
where
T: Serialize,
{
#[must_use]
pub fn new(method_name: &'static str, data: T, files: Option<Vec<InputFile>>) -> Self {
Self {
method_name,
data,
files,
}
}
}
#[derive(Deserialize)]
pub struct Response<T> {
pub ok: bool,
pub result: Option<T>,
pub description: Option<Box<str>>,
pub error_code: Option<i16>,
pub parameters: Option<ResponseParameters>,
}
pub trait TelegramMethod {
type Method: Serialize;
type Return: DeserializeOwned;
#[must_use]
fn build_request<Client>(self, bot: &Bot<Client>) -> Request<Self::Method>;
#[instrument(name = "build", skip_all)]
fn build_response(content: &str) -> Result<Response<Self::Return>, serde_json::Error> {
event!(Level::TRACE, %content, "Parsing");
let mut deserializer = serde_json::Deserializer::from_str(content);
deserializer.disable_recursion_limit();
let deserializer = serde_stacker::Deserializer::new(&mut deserializer);
let res = Response::<Self::Return>::deserialize(deserializer).inspect_err(|err| {
event!(
Level::ERROR,
error = %format_error_report(&err),
%content,
"Cannot parse content",
);
});
event!(Level::TRACE, "Parsed");
res
}
}
pub fn prepare_file(files: &mut Vec<InputFile>, file: &mut InputFile) {
match file {
InputFile::FS(_) | InputFile::Buffered(_) | InputFile::Stream(_) => {
files.push(file.take());
}
InputFile::Id(_) | InputFile::Url(_) => {
}
}
}
pub fn prepare_input_media(files: &mut Vec<InputFile>, input_media: &mut InputMedia) {
match input_media {
InputMedia::Animation(inner) => {
prepare_file(files, &mut inner.media);
}
InputMedia::Audio(inner) => {
prepare_file(files, &mut inner.media);
}
InputMedia::Document(inner) => {
prepare_file(files, &mut inner.media);
}
InputMedia::Photo(inner) => {
prepare_file(files, &mut inner.media);
}
InputMedia::Video(inner) => {
prepare_file(files, &mut inner.media);
}
}
}
pub fn prepare_input_media_group(
files: &mut Vec<InputFile>,
input_media_group: Vec<&mut InputMedia>,
) {
for input_media in input_media_group {
prepare_input_media(files, input_media);
}
}
pub fn prepare_input_sticker(files: &mut Vec<InputFile>, input_sticker: &mut InputSticker) {
prepare_file(files, &mut input_sticker.sticker);
}
pub fn prepare_input_stickers(files: &mut Vec<InputFile>, input_stickers: Vec<&mut InputSticker>) {
for input_sticker in input_stickers {
prepare_input_sticker(files, input_sticker);
}
}
pub fn prepare_input_paid_media(files: &mut Vec<InputFile>, input_paid_media: &mut InputPaidMedia) {
match input_paid_media {
InputPaidMedia::Photo(inner) => {
prepare_file(files, &mut inner.media);
}
InputPaidMedia::Video(inner) => {
prepare_file(files, &mut inner.media);
}
}
}
pub fn prepare_input_paid_media_group(
files: &mut Vec<InputFile>,
input_paid_media_group: Vec<&mut InputPaidMedia>,
) {
for input_paid_media in input_paid_media_group {
prepare_input_paid_media(files, input_paid_media);
}
}
pub fn prepare_input_story_content(
files: &mut Vec<InputFile>,
input_story_content: &mut InputStoryContent,
) {
match input_story_content {
InputStoryContent::Photo(inner) => {
prepare_file(files, &mut inner.photo);
}
InputStoryContent::Video(inner) => {
prepare_file(files, &mut inner.video);
}
}
}