用CoolQ Http Api搭建qq小机器人全过程(环境设置)

因为租了一个小vps,想着索性就弄一个小qq机器人群在群里活跃算了,以前用qqbot写的时候感觉很简单,仔细一搜发现随着webqq的smartqq协议关闭之后,死掉了一大批qqbot基于的机器人,现在想收发麻烦的多了。

目前来说,好像唯一活着还可以用的就是酷q。这是一个闭源软件,虽然功能也算强大,但可定制的功能比较少,都要通过他的插件来实现,而且只能在windows上面用,单纯为了小机器人买一个windows服务器也太不值了点,直接这么用酷q肯定是不行的。

万幸这里有一个叫做CoolQ http api的插件(https://github.com/richardchien/coolq-http-api)可以通过酷q来实现接受和发送消息的能力。

然后在这个CoolQ http api的基础上,更进一步有一个wrapper的library叫做Nonebot(https://github.com/richardchien/nonebot)的插件,基本实现了所有以前qqbot的功能。写机器人可以简单到用这个library加上图灵api或者其他api即可(并没有打算做成多fancy的机器人就是)。

但遗憾的是这个Nonebot整个安装过程中因为设计到linux通过docker镜像文件安装windows上面软件,以前没有用过docker的我在不少小地方卡了半天,特别写出来记录一下。

  1. Docker的基础单位叫做container

每一个docker container可以run program,在里面写数据。每次把container删掉的时候,所有数据都会消失不见。

  1. 从host到container的network的链接方法有两种。

Bridge:

通过publish port把container内部的port和外面的port相关。

比如在container 内部打开localhost:8080 然后publish port的时候 -p 7000:8080, 就可以直接在外面通过localhost:7000来进入container内部的8080。(和ssh的port forward很接近)

Network host:

这种相对来说简单多了,就是container内部也能用外面的network。但这次酷q docker镜像文件中貌似已经制订了vnc相关的东西,直接用network=host的时候打开ip:9000没反应,也不知道为什么

后来卡了我很长时间的东西就是在Bridge 模式的container内部,如何访问host的ip address。

这件事情本身并不难,通过执行

ip addr

可以看到这里面有着如下的网络

3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:30:76:8b:92 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:30ff:fe76:8b92/64 scope link
       valid_lft forever preferred_lft forever

这个docker就是 container的网络。也就是说“172.17.0.1” 是host的IP address。

但问题在于,当在host打开一个server后(比如端口6900),不管在container里怎么 curl 172.17.0.1:6900, 类似下面

在宿主机内

[hongxiaoyu@vultr ~]$ curl 127.0.0.1:6900

<!doctype html>
<title>405 Method Not Allowed</title>
<h1>Method Not Allowed</h1>
Specified method is invalid for this resource

但是在container内, 却一直都是connection refused

找了半天原因(刚开始都没有意识到是这个docker的network connection的原因),才发现是CentOS的防火墙屏蔽了docker 的network

所以在防火墙里加上这么一句

sudo iptables -I INPUT 3 -i docker0 -j ACCEPT

然后再在container内curl 172.17.0.1:6900就可以链接上了。

这个是一个很关键的点能不能导致coolq http api运行成功,因为coolq http api在container内要通过事件上报来和host的server进行交流。

  1. 具体来讲到CoolQ Http API和Nonebot

这边Nonebot的说明写的已经非常好了(https://nonebot.cqp.moe/guide/) ,上面的内容基本涵盖了所有有关的点。

CoolQ Http API 提供了三种通信方式,Nonebot支持了其中两点HTTP和反向Websocket,我对Websocket不是很了解,具体来说似乎比HTTP要更效率高一点,因为每次链接不需要重新打开channel?

总之具体的安装过程如下

$ docker pull richardchien/cqhttp:latest
$ mkdir coolq  # 用于存储 酷Q 的程序文件
$ docker run -ti --rm --name cqhttp-test \
             -v $(pwd)/coolq:/home/user/coolq \  # 将宿主目录挂载到容器内用于持久化 酷Q 的程序文件
             -p 9000:9000 \  # noVNC 端口,用于从浏览器控制 酷Q
             -p 5700:5700 \  # HTTP API 插件开放的端口
             -e COOLQ_ACCOUNT=123456 \ # 要登录的 QQ 账号,可选但建议填
             -e CQHTTP_POST_URL=http://172.17.0.1:8080 \  # 事件上报地址
             -e CQHTTP_SERVE_DATA_FILES=yes \  # 允许通过 HTTP 接口访问 酷Q 数据文件
             richardchien/cqhttp:latest

其中需要强调的是CQHTTP_POST_URL,这是从container内部往host服务器上传递信息的关键url。

因为我们前面已经发现了container内部看host的ip 地址是 172.17.0.1,这里需要写成 172.17.0.1:8080(端口无所谓)。

两个从container内部publish到外面的端口分别是9000和5700.

其中9000是coolq用来打开coolq的断开,publish出来后我们可以在外面通过服务器的ip:9000来登陆酷q。

5700端口是HTTP api插件用来发信息(而不是receive信息)的端口,我们可以通过这个端口来发信息。

8080端口不能被publish,因为host的服务器(要自己写)要listen这个端口,所以http插件可以上报上去。

(如果要运行在后台,就把—rm变成-d,然后docker start <container_name> 就行)

然后根据Nonebot在文档里写的配置要求一样,在”coolq/app/io.github.richardchien.coolqhttpapi/config/<qq number>.ini”里面加这三行

ws_reverse_api_url = ws://172.17.0.1:12345/ws/api/
ws_reverse_event_url = ws://172.17.0.1:12345/ws/event/
use_ws_reverse = true

打开Websocket反向通道,然后在UI中关掉酷q重启就完成了除服务器以外的所有配置。

  1. Host机器这边。

Host机器这边就简单多了,主要来说就是创建一个服务器,用来listen这个8080的端口,然后在每收到事件上报的时候做出反馈就行。

这就是nonebot library的作用。

import nonebot

if __name__ == '__main__':
    nonebot.init()
    nonebot.load_builtin_plugins()
    nonebot.run(host='0.0.0.0', port=12345)

然后run这个code,就建立了一个简单的服务器。

(服务器的作用就是核心的机器人如何反应的部分)

这时候终端应该出现这两行

[2019-12-16 10:01:34,058] 172.17.0.2:54679 GET /ws/event/ 1.1 101 - 1405
[2019-12-16 10:01:34,061] 172.17.0.2:59878 GET /ws/api/ 1.1 101 - 506

这表明http coolq api已经成功上报成功了,我们可以实现一些有的没的机器人功能了w/。

这时候,如果在qq上输入”/echo Hello, World”,小机器人就可以回复”Hello, World”,果然hello,world就是机器人的浪漫啊w

为什么回复了两条我也不知道hh,可能是小机器人太激动了吧。

总之自从qqbot挂掉之后,想在服务器上设置小机器人这可能是唯一的方法了吧。

至于真正机器人部分如何去写可能下一次会写?不过那部分相对来说就简单的多,最难的永远是environment的setup。。。。

——————

对了,一些docker的command感觉还是记录一下比较好

#用来run某一个程序
sudo docker run -ti --rm --name cqhttp-test …

#用来start某个程序
sudo docker start <name>

#用来stop某个程序
sudo docker stop <name>

#用来list所有的container
sudo docker container ls

#用来remove某个container
sudo docker container rm <containerid>

#用来进入container
sudo docker exec -it <containerid> bash

然后在container 内部我们可以执行通常的linux command,类似于

sudo apt-get update
sudo apt-get install telnet

等等,对于debug的时候有帮助。

总之遇到无法连接的情况比起怀疑自己的code有没有问题,先去看看是不是网本来就不通…..上次工作的时候就干了一样的蠢事这次又犯了(捂脸)

发表评论

电子邮件地址不会被公开。 必填项已用*标注