From a56bb8965dda63948188c661be38fe4c089410b1 Mon Sep 17 00:00:00 2001 From: Felix Date: Fri, 4 Jun 2021 22:09:08 +0200 Subject: [PATCH] Publish as lib and add channels --- Cargo.toml | 7 ++-- Dockerfile | 6 +-- README.md | 2 +- src/forward_stdin.rs | 40 ------------------- src/lib.rs | 85 +++++++++++++++++++++++++++++++++++++++ src/main.rs | 41 ++++++++++--------- src/telegram.rs | 94 +++++++++++++++++++++----------------------- 7 files changed, 161 insertions(+), 114 deletions(-) delete mode 100644 src/forward_stdin.rs create mode 100644 src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 9627a3b..2a7792e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] -name = "telegram-tracker" -version = "0.1.5" +name = "telegram_tracker" +version = "0.1.6" authors = ["Felix "] readme = "README.md" edition = "2018" @@ -15,4 +15,5 @@ colored = "1.9" regex = "1" clap = "3.0.0-beta.2" chrono = "0.4" -futures = "0.3" \ No newline at end of file +futures = "0.3" +#tokio = { version = "1.5.0", features = ["full"] } \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 8116ebc..b2fd385 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,7 +16,7 @@ RUN cmake cmake --install . -FROM rust as telegram-tracker-builder +FROM rust as telegram_tracker-builder WORKDIR app # Build dependencies COPY Cargo.toml /app/Cargo.toml @@ -34,7 +34,7 @@ FROM debian:9 as runtime WORKDIR app RUN apt -y update && apt install -y g++ ccache openssl && rm -rf /var/lib/apt/lists/* ENV LD_LIBRARY_PATH="/app/:${LD_LIBRARY_PATH}" -COPY --from=telegram-tracker-builder /app/target/release/telegram-tracker /app +COPY --from=telegram_tracker-builder /app/target/release/telegram_tracker /app COPY --from=tdlib-builder /td/build/libtd* /app -ENTRYPOINT ["/app/telegram-tracker"] \ No newline at end of file +ENTRYPOINT ["/app/telegram_tracker"] \ No newline at end of file diff --git a/README.md b/README.md index 693e6ac..31d2619 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ LD_LIBRARY_PATH=lib cargo build --release ``` * Build with Docker -```docker build -t telegram-tracker:0.1.5 .``` +```docker build -t telegram_tracker:0.1.6 .``` ## Run ``` diff --git a/src/forward_stdin.rs b/src/forward_stdin.rs deleted file mode 100644 index 0483bec..0000000 --- a/src/forward_stdin.rs +++ /dev/null @@ -1,40 +0,0 @@ -use std::io::{self, BufRead}; - -use futures::executor::block_on; -use log::info; -use rtdlib::types::*; -//use rtdlib::*; -use telegram_client::api::aasync::AsyncApi; -use telegram_client::api::Api; - -const TELEGRAM_START_MSG: &str = "TELEGRAM BOT<<<"; -/// Read stdin and forward to channel -pub fn forward_stdin_to_channel_id(api: Api, chat_id: i64) { - info!("Listening stdin to forward to channel... {}", chat_id); - let api = AsyncApi::new(api); - let stdin = io::stdin(); - - for line in stdin.lock().lines() { - let msg_to_send = line.unwrap().trim().to_owned(); - if msg_to_send.starts_with(TELEGRAM_START_MSG) { - let msg_to_send = msg_to_send.replace(TELEGRAM_START_MSG, ""); - let result = block_on(send_msg(&api, chat_id, msg_to_send)); - } - } -} - -async fn send_msg(api: &AsyncApi, chat_id: i64, msg_to_send: String) { - let msg_content = InputMessageContent::InputMessageText( - InputMessageText::builder() - .text(FormattedText::builder().text(msg_to_send).build()) - .clear_draft(true) - .build(), - ); - - let msg: SendMessage = SendMessage::builder() - .chat_id(chat_id) - .input_message_content(msg_content) - .build(); - - api.send_message(msg).await.unwrap(); -} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..9c6db6e --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,85 @@ +use std::sync::mpsc::SyncSender; + +use chrono::{DateTime, Utc}; +use log::{debug, error, info}; +use rtdlib::types::{FormattedText, InputMessageContent, SendMessage}; +use rtdlib::types::InputMessageText; +use telegram_client::api::Api; + +mod telegram; +mod tgfn; +mod thelp; + +pub fn test(s: String) { + println!("test {}", s); +} + +#[derive(Debug, Clone)] +pub struct TelegramMessage { + pub event_info: String, + pub msg_text: String, + pub chat_id: i64, + pub message_id: i64, + pub sender_id: i64, + pub sent_datetime: DateTime, +} + +impl TelegramMessage { + pub fn msg_lower_case(&self) -> String { + self.msg_text.to_lowercase() + } +} +#[derive(Debug, Clone)] +pub struct TelegramConfig { + pub phone: String, + pub telegram_api_id: String, + pub telegram_api_hash: String, + pub print_outgoing: bool, + pub follow_channel: Option, + pub send_notifications_to_channel: Option, +} + +pub struct TelegramTrackerClient { + api: Api, + config: TelegramConfig, +} + +impl TelegramTrackerClient { + pub fn new( + config: TelegramConfig, + sender: SyncSender, + ) -> TelegramTrackerClient { + let api = telegram::start( + config.phone.to_owned(), + config.telegram_api_id.to_owned(), + config.telegram_api_hash.to_owned(), + config.print_outgoing.to_owned(), + config.follow_channel.to_owned(), + sender, + ); + TelegramTrackerClient { api, config } + } + + pub fn send(&self, msg_to_send: &String) { + info!("SENDING >> 💬 {}", msg_to_send); + if let Some(chanel_id) = self.config.send_notifications_to_channel { + let msg_content = InputMessageContent::InputMessageText( + InputMessageText::builder() + .text(FormattedText::builder().text(msg_to_send).build()) + .clear_draft(true) + .build(), + ); + + let msg: SendMessage = SendMessage::builder() + .chat_id(chanel_id) + .input_message_content(msg_content) + .build(); + + + match self.api.send(msg) { + Ok(ok) => debug!("Message forwarded to Telegram {:?}: {} {}", ok,chanel_id, msg_to_send), + Err(err) => error!("Unable forward to Telegram {:?} ", err), + }; + } + } +} diff --git a/src/main.rs b/src/main.rs index 9cfe28d..732fa18 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,16 @@ use clap::{AppSettings, Clap}; use log::LevelFilter; use simple_logger::SimpleLogger; -use std::thread; -mod forward_stdin; +use std::sync::mpsc::sync_channel; +use telegram_tracker::TelegramMessage; + mod telegram; mod tgfn; mod thelp; #[derive(Clap)] #[clap( - version = "0.1.5", + version = "0.1.6", author = "Felix G. Borrego " )] #[clap(setting = AppSettings::ColoredHelp)] @@ -24,8 +25,6 @@ struct Opts { print_outgoing: String, #[clap(long)] follow_channel_id: Option, - #[clap(long)] - forward_stdin_to_channel_id: Option, } fn main() { @@ -34,7 +33,7 @@ fn main() { let opts: Opts = Opts::parse(); SimpleLogger::new() - .with_level(LevelFilter::Info) + .with_level(LevelFilter::Debug) .with_module_level("telegram_client::api", LevelFilter::Info) .with_module_level("telegram_client::handler", LevelFilter::Off) .init() @@ -45,11 +44,6 @@ fn main() { .parse::() .expect("Expected a valid chat_id") }); - let forward_channel_id = opts.forward_stdin_to_channel_id.map(|id| { - format!("-100{}", id) - .parse::() - .expect("Expected a valid chat_id") - }); if let Some(id) = channel_id { println!( @@ -63,19 +57,30 @@ fn main() { ); } - let api = telegram::start( + let (message_sender, message_receiver) = sync_channel(10); + let _ = telegram::start( opts.phone, opts.telegram_api_id, opts.telegram_api_hash, opts.print_outgoing.parse().expect("It must be a bool"), channel_id, + message_sender, ); - if let Some(channel_id) = forward_channel_id { - println!("Stdin to Telegram channel {} is ENABLED", channel_id); - forward_stdin::forward_stdin_to_channel_id(api, channel_id); - } else { - println!("Stdin to Telegram is disabled."); - thread::park(); + println!("Stdin to Telegram is disabled."); + for message in message_receiver { + on_new_message_in_room(message); } } + +fn on_new_message_in_room(message: TelegramMessage) { + println!( + "### chat: {};sender_id: {};message_id: {};time: {:?};event_info: {}; msg:==> {}", + message.chat_id, + message.sender_id, + message.message_id, + message.sent_datetime.to_rfc3339(), + message.event_info, + message.msg_text + ); +} diff --git a/src/telegram.rs b/src/telegram.rs index beece25..9f658c6 100644 --- a/src/telegram.rs +++ b/src/telegram.rs @@ -2,7 +2,7 @@ use std::fs::File; use std::thread; use chrono; -use chrono::Local; +use chrono::{DateTime, NaiveDateTime, Utc}; use colored::Colorize; use log::{debug, error, info, warn}; use rtdlib::types::MessageContent::*; @@ -11,9 +11,15 @@ use telegram_client::api::aevent::EventApi; use telegram_client::api::Api; use telegram_client::client::Client; -use crate::{tgfn, thelp}; +use crate::{tgfn, thelp, TelegramMessage}; +use std::sync::mpsc::SyncSender; -fn on_new_message(event_info: String, message: &Message, only_channel_id: &Option) { +fn on_new_message( + event_info: String, + message: &Message, + only_channel_id: &Option, + message_sender: SyncSender, +) { if message.is_outgoing() { debug!("Ignoring outgoing message "); } @@ -34,59 +40,50 @@ fn on_new_message(event_info: String, message: &Message, only_channel_id: &Optio msg_text.push_str(doc.caption().text()); } - if *only_channel_id == Some(message.chat_id()) { - on_new_message_in_room( + let msg_text = str::replace(&*msg_text, "\n", "; "); // one msg per line + + let naive = NaiveDateTime::from_timestamp(message.date(), 0); + + // Create a normal DateTime from the NaiveDateTime + let sent_datetime: DateTime = DateTime::from_utc(naive, Utc); + + let sender_id = match message.sender() { + MessageSender::_Default(_) => -1, + MessageSender::Chat(c) => c.chat_id(), + MessageSender::User(u) => u.user_id(), + }; + + if *only_channel_id == Some(message.chat_id()) || only_channel_id.is_none() { + let msg = TelegramMessage { event_info, - &msg_text, - message.chat_id(), - message.id(), - message.sender(), - ); + msg_text, + chat_id: message.chat_id(), + message_id: message.id(), + sender_id, + sent_datetime, + }; + message_sender.send(msg).unwrap(); } else { info!( "Ignoring message chat: {}; message_id: {}, time:{:?}; event_info: {}, msg: {}", message.chat_id(), message.id(), - Local::now().to_rfc3339(), + sent_datetime, event_info, &msg_text ); } } -fn on_new_message_in_room( - event_info: String, - msg: &String, - chat_id: i64, - message_id: i64, - sender: &MessageSender, -) { - let sender_id = match sender { - MessageSender::_Default(d) => -1, - MessageSender::Chat(c) => c.chat_id(), - MessageSender::User(u) => u.user_id(), - }; - - let line_msg = str::replace(msg, "\n", "; "); - println!( - "### chat: {};sender_id: {};message_id: {};time: {:?};event_info: {}; msg:==> {}", - chat_id, - sender_id, - message_id, - Local::now().to_rfc3339(), - event_info, - line_msg - ); -} - pub fn start( phone: String, telegram_api_id: String, telegram_api_hash: String, print_outgoing: bool, follow_channel: Option, + message_sender: SyncSender, ) -> Api { - let (mut client, api) = config(); + let (client, api) = config(); thread::spawn(move || { start_telegram_tracking( client, @@ -95,6 +92,7 @@ pub fn start( telegram_api_hash, print_outgoing, follow_channel, + message_sender.clone(), ); }); api @@ -107,8 +105,10 @@ fn start_telegram_tracking( telegram_api_hash: String, print_outgoing: bool, follow_channel: Option, + message_sender: SyncSender, ) { let listener = client.listener(); + let data_directory = format!("telegram_data-{}", follow_channel.unwrap_or(0)); listener.on_update_authorization_state(move |(api, update)| { let state = update.authorization_state(); @@ -116,7 +116,7 @@ fn start_telegram_tracking( api.set_tdlib_parameters(SetTdlibParameters::builder().parameters( TdlibParameters::builder() .use_test_dc(false) - .database_directory("telegram_data") + .database_directory(&data_directory) .use_message_database(false) .use_secret_chats(true) .api_id(toolkit::number::as_i64(&telegram_api_id).unwrap()) @@ -127,7 +127,7 @@ fn start_telegram_tracking( .application_version(env!("CARGO_PKG_VERSION")) .enable_storage_optimizer(false) .use_chat_info_database(false) - .files_directory("telegram_data/files") + .files_directory(format!("{}/files", &data_directory)) .build() ).build()).unwrap(); debug!("Set tdlib parameters"); @@ -235,7 +235,7 @@ fn start_telegram_tracking( }); listener.on_ok(|_| { - debug!("OK"); + //debug!("OK"); Ok(()) }); @@ -283,17 +283,12 @@ fn start_telegram_tracking( "on_update_new_message".to_string(), message, &follow_channel, + message_sender.clone(), ); Ok(()) }); - listener.on_update_chat_last_message(move |(_, _)| { - // update already sending with on_update_new_message - // .last_message() - // .clone() - // .map(|v| on_new_message("on_update_chat_last_message".to_string(), &v, &follow_channel)); - Ok(()) - }); + listener.on_update_chat_last_message(move |(_, _)| Ok(())); listener.on_update_have_pending_notifications(|(_, _)| Ok(())); @@ -310,13 +305,14 @@ fn start_telegram_tracking( fn open_channel(follow_channel: &Option, api: &EventApi) { if let Some(channel_id) = &follow_channel { - info!("📡 Opening channel to follow..."); + //info!("📡 Opening channel to follow..."); let option_value: OptionValueBoolean = OptionValueBoolean::builder().value(true).build(); api.set_option( SetOption::builder() .name("online") .value(OptionValue::Boolean(option_value)), - ); + ) + .unwrap(); let _ = api.open_chat(OpenChat::builder().chat_id(*channel_id).build()); }