use std::convert::TryInto;
use std::fmt;
use std::time::Duration;
use grammers_mtsender::InvocationError;
use grammers_session::types::{PeerId, PeerRef};
use grammers_session::updates::State;
use grammers_tl_types as tl;
use crate::Client;
use crate::message::{InputMessage, Message};
use crate::peer::{Peer, PeerMap};
#[derive(Clone)]
pub struct CallbackQuery {
pub raw: tl::enums::Update,
pub state: State,
pub(crate) client: Client,
pub(crate) peers: PeerMap,
}
pub struct Answer<'a> {
query: &'a CallbackQuery,
request: tl::functions::messages::SetBotCallbackAnswer,
}
impl CallbackQuery {
pub fn peer_id(&self) -> PeerId {
match &self.raw {
tl::enums::Update::BotCallbackQuery(update) => update.peer.clone().into(),
tl::enums::Update::InlineBotCallbackQuery(update) => {
PeerId::user_unchecked(update.user_id)
}
_ => unreachable!(),
}
}
pub async fn peer_ref(&self) -> Option<PeerRef> {
self.peers.get_ref(self.peer_id()).await
}
pub fn peer(&self) -> Option<&Peer> {
self.peers.get(self.peer_id())
}
pub fn sender_id(&self) -> PeerId {
PeerId::user_unchecked(match &self.raw {
tl::enums::Update::BotCallbackQuery(update) => update.user_id,
tl::enums::Update::InlineBotCallbackQuery(update) => update.user_id,
_ => unreachable!(),
})
}
pub async fn sender_ref(&self) -> Option<PeerRef> {
self.peers.get_ref(self.sender_id()).await
}
pub fn sender(&self) -> Option<&Peer> {
self.peers.get(self.sender_id())
}
pub fn data(&self) -> &[u8] {
match &self.raw {
tl::enums::Update::BotCallbackQuery(update) => update.data.as_deref().unwrap_or(&[]),
tl::enums::Update::InlineBotCallbackQuery(update) => {
update.data.as_deref().unwrap_or(&[])
}
_ => unreachable!(),
}
}
pub fn is_from_inline(&self) -> bool {
matches!(self.raw, tl::enums::Update::InlineBotCallbackQuery(_))
}
pub async fn load_message(&self) -> Result<Message, InvocationError> {
let msg_id = match &self.raw {
tl::enums::Update::BotCallbackQuery(update) => update.msg_id,
_ => return Err(InvocationError::Dropped),
};
Ok(self
.client
.get_messages_by_id(
self.peer_ref().await.ok_or(InvocationError::Dropped)?,
&[msg_id],
)
.await?
.pop()
.unwrap()
.unwrap())
}
pub fn answer(&self) -> Answer<'_> {
let query_id = match &self.raw {
tl::enums::Update::BotCallbackQuery(update) => update.query_id,
tl::enums::Update::InlineBotCallbackQuery(update) => update.query_id,
_ => unreachable!(),
};
Answer {
request: tl::functions::messages::SetBotCallbackAnswer {
alert: false,
query_id,
message: None,
url: None,
cache_time: 0,
},
query: self,
}
}
}
impl<'a> Answer<'a> {
pub fn text<T: Into<String>>(mut self, text: T) -> Self {
self.request.message = Some(text.into());
self.request.alert = false;
self
}
pub fn cache_time(mut self, time: Duration) -> Self {
self.request.cache_time = time.as_secs().try_into().unwrap_or(i32::MAX);
self
}
pub fn alert<T: Into<String>>(mut self, text: T) -> Self {
self.request.message = Some(text.into());
self.request.alert = true;
self
}
pub async fn send(self) -> Result<(), InvocationError> {
self.query.client.invoke(&self.request).await?;
Ok(())
}
pub async fn edit<M: Into<InputMessage>>(self, new_message: M) -> Result<(), InvocationError> {
self.query.client.invoke(&self.request).await?;
let peer = self
.query
.peer_ref()
.await
.ok_or(InvocationError::Dropped)?;
match &self.query.raw {
tl::enums::Update::BotCallbackQuery(update) => {
self.query
.client
.edit_message(peer, update.msg_id, new_message)
.await
}
tl::enums::Update::InlineBotCallbackQuery(update) => self
.query
.client
.edit_inline_message(update.msg_id.clone(), new_message.into())
.await
.map(drop),
_ => unreachable!(),
}
}
pub async fn respond<M: Into<InputMessage>>(
self,
message: M,
) -> Result<Message, InvocationError> {
self.query.client.invoke(&self.request).await?;
let peer = self
.query
.peer_ref()
.await
.ok_or(InvocationError::Dropped)?;
self.query.client.send_message(peer, message).await
}
pub async fn reply<M: Into<InputMessage>>(
self,
message: M,
) -> Result<Message, InvocationError> {
let msg_id = match &self.query.raw {
tl::enums::Update::BotCallbackQuery(update) => update.msg_id,
_ => return Err(InvocationError::Dropped),
};
self.query.client.invoke(&self.request).await?;
let peer = self
.query
.peer_ref()
.await
.ok_or(InvocationError::Dropped)?;
let message = message.into();
self.query
.client
.send_message(peer, message.reply_to(Some(msg_id)))
.await
}
}
impl fmt::Debug for CallbackQuery {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("CallbackQuery")
.field("data", &self.data())
.field("sender", &self.sender())
.field("peer", &self.peer())
.finish()
}
}