前言
好久没写博客了(同时前几篇也太水了),之前在折腾博客基建,这段时间也搞了一堆东西,虽然有记录,但是没时间整理一下然后写出来,刚好最近没有什么
事,本来想实践一下微信小程序和微信公众号的开发,奈何没有成年,申请不了,于是被打回来写qqbot,本着好玩的目的,但是实践的过程中还是遇到了一些困难,由于缺乏基本认识而踩了一堆坑
QQ 协议端搭建
没错,这个东西叫协议端!
目前比较常见的有:
- go-cqhttp (基于 MiraiGo)
- cqhttp-mirai-embedded
- Mirai + cqhttp-mirai
- Mirai + Mirai Native + CQHTTP
- OICQ-http-api (基于 OICQ)
- 酷Q (已停止开发)
(来自知乎)
我这里采用go-cqhttp,采用其他的基本也相同,最重要的是要基于onebot标准
关于如何搭建可以看文档
首先编写config.hjson
文件
1 | /* |
./go-cqhttp
运行后需要进行滑块认证,在浏览器抓取cap_union_new_verify
的返回值,然后把ticket的值输入就行了。
此时协议端搭建完毕
注:记得iptable开放相应端口
后端搭建
一、使用机器人框架
不得不说python的nonebot和nonebot2实在是太方便了,文档也十分详细。
如果你只是想要一个qqbot,推荐使用以上两个框架,大概几个小时就能实现一个bot
如果你想用go来写,也可以用ZeroBot来作为你的框架
二、写后端来调用协议
虽然框架很好用(单指python的库)
但由于觉得好玩,我还是头铁地使用了go来开发
找不到真正合适的go开发框架,于是自己写websocket来对接
go websocket的使用请自行学习,这里简单描述搭建服务的过程,细节可以参考我的代码部分https://github.com/RyaoChengfeng/rinqqbot/blob/main/controller/ws.go
- http监听ws反向端口
1
2
3
4
5
6controller.StartWebsocket()
err:= http.ListenAndServe(config.Addr+`:`+config.WsPort,nil)
if err != nil {
fmt.Println(err)
os.Exit(1)
} - 将http升级为ws并启动ws
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52type wsConnection struct {
wsSocket *websocket.Conn // 底层websocket
inChan chan *wsMessage // 读队列
outChan chan *wsMessage // 写队列
mutex sync.Mutex // 避免重复关闭管道,加锁处理
isClosed bool
closeChan chan byte // 关闭通知
id int64
}
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
// 允许所有的CORS 跨域请求,正式环境可以关闭
CheckOrigin: func(r *http.Request) bool {
return true
},
}
func StartWebsocket() {
WsConnAll = make(map[int64]*wsConnection)
http.HandleFunc("/", wsHandler)
}
func wsHandler(rsp http.ResponseWriter, req *http.Request) {
// 应答客户端告知升级连接为websocket
wsSocket, err := upgrader.Upgrade(rsp, req, nil)
if err != nil {
log.Logger.Error("升级为websocket失败", err.Error())
} maxConnId++
// 连接数保持一定数量,超过的部分不提供服务
// 如果要控制连接数可以计算WsConnAll长度 len(WsConnAll) wsConn := &wsConnection{
wsSocket: wsSocket,
inChan: make(chan *wsMessage, 1000),
outChan: make(chan *wsMessage, 1000),
closeChan: make(chan byte),
isClosed: false,
id: maxConnId,
}
WsConnAll[maxConnId] = wsConn
// 处理器,发送定时信息,避免意外关闭
go processLoop(wsConn)
// 读协程
go wsReadLoop(wsConn)
// 写协程
go wsWriteLoop(wsConn)
} - 在多线程中处理协议端发来的message,并提取信息进行调用协议端api
1
2
3
4
5
6err = json.Unmarshal(msg.data, &msgData)
if err != nil {
log.Logger.Error("json信息解析错误", err.Error())
}
//log.Logger.Debug("收到消息:",msgData)
HandleWsMsg(msgData) - 在
HandleWsMsg
中进行bot功能实现
message结构请参考对应的协议文档,以及基于onebot标准的协议的onebot标准,具体参考下方链接