use layer_tl_types as tl;
use layer_tl_types::{Cursor, Deserializable};
use crate::{Client, InvocationError as Error};
#[derive(Clone)]
pub struct IncomingMessage {
pub raw: tl::enums::Message,
pub client: Option<Client>,
}
impl std::fmt::Debug for IncomingMessage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("IncomingMessage")
.field("raw", &self.raw)
.field("has_client", &self.client.is_some())
.finish()
}
}
impl IncomingMessage {
pub fn from_raw(raw: tl::enums::Message) -> Self {
Self { raw, client: None }
}
pub fn with_client(mut self, client: Client) -> Self {
self.client = Some(client);
self
}
fn require_client(&self, method: &str) -> Result<&Client, Error> {
self.client.as_ref().ok_or_else(|| {
Error::Deserialize(format!(
"{method}: this IncomingMessage has no embedded client: \
use the `_with` variant and pass a &Client explicitly"
))
})
}
pub fn text(&self) -> Option<&str> {
match &self.raw {
tl::enums::Message::Message(m) => {
if m.message.is_empty() {
None
} else {
Some(&m.message)
}
}
_ => None,
}
}
pub fn id(&self) -> i32 {
match &self.raw {
tl::enums::Message::Message(m) => m.id,
tl::enums::Message::Service(m) => m.id,
tl::enums::Message::Empty(m) => m.id,
}
}
pub fn peer_id(&self) -> Option<&tl::enums::Peer> {
match &self.raw {
tl::enums::Message::Message(m) => Some(&m.peer_id),
tl::enums::Message::Service(m) => Some(&m.peer_id),
_ => None,
}
}
pub fn sender_id(&self) -> Option<&tl::enums::Peer> {
match &self.raw {
tl::enums::Message::Message(m) => m.from_id.as_ref(),
tl::enums::Message::Service(m) => m.from_id.as_ref(),
_ => None,
}
}
pub fn outgoing(&self) -> bool {
match &self.raw {
tl::enums::Message::Message(m) => m.out,
tl::enums::Message::Service(m) => m.out,
_ => false,
}
}
pub fn date(&self) -> i32 {
match &self.raw {
tl::enums::Message::Message(m) => m.date,
tl::enums::Message::Service(m) => m.date,
_ => 0,
}
}
pub fn edit_date(&self) -> Option<i32> {
match &self.raw {
tl::enums::Message::Message(m) => m.edit_date,
_ => None,
}
}
pub fn mentioned(&self) -> bool {
match &self.raw {
tl::enums::Message::Message(m) => m.mentioned,
tl::enums::Message::Service(m) => m.mentioned,
_ => false,
}
}
pub fn silent(&self) -> bool {
match &self.raw {
tl::enums::Message::Message(m) => m.silent,
tl::enums::Message::Service(m) => m.silent,
_ => false,
}
}
pub fn post(&self) -> bool {
match &self.raw {
tl::enums::Message::Message(m) => m.post,
_ => false,
}
}
pub fn pinned(&self) -> bool {
match &self.raw {
tl::enums::Message::Message(m) => m.pinned,
_ => false,
}
}
pub fn forward_count(&self) -> Option<i32> {
match &self.raw {
tl::enums::Message::Message(m) => m.forwards,
_ => None,
}
}
pub fn view_count(&self) -> Option<i32> {
match &self.raw {
tl::enums::Message::Message(m) => m.views,
_ => None,
}
}
pub fn reply_count(&self) -> Option<i32> {
match &self.raw {
tl::enums::Message::Message(m) => m.replies.as_ref().map(|r| match r {
tl::enums::MessageReplies::MessageReplies(x) => x.replies,
}),
_ => None,
}
}
pub fn reply_to_message_id(&self) -> Option<i32> {
match &self.raw {
tl::enums::Message::Message(m) => m.reply_to.as_ref().and_then(|r| match r {
tl::enums::MessageReplyHeader::MessageReplyHeader(h) => h.reply_to_msg_id,
_ => None,
}),
_ => None,
}
}
pub async fn reply_to_message(
&self,
client: &Client,
) -> Result<Option<IncomingMessage>, Error> {
let reply_id = match self.reply_to_message_id() {
Some(id) => id,
None => return Ok(None),
};
let peer = match self.peer_id() {
Some(p) => p.clone(),
None => return Ok(None),
};
let msgs = client.get_messages_by_id(peer, &[reply_id]).await?;
Ok(msgs.into_iter().next())
}
pub fn date_utc(&self) -> Option<chrono::DateTime<chrono::Utc>> {
use chrono::TimeZone;
let ts = self.date();
if ts == 0 {
return None;
}
chrono::Utc.timestamp_opt(ts as i64, 0).single()
}
pub fn edit_date_utc(&self) -> Option<chrono::DateTime<chrono::Utc>> {
use chrono::TimeZone;
self.edit_date()
.and_then(|ts| chrono::Utc.timestamp_opt(ts as i64, 0).single())
}
pub fn media(&self) -> Option<&tl::enums::MessageMedia> {
match &self.raw {
tl::enums::Message::Message(m) => m.media.as_ref(),
_ => None,
}
}
pub fn entities(&self) -> Option<&Vec<tl::enums::MessageEntity>> {
match &self.raw {
tl::enums::Message::Message(m) => m.entities.as_ref(),
_ => None,
}
}
pub fn grouped_id(&self) -> Option<i64> {
match &self.raw {
tl::enums::Message::Message(m) => m.grouped_id,
_ => None,
}
}
pub fn from_scheduled(&self) -> bool {
match &self.raw {
tl::enums::Message::Message(m) => m.from_scheduled,
_ => false,
}
}
pub fn edit_hide(&self) -> bool {
match &self.raw {
tl::enums::Message::Message(m) => m.edit_hide,
_ => false,
}
}
pub fn media_unread(&self) -> bool {
match &self.raw {
tl::enums::Message::Message(m) => m.media_unread,
tl::enums::Message::Service(m) => m.media_unread,
_ => false,
}
}
pub fn via_bot_id(&self) -> Option<i64> {
match &self.raw {
tl::enums::Message::Message(m) => m.via_bot_id,
_ => None,
}
}
pub fn post_author(&self) -> Option<&str> {
match &self.raw {
tl::enums::Message::Message(m) => m.post_author.as_deref(),
_ => None,
}
}
pub fn reaction_count(&self) -> i32 {
match &self.raw {
tl::enums::Message::Message(m) => m
.reactions
.as_ref()
.map(|r| match r {
tl::enums::MessageReactions::MessageReactions(x) => x
.results
.iter()
.map(|res| match res {
tl::enums::ReactionCount::ReactionCount(c) => c.count,
})
.sum(),
})
.unwrap_or(0),
_ => 0,
}
}
pub fn restriction_reason(&self) -> Option<&Vec<tl::enums::RestrictionReason>> {
match &self.raw {
tl::enums::Message::Message(m) => m.restriction_reason.as_ref(),
_ => None,
}
}
pub fn reply_markup(&self) -> Option<&tl::enums::ReplyMarkup> {
match &self.raw {
tl::enums::Message::Message(m) => m.reply_markup.as_ref(),
_ => None,
}
}
pub fn forward_header(&self) -> Option<&tl::enums::MessageFwdHeader> {
match &self.raw {
tl::enums::Message::Message(m) => m.fwd_from.as_ref(),
_ => None,
}
}
pub fn noforwards(&self) -> bool {
match &self.raw {
tl::enums::Message::Message(m) => m.noforwards,
_ => false,
}
}
pub fn markdown_text(&self) -> Option<String> {
let text = self.text()?;
let entities = self.entities().map(|e| e.as_slice()).unwrap_or(&[]);
Some(crate::parsers::generate_markdown(text, entities))
}
pub fn html_text(&self) -> Option<String> {
let text = self.text()?;
let entities = self.entities().map(|e| e.as_slice()).unwrap_or(&[]);
Some(crate::parsers::generate_html(text, entities))
}
pub fn action(&self) -> Option<&tl::enums::MessageAction> {
match &self.raw {
tl::enums::Message::Service(m) => Some(&m.action),
_ => None,
}
}
pub fn photo(&self) -> Option<crate::media::Photo> {
crate::media::Photo::from_media(self.media()?)
}
pub fn document(&self) -> Option<crate::media::Document> {
crate::media::Document::from_media(self.media()?)
}
pub async fn reply(&self, text: impl Into<String>) -> Result<IncomingMessage, Error> {
let client = self.require_client("reply")?.clone();
self.reply_with(&client, text).await
}
pub async fn reply_with(
&self,
client: &Client,
text: impl Into<String>,
) -> Result<IncomingMessage, Error> {
let peer = match self.peer_id() {
Some(p) => p.clone(),
None => return Err(Error::Deserialize("cannot reply: unknown peer".into())),
};
let msg_id = self.id();
client
.send_message_to_peer_ex(
peer,
&crate::InputMessage::text(text.into()).reply_to(Some(msg_id)),
)
.await
}
pub async fn reply_ex(&self, msg: crate::InputMessage) -> Result<IncomingMessage, Error> {
let client = self.require_client("reply_ex")?.clone();
self.reply_ex_with(&client, msg).await
}
pub async fn reply_ex_with(
&self,
client: &Client,
msg: crate::InputMessage,
) -> Result<IncomingMessage, Error> {
let peer = self
.peer_id()
.cloned()
.ok_or_else(|| Error::Deserialize("cannot reply_ex: unknown peer".into()))?;
client
.send_message_to_peer_ex(peer, &msg.reply_to(Some(self.id())))
.await
}
pub async fn respond(&self, text: impl Into<String>) -> Result<IncomingMessage, Error> {
let client = self.require_client("respond")?.clone();
self.respond_with(&client, text).await
}
pub async fn respond_with(
&self,
client: &Client,
text: impl Into<String>,
) -> Result<IncomingMessage, Error> {
let peer = self
.peer_id()
.cloned()
.ok_or_else(|| Error::Deserialize("cannot respond: unknown peer".into()))?;
client
.send_message_to_peer_ex(peer, &crate::InputMessage::text(text.into()))
.await
}
pub async fn respond_ex(&self, msg: crate::InputMessage) -> Result<IncomingMessage, Error> {
let client = self.require_client("respond_ex")?.clone();
self.respond_ex_with(&client, msg).await
}
pub async fn respond_ex_with(
&self,
client: &Client,
msg: crate::InputMessage,
) -> Result<IncomingMessage, Error> {
let peer = self
.peer_id()
.cloned()
.ok_or_else(|| Error::Deserialize("cannot respond_ex: unknown peer".into()))?;
client.send_message_to_peer_ex(peer, &msg).await
}
pub async fn edit(&self, new_text: impl Into<String>) -> Result<(), Error> {
let client = self.require_client("edit")?.clone();
self.edit_with(&client, new_text).await
}
pub async fn edit_with(
&self,
client: &Client,
new_text: impl Into<String>,
) -> Result<(), Error> {
let peer = self
.peer_id()
.cloned()
.ok_or_else(|| Error::Deserialize("cannot edit: unknown peer".into()))?;
client
.edit_message(peer, self.id(), new_text.into().as_str())
.await
}
pub async fn delete(&self) -> Result<(), Error> {
let client = self.require_client("delete")?.clone();
self.delete_with(&client).await
}
pub async fn delete_with(&self, client: &Client) -> Result<(), Error> {
client.delete_messages(vec![self.id()], true).await
}
pub async fn mark_as_read(&self) -> Result<(), Error> {
let client = self.require_client("mark_as_read")?.clone();
self.mark_as_read_with(&client).await
}
pub async fn mark_as_read_with(&self, client: &Client) -> Result<(), Error> {
let peer = self
.peer_id()
.cloned()
.ok_or_else(|| Error::Deserialize("cannot mark_as_read: unknown peer".into()))?;
client.mark_as_read(peer).await
}
pub async fn pin(&self) -> Result<(), Error> {
let client = self.require_client("pin")?.clone();
self.pin_with(&client).await
}
pub async fn pin_with(&self, client: &Client) -> Result<(), Error> {
let peer = self
.peer_id()
.cloned()
.ok_or_else(|| Error::Deserialize("cannot pin: unknown peer".into()))?;
client
.pin_message(peer, self.id(), true, false, false)
.await
}
pub async fn unpin(&self) -> Result<(), Error> {
let client = self.require_client("unpin")?.clone();
self.unpin_with(&client).await
}
pub async fn unpin_with(&self, client: &Client) -> Result<(), Error> {
let peer = self
.peer_id()
.cloned()
.ok_or_else(|| Error::Deserialize("cannot unpin: unknown peer".into()))?;
client.unpin_message(peer, self.id()).await
}
pub async fn forward_to(
&self,
destination: impl Into<crate::PeerRef>,
) -> Result<IncomingMessage, Error> {
let client = self.require_client("forward_to")?.clone();
self.forward_to_with(&client, destination).await
}
pub async fn forward_to_with(
&self,
client: &Client,
destination: impl Into<crate::PeerRef>,
) -> Result<IncomingMessage, Error> {
let src = self
.peer_id()
.cloned()
.ok_or_else(|| Error::Deserialize("cannot forward: unknown source peer".into()))?;
client
.forward_messages_returning(destination, &[self.id()], src)
.await
.and_then(|v| {
v.into_iter()
.next()
.ok_or_else(|| Error::Deserialize("forward returned no message".into()))
})
}
pub async fn refetch(&mut self) -> Result<(), Error> {
let client = self.require_client("refetch")?.clone();
self.refetch_with(&client).await
}
pub async fn refetch_with(&mut self, client: &Client) -> Result<(), Error> {
let peer = self
.peer_id()
.cloned()
.ok_or_else(|| Error::Deserialize("cannot refetch: unknown peer".into()))?;
let mut msgs = client.get_messages_by_id(peer, &[self.id()]).await?;
match msgs.pop() {
Some(m) => {
self.raw = m.raw;
Ok(())
}
None => Err(Error::Deserialize(
"refetch: message not found (deleted?)".into(),
)),
}
}
pub async fn download_media(&self, path: impl AsRef<std::path::Path>) -> Result<bool, Error> {
let client = self.require_client("download_media")?.clone();
self.download_media_with(&client, path).await
}
pub async fn download_media_with(
&self,
client: &Client,
path: impl AsRef<std::path::Path>,
) -> Result<bool, Error> {
if let Some(loc) = crate::media::download_location_from_media(self.media()) {
client.download_media_to_file(loc, path).await?;
Ok(true)
} else {
Ok(false)
}
}
pub async fn react(
&self,
reactions: impl Into<crate::reactions::InputReactions>,
) -> Result<(), Error> {
let client = self.require_client("react")?.clone();
self.react_with(&client, reactions).await
}
pub async fn react_with(
&self,
client: &Client,
reactions: impl Into<crate::reactions::InputReactions>,
) -> Result<(), Error> {
let peer = self
.peer_id()
.cloned()
.ok_or_else(|| Error::Deserialize("cannot react: unknown peer".into()))?;
client.send_reaction(peer, self.id(), reactions).await
}
pub async fn get_reply(&self) -> Result<Option<IncomingMessage>, Error> {
let client = self.require_client("get_reply")?.clone();
self.get_reply_with(&client).await
}
pub async fn get_reply_with(&self, client: &Client) -> Result<Option<IncomingMessage>, Error> {
client.get_reply_to_message(self).await
}
pub fn sender_user_id(&self) -> Option<i64> {
match self.sender_id()? {
tl::enums::Peer::User(u) => Some(u.user_id),
_ => None,
}
}
pub fn sender_chat_id(&self) -> Option<i64> {
match self.sender_id()? {
tl::enums::Peer::Chat(c) => Some(c.chat_id),
tl::enums::Peer::Channel(c) => Some(c.channel_id),
_ => None,
}
}
pub async fn sender_user(&self) -> Result<Option<crate::types::User>, Error> {
let uid = match self.sender_user_id() {
Some(id) => id,
None => return Ok(None),
};
let client = self.require_client("sender_user")?.clone();
let users = client.get_users_by_id(&[uid]).await?;
Ok(users.into_iter().next().flatten())
}
}
#[derive(Debug, Clone)]
pub struct MessageDeletion {
pub message_ids: Vec<i32>,
pub channel_id: Option<i64>,
}
impl MessageDeletion {
pub fn into_messages(self) -> Vec<i32> {
self.message_ids
}
}
#[derive(Debug, Clone)]
pub struct CallbackQuery {
pub query_id: i64,
pub user_id: i64,
pub message_id: Option<i32>,
pub chat_instance: i64,
pub data_raw: Option<Vec<u8>>,
pub game_short_name: Option<String>,
pub chat_peer: Option<tl::enums::Peer>,
pub inline_msg_id: Option<tl::enums::InputBotInlineMessageId>,
}
impl CallbackQuery {
pub fn data(&self) -> Option<&str> {
self.data_raw
.as_ref()
.and_then(|d| std::str::from_utf8(d).ok())
}
pub fn answer(&self) -> Answer<'_> {
Answer {
query_id: self.query_id,
message: None,
alert: false,
url: None,
cache_time: 0,
_marker: std::marker::PhantomData,
}
}
pub async fn answer_flat(&self, client: &Client, text: Option<&str>) -> Result<(), Error> {
client
.answer_callback_query(self.query_id, text, false)
.await
.map(|_| ())
}
pub async fn answer_alert(&self, client: &Client, text: &str) -> Result<(), Error> {
client
.answer_callback_query(self.query_id, Some(text), true)
.await
.map(|_| ())
}
}
pub struct Answer<'a> {
query_id: i64,
message: Option<String>,
alert: bool,
url: Option<String>,
cache_time: i32,
_marker: std::marker::PhantomData<&'a ()>,
}
impl<'a> Answer<'a> {
pub fn text<S: Into<String>>(mut self, text: S) -> Self {
self.message = Some(text.into());
self.alert = false;
self
}
pub fn alert<S: Into<String>>(mut self, text: S) -> Self {
self.message = Some(text.into());
self.alert = true;
self
}
pub fn url<S: Into<String>>(mut self, url: S) -> Self {
self.url = Some(url.into());
self
}
pub fn cache_time(mut self, duration: std::time::Duration) -> Self {
self.cache_time = duration.as_secs().min(i32::MAX as u64) as i32;
self
}
pub async fn send(self, client: &Client) -> Result<(), Error> {
let req = tl::functions::messages::SetBotCallbackAnswer {
alert: self.alert,
query_id: self.query_id,
message: self.message,
url: self.url,
cache_time: self.cache_time,
};
client.rpc_call_raw_pub(&req).await.map(|_| ())
}
}
#[derive(Debug, Clone)]
pub struct InlineQuery {
pub query_id: i64,
pub user_id: i64,
pub query: String,
pub offset: String,
pub peer: Option<tl::enums::Peer>,
}
impl InlineQuery {
pub fn query(&self) -> &str {
&self.query
}
}
#[derive(Debug, Clone)]
pub struct InlineSend {
pub user_id: i64,
pub query: String,
pub id: String,
pub msg_id: Option<tl::enums::InputBotInlineMessageId>,
}
impl InlineSend {
pub async fn edit_message(
&self,
client: &Client,
new_text: &str,
reply_markup: Option<tl::enums::ReplyMarkup>,
) -> Result<bool, Error> {
let msg_id =
match self.msg_id.clone() {
Some(id) => id,
None => return Err(Error::Deserialize(
"InlineSend::edit_message: msg_id is None (bot_inline_send had no peer_type)"
.into(),
)),
};
let req = tl::functions::messages::EditInlineBotMessage {
no_webpage: false,
invert_media: false,
id: msg_id,
message: Some(new_text.to_string()),
media: None,
reply_markup,
entities: None,
};
let body = client.rpc_call_raw(&req).await?;
Ok(!body.is_empty())
}
}
#[derive(Debug, Clone)]
pub struct RawUpdate {
pub constructor_id: u32,
}
#[derive(Debug, Clone)]
pub struct UserStatusUpdate {
pub user_id: i64,
pub status: tl::enums::UserStatus,
}
#[derive(Debug, Clone)]
pub struct ChatActionUpdate {
pub peer: tl::enums::Peer,
pub user_id: i64,
pub action: tl::enums::SendMessageAction,
}
#[non_exhaustive]
#[derive(Debug, Clone)]
pub enum Update {
NewMessage(IncomingMessage),
MessageEdited(IncomingMessage),
MessageDeleted(MessageDeletion),
CallbackQuery(CallbackQuery),
InlineQuery(InlineQuery),
InlineSend(InlineSend),
UserStatus(UserStatusUpdate),
UserTyping(ChatActionUpdate),
Raw(RawUpdate),
}
#[allow(dead_code)]
const ID_UPDATES_TOO_LONG: u32 = 0xe317af7e;
#[allow(dead_code)]
const ID_UPDATE_SHORT_MESSAGE: u32 = 0x313bc7f8;
#[allow(dead_code)]
const ID_UPDATE_SHORT_CHAT_MSG: u32 = 0x4d6deea5;
#[allow(dead_code)]
const ID_UPDATE_SHORT: u32 = 0x78d4dec1;
#[allow(dead_code)]
const ID_UPDATES: u32 = 0x74ae4240;
#[allow(dead_code)]
const ID_UPDATES_COMBINED: u32 = 0x725b04c3;
#[allow(dead_code)]
const ID_UPDATE_SHORT_SENT_MSG: u32 = 0x9015e101;
#[allow(dead_code)]
pub(crate) fn parse_updates(bytes: &[u8]) -> Vec<Update> {
if bytes.len() < 4 {
return vec![];
}
let cid = u32::from_le_bytes(bytes[..4].try_into().unwrap());
match cid {
ID_UPDATES_TOO_LONG => {
tracing::warn!(
"[layer] updatesTooLong: call client.get_difference() to recover missed updates"
);
vec![]
}
ID_UPDATE_SHORT_MESSAGE => {
let mut cur = Cursor::from_slice(&bytes[4..]); match tl::types::UpdateShortMessage::deserialize(&mut cur) {
Ok(m) => vec![Update::NewMessage(make_short_dm(m))],
Err(e) => {
tracing::debug!(
"[layer] updateShortMessage parse error (unknown constructor or newer layer): {e}"
);
vec![]
}
}
}
ID_UPDATE_SHORT_CHAT_MSG => {
let mut cur = Cursor::from_slice(&bytes[4..]); match tl::types::UpdateShortChatMessage::deserialize(&mut cur) {
Ok(m) => vec![Update::NewMessage(make_short_chat(m))],
Err(e) => {
tracing::debug!(
"[layer] updateShortChatMessage parse error (unknown constructor or newer layer): {e}"
);
vec![]
}
}
}
ID_UPDATE_SHORT => {
let mut cur = Cursor::from_slice(&bytes[4..]); match tl::types::UpdateShort::deserialize(&mut cur) {
Ok(m) => from_single_update(m.update),
Err(e) => {
tracing::debug!(
"[layer] updateShort parse error (unknown constructor or newer layer): {e}"
);
vec![]
}
}
}
ID_UPDATES => {
let mut cur = Cursor::from_slice(bytes);
match tl::enums::Updates::deserialize(&mut cur) {
Ok(tl::enums::Updates::Updates(u)) => {
u.updates.into_iter().flat_map(from_single_update).collect()
}
Err(e) => {
tracing::debug!(
"[layer] Updates parse error (unknown constructor or newer layer): {e}"
);
vec![]
}
_ => vec![],
}
}
ID_UPDATES_COMBINED => {
let mut cur = Cursor::from_slice(bytes);
match tl::enums::Updates::deserialize(&mut cur) {
Ok(tl::enums::Updates::Combined(u)) => {
u.updates.into_iter().flat_map(from_single_update).collect()
}
Err(e) => {
tracing::debug!(
"[layer] UpdatesCombined parse error (unknown constructor or newer layer): {e}"
);
vec![]
}
_ => vec![],
}
}
ID_UPDATE_SHORT_SENT_MSG => vec![],
_ => vec![],
}
}
pub fn from_single_update_pub(upd: tl::enums::Update) -> Vec<Update> {
from_single_update(upd)
}
fn from_single_update(upd: tl::enums::Update) -> Vec<Update> {
use tl::enums::Update::*;
match upd {
NewMessage(u) => vec![Update::NewMessage(IncomingMessage::from_raw(u.message))],
NewChannelMessage(u) => vec![Update::NewMessage(IncomingMessage::from_raw(u.message))],
EditMessage(u) => vec![Update::MessageEdited(IncomingMessage::from_raw(u.message))],
EditChannelMessage(u) => vec![Update::MessageEdited(IncomingMessage::from_raw(u.message))],
DeleteMessages(u) => vec![Update::MessageDeleted(MessageDeletion {
message_ids: u.messages,
channel_id: None,
})],
DeleteChannelMessages(u) => vec![Update::MessageDeleted(MessageDeletion {
message_ids: u.messages,
channel_id: Some(u.channel_id),
})],
BotCallbackQuery(u) => vec![Update::CallbackQuery(CallbackQuery {
query_id: u.query_id,
user_id: u.user_id,
message_id: Some(u.msg_id),
chat_instance: u.chat_instance,
data_raw: u.data,
game_short_name: u.game_short_name,
chat_peer: Some(u.peer),
inline_msg_id: None,
})],
InlineBotCallbackQuery(u) => vec![Update::CallbackQuery(CallbackQuery {
query_id: u.query_id,
user_id: u.user_id,
message_id: None,
chat_instance: u.chat_instance,
data_raw: u.data,
game_short_name: u.game_short_name,
chat_peer: None,
inline_msg_id: Some(u.msg_id),
})],
BotInlineQuery(u) => vec![Update::InlineQuery(InlineQuery {
query_id: u.query_id,
user_id: u.user_id,
query: u.query,
offset: u.offset,
peer: None,
})],
BotInlineSend(u) => vec![Update::InlineSend(InlineSend {
user_id: u.user_id,
query: u.query,
id: u.id,
msg_id: u.msg_id,
})],
UserStatus(u) => vec![Update::UserStatus(UserStatusUpdate {
user_id: u.user_id,
status: u.status,
})],
UserTyping(u) => vec![Update::UserTyping(ChatActionUpdate {
peer: tl::enums::Peer::User(tl::types::PeerUser { user_id: u.user_id }),
user_id: u.user_id,
action: u.action,
})],
ChatUserTyping(u) => vec![Update::UserTyping(ChatActionUpdate {
peer: tl::enums::Peer::Chat(tl::types::PeerChat { chat_id: u.chat_id }),
user_id: match u.from_id {
tl::enums::Peer::User(ref p) => p.user_id,
tl::enums::Peer::Chat(ref p) => p.chat_id,
tl::enums::Peer::Channel(ref p) => p.channel_id,
},
action: u.action,
})],
ChannelUserTyping(u) => vec![Update::UserTyping(ChatActionUpdate {
peer: tl::enums::Peer::Channel(tl::types::PeerChannel {
channel_id: u.channel_id,
}),
user_id: match u.from_id {
tl::enums::Peer::User(ref p) => p.user_id,
tl::enums::Peer::Chat(ref p) => p.chat_id,
tl::enums::Peer::Channel(ref p) => p.channel_id,
},
action: u.action,
})],
other => {
let cid = tl_constructor_id(&other);
vec![Update::Raw(RawUpdate {
constructor_id: cid,
})]
}
}
}
fn tl_constructor_id(upd: &tl::enums::Update) -> u32 {
use tl::enums::Update::*;
match upd {
AttachMenuBots => 0x17b7a20b,
AutoSaveSettings => 0xec05b097,
BotBusinessConnect(_) => 0x8ae5c97a,
BotCallbackQuery(_) => 0xb9cfc48d,
BotChatBoost(_) => 0x904dd49c,
BotChatInviteRequester(_) => 0x11dfa986,
BotCommands(_) => 0x4d712f2e,
BotDeleteBusinessMessage(_) => 0xa02a982e,
BotEditBusinessMessage(_) => 0x7df587c,
BotInlineQuery(_) => 0x496f379c,
BotInlineSend(_) => 0x12f12a07,
BotMenuButton(_) => 0x14b85813,
BotMessageReaction(_) => 0xac21d3ce,
BotMessageReactions(_) => 0x9cb7759,
BotNewBusinessMessage(_) => 0x9ddb347c,
BotPrecheckoutQuery(_) => 0x8caa9a96,
BotPurchasedPaidMedia(_) => 0x283bd312,
BotShippingQuery(_) => 0xb5aefd7d,
BotStopped(_) => 0xc4870a49,
BotWebhookJson(_) => 0x8317c0c3,
BotWebhookJsonquery(_) => 0x9b9240a6,
BusinessBotCallbackQuery(_) => 0x1ea2fda7,
Channel(_) => 0x635b4c09,
ChannelAvailableMessages(_) => 0xb23fc698,
ChannelMessageForwards(_) => 0xd29a27f4,
ChannelMessageViews(_) => 0xf226ac08,
ChannelParticipant(_) => 0x985d3abb,
ChannelReadMessagesContents(_) => 0x25f324f7,
ChannelTooLong(_) => 0x108d941f,
ChannelUserTyping(_) => 0x8c88c923,
ChannelViewForumAsMessages(_) => 0x7b68920,
ChannelWebPage(_) => 0x2f2ba99f,
Chat(_) => 0xf89a6a4e,
ChatDefaultBannedRights(_) => 0x54c01850,
ChatParticipant(_) => 0xd087663a,
ChatParticipantAdd(_) => 0x3dda5451,
ChatParticipantAdmin(_) => 0xd7ca61a2,
ChatParticipantDelete(_) => 0xe32f3d77,
ChatParticipants(_) => 0x7761198,
ChatUserTyping(_) => 0x83487af0,
Config => 0xa229dd06,
ContactsReset => 0x7084a7be,
DcOptions(_) => 0x8e5e9873,
DeleteChannelMessages(_) => 0xc32d5b12,
DeleteGroupCallMessages(_) => 0x3e85e92c,
DeleteMessages(_) => 0xa20db0e5,
DeleteQuickReply(_) => 0x53e6f1ec,
DeleteQuickReplyMessages(_) => 0x566fe7cd,
DeleteScheduledMessages(_) => 0xf2a71983,
DialogFilter(_) => 0x26ffde7d,
DialogFilterOrder(_) => 0xa5d72105,
DialogFilters => 0x3504914f,
DialogPinned(_) => 0x6e6fe51c,
DialogUnreadMark(_) => 0xb658f23e,
DraftMessage(_) => 0xedfc111e,
EditChannelMessage(_) => 0x1b3f4df7,
EditMessage(_) => 0xe40370a3,
EmojiGameInfo(_) => 0xfb9c547a,
EncryptedChatTyping(_) => 0x1710f156,
EncryptedMessagesRead(_) => 0x38fe25b7,
Encryption(_) => 0xb4a2e88d,
FavedStickers => 0xe511996d,
FolderPeers(_) => 0x19360dc0,
GeoLiveViewed(_) => 0x871fb939,
GroupCall(_) => 0x9d2216e0,
GroupCallChainBlocks(_) => 0xa477288f,
GroupCallConnection(_) => 0xb783982,
GroupCallEncryptedMessage(_) => 0xc957a766,
GroupCallMessage(_) => 0xd8326f0d,
GroupCallParticipants(_) => 0xf2ebdb4e,
InlineBotCallbackQuery(_) => 0x691e9052,
LangPack(_) => 0x56022f4d,
LangPackTooLong(_) => 0x46560264,
LoginToken => 0x564fe691,
MessageExtendedMedia(_) => 0xd5a41724,
MessageId(_) => 0x4e90bfd6,
MessagePoll(_) => 0xaca1657b,
MessagePollVote(_) => 0x24f40e77,
MessageReactions(_) => 0x1e297bfa,
MonoForumNoPaidException(_) => 0x9f812b08,
MoveStickerSetToTop(_) => 0x86fccf85,
NewAuthorization(_) => 0x8951abef,
NewChannelMessage(_) => 0x62ba04d9,
NewEncryptedMessage(_) => 0x12bcbd9a,
NewMessage(_) => 0x1f2b0afd,
NewQuickReply(_) => 0xf53da717,
NewScheduledMessage(_) => 0x39a51dfb,
NewStickerSet(_) => 0x688a30aa,
NewStoryReaction(_) => 0x1824e40b,
NotifySettings(_) => 0xbec268ef,
PaidReactionPrivacy(_) => 0x8b725fce,
PeerBlocked(_) => 0xebe07752,
PeerHistoryTtl(_) => 0xbb9bb9a5,
PeerLocated(_) => 0xb4afcfb0,
PeerSettings(_) => 0x6a7e7366,
PeerWallpaper(_) => 0xae3f101d,
PendingJoinRequests(_) => 0x7063c3db,
PhoneCall(_) => 0xab0f6b1e,
PhoneCallSignalingData(_) => 0x2661bf09,
PinnedChannelMessages(_) => 0x5bb98608,
PinnedDialogs(_) => 0xfa0f3ca2,
PinnedForumTopic(_) => 0x683b2c52,
PinnedForumTopics(_) => 0xdef143d0,
PinnedMessages(_) => 0xed85eab5,
PinnedSavedDialogs(_) => 0x686c85a6,
Privacy(_) => 0xee3b272a,
PtsChanged => 0x3354678f,
QuickReplies(_) => 0xf9470ab2,
QuickReplyMessage(_) => 0x3e050d0f,
ReadChannelDiscussionInbox(_) => 0xd6b19546,
ReadChannelDiscussionOutbox(_) => 0x695c9e7c,
ReadChannelInbox(_) => 0x922e6e10,
ReadChannelOutbox(_) => 0xb75f99a9,
ReadFeaturedEmojiStickers => 0xfb4c496c,
ReadFeaturedStickers => 0x571d2742,
ReadHistoryInbox(_) => 0x9e84bc99,
ReadHistoryOutbox(_) => 0x2f2f21bf,
ReadMessagesContents(_) => 0xf8227181,
ReadMonoForumInbox(_) => 0x77b0e372,
ReadMonoForumOutbox(_) => 0xa4a79376,
ReadStories(_) => 0xf74e932b,
RecentEmojiStatuses => 0x30f443db,
RecentReactions => 0x6f7863f4,
RecentStickers => 0x9a422c20,
SavedDialogPinned(_) => 0xaeaf9e74,
SavedGifs => 0x9375341e,
SavedReactionTags => 0x39c67432,
SavedRingtones => 0x74d8be99,
SentPhoneCode(_) => 0x504aa18f,
SentStoryReaction(_) => 0x7d627683,
ServiceNotification(_) => 0xebe46819,
SmsJob(_) => 0xf16269d4,
StarGiftAuctionState(_) => 0x48e246c2,
StarGiftAuctionUserState(_) => 0xdc58f31e,
StarGiftCraftFail => 0xac072444,
StarsBalance(_) => 0x4e80a379,
StarsRevenueStatus(_) => 0xa584b019,
StickerSets(_) => 0x31c24808,
StickerSetsOrder(_) => 0xbb2d201,
StoriesStealthMode(_) => 0x2c084dc1,
Story(_) => 0x75b3b798,
StoryId(_) => 0x1bf335b9,
Theme(_) => 0x8216fba3,
TranscribedAudio(_) => 0x84cd5a,
User(_) => 0x20529438,
UserEmojiStatus(_) => 0x28373599,
UserName(_) => 0xa7848924,
UserPhone(_) => 0x5492a13,
UserStatus(_) => 0xe5bdf8de,
UserTyping(_) => 0x2a17bf5c,
WebPage(_) => 0x7f891213,
WebViewResultSent(_) => 0x1592b79d,
ChatParticipantRank(_) => 0xbd8367b9,
ManagedBot(_) => 0x4880ed9a,
}
}
pub(crate) fn make_short_dm(m: tl::types::UpdateShortMessage) -> IncomingMessage {
let msg = tl::types::Message {
out: m.out,
mentioned: m.mentioned,
media_unread: m.media_unread,
silent: m.silent,
post: false,
from_scheduled: false,
legacy: false,
edit_hide: false,
pinned: false,
noforwards: false,
invert_media: false,
offline: false,
video_processing_pending: false,
id: m.id,
from_id: Some(tl::enums::Peer::User(tl::types::PeerUser {
user_id: m.user_id,
})),
peer_id: tl::enums::Peer::User(tl::types::PeerUser { user_id: m.user_id }),
saved_peer_id: None,
fwd_from: m.fwd_from,
via_bot_id: m.via_bot_id,
via_business_bot_id: None,
reply_to: m.reply_to,
date: m.date,
message: m.message,
media: None,
reply_markup: None,
entities: m.entities,
views: None,
forwards: None,
replies: None,
edit_date: None,
post_author: None,
grouped_id: None,
reactions: None,
restriction_reason: None,
ttl_period: None,
quick_reply_shortcut_id: None,
effect: None,
factcheck: None,
report_delivery_until_date: None,
paid_message_stars: None,
suggested_post: None,
from_rank: None,
from_boosts_applied: None,
paid_suggested_post_stars: false,
paid_suggested_post_ton: false,
schedule_repeat_period: None,
summary_from_language: None,
};
IncomingMessage {
raw: tl::enums::Message::Message(msg),
client: None,
}
}
pub(crate) fn make_short_chat(m: tl::types::UpdateShortChatMessage) -> IncomingMessage {
let msg = tl::types::Message {
out: m.out,
mentioned: m.mentioned,
media_unread: m.media_unread,
silent: m.silent,
post: false,
from_scheduled: false,
legacy: false,
edit_hide: false,
pinned: false,
noforwards: false,
invert_media: false,
offline: false,
video_processing_pending: false,
id: m.id,
from_id: Some(tl::enums::Peer::User(tl::types::PeerUser {
user_id: m.from_id,
})),
peer_id: tl::enums::Peer::Chat(tl::types::PeerChat { chat_id: m.chat_id }),
saved_peer_id: None,
fwd_from: m.fwd_from,
via_bot_id: m.via_bot_id,
via_business_bot_id: None,
reply_to: m.reply_to,
date: m.date,
message: m.message,
media: None,
reply_markup: None,
entities: m.entities,
views: None,
forwards: None,
replies: None,
edit_date: None,
post_author: None,
grouped_id: None,
reactions: None,
restriction_reason: None,
ttl_period: None,
quick_reply_shortcut_id: None,
effect: None,
factcheck: None,
report_delivery_until_date: None,
paid_message_stars: None,
suggested_post: None,
from_rank: None,
from_boosts_applied: None,
paid_suggested_post_stars: false,
paid_suggested_post_ton: false,
schedule_repeat_period: None,
summary_from_language: None,
};
IncomingMessage {
raw: tl::enums::Message::Message(msg),
client: None,
}
}