前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【每周一库】- teloxide (电报群机器人)

【每周一库】- teloxide (电报群机器人)

作者头像
MikeLoveRust
发布2020-11-16 15:33:12
3.2K0
发布2020-11-16 15:33:12
举报
文章被收录于专栏:Rust语言学习交流

一个功能齐全的框架,让你能使用Rust中的async/.await语法轻松构建电报群机器人。将困难的工作交给框架,你只需关注业务逻辑。

亮点

  • 函数式响应编程 teloxide遵循函数式响应设计模式,可以让您使用filters, maps, folds, zips和许多其他适配器声明式地操作来自电报的更新流。
  • 对话管理子系统 我们的对话管理子系统易于使用,且对话的存储方式/位置是不可知的。例如,你可以只替换一行来实现永久保留。开箱即用的存储方式包括Redis和Sqlite。
  • 强类型的机器人命令 你可以将机器人命令以枚举形式描述,然后它们将由字符串自动生成——像serve-json中的JSON结构和structopt中的命令行参数一样。

环境配置

  1. 下载Rust。
  2. 用@Botfather 创建一个新的机器人,得到一个格式为 123456789:blablabla的认证凭证。
  3. 将环境变量:TELOXIDE_TOKEN 数值初始化为你得到的认证凭证的哈希。
代码语言:javascript
复制
# Unix-like
$ export TELOXIDE_TOKEN=<Your token here>

# Windows
$ set TELOXIDE_TOKEN=<Your token here>
  1. 确保你的 Rust 编译器是最新版:
代码语言:javascript
复制
# 如果你在用稳定分支
$ rustup update stable
$ rustup override set stable

# 如果你在用每日构建分支
$ rustup update nightly
$ rustup override set nightly
  1. 运行cargo new my_bot, 进入文件目录将以下内容放进 Cargo.toml:
代码语言:javascript
复制
[dependencies]
teloxide = "0.3"
teloxide-macros = "0.3"

log = "0.4.8"
pretty_env_logger = "0.4.0"

tokio = { version =  "0.2.11", features = ["rt-threaded", "macros"] }

API 总览

骰子机器人

这个机器人会在每次收到消息时掷出随机骰子:

(完整)

代码语言:javascript
复制
use teloxide::prelude::*;

#[tokio::main]
async fn main() {
   teloxide::enable_logging!();
   log::info!("机器人启动中...");

   let bot = Bot::from_env();

   teloxide::repl(bot, |message| async move {
       message.answer_dice().send().await?;
       ResponseResult::<()>::Ok(())
  })
  .await;
}

命令

命令是强类型的声明式, 和我们在serde-json中使用 structopt 和JSON结构定义CLI类似,下列机器人接受以下命令

  • /username <你的用户名>
  • /usernameandage <你的用户名> <你的年龄>
  • /help

(完整)

代码语言:javascript
复制
use teloxide::{utils::command::BotCommand, prelude::*};

#[derive(BotCommand)]
#[command(rename = "lowercase", description = "These commands are supported:")]
enum Command {
   #[command(description = "帮助文本内容")]
   Help,
   #[command(description = "处理用户名")]
   Username(String),
   #[command(description = "处理用户名和年龄", parse_with = "split")]
   UsernameAndAge { username: String, age: u8 },
}

async fn answer(cx: UpdateWithCx<Message>, command: Command) -> ResponseResult<()> {
   match command {
       Command::Help => cx.answer(Command::descriptions()).send().await?,
       Command::Username(username) => {
           cx.answer_str(format!("你的用户名是 @{}.", username)).await?
      }
       Command::UsernameAndAge { username, age } => {
           cx.answer_str(format!("你的用户名是 @{} 年龄是 {}.", username, age)).await?
      }
  };

   Ok(())
}

#[tokio::main]
async fn main() {
   teloxide::enable_logging!();
   log::info!("命令机器人启动中...");

   let bot = Bot::from_env();

   let bot_name: String = panic!("机器人名称");
   teloxide::commands_repl(bot, bot_name, answer).await;
}

对话管理

对话是由一个枚举来描述的,其中每个变体都是可能的对话状态之一。还有子过渡函数,将对话从一个状态转到另一个状态,从而形成一个有限状态机。

下面是一个机器人,它会问你三个问题,然后把答案反馈给你。首先,让我们从一个枚举(我们对话的状态集合)开始。

(dialogue_bot/src/dialogue/mod.rs)

代码语言:javascript
复制
// 略去Imports...

#[derive(Transition, From)]
pub enum Dialogue {
   Start(StartState),
   ReceiveFullName(ReceiveFullNameState),
   ReceiveAge(ReceiveAgeState),
   ReceiveLocation(ReceiveLocationState),
}

impl Default for Dialogue {
   fn default() -> Self {
       Self::Start(StartState)
  }
}

当用户向我们的机器人发送消息,而这样的对话还不存在时,Dialogue::default()将会被调用,本例中为Dialogue::Start。每收到一条消息,就会提取一个相关的对话,然后传递给一个相应的子过渡函数:

Dialogue::Start

Dialogue::ReceiveFullName

Dialogue::ReceiveAge

Dialogue::ReceiveLocation

所有这些子过渡函数都接受一个相应的状态("对话 "的许多变体之一)、上下文或文本消息。它们返回TransitionOut<Dialogue>,例如从<你的状态类型>Dialogue的映射。

最后,main函数是这样的:

(dialogue_bot/src/main.rs)

代码语言:javascript
复制
// 略去Imports...

#[tokio::main]
async fn main() {
   teloxide::enable_logging!();
   log::info!("对话机器人启动中");

   let bot = Bot::from_env();

   teloxide::dialogues_repl(bot, |message, dialogue| async move {
       handle_message(message, dialogue).await.expect("机器人出错!")
  })
  .await;
}

async fn handle_message(cx: UpdateWithCx<Message>, dialogue: Dialogue) -> TransitionOut<Dialogue> {
   match cx.update.text_owned() {
       None => {
           cx.answer_str("Send me a text message.").await?;
           next(dialogue)
      }
       Some(ans) => dialogue.react(cx, ans).await,
  }
}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-11-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Rust语言学习交流 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 亮点
  • 环境配置
  • API 总览
    • 骰子机器人
    相关产品与服务
    云数据库 Redis
    腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档