mirror of
https://github.com/Mrs4s/go-cqhttp.git
synced 2025-05-04 19:17:37 +08:00
Merge branch 'dev'
This commit is contained in:
commit
bf77951f8d
106
coolq/api.go
106
coolq/api.go
@ -403,7 +403,7 @@ func (bot *CQBot) CQSendGroupForwardMessage(groupID int64, m gjson.Result) MSG {
|
||||
if m.Type != gjson.JSON {
|
||||
return Failed(100)
|
||||
}
|
||||
var sendNodes []*message.ForwardNode
|
||||
fm := message.NewForwardMessage()
|
||||
ts := time.Now().Add(-time.Minute * 5)
|
||||
hasCustom := false
|
||||
m.ForEach(func(_, item gjson.Result) bool {
|
||||
@ -414,8 +414,23 @@ func (bot *CQBot) CQSendGroupForwardMessage(groupID int64, m gjson.Result) MSG {
|
||||
return true
|
||||
})
|
||||
|
||||
var convert func(e gjson.Result) []*message.ForwardNode
|
||||
convert = func(e gjson.Result) (nodes []*message.ForwardNode) {
|
||||
var resolveElement = func(elems []message.IMessageElement) []message.IMessageElement {
|
||||
for i, elem := range elems {
|
||||
switch elem.(type) {
|
||||
case *LocalImageElement, *LocalVideoElement:
|
||||
gm, err := bot.uploadMedia(elem, groupID, true)
|
||||
if err != nil {
|
||||
log.Warnf("警告: 群 %d %s上传失败: %v", groupID, elem.Type().String(), err)
|
||||
continue
|
||||
}
|
||||
elems[i] = gm
|
||||
}
|
||||
}
|
||||
return elems
|
||||
}
|
||||
|
||||
var convert func(e gjson.Result) *message.ForwardNode
|
||||
convert = func(e gjson.Result) *message.ForwardNode {
|
||||
if e.Get("type").Str != "node" {
|
||||
return nil
|
||||
}
|
||||
@ -425,7 +440,7 @@ func (bot *CQBot) CQSendGroupForwardMessage(groupID int64, m gjson.Result) MSG {
|
||||
m := bot.GetMessage(int32(i))
|
||||
if m != nil {
|
||||
sender := m["sender"].(message.Sender)
|
||||
nodes = append(nodes, &message.ForwardNode{
|
||||
return &message.ForwardNode{
|
||||
SenderId: sender.Uin,
|
||||
SenderName: (&sender).DisplayName(),
|
||||
Time: func() int32 {
|
||||
@ -435,12 +450,11 @@ func (bot *CQBot) CQSendGroupForwardMessage(groupID int64, m gjson.Result) MSG {
|
||||
}
|
||||
return msgTime
|
||||
}(),
|
||||
Message: bot.ConvertStringMessage(m["message"].(string), true),
|
||||
})
|
||||
return
|
||||
Message: resolveElement(bot.ConvertStringMessage(m["message"].(string), true)),
|
||||
}
|
||||
}
|
||||
log.Warnf("警告: 引用消息 %v 错误或数据库未开启.", e.Get("data.id").Str)
|
||||
return
|
||||
return nil
|
||||
}
|
||||
uin := e.Get("data.[user_id,uin].0").Int()
|
||||
msgTime := e.Get("data.time").Int()
|
||||
@ -450,63 +464,59 @@ func (bot *CQBot) CQSendGroupForwardMessage(groupID int64, m gjson.Result) MSG {
|
||||
name := e.Get("data.name").Str
|
||||
c := e.Get("data.content")
|
||||
if c.IsArray() {
|
||||
flag := false
|
||||
nested := false
|
||||
c.ForEach(func(_, value gjson.Result) bool {
|
||||
if value.Get("type").Str == "node" {
|
||||
flag = true
|
||||
nested = true
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
if flag {
|
||||
var taowa []*message.ForwardNode
|
||||
if nested { // 处理嵌套
|
||||
nest := message.NewForwardMessage()
|
||||
for _, item := range c.Array() {
|
||||
taowa = append(taowa, convert(item)...)
|
||||
node := convert(item)
|
||||
if node != nil {
|
||||
nest.AddNode(node)
|
||||
}
|
||||
nodes = append(nodes, &message.ForwardNode{
|
||||
}
|
||||
elem := bot.Client.UploadGroupForwardMessage(groupID, nest)
|
||||
return &message.ForwardNode{
|
||||
SenderId: uin,
|
||||
SenderName: name,
|
||||
Time: int32(msgTime),
|
||||
Message: []message.IMessageElement{bot.Client.UploadGroupForwardMessage(groupID, &message.ForwardMessage{Nodes: taowa})},
|
||||
})
|
||||
return
|
||||
Message: []message.IMessageElement{elem},
|
||||
}
|
||||
}
|
||||
}
|
||||
content := bot.ConvertObjectMessage(e.Get("data.content"), true)
|
||||
if uin != 0 && name != "" && len(content) > 0 {
|
||||
var newElem []message.IMessageElement
|
||||
for _, elem := range content {
|
||||
switch elem.(type) {
|
||||
case *LocalImageElement, *LocalVideoElement:
|
||||
gm, err := bot.uploadMedia(elem, groupID, true)
|
||||
if err != nil {
|
||||
log.Warnf("警告: 群 %d %s上传失败: %v", groupID, elem.Type().String(), err)
|
||||
continue
|
||||
}
|
||||
elem = gm
|
||||
}
|
||||
newElem = append(newElem, elem)
|
||||
}
|
||||
nodes = append(nodes, &message.ForwardNode{
|
||||
return &message.ForwardNode{
|
||||
SenderId: uin,
|
||||
SenderName: name,
|
||||
Time: int32(msgTime),
|
||||
Message: newElem,
|
||||
})
|
||||
return
|
||||
Message: resolveElement(content),
|
||||
}
|
||||
}
|
||||
log.Warnf("警告: 非法 Forward node 将跳过. uin: %v name: %v content count: %v", uin, name, len(content))
|
||||
return
|
||||
return nil
|
||||
}
|
||||
if m.IsArray() {
|
||||
for _, item := range m.Array() {
|
||||
sendNodes = append(sendNodes, convert(item)...)
|
||||
node := convert(item)
|
||||
if node != nil {
|
||||
fm.AddNode(node)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sendNodes = convert(m)
|
||||
node := convert(m)
|
||||
if node != nil {
|
||||
fm.AddNode(node)
|
||||
}
|
||||
if len(sendNodes) > 0 {
|
||||
ret := bot.Client.SendGroupForwardMessage(groupID, &message.ForwardMessage{Nodes: sendNodes})
|
||||
}
|
||||
if fm.Length() > 0 {
|
||||
fe := bot.Client.UploadGroupForwardMessage(groupID, fm)
|
||||
ret := bot.Client.SendGroupForwardMessage(groupID, fe)
|
||||
if ret == nil || ret.Id == -1 {
|
||||
log.Warnf("合并转发(群)消息发送失败: 账号可能被风控.")
|
||||
return Failed(100, "SEND_MSG_API_ERROR", "请参考 go-cqhttp 端输出")
|
||||
@ -1408,6 +1418,23 @@ func (bot *CQBot) CQSetModelShow(modelName string, modelShow string) MSG {
|
||||
return OK(nil)
|
||||
}
|
||||
|
||||
// CQMarkMessageAsRead 标记消息已读
|
||||
func (bot *CQBot) CQMarkMessageAsRead(msgID int32) MSG {
|
||||
m := bot.GetMessage(msgID)
|
||||
if m == nil {
|
||||
return Failed(100, "MSG_NOT_FOUND", "消息不存在")
|
||||
}
|
||||
if _, ok := m["group"]; ok {
|
||||
bot.Client.MarkGroupMessageReaded(m["group"].(int64), int64(m["message-id"].(int32)))
|
||||
return OK(nil)
|
||||
}
|
||||
if _, ok := m["from-group"]; ok {
|
||||
return Failed(100, "MSG_TYPE_ERROR", "不支持标记临时会话")
|
||||
}
|
||||
bot.Client.MarkPrivateMessageReaded(m["sender"].(*message.Sender).Uin, m["time"].(int64))
|
||||
return OK(nil)
|
||||
}
|
||||
|
||||
// OK 生成成功返回值
|
||||
func OK(data interface{}) MSG {
|
||||
return MSG{"data": data, "retcode": 0, "status": "ok"}
|
||||
@ -1445,6 +1472,7 @@ func convertGroupMemberInfo(groupID int64, m *client.GroupMemberInfo) MSG {
|
||||
"area": "",
|
||||
"join_time": m.JoinTime,
|
||||
"last_sent_time": m.LastSpeakTime,
|
||||
"shut_up_timestamp": m.ShutUpTimestamp,
|
||||
"level": strconv.FormatInt(int64(m.Level), 10),
|
||||
"role": func() string {
|
||||
switch m.Permission {
|
||||
|
42
coolq/bot.go
42
coolq/bot.go
@ -81,9 +81,9 @@ var ForceFragmented = false
|
||||
// SkipMimeScan 是否跳过Mime扫描
|
||||
var SkipMimeScan bool
|
||||
|
||||
var lawfulImageTypes = []string{"image/png", "image/jpeg", "image/gif", "image/bmp"}
|
||||
var lawfulImageTypes = [...]string{"image/png", "image/jpeg", "image/gif", "image/bmp", "image/webp"}
|
||||
|
||||
var lawfulAudioTypes = []string{
|
||||
var lawfulAudioTypes = [...]string{
|
||||
"audio/mpeg", "audio/flac", "audio/midi", "audio/ogg",
|
||||
"audio/ape", "audio/amr", "audio/wav", "audio/aiff",
|
||||
"audio/mp4", "audio/aac", "audio/x-m4a",
|
||||
@ -126,6 +126,7 @@ func NewQQBot(cli *client.QQClient, conf *config.Config) *CQBot {
|
||||
bot.Client.OnGroupMessageRecalled(bot.groupRecallEvent)
|
||||
bot.Client.OnGroupNotify(bot.groupNotifyEvent)
|
||||
bot.Client.OnFriendNotify(bot.friendNotifyEvent)
|
||||
bot.Client.OnMemberSpecialTitleUpdated(bot.memberTitleUpdatedEvent)
|
||||
bot.Client.OnFriendMessageRecalled(bot.friendRecallEvent)
|
||||
bot.Client.OnReceivedOfflineFile(bot.offlineFileEvent)
|
||||
bot.Client.OnJoinGroup(bot.joinGroupEvent)
|
||||
@ -211,7 +212,6 @@ func (bot *CQBot) UploadLocalImageAsGroup(groupCode int64, img *LocalImageElemen
|
||||
|
||||
// UploadLocalVideo 上传本地短视频至群聊
|
||||
func (bot *CQBot) UploadLocalVideo(target int64, v *LocalVideoElement) (*message.ShortVideoElement, error) {
|
||||
if v.File != "" {
|
||||
video, err := os.Open(v.File)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -222,24 +222,22 @@ func (bot *CQBot) UploadLocalVideo(target int64, v *LocalVideoElement) (*message
|
||||
_, _ = video.Seek(0, io.SeekStart)
|
||||
_, _ = v.thumb.Seek(0, io.SeekStart)
|
||||
return bot.Client.UploadGroupShortVideo(target, video, v.thumb, cacheFile)
|
||||
}
|
||||
return &v.ShortVideoElement, nil
|
||||
}
|
||||
|
||||
// UploadLocalImageAsPrivate 上传本地图片至私聊
|
||||
func (bot *CQBot) UploadLocalImageAsPrivate(userID int64, img *LocalImageElement) (i *message.FriendImageElement, err error) {
|
||||
if img.Stream != nil {
|
||||
if img.File != "" {
|
||||
f, err := os.Open(img.File)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "open image error")
|
||||
}
|
||||
defer func() { _ = f.Close() }()
|
||||
img.Stream = f
|
||||
}
|
||||
if lawful, mime := IsLawfulImage(img.Stream); !lawful {
|
||||
return nil, errors.New("image type error: " + mime)
|
||||
}
|
||||
i, err = bot.Client.UploadPrivateImage(userID, img.Stream)
|
||||
} else {
|
||||
// need update.
|
||||
f, e := os.Open(img.File)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
defer f.Close()
|
||||
i, err = bot.Client.UploadPrivateImage(userID, f)
|
||||
}
|
||||
|
||||
if i != nil {
|
||||
i.Flash = img.Flash
|
||||
}
|
||||
@ -428,7 +426,7 @@ func (bot *CQBot) InsertTempMessage(target int64, m *message.TempMessage) int32
|
||||
val := MSG{
|
||||
"message-id": m.Id,
|
||||
// FIXME(InsertTempMessage) InternalId missing
|
||||
"group": m.GroupCode,
|
||||
"from-group": m.GroupCode,
|
||||
"group-name": m.GroupName,
|
||||
"target": target,
|
||||
"sender": m.Sender,
|
||||
@ -516,7 +514,7 @@ func (bot *CQBot) formatGroupMessage(m *message.GroupMessage) MSG {
|
||||
"user_id": m.Sender.Uin,
|
||||
},
|
||||
"sub_type": "normal",
|
||||
"time": time.Now().Unix(),
|
||||
"time": m.Time,
|
||||
"user_id": m.Sender.Uin,
|
||||
}
|
||||
if m.Sender.IsAnonymous() {
|
||||
@ -604,6 +602,10 @@ func IsLawfulImage(r io.ReadSeeker) (bool, string) {
|
||||
log.Debugf("扫描 Mime 时出现问题: %v", err)
|
||||
return false, ""
|
||||
}
|
||||
mime := t.String()
|
||||
return mimetype.EqualsAny(mime, lawfulImageTypes...), mime
|
||||
for _, lt := range lawfulImageTypes {
|
||||
if t.Is(lt) {
|
||||
return true, t.String()
|
||||
}
|
||||
}
|
||||
return false, t.String()
|
||||
}
|
||||
|
@ -81,7 +81,6 @@ type LocalVoiceElement struct {
|
||||
|
||||
// LocalVideoElement 本地视频
|
||||
type LocalVideoElement struct {
|
||||
message.ShortVideoElement
|
||||
File string
|
||||
thumb io.ReadSeeker
|
||||
}
|
||||
@ -97,6 +96,11 @@ func (e *GiftElement) Type() message.ElementType {
|
||||
return message.At
|
||||
}
|
||||
|
||||
// Type impl message.IMessageElement
|
||||
func (e *LocalVideoElement) Type() message.ElementType {
|
||||
return message.Video
|
||||
}
|
||||
|
||||
// GiftID 礼物ID数组
|
||||
var GiftID = [...]message.GroupGift{
|
||||
message.SweetWink,
|
||||
@ -731,9 +735,16 @@ func (bot *CQBot) ToElement(t string, d map[string]string, isGroup bool) (m inte
|
||||
return nil, err
|
||||
}
|
||||
if !SkipMimeScan && !global.IsAMRorSILK(data) {
|
||||
mt := mimetype.Detect(data).String()
|
||||
if !mimetype.EqualsAny(mt, lawfulAudioTypes...) {
|
||||
return nil, errors.New("audio type error: " + mt)
|
||||
mt := mimetype.Detect(data)
|
||||
lawful := false
|
||||
for _, lt := range lawfulAudioTypes {
|
||||
if mt.Is(lt) {
|
||||
lawful = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !lawful {
|
||||
return nil, errors.New("audio type error: " + mt.String())
|
||||
}
|
||||
}
|
||||
if !global.IsAMRorSILK(data) {
|
||||
@ -895,7 +906,10 @@ func (bot *CQBot) ToElement(t string, d map[string]string, isGroup bool) (m inte
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v := file.(*LocalVideoElement)
|
||||
v, ok := file.(*LocalVideoElement)
|
||||
if !ok {
|
||||
return file, nil
|
||||
}
|
||||
if v.File == "" {
|
||||
return v, nil
|
||||
}
|
||||
@ -1117,14 +1131,14 @@ func (bot *CQBot) makeImageOrVideoElem(d map[string]string, video, group bool) (
|
||||
if path.Ext(rawPath) == ".video" {
|
||||
b, _ := os.ReadFile(rawPath)
|
||||
r := binary.NewReader(b)
|
||||
return &LocalVideoElement{ShortVideoElement: message.ShortVideoElement{ // todo 检查缓存是否有效
|
||||
return &message.ShortVideoElement{ // todo 检查缓存是否有效
|
||||
Md5: r.ReadBytes(16),
|
||||
ThumbMd5: r.ReadBytes(16),
|
||||
Size: r.ReadInt32(),
|
||||
ThumbSize: r.ReadInt32(),
|
||||
Name: r.ReadString(),
|
||||
Uuid: r.ReadAvailable(),
|
||||
}}, nil
|
||||
}, nil
|
||||
}
|
||||
return &LocalVideoElement{File: rawPath}, nil
|
||||
}
|
||||
@ -1133,15 +1147,13 @@ func (bot *CQBot) makeImageOrVideoElem(d map[string]string, video, group bool) (
|
||||
exist = true
|
||||
rawPath = path.Join(global.ImagePathOld, f)
|
||||
}
|
||||
if !exist && global.PathExists(rawPath+".cqimg") {
|
||||
exist = true
|
||||
rawPath += ".cqimg"
|
||||
}
|
||||
if !exist && d["url"] != "" {
|
||||
if !exist {
|
||||
if d["url"] != "" {
|
||||
return bot.makeImageOrVideoElem(map[string]string{"file": d["url"]}, false, group)
|
||||
}
|
||||
if exist {
|
||||
if path.Ext(rawPath) != ".image" && path.Ext(rawPath) != ".cqimg" {
|
||||
return nil, errors.New("invalid image")
|
||||
}
|
||||
if path.Ext(rawPath) != ".image" {
|
||||
return &LocalImageElement{File: rawPath}, nil
|
||||
}
|
||||
b, err := os.ReadFile(rawPath)
|
||||
@ -1151,29 +1163,11 @@ func (bot *CQBot) makeImageOrVideoElem(d map[string]string, video, group bool) (
|
||||
if len(b) < 20 {
|
||||
return nil, errors.New("invalid local file")
|
||||
}
|
||||
var (
|
||||
size int32
|
||||
hash []byte
|
||||
imageURL string
|
||||
)
|
||||
if path.Ext(rawPath) == ".cqimg" {
|
||||
for _, line := range strings.Split(global.ReadAllText(rawPath), "\n") {
|
||||
kv := strings.SplitN(line, "=", 2)
|
||||
switch kv[0] {
|
||||
case "md5":
|
||||
hash, _ = hex.DecodeString(strings.ReplaceAll(kv[1], "\r", ""))
|
||||
case "size":
|
||||
t, _ := strconv.Atoi(strings.ReplaceAll(kv[1], "\r", ""))
|
||||
size = int32(t)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
r := binary.NewReader(b)
|
||||
hash = r.ReadBytes(16)
|
||||
size = r.ReadInt32()
|
||||
hash := r.ReadBytes(16)
|
||||
size := r.ReadInt32()
|
||||
r.ReadString()
|
||||
imageURL = r.ReadString()
|
||||
}
|
||||
imageURL := r.ReadString()
|
||||
if size == 0 {
|
||||
if imageURL != "" {
|
||||
return bot.makeImageOrVideoElem(map[string]string{"file": imageURL}, false, group)
|
||||
@ -1189,7 +1183,7 @@ func (bot *CQBot) makeImageOrVideoElem(d map[string]string, video, group bool) (
|
||||
goto ok
|
||||
}
|
||||
rsp, err = bot.Client.QueryFriendImage(int64(rand.Uint32()), hash, size)
|
||||
ok:
|
||||
ok:
|
||||
if err != nil {
|
||||
if imageURL != "" {
|
||||
return bot.makeImageOrVideoElem(map[string]string{"file": imageURL}, false, group)
|
||||
@ -1197,8 +1191,6 @@ func (bot *CQBot) makeImageOrVideoElem(d map[string]string, video, group bool) (
|
||||
return nil, err
|
||||
}
|
||||
return rsp, nil
|
||||
}
|
||||
return nil, errors.New("invalid image")
|
||||
}
|
||||
|
||||
// makeShowPic 一种xml 方式发送的群消息图片
|
||||
|
@ -69,9 +69,6 @@ func (bot *CQBot) privateMessageEvent(c *client.QQClient, m *message.PrivateMess
|
||||
},
|
||||
}
|
||||
bot.dispatchEventMessage(fm)
|
||||
if m.Sender.Uin != c.Uin {
|
||||
c.MarkPrivateMessageReaded(m.Sender.Uin, int64(m.Time))
|
||||
}
|
||||
}
|
||||
|
||||
func (bot *CQBot) groupMessageEvent(c *client.QQClient, m *message.GroupMessage) {
|
||||
@ -109,9 +106,6 @@ func (bot *CQBot) groupMessageEvent(c *client.QQClient, m *message.GroupMessage)
|
||||
}
|
||||
gm["message_id"] = id
|
||||
bot.dispatchEventMessage(gm)
|
||||
if m.Sender.Uin != c.Uin {
|
||||
c.MarkGroupMessageReaded(m.GroupCode, int64(m.Id))
|
||||
}
|
||||
}
|
||||
|
||||
func (bot *CQBot) tempMessageEvent(c *client.QQClient, e *client.TempMessageEvent) {
|
||||
@ -268,7 +262,11 @@ func (bot *CQBot) groupNotifyEvent(c *client.QQClient, e client.INotifyEvent) {
|
||||
func (bot *CQBot) friendNotifyEvent(c *client.QQClient, e client.INotifyEvent) {
|
||||
friend := c.FindFriend(e.From())
|
||||
if notify, ok := e.(*client.FriendPokeNotifyEvent); ok {
|
||||
if notify.Receiver == notify.Sender {
|
||||
log.Infof("好友 %v 戳了戳自己.", friend.Nickname)
|
||||
} else {
|
||||
log.Infof("好友 %v 戳了戳你.", friend.Nickname)
|
||||
}
|
||||
bot.dispatchEventMessage(MSG{
|
||||
"post_type": "notice",
|
||||
"notice_type": "notify",
|
||||
@ -282,6 +280,22 @@ func (bot *CQBot) friendNotifyEvent(c *client.QQClient, e client.INotifyEvent) {
|
||||
}
|
||||
}
|
||||
|
||||
func (bot *CQBot) memberTitleUpdatedEvent(c *client.QQClient, e *client.MemberSpecialTitleUpdatedEvent) {
|
||||
group := c.FindGroup(e.GroupCode)
|
||||
mem := group.FindMember(e.Uin)
|
||||
log.Infof("群 %v(%v) 内成员 %v(%v) 获得了新的头衔: %v", group.Name, group.Code, mem.DisplayName(), mem.Uin, e.NewTitle)
|
||||
bot.dispatchEventMessage(MSG{
|
||||
"post_type": "notice",
|
||||
"notice_type": "notify",
|
||||
"sub_type": "title",
|
||||
"group_id": group.Code,
|
||||
"self_id": c.Uin,
|
||||
"user_id": e.Uin,
|
||||
"time": time.Now().Unix(),
|
||||
"title": e.NewTitle,
|
||||
})
|
||||
}
|
||||
|
||||
func (bot *CQBot) friendRecallEvent(c *client.QQClient, e *client.FriendMessageRecalledEvent) {
|
||||
f := c.FindFriend(e.FriendUin)
|
||||
gid := toGlobalID(e.FriendUin, e.MessageId)
|
||||
|
@ -222,7 +222,7 @@ database: # 数据库相关设置
|
||||
在部署前,请在本地完成登录,并将 `config.yml` , `device.json` ,`bootstrap` 和 `go-cqhttp`
|
||||
一起打包。
|
||||
|
||||
在触发器中创建一个API网关触发器,并启用继承响应, 创建完成后即可通过api网关访问go-cqhttp(建议配置 AccessToken)。
|
||||
在触发器中创建一个API网关触发器,并启用集成响应,创建完成后即可通过api网关访问go-cqhttp(建议配置 AccessToken)。
|
||||
|
||||
> scripts/bootstrap 中使用的工作路径为 /tmp, 这个目录最大能容下500M文件, 如需长期使用,
|
||||
> 请挂载文件存储(CFS).
|
123
docs/cqhttp.md
123
docs/cqhttp.md
@ -7,6 +7,7 @@
|
||||
<p>
|
||||
|
||||
##### CQCode
|
||||
|
||||
- [图片](#图片)
|
||||
- [回复](#回复)
|
||||
- [红包](#红包)
|
||||
@ -21,6 +22,7 @@
|
||||
- [图片](#图片)
|
||||
|
||||
##### API
|
||||
|
||||
- [设置群名](#设置群名)
|
||||
- [设置群头像](#设置群头像)
|
||||
- [获取图片信息](#获取图片信息)
|
||||
@ -47,6 +49,7 @@
|
||||
- [重载事件过滤器](#重载事件过滤器)
|
||||
|
||||
##### 事件
|
||||
|
||||
- [群消息撤回](#群消息撤回)
|
||||
- [好友消息撤回](#好友消息撤回)
|
||||
- [好友戳一戳](#好友戳一戳)
|
||||
@ -112,8 +115,6 @@ Type : `reply`
|
||||
| `time` | int64 | 可选. 自定义回复时的时间, 格式为Unix时间 |
|
||||
| `seq` | int64 | 起始消息序号, 可通过 `get_msg` 获得 |
|
||||
|
||||
|
||||
|
||||
示例: `[CQ:reply,id=123456]`
|
||||
\
|
||||
自定义回复示例: `[CQ:reply,text=Hello World,qq=10086,time=3376656000,seq=5123]`
|
||||
@ -231,11 +232,9 @@ Type: `gift`
|
||||
| 12 | 我超忙的 |
|
||||
| 13 | 爱心口罩 |
|
||||
|
||||
|
||||
|
||||
示例: `[CQ:gift,qq=123456,id=8]`
|
||||
|
||||
### 合并转发
|
||||
### 合并转发
|
||||
|
||||
Type: `forward`
|
||||
|
||||
@ -265,7 +264,8 @@ Type: `node`
|
||||
| `content` | message | 具体消息 | 用于自定义消息 |
|
||||
| `seq` | message | 具体消息 | 用于自定义消息 |
|
||||
|
||||
特殊说明: **需要使用单独的API `/send_group_forward_msg` 发送,并且由于消息段较为复杂,仅支持Array形式入参。 如果引用消息和自定义消息同时出现,实际查看顺序将取消息段顺序. 另外按 [CQHTTP](https://git.io/JtxtN) 文档说明, `data` 应全为字符串, 但由于需要接收`message` 类型的消息, 所以 *仅限此Type的content字段* 支持Array套娃**
|
||||
特殊说明: **需要使用单独的API `/send_group_forward_msg` 发送,并且由于消息段较为复杂,仅支持Array形式入参。 如果引用消息和自定义消息同时出现,实际查看顺序将取消息段顺序.
|
||||
另外按 [CQHTTP](https://git.io/JtxtN) 文档说明, `data` 应全为字符串, 但由于需要接收`message` 类型的消息, 所以 *仅限此Type的content字段* 支持Array套娃**
|
||||
|
||||
示例:
|
||||
|
||||
@ -300,7 +300,9 @@ Type: `node`
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"data": {"text": "测试消息1"}
|
||||
"data": {
|
||||
"text": "测试消息1"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -338,6 +340,7 @@ Type: `node`
|
||||
}
|
||||
]
|
||||
````
|
||||
|
||||
### 短视频消息
|
||||
|
||||
Type: `video`
|
||||
@ -351,6 +354,7 @@ Type: `video`
|
||||
| `file` | string | 支持http和file发送 |
|
||||
| `cover` | string | 视频封面,支持http,file和base64发送,格式必须为jpg |
|
||||
| `c` | `2` `3` | 通过网络下载视频时的线程数, 默认单线程. (在资源不支持并发时会自动处理) |
|
||||
|
||||
示例: `[CQ:video,file=file:///C:\\Users\Richard\Videos\1.mp4]`
|
||||
|
||||
### XML 消息
|
||||
@ -375,30 +379,61 @@ Type: `xml`
|
||||
#### qq音乐
|
||||
|
||||
```xml
|
||||
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?><msg serviceID="2" templateID="1" action="web" brief="[分享] 十年" sourceMsgId="0" url="https://i.y.qq.com/v8/playsong.html?_wv=1&songid=4830342&souce=qqshare&source=qqshare&ADTAG=qqshare" flag="0" adverSign="0" multiMsgFlag="0" ><item layout="2"><audio cover="http://imgcache.qq.com/music/photo/album_500/26/500_albumpic_89526_0.jpg" src="http://ws.stream.qqmusic.qq.com/C400003mAan70zUy5O.m4a?guid=1535153710&vkey=D5315B8C0603653592AD4879A8A3742177F59D582A7A86546E24DD7F282C3ACF81526C76E293E57EA1E42CF19881C561275D919233333ADE&uin=&fromtag=3" /><title>十年</title><summary>陈奕迅</summary></item><source name="QQ音乐" icon="https://i.gtimg.cn/open/app_icon/01/07/98/56/1101079856_100_m.png" url="http://web.p.qq.com/qqmpmobile/aio/app.html?id=1101079856" action="app" a_actionData="com.tencent.qqmusic" i_actionData="tencent1101079856://" appid="1101079856" /></msg>
|
||||
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
|
||||
<msg serviceID="2" templateID="1" action="web" brief="[分享] 十年" sourceMsgId="0"
|
||||
url="https://i.y.qq.com/v8/playsong.html?_wv=1&songid=4830342&souce=qqshare&source=qqshare&ADTAG=qqshare"
|
||||
flag="0" adverSign="0" multiMsgFlag="0">
|
||||
<item layout="2">
|
||||
<audio cover="http://imgcache.qq.com/music/photo/album_500/26/500_albumpic_89526_0.jpg"
|
||||
src="http://ws.stream.qqmusic.qq.com/C400003mAan70zUy5O.m4a?guid=1535153710&vkey=D5315B8C0603653592AD4879A8A3742177F59D582A7A86546E24DD7F282C3ACF81526C76E293E57EA1E42CF19881C561275D919233333ADE&uin=&fromtag=3"/>
|
||||
<title>十年</title>
|
||||
<summary>陈奕迅</summary>
|
||||
</item>
|
||||
<source name="QQ音乐" icon="https://i.gtimg.cn/open/app_icon/01/07/98/56/1101079856_100_m.png"
|
||||
url="http://web.p.qq.com/qqmpmobile/aio/app.html?id=1101079856" action="app"
|
||||
a_actionData="com.tencent.qqmusic" i_actionData="tencent1101079856://" appid="1101079856"/>
|
||||
</msg>
|
||||
```
|
||||
|
||||
#### 网易音乐
|
||||
|
||||
```xml
|
||||
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?><msg serviceID="2" templateID="1" action="web" brief="[分享] 十年" sourceMsgId="0" url="http://music.163.com/m/song/409650368" flag="0" adverSign="0" multiMsgFlag="0" ><item layout="2"><audio cover="http://p2.music.126.net/g-Qgb9ibk9Wp_0HWra0xQQ==/16636710440565853.jpg?param=90y90" src="https://music.163.com/song/media/outer/url?id=409650368.mp3" /><title>十年</title><summary>黄梦之</summary></item><source name="网易云音乐" icon="https://pic.rmb.bdstatic.com/911423bee2bef937975b29b265d737b3.png" url="http://web.p.qq.com/qqmpmobile/aio/app.html?id=1101079856" action="app" a_actionData="com.netease.cloudmusic" i_actionData="tencent100495085://" appid="100495085" /></msg>
|
||||
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
|
||||
<msg serviceID="2" templateID="1" action="web" brief="[分享] 十年" sourceMsgId="0"
|
||||
url="http://music.163.com/m/song/409650368" flag="0" adverSign="0" multiMsgFlag="0">
|
||||
<item layout="2">
|
||||
<audio cover="http://p2.music.126.net/g-Qgb9ibk9Wp_0HWra0xQQ==/16636710440565853.jpg?param=90y90"
|
||||
src="https://music.163.com/song/media/outer/url?id=409650368.mp3"/>
|
||||
<title>十年</title>
|
||||
<summary>黄梦之</summary>
|
||||
</item>
|
||||
<source name="网易云音乐" icon="https://pic.rmb.bdstatic.com/911423bee2bef937975b29b265d737b3.png"
|
||||
url="http://web.p.qq.com/qqmpmobile/aio/app.html?id=1101079856" action="app"
|
||||
a_actionData="com.netease.cloudmusic" i_actionData="tencent100495085://" appid="100495085"/>
|
||||
</msg>
|
||||
```
|
||||
|
||||
#### 卡片消息1
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<msg serviceID="1">
|
||||
<item><title>生死8秒!女司机高速急刹,他一个操作救下一车性命</title></item>
|
||||
<source name="官方认证消息" icon="https://qzs.qq.com/ac/qzone_v5/client/auth_icon.png" action="" appid="-1" />
|
||||
<item>
|
||||
<title>生死8秒!女司机高速急刹,他一个操作救下一车性命</title>
|
||||
</item>
|
||||
<source name="官方认证消息" icon="https://qzs.qq.com/ac/qzone_v5/client/auth_icon.png" action="" appid="-1"/>
|
||||
</msg>
|
||||
```
|
||||
|
||||
#### 卡片消息2
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<msg serviceID="1">
|
||||
<item layout="4">
|
||||
<title>test title</title>
|
||||
<picture cover="http://url.cn/5CEwIUy"/>
|
||||
</item>
|
||||
<item layout="4">
|
||||
<title>test title</title>
|
||||
<picture cover="http://url.cn/5CEwIUy"/>
|
||||
</item>
|
||||
</msg>
|
||||
```
|
||||
|
||||
@ -417,23 +452,24 @@ Type: `json`
|
||||
|
||||
json中的字符串需要进行转义:
|
||||
|
||||
>","=> `,`
|
||||
> ","=> `,`
|
||||
|
||||
>"&"=> `&`
|
||||
> "&"=> `&`
|
||||
|
||||
>"["=> `[`
|
||||
> "["=> `[`
|
||||
|
||||
>"]"=> `]`
|
||||
> "]"=> `]`
|
||||
|
||||
否则无法正确得到解析
|
||||
|
||||
示例json 的cq码:
|
||||
|
||||
```test
|
||||
[CQ:json,data={"app":"com.tencent.miniapp","desc":"","view":"notification","ver":"0.0.0.1","prompt":"[应用]","appID":"","sourceName":"","actionData":"","actionData_A":"","sourceUrl":"","meta":{"notification":{"appInfo":{"appName":"全国疫情数据统计","appType":4,"appid":1109659848,"iconUrl":"http:\/\/gchat.qpic.cn\/gchatpic_new\/719328335\/-2010394141-6383A777BEB79B70B31CE250142D740F\/0"},"data":[{"title":"确诊","value":"80932"},{"title":"今日确诊","value":"28"},{"title":"疑似","value":"72"},{"title":"今日疑似","value":"5"},{"title":"治愈","value":"60197"},{"title":"今日治愈","value":"1513"},{"title":"死亡","value":"3140"},{"title":"今**亡","value":"17"}],"title":"中国加油,武汉加油","button":[{"name":"病毒:SARS-CoV-2,其导致疾病命名 COVID-19","action":""},{"name":"传染源:新冠肺炎的患者。无症状感染者也可能成为传染源。","action":""}],"emphasis_keyword":""}},"text":"","sourceAd":""}]
|
||||
```
|
||||
|
||||
|
||||
### cardimage
|
||||
|
||||
一种xml的图片消息(装逼大图)
|
||||
|
||||
ps: xml 接口的消息都存在风控风险,请自行兼容发送失败后的处理(可以失败后走普通图片模式)
|
||||
@ -454,8 +490,8 @@ Type: `cardimage`
|
||||
| `source` | string | 分享来源的名称,可以留空 |
|
||||
| `icon` | string | 分享来源的icon图标url,可以留空 |
|
||||
|
||||
|
||||
示例cardimage 的cq码:
|
||||
|
||||
```test
|
||||
[CQ:cardimage,file=https://i.pixiv.cat/img-master/img/2020/03/25/00/00/08/80334602_p0_master1200.jpg]
|
||||
```
|
||||
@ -505,7 +541,8 @@ Type: `tts`
|
||||
|
||||
- 绝对路径,例如 `file:///C:\\Users\Richard\Pictures\1.png`,格式使用 [`file` URI](https://tools.ietf.org/html/rfc8089)
|
||||
- 网络 URL,例如 `http://i1.piimg.com/567571/fdd6e7b6d93f1ef0.jpg`
|
||||
- Base64 编码,例如 `base64://iVBORw0KGgoAAAANSUhEUgAAABQAAAAVCAIAAADJt1n/AAAAKElEQVQ4EWPk5+RmIBcwkasRpG9UM4mhNxpgowFGMARGEwnBIEJVAAAdBgBNAZf+QAAAAABJRU5ErkJggg==`
|
||||
- Base64
|
||||
编码,例如 `base64://iVBORw0KGgoAAAANSUhEUgAAABQAAAAVCAIAAADJt1n/AAAAKElEQVQ4EWPk5+RmIBcwkasRpG9UM4mhNxpgowFGMARGEwnBIEJVAAAdBgBNAZf+QAAAAABJRU5ErkJggg==`
|
||||
|
||||
[2]`cache`参数: 通过网络 URL 发送时有效,`1`表示使用缓存,`0`关闭关闭缓存,默认 为`1`
|
||||
|
||||
@ -587,7 +624,8 @@ Type: `tts`
|
||||
"nickname": "发送者B",
|
||||
"user_id": 10087
|
||||
},
|
||||
"time": 1595694393 // 可选
|
||||
"time": 1595694393
|
||||
// 可选
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -708,7 +746,6 @@ Type: `tts`
|
||||
| `confidence` | int32 | 置信度 |
|
||||
| `coordinates` | vector2 | 坐标 |
|
||||
|
||||
|
||||
### 获取群系统消息
|
||||
|
||||
终结点: `/get_group_system_msg`
|
||||
@ -720,9 +757,9 @@ Type: `tts`
|
||||
| `invited_requests` | InvitedRequest[] | 邀请消息列表 |
|
||||
| `join_requests` | JoinRequest[] | 进群消息列表 |
|
||||
|
||||
> 注意: 如果列表不存在任何消息, 将返回 `null`
|
||||
> 注意: 如果列表不存在任何消息, 将返回 `null`
|
||||
|
||||
**InvitedRequest**
|
||||
**InvitedRequest**
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| -------------- | ------ | ----------------- |
|
||||
@ -734,7 +771,7 @@ Type: `tts`
|
||||
| `checked` | bool | 是否已被处理 |
|
||||
| `actor` | int64 | 处理者, 未处理为0 |
|
||||
|
||||
**JoinRequest**
|
||||
**JoinRequest**
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| ---------------- | ------ | ----------------- |
|
||||
@ -825,7 +862,7 @@ Type: `tts`
|
||||
| ----- | ------ | ------------ |
|
||||
| `url` | string | 文件下载链接 |
|
||||
|
||||
**File**
|
||||
**File**
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| ---------------- | ------ | ---------------------- |
|
||||
@ -840,7 +877,7 @@ Type: `tts`
|
||||
| `uploader` | int64 | 上传者ID |
|
||||
| `uploader_name` | string | 上传者名字 |
|
||||
|
||||
**Folder**
|
||||
**Folder**
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| ------------------ | ------ | ---------- |
|
||||
@ -885,7 +922,6 @@ Type: `tts`
|
||||
|
||||
**Statistics**
|
||||
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| ------------------ | ------ | ---------------- |
|
||||
| `packet_received` | uint64 | 收到的数据包总数 |
|
||||
@ -1076,13 +1112,22 @@ JSON数组:
|
||||
| `ext_name` | string | 用户昵称 |
|
||||
| `create_time` | int64 | 账号创建时间 |
|
||||
|
||||
### 标记消息已读
|
||||
|
||||
终结点: `/mark_msg_as_read`
|
||||
|
||||
**参数**
|
||||
|
||||
| 字段名 | 数据类型 | 默认值 | 说明 |
|
||||
| ---------- | -------- | ------ | -------- |
|
||||
| `message_id` | int32 | | 消息ID |
|
||||
|
||||
### 重载事件过滤器
|
||||
|
||||
终结点:`/reload_event_filter`
|
||||
|
||||
`该 API 无需参数也没有响应数据`
|
||||
|
||||
|
||||
## 事件
|
||||
|
||||
### 群消息撤回
|
||||
@ -1181,11 +1226,23 @@ JSON数组:
|
||||
| `notice_type` | string | `group_card` | 消息类型 |
|
||||
| `group_id` | int64 | | 群号 |
|
||||
| `user_id` | int64 | | 成员id |
|
||||
| `card_new` | int64 | | 新名片 |
|
||||
| `card_old` | int64 | | 旧名片 |
|
||||
| `card_new` | string | | 新名片 |
|
||||
| `card_old` | string | | 旧名片 |
|
||||
|
||||
> PS: 当名片为空时 `card_xx` 字段为空字符串, 并不是昵称
|
||||
|
||||
### 群成员头衔更新事件
|
||||
|
||||
**上报数据**
|
||||
|
||||
| 字段 | 类型 | 可能的值 | 说明 |
|
||||
| ------------- | ------ | ------------ | -------- |
|
||||
| `post_type` | string | `notice` | 上报类型 |
|
||||
| `notice_type` | string | `notify` | 消息类型 |
|
||||
| `group_id` | int64 | | 群号 |
|
||||
| `user_id` | int64 | | 成员id |
|
||||
| `title` | string | | 新头衔 |
|
||||
|
||||
### 接收到离线文件
|
||||
|
||||
**上报数据**
|
||||
|
26
docs/file.md
26
docs/file.md
@ -2,37 +2,39 @@
|
||||
|
||||
go-cqhttp 默认生成的文件树如下所示:
|
||||
|
||||
````
|
||||
```
|
||||
.
|
||||
├── go-cqhttp
|
||||
├── config.hjson
|
||||
├── config.yml
|
||||
├── device.json
|
||||
├── logs
|
||||
│ └── xx-xx-xx.log
|
||||
└── data
|
||||
├── images
|
||||
│ └── xxxx.image
|
||||
└── db
|
||||
````
|
||||
└── levleldb
|
||||
```
|
||||
|
||||
| 文件 | 用途 |
|
||||
| ----------- | ------------------- |
|
||||
| go-cqhttp | go-cqhttp可执行文件 |
|
||||
| config.hjson | 运行配置文件 |
|
||||
| ------------ | -------------------- |
|
||||
| go-cqhttp | go-cqhttp 可执行文件 |
|
||||
| config.yml | 运行配置文件 |
|
||||
| device.json | 虚拟设备配置文件 |
|
||||
| logs | 日志存放目录 |
|
||||
| data | 数据目录 |
|
||||
| data/leveldb | 数据库目录 |
|
||||
| data/images | 图片缓存目录 |
|
||||
| data/db | 数据库目录 |
|
||||
| data/voices | 语音缓存目录 |
|
||||
| data/videos | 视频缓存目录 |
|
||||
| data/cache | 发送图片缓存目录 |
|
||||
|
||||
## 图片缓存文件
|
||||
|
||||
出于性能考虑,go-cqhttp 并不会将图片源文件下载到本地,而是生成一个可以和QQ服务器对应的缓存文件 (.image),该缓存文件结构如下:
|
||||
出于性能考虑,go-cqhttp 并不会将图片源文件下载到本地,而是生成一个可以和 QQ 服务器对应的缓存文件 (.image),该缓存文件结构如下:
|
||||
|
||||
| 偏移 | 类型 | 说明 |
|
||||
| --------------- | -------- | ------------------ |
|
||||
| 0x00 | [16]byte | 图片源文件MD5 HASH |
|
||||
| --------------- | -------- | -------------------- |
|
||||
| 0x00 | [16]byte | 图片源文件 MD5 HASH |
|
||||
| 0x10 | uint32 | 图片源文件大小 |
|
||||
| 0x14 | string | 图片原名(QQ内部ID) |
|
||||
| 0x14 + 原名长度 | string | 图片下载链接 |
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
# 滑块验证码
|
||||
|
||||
> 该文档已过期, 最新版本下可直接使用手机扫描二维码通过验证.
|
||||
|
||||
由于TX最新的限制, 所有协议在陌生设备/IP登录时都有可能被要求通过滑块验证码, 否则将会出现 `当前上网环境异常` 的错误. 目前我们准备了两个临时方案应对该验证码.
|
||||
|
||||
> 如果您有一台运行Windows的PC/Server 并且不会抓包操作, 我们建议直接使用方案B
|
||||
|
@ -29,6 +29,10 @@ func EncodeToSilk(record []byte, tempName string, useCache bool) (silkWav []byte
|
||||
// 2.转换pcm
|
||||
pcmPath := path.Join(silkCachePath, tempName+".pcm")
|
||||
cmd := exec.Command("ffmpeg", "-i", rawPath, "-f", "s16le", "-ar", "24000", "-ac", "1", pcmPath)
|
||||
if Debug {
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
}
|
||||
if err = cmd.Run(); err != nil {
|
||||
return nil, errors.Wrap(err, "convert pcm file error")
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
//go:build (!arm && !arm64 && !amd64 && !386) || race
|
||||
// +build !arm,!arm64,!amd64,!386 race
|
||||
//go:build (!arm && !arm64 && !amd64 && !386) || race || (!windows && !linux && !darwin) || (windows && arm)
|
||||
// +build !arm,!arm64,!amd64,!386 race !windows,!linux,!darwin windows,arm
|
||||
|
||||
package codec
|
||||
|
@ -1,16 +0,0 @@
|
||||
//go:build !windows && !linux && !darwin
|
||||
// +build !windows,!linux,!darwin
|
||||
|
||||
package codec
|
||||
|
||||
import "errors"
|
||||
|
||||
// EncodeToSilk 将音频编码为Silk
|
||||
func EncodeToSilk(record []byte, tempName string, useCache bool) ([]byte, error) {
|
||||
return nil, errors.New("not supported now")
|
||||
}
|
||||
|
||||
// RecodeTo24K 将silk重新编码为 24000 bit rate
|
||||
func RecodeTo24K(data []byte) []byte {
|
||||
return data
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
package codec
|
||||
|
||||
import "errors"
|
||||
|
||||
// EncodeToSilk 将音频编码为Silk
|
||||
func EncodeToSilk(record []byte, tempName string, useCache bool) ([]byte, error) {
|
||||
return nil, errors.New("not supported now")
|
||||
}
|
||||
|
||||
// RecodeTo24K 将silk重新编码为 24000 bit rate
|
||||
func RecodeTo24K(data []byte) []byte {
|
||||
return data
|
||||
}
|
4
global/codec/stubs.go
Normal file
4
global/codec/stubs.go
Normal file
@ -0,0 +1,4 @@
|
||||
package codec
|
||||
|
||||
// Debug mode controls the ffmpeg output.
|
||||
var Debug bool
|
@ -174,6 +174,12 @@ func Get() *Config {
|
||||
global.SetAtDefault(&config.Account.ReLogin.Disabled, !global.EnsureBool(os.Getenv("GCQ_RELOGIN"), false), false)
|
||||
global.SetAtDefault(&config.Account.ReLogin.Delay, uint(toInt64(os.Getenv("GCQ_RELOGIN_DELAY"))), uint(0))
|
||||
global.SetAtDefault(&config.Account.ReLogin.MaxTimes, uint(toInt64(os.Getenv("GCQ_RELOGIN_MAX_TIMES"))), uint(0))
|
||||
dbConf := &LevelDBConfig{Enable: global.EnsureBool(os.Getenv("GCQ_LEVELDB"), true)}
|
||||
config.Database["leveldb"] = func() yaml.Node {
|
||||
n := &yaml.Node{}
|
||||
_ = n.Encode(dbConf)
|
||||
return *n
|
||||
}()
|
||||
accessTokenEnv := os.Getenv("GCQ_ACCESS_TOKEN")
|
||||
if os.Getenv("GCQ_HTTP_PORT") != "" {
|
||||
node := &yaml.Node{}
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
@ -174,3 +175,21 @@ func GetLogLevel(level string) []logrus.Level {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// LogFormat specialize for go-cqhttp
|
||||
type LogFormat struct{}
|
||||
|
||||
// Format implements logrus.Formatter
|
||||
func (f LogFormat) Format(entry *logrus.Entry) ([]byte, error) {
|
||||
buf := NewBuffer()
|
||||
defer PutBuffer(buf)
|
||||
buf.WriteByte('[')
|
||||
buf.WriteString(entry.Time.Format("2006-01-02 15:04:05"))
|
||||
buf.WriteString("] [")
|
||||
buf.WriteString(strings.ToUpper(entry.Level.String()))
|
||||
buf.WriteString("]: ")
|
||||
buf.WriteString(entry.Message)
|
||||
buf.WriteString(" \n")
|
||||
ret := append([]byte(nil), buf.Bytes()...) // copy buffer
|
||||
return ret, nil
|
||||
}
|
||||
|
@ -96,13 +96,14 @@ func SetAtDefault(variable, value, defaultValue interface{}) {
|
||||
if v.Kind() != reflect.Ptr || v.IsNil() {
|
||||
return
|
||||
}
|
||||
if v.Elem().Interface() != defaultValue {
|
||||
v = v.Elem()
|
||||
if v.Interface() != defaultValue {
|
||||
return
|
||||
}
|
||||
if v.Elem().Kind() != v2.Kind() {
|
||||
if v.Kind() != v2.Kind() {
|
||||
return
|
||||
}
|
||||
v.Elem().Set(v2)
|
||||
v.Set(v2)
|
||||
}
|
||||
|
||||
// SetExcludeDefault 在目标值 value 不为默认值 defaultValue 时修改 variable 为 value
|
||||
@ -112,13 +113,14 @@ func SetExcludeDefault(variable, value, defaultValue interface{}) {
|
||||
if v.Kind() != reflect.Ptr || v.IsNil() {
|
||||
return
|
||||
}
|
||||
if v2.Elem().Interface() != defaultValue {
|
||||
v = v.Elem()
|
||||
if reflect.Indirect(v2).Interface() != defaultValue {
|
||||
return
|
||||
}
|
||||
if v.Elem().Kind() != v2.Kind() {
|
||||
if v.Kind() != v2.Kind() {
|
||||
return
|
||||
}
|
||||
v.Elem().Set(v2)
|
||||
v.Set(v2)
|
||||
}
|
||||
|
||||
var (
|
||||
|
5
go.mod
5
go.mod
@ -5,9 +5,9 @@ go 1.16
|
||||
require (
|
||||
github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f
|
||||
github.com/Microsoft/go-winio v0.5.0
|
||||
github.com/Mrs4s/MiraiGo v0.0.0-20210726103104-1d68826cef0e
|
||||
github.com/Mrs4s/MiraiGo v0.0.0-20210810070836-6614d2383adb
|
||||
github.com/dustin/go-humanize v1.0.0
|
||||
github.com/gabriel-vasile/mimetype v1.3.1 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.3.1
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/guonaihong/gout v0.2.1
|
||||
github.com/jonboulle/clockwork v0.2.2 // indirect
|
||||
@ -21,7 +21,6 @@ require (
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/syndtr/goleveldb v1.0.0
|
||||
github.com/t-tomalak/logrus-easy-formatter v0.0.0-20190827215021-c074f06c5816
|
||||
github.com/tidwall/gjson v1.8.1
|
||||
github.com/tuotoo/qrcode v0.0.0-20190222102259-ac9c44189bf2
|
||||
github.com/wdvxdr1123/go-silk v0.0.0-20210316130616-d47b553def60
|
||||
|
13
go.sum
13
go.sum
@ -4,8 +4,8 @@ github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f/g
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Microsoft/go-winio v0.5.0 h1:Elr9Wn+sGKPlkaBvwu4mTrxtmOp3F3yV9qhaHbXGjwU=
|
||||
github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
||||
github.com/Mrs4s/MiraiGo v0.0.0-20210726103104-1d68826cef0e h1:PgFshw1L5TVdiDRLgr/bSotPGaGXYzbtn5cDBBvpL6U=
|
||||
github.com/Mrs4s/MiraiGo v0.0.0-20210726103104-1d68826cef0e/go.mod h1:CPaznIPn415uQqxJgjyMHLqGLkvLS6R6+bkW3/fe08Q=
|
||||
github.com/Mrs4s/MiraiGo v0.0.0-20210810070836-6614d2383adb h1:agCxYd/ZemDwrEYKpnpKqA0cubxfpkQ/b+GpIlIJK0U=
|
||||
github.com/Mrs4s/MiraiGo v0.0.0-20210810070836-6614d2383adb/go.mod h1:5V3f/+mTYtrI/+hLqbdzZQXuLMl2RyLfx0XYYjCQ90Q=
|
||||
github.com/bits-and-blooms/bitset v1.2.0 h1:Kn4yilvwNtMACtf1eYDlG8H77R07mZSPbMjLyS07ChA=
|
||||
github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
@ -71,7 +71,6 @@ github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMW
|
||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA=
|
||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8=
|
||||
@ -104,14 +103,12 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
@ -119,8 +116,6 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
||||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
||||
github.com/t-tomalak/logrus-easy-formatter v0.0.0-20190827215021-c074f06c5816 h1:J6v8awz+me+xeb/cUTotKgceAYouhIB3pjzgRd6IlGk=
|
||||
github.com/t-tomalak/logrus-easy-formatter v0.0.0-20190827215021-c074f06c5816/go.mod h1:tzym/CEb5jnFI+Q0k4Qq3+LvRF4gO3E2pxS8fHP8jcA=
|
||||
github.com/tidwall/gjson v1.8.1 h1:8j5EE9Hrh3l9Od1OIEDAb7IpezNA20UdRngNAj5N0WU=
|
||||
github.com/tidwall/gjson v1.8.1/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk=
|
||||
github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE=
|
||||
@ -150,7 +145,6 @@ golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73r
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125 h1:Ugb8sMTWuWRC3+sz5WeN/4kejDx9BvIwnPUiJBjJE+8=
|
||||
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
@ -158,10 +152,11 @@ golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAG
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
16
login.go
16
login.go
@ -117,21 +117,7 @@ func loginResponseProcessor(res *client.LoginResponse) error {
|
||||
var text string
|
||||
switch res.Error {
|
||||
case client.SliderNeededError:
|
||||
log.Warnf("登录需要滑条验证码. ")
|
||||
log.Warnf("请参考文档 -> https://docs.go-cqhttp.org/faq/slider.html <- 进行处理")
|
||||
log.Warnf("1. 自行抓包并获取 Ticket 输入.")
|
||||
log.Warnf("2. 使用手机QQ扫描二维码登入. (推荐)")
|
||||
log.Warn("请输入(1 - 2) (将在10秒后自动选择2):")
|
||||
text = readLineTimeout(time.Second*10, "2")
|
||||
if strings.Contains(text, "1") {
|
||||
println()
|
||||
log.Warnf("请用浏览器打开 -> %v <- 并获取Ticket.", res.VerifyUrl)
|
||||
println()
|
||||
log.Warn("请输入Ticket: (Enter 提交)")
|
||||
text = readLine()
|
||||
res, err = cli.SubmitTicket(text)
|
||||
continue
|
||||
}
|
||||
log.Warnf("登录需要滑条验证码, 请使用手机QQ扫描二维码以继续登录.")
|
||||
cli.Disconnect()
|
||||
cli.Release()
|
||||
cli = client.NewClientEmpty()
|
||||
|
10
main.go
10
main.go
@ -19,6 +19,7 @@ import (
|
||||
|
||||
"github.com/Mrs4s/go-cqhttp/coolq"
|
||||
"github.com/Mrs4s/go-cqhttp/global"
|
||||
"github.com/Mrs4s/go-cqhttp/global/codec"
|
||||
"github.com/Mrs4s/go-cqhttp/global/config"
|
||||
"github.com/Mrs4s/go-cqhttp/global/terminal"
|
||||
"github.com/Mrs4s/go-cqhttp/global/update"
|
||||
@ -29,7 +30,6 @@ import (
|
||||
"github.com/guonaihong/gout"
|
||||
rotatelogs "github.com/lestrrat-go/file-rotatelogs"
|
||||
log "github.com/sirupsen/logrus"
|
||||
easy "github.com/t-tomalak/logrus-easy-formatter"
|
||||
"github.com/tidwall/gjson"
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
"golang.org/x/term"
|
||||
@ -79,12 +79,9 @@ func main() {
|
||||
}
|
||||
if conf.Output.Debug {
|
||||
log.SetReportCaller(true)
|
||||
codec.Debug = true
|
||||
}
|
||||
|
||||
logFormatter := &easy.Formatter{
|
||||
TimestampFormat: "2006-01-02 15:04:05",
|
||||
LogFormat: "[%time%] [%lvl%]: %msg% \n",
|
||||
}
|
||||
rotateOptions := []rotatelogs.Option{
|
||||
rotatelogs.WithRotationTime(time.Hour * 24),
|
||||
}
|
||||
@ -102,7 +99,7 @@ func main() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
log.AddHook(global.NewLocalHook(w, logFormatter, global.GetLogLevel(conf.Output.LogLevel)...))
|
||||
log.AddHook(global.NewLocalHook(w, global.LogFormat{}, global.GetLogLevel(conf.Output.LogLevel)...))
|
||||
|
||||
mkCacheDir := func(path string, _type string) {
|
||||
if !global.PathExists(path) {
|
||||
@ -263,6 +260,7 @@ func main() {
|
||||
text := readLineTimeout(time.Second*5, "1")
|
||||
if text == "2" {
|
||||
_ = os.Remove("session.token")
|
||||
log.Infof("缓存已删除.")
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
|
@ -350,6 +350,10 @@ func setModelShow(bot *coolq.CQBot, p resultGetter) coolq.MSG {
|
||||
return bot.CQSetModelShow(p.Get("model").String(), p.Get("model_show").String())
|
||||
}
|
||||
|
||||
func markMSGAsRead(bot *coolq.CQBot, p resultGetter) coolq.MSG {
|
||||
return bot.CQMarkMessageAsRead(int32(p.Get("message_id").Int()))
|
||||
}
|
||||
|
||||
// API 是go-cqhttp当前支持的所有api的映射表
|
||||
var API = map[string]func(*coolq.CQBot, resultGetter) coolq.MSG{
|
||||
"get_login_info": getLoginInfo,
|
||||
@ -413,6 +417,7 @@ var API = map[string]func(*coolq.CQBot, resultGetter) coolq.MSG{
|
||||
"qidian_get_account_info": getQiDianAccountInfo,
|
||||
"_get_model_show": getModelShow,
|
||||
"_set_model_show": setModelShow,
|
||||
"mark_msg_as_read": markMSGAsRead,
|
||||
}
|
||||
|
||||
func (api *apiCaller) callAPI(action string, p resultGetter) coolq.MSG {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
@ -34,20 +35,22 @@ type lambdaResponse struct {
|
||||
|
||||
type lambdaResponseWriter struct {
|
||||
statusCode int
|
||||
buf bytes.Buffer
|
||||
header http.Header
|
||||
}
|
||||
|
||||
func (l *lambdaResponseWriter) Write(p []byte) (n int, err error) {
|
||||
return l.buf.Write(p)
|
||||
}
|
||||
|
||||
func (l *lambdaResponseWriter) Header() http.Header {
|
||||
return l.header
|
||||
}
|
||||
|
||||
func (l *lambdaResponseWriter) Write(data []byte) (int, error) {
|
||||
func (l *lambdaResponseWriter) flush() error {
|
||||
buffer := global.NewBuffer()
|
||||
defer global.PutBuffer(buffer)
|
||||
body := ""
|
||||
if data != nil {
|
||||
body = utils.B2S(data)
|
||||
}
|
||||
body := utils.B2S(l.buf.Bytes())
|
||||
header := make(map[string]string)
|
||||
for k, v := range l.header {
|
||||
header[k] = v[0]
|
||||
@ -62,10 +65,9 @@ func (l *lambdaResponseWriter) Write(data []byte) (int, error) {
|
||||
r, _ := http.NewRequest("POST", cli.responseURL, buffer)
|
||||
do, err := cli.client.Do(r)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
return err
|
||||
}
|
||||
_ = do.Body.Close()
|
||||
return len(data), nil
|
||||
return do.Body.Close()
|
||||
}
|
||||
|
||||
func (l *lambdaResponseWriter) WriteHeader(statusCode int) {
|
||||
@ -125,7 +127,11 @@ func RunLambdaClient(bot *coolq.CQBot, conf *config.LambdaServer) {
|
||||
log.Warnf("Lambda 出现不可恢复错误: %v\n%s", e, debug.Stack())
|
||||
}
|
||||
}()
|
||||
server.ServeHTTP(&lambdaResponseWriter{header: make(http.Header)}, req)
|
||||
writer := lambdaResponseWriter{header: make(http.Header)}
|
||||
server.ServeHTTP(&writer, req)
|
||||
if err := writer.flush(); err != nil {
|
||||
log.Warnf("Lambda 发送响应失败: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
@ -160,7 +160,12 @@ func (c *websocketClient) connectEvent() {
|
||||
}
|
||||
|
||||
log.Infof("已连接到反向WebSocket Event服务器 %v", c.conf.Event)
|
||||
c.eventConn = &webSocketConn{Conn: conn, apiCaller: newAPICaller(c.bot)}
|
||||
if c.eventConn == nil {
|
||||
wrappedConn := &webSocketConn{Conn: conn, apiCaller: newAPICaller(c.bot)}
|
||||
c.eventConn = wrappedConn
|
||||
} else {
|
||||
c.eventConn.Conn = conn
|
||||
}
|
||||
}
|
||||
|
||||
func (c *websocketClient) connectUniversal() {
|
||||
@ -189,12 +194,16 @@ func (c *websocketClient) connectUniversal() {
|
||||
log.Warnf("反向WebSocket 握手时出现错误: %v", err)
|
||||
}
|
||||
|
||||
if c.universalConn == nil {
|
||||
wrappedConn := &webSocketConn{Conn: conn, apiCaller: newAPICaller(c.bot)}
|
||||
if c.conf.RateLimit.Enabled {
|
||||
wrappedConn.apiCaller.use(rateLimit(c.conf.RateLimit.Frequency, c.conf.RateLimit.Bucket))
|
||||
}
|
||||
go c.listenAPI(wrappedConn, true)
|
||||
c.universalConn = wrappedConn
|
||||
} else {
|
||||
c.universalConn.Conn = conn
|
||||
}
|
||||
go c.listenAPI(c.universalConn, true)
|
||||
}
|
||||
|
||||
func (c *websocketClient) listenAPI(conn *webSocketConn, u bool) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user