-
Notifications
You must be signed in to change notification settings - Fork 119
/
dialogs.rs
114 lines (97 loc) · 3.55 KB
/
dialogs.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//! Example to print the ID and title of all the dialogs.
//!
//! The `TG_ID` and `TG_HASH` environment variables must be set (learn how to do it for
//! [Windows](https://ss64.com/nt/set.html) or [Linux](https://ss64.com/bash/export.html))
//! to Telegram's API ID and API hash respectively.
//!
//! Then, run it as:
//!
//! ```sh
//! cargo run --example dialogs
//! ```
use futures::TryStreamExt;
use grammers_client::session::Session;
use grammers_client::{Client, Config, SignInError};
use simple_logger::SimpleLogger;
use std::env;
use std::io::{self, BufRead as _, Write as _};
use tokio::runtime;
type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
const SESSION_FILE: &str = "dialogs.session";
fn prompt(message: &str) -> Result<String> {
let stdout = io::stdout();
let mut stdout = stdout.lock();
stdout.write_all(message.as_bytes())?;
stdout.flush()?;
let stdin = io::stdin();
let mut stdin = stdin.lock();
let mut line = String::new();
stdin.read_line(&mut line)?;
Ok(line)
}
async fn async_main() -> Result<()> {
SimpleLogger::new()
.with_level(log::LevelFilter::Debug)
.init()
.unwrap();
let api_id = env!("TG_ID").parse().expect("TG_ID invalid");
let api_hash = env!("TG_HASH").to_string();
println!("Connecting to Telegram...");
let client = Client::connect(Config {
session: Session::load_file_or_create(SESSION_FILE)?,
api_id,
api_hash: api_hash.clone(),
params: Default::default(),
})
.await?;
println!("Connected!");
// If we can't save the session, sign out once we're done.
let mut sign_out = false;
if !client.is_authorized().await? {
println!("Signing in...");
let phone = prompt("Enter your phone number (international format): ")?;
let token = client.request_login_code(&phone).await?;
let code = prompt("Enter the code you received: ")?;
let signed_in = client.sign_in(&token, &code).await;
match signed_in {
Err(SignInError::PasswordRequired(password_token)) => {
// Note: this `prompt` method will echo the password in the console.
// Real code might want to use a better way to handle this.
let hint = password_token.hint().unwrap_or("None");
let prompt_message = format!("Enter the password (hint {}): ", &hint);
let password = prompt(prompt_message.as_str())?;
client
.check_password(password_token, password.trim())
.await?;
}
Ok(_) => (),
Err(e) => panic!("{}", e),
};
println!("Signed in!");
match client.session().save_to_file(SESSION_FILE) {
Ok(_) => {}
Err(e) => {
println!("NOTE: failed to save the session, will sign out when done: {e}");
sign_out = true;
}
}
}
let mut dialogs = client.stream_dialogs();
println!("Showing up to {} dialogs:", dialogs.total().await?);
while let Some(dialog) = dialogs.try_next().await? {
let chat = dialog.chat();
println!("- {: >10} {}", chat.id(), chat.name().unwrap_or_default());
}
if sign_out {
// TODO revisit examples and get rid of "handle references" (also, this panics)
drop(client.sign_out_disconnect().await);
}
Ok(())
}
fn main() -> Result<()> {
runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap()
.block_on(async_main())
}