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
a582a1dd
Commit
a582a1dd
authored
Aug 20, 2020
by
nanahira
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of github.com:Mrs4s/go-cqhttp
parents
71cb4290
322b70c6
Pipeline
#566
passed with stages
in 4 minutes and 15 seconds
Changes
14
Pipelines
1
Show whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
371 additions
and
141 deletions
+371
-141
README.md
README.md
+12
-1
coolq/api.go
coolq/api.go
+96
-20
coolq/bot.go
coolq/bot.go
+32
-7
coolq/cqcode.go
coolq/cqcode.go
+35
-3
coolq/event.go
coolq/event.go
+18
-6
docs/config.md
docs/config.md
+2
-1
global/config.go
global/config.go
+15
-14
global/fs.go
global/fs.go
+14
-9
global/param.go
global/param.go
+50
-0
go.mod
go.mod
+1
-1
go.sum
go.sum
+2
-6
main.go
main.go
+27
-17
server/http.go
server/http.go
+16
-7
server/websocket.go
server/websocket.go
+51
-49
No files found.
README.md
View file @
a582a1dd
...
...
@@ -28,6 +28,7 @@
-
[CQ:image]
-
[CQ:record]
-
[CQ:video]
-
[CQ:face]
-
[CQ:at]
-
[CQ:share]
...
...
@@ -91,7 +92,17 @@
</details>
## 性能
# 关于ISSUE
以下ISSUE会被直接关闭
-
提交BUG不使用Template
-
询问已知问题
-
提问找不到重点
-
重复提问
> 请注意, 开发者并没有义务回复您的问题. 您应该具备基本的提问技巧。
# 性能
在关闭数据库的情况下, 加载25个好友128个群运行24小时后内存使用为10MB左右. 开启数据库后内存使用将根据消息量增加10-20MB, 如果系统内存小于128M建议关闭数据库使用.
...
...
coolq/api.go
View file @
a582a1dd
...
...
@@ -34,8 +34,11 @@ func (bot *CQBot) CQGetFriendList() MSG {
}
// https://cqhttp.cc/docs/4.15/#/API?id=get_group_list-%E8%8E%B7%E5%8F%96%E7%BE%A4%E5%88%97%E8%A1%A8
func
(
bot
*
CQBot
)
CQGetGroupList
()
MSG
{
func
(
bot
*
CQBot
)
CQGetGroupList
(
noCache
bool
)
MSG
{
var
gs
[]
MSG
if
noCache
{
_
=
bot
.
Client
.
ReloadGroupList
()
}
for
_
,
g
:=
range
bot
.
Client
.
GroupList
{
gs
=
append
(
gs
,
MSG
{
"group_id"
:
g
.
Code
,
...
...
@@ -96,11 +99,25 @@ func (bot *CQBot) CQGetGroupMemberInfo(groupId, userId int64, noCache bool) MSG
}
// https://cqhttp.cc/docs/4.15/#/API?id=send_group_msg-%E5%8F%91%E9%80%81%E7%BE%A4%E6%B6%88%E6%81%AF
func
(
bot
*
CQBot
)
CQSendGroupMessage
(
groupId
int64
,
i
interface
{})
MSG
{
func
(
bot
*
CQBot
)
CQSendGroupMessage
(
groupId
int64
,
i
interface
{}
,
autoEscape
bool
)
MSG
{
var
str
string
fixAt
:=
func
(
elem
[]
message
.
IMessageElement
)
{
for
_
,
e
:=
range
elem
{
if
at
,
ok
:=
e
.
(
*
message
.
AtElement
);
ok
&&
at
.
Target
!=
0
{
at
.
Display
=
"@"
+
func
()
string
{
mem
:=
bot
.
Client
.
FindGroup
(
groupId
)
.
FindMember
(
at
.
Target
)
if
mem
!=
nil
{
return
mem
.
DisplayName
()
}
return
strconv
.
FormatInt
(
at
.
Target
,
10
)
}()
}
}
}
if
m
,
ok
:=
i
.
(
gjson
.
Result
);
ok
{
if
m
.
Type
==
gjson
.
JSON
{
elem
:=
bot
.
ConvertObjectMessage
(
m
,
true
)
fixAt
(
elem
)
mid
:=
bot
.
SendGroupMessage
(
groupId
,
&
message
.
SendingMessage
{
Elements
:
elem
})
if
mid
==
-
1
{
return
Failed
(
100
)
...
...
@@ -113,20 +130,19 @@ func (bot *CQBot) CQSendGroupMessage(groupId int64, i interface{}) MSG {
}
return
m
.
Raw
}()
}
if
s
,
ok
:=
i
.
(
string
);
ok
{
}
else
if
s
,
ok
:=
i
.
(
string
);
ok
{
str
=
s
}
if
str
==
""
{
return
Failed
(
100
)
}
elem
:=
bot
.
ConvertStringMessage
(
str
,
true
)
// fix at display
for
_
,
e
:=
range
elem
{
if
at
,
ok
:=
e
.
(
*
message
.
AtElement
);
ok
&&
at
.
Target
!=
0
{
at
.
Display
=
"@"
+
bot
.
Client
.
FindGroup
(
groupId
)
.
FindMember
(
at
.
Target
)
.
DisplayName
()
}
var
elem
[]
message
.
IMessageElement
if
autoEscape
{
elem
=
append
(
elem
,
message
.
NewText
(
str
))
}
else
{
elem
=
bot
.
ConvertStringMessage
(
str
,
true
)
}
fixAt
(
elem
)
mid
:=
bot
.
SendGroupMessage
(
groupId
,
&
message
.
SendingMessage
{
Elements
:
elem
})
if
mid
==
-
1
{
return
Failed
(
100
)
...
...
@@ -205,7 +221,7 @@ func (bot *CQBot) CQSendGroupForwardMessage(groupId int64, m gjson.Result) MSG {
}
// https://cqhttp.cc/docs/4.15/#/API?id=send_private_msg-%E5%8F%91%E9%80%81%E7%A7%81%E8%81%8A%E6%B6%88%E6%81%AF
func
(
bot
*
CQBot
)
CQSendPrivateMessage
(
userId
int64
,
i
interface
{})
MSG
{
func
(
bot
*
CQBot
)
CQSendPrivateMessage
(
userId
int64
,
i
interface
{}
,
autoEscape
bool
)
MSG
{
var
str
string
if
m
,
ok
:=
i
.
(
gjson
.
Result
);
ok
{
if
m
.
Type
==
gjson
.
JSON
{
...
...
@@ -222,14 +238,18 @@ func (bot *CQBot) CQSendPrivateMessage(userId int64, i interface{}) MSG {
}
return
m
.
Raw
}()
}
if
s
,
ok
:=
i
.
(
string
);
ok
{
}
else
if
s
,
ok
:=
i
.
(
string
);
ok
{
str
=
s
}
if
str
==
""
{
return
Failed
(
100
)
}
elem
:=
bot
.
ConvertStringMessage
(
str
,
false
)
var
elem
[]
message
.
IMessageElement
if
autoEscape
{
elem
=
append
(
elem
,
message
.
NewText
(
str
))
}
else
{
elem
=
bot
.
ConvertStringMessage
(
str
,
false
)
}
mid
:=
bot
.
SendPrivateMessage
(
userId
,
&
message
.
SendingMessage
{
Elements
:
elem
})
if
mid
==
-
1
{
return
Failed
(
100
)
...
...
@@ -359,6 +379,61 @@ func (bot *CQBot) CQDeleteMessage(messageId int32) MSG {
return
OK
(
nil
)
}
// https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_group_honor_info-%E8%8E%B7%E5%8F%96%E7%BE%A4%E8%8D%A3%E8%AA%89%E4%BF%A1%E6%81%AF
func
(
bot
*
CQBot
)
CQGetGroupHonorInfo
(
groupId
int64
,
t
string
)
MSG
{
msg
:=
MSG
{
"group_id"
:
groupId
}
convertMem
:=
func
(
memList
[]
client
.
HonorMemberInfo
)
(
ret
[]
MSG
)
{
for
_
,
mem
:=
range
memList
{
ret
=
append
(
ret
,
MSG
{
"user_id"
:
mem
.
Uin
,
"nickname"
:
mem
.
Name
,
"avatar"
:
mem
.
Avatar
,
"description"
:
mem
.
Desc
,
})
}
return
}
if
t
==
"talkative"
||
t
==
"all"
{
if
honor
,
err
:=
bot
.
Client
.
GetGroupHonorInfo
(
groupId
,
client
.
Talkative
);
err
==
nil
{
if
honor
.
CurrentTalkative
.
Uin
!=
0
{
msg
[
"current_talkative"
]
=
MSG
{
"user_id"
:
honor
.
CurrentTalkative
.
Uin
,
"nickname"
:
honor
.
CurrentTalkative
.
Name
,
"avatar"
:
honor
.
CurrentTalkative
.
Avatar
,
"day_count"
:
honor
.
CurrentTalkative
.
DayCount
,
}
}
msg
[
"talkative_list"
]
=
convertMem
(
honor
.
TalkativeList
)
}
}
if
t
==
"performer"
||
t
==
"all"
{
if
honor
,
err
:=
bot
.
Client
.
GetGroupHonorInfo
(
groupId
,
client
.
Performer
);
err
==
nil
{
msg
[
"performer_lis"
]
=
convertMem
(
honor
.
ActorList
)
}
}
if
t
==
"legend"
||
t
==
"all"
{
if
honor
,
err
:=
bot
.
Client
.
GetGroupHonorInfo
(
groupId
,
client
.
Legend
);
err
==
nil
{
msg
[
"legend_list"
]
=
convertMem
(
honor
.
LegendList
)
}
}
if
t
==
"strong_newbie"
||
t
==
"all"
{
if
honor
,
err
:=
bot
.
Client
.
GetGroupHonorInfo
(
groupId
,
client
.
StrongNewbie
);
err
==
nil
{
msg
[
"strong_newbie_list"
]
=
convertMem
(
honor
.
StrongNewbieList
)
}
}
if
t
==
"emotion"
||
t
==
"all"
{
if
honor
,
err
:=
bot
.
Client
.
GetGroupHonorInfo
(
groupId
,
client
.
Emotion
);
err
==
nil
{
msg
[
"emotion_list"
]
=
convertMem
(
honor
.
EmotionList
)
}
}
return
OK
(
msg
)
}
// https://cqhttp.cc/docs/4.15/#/API?id=-handle_quick_operation-%E5%AF%B9%E4%BA%8B%E4%BB%B6%E6%89%A7%E8%A1%8C%E5%BF%AB%E9%80%9F%E6%93%8D%E4%BD%9C
// https://github.com/richardchien/coolq-http-api/blob/master/src/cqhttp/plugins/web/http.cpp#L376
func
(
bot
*
CQBot
)
CQHandleQuickOperation
(
context
,
operation
gjson
.
Result
)
MSG
{
...
...
@@ -368,6 +443,7 @@ func (bot *CQBot) CQHandleQuickOperation(context, operation gjson.Result) MSG {
msgType
:=
context
.
Get
(
"message_type"
)
.
Str
reply
:=
operation
.
Get
(
"reply"
)
if
reply
.
Exists
()
{
autoEscape
:=
global
.
EnsureBool
(
operation
.
Get
(
"auto_escape"
),
false
)
/*
at := true
if operation.Get("at_sender").Exists() {
...
...
@@ -376,10 +452,10 @@ func (bot *CQBot) CQHandleQuickOperation(context, operation gjson.Result) MSG {
*/
// TODO: 处理at字段
if
msgType
==
"group"
{
bot
.
CQSendGroupMessage
(
context
.
Get
(
"group_id"
)
.
Int
(),
reply
)
bot
.
CQSendGroupMessage
(
context
.
Get
(
"group_id"
)
.
Int
(),
reply
,
autoEscape
)
}
if
msgType
==
"private"
{
bot
.
CQSendPrivateMessage
(
context
.
Get
(
"user_id"
)
.
Int
(),
reply
)
bot
.
CQSendPrivateMessage
(
context
.
Get
(
"user_id"
)
.
Int
(),
reply
,
autoEscape
)
}
}
if
msgType
==
"group"
{
...
...
@@ -404,12 +480,12 @@ func (bot *CQBot) CQHandleQuickOperation(context, operation gjson.Result) MSG {
}
case
"request"
:
reqType
:=
context
.
Get
(
"request_type"
)
.
Str
if
context
.
Get
(
"approve"
)
.
Bool
()
{
if
operation
.
Get
(
"approve"
)
.
Exists
()
{
if
reqType
==
"friend"
{
bot
.
CQProcessFriendRequest
(
context
.
Get
(
"flag"
)
.
Str
,
true
)
bot
.
CQProcessFriendRequest
(
context
.
Get
(
"flag"
)
.
Str
,
operation
.
Get
(
"approve"
)
.
Bool
()
)
}
if
reqType
==
"group"
{
bot
.
CQProcessGroupRequest
(
context
.
Get
(
"flag"
)
.
Str
,
context
.
Get
(
"sub_type"
)
.
Str
,
true
)
bot
.
CQProcessGroupRequest
(
context
.
Get
(
"flag"
)
.
Str
,
context
.
Get
(
"sub_type"
)
.
Str
,
operation
.
Get
(
"approve"
)
.
Bool
()
)
}
}
}
...
...
@@ -439,7 +515,7 @@ func (bot *CQBot) CQGetForwardMessage(resId string) MSG {
}
var
r
[]
MSG
for
_
,
n
:=
range
m
.
Nodes
{
checkMedia
(
n
.
Message
)
bot
.
checkMedia
(
n
.
Message
)
r
=
append
(
r
,
MSG
{
"sender"
:
MSG
{
"user_id"
:
n
.
SenderId
,
...
...
coolq/bot.go
View file @
a582a1dd
...
...
@@ -12,6 +12,7 @@ import (
log
"github.com/sirupsen/logrus"
"github.com/xujiajun/nutsdb"
"hash/crc32"
"math/rand"
"path"
"sync"
"time"
...
...
@@ -63,6 +64,19 @@ func NewQQBot(cli *client.QQClient, conf *global.JsonConfig) *CQBot {
bot
.
Client
.
OnNewFriendAdded
(
bot
.
friendAddedEvent
)
bot
.
Client
.
OnGroupInvited
(
bot
.
groupInvitedEvent
)
bot
.
Client
.
OnUserWantJoinGroup
(
bot
.
groupJoinReqEvent
)
go
func
()
{
for
{
time
.
Sleep
(
time
.
Second
*
5
)
bot
.
dispatchEventMessage
(
MSG
{
"time"
:
time
.
Now
()
.
Unix
(),
"self_id"
:
bot
.
Client
.
Uin
,
"post_type"
:
"meta_event"
,
"meta_event_type"
:
"heartbeat"
,
"status"
:
nil
,
"interval"
:
5000
,
})
}
}()
return
bot
}
...
...
@@ -85,7 +99,7 @@ func (bot *CQBot) GetGroupMessage(mid int32) MSG {
if
err
==
nil
{
return
m
}
log
.
Warnf
(
"获取信息时出现错误: %v
"
,
err
)
log
.
Warnf
(
"获取信息时出现错误: %v
id: %v"
,
err
,
mid
)
}
return
nil
}
...
...
@@ -94,6 +108,7 @@ func (bot *CQBot) SendGroupMessage(groupId int64, m *message.SendingMessage) int
var
newElem
[]
message
.
IMessageElement
for
_
,
elem
:=
range
m
.
Elements
{
if
i
,
ok
:=
elem
.
(
*
message
.
ImageElement
);
ok
{
_
,
_
=
bot
.
Client
.
UploadGroupImage
(
int64
(
rand
.
Intn
(
11451419
)),
i
.
Data
)
gm
,
err
:=
bot
.
Client
.
UploadGroupImage
(
groupId
,
i
.
Data
)
if
err
!=
nil
{
log
.
Warnf
(
"警告: 群 %v 消息图片上传失败: %v"
,
groupId
,
err
)
...
...
@@ -115,6 +130,9 @@ func (bot *CQBot) SendGroupMessage(groupId int64, m *message.SendingMessage) int
}
m
.
Elements
=
newElem
ret
:=
bot
.
Client
.
SendGroupMessage
(
groupId
,
m
)
if
ret
==
nil
||
ret
.
Id
==
-
1
{
return
-
1
}
return
bot
.
InsertGroupMessage
(
ret
)
}
...
...
@@ -133,16 +151,23 @@ func (bot *CQBot) SendPrivateMessage(target int64, m *message.SendingMessage) in
newElem
=
append
(
newElem
,
elem
)
}
m
.
Elements
=
newElem
var
id
int32
var
id
int32
=
-
1
if
bot
.
Client
.
FindFriend
(
target
)
!=
nil
{
id
=
bot
.
Client
.
SendPrivateMessage
(
target
,
m
)
.
Id
msg
:=
bot
.
Client
.
SendPrivateMessage
(
target
,
m
)
if
msg
!=
nil
{
id
=
msg
.
Id
}
}
else
{
if
code
,
ok
:=
bot
.
tempMsgCache
.
Load
(
target
);
ok
{
id
=
bot
.
Client
.
SendTempMessage
(
code
.
(
int64
),
target
,
m
)
.
Id
}
else
{
return
-
1
msg
:=
bot
.
Client
.
SendTempMessage
(
code
.
(
int64
),
target
,
m
)
if
msg
!=
nil
{
id
=
msg
.
Id
}
}
}
if
id
==
-
1
{
return
-
1
}
return
ToGlobalId
(
target
,
id
)
}
...
...
@@ -191,7 +216,7 @@ func (bot *CQBot) dispatchEventMessage(m MSG) {
fn
(
m
)
end
:=
time
.
Now
()
if
end
.
Sub
(
start
)
>
time
.
Second
*
5
{
log
.
Debugf
(
"警告: 事件处理耗时超过 5 秒 (%v
秒), 请检查应用是否有堵塞."
,
end
.
Sub
(
start
)
/
time
.
Second
)
log
.
Debugf
(
"警告: 事件处理耗时超过 5 秒 (%v
), 请检查应用是否有堵塞."
,
end
.
Sub
(
start
)
)
}
}()
}
...
...
coolq/cqcode.go
View file @
a582a1dd
package
coolq
import
(
"crypto/md5"
"encoding/base64"
"encoding/hex"
"errors"
...
...
@@ -75,6 +76,18 @@ func ToArrayMessage(e []message.IMessageElement, code int64, raw ...bool) (r []M
"data"
:
map
[
string
]
string
{
"file"
:
o
.
Name
,
"url"
:
o
.
Url
},
}
}
case
*
message
.
ShortVideoElement
:
if
ur
{
m
=
MSG
{
"type"
:
"video"
,
"data"
:
map
[
string
]
string
{
"file"
:
o
.
Name
},
}
}
else
{
m
=
MSG
{
"type"
:
"video"
,
"data"
:
map
[
string
]
string
{
"file"
:
o
.
Name
,
"url"
:
o
.
Url
},
}
}
case
*
message
.
ImageElement
:
if
ur
{
m
=
MSG
{
...
...
@@ -120,6 +133,12 @@ func ToStringMessage(e []message.IMessageElement, code int64, raw ...bool) (r st
}
else
{
r
+=
fmt
.
Sprintf
(
`[CQ:record,file=%s,url=%s]`
,
o
.
Name
,
CQCodeEscapeValue
(
o
.
Url
))
}
case
*
message
.
ShortVideoElement
:
if
ur
{
r
+=
fmt
.
Sprintf
(
`[CQ:video,file=%s]`
,
o
.
Name
)
}
else
{
r
+=
fmt
.
Sprintf
(
`[CQ:video,file=%s,url=%s]`
,
o
.
Name
,
CQCodeEscapeValue
(
o
.
Url
))
}
case
*
message
.
ImageElement
:
if
ur
{
r
+=
fmt
.
Sprintf
(
`[CQ:image,file=%s]`
,
o
.
Filename
)
...
...
@@ -243,10 +262,23 @@ func (bot *CQBot) ToElement(t string, d map[string]string, group bool) (message.
case
"image"
:
f
:=
d
[
"file"
]
if
strings
.
HasPrefix
(
f
,
"http"
)
||
strings
.
HasPrefix
(
f
,
"https"
)
{
cache
:=
d
[
"cache"
]
if
cache
==
""
{
cache
=
"1"
}
hash
:=
md5
.
Sum
([]
byte
(
f
))
cacheFile
:=
path
.
Join
(
global
.
CACHE_PATH
,
hex
.
EncodeToString
(
hash
[
:
])
+
".cache"
)
if
global
.
PathExists
(
cacheFile
)
&&
cache
==
"1"
{
b
,
err
:=
ioutil
.
ReadFile
(
cacheFile
)
if
err
==
nil
{
return
message
.
NewImage
(
b
),
nil
}
}
b
,
err
:=
global
.
GetBytes
(
f
)
if
err
!=
nil
{
return
nil
,
err
}
_
=
ioutil
.
WriteFile
(
cacheFile
,
b
,
0644
)
return
message
.
NewImage
(
b
),
nil
}
if
strings
.
HasPrefix
(
f
,
"base64"
)
{
...
...
@@ -367,7 +399,7 @@ func (bot *CQBot) ToElement(t string, d map[string]string, group bool) (message.
}
data
=
b
}
if
!
global
.
IsAMR
(
data
)
{
if
!
global
.
IsAMR
orSILK
(
data
)
{
return
nil
,
errors
.
New
(
"unsupported voice file format (please use AMR file for now)"
)
}
return
&
message
.
VoiceElement
{
Data
:
data
},
nil
...
...
@@ -414,7 +446,7 @@ func CQCodeUnescapeText(content string) string {
}
func
CQCodeUnescapeValue
(
content
string
)
string
{
ret
:=
CQCodeUnescapeText
(
content
)
ret
=
strings
.
ReplaceAll
(
ret
,
","
,
","
)
ret
:=
strings
.
ReplaceAll
(
content
,
","
,
","
)
ret
=
CQCodeUnescapeText
(
ret
)
return
ret
}
coolq/event.go
View file @
a582a1dd
...
...
@@ -30,7 +30,7 @@ func ToFormattedMessage(e []message.IMessageElement, code int64, raw ...bool) (r
}
func
(
bot
*
CQBot
)
privateMessageEvent
(
c
*
client
.
QQClient
,
m
*
message
.
PrivateMessage
)
{
checkMedia
(
m
.
Elements
)
bot
.
checkMedia
(
m
.
Elements
)
cqm
:=
ToStringMessage
(
m
.
Elements
,
0
,
true
)
log
.
Infof
(
"收到好友 %v(%v) 的消息: %v"
,
m
.
Sender
.
DisplayName
(),
m
.
Sender
.
Uin
,
cqm
)
fm
:=
MSG
{
...
...
@@ -55,7 +55,7 @@ func (bot *CQBot) privateMessageEvent(c *client.QQClient, m *message.PrivateMess
}
func
(
bot
*
CQBot
)
groupMessageEvent
(
c
*
client
.
QQClient
,
m
*
message
.
GroupMessage
)
{
checkMedia
(
m
.
Elements
)
bot
.
checkMedia
(
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
)
...
...
@@ -133,7 +133,7 @@ func (bot *CQBot) groupMessageEvent(c *client.QQClient, m *message.GroupMessage)
}
func
(
bot
*
CQBot
)
tempMessageEvent
(
c
*
client
.
QQClient
,
m
*
message
.
TempMessage
)
{
checkMedia
(
m
.
Elements
)
bot
.
checkMedia
(
m
.
Elements
)
cqm
:=
ToStringMessage
(
m
.
Elements
,
0
,
true
)
bot
.
tempMsgCache
.
Store
(
m
.
Sender
.
Uin
,
m
.
GroupCode
)
log
.
Infof
(
"收到来自群 %v(%v) 内 %v(%v) 的临时会话消息: %v"
,
m
.
GroupName
,
m
.
GroupCode
,
m
.
Sender
.
DisplayName
(),
m
.
Sender
.
Uin
,
cqm
)
...
...
@@ -362,7 +362,7 @@ func (bot *CQBot) groupDecrease(groupCode, userUin int64, operator *client.Group
}
}
func
checkMedia
(
e
[]
message
.
IMessageElement
)
{
func
(
bot
*
CQBot
)
checkMedia
(
e
[]
message
.
IMessageElement
)
{
for
_
,
elem
:=
range
e
{
switch
i
:=
elem
.
(
type
)
{
case
*
message
.
ImageElement
:
...
...
@@ -373,7 +373,7 @@ func checkMedia(e []message.IMessageElement) {
w
.
WriteUInt32
(
uint32
(
i
.
Size
))
w
.
WriteString
(
i
.
Filename
)
w
.
WriteString
(
i
.
Url
)
}),
0
777
)
}),
0
644
)
}
i
.
Filename
=
filename
case
*
message
.
VoiceElement
:
...
...
@@ -385,8 +385,20 @@ func checkMedia(e []message.IMessageElement) {
log
.
Warnf
(
"语音文件 %v 下载失败: %v"
,
i
.
Name
,
err
)
continue
}
_
=
ioutil
.
WriteFile
(
path
.
Join
(
global
.
VOICE_PATH
,
i
.
Name
),
b
,
0
777
)
_
=
ioutil
.
WriteFile
(
path
.
Join
(
global
.
VOICE_PATH
,
i
.
Name
),
b
,
0
644
)
}
case
*
message
.
ShortVideoElement
:
filename
:=
hex
.
EncodeToString
(
i
.
Md5
)
+
".video"
if
!
global
.
PathExists
(
path
.
Join
(
global
.
VIDEO_PATH
,
filename
))
{
_
=
ioutil
.
WriteFile
(
path
.
Join
(
global
.
VIDEO_PATH
,
filename
),
binary
.
NewWriterF
(
func
(
w
*
binary
.
Writer
)
{
w
.
Write
(
i
.
Md5
)
w
.
WriteUInt32
(
uint32
(
i
.
Size
))
w
.
WriteString
(
i
.
Name
)
w
.
Write
(
i
.
Uuid
)
}),
0644
)
}
i
.
Name
=
filename
i
.
Url
=
bot
.
Client
.
GetShortVideoUrl
(
i
.
Uuid
,
i
.
Md5
)
}
}
}
docs/config.md
View file @
a582a1dd
...
...
@@ -24,12 +24,13 @@ go-cqhttp 支持导入CQHTTP的配置文件, 具体步骤为:
"access_token"
:
""
,
"relogin"
:
false
,
"relogin_delay"
:
0
,
"post_message_format"
:
"string"
,
"http_config"
:
{
"enabled"
:
true
,
"host"
:
"0.0.0.0"
,
"port"
:
5700
,
"timeout"
:
5
,
"post_urls"
:
{
"url:port"
:
"secret"
},
"post_message_format"
:
"string"
},
"ws_config"
:
{
"enabled"
:
true
,
...
...
global/config.go
View file @
a582a1dd
...
...
@@ -14,9 +14,11 @@ type JsonConfig struct {
AccessToken
string
`json:"access_token"`
ReLogin
bool
`json:"relogin"`
ReLoginDelay
int
`json:"relogin_delay"`
AsyncLoad
bool
`json:"async_load"`
HttpConfig
*
GoCQHttpConfig
`json:"http_config"`
WSConfig
*
GoCQWebsocketConfig
`json:"ws_config"`
ReverseServers
[]
*
GoCQReverseWebsocketConfig
`json:"ws_reverse_servers"`
PostMessageFormat
string
`json:"post_message_format"`
Debug
bool
`json:"debug"`
}
...
...
@@ -45,7 +47,6 @@ type GoCQHttpConfig struct {
Port
uint16
`json:"port"`
Timeout
int32
`json:"timeout"`
PostUrls
map
[
string
]
string
`json:"post_urls"`
PostMessageFormat
string
`json:"post_message_format"`
}
type
GoCQWebsocketConfig
struct
{
...
...
@@ -67,12 +68,12 @@ func DefaultConfig() *JsonConfig {
EnableDB
:
true
,
ReLogin
:
true
,
ReLoginDelay
:
3
,
PostMessageFormat
:
"string"
,
HttpConfig
:
&
GoCQHttpConfig
{
Enabled
:
true
,
Host
:
"0.0.0.0"
,
Port
:
5700
,
PostUrls
:
map
[
string
]
string
{},
PostMessageFormat
:
"string"
,
},
WSConfig
:
&
GoCQWebsocketConfig
{
Enabled
:
true
,
...
...
global/fs.go
View file @
a582a1dd
package
global
import
(
log
"github.com/sirupsen/logru
s"
"byte
s"
"io/ioutil"
"os"
"path"
log
"github.com/sirupsen/logrus"
)
var
IMAGE_PATH
=
path
.
Join
(
"data"
,
"images"
)
var
(
IMAGE_PATH
=
path
.
Join
(
"data"
,
"images"
)
VOICE_PATH
=
path
.
Join
(
"data"
,
"voices"
)
VIDEO_PATH
=
path
.
Join
(
"data"
,
"videos"
)
CACHE_PATH
=
path
.
Join
(
"data"
,
"cache"
)
var
VOICE_PATH
=
path
.
Join
(
"data"
,
"voices"
)
HEADER_AMR
=
[]
byte
(
"#!AMR"
)
HEADER_SILK
=
[]
byte
(
"
\x02
#!SILK_V3"
)
)
func
PathExists
(
path
string
)
bool
{
_
,
err
:=
os
.
Stat
(
path
)
...
...
@@ -25,7 +33,7 @@ func ReadAllText(path string) string {
}
func
WriteAllText
(
path
,
text
string
)
{
_
=
ioutil
.
WriteFile
(
path
,
[]
byte
(
text
),
0
777
)
_
=
ioutil
.
WriteFile
(
path
,
[]
byte
(
text
),
0
644
)
}
func
Check
(
err
error
)
{
...
...
@@ -34,9 +42,6 @@ func Check(err error) {
}
}
func
IsAMR
(
b
[]
byte
)
bool
{
if
len
(
b
)
<=
6
{
return
false
}
return
b
[
0
]
==
0x23
&&
b
[
1
]
==
0x21
&&
b
[
2
]
==
0x41
&&
b
[
3
]
==
0x4D
&&
b
[
4
]
==
0x52
// amr file header
func
IsAMRorSILK
(
b
[]
byte
)
bool
{
return
bytes
.
HasPrefix
(
b
,
HEADER_AMR
)
||
bytes
.
HasPrefix
(
b
,
HEADER_SILK
)
}
global/param.go
0 → 100644
View file @
a582a1dd
package
global
import
(
"github.com/tidwall/gjson"
"strings"
)
var
trueSet
=
map
[
string
]
struct
{}{
"true"
:
{},
"yes"
:
{},
"1"
:
{},
}
var
falseSet
=
map
[
string
]
struct
{}{
"false"
:
{},
"no"
:
{},
"0"
:
{},
}
func
EnsureBool
(
p
interface
{},
defaultVal
bool
)
bool
{
var
str
string
if
b
,
ok
:=
p
.
(
bool
);
ok
{
return
b
}
if
j
,
ok
:=
p
.
(
gjson
.
Result
);
ok
{
if
!
j
.
Exists
()
{
return
defaultVal
}
if
j
.
Type
==
gjson
.
True
{
return
true
}
if
j
.
Type
==
gjson
.
False
{
return
false
}
if
j
.
Type
!=
gjson
.
String
{
return
defaultVal
}
str
=
j
.
Str
}
else
if
s
,
ok
:=
p
.
(
string
);
ok
{
str
=
s
}
str
=
strings
.
ToLower
(
str
)
if
_
,
ok
:=
trueSet
[
str
];
ok
{
return
true
}
if
_
,
ok
:=
falseSet
[
str
];
ok
{
return
false
}
return
defaultVal
}
go.mod
View file @
a582a1dd
...
...
@@ -3,7 +3,7 @@ module github.com/Mrs4s/go-cqhttp
go 1.14
require (
github.com/Mrs4s/MiraiGo v0.0.0-2020081
2011522-ee1117893fad
github.com/Mrs4s/MiraiGo v0.0.0-2020081
9185537-8d1e5fb04c17
github.com/gin-gonic/gin v1.6.3
github.com/gorilla/websocket v1.4.2
github.com/guonaihong/gout v0.1.1
...
...
go.sum
View file @
a582a1dd
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-20200809221224-7a84cfae6795 h1:Bu4k9ZS/IIy9Shwd9lS/C2P/2I8fYUwg1OpRF91hr1w=
github.com/Mrs4s/MiraiGo v0.0.0-20200809221224-7a84cfae6795/go.mod h1:0je03wji/tSw4bUH4QCF2Z4/EjyNWjSJTyy5tliX6EM=
github.com/Mrs4s/MiraiGo v0.0.0-20200810032556-a425f9d1b98e h1:5LYDouOL9ZgTL5PwZuuSlFYSfboRQjnXqRIlhviRcGE=
github.com/Mrs4s/MiraiGo v0.0.0-20200810032556-a425f9d1b98e/go.mod h1:0je03wji/tSw4bUH4QCF2Z4/EjyNWjSJTyy5tliX6EM=
github.com/Mrs4s/MiraiGo v0.0.0-20200812011522-ee1117893fad h1:mOz8SozY2NEjXivlOrTwGPsbukcpLYpi/rv0/ASM/Hg=
github.com/Mrs4s/MiraiGo v0.0.0-20200812011522-ee1117893fad/go.mod h1:0je03wji/tSw4bUH4QCF2Z4/EjyNWjSJTyy5tliX6EM=
github.com/Mrs4s/MiraiGo v0.0.0-20200819185537-8d1e5fb04c17 h1:sY4lwW34serGKnD26hP7ZLpnJ4NfVYKdS2SJIW1Mezs=
github.com/Mrs4s/MiraiGo v0.0.0-20200819185537-8d1e5fb04c17/go.mod h1:0je03wji/tSw4bUH4QCF2Z4/EjyNWjSJTyy5tliX6EM=
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=
...
...
main.go
View file @
a582a1dd
...
...
@@ -38,15 +38,25 @@ func init() {
log
.
SetOutput
(
io
.
MultiWriter
(
os
.
Stderr
,
w
))
}
if
!
global
.
PathExists
(
global
.
IMAGE_PATH
)
{
if
err
:=
os
.
MkdirAll
(
global
.
IMAGE_PATH
,
os
.
ModePerm
);
err
!=
nil
{
if
err
:=
os
.
MkdirAll
(
global
.
IMAGE_PATH
,
0755
);
err
!=
nil
{
log
.
Fatalf
(
"创建图片缓存文件夹失败: %v"
,
err
)
}
}
if
!
global
.
PathExists
(
global
.
VOICE_PATH
)
{
if
err
:=
os
.
MkdirAll
(
global
.
VOICE_PATH
,
os
.
ModePerm
);
err
!=
nil
{
if
err
:=
os
.
MkdirAll
(
global
.
VOICE_PATH
,
0755
);
err
!=
nil
{
log
.
Fatalf
(
"创建语音缓存文件夹失败: %v"
,
err
)
}
}
if
!
global
.
PathExists
(
global
.
VIDEO_PATH
)
{
if
err
:=
os
.
MkdirAll
(
global
.
VIDEO_PATH
,
0755
);
err
!=
nil
{
log
.
Fatalf
(
"创建视频缓存文件夹失败: %v"
,
err
)
}
}
if
!
global
.
PathExists
(
global
.
CACHE_PATH
)
{
if
err
:=
os
.
MkdirAll
(
global
.
CACHE_PATH
,
0755
);
err
!=
nil
{
log
.
Fatalf
(
"创建发送图片缓存文件夹失败: %v"
,
err
)
}
}
if
global
.
PathExists
(
"cqhttp.json"
)
{
log
.
Info
(
"发现 cqhttp.json 将在五秒后尝试导入配置,按 Ctrl+C 取消."
)
log
.
Warn
(
"警告: 该操作会删除 cqhttp.json 并覆盖 config.json 文件."
)
...
...
@@ -96,13 +106,13 @@ func main() {
Host
:
"0.0.0.0"
,
Port
:
5700
,
PostUrls
:
map
[
string
]
string
{},
PostMessageFormat
:
"string"
,
},
WSConfig
:
&
global
.
GoCQWebsocketConfig
{
Enabled
:
true
,
Host
:
"0.0.0.0"
,
Port
:
6700
,
},
PostMessageFormat
:
"string"
,
Debug
:
os
.
Getenv
(
"DEBUG"
)
==
"true"
,
}
if
post
!=
""
{
...
...
@@ -131,7 +141,7 @@ func main() {
if
!
global
.
PathExists
(
"device.json"
)
{
log
.
Warn
(
"虚拟设备信息不存在, 将自动生成随机设备."
)
client
.
GenRandomDevice
()
_
=
ioutil
.
WriteFile
(
"device.json"
,
client
.
SystemDeviceInfo
.
ToJson
(),
os
.
ModePerm
)
_
=
ioutil
.
WriteFile
(
"device.json"
,
client
.
SystemDeviceInfo
.
ToJson
(),
0644
)
log
.
Info
(
"已生成设备信息并保存到 device.json 文件."
)
}
else
{
log
.
Info
(
"将使用 device.json 内的设备信息运行Bot."
)
...
...
@@ -181,7 +191,7 @@ func main() {
if
!
rsp
.
Success
{
switch
rsp
.
Error
{
case
client
.
NeedCaptcha
:
_
=
ioutil
.
WriteFile
(
"captcha.jpg"
,
rsp
.
CaptchaImage
,
os
.
ModePerm
)
_
=
ioutil
.
WriteFile
(
"captcha.jpg"
,
rsp
.
CaptchaImage
,
0644
)
img
,
_
,
_
:=
image
.
Decode
(
bytes
.
NewReader
(
rsp
.
CaptchaImage
))
fmt
.
Println
(
asciiart
.
New
(
"image"
,
img
)
.
Art
)
log
.
Warn
(
"请输入验证码 (captcha.jpg): (Enter 提交)"
)
...
...
@@ -205,17 +215,17 @@ func main() {
global
.
Check
(
cli
.
ReloadFriendList
())
log
.
Infof
(
"共加载 %v 个好友."
,
len
(
cli
.
FriendList
))
log
.
Infof
(
"开始加载群列表..."
)
global
.
Check
(
cli
.
ReloadGroupList
())
global
.
Check
(
cli
.
ReloadGroupList
(
conf
.
AsyncLoad
))
log
.
Infof
(
"共加载 %v 个群."
,
len
(
cli
.
GroupList
))
b
:=
coolq
.
NewQQBot
(
cli
,
conf
)
if
conf
.
HttpConfig
!=
nil
&&
conf
.
HttpConfig
.
Enabled
{
server
.
HttpServer
.
Run
(
fmt
.
Sprintf
(
"%s:%d"
,
conf
.
HttpConfig
.
Host
,
conf
.
HttpConfig
.
Port
),
conf
.
AccessToken
,
b
)
if
conf
.
HttpConfig
.
PostMessageFormat
!=
"string"
&&
conf
.
HttpConfig
.
PostMessageFormat
!=
"array"
{
log
.
Warnf
(
"http_config.post_message_format 配置错误, 将自动使用 string"
)
if
conf
.
PostMessageFormat
!=
"string"
&&
conf
.
PostMessageFormat
!=
"array"
{
log
.
Warnf
(
"post_message_format 配置错误, 将自动使用 string"
)
coolq
.
SetMessageFormat
(
"string"
)
}
else
{
coolq
.
SetMessageFormat
(
conf
.
HttpConfig
.
PostMessageFormat
)
coolq
.
SetMessageFormat
(
conf
.
PostMessageFormat
)
}
if
conf
.
HttpConfig
!=
nil
&&
conf
.
HttpConfig
.
Enabled
{
server
.
HttpServer
.
Run
(
fmt
.
Sprintf
(
"%s:%d"
,
conf
.
HttpConfig
.
Host
,
conf
.
HttpConfig
.
Port
),
conf
.
AccessToken
,
b
)
for
k
,
v
:=
range
conf
.
HttpConfig
.
PostUrls
{
server
.
NewHttpClient
()
.
Run
(
k
,
v
,
conf
.
HttpConfig
.
Timeout
,
b
)
}
...
...
server/http.go
View file @
a582a1dd
...
...
@@ -9,6 +9,7 @@ import (
"time"
"github.com/Mrs4s/go-cqhttp/coolq"
"github.com/Mrs4s/go-cqhttp/global"
"github.com/gin-gonic/gin"
"github.com/guonaihong/gout"
log
"github.com/sirupsen/logrus"
...
...
@@ -133,12 +134,12 @@ func (s *httpServer) Run(addr, authToken string, bot *coolq.CQBot) {
s
.
engine
.
Any
(
"/set_group_leave_async"
,
s
.
SetGroupLeave
)
s
.
engine
.
Any
(
"/get_image"
,
s
.
GetImage
)
s
.
engine
.
Any
(
"/get_image_async"
,
s
.
GetImage
)
s
.
engine
.
Any
(
"/get_forward_msg"
,
s
.
GetForwardMessage
)
s
.
engine
.
Any
(
"/get_group_msg"
,
s
.
GetGroupMessage
)
s
.
engine
.
Any
(
"/get_group_msg_async"
,
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
)
...
...
@@ -208,7 +209,8 @@ func (s *httpServer) GetFriendList(c *gin.Context) {
}
func
(
s
*
httpServer
)
GetGroupList
(
c
*
gin
.
Context
)
{
c
.
JSON
(
200
,
s
.
bot
.
CQGetGroupList
())
nc
:=
getParamOrDefault
(
c
,
"no_cache"
,
"false"
)
c
.
JSON
(
200
,
s
.
bot
.
CQGetGroupList
(
nc
==
"true"
))
}
func
(
s
*
httpServer
)
GetGroupInfo
(
c
*
gin
.
Context
)
{
...
...
@@ -249,21 +251,23 @@ func (s *httpServer) SendMessage(c *gin.Context) {
func
(
s
*
httpServer
)
SendPrivateMessage
(
c
*
gin
.
Context
)
{
uid
,
_
:=
strconv
.
ParseInt
(
getParam
(
c
,
"user_id"
),
10
,
64
)
msg
,
t
:=
getParamWithType
(
c
,
"message"
)
autoEscape
:=
global
.
EnsureBool
(
getParam
(
c
,
"auto_escape"
),
false
)
if
t
==
gjson
.
JSON
{
c
.
JSON
(
200
,
s
.
bot
.
CQSendPrivateMessage
(
uid
,
gjson
.
Parse
(
msg
)))
c
.
JSON
(
200
,
s
.
bot
.
CQSendPrivateMessage
(
uid
,
gjson
.
Parse
(
msg
)
,
autoEscape
))
return
}
c
.
JSON
(
200
,
s
.
bot
.
CQSendPrivateMessage
(
uid
,
msg
))
c
.
JSON
(
200
,
s
.
bot
.
CQSendPrivateMessage
(
uid
,
msg
,
autoEscape
))
}
func
(
s
*
httpServer
)
SendGroupMessage
(
c
*
gin
.
Context
)
{
gid
,
_
:=
strconv
.
ParseInt
(
getParam
(
c
,
"group_id"
),
10
,
64
)
msg
,
t
:=
getParamWithType
(
c
,
"message"
)
autoEscape
:=
global
.
EnsureBool
(
getParam
(
c
,
"auto_escape"
),
false
)
if
t
==
gjson
.
JSON
{
c
.
JSON
(
200
,
s
.
bot
.
CQSendGroupMessage
(
gid
,
gjson
.
Parse
(
msg
)))
c
.
JSON
(
200
,
s
.
bot
.
CQSendGroupMessage
(
gid
,
gjson
.
Parse
(
msg
)
,
autoEscape
))
return
}
c
.
JSON
(
200
,
s
.
bot
.
CQSendGroupMessage
(
gid
,
msg
))
c
.
JSON
(
200
,
s
.
bot
.
CQSendGroupMessage
(
gid
,
msg
,
autoEscape
))
}
func
(
s
*
httpServer
)
SendGroupForwardMessage
(
c
*
gin
.
Context
)
{
...
...
@@ -282,6 +286,11 @@ func (s *httpServer) GetGroupMessage(c *gin.Context) {
c
.
JSON
(
200
,
s
.
bot
.
CQGetGroupMessage
(
int32
(
mid
)))
}
func
(
s
*
httpServer
)
GetGroupHonorInfo
(
c
*
gin
.
Context
)
{
gid
,
_
:=
strconv
.
ParseInt
(
getParam
(
c
,
"group_id"
),
10
,
64
)
c
.
JSON
(
200
,
s
.
bot
.
CQGetGroupHonorInfo
(
gid
,
getParam
(
c
,
"type"
)))
}
func
(
s
*
httpServer
)
ProcessFriendRequest
(
c
*
gin
.
Context
)
{
flag
:=
getParam
(
c
,
"flag"
)
approve
:=
getParamOrDefault
(
c
,
"approve"
,
"true"
)
...
...
server/websocket.go
View file @
a582a1dd
...
...
@@ -7,7 +7,6 @@ import (
"github.com/gorilla/websocket"
log
"github.com/sirupsen/logrus"
"github.com/tidwall/gjson"
wsc
"golang.org/x/net/websocket"
"net/http"
"strconv"
"strings"
...
...
@@ -29,8 +28,8 @@ type websocketClient struct {
bot
*
coolq
.
CQBot
pushLock
*
sync
.
Mutex
universalConn
*
w
sc
.
Conn
eventConn
*
w
sc
.
Conn
universalConn
*
w
ebsocket
.
Conn
eventConn
*
w
ebsocket
.
Conn
}
var
WebsocketServer
=
&
websocketServer
{}
...
...
@@ -79,18 +78,15 @@ func (c *websocketClient) Run() {
func
(
c
*
websocketClient
)
connectApi
()
{
log
.
Infof
(
"开始尝试连接到反向Websocket API服务器: %v"
,
c
.
conf
.
ReverseApiUrl
)
wsConf
,
err
:=
wsc
.
NewConfig
(
c
.
conf
.
ReverseApiUrl
,
c
.
conf
.
ReverseApiUrl
)
if
err
!=
nil
{
log
.
Warnf
(
"连接到反向Websocket API服务器 %v 时出现致命错误: %v"
,
c
.
conf
.
ReverseApiUrl
,
err
)
return
header
:=
http
.
Header
{
"X-Client-Role"
:
[]
string
{
"API"
},
"X-Self-ID"
:
[]
string
{
strconv
.
FormatInt
(
c
.
bot
.
Client
.
Uin
,
10
)},
"User-Agent"
:
[]
string
{
"CQHttp/4.15.0"
},
}
wsConf
.
Header
[
"X-Client-Role"
]
=
[]
string
{
"API"
}
wsConf
.
Header
[
"X-Self-ID"
]
=
[]
string
{
strconv
.
FormatInt
(
c
.
bot
.
Client
.
Uin
,
10
)}
wsConf
.
Header
[
"User-Agent"
]
=
[]
string
{
"CQHttp/4.15.0"
}
if
c
.
token
!=
""
{
wsConf
.
H
eader
[
"Authorization"
]
=
[]
string
{
"Token "
+
c
.
token
}
h
eader
[
"Authorization"
]
=
[]
string
{
"Token "
+
c
.
token
}
}
conn
,
err
:=
wsc
.
DialConfig
(
wsConf
)
conn
,
_
,
err
:=
websocket
.
DefaultDialer
.
Dial
(
c
.
conf
.
ReverseApiUrl
,
header
)
if
err
!=
nil
{
log
.
Warnf
(
"连接到反向Websocket API服务器 %v 时出现错误: %v"
,
c
.
conf
.
ReverseApiUrl
,
err
)
if
c
.
conf
.
ReverseReconnectInterval
!=
0
{
...
...
@@ -105,23 +101,20 @@ func (c *websocketClient) connectApi() {
func
(
c
*
websocketClient
)
connectEvent
()
{
log
.
Infof
(
"开始尝试连接到反向Websocket Event服务器: %v"
,
c
.
conf
.
ReverseEventUrl
)
wsConf
,
err
:=
wsc
.
NewConfig
(
c
.
conf
.
ReverseEventUrl
,
c
.
conf
.
ReverseEventUrl
)
if
err
!=
nil
{
log
.
Warnf
(
"连接到反向Websocket Event服务器 %v 时出现致命错误: %v"
,
c
.
conf
.
ReverseApiUrl
,
err
)
return
header
:=
http
.
Header
{
"X-Client-Role"
:
[]
string
{
"Event"
},
"X-Self-ID"
:
[]
string
{
strconv
.
FormatInt
(
c
.
bot
.
Client
.
Uin
,
10
)},
"User-Agent"
:
[]
string
{
"CQHttp/4.15.0"
},
}
wsConf
.
Header
[
"X-Client-Role"
]
=
[]
string
{
"Event"
}
wsConf
.
Header
[
"X-Self-ID"
]
=
[]
string
{
strconv
.
FormatInt
(
c
.
bot
.
Client
.
Uin
,
10
)}
wsConf
.
Header
[
"User-Agent"
]
=
[]
string
{
"CQHttp/4.15.0"
}
if
c
.
token
!=
""
{
wsConf
.
H
eader
[
"Authorization"
]
=
[]
string
{
"Token "
+
c
.
token
}
h
eader
[
"Authorization"
]
=
[]
string
{
"Token "
+
c
.
token
}
}
conn
,
err
:=
wsc
.
DialConfig
(
wsConf
)
conn
,
_
,
err
:=
websocket
.
DefaultDialer
.
Dial
(
c
.
conf
.
ReverseEventUrl
,
header
)
if
err
!=
nil
{
log
.
Warnf
(
"连接到反向Websocket
API服务器 %v 时出现错误: %v"
,
c
.
conf
.
ReverseApi
Url
,
err
)
log
.
Warnf
(
"连接到反向Websocket
Event服务器 %v 时出现错误: %v"
,
c
.
conf
.
ReverseEvent
Url
,
err
)
if
c
.
conf
.
ReverseReconnectInterval
!=
0
{
time
.
Sleep
(
time
.
Millisecond
*
time
.
Duration
(
c
.
conf
.
ReverseReconnectInterval
))
c
.
connect
Api
()
c
.
connect
Event
()
}
return
}
...
...
@@ -131,18 +124,15 @@ func (c *websocketClient) connectEvent() {
func
(
c
*
websocketClient
)
connectUniversal
()
{
log
.
Infof
(
"开始尝试连接到反向Websocket Universal服务器: %v"
,
c
.
conf
.
ReverseUrl
)
wsConf
,
err
:=
wsc
.
NewConfig
(
c
.
conf
.
ReverseUrl
,
c
.
conf
.
ReverseUrl
)
if
err
!=
nil
{
log
.
Warnf
(
"连接到反向Websocket Universal服务器 %v 时出现致命错误: %v"
,
c
.
conf
.
ReverseUrl
,
err
)
return
header
:=
http
.
Header
{
"X-Client-Role"
:
[]
string
{
"Universal"
},
"X-Self-ID"
:
[]
string
{
strconv
.
FormatInt
(
c
.
bot
.
Client
.
Uin
,
10
)},
"User-Agent"
:
[]
string
{
"CQHttp/4.15.0"
},
}
wsConf
.
Header
[
"X-Client-Role"
]
=
[]
string
{
"Universal"
}
wsConf
.
Header
[
"X-Self-ID"
]
=
[]
string
{
strconv
.
FormatInt
(
c
.
bot
.
Client
.
Uin
,
10
)}
wsConf
.
Header
[
"User-Agent"
]
=
[]
string
{
"CQHttp/4.15.0"
}
if
c
.
token
!=
""
{
wsConf
.
H
eader
[
"Authorization"
]
=
[]
string
{
"Token "
+
c
.
token
}
h
eader
[
"Authorization"
]
=
[]
string
{
"Token "
+
c
.
token
}
}
conn
,
err
:=
wsc
.
DialConfig
(
wsConf
)
conn
,
_
,
err
:=
websocket
.
DefaultDialer
.
Dial
(
c
.
conf
.
ReverseUrl
,
header
)
if
err
!=
nil
{
log
.
Warnf
(
"连接到反向Websocket Universal服务器 %v 时出现错误: %v"
,
c
.
conf
.
ReverseUrl
,
err
)
if
c
.
conf
.
ReverseReconnectInterval
!=
0
{
...
...
@@ -155,12 +145,12 @@ func (c *websocketClient) connectUniversal() {
c
.
universalConn
=
conn
}
func
(
c
*
websocketClient
)
listenApi
(
conn
*
w
sc
.
Conn
,
u
bool
)
{
func
(
c
*
websocketClient
)
listenApi
(
conn
*
w
ebsocket
.
Conn
,
u
bool
)
{
defer
conn
.
Close
()
for
{
var
buf
[]
byte
err
:=
wsc
.
Message
.
Receive
(
conn
,
&
buf
)
_
,
buf
,
err
:=
conn
.
ReadMessage
()
if
err
!=
nil
{
log
.
Warnf
(
"监听反向WS API时出现错误: %v"
,
err
)
break
}
j
:=
gjson
.
ParseBytes
(
buf
)
...
...
@@ -173,18 +163,16 @@ func (c *websocketClient) listenApi(conn *wsc.Conn, u bool) {
}
c
.
pushLock
.
Lock
()
log
.
Debugf
(
"准备发送API %v 处理结果: %v"
,
t
,
ret
.
ToJson
())
_
,
_
=
conn
.
Write
([]
byte
(
ret
.
ToJson
())
)
_
=
conn
.
WriteJSON
(
ret
)
c
.
pushLock
.
Unlock
()
}
}
if
c
.
conf
.
ReverseReconnectInterval
!=
0
{
time
.
Sleep
(
time
.
Millisecond
*
time
.
Duration
(
c
.
conf
.
ReverseReconnectInterval
))
if
u
{
c
.
connectUniversal
()
return
}
if
!
u
{
c
.
connectApi
()
}
}
}
func
(
c
*
websocketClient
)
onBotPushEvent
(
m
coolq
.
MSG
)
{
...
...
@@ -192,7 +180,8 @@ func (c *websocketClient) onBotPushEvent(m coolq.MSG) {
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
{
if
err
:=
c
.
eventConn
.
WriteJSON
(
m
);
err
!=
nil
{
log
.
Warnf
(
"向WS服务器 %v 推送Event时出现错误: %v"
,
c
.
eventConn
.
RemoteAddr
()
.
String
(),
err
)
_
=
c
.
eventConn
.
Close
()
if
c
.
conf
.
ReverseReconnectInterval
!=
0
{
go
func
()
{
...
...
@@ -204,7 +193,16 @@ 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
()))
if
err
:=
c
.
universalConn
.
WriteJSON
(
m
);
err
!=
nil
{
log
.
Warnf
(
"向WS服务器 %v 推送Event时出现错误: %v"
,
c
.
universalConn
.
RemoteAddr
()
.
String
(),
err
)
_
=
c
.
universalConn
.
Close
()
if
c
.
conf
.
ReverseReconnectInterval
!=
0
{
go
func
()
{
time
.
Sleep
(
time
.
Millisecond
*
time
.
Duration
(
c
.
conf
.
ReverseReconnectInterval
))
c
.
connectUniversal
()
}()
}
}
}
}
...
...
@@ -316,7 +314,7 @@ var wsApi = map[string]func(*coolq.CQBot, gjson.Result) coolq.MSG{
return
bot
.
CQGetFriendList
()
},
"get_group_list"
:
func
(
bot
*
coolq
.
CQBot
,
p
gjson
.
Result
)
coolq
.
MSG
{
return
bot
.
CQGetGroupList
()
return
bot
.
CQGetGroupList
(
p
.
Get
(
"no_cache"
)
.
Bool
()
)
},
"get_group_info"
:
func
(
bot
*
coolq
.
CQBot
,
p
gjson
.
Result
)
coolq
.
MSG
{
return
bot
.
CQGetGroupInfo
(
p
.
Get
(
"group_id"
)
.
Int
())
...
...
@@ -331,28 +329,29 @@ var wsApi = map[string]func(*coolq.CQBot, gjson.Result) coolq.MSG{
)
},
"send_msg"
:
func
(
bot
*
coolq
.
CQBot
,
p
gjson
.
Result
)
coolq
.
MSG
{
autoEscape
:=
global
.
EnsureBool
(
p
.
Get
(
"auto_escape"
),
false
)
if
p
.
Get
(
"message_type"
)
.
Str
==
"private"
{
return
bot
.
CQSendPrivateMessage
(
p
.
Get
(
"user_id"
)
.
Int
(),
p
.
Get
(
"message"
))
return
bot
.
CQSendPrivateMessage
(
p
.
Get
(
"user_id"
)
.
Int
(),
p
.
Get
(
"message"
)
,
autoEscape
)
}
if
p
.
Get
(
"message_type"
)
.
Str
==
"group"
{
return
bot
.
CQSendGroupMessage
(
p
.
Get
(
"group_id"
)
.
Int
(),
p
.
Get
(
"message"
))
return
bot
.
CQSendGroupMessage
(
p
.
Get
(
"group_id"
)
.
Int
(),
p
.
Get
(
"message"
)
,
autoEscape
)
}
if
p
.
Get
(
"group_id"
)
.
Int
()
!=
0
{
return
bot
.
CQSendGroupMessage
(
p
.
Get
(
"group_id"
)
.
Int
(),
p
.
Get
(
"message"
))
return
bot
.
CQSendGroupMessage
(
p
.
Get
(
"group_id"
)
.
Int
(),
p
.
Get
(
"message"
)
,
autoEscape
)
}
if
p
.
Get
(
"user_id"
)
.
Int
()
!=
0
{
return
bot
.
CQSendPrivateMessage
(
p
.
Get
(
"user_id"
)
.
Int
(),
p
.
Get
(
"message"
))
return
bot
.
CQSendPrivateMessage
(
p
.
Get
(
"user_id"
)
.
Int
(),
p
.
Get
(
"message"
)
,
autoEscape
)
}
return
coolq
.
MSG
{}
},
"send_group_msg"
:
func
(
bot
*
coolq
.
CQBot
,
p
gjson
.
Result
)
coolq
.
MSG
{
return
bot
.
CQSendGroupMessage
(
p
.
Get
(
"group_id"
)
.
Int
(),
p
.
Get
(
"message"
))
return
bot
.
CQSendGroupMessage
(
p
.
Get
(
"group_id"
)
.
Int
(),
p
.
Get
(
"message"
)
,
global
.
EnsureBool
(
p
.
Get
(
"auto_escape"
),
false
)
)
},
"send_group_forward_msg"
:
func
(
bot
*
coolq
.
CQBot
,
p
gjson
.
Result
)
coolq
.
MSG
{
return
bot
.
CQSendGroupForwardMessage
(
p
.
Get
(
"group_id"
)
.
Int
(),
p
.
Get
(
"messages"
))
},
"send_private_msg"
:
func
(
bot
*
coolq
.
CQBot
,
p
gjson
.
Result
)
coolq
.
MSG
{
return
bot
.
CQSendPrivateMessage
(
p
.
Get
(
"user_id"
)
.
Int
(),
p
.
Get
(
"message"
))
return
bot
.
CQSendPrivateMessage
(
p
.
Get
(
"user_id"
)
.
Int
(),
p
.
Get
(
"message"
)
,
global
.
EnsureBool
(
p
.
Get
(
"auto_escape"
),
false
)
)
},
"delete_msg"
:
func
(
bot
*
coolq
.
CQBot
,
p
gjson
.
Result
)
coolq
.
MSG
{
return
bot
.
CQDeleteMessage
(
int32
(
p
.
Get
(
"message_id"
)
.
Int
()))
...
...
@@ -415,6 +414,9 @@ var wsApi = map[string]func(*coolq.CQBot, gjson.Result) coolq.MSG{
"get_group_msg"
:
func
(
bot
*
coolq
.
CQBot
,
p
gjson
.
Result
)
coolq
.
MSG
{
return
bot
.
CQGetGroupMessage
(
int32
(
p
.
Get
(
"message_id"
)
.
Int
()))
},
"get_group_honor_info"
:
func
(
bot
*
coolq
.
CQBot
,
p
gjson
.
Result
)
coolq
.
MSG
{
return
bot
.
CQGetGroupHonorInfo
(
p
.
Get
(
"group_id"
)
.
Int
(),
p
.
Get
(
"type"
)
.
Str
)
},
"can_send_image"
:
func
(
bot
*
coolq
.
CQBot
,
p
gjson
.
Result
)
coolq
.
MSG
{
return
bot
.
CQCanSendImage
()
},
...
...
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