logo
pub struct Dispatcher<R, Err, Key> { /* private fields */ }
Expand description

The base for update dispatching.

Updates from different chats are handled concurrently, whereas updates from the same chats are handled sequentially. If the dispatcher is unable to determine a chat ID of an incoming update, it will be handled concurrently. Note that this behaviour can be altered with distribution_function.

See also: “Dispatching or REPLs?”

Implementations

Constructs a new DispatcherBuilder with bot and handler.

Examples found in repository?
examples/purchase.rs (line 53)
47
48
49
50
51
52
53
54
55
56
57
58
59
async fn main() {
    pretty_env_logger::init();
    log::info!("Starting purchase bot...");

    let bot = Bot::from_env();

    Dispatcher::builder(bot, schema())
        .dependencies(dptree::deps![InMemStorage::<State>::new()])
        .enable_ctrlc_handler()
        .build()
        .dispatch()
        .await;
}
More examples
Hide additional examples
examples/buttons.rs (line 33)
22
23
24
25
26
27
28
29
30
31
32
33
34
35
async fn main() -> Result<(), Box<dyn Error>> {
    pretty_env_logger::init();
    log::info!("Starting buttons bot...");

    let bot = Bot::from_env();

    let handler = dptree::entry()
        .branch(Update::filter_message().endpoint(message_handler))
        .branch(Update::filter_callback_query().endpoint(callback_handler))
        .branch(Update::filter_inline_query().endpoint(inline_query_handler));

    Dispatcher::builder(bot, handler).enable_ctrlc_handler().build().dispatch().await;
    Ok(())
}
examples/dialogue.rs (lines 42-52)
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
async fn main() {
    pretty_env_logger::init();
    log::info!("Starting dialogue bot...");

    let bot = Bot::from_env();

    Dispatcher::builder(
        bot,
        Update::filter_message()
            .enter_dialogue::<Message, InMemStorage<State>, State>()
            .branch(dptree::case![State::Start].endpoint(start))
            .branch(dptree::case![State::ReceiveFullName].endpoint(receive_full_name))
            .branch(dptree::case![State::ReceiveAge { full_name }].endpoint(receive_age))
            .branch(
                dptree::case![State::ReceiveLocation { full_name, age }].endpoint(receive_location),
            ),
    )
    .dependencies(dptree::deps![InMemStorage::<State>::new()])
    .enable_ctrlc_handler()
    .build()
    .dispatch()
    .await;
}
examples/shared_state.rs (line 27)
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
async fn main() {
    pretty_env_logger::init();
    log::info!("Starting shared state bot...");

    let bot = Bot::from_env();
    let messages_total = Arc::new(AtomicU64::new(0));

    let handler = Update::filter_message().endpoint(
        |bot: Bot, messages_total: Arc<AtomicU64>, msg: Message| async move {
            let previous = messages_total.fetch_add(1, Ordering::Relaxed);
            bot.send_message(msg.chat.id, format!("I received {previous} messages in total."))
                .await?;
            respond(())
        },
    );

    Dispatcher::builder(bot, handler)
        // Pass the shared state to the handler as a dependency.
        .dependencies(dptree::deps![messages_total])
        .enable_ctrlc_handler()
        .build()
        .dispatch()
        .await;
}
examples/db_remember.rs (line 55)
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
async fn main() {
    pretty_env_logger::init();
    log::info!("Starting DB remember bot...");

    let bot = Bot::from_env();

    let storage: MyStorage = if std::env::var("DB_REMEMBER_REDIS").is_ok() {
        RedisStorage::open("redis://127.0.0.1:6379", Bincode).await.unwrap().erase()
    } else {
        SqliteStorage::open("db.sqlite", Json).await.unwrap().erase()
    };

    let handler = Update::filter_message()
        .enter_dialogue::<Message, ErasedStorage<State>, State>()
        .branch(dptree::case![State::Start].endpoint(start))
        .branch(
            dptree::case![State::GotNumber(n)]
                .branch(dptree::entry().filter_command::<Command>().endpoint(got_number))
                .branch(dptree::endpoint(invalid_command)),
        );

    Dispatcher::builder(bot, handler)
        .dependencies(dptree::deps![storage])
        .enable_ctrlc_handler()
        .build()
        .dispatch()
        .await;
}
examples/inline.rs (line 63)
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
async fn main() {
    pretty_env_logger::init();
    log::info!("Starting inline bot...");

    let bot = Bot::from_env();

    let handler = Update::filter_inline_query().branch(dptree::endpoint(
        |bot: Bot, q: InlineQuery| async move {
            // First, create your actual response
            let google_search = InlineQueryResultArticle::new(
                // Each item needs a unique ID, as well as the response container for the
                // items. These can be whatever, as long as they don't
                // conflict.
                "01".to_string(),
                // What the user will actually see
                "Google Search",
                // What message will be sent when clicked/tapped
                InputMessageContent::Text(InputMessageContentText::new(format!(
                    "https://www.google.com/search?q={}",
                    q.query,
                ))),
            );
            // While constructing them from the struct itself is possible, it is preferred
            // to use the builder pattern if you wish to add more
            // information to your result. Please refer to the documentation
            // for more detailed information about each field. https://docs.rs/teloxide/latest/teloxide/types/struct.InlineQueryResultArticle.html
            let ddg_search = InlineQueryResultArticle::new(
                "02".to_string(),
                "DuckDuckGo Search".to_string(),
                InputMessageContent::Text(InputMessageContentText::new(format!(
                    "https://duckduckgo.com/?q={}",
                    q.query
                ))),
            )
            .description("DuckDuckGo Search")
            .thumb_url("https://duckduckgo.com/assets/logo_header.v108.png".parse().unwrap())
            .url("https://duckduckgo.com/about".parse().unwrap()); // Note: This is the url that will open if they click the thumbnail

            let results = vec![
                InlineQueryResult::Article(google_search),
                InlineQueryResult::Article(ddg_search),
            ];

            // Send it off! One thing to note -- the ID we use here must be of the query
            // we're responding to.
            let response = bot.answer_inline_query(&q.id, results).send().await;
            if let Err(err) = response {
                log::error!("Error in handler: {:?}", err);
            }
            respond(())
        },
    ));

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

Starts your bot with the default parameters.

The default parameters are a long polling update listener and log all errors produced by this listener.

Each time a handler is invoked, Dispatcher adds the following dependencies (in addition to those passed to DispatcherBuilder::dependencies):

Examples found in repository?
examples/purchase.rs (line 57)
47
48
49
50
51
52
53
54
55
56
57
58
59
async fn main() {
    pretty_env_logger::init();
    log::info!("Starting purchase bot...");

    let bot = Bot::from_env();

    Dispatcher::builder(bot, schema())
        .dependencies(dptree::deps![InMemStorage::<State>::new()])
        .enable_ctrlc_handler()
        .build()
        .dispatch()
        .await;
}
More examples
Hide additional examples
examples/buttons.rs (line 33)
22
23
24
25
26
27
28
29
30
31
32
33
34
35
async fn main() -> Result<(), Box<dyn Error>> {
    pretty_env_logger::init();
    log::info!("Starting buttons bot...");

    let bot = Bot::from_env();

    let handler = dptree::entry()
        .branch(Update::filter_message().endpoint(message_handler))
        .branch(Update::filter_callback_query().endpoint(callback_handler))
        .branch(Update::filter_inline_query().endpoint(inline_query_handler));

    Dispatcher::builder(bot, handler).enable_ctrlc_handler().build().dispatch().await;
    Ok(())
}
examples/dialogue.rs (line 56)
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
async fn main() {
    pretty_env_logger::init();
    log::info!("Starting dialogue bot...");

    let bot = Bot::from_env();

    Dispatcher::builder(
        bot,
        Update::filter_message()
            .enter_dialogue::<Message, InMemStorage<State>, State>()
            .branch(dptree::case![State::Start].endpoint(start))
            .branch(dptree::case![State::ReceiveFullName].endpoint(receive_full_name))
            .branch(dptree::case![State::ReceiveAge { full_name }].endpoint(receive_age))
            .branch(
                dptree::case![State::ReceiveLocation { full_name, age }].endpoint(receive_location),
            ),
    )
    .dependencies(dptree::deps![InMemStorage::<State>::new()])
    .enable_ctrlc_handler()
    .build()
    .dispatch()
    .await;
}
examples/shared_state.rs (line 32)
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
async fn main() {
    pretty_env_logger::init();
    log::info!("Starting shared state bot...");

    let bot = Bot::from_env();
    let messages_total = Arc::new(AtomicU64::new(0));

    let handler = Update::filter_message().endpoint(
        |bot: Bot, messages_total: Arc<AtomicU64>, msg: Message| async move {
            let previous = messages_total.fetch_add(1, Ordering::Relaxed);
            bot.send_message(msg.chat.id, format!("I received {previous} messages in total."))
                .await?;
            respond(())
        },
    );

    Dispatcher::builder(bot, handler)
        // Pass the shared state to the handler as a dependency.
        .dependencies(dptree::deps![messages_total])
        .enable_ctrlc_handler()
        .build()
        .dispatch()
        .await;
}
examples/db_remember.rs (line 59)
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
async fn main() {
    pretty_env_logger::init();
    log::info!("Starting DB remember bot...");

    let bot = Bot::from_env();

    let storage: MyStorage = if std::env::var("DB_REMEMBER_REDIS").is_ok() {
        RedisStorage::open("redis://127.0.0.1:6379", Bincode).await.unwrap().erase()
    } else {
        SqliteStorage::open("db.sqlite", Json).await.unwrap().erase()
    };

    let handler = Update::filter_message()
        .enter_dialogue::<Message, ErasedStorage<State>, State>()
        .branch(dptree::case![State::Start].endpoint(start))
        .branch(
            dptree::case![State::GotNumber(n)]
                .branch(dptree::entry().filter_command::<Command>().endpoint(got_number))
                .branch(dptree::endpoint(invalid_command)),
        );

    Dispatcher::builder(bot, handler)
        .dependencies(dptree::deps![storage])
        .enable_ctrlc_handler()
        .build()
        .dispatch()
        .await;
}
examples/inline.rs (line 63)
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
async fn main() {
    pretty_env_logger::init();
    log::info!("Starting inline bot...");

    let bot = Bot::from_env();

    let handler = Update::filter_inline_query().branch(dptree::endpoint(
        |bot: Bot, q: InlineQuery| async move {
            // First, create your actual response
            let google_search = InlineQueryResultArticle::new(
                // Each item needs a unique ID, as well as the response container for the
                // items. These can be whatever, as long as they don't
                // conflict.
                "01".to_string(),
                // What the user will actually see
                "Google Search",
                // What message will be sent when clicked/tapped
                InputMessageContent::Text(InputMessageContentText::new(format!(
                    "https://www.google.com/search?q={}",
                    q.query,
                ))),
            );
            // While constructing them from the struct itself is possible, it is preferred
            // to use the builder pattern if you wish to add more
            // information to your result. Please refer to the documentation
            // for more detailed information about each field. https://docs.rs/teloxide/latest/teloxide/types/struct.InlineQueryResultArticle.html
            let ddg_search = InlineQueryResultArticle::new(
                "02".to_string(),
                "DuckDuckGo Search".to_string(),
                InputMessageContent::Text(InputMessageContentText::new(format!(
                    "https://duckduckgo.com/?q={}",
                    q.query
                ))),
            )
            .description("DuckDuckGo Search")
            .thumb_url("https://duckduckgo.com/assets/logo_header.v108.png".parse().unwrap())
            .url("https://duckduckgo.com/about".parse().unwrap()); // Note: This is the url that will open if they click the thumbnail

            let results = vec![
                InlineQueryResult::Article(google_search),
                InlineQueryResult::Article(ddg_search),
            ];

            // Send it off! One thing to note -- the ID we use here must be of the query
            // we're responding to.
            let response = bot.answer_inline_query(&q.id, results).send().await;
            if let Err(err) = response {
                log::error!("Error in handler: {:?}", err);
            }
            respond(())
        },
    ));

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

Starts your bot with custom update_listener and update_listener_error_handler.

This method adds the same dependencies as Dispatcher::dispatch.

👎Deprecated since 0.10.0: use enable_ctrlc_handler on builder instead
Available on crate feature ctrlc_handler only.

Setups the ^C handler that shutdowns dispatching.

Returns a shutdown token, which can later be used to shutdown dispatching.

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Unerase this erased pointer. Read more
Available on non-enforce_1_1_0_semantics only.
Whether this implementor has acknowledged the 1.1.0 update to unerase’s documented implementation requirements. Read more
Turn this erasable pointer into an erased pointer. Read more

Returns the argument unchanged.

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Instruments this type with the current Span, returning an Instrumented wrapper. Read more

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more