51个版本

0.3.10 2023年8月6日
0.3.9 2023年7月18日
0.3.6 2023年6月13日
0.2.28 2023年6月11日
0.1.2 2023年4月30日

#7 in #bot-api

Download history 10/week @ 2024-04-08 1/week @ 2024-05-20 312/week @ 2024-07-01 2/week @ 2024-07-22

314 每月下载量

MIT 许可证

140KB
2.5K SLoC

MOBOT

Crates.io Documentation License: MIT

MOBOT 是用Rust编写的Telegram聊天框架。它包含了对Telegram Bot API的完全本地实现。

特性

  • 原始Telegram API,支持消息、频道、贴纸、回调等。
  • 具有基于消息的路由和嵌套处理程序堆栈支持的Web框架风格路由API。
  • 简单的应用程序状态管理。MOBOT 确保每个聊天都为处理程序提供正确的状态。
  • 集成的测试基础设施 (FakeBot),简化为您的机器人编写单元测试。
  • 支持进度条、内嵌键盘、“正在输入...”指示器等。请参见下面的演示视频。

演示和示例

这是使用MOBOT框架构建的devops机器人的演示。

https://github.com/0xfe/mobot/assets/241299/22b3c420-6acd-43f9-81f8-eb957ff24288

使用 MOBOT 构建的其它机器人

  • WordleBot - Wordle Telegram机器人
  • <在此处添加您的>

Hello World!

mobot 添加到您的 Cargo.toml 文件中。

cargo add mobot

示例机器人:对每条消息回复“Hello world!”。在 src/bin/hello.rs 中有一个工作示例。

use mobot::*;

#[tokio::main]
async fn main() {
    let client = Client::new(std::env::var("TELEGRAM_TOKEN").unwrap().into());
    let mut router = Router::<()>::new(client);

    router.add_route(Route::Default, |_, _| async move {
        Ok(Action::ReplyText("Hello world!".into()))
    });
    router.start().await;
}

文档

请参阅完整的API文档:https://docs.rs/mobot

请参阅 src/bin 中的示例。

测试

MOBOT 包含了 fake::FakeAPI 库,这是一个简化您机器人单元测试的库。使用 with_post_handler 钩子可以将 FakeAPI 插入到 mobot::Client 中。以下是从 router_test.rs 的示例。

async fn it_works() {
    mobot::init_logger();

    // Create a FakeAPI and attach it to the client. Any Telegram requests are now forwarded
    // to `fakeserver` instead.
    let fakeserver = fake::FakeAPI::new();
    let client = Client::new("token".to_string().into()).with_post_handler(fakeserver.clone());

    // Keep the Telegram poll timeout short for testing. The default Telegram poll timeout is 60s.
    let mut router = Router::new(client).with_poll_timeout_s(1);

    // Since we're passing ownership of the Router to a background task, grab the
    // shutdown channels so we can shut it down from this task.
    let (shutdown_notifier, shutdown_tx) = router.shutdown();

    // Our bot is a ping bot. Add the handler to the router (see bin/ping.rs).
    router.add_route(Route::Default, handle_chat_event);

    // Start the router in a background task.
    tokio::spawn(async move {
        info!("Starting router...");
        router.start().await;
    });

    // We're in the foreground. Create a new chat session with the bot, providing your
    // username. This shows up in the `from` field of messages.
    let chat = fakeserver.create_chat("qubyte").await;

    // Send the message "ping1", expect the response "pong(1): ping1"
    chat.send_text("ping1").await.unwrap();
    assert_eq!(
        chat.recv_update().await.unwrap().to_string(),
        "pong(1): ping1"
    );

    // Send the message "ping2", expect the response "pong(2): ping2"
    chat.send_text("ping2").await.unwrap();
    assert_eq!(
        chat.recv_update().await.unwrap().to_string(),
        "pong(2): ping2"
    );

    // Optional: validate there's no more messages from the bot, by waiting two seconds
    // for more messages.
    assert!(
        tokio::time::timeout(Duration::from_millis(2000), chat.recv_update())
            .await
            .is_err()
    );

    // All done shutdown the router, and wait for it to complete.
    info!("Shutting down...");
    shutdown_tx.send(()).await.unwrap();
    shutdown_notifier.notified().await;
}

扩展 MOBOT

添加新的Telegram API调用

添加对额外API的支持很简单。它涉及在 lib/api 中创建请求和响应的 struct,并添加到 API 的方法。

例如,为了添加对 sendSticker Telegram API 的支持

创建 SendStickerRequest 结构体

确保将 BotRequest 特征推导到请求中。

#[derive(Debug, Serialize, Clone, BotRequest)]
pub struct SendStickerRequest {
    /// Unique identifier for the target chat or username of the target
    pub chat_id: i64,

    /// Sticker to send. Pass a file_id as String to send a file that
    pub sticker: String,

    /// Sends the message silently. Users will receive a notification with
    #[serde(skip_serializing_if = "Option::is_none")]
    pub disable_notification: Option<bool>,

    /// If the message is a reply, ID of the original message
    #[serde(skip_serializing_if = "Option::is_none")]
    pub reply_to_message_id: Option<i64>,
}

send_sticker 方法调用添加到 API


impl API {
    pub async fn send_sticker(&self, req: &SendStickerRequest) -> anyhow::Result<Message> {
        self.client.post("sendSticker", req).await
    }
}

测试并发送给我一个拉取请求

  • tests/ 中添加测试。如果需要,更新 lib/fake.rs 以进行客户端测试。
  • src/bin/ 中添加示例代码。
  • 提交并发送给我一个 PR!

发布版本

安装 Cargo Release - crate install cargo-release

运行

cargo update
cargo test
cargo doc
git commit -a -m '...'

# Cut release
cargo release --execute patch

外部依赖

此软件包需要 OpenSSL 和 pkg-config

  • 在 Linux 上: sudo apt-get install pkg-config libssl-dev
  • 在 Mac 上:无需操作!

待办事项

  • 默认日志处理程序
  • 默认身份验证处理程序
  • 对话框/脚本框架
  • 收集旧会话

许可

MIT 许可证 版权 2023 Mohit Muthanna Cheppudira

特此授予任何获得此软件和相关文档副本(“软件”)的人免费处理软件的权利,包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或出售软件副本的权利,并允许向软件提供者提供软件的人这样做,前提是遵守以下条件

上述版权声明和本许可声明应包含在软件的所有副本或实质性部分中。

软件按“原样”提供,不提供任何明示或暗示的保证,包括但不限于适销性、针对特定目的的适用性和非侵权性。在任何情况下,作者或版权所有者均不对任何索赔、损害或其他责任负责,无论此类责任是基于合同、侵权或其他方式,无论此类责任源于、因之而产生或与此类软件或软件的使用或其他交易有关。

依赖关系

~10–24MB
~365K SLoC