MiraiGo-CQHTTP-hakuBot
haku-bot,小白哥哥:面向过程的,利用go-cqhttp在龙芯和其他平台快速构建的QQ机器人。
接下来将致力于将其用C语言重写,故此后该项目将不会有较大的更新。
实现的功能
主程序
- 程序启动时线程启动失败重试
- 在终端打印接收到消息的整个dict
- 在终端打印发送消息的整个GET请求
- 在终端打印错误信息
- 定时在终端打印机器人流量
- 部分api可以通过函数调用
- 智zhi能zhang复读机
- 群提醒(支持命令)
- 欢迎新人
- 被at回复
已经函数实现的 api 见 hakuCore/botApi.py ,未实现的可以自行实现,具体参照 go-cqhttp 的 http 请求格式即可。
插件
- about 回复关于信息
- help 回复帮助信息
- ping 检测机器人是否在工作
- echo 人类的本质(类似有 repeat 插件)
- time 回复指定时区的当前时间
- bc 简单的四则运算计算器
- music 网易云音乐搜索
- qqmusic qq音乐搜索
- weather 和风天气实时
- forecast 和风天气预报
- run glot代码在线运行
- yiyan 一言搜索
- log 返回小白的状态
- timertest* 自动提醒测试
- atall* 群发消息
ps: 带*为管理员指令,可在插件中分别设置允许的QQ id
依赖于
- go-cqhttp 使用 mirai 以及 MiraiGo 开发的cqhttp golang原生实现
- Python3.6 尽量使用了较底层的标准库,在龙梦Fedora28平台编写测试,不考虑Windows平台兼容性。
使用到的库
主程序
- importlib
- json
- math
- os
- random
- socket
- threading
- time
插件额外依赖
- requests: qqmusic, yiyan, weather, forecast, run
目的
用于Python的学习和交流。
快速上手
配置
在 hakuCore/config.py
中设置监听的地址和端口等即可。带星号“*”的字段必须重新设置并保证其正确性,其他字段可以保留其默认值
- BUF_SIZE socket接收和发送一个包的大小
- TESTQQID 测试程序时私发消息的qq号
- HOST 和go-cqhttp通信的ip *
- RECEIVEPORT go-cqhttp上报消息的端口 *
- SENDPORT cq-cqhttp接受消息的端口 *
- TIKEN cq-cqhttp的access_token *
- INTERVAL 每分钟go-cqhttp发送的心跳个数,默认12
- PROFIX 命令前缀设置,默认
':'
(不包含引号)
运行
python3 main.py
运行,也可以通过脚本 ./haku.sh
运行。
若在远程服务器上运行需要用 screen 等工具挂在后台。
停止运行
有两种方式可以停止程序的运行。
- 终端 Ctrl+C(按一次即可,按多次可能造成结束工作被打断!)
- 向程序接受go-cqhttp上报消息的端口(即HOST:RECEIVEPORT)发送一个POST请求。请求头中包含
X-Self-Id
关键字,值为1009
;包含Content-Length
关键字,值为0
。
POST请求示例(可以参考 main.py 中的 sendQuitPackage() 函数):
POST / HTTP/1.0
X-Self-Id: 1009
Connect-Length: 0
server
main.py
创建了一个线程运行 server.py
。 server.py
监听 go-cqhttp 的上报并将接收到的 json 转换为 dict ,并调用 hakuCore/hakuCore.py
。如果是心跳,则会调用 hakuHeart()
触发时间事件;反之把 dict 发送给 haku()
函数处理回应或再将其发送给 plugins 包下的相应插件回应。
hakuCore
hakuCore 包是机器人的核心内涵,其中 config.py
用于参数设置, hakuCore.py
对所有信息进行处理和分发, botApi.py
作为回应 go-cqhttp 的接口, tcpSend.py
(通常不需要手动调用)向 go-cqhttp 发送包, logging.py
打印和记录日志以及自动复读机的实现, timeEvent.py
读取时间事件相关文件, authorisasion.py
是小白的所有权利(token/key)。
hakuCore.py
接受一个 dict ,这个 dict 和 go-cqhttp 上报的 json 格式一致,主要包含:
- "message_type" 事件类型。群消息:"group",私发消息:"private"
- "group_id" 群号,群消息和临时会话有此字段
- "user_id" QQ号,私发消息和临时会话有此字段
- "raw_message" 信息,收到的信息
- "message" 同"raw_message"
- "self_id" 机器人自己的qq号
hakuCore.py
主要有两个方法: haku()
和 hakuHeart()
。 haku()
负责消息触发的事件, server.py
收到消息后会传到这里处理; hakuHeart()
则负责时间触发的事件, server.py
收到心跳后会触发 hakuHeart()
一次,该事件由 hakuHeart()
和 timeEvent.py
协同处理。所有线程都在这里产生、灭亡和销毁。
timeEvent
hakuCore/timeEvent.py
读取时间相关事件的配置,这些配置是在 data/groupDay
文件夹中的纯文本文件。**它们都以对应的群号或QQ号命名,且均没有后缀。**如群号123的配置文件,文件名即为 123
;同理QQ号为456的用户的配置文件,文件名即为 456
。这个功能通常用于定时提醒。
配置均遵循一行一个记录,时间戳+空格+消息文本。按日提醒则时间戳以 mmdd
格式,按时间提醒则时间戳以 hhmm
格式。如每年十月一日自动发送“祖国母亲生日快乐”: 1001 祖国母亲生日快乐
;每天晚上十点自动发送“晚安”: 2200 晚安
。消息文本内可以有空格但是不能有换行,并列的多余空格会被忽略而只有一个空格,格式错误的记录会被忽略或消息文本发送不全。若一个记录以命令格式开头,则其会被发送给对应的插件执行;若出错,日志中将记录错误信息。若需要原样发送一个命令,可以调用 echo
、 repeat
等插件。
同一时间的多条记录:非命令的记录按出现顺序合并发送;命令按出现顺序逐条执行。
已经实现时间事件的有:
- 群内按日提醒:配置放在
data/groupDay
文件夹中,在凌晨零点发送(可以在 hakuCore/hakuCore.py 中更改)。 - 群内每日按时间提醒:配置放在
data/groupTime
文件夹中。
logging
hakuCore/logging.py
用于日志的记录,日志文件在 data/log
文件夹下,日志第一行是程序启动的时间,重启程序并不会覆盖日志,旧日志会被重命名。
hakuCore/logging.py
中 printLog(logType, logInfo)
和 directPrintLog(logInfo)
两个函数在将日志信息打印在终端的同时在日志文件中记录之,所以推荐用 directPrintLog(logInfo)
代替 print()
,以防一些错误被遗漏。 printLog(logType, logInfo)
则会在信息上加上时间戳, logType
是自定义的错误类型,如 "ERROR"、"INFO" 等。
插件开发
所有插件在 plugins 目录下,命令名即文件名,使用 PREFIX
+命令名调用。 PREFIX
在 hakuCore/config.py
中设置,默认为 ':'
。如 ping
命令,对应插件名为 ping.py
,当hakuBot收到 :ping
时自动调用这个插件。
插件必须包含一个 main()
方法,其具有一个参数,当调用时会传给 main()
一个 dict ,这个 dict 包含这个事件的所有信息,其格式上面已经阐述。 main()
方法可以返回一个 str
,用于回应,也可以无返回值。
插件可以做任何事,包括自由调用 plugins
和 hakuCore
下的任何模块。常见的是调用 hakuCore.botApi
下的方法发送消息进行除返回值外的回应。
具体可以参考已经编写好的插件。
参考资料
其他
- go-cqhttp 需要交叉编译为 mips64le 。暂时没有官方的 mips64le release。
- 程序中只是使用 socket 模拟了 http 协议的通信,虽然写 HTTP/1.0 但实际并没有完全遵循任何标准。
- 不要直接用 print 在终端显示信息,而用
hakuCore.logging
中的printLog
和directPrintLog
代替 。 - 不知道哪里的问题,程序退出以后端口并没有立即释放,重启间隔一分钟内会出现端口占用的错误。
- 我的小文章
By SDUST weilinfox