One week ago, I saw a post on RustDesk subreddit, https://www.reddit.com/r/rustdesk/comments/1dk4mzp/how_can_i_be_notified_track_when_someone_connects/. It gave me hint to send the notification to Telegram bot, because I had been using it to receive news and signals while I traded FX before. This also inspired to me to receive OTP through Telegram bot.
So I started to ask Copilot.
- "Please write a function to send OTP to telegram bot"
async fn send_otp_to_telegram(bot_token: &str, chat_id: &str, otp: &str) -> Result<()> {
let client = Client::new();
let url = format!("https://api.telegram.org/bot{}/sendMessage", bot_token);
let payload = json!({
"chat_id": chat_id,
"text": otp
});
let response = client.post(&url)
.json(&payload)
.send()
.await?;
if response.status().is_success() {
Ok(())
} else {
Err(anyhow!("Failed to send OTP to Telegram: {}", response.status()))
}
}
- "Please write a function to send OTP to telegram bot, use reqwest"
use reqwest::Client;
use serde_json::json;
use std::error::Error;
async fn send_otp_to_telegram(otp: &str, bot_token: &str, chat_id: &str) -> Result<(), Box<dyn Error>> {
let client = Client::new();
let telegram_api_url = format!("https://api.telegram.org/bot{}/sendMessage", bot_token);
let message = format!("Your OTP is: {}", otp);
let response = client.post(&telegram_api_url)
.json(&json!({
"chat_id": chat_id,
"text": message,
}))
.send()
.await?;
if response.status().is_success() {
Ok(())
} else {
Err(Box::new(std::io::Error::new(std::io::ErrorKind::Other, "Failed to send OTP")))
}
}
- "How can I get telegram bot chat id with reqwest?"
async fn fetch_telegram_chat_id(bot_token: &str) -> Result<Vec<i64>, Box<dyn Error>> {
let client = Client::new();
let url = format!("https://api.telegram.org/bot{}/getUpdates", bot_token);
let res = client.get(&url).send().await?;
let body = res.text().await?;
let json: Value = serde_json::from_str(&body)?;
let mut chat_ids = Vec::new();
if let Some(updates) = json["result"].as_array() {
for update in updates {
if let Some(chat_id) = update["message"]["chat"]["id"].as_i64() {
chat_ids.push(chat_id);
}
}
}
Ok(chat_ids)
}
After some polish, I finished my job,
// https://gist.github.com/dideler/85de4d64f66c1966788c1b2304b9caf1
pub async fn send_2fa_code_to_telegram(text: &str, bot: TelegramBot) -> ResultType<()> {
let url = format!("https://api.telegram.org/bot{}/sendMessage", bot.token_str);
let params = serde_json::json!({"chat_id": bot.chat_id, "text": text});
crate::post_request(url, params.to_string(), "").await?;
Ok(())
}
pub fn get_chatid_telegram(bot_token: &str) -> ResultType> {
let url = format!("https://api.telegram.org/bot{}/getUpdates", bot_token);
// because caller is in tokio runtime, so we must call post_request_sync in new thread.
let handle = std:๐งต:spawn(move || {
crate::post_request_sync(url, "".to_owned(), "")
});
let resp = handle.join().map_err(|_| anyhow!("Thread panicked"))??;
let value = serde_json::from_str::(&resp).map_err(|e| anyhow!(e))?;
// Check for an error_code in the response
if let Some(error_code) = value.get("error_code").and_then(|code| code.as_i64()) {
// If there's an error_code, try to use the description for the error message
let description = value["description"]
.as_str()
.unwrap_or("Unknown error occurred");
return Err(anyhow!(
"Telegram API error: {} (error_code: {})",
description,
error_code
));
}
let chat_id = &value["result"][0]["message"]["chat"]["id"];
let chat_id = if let Some(id) = chat_id.as_i64() {
Some(id.to_string())
} else if let Some(id) = chat_id.as_str() {
Some(id.to_owned())
} else {
None
};
if let Some(chat_id) = chat_id.as_ref() {
let bot = TelegramBot {
token_str: bot_token.to_owned(),
chat_id: chat_id.to_owned(),
..Default::default()
};
bot.save()?;
}
Ok(chat_id)
}
- Flutter UI
https://github.com/rustdesk/rustdesk/blob/a632718e80649f2be8a1a7cc1df20a6056b119b9/flutter/lib/common/widgets/dialog.dart#L1769
void changeBot({Function()? callback}) async {
if (bind.mainHasValidBotSync()) {
await bind.mainSetOption(key: "bot", value: "");
callback?.call();
return;
}
String errorText = '';
bool loading = false;
final controller = TextEditingController();
gFFI.dialogManager.show((setState, close, context) {
onVerify() async {
final token = controller.text.trim();
if (token == "") return;
loading = true;
errorText = '';
setState(() {});
final error = await bind.mainVerifyBot(token: token);
if (error == "") {
callback?.call();
close();
} else {
errorText = translate(error);
loading = false;
setState(() {});
}
}
final codeField = TextField(
autofocus: true,
controller: controller,
decoration: InputDecoration(
hintText: translate('Token'),
),
);
return CustomAlertDialog(
title: Text(translate("Telegram bot")),
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SelectableText(translate("enable-bot-desc"),
style: TextStyle(fontSize: 12))
.marginOnly(bottom: 12),
Row(children: [Expanded(child: codeField)]),
if (errorText != '')
Text(errorText, style: TextStyle(color: Colors.red))
.marginOnly(top: 12),
],
),
actions: [
dialogButton("Cancel", onPressed: close, isOutline: true),
loading
? CircularProgressIndicator()
: dialogButton("OK", onPressed: onVerify),
],
onCancel: close,
);
});
}
![The UI to set bot token and also get chat id implicitly](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/21d02vaxp6an9ojhumn5.png)
Thanks to Copilot.
Top comments (0)