use std::collections::VecDeque;
use layer_tl_types as tl;
use layer_tl_types::{Cursor, Deserializable};
use tokio::sync::mpsc;
use crate::update::{InlineQuery, Update};
use crate::{Client, InvocationError};
pub struct InlineQueryIter {
rx: mpsc::UnboundedReceiver<InlineQuery>,
}
impl InlineQueryIter {
pub async fn next(&mut self) -> Option<InlineQuery> {
self.rx.recv().await
}
}
pub struct InlineResult {
client: Client,
query_id: i64,
pub raw: tl::enums::BotInlineResult,
}
impl InlineResult {
pub fn id(&self) -> &str {
match &self.raw {
tl::enums::BotInlineResult::BotInlineResult(r) => &r.id,
tl::enums::BotInlineResult::BotInlineMediaResult(r) => &r.id,
}
}
pub fn title(&self) -> Option<&str> {
match &self.raw {
tl::enums::BotInlineResult::BotInlineResult(r) => r.title.as_deref(),
tl::enums::BotInlineResult::BotInlineMediaResult(r) => r.title.as_deref(),
}
}
pub fn description(&self) -> Option<&str> {
match &self.raw {
tl::enums::BotInlineResult::BotInlineResult(r) => r.description.as_deref(),
tl::enums::BotInlineResult::BotInlineMediaResult(r) => r.description.as_deref(),
}
}
pub async fn send(&self, peer: tl::enums::Peer) -> Result<(), InvocationError> {
let input_peer = {
let cache = self.client.inner.peer_cache.read().await;
cache.peer_to_input(&peer)
};
let req = tl::functions::messages::SendInlineBotResult {
silent: false,
background: false,
clear_draft: false,
hide_via: false,
peer: input_peer,
reply_to: None,
random_id: crate::random_i64_pub(),
query_id: self.query_id,
id: self.id().to_string(),
schedule_date: None,
send_as: None,
quick_reply_shortcut: None,
allow_paid_stars: None,
};
self.client.rpc_call_raw_pub(&req).await?;
Ok(())
}
}
pub struct InlineResultIter {
client: Client,
request: tl::functions::messages::GetInlineBotResults,
buffer: VecDeque<InlineResult>,
last_chunk: bool,
}
impl InlineResultIter {
fn new(client: Client, request: tl::functions::messages::GetInlineBotResults) -> Self {
Self {
client,
request,
buffer: VecDeque::new(),
last_chunk: false,
}
}
pub fn peer(mut self, peer: tl::enums::InputPeer) -> Self {
self.request.peer = peer;
self
}
pub async fn next(&mut self) -> Result<Option<InlineResult>, InvocationError> {
if let Some(item) = self.buffer.pop_front() {
return Ok(Some(item));
}
if self.last_chunk {
return Ok(None);
}
let raw = self.client.rpc_call_raw_pub(&self.request).await?;
let mut cur = Cursor::from_slice(&raw);
let tl::enums::messages::BotResults::BotResults(r) =
tl::enums::messages::BotResults::deserialize(&mut cur)?;
let query_id = r.query_id;
if let Some(offset) = r.next_offset {
self.request.offset = offset;
} else {
self.last_chunk = true;
}
let client = self.client.clone();
self.buffer
.extend(r.results.into_iter().map(|raw| InlineResult {
client: client.clone(),
query_id,
raw,
}));
Ok(self.buffer.pop_front())
}
}
impl Client {
pub fn iter_inline_queries(&self) -> InlineQueryIter {
let (tx, rx) = mpsc::unbounded_channel();
let client = self.clone();
tokio::spawn(async move {
let mut stream = client.stream_updates();
loop {
match stream.next().await {
Some(Update::InlineQuery(q)) => {
if tx.send(q).is_err() {
break;
}
}
Some(_) => {}
None => break,
}
}
});
InlineQueryIter { rx }
}
pub async fn inline_query(
&self,
bot: tl::enums::Peer,
query: &str,
) -> Result<InlineResultIter, InvocationError> {
let input_bot = {
let cache = self.inner.peer_cache.read().await;
match cache.peer_to_input(&bot) {
tl::enums::InputPeer::User(u) => {
tl::enums::InputUser::InputUser(tl::types::InputUser {
user_id: u.user_id,
access_hash: u.access_hash,
})
}
_ => tl::enums::InputUser::Empty,
}
};
let request = tl::functions::messages::GetInlineBotResults {
bot: input_bot,
peer: tl::enums::InputPeer::Empty,
geo_point: None,
query: query.to_string(),
offset: String::new(),
};
Ok(InlineResultIter::new(self.clone(), request))
}
}