专栏首页owentRust玩具-企业微信机器人通用服务

Rust玩具-企业微信机器人通用服务

新玩具-企业微信机器人

这个机器人其实蛮久前就做好了,现在才写了点分享出来。 最近企业微信不断地开放了机器人的接口,所以我想想拿来做一些开发工具集成也是挺不错的,顺便也是为了继续熟悉一下 Rust 的编程习惯。 那么这次就大量使用 futures 来实现这个机器人的接口服务,这也是即将到来的无栈协程语法糖 await 的基石。

企业微信机器人大体上分为两个部分,第一个部分是主动推送消息。就是机器人创建好以后,会给一个地址,用这个地址按文档发json的HTTP/HTTPS请求就可以用机器人发消息了。这类接口给的消息种类比较多,图片、功能及其首先的Markdown、带At功能的文字等都可以。这个主动发消息的接口我就用 python 实现了。

机器人主要是实现Web Server监听来自企业微信的消息,

graph LR; 收包-->Dispatch; Dispatch-->鉴权; 鉴权-->解密; 解密-->执行处理; 执行处理-->打包; 打包-->加密; 加密-->二次打包; 二次打包-->Response;

jQuery(function() { var diagram_id = "process_wxwork_robot"; var diagram_jdom = jQuery("#" + diagram_id); var css_objs = { "text-align": "center" }; diagram_jdom.css(css_objs); try { mermaid.init(undefined, diagram_jdom, function() { console.log("done"); }); } catch(e) { diagram_jdom.empty(); diagram_jdom.append($('<pre></pre>').css({ "text-align": "left" }).html(e.message)); } });

这个流程。截至到我写这篇分享为止,回包还仅支持Markdown和Text两种。 先贴下成果吧: https://github.com/owt5008137/wxwork_robotd

关于文献

Rust 官网改版了,之前的 《Rust 程序设计语言》 变得很难找到了,这里记录下这本书的地址:

