Giter Site home page Giter Site logo

Comments (10)

WaffleLapkin avatar WaffleLapkin commented on June 16, 2024 1

@syrtcevvi polling timeout must be smaller than http client's, which is the case (polling_default = 10s, http = 17s), so I don't think this is the problem...

from teloxide.

Bl4d3s avatar Bl4d3s commented on June 16, 2024

Update:

I implemented now a inline response handler as well:

#[tokio::main]
async fn main() {
    pretty_env_logger::init();
    Config::load_from_file();
    log::info!("Starting command bot...");

    let token = Config::global().telegram_token.to_string();
    let bot = Bot::new(token);
    let command_handler = Update::filter_message().filter_command::<PortainerCommands>().endpoint(answer);
    let inline_handler = Update::filter_inline_query().endpoint(inline_answer);

    let handler = dptree::entry()
        .branch(command_handler)
        .branch(inline_handler);

    Dispatcher::builder(bot, handler)
        .enable_ctrlc_handler()
        .build()
        .dispatch()
        .await;
}

#[derive(BotCommands, Clone)]
#[command(rename_rule = "lowercase", description = "These commands are supported:")]
enum PortainerCommands {
    #[command(description = "Responds with info required to setup this bot.")]
    Info,
    #[command(description = "display this text.")]
    Help,
    #[command(description = "update a stack. Parameters: env,stack", parse_with = "split")]
    Update { env: String, stack: String },
}

async fn answer(bot: Bot, msg: Message, cmd: PortainerCommands) -> ResponseResult<()> {
    let text = match cmd {
        PortainerCommands::Info =>
             if Config::global().is_allowed_chat(msg.chat.id) {
                 format!("Your bot is correctly configured to answer to this chat and execute given updates")
             } else {
                 format!("Please configure your bot to allow processing of your chat.\nAdd the chat id to the list of allowed ones in the config.toml.\n\nYour chat id: {}", msg.chat.id)
             },
        PortainerCommands::Help => PortainerCommands::descriptions().to_string(),
        PortainerCommands::Update { env, stack } => {
            log::info!("Received trigger for {} on {}", stack, env);
            if Config::global().is_allowed_chat(msg.chat.id) {
                let success = trigger_update(env.to_string(), stack.to_string()).await;

                if success.is_none() {
                    log::warn!("Something unexpected happened for {} on {}", stack, env);
                    format!("Something unexpected happened while updating {stack} on environment {env}.")
                } else if success.is_some_and(|success| success) {
                    log::info!("Triggered update for {} on {}", stack, env);
                    format!("Triggered update for {stack} on environment {env}.")
                } else {
                    log::warn!("Failed to update {} on {}", stack, env);
                    format!("Failed to update {stack} on environment {env}.")
                }
            } else {
                log::warn!("Unconfigured chat update");

                format!("Update not allowed from this chat. Please use /info to get instructions to set up this bot.")
            }
        }
    };

    bot.send_message(msg.chat.id, text).await?;

    Ok(())
}



pub async fn inline_answer(bot: Bot, update: InlineQuery) -> Result<(), RequestError> {
    let mut inline_result = get_configured_stacks(update.query.as_str());

    let mut offset = update.offset.parse::<usize>().unwrap_or_default();
    if inline_result.is_empty() {
        inline_result.push(InlineQueryResult::Article(InlineQueryResultArticle::new(
            "1",
            "No stacks configured",
            InputMessageContent::Text(InputMessageContentText::new("No stacks configured")),
        )))
    }
    let mut req_builder = bot.answer_inline_query(update.id, inline_result);
    if offset != 0 {
        req_builder = req_builder.next_offset(offset.to_string());
    }
    req_builder.await?;

    respond(())
}

fn get_configured_stacks(search: &str) -> Vec<InlineQueryResult> {
    let keywords: Vec<&str> = search.split(' ').collect();
    let mut results: Vec<InlineQueryResult> = Vec::new();
    for (environment, stacks) in &Config::global().environments {
        for key in stacks.keys() {
            if keywords.iter().any(|k| key.contains(k)) {
                results.push(InlineQueryResult::Article(InlineQueryResultArticle::new(
                    format!("{}_{}", environment, key),
                    format!("Environment: {}, Stack: {}", environment, key),
                    InputMessageContent::Text(InputMessageContentText::new(format!("/update {} {}", environment, key))),
                )))
            }
        }
    }

    results
}

