I can’t fix the problem, the error still repeats itself, the suggested fixes by ChatGPT don’t help

My code:

use telebot::Bot;
use dotenv::dotenv;
use std::env;

use serde::Deserialize;
use reqwest::Error;

// import all available functions
use telebot::functions::*;
use futures::stream::Stream;

#[derive(Deserialize, Debug)]
struct ApiResponse {
    translated_text: String,
}

async fn translate(text: &str, api_translate_url: &str, api_translate_key: &str) -> Result<ApiResponse, Error> {
    let client = reqwest::Client::new();
    let response = client.post(api_translate_url)
        .header("Authorization", format!("Bearer {}", api_translate_key))
        .form(&[("text", text)])
        .send()
        .await?
        .json::<ApiResponse>()
        .await?;

    Ok(response)
}

#[tokio::main]
async fn main() {
    dotenv().ok();
    env_logger::init();

    let token_bot = env::var("TELEGRAM_BOT_KEY").expect("TELEGRAM_BOT_KEY not found");

    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");

    // Create the bot
    let mut bot = Bot::new(&token_bot).update_interval(200);

    // Register a reply command which answers a message
    let stream = bot.new_cmd("/reply")
        .for_each(move |(bot, msg)| {
            let text = msg.text.clone().unwrap_or_else(|| "<empty>".into());
            let api_translate_url = api_translate_url.clone();
            let api_translate_key = api_translate_key.clone();

            async move {
                bot.message(msg.chat.id, text.clone()).send().await.unwrap();
                match translate(&text, &api_translate_url, &api_translate_key).await {
                    Ok(response) => println!("{:#?}", response),
                    Err(err) => eprintln!("Translation error: {:?}", err),
                }
            }
        });

    bot.run_with(stream);
}

I'm puzzling over the problem, I don't understand in the end what needs to be fixed so that the asynchronous code would work, before that I wrote synchronous, it worked

Error listing:

   Compiling telegram_bot v0.1.0 (D:\workspace\rust\telegram_bot)
error[E0277]: `impl futures::Future<Item = (RequestHandle, telebot::objects::Message), Error = failure::error::Error> + '_` is not a future
  --> src/main.rs:51:63
   |
51 |                 bot.message(msg.chat.id, text.clone()).send().await.unwrap();
   |                                                              -^^^^^
   |                                                              ||
   |                                                              |`impl futures::Future<Item = (RequestHandle, telebot::objects::Message), Error = failure::error::Error> + '_` is not a future
   |                                                              help: remove the `.await`
   |
   = help: the trait `std::future::Future` is not implemented for `impl futures::Future<Item = (RequestHandle, telebot::objects::Message), Error = failure::error::Error> + '_`, which is required by `impl futures::Future<Item = (RequestHandle, telebot::objects::Message), Error = failure::error::Error> + '_: std::future::IntoFuture`
   = note: impl futures::Future<Item = (RequestHandle, telebot::objects::Message), Error = failure::error::Error> + '_ must be a future or must implement `IntoFuture` to be awaited
   = note: required for `impl futures::Future<Item = (RequestHandle, telebot::objects::Message), Error = failure::error::Error> + '_` to implement `std::future::IntoFuture`

error[E0277]: the trait bound `{async block@src/main.rs:50:13: 56:14}: futures::IntoFuture` is not satisfied
   --> src/main.rs:45:10
    |