现在翻译版本也很完整了,但是第一版英文原版似乎被删除了,其实我觉得第二版的关于宏的部分讲得很模糊,特别是过程宏。Rust 现有的很多库的语法糖和高级特新都是过程宏,它允许在编译期直接对抽象语法树(AST)做Patch,十分强大(我还是很怀疑这样工程规模大了以后编译是不是也是奇慢无比)。这方面也结合一下原来第一版的文档和其他的一些文档(我之前文章里贴的 https://danielkeep.github.io/tlborm/book/index.html )。

企业微信机器人的通用服务接入

前面也贴了大致的流程,实际执行的时候还有一些工作在 执行处理 这个阶段。首先我想要支持多个命令,于是对输入消息就采用了正则表达式的方式。用输入的消息依次匹配到一个可以匹配到的语句,然后执行内容。另外考虑到想要一个机器人服务可以提供多个机器人,并且可以共用一部分命令,所以机器人服务内部加了一个 项目 机制首先通过 URL找到对应的项目, 然后指令部分分为了 公共指令项目指令 。收到消息后先去匹配 项目指令 ,如果匹配不成功再去匹配 公共指令 , 还是不成功的话依次查找 项目指令公共指令 指令里的默认项目。

一开始我接入的 执行处理 的实际执行内容的时候,考虑的是接入内部的CI系统。所以行为是访问一个HTTP请求,当然要支持多个的话必然涉及变量。我找到一个看起来还不错的模板引擎 handlebars 就用它对部分变量做参数填充了。而后为了测试方便增加了echo命令来直接输出消息;为了统一自动输出帮助消息增加了help命令来自动生成所有可用的命令描述然后数据;为了更灵活增加了spawn命令用于起一个子线程执行任意脚本或程序。 为了方便子进程里读取到接出来的企业微信的消息数据把配置的变量和一些匹配结果都写到了环境变量里,这样子进程或者脚本直接读取对应的环境变量就行了。

大致流程就是这样:

graph TB; 执行消息-->URL查找项目; URL查找项目-->项目1; URL查找项目-->项目2-命中; URL查找项目-->项目3; URL查找项目-->项目...; 项目2-命中-->匹配项目指令; 匹配项目指令-->项目指令1; 匹配项目指令-->项目指令2; 匹配项目指令-->项目指令...; 匹配项目指令-->全部失败则匹配全局指令; 全部失败则匹配全局指令-->全局指令1; 全部失败则匹配全局指令-->全局指令2; 全部失败则匹配全局指令-->全局指令...; 项目指令2-->命中指令; 全局指令1-->命中指令; 命中指令-->准备执行环境; 准备执行环境-->执行内容; 执行内容-->打包结果; 打包结果-->构造回包;

jQuery(function() { var diagram_id = "dispatch_wxwork_robot"; var diagram_jdom = jQuery("#" + diagram_id); var css_objs = { "text-align": "center" }; diagram_jdom.css(css_objs); try { mermaid.init(undefined, diagram_jdom, function() { console.log("done"); }); } catch(e) { diagram_jdom.empty(); diagram_jdom.append($('<pre></pre>').css({ "text-align": "left" }).html(e.message)); } });

在第一阶段实现完成之后,企业微信又增加了分享机器人的功能。这样一个机器人的URL就可能对应多个群,我们原来有个脚本为了发送图片回去,是收到消息后启动一个后台脚本,执行完调用发消息的接口去发送结果的,而这么一来以后,原来的发布消息的接口变成了群发。 后来我看了下它也增加了个一个 ChatId 字段和 GetChatInfoUrl 字段。前面一个用于区分来源的群,收到消息以后。发消息接口附带这个参数就能实现仅回复来源的群,而后一个接口是用于拉取来源群的信息的。

另外我们内网的地址和外部的机器人地址不一样,所以为了方便我也是提取出了机器人的KEY,以便后台任务执行完后通知的时候直接用转换后的地址。还有些零零碎碎的字段都在最开始贴的项目地址里了。

跨平台构建cross和自动release

之前也提到rust的嵌入式小组提供了交叉编译的工具链 cross 。这其实是一套基于docker的工具链集合,帮我们把一些通用的依赖库和工具链准备好了,这样我们就不用每个环境自己去配交叉编译环境。 我就依赖这个部署了 appveyor和travis-ci的自动部署服务。

在使用过程中我发现这套工具还不是非常稳定,特别是MIPS架构下有些很基础的库构建不出来,当然这也算是这些库的构建脚本或者代码有点问题。所以最终我只提供了我测试能够打包出来的几个版本,至少目前Linux的ARM、ARM64、x86、x86_64和和Windows的x86、x86_64没什么太大问题,部分架构下的musl工具链也编不出来。最终自动发布的结果都放在 https://github.com/owt5008137/wxwork_robotd/releases 了,以后发现有新的可用适配环境的话再加吧。

大家有兴趣也可以下载自己需要的架构的预编译好的机器人发布包自己Happy自己玩。 README.md 里的用法说明应该还是比较完整易懂的。

写在最后

倒腾完这个小玩具,我也基本上了解了 rustfutures 的设计模型和设计思路了吧。通过标准化的依赖反转来减轻开发人员的心智负担,同时为了静态类型语言而做的各种类型转换着实是有点绕,要各种 map 结果和 map_err ,如果涉及join操作可能还要提取结果,也是有点反人类。等新版出来移除了强制的Error类型依赖应该会简单一些。另外还有不同futures之间的参数传递要保证最优的生命周期管理就只能借助它的零开销移动语义,通过Result或者Error传递给下一跳了,这个在 await 功能标准化了以后也能解决这个问题。

C++下一代里的协程设计也差不多是这个思路,可惜C++不支持过程宏,所以接入起来目前看来非常的恶心,也很不直观。印象中挺久以前有位大神提了个编译期反射的草案,看起来有点过程宏的意思,但是还没强大到到能够修改语法树的程度。

Rust 的路还很长远,期待ing…。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 整理一波软件源镜像同步工具+DevOps工具

    上个月,同学的公司,格奕,突然间跪了。这个月基本属于休息+四处溜达。同时空闲的时候也想整理下之前做得一些之前的做得一些小工具们。在不泄密的情况下开源出来吧(其实...

    owent
  • 最长单调子序列 复杂度nlog(n)

    owent
  • 使用restructedtext编写xresloader文档

    离上一次写Blog过了好久啦。这次拖这么长时间主要是因为最近学习了一个新的文本标记语言 – ReStructuredText 。并且重新整理了Excel导表工具...

    owent
  • WPF 从 DrawingVisual 转 BitmapImage 图片

    有一些库的设计是需要传入一个 BitmapImage 图片,但是我需要从界面代码创建图片,我没有文件,如何通过 DrawingVisual 画出的控件转换 Bi...

    林德熙
  • 特写李飞飞:她激励了人工智能的发展,更要给人工智能赋予人的价值

    AI 科技评论按:李飞飞无疑是人工智能界最响亮的名字之一。她既对机器学习领域的发展做出了杰出的贡献,也是普通大众眼中温和的人工智能技术宣扬者,还是谷歌这一科技...

    AI科技评论
  • 启动物联网项目所需的一切:第 3 章

    原文地址:https://dzone.com/articles/everything-you-need-to-start-your-iot-project-pa...

    未来守护者
  • Yii2 自定义类

    <?php // 这里假设放到 vendor/tk/extensions/Utils.php namespace tk\extensions; /** ...

    botkenni
  • Python初学——窗口视窗Tkinter

    此篇文章是跟着沫凡小哥的视频学习的,附上学习网址:https://morvanzhou.github.io/tutorials/python-basic/ 什么...

    闪电gogogo
  • 海量数据处理技术学习

      外排序:因为海量数据无法全部装入内存,所以数据的大部分存入磁盘中,小部分在排序需要时存入内存。

    用户3003813
  • Jmeter体系结构和基本原理

    Jmeter在不断的升级的过程中功能不断增加,越来越强大。Jmeter至今已更新Apache JMeter 5.1.1 (Requires Java 8+)版本...

    Altumn

扫码关注云+社区

领取腾讯云代金券