Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
G
go-cqhttp
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nanahira
go-cqhttp
Commits
4c3bf416
Commit
4c3bf416
authored
Sep 13, 2020
by
nanahira
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of github.com:Mrs4s/go-cqhttp
parents
3bcdd8ac
e9db10c9
Changes
16
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
413 additions
and
177 deletions
+413
-177
README.md
README.md
+4
-3
coolq/api.go
coolq/api.go
+25
-0
coolq/bot.go
coolq/bot.go
+2
-1
coolq/cqcode.go
coolq/cqcode.go
+7
-0
coolq/event.go
coolq/event.go
+36
-0
docs/config.md
docs/config.md
+34
-1
docs/cqhttp.md
docs/cqhttp.md
+41
-0
docs/file.md
docs/file.md
+2
-0
global/config.go
global/config.go
+14
-0
global/filter.go
global/filter.go
+39
-55
global/ratelimit.go
global/ratelimit.go
+20
-0
go.mod
go.mod
+4
-3
go.sum
go.sum
+8
-26
main.go
main.go
+39
-0
server/http.go
server/http.go
+125
-87
server/websocket.go
server/websocket.go
+13
-1
No files found.
README.md
View file @
4c3bf416
...
...
@@ -80,13 +80,14 @@
| ------------------------------------------------------------ |
|
[
私聊信息
](
https://cqhttp.cc/docs/4.15/#/Post?id=私聊消息
)
|
|
[
群消息
](
https://cqhttp.cc/docs/4.15/#/Post?id=群消息
)
|
|
[
群消息撤回(拓展Event)
](
docs/cqhttp.md#群消息撤回
)
|
|
[
好友消息撤回(拓展Event)
](
docs/cqhttp.md#好友消息撤回
)
|
|
[
群消息撤回(拓展Event)
](
docs/cqhttp.md#群消息撤回
)
|
|
[
好友消息撤回(拓展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=加好友请求
)
|
|
[
加群请求/邀请
](
https://cqhttp.cc/docs/4.15/#/Post?id=加群请求/邀请
)
|
...
...
coolq/api.go
View file @
4c3bf416
...
...
@@ -404,6 +404,26 @@ func (bot *CQBot) CQDeleteMessage(messageId int32) MSG {
return
OK
(
nil
)
}
// https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#set_group_admin-%E7%BE%A4%E7%BB%84%E8%AE%BE%E7%BD%AE%E7%AE%A1%E7%90%86%E5%91%98
func
(
bot
*
CQBot
)
CQSetGroupAdmin
(
groupId
,
userId
int64
,
enable
bool
)
MSG
{
group
:=
bot
.
Client
.
FindGroup
(
groupId
)
if
group
==
nil
||
group
.
OwnerUin
!=
bot
.
Client
.
Uin
{
return
Failed
(
100
)
}
mem
:=
group
.
FindMember
(
userId
)
if
mem
==
nil
{
return
Failed
(
100
)
}
mem
.
SetAdmin
(
enable
)
t
,
err
:=
bot
.
Client
.
GetGroupMembers
(
group
)
if
err
!=
nil
{
log
.
Warnf
(
"刷新群 %v 成员列表失败: %v"
,
groupId
,
err
)
return
Failed
(
100
)
}
group
.
Members
=
t
return
OK
(
nil
)
}
func
(
bot
*
CQBot
)
CQGetVipInfo
(
userId
int64
)
MSG
{
msg
:=
MSG
{}
vip
,
err
:=
bot
.
Client
.
GetVipInfo
(
userId
)
...
...
@@ -607,6 +627,11 @@ func (bot *CQBot) CQCanSendRecord() MSG {
return
OK
(
MSG
{
"yes"
:
true
})
}
func
(
bot
*
CQBot
)
CQReloadEventFilter
()
MSG
{
global
.
BootFilter
()
return
OK
(
nil
)
}
func
(
bot
*
CQBot
)
CQGetStatus
()
MSG
{
return
OK
(
MSG
{
"app_initialized"
:
true
,
...
...
coolq/bot.go
View file @
4c3bf416
...
...
@@ -59,6 +59,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
.
OnGroupNotify
(
bot
.
groupNotifyEvent
)
bot
.
Client
.
OnFriendMessageRecalled
(
bot
.
friendRecallEvent
)
bot
.
Client
.
OnJoinGroup
(
bot
.
joinGroupEvent
)
bot
.
Client
.
OnLeaveGroup
(
bot
.
leaveGroupEvent
)
...
...
@@ -226,7 +227,7 @@ func (bot *CQBot) Release() {
func
(
bot
*
CQBot
)
dispatchEventMessage
(
m
MSG
)
{
payload
:=
gjson
.
Parse
(
m
.
ToJson
())
filter
:=
global
.
GetFilter
()
filter
:=
global
.
EventFilter
if
filter
!=
nil
&&
(
*
filter
)
.
Eval
(
payload
)
==
false
{
log
.
Debug
(
"Event filtered!"
)
return
...
...
coolq/cqcode.go
View file @
4c3bf416
...
...
@@ -71,6 +71,11 @@ func ToArrayMessage(e []message.IMessageElement, code int64, raw ...bool) (r []M
"data"
:
map
[
string
]
string
{
"qq"
:
fmt
.
Sprint
(
o
.
Target
)},
}
}
case
*
message
.
RedBagElement
:
m
=
MSG
{
"type"
:
"redbag"
,
"data"
:
map
[
string
]
string
{
"title"
:
o
.
Title
},
}
case
*
message
.
ForwardElement
:
m
=
MSG
{
"type"
:
"forward"
,
...
...
@@ -159,6 +164,8 @@ func ToStringMessage(e []message.IMessageElement, code int64, raw ...bool) (r st
continue
}
r
+=
fmt
.
Sprintf
(
"[CQ:at,qq=%d]"
,
o
.
Target
)
case
*
message
.
RedBagElement
:
r
+=
fmt
.
Sprintf
(
"[CQ:redbag,title=%s]"
,
o
.
Title
)
case
*
message
.
ForwardElement
:
r
+=
fmt
.
Sprintf
(
"[CQ:forward,id=%s]"
,
o
.
ResId
)
case
*
message
.
FaceElement
:
...
...
coolq/event.go
View file @
4c3bf416
...
...
@@ -205,6 +205,42 @@ func (bot *CQBot) groupRecallEvent(c *client.QQClient, e *client.GroupMessageRec
})
}
func
(
bot
*
CQBot
)
groupNotifyEvent
(
c
*
client
.
QQClient
,
e
client
.
IGroupNotifyEvent
)
{
group
:=
c
.
FindGroup
(
e
.
From
())
switch
notify
:=
e
.
(
type
)
{
case
*
client
.
GroupPokeNotifyEvent
:
sender
:=
group
.
FindMember
(
notify
.
Sender
)
receiver
:=
group
.
FindMember
(
notify
.
Receiver
)
log
.
Infof
(
"群 %v 内 %v 戳了戳 %v"
,
formatGroupName
(
group
),
formatMemberName
(
sender
),
formatMemberName
(
receiver
))
bot
.
dispatchEventMessage
(
MSG
{
"post_type"
:
"notice"
,
"group_id"
:
group
.
Code
,
"notice_type"
:
"notify"
,
"notify_type"
:
"poke"
,
"self_id"
:
c
.
Uin
,
"user_id"
:
notify
.
Sender
,
"sender_id"
:
notify
.
Sender
,
"receiver_id"
:
notify
.
Receiver
,
"time"
:
time
.
Now
()
.
Unix
(),
})
case
*
client
.
GroupRedBagLuckyKingNotifyEvent
:
sender
:=
group
.
FindMember
(
notify
.
Sender
)
luckyKing
:=
group
.
FindMember
(
notify
.
LuckyKing
)
log
.
Infof
(
"群 %v 内 %v 的红包被抢完, %v 是运气王"
,
formatGroupName
(
group
),
formatMemberName
(
sender
),
formatMemberName
(
luckyKing
))
bot
.
dispatchEventMessage
(
MSG
{
"post_type"
:
"notice"
,
"group_id"
:
group
.
Code
,
"notice_type"
:
"notify"
,
"notify_type"
:
"lucky_king"
,
"self_id"
:
c
.
Uin
,
"user_id"
:
notify
.
Sender
,
"sender_id"
:
notify
.
Sender
,
"lucky_king_id"
:
notify
.
LuckyKing
,
"time"
:
time
.
Now
()
.
Unix
(),
})
}
}
func
(
bot
*
CQBot
)
friendRecallEvent
(
c
*
client
.
QQClient
,
e
*
client
.
FriendMessageRecalledEvent
)
{
f
:=
c
.
FindFriend
(
e
.
FriendUin
)
gid
:=
ToGlobalId
(
e
.
FriendUin
,
e
.
MessageId
)
...
...
docs/config.md
View file @
4c3bf416
...
...
@@ -27,6 +27,11 @@ go-cqhttp 支持导入CQHTTP的配置文件, 具体步骤为:
"relogin_delay"
:
3
,
"max_relogin_times"
:
0
},
"_rate_limit"
:
{
"enabled"
:
false
,
"frequency"
:
1
,
"bucket_size"
:
1
},
"post_message_format"
:
"string"
,
"ignore_invalid_cqcode"
:
false
,
"force_fragmented"
:
true
,
...
...
@@ -66,10 +71,13 @@ go-cqhttp 支持导入CQHTTP的配置文件, 具体步骤为:
| relogin | bool | 是否自动重新登录 |
| relogin_delay | int | 重登录延时(秒) |
| max_relogin_times | uint | 最大重登录次数,若0则不设置上限 |
| _rate_limit | bool | 是否启用API调用限速 |
| frequency | float64 | 1s内能调用API的次数 |
| bucket_size | int | 令牌桶的大小,默认为1,修改此值可允许一定程度内连续调用api |
| post_message_format | string | 上报信息类型 |
| ignore_invalid_cqcode| bool | 是否忽略错误的CQ码 |
| force_fragmented | bool | 是否强制分片发送群长消息 |
| heartbeat_interval | int64 | 心跳间隔时间,单位秒
,若0则关闭心跳
|
| heartbeat_interval | int64 | 心跳间隔时间,单位秒
。小于0则关闭心跳,等于0使用默认值(5秒)
|
| http_config | object | HTTP API配置 |
| ws_config | object | Websocket API 配置 |
| ws_reverse_servers | object[] | 反向 Websocket API 配置 |
...
...
@@ -82,3 +90,28 @@ go-cqhttp 支持导入CQHTTP的配置文件, 具体步骤为:
> 注2: 分片发送为原酷Q发送长消息的老方案, 发送速度更优/兼容性更好,但在有发言频率限制的群里,可能无法发送。关闭后将优先使用新方案, 能发送更长的消息, 但发送速度更慢,在部分老客户端将无法解析.
> 注3:关闭心跳服务可能引起断线,请谨慎关闭
## 设备信息
默认生成的设备信息如下所示:
```
json
{
"protocol"
:
0
,
"display"
:
"xxx"
,
"finger_print"
:
"xxx"
,
"boot_id"
:
"xxx"
,
"proc_version"
:
"xxx"
,
"imei"
:
"xxx"
}
```
在大部分情况下 我们只需要关心
`protocol`
字段:
| 值 | 类型 | 限制 |
| ---- | ------------- | ----------------------------------------------------- |
| 0 | Android Pad | 无法接收
`group_notify`
事件、无法接收口令红包 |
| 1 | Android Phone | 无 |
| 2 | Android Watch | 除了
`Android Pad`
有的限制外还包括: 无法接收撤回消息 |
> 注意, 根据协议的不同, 各类消息有所限制
\ No newline at end of file
docs/cqhttp.md
View file @
4c3bf416
...
...
@@ -18,6 +18,20 @@ Type : `reply`
示例:
`[CQ:reply,id=123456]`
### 红包
Type:
`redbag`
范围:
**接收**
参数:
| 参数名 | 类型 | 说明 |
| ------ | ------ | ----------- |
| title | string | 祝福语/口令 |
示例:
`[CQ:redbag,title=恭喜发财]`
### 合并转发
Type:
`forward`
...
...
@@ -362,3 +376,30 @@ Type: `cardimage`
|
`user_id`
| int64 | | 好友id |
|
`message_id`
| int64 | | 被撤回的消息id |
#### 群内戳一戳
> 注意:此事件无法在平板和手表协议上触发
**上报数据**
| 字段 | 类型 | 可能的值 | 说明 |
| ------------- | ------ | -------------- | -------------- |
|
`post_type`
| string |
`notice`
| 上报类型 |
|
`notice_type`
| string |
`notify`
| 消息类型 |
|
`notify_type`
| string |
`poke`
| 提示类型 |
|
`user_id`
| int64 | | 发送者id |
|
`receiver_id`
| int64 | | 被戳者id |
#### 群红包运气王提示
> 注意:此事件无法在平板和手表协议上触发
**上报数据**
| 字段 | 类型 | 可能的值 | 说明 |
| ------------- | ------ | -------------- | -------------- |
|
`post_type`
| string |
`notice`
| 上报类型 |
|
`notice_type`
| string |
`notify`
| 消息类型 |
|
`notify_type`
| string |
`lucky_king`
| 提示类型 |
|
`user_id`
| int64 | | 红包发送者id |
|
`lucky_king_id`
| int64 | | 运气王id |
docs/file.md
View file @
4c3bf416
...
...
@@ -7,6 +7,7 @@ go-cqhttp 默认生成的文件树如下所示:
├── go-cqhttp
├── config.json
├── device.json
├── servers.bin
├── logs
│ └── xx-xx-xx.log
└── data
...
...
@@ -20,6 +21,7 @@ go-cqhttp 默认生成的文件树如下所示:
| go-cqhttp | go-cqhttp可执行文件 |
| config.json | 运行配置文件 |
| device.json | 虚拟设备配置文件 |
| servers.bin | 储存QQ服务器地址 |
| logs | 日志存放目录 |
| data | 数据目录 |
| data/images | 图片缓存目录 |
...
...
global/config.go
View file @
4c3bf416
...
...
@@ -21,6 +21,11 @@ type JsonConfig struct {
ReLoginDelay
int
`json:"relogin_delay"`
MaxReloginTimes
uint
`json:"max_relogin_times"`
}
`json:"relogin"`
RateLimit
struct
{
Enabled
bool
`json:"enabled"`
Frequency
float64
`json:"frequency"`
BucketSize
int
`json:"bucket_size"`
}
`json:"_rate_limit"`
IgnoreInvalidCQCode
bool
`json:"ignore_invalid_cqcode"`
ForceFragmented
bool
`json:"force_fragmented"`
HeartbeatInterval
time
.
Duration
`json:"heartbeat_interval"`
...
...
@@ -85,6 +90,15 @@ func DefaultConfig() *JsonConfig {
ReLoginDelay
:
3
,
MaxReloginTimes
:
0
,
},
RateLimit
:
struct
{
Enabled
bool
`json:"enabled"`
Frequency
float64
`json:"frequency"`
BucketSize
int
`json:"bucket_size"`
}{
Enabled
:
false
,
Frequency
:
1
,
BucketSize
:
1
,
},
PostMessageFormat
:
"string"
,
ForceFragmented
:
true
,
HttpConfig
:
&
GoCQHttpConfig
{
...
...
global/filter.go
View file @
4c3bf416
...
...
@@ -6,7 +6,6 @@ import (
"io/ioutil"
"regexp"
"strings"
"sync"
)
type
Filter
interface
{
...
...
@@ -14,7 +13,7 @@ type Filter interface {
}
type
OperationNode
struct
{
key
string
key
string
filter
Filter
}
...
...
@@ -24,15 +23,14 @@ type NotOperator struct {
func
notOperatorConstruct
(
argument
gjson
.
Result
)
*
NotOperator
{
if
!
argument
.
IsObject
()
{
log
.
Error
(
"the argument of 'not' operator must be an object"
)
panic
(
"the argument of 'not' operator must be an object"
)
}
op
:=
new
(
NotOperator
)
op
.
operand_
=
Ge
tOperatorFactory
()
.
Ge
nerate
(
"and"
,
argument
)
op
.
operand_
=
Generate
(
"and"
,
argument
)
return
op
}
func
(
notOperator
NotOperator
)
Eval
(
payload
gjson
.
Result
)
bool
{
log
.
Debug
(
"not "
+
payload
.
Str
)
return
!
(
notOperator
.
operand_
)
.
Eval
(
payload
)
}
...
...
@@ -42,7 +40,7 @@ type AndOperator struct {
func
andOperatorConstruct
(
argument
gjson
.
Result
)
*
AndOperator
{
if
!
argument
.
IsObject
()
{
log
.
Error
(
"the argument of 'and' operator must be an object"
)
panic
(
"the argument of 'and' operator must be an object"
)
}
op
:=
new
(
AndOperator
)
argument
.
ForEach
(
func
(
key
,
value
gjson
.
Result
)
bool
{
...
...
@@ -52,19 +50,19 @@ func andOperatorConstruct(argument gjson.Result) *AndOperator {
// "bar": "baz"
// }
opKey
:=
key
.
Str
[
1
:
]
op
.
operands
=
append
(
op
.
operands
,
OperationNode
{
""
,
Ge
tOperatorFactory
()
.
Ge
nerate
(
opKey
,
value
)})
op
.
operands
=
append
(
op
.
operands
,
OperationNode
{
""
,
Generate
(
opKey
,
value
)})
}
else
if
value
.
IsObject
()
{
// is an normal key with an object as the value
// "foo": {
// ".bar": "baz"
// }
opKey
:=
key
.
Str
op
.
operands
=
append
(
op
.
operands
,
OperationNode
{
opKey
,
Ge
tOperatorFactory
()
.
Ge
nerate
(
"and"
,
value
)})
opKey
:=
key
.
Str
ing
()
op
.
operands
=
append
(
op
.
operands
,
OperationNode
{
opKey
,
Generate
(
"and"
,
value
)})
}
else
{
// is an normal key with a non-object as the value
// "foo": "bar"
opKey
:=
key
.
Str
op
.
operands
=
append
(
op
.
operands
,
OperationNode
{
opKey
,
Ge
tOperatorFactory
()
.
Ge
nerate
(
"eq"
,
value
)})
opKey
:=
key
.
Str
ing
()
op
.
operands
=
append
(
op
.
operands
,
OperationNode
{
opKey
,
Generate
(
"eq"
,
value
)})
}
return
true
})
...
...
@@ -72,7 +70,6 @@ func andOperatorConstruct(argument gjson.Result) *AndOperator {
}
func
(
andOperator
*
AndOperator
)
Eval
(
payload
gjson
.
Result
)
bool
{
log
.
Debug
(
"and "
+
payload
.
Str
)
res
:=
true
for
_
,
operand
:=
range
andOperator
.
operands
{
...
...
@@ -98,19 +95,18 @@ type OrOperator struct {
func
orOperatorConstruct
(
argument
gjson
.
Result
)
*
OrOperator
{
if
!
argument
.
IsArray
()
{
log
.
Error
(
"the argument of 'or' operator must be an array"
)
panic
(
"the argument of 'or' operator must be an array"
)
}
op
:=
new
(
OrOperator
)
argument
.
ForEach
(
func
(
_
,
value
gjson
.
Result
)
bool
{
op
.
operands
=
append
(
op
.
operands
,
Ge
tOperatorFactory
()
.
Ge
nerate
(
"and"
,
value
))
op
.
operands
=
append
(
op
.
operands
,
Generate
(
"and"
,
value
))
return
true
})
return
op
}
func
(
orOperator
OrOperator
)
Eval
(
payload
gjson
.
Result
)
bool
{
log
.
Debug
(
"or "
+
payload
.
Str
)
res
:=
false
res
:=
false
for
_
,
operand
:=
range
orOperator
.
operands
{
res
=
res
||
operand
.
Eval
(
payload
)
...
...
@@ -132,8 +128,7 @@ func equalOperatorConstruct(argument gjson.Result) *EqualOperator {
}
func
(
equalOperator
EqualOperator
)
Eval
(
payload
gjson
.
Result
)
bool
{
log
.
Debug
(
"eq "
+
payload
.
Str
+
"=="
+
equalOperator
.
value
.
Str
)
return
payload
.
Str
==
equalOperator
.
value
.
Str
return
payload
.
String
()
==
equalOperator
.
value
.
String
()
}
type
NotEqualOperator
struct
{
...
...
@@ -147,18 +142,16 @@ func notEqualOperatorConstruct(argument gjson.Result) *NotEqualOperator {
}
func
(
notEqualOperator
NotEqualOperator
)
Eval
(
payload
gjson
.
Result
)
bool
{
log
.
Debug
(
"neq "
+
payload
.
Str
)
return
!
(
payload
.
Str
==
notEqualOperator
.
value
.
Str
)
return
!
(
payload
.
String
()
==
notEqualOperator
.
value
.
String
())
}
type
InOperator
struct
{
operand
gjson
.
Result
}
func
inOperatorConstruct
(
argument
gjson
.
Result
)
*
InOperator
{
if
argument
.
IsObject
()
{
log
.
Error
(
"the argument of 'in' operator must be an array or a string"
)
panic
(
"the argument of 'in' operator must be an array or a string"
)
}
op
:=
new
(
InOperator
)
op
.
operand
=
argument
...
...
@@ -166,16 +159,15 @@ func inOperatorConstruct(argument gjson.Result) *InOperator {
}
func
(
inOperator
InOperator
)
Eval
(
payload
gjson
.
Result
)
bool
{
log
.
Debug
(
"in "
+
payload
.
Str
)
if
inOperator
.
operand
.
IsArray
()
{
res
:=
false
inOperator
.
operand
.
ForEach
(
func
(
key
,
value
gjson
.
Result
)
bool
{
res
=
res
||
value
.
Str
==
payload
.
Str
res
=
res
||
value
.
Str
ing
()
==
payload
.
String
()
return
true
})
return
res
}
return
strings
.
Contains
(
inOperator
.
operand
.
Str
,
payload
.
Str
)
return
strings
.
Contains
(
inOperator
.
operand
.
Str
ing
(),
payload
.
String
()
)
}
type
ContainsOperator
struct
{
...
...
@@ -184,15 +176,14 @@ type ContainsOperator struct {
func
containsOperatorConstruct
(
argument
gjson
.
Result
)
*
ContainsOperator
{
if
argument
.
IsArray
()
||
argument
.
IsObject
()
{
log
.
Error
(
"the argument of 'contains' operator must be a string"
)
panic
(
"the argument of 'contains' operator must be a string"
)
}
op
:=
new
(
ContainsOperator
)
op
.
operand
=
argument
.
Str
op
.
operand
=
argument
.
Str
ing
()
return
op
}
func
(
containsOperator
ContainsOperator
)
Eval
(
payload
gjson
.
Result
)
bool
{
log
.
Debug
(
"contains "
+
payload
.
Str
)
if
payload
.
IsObject
()
||
payload
.
IsArray
()
{
return
false
}
...
...
@@ -205,29 +196,19 @@ type RegexOperator struct {
func
regexOperatorConstruct
(
argument
gjson
.
Result
)
*
RegexOperator
{
if
argument
.
IsArray
()
||
argument
.
IsObject
()
{
log
.
Error
(
"the argument of 'regex' operator must be a string"
)
panic
(
"the argument of 'regex' operator must be a string"
)
}
op
:=
new
(
RegexOperator
)
op
.
regex
=
argument
.
Str
op
.
regex
=
argument
.
Str
ing
()
return
op
}
func
(
containsOperator
RegexOperator
)
Eval
(
payload
gjson
.
Result
)
bool
{
log
.
Debug
(
"regex "
+
payload
.
Str
)
matched
,
_
:=
regexp
.
MatchString
(
containsOperator
.
regex
,
payload
.
Str
)
matched
,
_
:=
regexp
.
MatchString
(
containsOperator
.
regex
,
payload
.
String
())
return
matched
}
// 单例工厂
type
operatorFactory
struct
{
}
var
instance
*
operatorFactory
=
&
operatorFactory
{}
func
GetOperatorFactory
()
*
operatorFactory
{
return
instance
}
func
(
o
operatorFactory
)
Generate
(
opName
string
,
argument
gjson
.
Result
)
Filter
{
func
Generate
(
opName
string
,
argument
gjson
.
Result
)
Filter
{
switch
opName
{
case
"not"
:
return
notOperatorConstruct
(
argument
)
...
...
@@ -246,22 +227,25 @@ func (o operatorFactory) Generate(opName string, argument gjson.Result) Filter {
case
"regex"
:
return
regexOperatorConstruct
(
argument
)
default
:
log
.
Warnf
(
"the operator '%s' is not supported"
,
opName
)
return
nil
panic
(
"the operator "
+
opName
+
" is not supported"
)
}
}
var
filter
=
new
(
Filter
)
var
once
sync
.
Once
// 过滤器单例模式
var
EventFilter
=
new
(
Filter
)
func
GetFilter
()
*
Filter
{
once
.
Do
(
func
()
{
f
,
err
:=
ioutil
.
ReadFile
(
"filter.json"
)
if
err
!=
nil
{
f
ilter
=
nil
func
BootFilter
()
{
defer
func
()
{
if
e
:=
recover
();
e
!=
nil
{
log
.
Warnf
(
"事件过滤器启动失败: %v"
,
e
)
EventF
ilter
=
nil
}
else
{
*
filter
=
GetOperatorFactory
()
.
Generate
(
"and"
,
gjson
.
ParseBytes
(
f
)
)
log
.
Info
(
"事件过滤器启动成功."
)
}
})
return
filter
}
\ No newline at end of file
}()
f
,
err
:=
ioutil
.
ReadFile
(
"filter.json"
)
if
err
!=
nil
{
panic
(
err
)
}
else
{
*
EventFilter
=
Generate
(
"and"
,
gjson
.
ParseBytes
(
f
))
}
}
global/ratelimit.go
0 → 100644
View file @
4c3bf416
package
global
import
(
"context"
"golang.org/x/time/rate"
)
var
limiter
*
rate
.
Limiter
var
limitEnable
=
false
func
RateLimit
(
ctx
context
.
Context
)
{
if
limitEnable
{
_
=
limiter
.
Wait
(
ctx
)
}
}
func
InitLimiter
(
r
float64
,
b
int
)
{
limitEnable
=
true
limiter
=
rate
.
NewLimiter
(
rate
.
Limit
(
r
),
b
)
}
go.mod
View file @
4c3bf416
...
...
@@ -3,7 +3,7 @@ module github.com/Mrs4s/go-cqhttp
go 1.14
require (
github.com/Mrs4s/MiraiGo v0.0.0-202009
06025848-23750bb59124
github.com/Mrs4s/MiraiGo v0.0.0-202009
12123655-d92d61c5998e
github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 // indirect
github.com/gin-gonic/gin v1.6.3
github.com/go-playground/validator/v10 v10.3.0 // indirect
...
...
@@ -12,7 +12,7 @@ require (
github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 // indirect
github.com/jonboulle/clockwork v0.2.0 // indirect
github.com/json-iterator/go v1.1.10 // indirect
github.com/lestrrat-go/file-rotatelogs v2.
3
.0+incompatible
github.com/lestrrat-go/file-rotatelogs v2.
4
.0+incompatible
github.com/lestrrat-go/strftime v1.0.3 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
...
...
@@ -25,6 +25,7 @@ require (
github.com/xujiajun/nutsdb v0.5.0
github.com/yinghau76/go-ascii-art v0.0.0-20190517192627-e7f465a30189
golang.org/x/net v0.0.0-20200904194848-62affa334b73 // indirect
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f // indirect
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009 // indirect
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e
gopkg.in/yaml.v2 v2.3.0 // indirect
)
go.sum
View file @
4c3bf416
This diff is collapsed.
Click to expand it.
main.go
View file @
4c3bf416
...
...
@@ -10,6 +10,7 @@ import (
"image"
"io"
"io/ioutil"
"net"
"os"
"os/signal"
"path"
...
...
@@ -245,6 +246,17 @@ func main() {
log
.
Info
(
"Bot将在5秒后登录并开始信息处理, 按 Ctrl+C 取消."
)
time
.
Sleep
(
time
.
Second
*
5
)
log
.
Info
(
"开始尝试登录并同步消息..."
)
log
.
Infof
(
"使用协议: %v"
,
func
()
string
{
switch
client
.
SystemDeviceInfo
.
Protocol
{
case
client
.
AndroidPad
:
return
"Android Pad"
case
client
.
AndroidPhone
:
return
"Android Phone"
case
client
.
AndroidWatch
:
return
"Android Watch"
}
return
"未知"
}())
cli
:=
client
.
NewClient
(
conf
.
Uin
,
conf
.
Password
)
cli
.
OnLog
(
func
(
c
*
client
.
QQClient
,
e
*
client
.
LogEvent
)
{
switch
e
.
Type
{
...
...
@@ -256,6 +268,28 @@ func main() {
log
.
Debug
(
"Protocol -> "
+
e
.
Message
)
}
})
cli
.
OnServerUpdated
(
func
(
bot
*
client
.
QQClient
,
e
*
client
.
ServerUpdatedEvent
)
{
log
.
Infof
(
"收到服务器地址更新通知, 将在下一次重连时应用. 服务器地址: %v:%v 服务器位置: %v"
,
e
.
Servers
[
0
]
.
Server
,
e
.
Servers
[
0
]
.
Port
,
e
.
Servers
[
0
]
.
Location
)
_
=
ioutil
.
WriteFile
(
"servers.bin"
,
binary
.
NewWriterF
(
func
(
w
*
binary
.
Writer
)
{
w
.
WriteUInt16
(
uint16
(
len
(
e
.
Servers
)))
for
_
,
s
:=
range
e
.
Servers
{
if
!
strings
.
Contains
(
s
.
Server
,
"com"
)
{
w
.
WriteString
(
s
.
Server
)
w
.
WriteUInt16
(
uint16
(
s
.
Port
))
}
}
}),
0644
)
})
if
global
.
PathExists
(
"servers.bin"
)
{
if
data
,
err
:=
ioutil
.
ReadFile
(
"servers.bin"
);
err
==
nil
{
r
:=
binary
.
NewReader
(
data
)
r
.
ReadUInt16
()
cli
.
CustomServer
=
&
net
.
TCPAddr
{
IP
:
net
.
ParseIP
(
r
.
ReadString
()),
Port
:
int
(
r
.
ReadUInt16
()),
}
}
}
rsp
,
err
:=
cli
.
Login
()
for
{
global
.
Check
(
err
)
...
...
@@ -295,6 +329,11 @@ func main() {
}
else
{
coolq
.
SetMessageFormat
(
conf
.
PostMessageFormat
)
}
if
conf
.
RateLimit
.
Enabled
{
global
.
InitLimiter
(
conf
.
RateLimit
.
Frequency
,
conf
.
RateLimit
.
BucketSize
)
}
log
.
Info
(
"正在加载事件过滤器."
)
global
.
BootFilter
()
coolq
.
IgnoreInvalidCQCode
=
conf
.
IgnoreInvalidCQCode
coolq
.
ForceFragmented
=
conf
.
ForceFragmented
if
conf
.
HttpConfig
!=
nil
&&
conf
.
HttpConfig
.
Enabled
{
...
...
server/http.go
View file @
4c3bf416
package
server
import
(
"context"
"crypto/hmac"
"crypto/sha1"
"encoding/hex"
...
...
@@ -74,93 +75,7 @@ func (s *httpServer) Run(addr, authToken string, bot *coolq.CQBot) {
})
}
s
.
engine
.
Any
(
"/get_login_info"
,
s
.
GetLoginInfo
)
s
.
engine
.
Any
(
"/get_login_info_async"
,
s
.
GetLoginInfo
)
s
.
engine
.
Any
(
"/get_friend_list"
,
s
.
GetFriendList
)
s
.
engine
.
Any
(
"/get_friend_list_async"
,
s
.
GetFriendList
)
s
.
engine
.
Any
(
"/get_group_list"
,
s
.
GetGroupList
)
s
.
engine
.
Any
(
"/get_group_list_async"
,
s
.
GetGroupList
)
s
.
engine
.
Any
(
"/get_group_info"
,
s
.
GetGroupInfo
)
s
.
engine
.
Any
(
"/get_group_info_async"
,
s
.
GetGroupInfo
)
s
.
engine
.
Any
(
"/get_group_member_list"
,
s
.
GetGroupMemberList
)
s
.
engine
.
Any
(
"/get_group_member_list_async"
,
s
.
GetGroupMemberList
)
s
.
engine
.
Any
(
"/get_group_member_info"
,
s
.
GetGroupMemberInfo
)
s
.
engine
.
Any
(
"/get_group_member_info_async"
,
s
.
GetGroupMemberInfo
)
s
.
engine
.
Any
(
"/send_msg"
,
s
.
SendMessage
)
s
.
engine
.
Any
(
"/send_msg_async"
,
s
.
SendMessage
)
s
.
engine
.
Any
(
"/send_private_msg"
,
s
.
SendPrivateMessage
)
s
.
engine
.
Any
(
"/send_private_msg_async"
,
s
.
SendPrivateMessage
)
s
.
engine
.
Any
(
"/send_group_msg"
,
s
.
SendGroupMessage
)
s
.
engine
.
Any
(
"/send_group_msg_async"
,
s
.
SendGroupMessage
)
s
.
engine
.
Any
(
"/send_group_forward_msg"
,
s
.
SendGroupForwardMessage
)
s
.
engine
.
Any
(
"/send_group_forward_msg_async"
,
s
.
SendGroupForwardMessage
)
s
.
engine
.
Any
(
"/delete_msg"
,
s
.
DeleteMessage
)
s
.
engine
.
Any
(
"/delete_msg_async"
,
s
.
DeleteMessage
)
s
.
engine
.
Any
(
"/set_friend_add_request"
,
s
.
ProcessFriendRequest
)
s
.
engine
.
Any
(
"/set_friend_add_request_async"
,
s
.
ProcessFriendRequest
)
s
.
engine
.
Any
(
"/set_group_add_request"
,
s
.
ProcessGroupRequest
)
s
.
engine
.
Any
(
"/set_group_add_request_async"
,
s
.
ProcessGroupRequest
)
s
.
engine
.
Any
(
"/set_group_card"
,
s
.
SetGroupCard
)
s
.
engine
.
Any
(
"/set_group_card_async"
,
s
.
SetGroupCard
)
s
.
engine
.
Any
(
"/set_group_special_title"
,
s
.
SetSpecialTitle
)
s
.
engine
.
Any
(
"/set_group_special_title_async"
,
s
.
SetSpecialTitle
)
s
.
engine
.
Any
(
"/set_group_kick"
,
s
.
SetGroupKick
)
s
.
engine
.
Any
(
"/set_group_kick_async"
,
s
.
SetGroupKick
)
s
.
engine
.
Any
(
"/set_group_ban"
,
s
.
SetGroupBan
)
s
.
engine
.
Any
(
"/set_group_ban_async"
,
s
.
SetGroupBan
)
s
.
engine
.
Any
(
"/set_group_whole_ban"
,
s
.
SetWholeBan
)
s
.
engine
.
Any
(
"/set_group_whole_ban_async"
,
s
.
SetWholeBan
)
s
.
engine
.
Any
(
"/set_group_name"
,
s
.
SetGroupName
)
s
.
engine
.
Any
(
"/set_group_name_async"
,
s
.
SetGroupName
)
s
.
engine
.
Any
(
"/_send_group_notice"
,
s
.
SendGroupNotice
)
s
.
engine
.
Any
(
"/_send_group_notice_async"
,
s
.
SendGroupNotice
)
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_forward_msg"
,
s
.
GetForwardMessage
)
s
.
engine
.
Any
(
"/get_group_msg"
,
s
.
GetGroupMessage
)
s
.
engine
.
Any
(
"/get_group_honor_info"
,
s
.
GetGroupHonorInfo
)
s
.
engine
.
Any
(
"/can_send_image"
,
s
.
CanSendImage
)
s
.
engine
.
Any
(
"/can_send_image_async"
,
s
.
CanSendImage
)
s
.
engine
.
Any
(
"/can_send_record"
,
s
.
CanSendRecord
)
s
.
engine
.
Any
(
"/can_send_record_async"
,
s
.
CanSendRecord
)
s
.
engine
.
Any
(
"/get_status"
,
s
.
GetStatus
)
s
.
engine
.
Any
(
"/get_status_async"
,
s
.
GetStatus
)
s
.
engine
.
Any
(
"/get_version_info"
,
s
.
GetVersionInfo
)
s
.
engine
.
Any
(
"/get_version_info_async"
,
s
.
GetVersionInfo
)
s
.
engine
.
Any
(
"/_get_vip_info"
,
s
.
GetVipInfo
)
s
.
engine
.
Any
(
"/_get_vip_info_async"
,
s
.
GetVipInfo
)
s
.
engine
.
Any
(
"/.handle_quick_operation"
,
s
.
HandleQuickOperation
)
s
.
engine
.
Any
(
"/:action"
,
s
.
HandleActions
)
go
func
()
{
log
.
Infof
(
"CQ HTTP 服务器已启动: %v"
,
addr
)
...
...
@@ -213,6 +128,17 @@ func (c *httpClient) onBotPushEvent(m coolq.MSG) {
}
}
func
(
s
*
httpServer
)
HandleActions
(
c
*
gin
.
Context
)
{
global
.
RateLimit
(
context
.
Background
())
action
:=
strings
.
ReplaceAll
(
c
.
Param
(
"action"
),
"_async"
,
""
)
log
.
Debugf
(
"HTTPServer接收到API调用: %v"
,
action
)
if
f
,
ok
:=
httpApi
[
action
];
ok
{
f
(
s
,
c
)
}
else
{
c
.
JSON
(
200
,
coolq
.
Failed
(
404
))
}
}
func
(
s
*
httpServer
)
GetLoginInfo
(
c
*
gin
.
Context
)
{
c
.
JSON
(
200
,
s
.
bot
.
CQGetLoginInfo
())
}
...
...
@@ -356,6 +282,12 @@ func (s *httpServer) SetGroupName(c *gin.Context) {
c
.
JSON
(
200
,
s
.
bot
.
CQSetGroupName
(
gid
,
getParam
(
c
,
"group_name"
)))
}
func
(
s
*
httpServer
)
SetGroupAdmin
(
c
*
gin
.
Context
)
{
gid
,
_
:=
strconv
.
ParseInt
(
getParam
(
c
,
"group_id"
),
10
,
64
)
uid
,
_
:=
strconv
.
ParseInt
(
getParam
(
c
,
"user_id"
),
10
,
64
)
c
.
JSON
(
200
,
s
.
bot
.
CQSetGroupAdmin
(
gid
,
uid
,
getParamOrDefault
(
c
,
"enable"
,
"true"
)
==
"true"
))
}
func
(
s
*
httpServer
)
SendGroupNotice
(
c
*
gin
.
Context
)
{
gid
,
_
:=
strconv
.
ParseInt
(
getParam
(
c
,
"group_id"
),
10
,
64
)
c
.
JSON
(
200
,
s
.
bot
.
CQSetGroupMemo
(
gid
,
getParam
(
c
,
"content"
)))
...
...
@@ -392,6 +324,10 @@ func (s *httpServer) GetVersionInfo(c *gin.Context) {
c
.
JSON
(
200
,
s
.
bot
.
CQGetVersionInfo
())
}
func
(
s
*
httpServer
)
ReloadEventFilter
(
c
*
gin
.
Context
)
{
c
.
JSON
(
200
,
s
.
bot
.
CQReloadEventFilter
())
}
func
(
s
*
httpServer
)
GetVipInfo
(
c
*
gin
.
Context
)
{
uid
,
_
:=
strconv
.
ParseInt
(
getParam
(
c
,
"user_id"
),
10
,
64
)
c
.
JSON
(
200
,
s
.
bot
.
CQGetVipInfo
(
uid
))
...
...
@@ -455,3 +391,105 @@ func getParamWithType(c *gin.Context, k string) (string, gjson.Type) {
}
return
""
,
gjson
.
Null
}
var
httpApi
=
map
[
string
]
func
(
s
*
httpServer
,
c
*
gin
.
Context
){
"get_login_info"
:
func
(
s
*
httpServer
,
c
*
gin
.
Context
)
{
s
.
GetLoginInfo
(
c
)
},
"get_friend_list"
:
func
(
s
*
httpServer
,
c
*
gin
.
Context
)
{
s
.
GetFriendList
(
c
)
},
"get_group_list"
:
func
(
s
*
httpServer
,
c
*
gin
.
Context
)
{
s
.
GetGroupList
(
c
)
},
"get_group_info"
:
func
(
s
*
httpServer
,
c
*
gin
.
Context
)
{
s
.
GetGroupInfo
(
c
)
},
"get_group_member_list"
:
func
(
s
*
httpServer
,
c
*
gin
.
Context
)
{
s
.
GetGroupMemberList
(
c
)
},
"get_group_member_info"
:
func
(
s
*
httpServer
,
c
*
gin
.
Context
)
{
s
.
GetGroupMemberInfo
(
c
)
},
"send_msg"
:
func
(
s
*
httpServer
,
c
*
gin
.
Context
)
{
s
.
SendMessage
(
c
)
},
"send_group_msg"
:
func
(
s
*
httpServer
,
c
*
gin
.
Context
)
{
s
.
SendGroupMessage
(
c
)
},
"send_group_forward_msg"
:
func
(
s
*
httpServer
,
c
*
gin
.
Context
)
{
s
.
SendGroupForwardMessage
(
c
)
},
"send_private_msg"
:
func
(
s
*
httpServer
,
c
*
gin
.
Context
)
{
s
.
SendPrivateMessage
(
c
)
},
"delete_msg"
:
func
(
s
*
httpServer
,
c
*
gin
.
Context
)
{
s
.
DeleteMessage
(
c
)
},
"set_friend_add_request"
:
func
(
s
*
httpServer
,
c
*
gin
.
Context
)
{
s
.
ProcessFriendRequest
(
c
)
},
"set_group_add_request"
:
func
(
s
*
httpServer
,
c
*
gin
.
Context
)
{
s
.
ProcessGroupRequest
(
c
)
},
"set_group_card"
:
func
(
s
*
httpServer
,
c
*
gin
.
Context
)
{
s
.
SetGroupCard
(
c
)
},
"set_group_special_title"
:
func
(
s
*
httpServer
,
c
*
gin
.
Context
)
{
s
.
SetSpecialTitle
(
c
)
},
"set_group_kick"
:
func
(
s
*
httpServer
,
c
*
gin
.
Context
)
{
s
.
SetGroupKick
(
c
)
},
"set_group_ban"
:
func
(
s
*
httpServer
,
c
*
gin
.
Context
)
{
s
.
SetGroupBan
(
c
)
},
"set_group_whole_ban"
:
func
(
s
*
httpServer
,
c
*
gin
.
Context
)
{
s
.
SetWholeBan
(
c
)
},
"set_group_name"
:
func
(
s
*
httpServer
,
c
*
gin
.
Context
)
{
s
.
SetGroupName
(
c
)
},
"set_group_admin"
:
func
(
s
*
httpServer
,
c
*
gin
.
Context
)
{
s
.
SetGroupAdmin
(
c
)
},
"_send_group_notice"
:
func
(
s
*
httpServer
,
c
*
gin
.
Context
)
{
s
.
SendGroupNotice
(
c
)
},
"set_group_leave"
:
func
(
s
*
httpServer
,
c
*
gin
.
Context
)
{
s
.
SetGroupLeave
(
c
)
},
"get_image"
:
func
(
s
*
httpServer
,
c
*
gin
.
Context
)
{
s
.
GetImage
(
c
)
},
"get_forward_msg"
:
func
(
s
*
httpServer
,
c
*
gin
.
Context
)
{
s
.
GetForwardMessage
(
c
)
},
"get_group_msg"
:
func
(
s
*
httpServer
,
c
*
gin
.
Context
)
{
s
.
GetGroupMessage
(
c
)
},
"get_group_honor_info"
:
func
(
s
*
httpServer
,
c
*
gin
.
Context
)
{
s
.
GetGroupHonorInfo
(
c
)
},
"can_send_image"
:
func
(
s
*
httpServer
,
c
*
gin
.
Context
)
{
s
.
CanSendImage
(
c
)
},
"can_send_record"
:
func
(
s
*
httpServer
,
c
*
gin
.
Context
)
{
s
.
CanSendRecord
(
c
)
},
"get_status"
:
func
(
s
*
httpServer
,
c
*
gin
.
Context
)
{
s
.
GetStatus
(
c
)
},
"get_version_info"
:
func
(
s
*
httpServer
,
c
*
gin
.
Context
)
{
s
.
GetVersionInfo
(
c
)
},
"_get_vip_info"
:
func
(
s
*
httpServer
,
c
*
gin
.
Context
)
{
s
.
GetVipInfo
(
c
)
},
"reload_event_filter"
:
func
(
s
*
httpServer
,
c
*
gin
.
Context
)
{
s
.
ReloadEventFilter
(
c
)
},
".handle_quick_operation"
:
func
(
s
*
httpServer
,
c
*
gin
.
Context
)
{
s
.
HandleQuickOperation
(
c
)
},
}
server/websocket.go
View file @
4c3bf416
package
server
import
(
"context"
"fmt"
"net/http"
"strconv"
...
...
@@ -319,7 +320,7 @@ func (c *websocketConn) handleRequest(bot *coolq.CQBot, payload []byte) {
c
.
Close
()
}
}()
global
.
RateLimit
(
context
.
Background
())
j
:=
gjson
.
ParseBytes
(
payload
)
t
:=
strings
.
ReplaceAll
(
j
.
Get
(
"action"
)
.
Str
,
"_async"
,
""
)
log
.
Debugf
(
"WS接收到API调用: %v 参数: %v"
,
t
,
j
.
Get
(
"params"
)
.
Raw
)
...
...
@@ -453,6 +454,14 @@ 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
(
"group_name"
)
.
Str
)
},
"set_group_admin"
:
func
(
bot
*
coolq
.
CQBot
,
p
gjson
.
Result
)
coolq
.
MSG
{
return
bot
.
CQSetGroupAdmin
(
p
.
Get
(
"group_id"
)
.
Int
(),
p
.
Get
(
"user_id"
)
.
Int
(),
func
()
bool
{
if
p
.
Get
(
"enable"
)
.
Exists
()
{
return
p
.
Get
(
"enable"
)
.
Bool
()
}
return
true
}())
},
"_send_group_notice"
:
func
(
bot
*
coolq
.
CQBot
,
p
gjson
.
Result
)
coolq
.
MSG
{
return
bot
.
CQSetGroupMemo
(
p
.
Get
(
"group_id"
)
.
Int
(),
p
.
Get
(
"content"
)
.
Str
)
},
...
...
@@ -486,6 +495,9 @@ var wsApi = map[string]func(*coolq.CQBot, gjson.Result) coolq.MSG{
"_get_vip_info"
:
func
(
bot
*
coolq
.
CQBot
,
p
gjson
.
Result
)
coolq
.
MSG
{
return
bot
.
CQGetVipInfo
(
p
.
Get
(
"user_id"
)
.
Int
())
},
"reload_event_filter"
:
func
(
bot
*
coolq
.
CQBot
,
p
gjson
.
Result
)
coolq
.
MSG
{
return
bot
.
CQReloadEventFilter
()
},
".handle_quick_operation"
:
func
(
bot
*
coolq
.
CQBot
,
p
gjson
.
Result
)
coolq
.
MSG
{
return
bot
.
CQHandleQuickOperation
(
p
.
Get
(
"context"
),
p
.
Get
(
"operation"
))
},
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment