mirror of
https://github.com/teloxide/teloxide.git
synced 2024-12-23 06:51:01 +01:00
Remove the high-level overview from lib.rs
This commit is contained in:
parent
eedf2853b1
commit
234a0e4607
1 changed files with 1 additions and 298 deletions
299
src/lib.rs
299
src/lib.rs
|
@ -2,308 +2,11 @@
|
||||||
//! using the [`async`/`.await`] syntax in [Rust]. It handles all the difficult
|
//! using the [`async`/`.await`] syntax in [Rust]. It handles all the difficult
|
||||||
//! stuff so you can focus only on your business logic.
|
//! stuff so you can focus only on your business logic.
|
||||||
//!
|
//!
|
||||||
//! See also [our GitHub repository](https://github.com/teloxide/teloxide).
|
//! For a high-level overview, see [our GitHub repository](https://github.com/teloxide/teloxide).
|
||||||
//!
|
|
||||||
//! # Getting started
|
|
||||||
//! 1. Create a new bot using [@Botfather] to get a token in the format
|
|
||||||
//! `123456789:blablabla`.
|
|
||||||
//! 2. Initialise the `TELOXIDE_TOKEN` environmental
|
|
||||||
//! variable to your token:
|
|
||||||
//! ```text
|
|
||||||
//! # Unix
|
|
||||||
//! $ export TELOXIDE_TOKEN=<Your token here>
|
|
||||||
//!
|
|
||||||
//! # Windows
|
|
||||||
//! $ set TELOXIDE_TOKEN=<Your token here>
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! 3. Be sure that you are up to date:
|
|
||||||
//! ```bash
|
|
||||||
//! # If you're using stable
|
|
||||||
//! $ rustup update stable
|
|
||||||
//! $ rustup override set stable
|
|
||||||
//!
|
|
||||||
//! # If you're using nightly
|
|
||||||
//! $ rustup update nightly
|
|
||||||
//! $ rustup override set nightly
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! 4. Execute `cargo new my_bot`, enter the directory and put these lines into
|
|
||||||
//! your `Cargo.toml`:
|
|
||||||
//! ```text
|
|
||||||
//! [dependencies]
|
|
||||||
//! teloxide = "0.2.0"
|
|
||||||
//! log = "0.4.8"
|
|
||||||
//! tokio = "0.2.11"
|
|
||||||
//! pretty_env_logger = "0.4.0"
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! # The ping-pong bot
|
|
||||||
//! This bot has a single message handler, which answers "pong" to each incoming
|
|
||||||
//! message:
|
|
||||||
//!
|
|
||||||
//! ([Full](https://github.com/teloxide/teloxide/blob/master/examples/ping_pong_bot/src/main.rs))
|
|
||||||
//! ```no_run
|
|
||||||
//! use teloxide::prelude::*;
|
|
||||||
//!
|
|
||||||
//! #[tokio::main]
|
|
||||||
//! async fn main() {
|
|
||||||
//! teloxide::enable_logging!();
|
|
||||||
//! log::info!("Starting ping_pong_bot!");
|
|
||||||
//!
|
|
||||||
//! let bot = Bot::from_env();
|
|
||||||
//!
|
|
||||||
//! Dispatcher::new(bot)
|
|
||||||
//! .messages_handler(|rx: DispatcherHandlerRx<Message>| {
|
|
||||||
//! rx.for_each(|message| async move {
|
|
||||||
//! message.answer("pong").send().await.log_on_error().await;
|
|
||||||
//! })
|
|
||||||
//! })
|
|
||||||
//! .dispatch()
|
|
||||||
//! .await;
|
|
||||||
//! }
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! <div align="center">
|
|
||||||
//! <kbd>
|
|
||||||
//! <img src=https://github.com/teloxide/teloxide/raw/master/media/PING_PONG_BOT.png width="600" />
|
|
||||||
//! </kbd>
|
|
||||||
//! </div>
|
|
||||||
//!
|
|
||||||
//! # Commands
|
|
||||||
//! Commands are defined similar to how we define CLI using [structopt]. This
|
|
||||||
//! bot says "I am a cat! Meow!" on `/meow`, generates a random number within
|
|
||||||
//! [0; 1) on `/generate`, and shows the usage guide on `/help`:
|
|
||||||
//!
|
|
||||||
//! ([Full](https://github.com/teloxide/teloxide/blob/master/examples/simple_commands_bot/src/main.rs))
|
|
||||||
//! ```no_run
|
|
||||||
//! // Imports are omitted...
|
|
||||||
//! # #[allow(unreachable_code)]
|
|
||||||
//! # use teloxide::{prelude::*, utils::command::BotCommand};
|
|
||||||
//! # use rand::{thread_rng, Rng};
|
|
||||||
//!
|
|
||||||
//! #[derive(BotCommand)]
|
|
||||||
//! #[command(
|
|
||||||
//! rename = "lowercase",
|
|
||||||
//! description = "These commands are supported:"
|
|
||||||
//! )]
|
|
||||||
//! enum Command {
|
|
||||||
//! #[command(description = "display this text.")]
|
|
||||||
//! Help,
|
|
||||||
//! #[command(description = "be a cat.")]
|
|
||||||
//! Meow,
|
|
||||||
//! #[command(description = "generate a random number within [0; 1).")]
|
|
||||||
//! Generate,
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! fn generate() -> String {
|
|
||||||
//! thread_rng().gen_range(0.0, 1.0).to_string()
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! async fn answer(
|
|
||||||
//! cx: DispatcherHandlerCx<Message>,
|
|
||||||
//! command: Command,
|
|
||||||
//! ) -> ResponseResult<()> {
|
|
||||||
//! match command {
|
|
||||||
//! Command::Help => cx.answer(Command::descriptions()).send().await?,
|
|
||||||
//! Command::Generate => cx.answer(generate()).send().await?,
|
|
||||||
//! Command::Meow => cx.answer("I am a cat! Meow!").send().await?,
|
|
||||||
//! };
|
|
||||||
//!
|
|
||||||
//! Ok(())
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! async fn handle_commands(rx: DispatcherHandlerRx<Message>) {
|
|
||||||
//! // Only iterate through commands in a proper format:
|
|
||||||
//! rx.commands::<Command, &str>(panic!("Insert here your bot's name"))
|
|
||||||
//! // Execute all incoming commands concurrently:
|
|
||||||
//! .for_each_concurrent(None, |(cx, command, _)| async move {
|
|
||||||
//! answer(cx, command).await.log_on_error().await;
|
|
||||||
//! })
|
|
||||||
//! .await;
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! #[tokio::main]
|
|
||||||
//! async fn main() {
|
|
||||||
//! // Setup is omitted...
|
|
||||||
//! # teloxide::enable_logging!();
|
|
||||||
//! # log::info!("Starting simple_commands_bot!");
|
|
||||||
//! # let bot = Bot::from_env();
|
|
||||||
//! # Dispatcher::new(bot).messages_handler(handle_commands).dispatch().await;
|
|
||||||
//! }
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! <div align="center">
|
|
||||||
//! <kbd>
|
|
||||||
//! <img src=https://github.com/teloxide/teloxide/raw/master/media/SIMPLE_COMMANDS_BOT.png width="500"/>
|
|
||||||
//! </kbd>
|
|
||||||
//! <br/><br/>
|
|
||||||
//! </div>
|
|
||||||
//!
|
|
||||||
//!
|
|
||||||
//! See? The dispatcher gives us a stream of messages, so we can handle it as we
|
|
||||||
//! want! Here we use our `.commands::<Command>()` and
|
|
||||||
//! [`.for_each_concurrent()`], but others are also available:
|
|
||||||
//! - [`.flatten()`](https://docs.rs/futures/0.3.4/futures/stream/trait.StreamExt.html#method.flatten)
|
|
||||||
//! - [`.left_stream()`](https://docs.rs/futures/0.3.4/futures/stream/trait.StreamExt.html#method.left_stream)
|
|
||||||
//! - [`.scan()`](https://docs.rs/futures/0.3.4/futures/stream/trait.StreamExt.html#method.scan)
|
|
||||||
//! - [`.skip_while()`](https://docs.rs/futures/0.3.4/futures/stream/trait.StreamExt.html#method.skip_while)
|
|
||||||
//! - [`.zip()`](https://docs.rs/futures/0.3.4/futures/stream/trait.StreamExt.html#method.zip)
|
|
||||||
//! - [`.select_next_some()`](https://docs.rs/futures/0.3.4/futures/stream/trait.StreamExt.html#method.select_next_some)
|
|
||||||
//! - [`.fold()`](https://docs.rs/futures/0.3.4/futures/stream/trait.StreamExt.html#method.fold)
|
|
||||||
//! - [`.inspect()`](https://docs.rs/futures/0.3.4/futures/stream/trait.StreamExt.html#method.inspect)
|
|
||||||
//! - ... And lots of [others](https://docs.rs/futures/0.3.4/futures/stream/trait.StreamExt.html)!
|
|
||||||
//!
|
|
||||||
//! # Guess a number
|
|
||||||
//! Wanna see more? This is a bot, which starts a game on each incoming message.
|
|
||||||
//! You must guess a number from 1 to 10 (inclusively):
|
|
||||||
//!
|
|
||||||
//! ([Full](https://github.com/teloxide/teloxide/blob/master/examples/guess_a_number_bot/src/main.rs))
|
|
||||||
//! ```no_run
|
|
||||||
//! // Setup is omitted...
|
|
||||||
//! # #[macro_use]
|
|
||||||
//! # extern crate smart_default;
|
|
||||||
//! # use teloxide::prelude::*;
|
|
||||||
//! # use rand::{thread_rng, Rng};
|
|
||||||
//!
|
|
||||||
//! #[derive(SmartDefault)]
|
|
||||||
//! enum Dialogue {
|
|
||||||
//! #[default]
|
|
||||||
//! Start,
|
|
||||||
//! ReceiveAttempt(u8),
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! async fn handle_message(
|
|
||||||
//! cx: DialogueDispatcherHandlerCx<Message, Dialogue>,
|
|
||||||
//! ) -> ResponseResult<DialogueStage<Dialogue>> {
|
|
||||||
//! match cx.dialogue {
|
|
||||||
//! Dialogue::Start => {
|
|
||||||
//! cx.answer(
|
|
||||||
//! "Let's play a game! Guess a number from 1 to 10 \
|
|
||||||
//! (inclusively).",
|
|
||||||
//! )
|
|
||||||
//! .send()
|
|
||||||
//! .await?;
|
|
||||||
//! next(Dialogue::ReceiveAttempt(thread_rng().gen_range(1, 11)))
|
|
||||||
//! }
|
|
||||||
//! Dialogue::ReceiveAttempt(secret) => match cx.update.text() {
|
|
||||||
//! None => {
|
|
||||||
//! cx.answer("Oh, please, send me a text message!")
|
|
||||||
//! .send()
|
|
||||||
//! .await?;
|
|
||||||
//! next(cx.dialogue)
|
|
||||||
//! }
|
|
||||||
//! Some(text) => match text.parse::<u8>() {
|
|
||||||
//! Ok(attempt) => match attempt {
|
|
||||||
//! x if !(1..=10).contains(&x) => {
|
|
||||||
//! cx.answer(
|
|
||||||
//! "Oh, please, send me a number in the range \
|
|
||||||
//! [1; 10]!",
|
|
||||||
//! )
|
|
||||||
//! .send()
|
|
||||||
//! .await?;
|
|
||||||
//! next(cx.dialogue)
|
|
||||||
//! }
|
|
||||||
//! x if x == secret => {
|
|
||||||
//! cx.answer("Congratulations! You won!")
|
|
||||||
//! .send()
|
|
||||||
//! .await?;
|
|
||||||
//! exit()
|
|
||||||
//! }
|
|
||||||
//! _ => {
|
|
||||||
//! cx.answer("No.").send().await?;
|
|
||||||
//! next(cx.dialogue)
|
|
||||||
//! }
|
|
||||||
//! },
|
|
||||||
//! Err(_) => {
|
|
||||||
//! cx.answer(
|
|
||||||
//! "Oh, please, send me a number in the range [1; \
|
|
||||||
//! 10]!",
|
|
||||||
//! )
|
|
||||||
//! .send()
|
|
||||||
//! .await?;
|
|
||||||
//! next(cx.dialogue)
|
|
||||||
//! }
|
|
||||||
//! },
|
|
||||||
//! },
|
|
||||||
//! }
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! #[tokio::main]
|
|
||||||
//! async fn main() {
|
|
||||||
//! // Setup is omitted...
|
|
||||||
//! # teloxide::enable_logging!();
|
|
||||||
//! # log::info!("Starting guess_a_number_bot!");
|
|
||||||
//! # let bot = Bot::from_env();
|
|
||||||
//! # Dispatcher::new(bot)
|
|
||||||
//! # .messages_handler(DialogueDispatcher::new(|cx| async move {
|
|
||||||
//! # handle_message(cx).await.expect("Something wrong with the bot!")
|
|
||||||
//! # }))
|
|
||||||
//! # .dispatch()
|
|
||||||
//! # .await;
|
|
||||||
//! }
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! <div align="center">
|
|
||||||
//! <kbd>
|
|
||||||
//! <img src=https://github.com/teloxide/teloxide/raw/master/media/GUESS_A_NUMBER_BOT.png width="600" />
|
|
||||||
//! </kbd>
|
|
||||||
//! <br/><br/>
|
|
||||||
//! </div>
|
|
||||||
//!
|
|
||||||
//! Our [finite automaton], designating a user dialogue, cannot be in an invalid
|
|
||||||
//! state, and this is why it is called "type-safe". We could use `enum` +
|
|
||||||
//! `Option`s instead, but it will lead is to lots of unpleasure `.unwrap()`s.
|
|
||||||
//!
|
|
||||||
//! Remember that a classical [finite automaton] is defined by its initial
|
|
||||||
//! state, a list of its possible states and a transition function? We can think
|
|
||||||
//! that `Dialogue` is a finite automaton with a context type at each state
|
|
||||||
//! (`Dialogue::Start` has `()`, `Dialogue::ReceiveAttempt` has `u8`).
|
|
||||||
//!
|
|
||||||
//! See [examples/dialogue_bot] to see a bit more complicated bot with
|
|
||||||
//! dialogues. [See all examples](https://github.com/teloxide/teloxide/tree/master/examples).
|
|
||||||
//!
|
|
||||||
//! # Recommendations
|
|
||||||
//!
|
|
||||||
//! - Use this pattern:
|
|
||||||
//!
|
|
||||||
//! ```rust
|
|
||||||
//! #[tokio::main]
|
|
||||||
//! async fn main() {
|
|
||||||
//! run().await;
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! async fn run() {
|
|
||||||
//! // Your logic here...
|
|
||||||
//! }
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! Instead of this:
|
|
||||||
//!
|
|
||||||
//! ```rust
|
|
||||||
//! #[tokio::main]
|
|
||||||
//! async fn main() {
|
|
||||||
//! // Your logic here...
|
|
||||||
//! }
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! The second one produces very strange compiler messages because of the
|
|
||||||
//! `#[tokio::main]` macro. However, the examples above use the second one for
|
|
||||||
//! brevity.
|
|
||||||
//!
|
//!
|
||||||
//! [Telegram bots]: https://telegram.org/blog/bot-revolution
|
//! [Telegram bots]: https://telegram.org/blog/bot-revolution
|
||||||
//! [`async`/`.await`]: https://rust-lang.github.io/async-book/01_getting_started/01_chapter.html
|
//! [`async`/`.await`]: https://rust-lang.github.io/async-book/01_getting_started/01_chapter.html
|
||||||
//! [Rust]: https://www.rust-lang.org/
|
//! [Rust]: https://www.rust-lang.org/
|
||||||
//! [finite automaton]: https://en.wikipedia.org/wiki/Finite-state_machine
|
|
||||||
//! [examples/dialogue_bot]: https://github.com/teloxide/teloxide/blob/master/examples/dialogue_bot/src/main.rs
|
|
||||||
//! [structopt]: https://docs.rs/structopt/0.3.9/structopt/
|
|
||||||
//! [@Botfather]: https://t.me/botfather
|
|
||||||
//! [streams]: https://docs.rs/futures/0.3.4/futures/stream/index.html
|
|
||||||
//! [all 30+ patterns]: https://docs.rs/futures/0.3.4/futures/stream/trait.StreamExt.html
|
|
||||||
//! [`.for_each_concurrent()`]: https://docs.rs/futures/0.3.4/futures/stream/trait.StreamExt.html#method.for_each_concurrent
|
|
||||||
//! [See more examples]: https://github.com/teloxide/teloxide/tree/master/examples
|
|
||||||
//! [category theory]: https://en.wikipedia.org/wiki/Category_theory
|
|
||||||
//! [coproduct]: https://en.wikipedia.org/wiki/Coproduct
|
|
||||||
|
|
||||||
// https://github.com/teloxide/teloxide/raw/master/logo.svg doesn't work in html_logo_url, I don't know why.
|
// https://github.com/teloxide/teloxide/raw/master/logo.svg doesn't work in html_logo_url, I don't know why.
|
||||||
#![doc(
|
#![doc(
|
||||||
|
|
Loading…
Reference in a new issue