Now I have the following behaviour:

  1. Bot will still stop responding to commands after some time.
  2. But if I use the inline query that still works.
  3. If I select a search result from the inline query, the body of the result (a command) is posted and correctly executed.
    Afterwards, normal commands are processed again as well (for some time).

This behaviour seems to be restricted to groups, I could not replicate it when talking to the bot in a direct chat.

from teloxide.

WaffleLapkin avatar WaffleLapkin commented on June 16, 2024

Sadly, I have no idea why this might be happening, if you can minimize the example more, that would be helpful.

from teloxide.

Bl4d3s avatar Bl4d3s commented on June 16, 2024

I will try to do so next week, will keep you posted.

from teloxide.

Bl4d3s avatar Bl4d3s commented on June 16, 2024

I managed to create a minimal example: Code here

Environments I could not reproduce the issue:

  • Windows: as exe (directly built without docker)
  • Windows: Built container (as provided in example)

Where it still occurs (where I also noticed it the most with my full bot):

  • Debian server, running Docker/Portainer. There the same docker image behaves just fine for direct chat messages, but not to group commands. Sometimes directly after startup, sometimes after some idle time.

Could there be an issue with how I build the docker container?
The container is in both environments simply part of the default docker network (bridge, ipv4 only).

If you need any further information about my environment, I am happy to provide.

from teloxide.

syrtcevvi avatar syrtcevvi commented on June 16, 2024

At first glance, it seems to me, that polling_default (which is used by the repl fn) settings clash with the proper bot's HTTP client timings (issue 223)

polling_default uses 10 seconds of timeout which is different than ones at default_reqwest_settings

from teloxide.

WaffleLapkin avatar WaffleLapkin commented on June 16, 2024

Just a note: I'm overwhelmed with work, so I'm unlikely to have time to debug this issue anytime soon.

from teloxide.

Bl4d3s avatar Bl4d3s commented on June 16, 2024

Just a note: I'm overwhelmed with work, so I'm unlikely to have time to debug this issue anytime soon.

No rush, for now it works when chatting directly with the bot, so I have a workaround ^^

from teloxide.

PrincessLunaOfficial avatar PrincessLunaOfficial commented on June 16, 2024

Having the same problem, for some reason bot just stops responding to the commands in the group chat, but it still works in the direct chat. Hosted in docker, using debian:bullseye-slim image

UPD: Even if I use custom branch, bot stops catching updates from the group after some time.

pub async fn start_bot() {
    let client = Client::builder().danger_accept_invalid_certs(true).build().unwrap();
    let bot = Arc::new(Bot::with_client("TOKEN", client));
    let bot_clone_call = Arc::clone(&bot);
    let bot_clone_msg = Arc::clone(&bot);
    let task_branch = {
        dptree::filter(|msg: Message| msg.text().unwrap() == "/calls").endpoint({
            let bot = Arc::clone(&bot);
            move |msg: Message| {
                let bot = Arc::clone(&bot);
                async move {
                    let calls = history_by_period(Period::Today).await.unwrap();
                    let message = extract_missed_calls(calls);
                    bot.send_message(ChatId {
                        0: msg.chat.id.0
                    }, message).await.unwrap();
                    respond(())
                }
            }
        })
    };

    let handler = Update::filter_message().branch(task_branch);

    let call_announce_task = tokio::spawn(async move {
        // This tasks does bot.send_message in group chat every 5 minutes
        // without adding additional dispatchers
        start_calls_announce(&*bot_clone_call).await.unwrap();
    });

    let msg_tsk = tokio::spawn(async move {
        Dispatcher::builder(bot_clone_msg, handler).default_handler(|upd| async move {
            warn!("Unhandled update: {:?}", upd);
        }).enable_ctrlc_handler().build().dispatch().await;
    });

    let _ = tokio::join!(msg_tsk, call_announce_task);
};

from teloxide.

WaffleLapkin avatar WaffleLapkin commented on June 16, 2024

One thing you can do is add tracing for all updates and try to make the problem reproducible. By recording updates we can then later make an update listener that will return them and then try to minimize the issue from there...

from teloxide.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.