1
0
mirror of https://github.com/Mrs4s/go-cqhttp.git synced 2025-06-30 20:03:24 +00:00

Compare commits

...

11 Commits

Author SHA1 Message Date
e2b6c3d607 doc update. 2020-08-01 10:57:48 +08:00
58a3f81142 new event: friend_recall. 2020-08-01 10:55:17 +08:00
64cb539c0d update MiraiGo. 2020-07-31 23:12:02 +08:00
3bb844d1d4 support group quit. 2020-07-31 12:45:52 +08:00
0fdb01e82c cqcode share supported. 2020-07-31 01:30:45 +08:00
7cf199189a doc update. 2020-07-30 22:11:52 +08:00
3aea70e92a fix concurrent write panic #6 2020-07-30 20:04:00 +08:00
d1505ec15d fix typo. 2020-07-30 19:45:47 +08:00
750a01acdd update README.md 2020-07-30 08:54:25 +08:00
a12dcfa2d7 add: group_upload event support.
add: simple debug.
2020-07-30 08:52:01 +08:00
86422c5a00 Update README.md 2020-07-29 22:02:09 +08:00
12 changed files with 97 additions and 15 deletions

View File

@ -13,6 +13,7 @@
- [x] 反向Websocket
#### 拓展支持
> 拓展API可前往 [文档](docs/cqhttp.md) 查看
- [x] HTTP POST多点上报
- [x] 反向WS多点连接
- [x] 修改群名
@ -45,6 +46,7 @@
| /set_group_kick | [群组T人](https://cqhttp.cc/docs/4.15/#/API?id=set_group_kick-群组踢人) |
| /set_group_ban | [群组单人禁言](https://cqhttp.cc/docs/4.15/#/API?id=set_group_ban-群组单人禁言) |
| /set_group_whole_ban | [群组全员禁言](https://cqhttp.cc/docs/4.15/#/API?id=set_group_whole_ban-群组全员禁言) |
| /set_group_leave | [退出群组](https://cqhttp.cc/docs/4.15/#/API?id=set_group_leave-退出群组) |
| /set_group_name | 设置群组名(拓展API) |
| /get_image | 获取图片信息(拓展API) |
| /get_group_msg | 获取群组消息(拓展API) |
@ -64,10 +66,12 @@
| [私聊信息](https://cqhttp.cc/docs/4.15/#/Post?id=私聊消息) |
| [群消息](https://cqhttp.cc/docs/4.15/#/Post?id=群消息) |
| [群消息撤回(拓展Event)](docs/cqhttp.md#群消息撤回) |
| [好友消息撤回(拓展Event)](docs/cqhttp.md#好友消息撤回) |
| [群管理员变动](https://cqhttp.cc/docs/4.15/#/Post?id=群管理员变动) |
| [群成员减少](https://cqhttp.cc/docs/4.15/#/Post?id=群成员减少) |
| [群成员增加](https://cqhttp.cc/docs/4.15/#/Post?id=群成员增加) |
| [群禁言](https://cqhttp.cc/docs/4.15/#/Post?id=群禁言) |
| [群文件上传](https://cqhttp.cc/docs/4.15/#/Post?id=群文件上传)|
| [加好友请求](https://cqhttp.cc/docs/4.15/#/Post?id=加好友请求) |
| [加群请求/邀请](https://cqhttp.cc/docs/4.15/#/Post?id=加群请求/邀请) |

View File

@ -273,6 +273,15 @@ func (bot *CQBot) CQSetGroupWholeBan(groupId int64, enable bool) MSG {
return Failed(100)
}
// https://cqhttp.cc/docs/4.15/#/API?id=set_group_leave-%E9%80%80%E5%87%BA%E7%BE%A4%E7%BB%84
func (bot *CQBot) CQSetGroupLeave(groupId int64) MSG {
if g := bot.Client.FindGroup(groupId); g != nil {
g.Quit()
return OK(nil)
}
return Failed(100)
}
// https://cqhttp.cc/docs/4.15/#/API?id=set_friend_add_request-%E5%A4%84%E7%90%86%E5%8A%A0%E5%A5%BD%E5%8F%8B%E8%AF%B7%E6%B1%82
func (bot *CQBot) CQProcessFriendRequest(flag string, approve bool) MSG {
req, ok := bot.friendReqCache.Load(flag)
@ -407,7 +416,7 @@ func (bot *CQBot) CQGetForwardMessage(resId string) MSG {
r = append(r, MSG{
"sender": MSG{
"user_id": n.SenderId,
"nick": n.SenderName,
"nickname": n.SenderName,
},
"time": n.Time,
"content": ToStringMessage(n.Message, 0, false),

View File

@ -51,6 +51,7 @@ func NewQQBot(cli *client.QQClient, conf *global.JsonConfig) *CQBot {
bot.Client.OnTempMessage(bot.tempMessageEvent)
bot.Client.OnGroupMuted(bot.groupMutedEvent)
bot.Client.OnGroupMessageRecalled(bot.groupRecallEvent)
bot.Client.OnFriendMessageRecalled(bot.friendRecallEvent)
bot.Client.OnJoinGroup(bot.joinGroupEvent)
bot.Client.OnLeaveGroup(bot.leaveGroupEvent)
bot.Client.OnGroupMemberJoined(bot.memberJoinEvent)

View File

@ -213,6 +213,8 @@ func (bot *CQBot) ToElement(t string, d map[string]string, group bool) (message.
}
t, _ := strconv.ParseInt(qq, 10, 64)
return message.NewAt(t), nil
case "share":
return message.NewUrlShare(d["url"], d["title"], d["content"], d["image"]), nil
default:
return nil, errors.New("unsupported cq code: " + t)
}

View File

@ -21,7 +21,7 @@ func (bot *CQBot) privateMessageEvent(c *client.QQClient, m *message.PrivateMess
"post_type": "message",
"message_type": "private",
"sub_type": "friend",
"message_id": m.Id,
"message_id": ToGlobalId(m.Sender.Uin, m.Id),
"user_id": m.Sender.Uin,
"message": ToStringMessage(m.Elements, 0, false),
"raw_message": cqm,
@ -40,6 +40,26 @@ func (bot *CQBot) privateMessageEvent(c *client.QQClient, m *message.PrivateMess
func (bot *CQBot) groupMessageEvent(c *client.QQClient, m *message.GroupMessage) {
checkImage(m.Elements)
for _, elem := range m.Elements {
if file, ok := elem.(*message.GroupFileElement); ok {
log.Infof("群 %v(%v) 内 %v(%v) 上传了文件: %v", m.GroupName, m.GroupCode, m.Sender.DisplayName(), m.Sender.Uin, file.Name)
bot.dispatchEventMessage(MSG{
"post_type": "notice",
"notice_type": "group_upload",
"group_id": m.GroupCode,
"user_id": m.Sender.Uin,
"file": MSG{
"id": file.Path,
"name": file.Name,
"size": file.Size,
"busid": file.Busid,
},
"self_id": c.Uin,
"time": time.Now().Unix(),
})
return
}
}
cqm := ToStringMessage(m.Elements, m.GroupCode, true)
id := m.Id
if bot.db != nil {
@ -164,6 +184,20 @@ func (bot *CQBot) groupRecallEvent(c *client.QQClient, e *client.GroupMessageRec
})
}
func (bot *CQBot) friendRecallEvent(c *client.QQClient, e *client.FriendMessageRecalledEvent) {
f := c.FindFriend(e.FriendUin)
gid := ToGlobalId(e.FriendUin, e.MessageId)
log.Infof("好友 %v(%v) 撤回了消息: %v", f.Nickname, f.Uin, gid)
bot.dispatchEventMessage(MSG{
"post_type": "notice",
"notice_type": "friend_recall",
"self_id": c.Uin,
"user_id": f.Uin,
"time": e.Time,
"message_id": gid,
})
}
func (bot *CQBot) joinGroupEvent(c *client.QQClient, group *client.GroupInfo) {
log.Infof("Bot进入了群 %v.", formatGroupName(group))
bot.dispatchEventMessage(bot.groupIncrease(group.Code, 0, c.Uin))

View File

@ -199,7 +199,7 @@ Type: `node`
{
"content": "合并转发1",
"sender": {
"nick": "发送者A",
"nickname": "发送者A",
"user_id": 10086
},
"time": 1595694374
@ -207,7 +207,7 @@ Type: `node`
{
"content": "合并转发2[CQ:image,file=xxxx,url=xxxx]",
"sender": {
"nick": "发送者B",
"nickname": "发送者B",
"user_id": 10087
},
"time": 1595694393
@ -247,3 +247,14 @@ Type: `node`
| `operator_id` | int64 | | 操作者id |
| `message_id` | int64 | | 被撤回的消息id |
#### 好友消息撤回
**上报数据**
| 字段 | 类型 | 可能的值 | 说明 |
| ------------- | ------ | -------------- | -------------- |
| `post_type` | string | `notice` | 上报类型 |
| `notice_type` | string | `friend_recall`| 消息类型 |
| `user_id` | int64 | | 好友id |
| `message_id` | int64 | | 被撤回的消息id |

View File

@ -16,6 +16,7 @@ type JsonConfig struct {
WSConfig *GoCQWebsocketConfig `json:"ws_config"`
ReverseServers []*GoCQReverseWebsocketConfig `json:"ws_reverse_servers"`
Proxy string `json:"proxy"`
Debug bool `json:"debug"`
}
type CQHttpApiConfig struct {

2
go.mod
View File

@ -3,7 +3,7 @@ module github.com/Mrs4s/go-cqhttp
go 1.14
require (
github.com/Mrs4s/MiraiGo v0.0.0-20200729044443-98a77a6cf354
github.com/Mrs4s/MiraiGo v0.0.0-20200801022834-8f1c0c053a86
github.com/gin-gonic/gin v1.6.3
github.com/gorilla/websocket v1.4.2
github.com/guonaihong/gout v0.1.1

10
go.sum
View File

@ -1,11 +1,9 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Mrs4s/MiraiGo v0.0.0-20200727124316-9d432df098d9 h1:sgwJQnKKAJF/FCXyGv5HHpE5BcKGnwGyCSmPKTB7/vE=
github.com/Mrs4s/MiraiGo v0.0.0-20200727124316-9d432df098d9/go.mod h1:M9wh1hjd0rie3+wm27tjPZkYMbD+MBV76CGqp2G7WSU=
github.com/Mrs4s/MiraiGo v0.0.0-20200728112613-91aa75e8270d h1:Pv8lvODPBb+By7CU1crF0/KrmwIrUb4W/3jTs9WDSN4=
github.com/Mrs4s/MiraiGo v0.0.0-20200728112613-91aa75e8270d/go.mod h1:M9wh1hjd0rie3+wm27tjPZkYMbD+MBV76CGqp2G7WSU=
github.com/Mrs4s/MiraiGo v0.0.0-20200729044443-98a77a6cf354 h1:f2Cv15Nir9tcefrvwD0+imVx1RQAw2TQI7LFipPUzrI=
github.com/Mrs4s/MiraiGo v0.0.0-20200729044443-98a77a6cf354/go.mod h1:M9wh1hjd0rie3+wm27tjPZkYMbD+MBV76CGqp2G7WSU=
github.com/Mrs4s/MiraiGo v0.0.0-20200731150933-29a5a459fd85 h1:qLNIyNtxORtHJsBcuwFkKHSXgAffxCN5H9zYrWaAr+Y=
github.com/Mrs4s/MiraiGo v0.0.0-20200731150933-29a5a459fd85/go.mod h1:M9wh1hjd0rie3+wm27tjPZkYMbD+MBV76CGqp2G7WSU=
github.com/Mrs4s/MiraiGo v0.0.0-20200801022834-8f1c0c053a86 h1:Rnfejw8W7MX3nW15a1tDW3ybAq2y95iQFGZmcQUKuRs=
github.com/Mrs4s/MiraiGo v0.0.0-20200801022834-8f1c0c053a86/go.mod h1:M9wh1hjd0rie3+wm27tjPZkYMbD+MBV76CGqp2G7WSU=
github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0=
github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=

View File

@ -85,6 +85,10 @@ func main() {
if conf.Uin == 0 || conf.Password == "" {
log.Fatal("请修改 config.json 以添加账号密码.")
}
if conf.Debug {
log.SetLevel(log.DebugLevel)
log.Warnf("已开启Debug模式.")
}
if !global.PathExists("device.json") {
log.Warn("虚拟设备信息不存在, 将自动生成随机设备,按 Enter 继续.")
_, _ = console.ReadString('\n')

View File

@ -127,6 +127,9 @@ func (s *httpServer) Run(addr, authToken string, bot *coolq.CQBot) {
s.engine.Any("/set_group_name", s.SetGroupName)
s.engine.Any("/set_group_name_async", s.SetGroupName)
s.engine.Any("/set_group_leave", s.SetGroupLeave)
s.engine.Any("/set_group_leave_async", s.SetGroupLeave)
s.engine.Any("/get_image", s.GetImage)
s.engine.Any("/get_image_async", s.GetImage)
@ -317,6 +320,11 @@ func (s *httpServer) SetGroupName(c *gin.Context) {
c.JSON(200, s.bot.CQSetGroupName(gid, getParam(c, "name")))
}
func (s *httpServer) SetGroupLeave(c *gin.Context) {
gid, _ := strconv.ParseInt(getParam(c, "group_id"), 10, 64)
c.JSON(200, s.bot.CQSetGroupLeave(gid))
}
func (s *httpServer) GetForwardMessage(c *gin.Context) {
resId := getParam(c, "message_id")
c.JSON(200, s.bot.CQGetForwardMessage(resId))

View File

@ -164,13 +164,15 @@ func (c *websocketClient) listenApi(conn *wsc.Conn, u bool) {
}
j := gjson.ParseBytes(buf[:l])
t := strings.ReplaceAll(j.Get("action").Str, "_async", "")
//log.Infof("调用API: %v p: %v", t, j.Get("params").Raw)
log.Debugf("反向WS接收到API调用: %v 参数: %v", t, j.Get("params").Raw)
if f, ok := wsApi[t]; ok {
ret := f(c.bot, j.Get("params"))
if j.Get("echo").Exists() {
ret["echo"] = j.Get("echo").Value()
}
c.pushLock.Lock()
_, _ = conn.Write([]byte(ret.ToJson()))
c.pushLock.Unlock()
}
}
if c.conf.ReverseReconnectInterval != 0 {
@ -187,6 +189,7 @@ func (c *websocketClient) onBotPushEvent(m coolq.MSG) {
c.pushLock.Lock()
defer c.pushLock.Unlock()
if c.eventConn != nil {
log.Debugf("向WS服务器 %v 推送Event: %v", c.eventConn.RemoteAddr().String(), m.ToJson())
if _, err := c.eventConn.Write([]byte(m.ToJson())); err != nil {
_ = c.eventConn.Close()
if c.conf.ReverseReconnectInterval != 0 {
@ -196,6 +199,7 @@ func (c *websocketClient) onBotPushEvent(m coolq.MSG) {
}
}
if c.universalConn != nil {
log.Debugf("向WS服务器 %v 推送Event: %v", c.universalConn.RemoteAddr().String(), m.ToJson())
_, _ = c.universalConn.Write([]byte(m.ToJson()))
}
}
@ -268,13 +272,15 @@ func (s *websocketServer) listenApi(c *websocket.Conn) {
if t == websocket.TextMessage {
j := gjson.ParseBytes(payload)
t := strings.ReplaceAll(j.Get("action").Str, "_async", "") //TODO: async support
//log.Infof("API调用: %v", j.Get("action").Str)
log.Debugf("WS接收到API调用: %v 参数: %v", t, j.Get("params").Raw)
if f, ok := wsApi[t]; ok {
ret := f(s.bot, j.Get("params"))
if j.Get("echo").Exists() {
ret["echo"] = j.Get("echo").Value()
}
s.pushLock.Lock()
_ = c.WriteJSON(ret)
s.pushLock.Unlock()
}
}
}
@ -285,6 +291,7 @@ func (s *websocketServer) onBotPushEvent(m coolq.MSG) {
defer s.pushLock.Unlock()
pos := 0
for _, conn := range s.eventConn {
log.Debugf("向WS客户端 %v 推送Event: %v", conn.RemoteAddr().String(), m.ToJson())
err := conn.WriteMessage(websocket.TextMessage, []byte(m.ToJson()))
if err != nil {
_ = conn.Close()
@ -386,6 +393,9 @@ var wsApi = map[string]func(*coolq.CQBot, gjson.Result) coolq.MSG{
"set_group_name": func(bot *coolq.CQBot, p gjson.Result) coolq.MSG {
return bot.CQSetGroupName(p.Get("group_id").Int(), p.Get("name").Str)
},
"set_group_leave": func(bot *coolq.CQBot, p gjson.Result) coolq.MSG {
return bot.CQSetGroupLeave(p.Get("group_id").Int())
},
"get_image": func(bot *coolq.CQBot, p gjson.Result) coolq.MSG {
return bot.CQGetImage(p.Get("file").Str)
},