How I “try|tried” in Rust
![This is how Chat GPT would represent a human if it were the Rust language This is how Chat GPT would represent a human if it were the Rust language](https://habrastorage.org/getpro/habr/upload_files/3ed/147/b09/3ed147b0920af76193a6393f205e017a.png)
I am the CEO of my company MediaRise (the company has just started to develop), with a technical background. I like to write in different languages, or rather try to work with them. I have long heard about such a language as Rust.
Rust is a modern systems programming language designed for high performance and safety, especially when working with concurrent processes. Originally developed by Mozilla and now maintained by the Rust Foundation, Rust is gaining popularity due to its reliability and efficiency.
Key features of Rust:
Key features of Rust:
Memory safety: Rust eliminates common programming errors such as null pointer dereferences and buffer overflows through strict compile-time checking, without relying on the garbage collector.
Ownership system: Rust's unique ownership system provides memory safety without the need for a garbage collector. It uses an ownership system with rules that are checked by the compiler at compile time.
Competitiveness: Rust makes it easier to write concurrent programs by preventing race conditions at compile time through the concepts of ownership and borrowing.
Performance: Rust was designed to be as fast as C++, and often achieves comparable performance. It can be used for systems programming where performance is critical.
Expressive typical system: Rust has a powerful type system, including features like pattern matching, algebraic data types, and trait-based generics, allowing you to write more expressive and safe code.
Cargo: Rust comes with Cargo, a build system and package manager that makes it easy to manage dependencies, build, and distribute code.
Ecosystem: The Rust ecosystem includes a growing collection of libraries and tools that help developers write reliable and efficient code. The official package registry, crates.io, contains thousands of open-source libraries.
Areas of application of Rust:
System Programming: Rust is ideal for writing operating systems, device drivers, and other low-level tasks where control over hardware and performance are critical.
WebAssembly: Rust can compile to WebAssembly, allowing Rust code to run in web browsers with near-native performance.
Network programming: Rust's security features and performance make it suitable for writing network software, including web servers and clients.
Game development: Rust's performance characteristics make it a good choice for game development where speed and efficiency are critical.
Command utilities: The Cargo package manager makes it easy to create and distribute command-line utilities.
Notable projects using Rust:
Firefox Quantum: Mozilla used Rust to rewrite parts of their browser engine, resulting in significant performance improvements.
Dropbox: Dropbox uses Rust for some of its server services.
Cloudflare: Cloudflare uses Rust for several of its performance-critical services.
Rustlings: An educational project that helps you learn Rust through small exercises.
The combination of safety, performance, and concurrency support makes Rust an attractive choice for many types of software development. Its growing popularity and active community ensure that Rust will continue to evolve and improve.
I was thinking about an idea of what to implement in this language. Since I have a friend Thai, there are problems when communicating in messengers, I wanted to write a telegram bot that would bidirectionally translate from Russian to Thai and vice versa in the group chat.
I understand that there are ready-made solutions, but I wanted to create my own bike, try out the new Rust language.
There is an idea, there is no problem with the telegram bot, but there is a problem with the service that will translate from one language to another. The choice fell on LibreTranslate. To use it for free, you need to deploy the application on your server. I did it, installed the dependencies, deployed it in a Docker container. There were no problems. The only thing is that the application needs to be run with the flag: ./run.sh –api-keys, in order to get the api_key. You can read more about setting up and getting the LiberTranslate api-key on the official website
Having deployed the LiberTranslate server and received the telegram bot token, it remains to implement the application. Having reviewed the official documentation on Rust and the developments on github, I began to create. I installed rust and corgo (registry (manager) of packages for Rust). Having studied the documentation of the teloxide library for the telegram bot written in rust, I wrote a handler for message events in the chat.
#[tokio::main]
async fn main() -> ResponseResult<()> {
dotenv().ok();
env_logger::init();
let token_bot = env::var("TELEGRAM_BOT_KEY").expect("TELEGRAM_BOT_KEY not found");
let bot = teloxide::Bot::new(&token_bot).parse_mode(ParseMode::Html);
// Create a handler for our bot, that will process updates from Telegram
let handler = dptree::entry()
.inspect(|u: Update| {
eprintln!("{u:#?}"); // Print the update to the console with inspect
})
...
.branch(
Update::filter_message()
.branch(
dptree::endpoint(translate_message),
)
);
// Create a dispatcher for our bot
Dispatcher::builder(bot, handler).enable_ctrlc_handler().build().dispatch().await;
Ok(())
}
async fn translate_message(bot: Bot, msg: Message) -> ResponseResult<()> {
if let Some(text) = msg.text() {
match translate(text).await {
Ok(translated_word) => {
bot.send_message(msg.chat.id, translated_word).await?;
}
Err(e) => {
bot.send_message(msg.chat.id, format!("Translation error: {}", e)).await?;
}
}
} else {
bot.send_message(msg.chat.id, "Send me plain text.").await?;
}
Ok(())
}
Next, the function itself for requesting a translation from the LiberTranslate application. The gist is this: the translation application determines what language the message is in and translates it into the required language (ru -> th, th -> ru)
async fn translate(text: &str) -> ResponseResult<String> {
let client = reqwest::Client::new();
let api_translate_url = env::var("API_TRANSLATE_URL").expect("API_TRANSLATE_URL not found");
let api_translate_key = env::var("API_TRANSLATE_KEY").expect("API_TRANSLATE_KEY not found");
let api_detect_url = env::var("API_DETECT_URL").expect("API_DETECT_URL not found");
eprintln!("{text:#?}");
let detect_request = DetectRequest {
q: String::from(text),
api_key: String::from(api_translate_key.clone()),
};
let res = client.post(api_detect_url)
.header("Content-Type", "application/x-www-form-urlencoded")
.form(&detect_request)
.send()
.await?;
let resp_json = res.json::<Vec<DetectResponse>>().await?;
let lang = &resp_json[0].language;
eprintln!("{lang:#?}");
let target_lang = if lang == "ru" { "th" } else { "ru" };
let json_object = json!({
"q": text,
"source": "auto",
"target": target_lang,
"format": "text",
"alternatives": 3,
"api_key": api_translate_key
});
let json_string = serde_json::to_string(&json_object).unwrap();
let res = client.post(api_translate_url)
.body(json_string)
.header("Content-Type", "application/json")
.send()
.await?;
let resp_json = res.json::<TranslateResult>().await?;
let translated_word = resp_json.translatedText;
Ok(translated_word)
}
Here is the result in the Telegram chat itself
![Image from chat Image from chat](https://habrastorage.org/getpro/habr/upload_files/d98/e92/6fa/d98e926fa3c9f7587e741585944eba7f.jpg)
There were problems with bugs, which were due to the fact that I used old libraries in Rust, when I tried to solve the problem with ChatGPT. But the live experience of developers from GitHub helped more, where I looked at the implementation of some functionality: API documentation of the bot, working with env (environment files), examples of working with json, sending rest requests and also the work of the language structure.
I am very happy with the working application, because I have not written in Rust before and it inspired me to study it further. Experienced developers will certainly tell me how to optimize the code, which I will be very happy about.
All that remains is to build the application and run it in daemon mode on the server
Setting up systemd
Build your application using the command:
cargo build --release
Create a unit file for systemd
. For example, let's create a file /etc/systemd/system/translate_bot.service
[Unit]
Description=Translate Bot
After=network.target
[Service]
ExecStart=/path/to/your/application
Restart=always
User=yourusername
Group=yourgroupname
Environment=/path/to/your/.env
WorkingDirectory=/path/to/your/application/directory
[Install]
WantedBy=multi-user.target
Reload the configuration systemd
so that he knows about the new service:
sudo systemctl daemon-reload
Start the service:
sudo systemctl start translate_bot
Make sure the service is up and running:
sudo systemctl status translate_bot
To make your service start automatically when the system starts, run the command:
sudo systemctl enable rust_service
Your Rust application will run as a system service, managed by systemd
. You can control it using standard commands. systemd
such as start
, stop
, restart
And status
.
PS I would also like to solve the problem with env files so that they can be accessed in the function from main.
Next in the plans: I would like to implement event handling if a new user appears in the chat (as well as a live chat). The user can choose the language in which he would like to receive the translation. The users themselves and their settings will be stored in the PostgreSQL database
Thank you all for your attention! I have posted the source code on GitHub.