126 lines
3.8 KiB
Rust
126 lines
3.8 KiB
Rust
|
use std::pin::Pin;
|
||
|
|
||
|
use futures::Future;
|
||
|
use telexide::{
|
||
|
api::types::SendMessage,
|
||
|
client::{self, ClientBuilder},
|
||
|
model::{self, MessageContent, MessageEntity, UpdateContent},
|
||
|
};
|
||
|
use typemap::Key;
|
||
|
|
||
|
use crate::browser::BrowserHandle;
|
||
|
|
||
|
pub struct BotDriver {
|
||
|
client: client::Client,
|
||
|
listen_user: String,
|
||
|
}
|
||
|
|
||
|
struct BotConfig {
|
||
|
handle: BrowserHandle,
|
||
|
listen_user: String,
|
||
|
}
|
||
|
struct BotConfigKey {}
|
||
|
impl Key for BotConfigKey {
|
||
|
type Value = BotConfig;
|
||
|
}
|
||
|
|
||
|
fn telegram_handler(
|
||
|
ctx: client::Context,
|
||
|
upd: model::Update,
|
||
|
) -> Pin<Box<dyn Future<Output = ()> + Send>> {
|
||
|
let config = if let Some(cfg) = ctx.data.read().get::<BotConfigKey>() {
|
||
|
BotConfig {
|
||
|
handle: cfg.handle.clone(),
|
||
|
listen_user: cfg.listen_user.clone(),
|
||
|
}
|
||
|
} else {
|
||
|
panic!("no config");
|
||
|
};
|
||
|
if let UpdateContent::Message(msg) = upd.content {
|
||
|
if let Some(user) = msg.from {
|
||
|
if let Some(name) = user.username {
|
||
|
if name.to_lowercase() == config.listen_user.to_lowercase() {
|
||
|
if let MessageContent::Text { content, entities } = msg.content {
|
||
|
if let Some(url_text) = get_url(content, entities) {
|
||
|
return Box::pin(async move {
|
||
|
match config.handle.go_to(url_text.as_str()).await {
|
||
|
Err(err) => {
|
||
|
println!("failed opening url [{}]: {}", url_text, err)
|
||
|
}
|
||
|
_ => {}
|
||
|
};
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
return Box::pin(async move {
|
||
|
match ctx
|
||
|
.api
|
||
|
.send_message(SendMessage::new(
|
||
|
msg.chat.get_id(),
|
||
|
"we don't listen to you",
|
||
|
))
|
||
|
.await
|
||
|
{
|
||
|
Err(err) => println!("failed writing not listening: {}", err),
|
||
|
_ => {}
|
||
|
};
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
Box::pin(async {})
|
||
|
}
|
||
|
|
||
|
impl BotDriver {
|
||
|
pub fn new(token: String, listen_user: String) -> Self {
|
||
|
Self {
|
||
|
client: ClientBuilder::new()
|
||
|
.set_token(&token)
|
||
|
.add_handler_func(telegram_handler)
|
||
|
.build(),
|
||
|
listen_user: listen_user,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub async fn listen_and_paste(&mut self, handle: BrowserHandle) -> Result<(), anyhow::Error> {
|
||
|
let listen_to = self.listen_user.clone();
|
||
|
let config = BotConfig {
|
||
|
handle: handle,
|
||
|
listen_user: listen_to,
|
||
|
};
|
||
|
// Scope it so it instantly drops. Might instantly drop anyway cause I don't use the result. Ah well.
|
||
|
{
|
||
|
self.client.data.write().insert::<BotConfigKey>(config);
|
||
|
}
|
||
|
self.client.start().await?;
|
||
|
println!("telegram bot finished early");
|
||
|
Ok(())
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn get_url(text: String, entities: Vec<MessageEntity>) -> Option<String> {
|
||
|
match entities
|
||
|
.into_iter()
|
||
|
.filter(|ent| match ent {
|
||
|
MessageEntity::Url(_) => true,
|
||
|
_ => false,
|
||
|
})
|
||
|
.take(1)
|
||
|
.collect::<Vec<MessageEntity>>()
|
||
|
.first()
|
||
|
{
|
||
|
Some(def) => match def {
|
||
|
MessageEntity::Url(url_def) => Some(
|
||
|
text.chars()
|
||
|
.skip(url_def.offset as usize)
|
||
|
.take(url_def.length as usize)
|
||
|
.collect(),
|
||
|
),
|
||
|
_ => None,
|
||
|
},
|
||
|
_ => None,
|
||
|
}
|
||
|
}
|