45  |         .for_each(move |(bot, msg)| {
    |          ^^^^^^^^ the trait `futures::Future` is not implemented for `{async block@src/main.rs:50:13: 56:14}`, which is required by `{async block@src/main.rs:50:13: 56:14}: futures::IntoFuture`
    |
    = help: the following other types implement trait `futures::IntoFuture`:
              (A, B)
              (A, B, C)
              (A, B, C, D)
              (A, B, C, D, E)
              Result<T, E>
              hyper::service::service::ServiceFn<F, R>
              hyper::service::service::ServiceFnOk<F, R>
              tokio::executor::Spawn
    = note: required for `{async block@src/main.rs:50:13: 56:14}` to implement `futures::IntoFuture`
note: required by a bound in `futures::Stream::for_each`
   --> C:\Users\Digkill\.cargo\registry\src\index.crates.io-6f17d22bba15001f\futures-0.1.31\src\stream\mod.rs:764:18
    |
762 |     fn for_each<F, U>(self, f: F) -> ForEach<Self, F, U>
    |        -------- required by a bound in this associated function
763 |         where F: FnMut(Self::Item) -> U,
764 |               U: IntoFuture<Item=(), Error = Self::Error>,
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Stream::for_each`

error[E0277]: the trait bound `{async block@src/main.rs:50:13: 56:14}: futures::Future` is not satisfied
   --> src/main.rs:59:18
    |
59  |     bot.run_with(stream);
    |         -------- ^^^^^^ the trait `futures::Future` is not implemented for `{async block@src/main.rs:50:13: 56:14}`, which is required by `ForEach<impl Stream<Item = (RequestHandle, telebot::objects::Message), Error = failure::error::Error>, {closure@src/main.rs:45:19: 45:36}, {async block@src/main.rs:50:13: 56:14}>: std::marker::Send`
    |         |
    |         required by a bound introduced by this call
    |
    = help: the following other types implement trait `futures::Future`:
              &'a mut F
              AssertUnwindSafe<F>
              BiLockAcquire<T>
              Box<F>
              Concat2<S>
              Either<A, B>
              Failed<T, E>
              Flush<S>
            and 87 others
    = note: required for `{async block@src/main.rs:50:13: 56:14}` to implement `futures::IntoFuture`
note: required because it appears within the type `ForEach<impl Stream<Item = (RequestHandle, Message), Error = Error>, ..., ...>`
   --> C:\Users\Digkill\.cargo\registry\src\index.crates.io-6f17d22bba15001f\futures-0.1.31\src\stream\for_each.rs:10:12
    |
10  | pub struct ForEach<S, F, U> where U: IntoFuture {
    |            ^^^^^^^
note: required by a bound in `Bot::run_with`
   --> C:\Users\Digkill\.cargo\registry\src\index.crates.io-6f17d22bba15001f\telebot-0.3.1\src\bot.rs:398:36
    |
395 |     pub fn run_with<I>(self, other: I)
    |            -------- required by a bound in this associated function
...
398 |         <I as IntoFuture>::Future: Send + 'static,
    |                                    ^^^^ required by this bound in `Bot::run_with`
    = note: the full name for the type has been written to 'D:\workspace\rust\telegram_bot\target\debug\deps\telegram_bot.long-type-11458010299628303036.txt'
    = note: consider using `--verbose` to print the full type name to the console

For more information about this error, try `rustc --explain E0277`.
error: could not compile `telegram_bot` (bin "telegram_bot") due to 3 previous errors
PS D:\workspace\rust\telegram_bot>

Cargo.toml:

[package]
name = "telegram_bot"
version = "0.1.0"
edition = "2021"

[dependencies]
dotenv = "0.15"
telebot = "0.3.1"
futures = "0.1.31"
env_logger = "0.11.3"
reqwest = { version = "0.12.5", features = ["json"] }
serde = { version = "1.0.204", features = ["derive"] }
tokio = { version = "1.38.1", features = ["full"] }

the suggested fixes by ChatGPT don’t help

Color me surprised :face_with_open_eyes_and_hand_over_mouth: ChatGPT repeatedly gets wrong even trivial Rust stuff – information that could have been extracted directly from the documentation. See e.g. this post, where it hallucinates that indexing syntax is sugar for Deref, which it isn't. This doesn't even require any deep insight or even superficial "understanding", it's just a definition. So, yeah, absolutely don't ask ChatGPT to fix your Rust code, it won't – it will only cause endless frustration and likely lead you to the completely wrong direction, which it probably did.


With that said, the answer is in the question:

`impl futures::Future<Item = (RequestHandle, telebot::objects::Message), Error = failure::error::Error> + '_` is not a future

Well, if impl Future is "not a future", that very clearly says that futures::Future is not the same trait as the one "baked in the language", i.e., std::future::Future.

That is because the library you are using (and its dependencies) are ancient (≥4 years old). They are so old that they pre-date the stabilization of async-await and futures. The futures crate used to ship its own Future trait definition, which is of course distinct from the one in std (which current versions of futures simply re-export).

You'll need to use newer crates.

8 Likes

Thanks everyone, I beat it

use std::collections::HashMap;
use teloxide::{prelude::*, types::ParseMode};
use teloxide_core::adaptors::DefaultParseMode;
use dotenv::dotenv;
use std::env;
use std::iter::Map;
use reqwest::header::HeaderValue;
use serde::{Deserialize, Serialize};

extern crate serde;
extern crate serde_json;

use serde_json::{json};

type Bot = DefaultParseMode<teloxide::Bot>;

#[derive(Serialize, Deserialize, Debug)]
struct TranslateResult {
    translatedText: String,
}

#[derive(Serialize, Deserialize, Debug)]
struct DetectResponse {
    language: String,
}

#[derive(Serialize, Deserialize, Debug)]
struct DetectRequest {
    q: String,
    api_key: String,
}

#[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_chat_member()
                .branch(
                    dptree::filter(|m: ChatMemberUpdated| {
                        m.old_chat_member.is_left() && m.new_chat_member.is_present()
                    })
                        .endpoint(new_chat_member),
                )
                .branch(
                    dptree::filter(|m: ChatMemberUpdated| {
                        m.old_chat_member.is_present() && m.new_chat_member.is_left()
                    })
                        .endpoint(left_chat_member),
                )
        )
        .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(())
}

/// Welcome Endpoint
async fn new_chat_member(bot: Bot, chat_member: ChatMemberUpdated) -> ResponseResult<()> {
    let user = chat_member.old_chat_member.user.clone();

    let telegram_group_name = chat_member.chat.title().unwrap_or("");
    let username = user.id;

    bot.send_message(chat_member.chat.id, format!("Welcome to {telegram_group_name} {username}!"))
        .await?;

    Ok(())
}

async fn left_chat_member(bot: Bot, chat_member: ChatMemberUpdated) -> ResponseResult<()> {
    let user = chat_member.old_chat_member.user;
    let username = user.id;

    bot.send_message(chat_member.chat.id, format!("Goodbye {username}!")).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(())
}

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)
}

Suggestions for code optimization are welcome

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.