mirror of
https://github.com/Mrs4s/go-cqhttp.git
synced 2025-06-30 11:53:25 +00:00
Compare commits
42 Commits
Author | SHA1 | Date | |
---|---|---|---|
00d80d5dfc | |||
22d9ddb4ea | |||
fa33dbdd4e | |||
be8b68c8e9 | |||
cef129eff7 | |||
1fac06f58a | |||
1a1f860dbe | |||
f325b26e1a | |||
b545e05a9d | |||
b290a0a596 | |||
774a1e32da | |||
50eee15a67 | |||
edf6180e1c | |||
3c04573e82 | |||
5e49820319 | |||
1418e36bab | |||
611d16d79e | |||
c6f701e8c8 | |||
a49a57b964 | |||
bb03315930 | |||
5683db6324 | |||
f1ffa17d20 | |||
69675aa0f9 | |||
782a3e2a39 | |||
1967e687af | |||
23d436972c | |||
129622dd24 | |||
19104d00a3 | |||
6c0e78b60c | |||
a075f41a51 | |||
cdbf903361 | |||
906247fcf0 | |||
72a7430841 | |||
5c4f586c36 | |||
5d2e202b0c | |||
c27ebadbc4 | |||
d5a8f3ead2 | |||
03bfd9dd3d | |||
0b02178402 | |||
3819f2c2da | |||
fdd517ee8c | |||
2d010326c7 |
5
.dockerignore
Normal file
5
.dockerignore
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
.gitlab-ci.yml
|
||||||
|
.dockerignore
|
||||||
|
Dockerfile
|
||||||
|
README.md
|
||||||
|
LICENSE
|
21
Dockerfile
Normal file
21
Dockerfile
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
FROM golang:1.14.2-alpine AS builder
|
||||||
|
|
||||||
|
RUN go env -w GO111MODULE=auto \
|
||||||
|
&& go env -w CGO_ENABLED=0 \
|
||||||
|
&& mkdir /build
|
||||||
|
|
||||||
|
WORKDIR /build
|
||||||
|
|
||||||
|
COPY ./ .
|
||||||
|
|
||||||
|
RUN cd /build \
|
||||||
|
&& go build -ldflags "-s -w -extldflags '-static'" -o cqhttp
|
||||||
|
|
||||||
|
FROM alpine:latest
|
||||||
|
|
||||||
|
COPY --from=builder /build/cqhttp /usr/bin/cqhttp
|
||||||
|
RUN chmod +x /usr/bin/cqhttp
|
||||||
|
|
||||||
|
WORKDIR /data
|
||||||
|
|
||||||
|
ENTRYPOINT [ "/usr/bin/cqhttp" ]
|
11
README.md
11
README.md
@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
- [CQ:image]
|
- [CQ:image]
|
||||||
- [CQ:record]
|
- [CQ:record]
|
||||||
|
- [CQ:video]
|
||||||
- [CQ:face]
|
- [CQ:face]
|
||||||
- [CQ:at]
|
- [CQ:at]
|
||||||
- [CQ:share]
|
- [CQ:share]
|
||||||
@ -91,6 +92,16 @@
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
# 关于ISSUE
|
||||||
|
|
||||||
|
以下ISSUE会被直接关闭
|
||||||
|
- 提交BUG不使用Template
|
||||||
|
- 询问已知问题
|
||||||
|
- 提问找不到重点
|
||||||
|
- 重复提问
|
||||||
|
|
||||||
|
> 请注意, 开发者并没有义务回复您的问题. 您应该具备基本的提问技巧。
|
||||||
|
|
||||||
# 性能
|
# 性能
|
||||||
|
|
||||||
在关闭数据库的情况下, 加载25个好友128个群运行24小时后内存使用为10MB左右. 开启数据库后内存使用将根据消息量增加10-20MB, 如果系统内存小于128M建议关闭数据库使用.
|
在关闭数据库的情况下, 加载25个好友128个群运行24小时后内存使用为10MB左右. 开启数据库后内存使用将根据消息量增加10-20MB, 如果系统内存小于128M建议关闭数据库使用.
|
||||||
|
18
coolq/api.go
18
coolq/api.go
@ -124,7 +124,13 @@ func (bot *CQBot) CQSendGroupMessage(groupId int64, i interface{}) MSG {
|
|||||||
// fix at display
|
// fix at display
|
||||||
for _, e := range elem {
|
for _, e := range elem {
|
||||||
if at, ok := e.(*message.AtElement); ok && at.Target != 0 {
|
if at, ok := e.(*message.AtElement); ok && at.Target != 0 {
|
||||||
at.Display = "@" + bot.Client.FindGroup(groupId).FindMember(at.Target).DisplayName()
|
at.Display = "@" + func() string {
|
||||||
|
mem := bot.Client.FindGroup(groupId).FindMember(at.Target)
|
||||||
|
if mem != nil {
|
||||||
|
return mem.DisplayName()
|
||||||
|
}
|
||||||
|
return strconv.FormatInt(at.Target, 10)
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mid := bot.SendGroupMessage(groupId, &message.SendingMessage{Elements: elem})
|
mid := bot.SendGroupMessage(groupId, &message.SendingMessage{Elements: elem})
|
||||||
@ -404,12 +410,12 @@ func (bot *CQBot) CQHandleQuickOperation(context, operation gjson.Result) MSG {
|
|||||||
}
|
}
|
||||||
case "request":
|
case "request":
|
||||||
reqType := context.Get("request_type").Str
|
reqType := context.Get("request_type").Str
|
||||||
if context.Get("approve").Bool() {
|
if operation.Get("approve").Exists() {
|
||||||
if reqType == "friend" {
|
if reqType == "friend" {
|
||||||
bot.CQProcessFriendRequest(context.Get("flag").Str, true)
|
bot.CQProcessFriendRequest(context.Get("flag").Str, operation.Get("approve").Bool())
|
||||||
}
|
}
|
||||||
if reqType == "group" {
|
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,14 +445,14 @@ func (bot *CQBot) CQGetForwardMessage(resId string) MSG {
|
|||||||
}
|
}
|
||||||
var r []MSG
|
var r []MSG
|
||||||
for _, n := range m.Nodes {
|
for _, n := range m.Nodes {
|
||||||
checkImage(n.Message)
|
bot.checkMedia(n.Message)
|
||||||
r = append(r, MSG{
|
r = append(r, MSG{
|
||||||
"sender": MSG{
|
"sender": MSG{
|
||||||
"user_id": n.SenderId,
|
"user_id": n.SenderId,
|
||||||
"nickname": n.SenderName,
|
"nickname": n.SenderName,
|
||||||
},
|
},
|
||||||
"time": n.Time,
|
"time": n.Time,
|
||||||
"content": ToStringMessage(n.Message, 0, false),
|
"content": ToFormattedMessage(n.Message, 0, false),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return OK(MSG{
|
return OK(MSG{
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/xujiajun/nutsdb"
|
"github.com/xujiajun/nutsdb"
|
||||||
"hash/crc32"
|
"hash/crc32"
|
||||||
|
"math/rand"
|
||||||
"path"
|
"path"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@ -85,7 +86,7 @@ func (bot *CQBot) GetGroupMessage(mid int32) MSG {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
log.Warnf("获取信息时出现错误: %v", err)
|
log.Warnf("获取信息时出现错误: %v id: %v", err, mid)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -94,6 +95,7 @@ func (bot *CQBot) SendGroupMessage(groupId int64, m *message.SendingMessage) int
|
|||||||
var newElem []message.IMessageElement
|
var newElem []message.IMessageElement
|
||||||
for _, elem := range m.Elements {
|
for _, elem := range m.Elements {
|
||||||
if i, ok := elem.(*message.ImageElement); ok {
|
if i, ok := elem.(*message.ImageElement); ok {
|
||||||
|
_, _ = bot.Client.UploadGroupImage(int64(rand.Intn(11451419)), i.Data)
|
||||||
gm, err := bot.Client.UploadGroupImage(groupId, i.Data)
|
gm, err := bot.Client.UploadGroupImage(groupId, i.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("警告: 群 %v 消息图片上传失败: %v", groupId, err)
|
log.Warnf("警告: 群 %v 消息图片上传失败: %v", groupId, err)
|
||||||
@ -191,7 +193,7 @@ func (bot *CQBot) dispatchEventMessage(m MSG) {
|
|||||||
fn(m)
|
fn(m)
|
||||||
end := time.Now()
|
end := time.Now()
|
||||||
if end.Sub(start) > time.Second*5 {
|
if end.Sub(start) > time.Second*5 {
|
||||||
log.Debugf("警告: 事件处理耗时超过 5 秒 (%v秒), 请检查应用是否有堵塞.", end.Sub(start)/time.Second)
|
log.Debugf("警告: 事件处理耗时超过 5 秒 (%v), 请检查应用是否有堵塞.", end.Sub(start))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
117
coolq/cqcode.go
117
coolq/cqcode.go
@ -23,6 +23,88 @@ var matchReg = regexp.MustCompile(`\[CQ:\w+?.*?]`)
|
|||||||
var typeReg = regexp.MustCompile(`\[CQ:(\w+)`)
|
var typeReg = regexp.MustCompile(`\[CQ:(\w+)`)
|
||||||
var paramReg = regexp.MustCompile(`,([\w\-.]+?)=([^,\]]+)`)
|
var paramReg = regexp.MustCompile(`,([\w\-.]+?)=([^,\]]+)`)
|
||||||
|
|
||||||
|
func ToArrayMessage(e []message.IMessageElement, code int64, raw ...bool) (r []MSG) {
|
||||||
|
ur := false
|
||||||
|
if len(raw) != 0 {
|
||||||
|
ur = raw[0]
|
||||||
|
}
|
||||||
|
for _, elem := range e {
|
||||||
|
m := MSG{}
|
||||||
|
switch o := elem.(type) {
|
||||||
|
case *message.TextElement:
|
||||||
|
m = MSG{
|
||||||
|
"type": "text",
|
||||||
|
"data": map[string]string{"text": o.Content},
|
||||||
|
}
|
||||||
|
case *message.AtElement:
|
||||||
|
if o.Target == 0 {
|
||||||
|
m = MSG{
|
||||||
|
"type": "at",
|
||||||
|
"data": map[string]string{"qq": "all"},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m = MSG{
|
||||||
|
"type": "at",
|
||||||
|
"data": map[string]string{"qq": fmt.Sprint(o.Target)},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case *message.ReplyElement:
|
||||||
|
m = MSG{
|
||||||
|
"type": "reply",
|
||||||
|
"data": map[string]string{"id": fmt.Sprint(ToGlobalId(code, o.ReplySeq))},
|
||||||
|
}
|
||||||
|
case *message.ForwardElement:
|
||||||
|
m = MSG{
|
||||||
|
"type": "forward",
|
||||||
|
"data": map[string]string{"id": o.ResId},
|
||||||
|
}
|
||||||
|
case *message.FaceElement:
|
||||||
|
m = MSG{
|
||||||
|
"type": "face",
|
||||||
|
"data": map[string]string{"id": fmt.Sprint(o.Index)},
|
||||||
|
}
|
||||||
|
case *message.VoiceElement:
|
||||||
|
if ur {
|
||||||
|
m = MSG{
|
||||||
|
"type": "record",
|
||||||
|
"data": map[string]string{"file": o.Name},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m = MSG{
|
||||||
|
"type": "record",
|
||||||
|
"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{
|
||||||
|
"type": "image",
|
||||||
|
"data": map[string]string{"file": o.Filename},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m = MSG{
|
||||||
|
"type": "image",
|
||||||
|
"data": map[string]string{"file": o.Filename, "url": o.Url},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r = append(r, m)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func ToStringMessage(e []message.IMessageElement, code int64, raw ...bool) (r string) {
|
func ToStringMessage(e []message.IMessageElement, code int64, raw ...bool) (r string) {
|
||||||
ur := false
|
ur := false
|
||||||
if len(raw) != 0 {
|
if len(raw) != 0 {
|
||||||
@ -45,12 +127,22 @@ func ToStringMessage(e []message.IMessageElement, code int64, raw ...bool) (r st
|
|||||||
case *message.FaceElement:
|
case *message.FaceElement:
|
||||||
r += fmt.Sprintf(`[CQ:face,id=%d]`, o.Index)
|
r += fmt.Sprintf(`[CQ:face,id=%d]`, o.Index)
|
||||||
case *message.VoiceElement:
|
case *message.VoiceElement:
|
||||||
|
if ur {
|
||||||
r += fmt.Sprintf(`[CQ:record,file=%s]`, o.Name)
|
r += fmt.Sprintf(`[CQ:record,file=%s]`, o.Name)
|
||||||
|
} 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:
|
case *message.ImageElement:
|
||||||
if ur {
|
if ur {
|
||||||
r += fmt.Sprintf(`[CQ:image,file=%s]`, o.Filename)
|
r += fmt.Sprintf(`[CQ:image,file=%s]`, o.Filename)
|
||||||
} else {
|
} else {
|
||||||
r += fmt.Sprintf(`[CQ:image,file=%s,url=%s]`, o.Filename, o.Url)
|
r += fmt.Sprintf(`[CQ:image,file=%s,url=%s]`, o.Filename, CQCodeEscapeValue(o.Url))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -71,7 +163,7 @@ func (bot *CQBot) ConvertStringMessage(m string, group bool) (r []message.IMessa
|
|||||||
ps := paramReg.FindAllStringSubmatch(code, -1)
|
ps := paramReg.FindAllStringSubmatch(code, -1)
|
||||||
d := make(map[string]string)
|
d := make(map[string]string)
|
||||||
for _, p := range ps {
|
for _, p := range ps {
|
||||||
d[p[1]] = p[2]
|
d[p[1]] = CQCodeUnescapeValue(p[2])
|
||||||
}
|
}
|
||||||
if t == "reply" && group {
|
if t == "reply" && group {
|
||||||
if len(r) > 0 {
|
if len(r) > 0 {
|
||||||
@ -286,6 +378,13 @@ func (bot *CQBot) ToElement(t string, d map[string]string, group bool) (message.
|
|||||||
}
|
}
|
||||||
data = b
|
data = b
|
||||||
}
|
}
|
||||||
|
if global.PathExists(path.Join(global.VOICE_PATH, f)) {
|
||||||
|
b, err := ioutil.ReadFile(path.Join(global.VOICE_PATH, f))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
data = b
|
||||||
|
}
|
||||||
if !global.IsAMR(data) {
|
if !global.IsAMR(data) {
|
||||||
return nil, errors.New("unsupported voice file format (please use AMR file for now)")
|
return nil, errors.New("unsupported voice file format (please use AMR file for now)")
|
||||||
}
|
}
|
||||||
@ -312,9 +411,15 @@ func (bot *CQBot) ToElement(t string, d map[string]string, group bool) (message.
|
|||||||
|
|
||||||
func CQCodeEscapeText(raw string) string {
|
func CQCodeEscapeText(raw string) string {
|
||||||
ret := raw
|
ret := raw
|
||||||
|
ret = strings.ReplaceAll(ret, "&", "&")
|
||||||
ret = strings.ReplaceAll(ret, "[", "[")
|
ret = strings.ReplaceAll(ret, "[", "[")
|
||||||
ret = strings.ReplaceAll(ret, "]", "]")
|
ret = strings.ReplaceAll(ret, "]", "]")
|
||||||
ret = strings.ReplaceAll(ret, "&", "&")
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func CQCodeEscapeValue(value string) string {
|
||||||
|
ret := CQCodeEscapeText(value)
|
||||||
|
ret = strings.ReplaceAll(ret, ",", ",")
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,3 +430,9 @@ func CQCodeUnescapeText(content string) string {
|
|||||||
ret = strings.ReplaceAll(ret, "&", "&")
|
ret = strings.ReplaceAll(ret, "&", "&")
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CQCodeUnescapeValue(content string) string {
|
||||||
|
ret := strings.ReplaceAll(content, ",", ",")
|
||||||
|
ret = CQCodeUnescapeText(ret)
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
@ -10,11 +10,27 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"path"
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var format = "string"
|
||||||
|
|
||||||
|
func SetMessageFormat(f string) {
|
||||||
|
format = f
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToFormattedMessage(e []message.IMessageElement, code int64, raw ...bool) (r interface{}) {
|
||||||
|
if format == "string" {
|
||||||
|
r = ToStringMessage(e, code, raw...)
|
||||||
|
} else if format == "array" {
|
||||||
|
r = ToArrayMessage(e, code, raw...)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (bot *CQBot) privateMessageEvent(c *client.QQClient, m *message.PrivateMessage) {
|
func (bot *CQBot) privateMessageEvent(c *client.QQClient, m *message.PrivateMessage) {
|
||||||
checkImage(m.Elements)
|
bot.checkMedia(m.Elements)
|
||||||
cqm := ToStringMessage(m.Elements, 0, true)
|
cqm := ToStringMessage(m.Elements, 0, true)
|
||||||
log.Infof("收到好友 %v(%v) 的消息: %v", m.Sender.DisplayName(), m.Sender.Uin, cqm)
|
log.Infof("收到好友 %v(%v) 的消息: %v", m.Sender.DisplayName(), m.Sender.Uin, cqm)
|
||||||
fm := MSG{
|
fm := MSG{
|
||||||
@ -23,7 +39,7 @@ func (bot *CQBot) privateMessageEvent(c *client.QQClient, m *message.PrivateMess
|
|||||||
"sub_type": "friend",
|
"sub_type": "friend",
|
||||||
"message_id": ToGlobalId(m.Sender.Uin, m.Id),
|
"message_id": ToGlobalId(m.Sender.Uin, m.Id),
|
||||||
"user_id": m.Sender.Uin,
|
"user_id": m.Sender.Uin,
|
||||||
"message": ToStringMessage(m.Elements, 0, false),
|
"message": ToFormattedMessage(m.Elements, 0, false),
|
||||||
"raw_message": cqm,
|
"raw_message": cqm,
|
||||||
"font": 0,
|
"font": 0,
|
||||||
"self_id": c.Uin,
|
"self_id": c.Uin,
|
||||||
@ -39,7 +55,7 @@ func (bot *CQBot) privateMessageEvent(c *client.QQClient, m *message.PrivateMess
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (bot *CQBot) groupMessageEvent(c *client.QQClient, m *message.GroupMessage) {
|
func (bot *CQBot) groupMessageEvent(c *client.QQClient, m *message.GroupMessage) {
|
||||||
checkImage(m.Elements)
|
bot.checkMedia(m.Elements)
|
||||||
for _, elem := range m.Elements {
|
for _, elem := range m.Elements {
|
||||||
if file, ok := elem.(*message.GroupFileElement); ok {
|
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)
|
log.Infof("群 %v(%v) 内 %v(%v) 上传了文件: %v", m.GroupName, m.GroupCode, m.Sender.DisplayName(), m.Sender.Uin, file.Name)
|
||||||
@ -71,7 +87,7 @@ func (bot *CQBot) groupMessageEvent(c *client.QQClient, m *message.GroupMessage)
|
|||||||
"anonymous": nil,
|
"anonymous": nil,
|
||||||
"font": 0,
|
"font": 0,
|
||||||
"group_id": m.GroupCode,
|
"group_id": m.GroupCode,
|
||||||
"message": ToStringMessage(m.Elements, m.GroupCode, false),
|
"message": ToFormattedMessage(m.Elements, m.GroupCode, false),
|
||||||
"message_id": id,
|
"message_id": id,
|
||||||
"message_type": "group",
|
"message_type": "group",
|
||||||
"post_type": "message",
|
"post_type": "message",
|
||||||
@ -117,7 +133,7 @@ func (bot *CQBot) groupMessageEvent(c *client.QQClient, m *message.GroupMessage)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (bot *CQBot) tempMessageEvent(c *client.QQClient, m *message.TempMessage) {
|
func (bot *CQBot) tempMessageEvent(c *client.QQClient, m *message.TempMessage) {
|
||||||
checkImage(m.Elements)
|
bot.checkMedia(m.Elements)
|
||||||
cqm := ToStringMessage(m.Elements, 0, true)
|
cqm := ToStringMessage(m.Elements, 0, true)
|
||||||
bot.tempMsgCache.Store(m.Sender.Uin, m.GroupCode)
|
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)
|
log.Infof("收到来自群 %v(%v) 内 %v(%v) 的临时会话消息: %v", m.GroupName, m.GroupCode, m.Sender.DisplayName(), m.Sender.Uin, cqm)
|
||||||
@ -127,7 +143,7 @@ func (bot *CQBot) tempMessageEvent(c *client.QQClient, m *message.TempMessage) {
|
|||||||
"sub_type": "group",
|
"sub_type": "group",
|
||||||
"message_id": m.Id,
|
"message_id": m.Id,
|
||||||
"user_id": m.Sender.Uin,
|
"user_id": m.Sender.Uin,
|
||||||
"message": ToStringMessage(m.Elements, 0, false),
|
"message": ToFormattedMessage(m.Elements, 0, false),
|
||||||
"raw_message": cqm,
|
"raw_message": cqm,
|
||||||
"font": 0,
|
"font": 0,
|
||||||
"self_id": c.Uin,
|
"self_id": c.Uin,
|
||||||
@ -300,7 +316,7 @@ func (bot *CQBot) groupJoinReqEvent(c *client.QQClient, e *client.UserJoinGroupR
|
|||||||
"sub_type": "add",
|
"sub_type": "add",
|
||||||
"group_id": e.GroupCode,
|
"group_id": e.GroupCode,
|
||||||
"user_id": e.RequesterUin,
|
"user_id": e.RequesterUin,
|
||||||
"comment": "",
|
"comment": e.Message,
|
||||||
"flag": flag,
|
"flag": flag,
|
||||||
"time": time.Now().Unix(),
|
"time": time.Now().Unix(),
|
||||||
"self_id": c.Uin,
|
"self_id": c.Uin,
|
||||||
@ -346,9 +362,10 @@ func (bot *CQBot) groupDecrease(groupCode, userUin int64, operator *client.Group
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkImage(e []message.IMessageElement) {
|
func (bot *CQBot) checkMedia(e []message.IMessageElement) {
|
||||||
for _, elem := range e {
|
for _, elem := range e {
|
||||||
if i, ok := elem.(*message.ImageElement); ok {
|
switch i := elem.(type) {
|
||||||
|
case *message.ImageElement:
|
||||||
filename := hex.EncodeToString(i.Md5) + ".image"
|
filename := hex.EncodeToString(i.Md5) + ".image"
|
||||||
if !global.PathExists(path.Join(global.IMAGE_PATH, filename)) {
|
if !global.PathExists(path.Join(global.IMAGE_PATH, filename)) {
|
||||||
_ = ioutil.WriteFile(path.Join(global.IMAGE_PATH, filename), binary.NewWriterF(func(w *binary.Writer) {
|
_ = ioutil.WriteFile(path.Join(global.IMAGE_PATH, filename), binary.NewWriterF(func(w *binary.Writer) {
|
||||||
@ -356,9 +373,32 @@ func checkImage(e []message.IMessageElement) {
|
|||||||
w.WriteUInt32(uint32(i.Size))
|
w.WriteUInt32(uint32(i.Size))
|
||||||
w.WriteString(i.Filename)
|
w.WriteString(i.Filename)
|
||||||
w.WriteString(i.Url)
|
w.WriteString(i.Url)
|
||||||
}), 0777)
|
}), 0644)
|
||||||
}
|
}
|
||||||
i.Filename = filename
|
i.Filename = filename
|
||||||
|
case *message.VoiceElement:
|
||||||
|
i.Name = strings.ReplaceAll(i.Name, "{", "")
|
||||||
|
i.Name = strings.ReplaceAll(i.Name, "}", "")
|
||||||
|
if !global.PathExists(path.Join(global.VOICE_PATH, i.Name)) {
|
||||||
|
b, err := global.GetBytes(i.Url)
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("语音文件 %v 下载失败: %v", i.Name, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
_ = ioutil.WriteFile(path.Join(global.VOICE_PATH, i.Name), b, 0644)
|
||||||
|
}
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,11 +24,13 @@ go-cqhttp 支持导入CQHTTP的配置文件, 具体步骤为:
|
|||||||
"access_token": "",
|
"access_token": "",
|
||||||
"relogin": false,
|
"relogin": false,
|
||||||
"relogin_delay": 0,
|
"relogin_delay": 0,
|
||||||
|
"post_message_format": "string",
|
||||||
"http_config": {
|
"http_config": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"host": "0.0.0.0",
|
"host": "0.0.0.0",
|
||||||
"port": 5700,
|
"port": 5700,
|
||||||
"post_urls": {"url:port": "secret"}
|
"timeout": 5,
|
||||||
|
"post_urls": {"url:port": "secret"},
|
||||||
},
|
},
|
||||||
"ws_config": {
|
"ws_config": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
|
@ -14,9 +14,11 @@ type JsonConfig struct {
|
|||||||
AccessToken string `json:"access_token"`
|
AccessToken string `json:"access_token"`
|
||||||
ReLogin bool `json:"relogin"`
|
ReLogin bool `json:"relogin"`
|
||||||
ReLoginDelay int `json:"relogin_delay"`
|
ReLoginDelay int `json:"relogin_delay"`
|
||||||
|
AsyncLoad bool `json:"async_load"`
|
||||||
HttpConfig *GoCQHttpConfig `json:"http_config"`
|
HttpConfig *GoCQHttpConfig `json:"http_config"`
|
||||||
WSConfig *GoCQWebsocketConfig `json:"ws_config"`
|
WSConfig *GoCQWebsocketConfig `json:"ws_config"`
|
||||||
ReverseServers []*GoCQReverseWebsocketConfig `json:"ws_reverse_servers"`
|
ReverseServers []*GoCQReverseWebsocketConfig `json:"ws_reverse_servers"`
|
||||||
|
PostMessageFormat string `json:"post_message_format"`
|
||||||
Debug bool `json:"debug"`
|
Debug bool `json:"debug"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,6 +45,7 @@ type GoCQHttpConfig struct {
|
|||||||
Enabled bool `json:"enabled"`
|
Enabled bool `json:"enabled"`
|
||||||
Host string `json:"host"`
|
Host string `json:"host"`
|
||||||
Port uint16 `json:"port"`
|
Port uint16 `json:"port"`
|
||||||
|
Timeout int32 `json:"timeout"`
|
||||||
PostUrls map[string]string `json:"post_urls"`
|
PostUrls map[string]string `json:"post_urls"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,6 +68,7 @@ func DefaultConfig() *JsonConfig {
|
|||||||
EnableDB: true,
|
EnableDB: true,
|
||||||
ReLogin: true,
|
ReLogin: true,
|
||||||
ReLoginDelay: 3,
|
ReLoginDelay: 3,
|
||||||
|
PostMessageFormat: "string",
|
||||||
HttpConfig: &GoCQHttpConfig{
|
HttpConfig: &GoCQHttpConfig{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
Host: "0.0.0.0",
|
Host: "0.0.0.0",
|
||||||
|
@ -9,6 +9,10 @@ import (
|
|||||||
|
|
||||||
var IMAGE_PATH = path.Join("data", "images")
|
var IMAGE_PATH = path.Join("data", "images")
|
||||||
|
|
||||||
|
var VOICE_PATH = path.Join("data", "voices")
|
||||||
|
|
||||||
|
var VIDEO_PATH = path.Join("data", "videos")
|
||||||
|
|
||||||
func PathExists(path string) bool {
|
func PathExists(path string) bool {
|
||||||
_, err := os.Stat(path)
|
_, err := os.Stat(path)
|
||||||
return err == nil || os.IsExist(err)
|
return err == nil || os.IsExist(err)
|
||||||
@ -23,7 +27,7 @@ func ReadAllText(path string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func WriteAllText(path, text string) {
|
func WriteAllText(path, text string) {
|
||||||
_ = ioutil.WriteFile(path, []byte(text), 0777)
|
_ = ioutil.WriteFile(path, []byte(text), 0644)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Check(err error) {
|
func Check(err error) {
|
||||||
|
2
go.mod
2
go.mod
@ -3,7 +3,7 @@ module github.com/Mrs4s/go-cqhttp
|
|||||||
go 1.14
|
go 1.14
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Mrs4s/MiraiGo v0.0.0-20200809221224-7a84cfae6795
|
github.com/Mrs4s/MiraiGo v0.0.0-20200816111850-988a766ae224
|
||||||
github.com/gin-gonic/gin v1.6.3
|
github.com/gin-gonic/gin v1.6.3
|
||||||
github.com/gorilla/websocket v1.4.2
|
github.com/gorilla/websocket v1.4.2
|
||||||
github.com/guonaihong/gout v0.1.1
|
github.com/guonaihong/gout v0.1.1
|
||||||
|
6
go.sum
6
go.sum
@ -1,7 +1,9 @@
|
|||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
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/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-20200813091456-988a010b51df h1:ERLrnv7bONrg4NqvC8AWhtEgCZk97uCZdRpQS4gF8UE=
|
||||||
github.com/Mrs4s/MiraiGo v0.0.0-20200809221224-7a84cfae6795/go.mod h1:0je03wji/tSw4bUH4QCF2Z4/EjyNWjSJTyy5tliX6EM=
|
github.com/Mrs4s/MiraiGo v0.0.0-20200813091456-988a010b51df/go.mod h1:0je03wji/tSw4bUH4QCF2Z4/EjyNWjSJTyy5tliX6EM=
|
||||||
|
github.com/Mrs4s/MiraiGo v0.0.0-20200816111850-988a766ae224 h1:tlWc7RpBCh5VhT0H6wzm/knxj2PpAV3J7wQyieF0nkk=
|
||||||
|
github.com/Mrs4s/MiraiGo v0.0.0-20200816111850-988a766ae224/go.mod h1:0je03wji/tSw4bUH4QCF2Z4/EjyNWjSJTyy5tliX6EM=
|
||||||
github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0=
|
github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0=
|
||||||
github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE=
|
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=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
|
33
main.go
33
main.go
@ -36,14 +36,21 @@ func init() {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
log.SetOutput(io.MultiWriter(os.Stderr, w))
|
log.SetOutput(io.MultiWriter(os.Stderr, w))
|
||||||
}
|
}
|
||||||
if !global.PathExists("data") {
|
if !global.PathExists(global.IMAGE_PATH) {
|
||||||
if err := os.Mkdir("data", 0777); err != nil {
|
if err := os.MkdirAll(global.IMAGE_PATH, 0755); err != nil {
|
||||||
log.Fatalf("创建数据文件夹失败: %v", err)
|
|
||||||
}
|
|
||||||
if err := os.Mkdir(path.Join("data", "images"), 0777); err != nil {
|
|
||||||
log.Fatalf("创建图片缓存文件夹失败: %v", err)
|
log.Fatalf("创建图片缓存文件夹失败: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if !global.PathExists(global.VOICE_PATH) {
|
||||||
|
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("cqhttp.json") {
|
if global.PathExists("cqhttp.json") {
|
||||||
log.Info("发现 cqhttp.json 将在五秒后尝试导入配置,按 Ctrl+C 取消.")
|
log.Info("发现 cqhttp.json 将在五秒后尝试导入配置,按 Ctrl+C 取消.")
|
||||||
log.Warn("警告: 该操作会删除 cqhttp.json 并覆盖 config.json 文件.")
|
log.Warn("警告: 该操作会删除 cqhttp.json 并覆盖 config.json 文件.")
|
||||||
@ -99,6 +106,7 @@ func main() {
|
|||||||
Host: "0.0.0.0",
|
Host: "0.0.0.0",
|
||||||
Port: 6700,
|
Port: 6700,
|
||||||
},
|
},
|
||||||
|
PostMessageFormat: "string",
|
||||||
Debug: os.Getenv("DEBUG") == "true",
|
Debug: os.Getenv("DEBUG") == "true",
|
||||||
}
|
}
|
||||||
if post != "" {
|
if post != "" {
|
||||||
@ -127,7 +135,7 @@ func main() {
|
|||||||
if !global.PathExists("device.json") {
|
if !global.PathExists("device.json") {
|
||||||
log.Warn("虚拟设备信息不存在, 将自动生成随机设备.")
|
log.Warn("虚拟设备信息不存在, 将自动生成随机设备.")
|
||||||
client.GenRandomDevice()
|
client.GenRandomDevice()
|
||||||
_ = ioutil.WriteFile("device.json", client.SystemDeviceInfo.ToJson(), 0777)
|
_ = ioutil.WriteFile("device.json", client.SystemDeviceInfo.ToJson(), 0644)
|
||||||
log.Info("已生成设备信息并保存到 device.json 文件.")
|
log.Info("已生成设备信息并保存到 device.json 文件.")
|
||||||
} else {
|
} else {
|
||||||
log.Info("将使用 device.json 内的设备信息运行Bot.")
|
log.Info("将使用 device.json 内的设备信息运行Bot.")
|
||||||
@ -163,9 +171,10 @@ func main() {
|
|||||||
if !rsp.Success {
|
if !rsp.Success {
|
||||||
switch rsp.Error {
|
switch rsp.Error {
|
||||||
case client.NeedCaptcha:
|
case client.NeedCaptcha:
|
||||||
|
_ = ioutil.WriteFile("captcha.jpg", rsp.CaptchaImage, 0644)
|
||||||
img, _, _ := image.Decode(bytes.NewReader(rsp.CaptchaImage))
|
img, _, _ := image.Decode(bytes.NewReader(rsp.CaptchaImage))
|
||||||
fmt.Println(asciiart.New("image", img).Art)
|
fmt.Println(asciiart.New("image", img).Art)
|
||||||
log.Warn("请输入验证码: (Enter 提交)")
|
log.Warn("请输入验证码 (captcha.jpg): (Enter 提交)")
|
||||||
text, _ := console.ReadString('\n')
|
text, _ := console.ReadString('\n')
|
||||||
rsp, err = cli.SubmitCaptcha(strings.ReplaceAll(text, "\n", ""), rsp.CaptchaSign)
|
rsp, err = cli.SubmitCaptcha(strings.ReplaceAll(text, "\n", ""), rsp.CaptchaSign)
|
||||||
continue
|
continue
|
||||||
@ -186,13 +195,19 @@ func main() {
|
|||||||
global.Check(cli.ReloadFriendList())
|
global.Check(cli.ReloadFriendList())
|
||||||
log.Infof("共加载 %v 个好友.", len(cli.FriendList))
|
log.Infof("共加载 %v 个好友.", len(cli.FriendList))
|
||||||
log.Infof("开始加载群列表...")
|
log.Infof("开始加载群列表...")
|
||||||
global.Check(cli.ReloadGroupList())
|
global.Check(cli.ReloadGroupList(conf.AsyncLoad))
|
||||||
log.Infof("共加载 %v 个群.", len(cli.GroupList))
|
log.Infof("共加载 %v 个群.", len(cli.GroupList))
|
||||||
b := coolq.NewQQBot(cli, conf)
|
b := coolq.NewQQBot(cli, conf)
|
||||||
|
if conf.PostMessageFormat != "string" && conf.PostMessageFormat != "array" {
|
||||||
|
log.Warnf("post_message_format 配置错误, 将自动使用 string")
|
||||||
|
coolq.SetMessageFormat("string")
|
||||||
|
} else {
|
||||||
|
coolq.SetMessageFormat(conf.PostMessageFormat)
|
||||||
|
}
|
||||||
if conf.HttpConfig != nil && conf.HttpConfig.Enabled {
|
if conf.HttpConfig != nil && conf.HttpConfig.Enabled {
|
||||||
server.HttpServer.Run(fmt.Sprintf("%s:%d", conf.HttpConfig.Host, conf.HttpConfig.Port), conf.AccessToken, b)
|
server.HttpServer.Run(fmt.Sprintf("%s:%d", conf.HttpConfig.Host, conf.HttpConfig.Port), conf.AccessToken, b)
|
||||||
for k, v := range conf.HttpConfig.PostUrls {
|
for k, v := range conf.HttpConfig.PostUrls {
|
||||||
server.NewHttpClient().Run(k, v, b)
|
server.NewHttpClient().Run(k, v, conf.HttpConfig.Timeout, b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if conf.WSConfig != nil && conf.WSConfig.Enabled {
|
if conf.WSConfig != nil && conf.WSConfig.Enabled {
|
||||||
|
@ -24,6 +24,7 @@ type httpClient struct {
|
|||||||
bot *coolq.CQBot
|
bot *coolq.CQBot
|
||||||
secret string
|
secret string
|
||||||
addr string
|
addr string
|
||||||
|
timeout int32
|
||||||
}
|
}
|
||||||
|
|
||||||
var HttpServer = &httpServer{}
|
var HttpServer = &httpServer{}
|
||||||
@ -163,10 +164,14 @@ func NewHttpClient() *httpClient {
|
|||||||
return &httpClient{}
|
return &httpClient{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *httpClient) Run(addr, secret string, bot *coolq.CQBot) {
|
func (c *httpClient) Run(addr, secret string, timeout int32, bot *coolq.CQBot) {
|
||||||
c.bot = bot
|
c.bot = bot
|
||||||
c.secret = secret
|
c.secret = secret
|
||||||
c.addr = addr
|
c.addr = addr
|
||||||
|
c.timeout = timeout
|
||||||
|
if c.timeout < 5 {
|
||||||
|
c.timeout = 5
|
||||||
|
}
|
||||||
bot.OnEventPush(c.onBotPushEvent)
|
bot.OnEventPush(c.onBotPushEvent)
|
||||||
log.Infof("HTTP POST上报器已启动: %v", addr)
|
log.Infof("HTTP POST上报器已启动: %v", addr)
|
||||||
}
|
}
|
||||||
@ -184,7 +189,7 @@ func (c *httpClient) onBotPushEvent(m coolq.MSG) {
|
|||||||
h["X-Signature"] = "sha1=" + hex.EncodeToString(mac.Sum(nil))
|
h["X-Signature"] = "sha1=" + hex.EncodeToString(mac.Sum(nil))
|
||||||
}
|
}
|
||||||
return h
|
return h
|
||||||
}()).SetTimeout(time.Second * 5).Do()
|
}()).SetTimeout(time.Second * time.Duration(c.timeout)).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("上报Event数据到 %v 失败: %v", c.addr, err)
|
log.Warnf("上报Event数据到 %v 失败: %v", c.addr, err)
|
||||||
return
|
return
|
||||||
@ -224,6 +229,14 @@ func (s *httpServer) GetGroupMemberInfo(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *httpServer) SendMessage(c *gin.Context) {
|
func (s *httpServer) SendMessage(c *gin.Context) {
|
||||||
|
if getParam(c, "message_type") == "private" {
|
||||||
|
s.SendPrivateMessage(c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if getParam(c, "message_type") == "group" {
|
||||||
|
s.SendGroupMessage(c)
|
||||||
|
return
|
||||||
|
}
|
||||||
if getParam(c, "group_id") != "" {
|
if getParam(c, "group_id") != "" {
|
||||||
s.SendGroupMessage(c)
|
s.SendGroupMessage(c)
|
||||||
return
|
return
|
||||||
@ -235,8 +248,8 @@ func (s *httpServer) SendMessage(c *gin.Context) {
|
|||||||
|
|
||||||
func (s *httpServer) SendPrivateMessage(c *gin.Context) {
|
func (s *httpServer) SendPrivateMessage(c *gin.Context) {
|
||||||
uid, _ := strconv.ParseInt(getParam(c, "user_id"), 10, 64)
|
uid, _ := strconv.ParseInt(getParam(c, "user_id"), 10, 64)
|
||||||
msg := getParam(c, "message")
|
msg, t := getParamWithType(c, "message")
|
||||||
if gjson.Valid(msg) {
|
if t == gjson.JSON {
|
||||||
c.JSON(200, s.bot.CQSendPrivateMessage(uid, gjson.Parse(msg)))
|
c.JSON(200, s.bot.CQSendPrivateMessage(uid, gjson.Parse(msg)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -245,8 +258,8 @@ func (s *httpServer) SendPrivateMessage(c *gin.Context) {
|
|||||||
|
|
||||||
func (s *httpServer) SendGroupMessage(c *gin.Context) {
|
func (s *httpServer) SendGroupMessage(c *gin.Context) {
|
||||||
gid, _ := strconv.ParseInt(getParam(c, "group_id"), 10, 64)
|
gid, _ := strconv.ParseInt(getParam(c, "group_id"), 10, 64)
|
||||||
msg := getParam(c, "message")
|
msg, t := getParamWithType(c, "message")
|
||||||
if gjson.Valid(msg) {
|
if t == gjson.JSON {
|
||||||
c.JSON(200, s.bot.CQSendGroupMessage(gid, gjson.Parse(msg)))
|
c.JSON(200, s.bot.CQSendGroupMessage(gid, gjson.Parse(msg)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -372,14 +385,19 @@ func getParamOrDefault(c *gin.Context, k, def string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getParam(c *gin.Context, k string) string {
|
func getParam(c *gin.Context, k string) string {
|
||||||
|
p, _ := getParamWithType(c, k)
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func getParamWithType(c *gin.Context, k string) (string, gjson.Type) {
|
||||||
if q := c.Query(k); q != "" {
|
if q := c.Query(k); q != "" {
|
||||||
return q
|
return q, gjson.Null
|
||||||
}
|
}
|
||||||
if c.Request.Method == "POST" {
|
if c.Request.Method == "POST" {
|
||||||
if h := c.Request.Header.Get("Content-Type"); h != "" {
|
if h := c.Request.Header.Get("Content-Type"); h != "" {
|
||||||
if h == "application/x-www-form-urlencoded" {
|
if h == "application/x-www-form-urlencoded" {
|
||||||
if p, ok := c.GetPostForm(k); ok {
|
if p, ok := c.GetPostForm(k); ok {
|
||||||
return p
|
return p, gjson.Null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if h == "application/json" {
|
if h == "application/json" {
|
||||||
@ -388,20 +406,20 @@ func getParam(c *gin.Context, k string) string {
|
|||||||
if res.Exists() {
|
if res.Exists() {
|
||||||
switch res.Type {
|
switch res.Type {
|
||||||
case gjson.JSON:
|
case gjson.JSON:
|
||||||
return res.Raw
|
return res.Raw, gjson.JSON
|
||||||
case gjson.String:
|
case gjson.String:
|
||||||
return res.Str
|
return res.Str, gjson.String
|
||||||
case gjson.Number:
|
case gjson.Number:
|
||||||
return strconv.FormatInt(res.Int(), 10) // 似乎没有需要接受 float 类型的api
|
return strconv.FormatInt(res.Int(), 10), gjson.Number // 似乎没有需要接受 float 类型的api
|
||||||
case gjson.True:
|
case gjson.True:
|
||||||
return "true"
|
return "true", gjson.True
|
||||||
case gjson.False:
|
case gjson.False:
|
||||||
return "false"
|
return "false", gjson.False
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ""
|
return "", gjson.Null
|
||||||
}
|
}
|
||||||
|
@ -136,7 +136,6 @@ func (c *websocketClient) connectUniversal() {
|
|||||||
log.Warnf("连接到反向Websocket Universal服务器 %v 时出现致命错误: %v", c.conf.ReverseUrl, err)
|
log.Warnf("连接到反向Websocket Universal服务器 %v 时出现致命错误: %v", c.conf.ReverseUrl, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
wsConf.Dialer.Timeout = time.Second * 5
|
|
||||||
wsConf.Header["X-Client-Role"] = []string{"Universal"}
|
wsConf.Header["X-Client-Role"] = []string{"Universal"}
|
||||||
wsConf.Header["X-Self-ID"] = []string{strconv.FormatInt(c.bot.Client.Uin, 10)}
|
wsConf.Header["X-Self-ID"] = []string{strconv.FormatInt(c.bot.Client.Uin, 10)}
|
||||||
wsConf.Header["User-Agent"] = []string{"CQHttp/4.15.0"}
|
wsConf.Header["User-Agent"] = []string{"CQHttp/4.15.0"}
|
||||||
@ -173,18 +172,17 @@ func (c *websocketClient) listenApi(conn *wsc.Conn, u bool) {
|
|||||||
ret["echo"] = j.Get("echo").Value()
|
ret["echo"] = j.Get("echo").Value()
|
||||||
}
|
}
|
||||||
c.pushLock.Lock()
|
c.pushLock.Lock()
|
||||||
|
log.Debugf("准备发送API %v 处理结果: %v", t, ret.ToJson())
|
||||||
_, _ = conn.Write([]byte(ret.ToJson()))
|
_, _ = conn.Write([]byte(ret.ToJson()))
|
||||||
c.pushLock.Unlock()
|
c.pushLock.Unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if c.conf.ReverseReconnectInterval != 0 {
|
if c.conf.ReverseReconnectInterval != 0 {
|
||||||
time.Sleep(time.Millisecond * time.Duration(c.conf.ReverseReconnectInterval))
|
time.Sleep(time.Millisecond * time.Duration(c.conf.ReverseReconnectInterval))
|
||||||
if u {
|
if !u {
|
||||||
c.connectUniversal()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.connectApi()
|
c.connectApi()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *websocketClient) onBotPushEvent(m coolq.MSG) {
|
func (c *websocketClient) onBotPushEvent(m coolq.MSG) {
|
||||||
@ -192,7 +190,6 @@ func (c *websocketClient) onBotPushEvent(m coolq.MSG) {
|
|||||||
defer c.pushLock.Unlock()
|
defer c.pushLock.Unlock()
|
||||||
if c.eventConn != nil {
|
if c.eventConn != nil {
|
||||||
log.Debugf("向WS服务器 %v 推送Event: %v", c.eventConn.RemoteAddr().String(), m.ToJson())
|
log.Debugf("向WS服务器 %v 推送Event: %v", c.eventConn.RemoteAddr().String(), m.ToJson())
|
||||||
_ = c.eventConn.SetWriteDeadline(time.Now().Add(time.Second * 3))
|
|
||||||
if _, err := c.eventConn.Write([]byte(m.ToJson())); err != nil {
|
if _, err := c.eventConn.Write([]byte(m.ToJson())); err != nil {
|
||||||
_ = c.eventConn.Close()
|
_ = c.eventConn.Close()
|
||||||
if c.conf.ReverseReconnectInterval != 0 {
|
if c.conf.ReverseReconnectInterval != 0 {
|
||||||
@ -205,8 +202,15 @@ func (c *websocketClient) onBotPushEvent(m coolq.MSG) {
|
|||||||
}
|
}
|
||||||
if c.universalConn != nil {
|
if c.universalConn != nil {
|
||||||
log.Debugf("向WS服务器 %v 推送Event: %v", c.universalConn.RemoteAddr().String(), m.ToJson())
|
log.Debugf("向WS服务器 %v 推送Event: %v", c.universalConn.RemoteAddr().String(), m.ToJson())
|
||||||
_ = c.universalConn.SetWriteDeadline(time.Now().Add(time.Second * 3))
|
if _, err := c.universalConn.Write([]byte(m.ToJson())); err != nil {
|
||||||
_, _ = c.universalConn.Write([]byte(m.ToJson()))
|
_ = c.universalConn.Close()
|
||||||
|
if c.conf.ReverseReconnectInterval != 0 {
|
||||||
|
go func() {
|
||||||
|
time.Sleep(time.Millisecond * time.Duration(c.conf.ReverseReconnectInterval))
|
||||||
|
c.connectUniversal()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,6 +337,12 @@ var wsApi = map[string]func(*coolq.CQBot, gjson.Result) coolq.MSG{
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
"send_msg": func(bot *coolq.CQBot, p gjson.Result) coolq.MSG {
|
"send_msg": func(bot *coolq.CQBot, p gjson.Result) coolq.MSG {
|
||||||
|
if p.Get("message_type").Str == "private" {
|
||||||
|
return bot.CQSendPrivateMessage(p.Get("user_id").Int(), p.Get("message"))
|
||||||
|
}
|
||||||
|
if p.Get("message_type").Str == "group" {
|
||||||
|
return bot.CQSendGroupMessage(p.Get("group_id").Int(), p.Get("message"))
|
||||||
|
}
|
||||||
if p.Get("group_id").Int() != 0 {
|
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"))
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user