1
0
mirror of https://github.com/Mrs4s/go-cqhttp.git synced 2025-05-06 03:53:50 +08:00

fix golint

This commit is contained in:
Ink-33 2021-01-25 01:04:39 +08:00
parent a74c623cc1
commit 6f5e582213
No known key found for this signature in database
GPG Key ID: 5D8B1D036EFB0D2E
10 changed files with 284 additions and 201 deletions

View File

@ -28,6 +28,7 @@ import (
var json = jsoniter.ConfigCompatibleWithStandardLibrary var json = jsoniter.ConfigCompatibleWithStandardLibrary
//CQBot CQBot结构体,存储Bot实例相关配置
type CQBot struct { type CQBot struct {
Client *client.QQClient Client *client.QQClient
@ -38,10 +39,13 @@ type CQBot struct {
oneWayMsgCache sync.Map oneWayMsgCache sync.Map
} }
//MSG 消息Map
type MSG map[string]interface{} type MSG map[string]interface{}
//ForceFragmented 是否启用强制分片
var ForceFragmented = false var ForceFragmented = false
//NewQQBot 初始化一个QQBot实例
func NewQQBot(cli *client.QQClient, conf *global.JSONConfig) *CQBot { func NewQQBot(cli *client.QQClient, conf *global.JSONConfig) *CQBot {
bot := &CQBot{ bot := &CQBot{
Client: cli, Client: cli,
@ -102,10 +106,12 @@ func NewQQBot(cli *client.QQClient, conf *global.JSONConfig) *CQBot {
return bot return bot
} }
//OnEventPush 注册事件上报函数
func (bot *CQBot) OnEventPush(f func(m MSG)) { func (bot *CQBot) OnEventPush(f func(m MSG)) {
bot.events = append(bot.events, f) bot.events = append(bot.events, f)
} }
//GetMessage 获取给定消息id对应的消息
func (bot *CQBot) GetMessage(mid int32) MSG { func (bot *CQBot) GetMessage(mid int32) MSG {
if bot.db != nil { if bot.db != nil {
m := MSG{} m := MSG{}
@ -123,6 +129,7 @@ func (bot *CQBot) GetMessage(mid int32) MSG {
return nil return nil
} }
//UploadLocalImageAsGroup 上传本地图片至群聊
func (bot *CQBot) UploadLocalImageAsGroup(groupCode int64, img *LocalImageElement) (*message.GroupImageElement, error) { func (bot *CQBot) UploadLocalImageAsGroup(groupCode int64, img *LocalImageElement) (*message.GroupImageElement, error) {
if img.Stream != nil { if img.Stream != nil {
return bot.Client.UploadGroupImage(groupCode, img.Stream) return bot.Client.UploadGroupImage(groupCode, img.Stream)
@ -130,6 +137,7 @@ func (bot *CQBot) UploadLocalImageAsGroup(groupCode int64, img *LocalImageElemen
return bot.Client.UploadGroupImageByFile(groupCode, img.File) return bot.Client.UploadGroupImageByFile(groupCode, img.File)
} }
//UploadLocalVideo 上传本地短视频至群聊
func (bot *CQBot) UploadLocalVideo(target int64, v *LocalVideoElement) (*message.ShortVideoElement, error) { func (bot *CQBot) UploadLocalVideo(target int64, v *LocalVideoElement) (*message.ShortVideoElement, error) {
if v.File != "" { if v.File != "" {
video, err := os.Open(v.File) video, err := os.Open(v.File)
@ -146,9 +154,10 @@ func (bot *CQBot) UploadLocalVideo(target int64, v *LocalVideoElement) (*message
return &v.ShortVideoElement, nil return &v.ShortVideoElement, nil
} }
func (bot *CQBot) UploadLocalImageAsPrivate(userId int64, img *LocalImageElement) (*message.FriendImageElement, error) { //UploadLocalImageAsPrivate 上传本地图片至私聊
func (bot *CQBot) UploadLocalImageAsPrivate(userID int64, img *LocalImageElement) (*message.FriendImageElement, error) {
if img.Stream != nil { if img.Stream != nil {
return bot.Client.UploadPrivateImage(userId, img.Stream) return bot.Client.UploadPrivateImage(userID, img.Stream)
} }
// need update. // need update.
f, err := os.Open(img.File) f, err := os.Open(img.File)
@ -156,41 +165,42 @@ func (bot *CQBot) UploadLocalImageAsPrivate(userId int64, img *LocalImageElement
return nil, err return nil, err
} }
defer f.Close() defer f.Close()
return bot.Client.UploadPrivateImage(userId, f) return bot.Client.UploadPrivateImage(userID, f)
} }
func (bot *CQBot) SendGroupMessage(groupId int64, m *message.SendingMessage) int32 { //SendGroupMessage 发送群消息
func (bot *CQBot) SendGroupMessage(groupID int64, m *message.SendingMessage) int32 {
var newElem []message.IMessageElement var newElem []message.IMessageElement
for _, elem := range m.Elements { for _, elem := range m.Elements {
if i, ok := elem.(*LocalImageElement); ok { if i, ok := elem.(*LocalImageElement); ok {
gm, err := bot.UploadLocalImageAsGroup(groupId, i) gm, err := bot.UploadLocalImageAsGroup(groupID, i)
if err != nil { if err != nil {
log.Warnf("警告: 群 %v 消息图片上传失败: %v", groupId, err) log.Warnf("警告: 群 %v 消息图片上传失败: %v", groupID, err)
continue continue
} }
newElem = append(newElem, gm) newElem = append(newElem, gm)
continue continue
} }
if i, ok := elem.(*message.VoiceElement); ok { if i, ok := elem.(*message.VoiceElement); ok {
gv, err := bot.Client.UploadGroupPtt(groupId, bytes.NewReader(i.Data)) gv, err := bot.Client.UploadGroupPtt(groupID, bytes.NewReader(i.Data))
if err != nil { if err != nil {
log.Warnf("警告: 群 %v 消息语音上传失败: %v", groupId, err) log.Warnf("警告: 群 %v 消息语音上传失败: %v", groupID, err)
continue continue
} }
newElem = append(newElem, gv) newElem = append(newElem, gv)
continue continue
} }
if i, ok := elem.(*LocalVideoElement); ok { if i, ok := elem.(*LocalVideoElement); ok {
gv, err := bot.UploadLocalVideo(groupId, i) gv, err := bot.UploadLocalVideo(groupID, i)
if err != nil { if err != nil {
log.Warnf("警告: 群 %v 消息短视频上传失败: %v", groupId, err) log.Warnf("警告: 群 %v 消息短视频上传失败: %v", groupID, err)
continue continue
} }
newElem = append(newElem, gv) newElem = append(newElem, gv)
continue continue
} }
if i, ok := elem.(*PokeElement); ok { if i, ok := elem.(*PokeElement); ok {
if group := bot.Client.FindGroup(groupId); group != nil { if group := bot.Client.FindGroup(groupID); group != nil {
if mem := group.FindMember(i.Target); mem != nil { if mem := group.FindMember(i.Target); mem != nil {
mem.Poke() mem.Poke()
return 0 return 0
@ -198,15 +208,15 @@ func (bot *CQBot) SendGroupMessage(groupId int64, m *message.SendingMessage) int
} }
} }
if i, ok := elem.(*GiftElement); ok { if i, ok := elem.(*GiftElement); ok {
bot.Client.SendGroupGift(uint64(groupId), uint64(i.Target), i.GiftId) bot.Client.SendGroupGift(uint64(groupID), uint64(i.Target), i.GiftID)
return 0 return 0
} }
if i, ok := elem.(*QQMusicElement); ok { if i, ok := elem.(*QQMusicElement); ok {
var msgStyle uint32 = 4 var msgStyle uint32 = 4
if i.MusicUrl == "" { if i.MusicURL == "" {
msgStyle = 0 // fix vip song msgStyle = 0 // fix vip song
} }
ret, err := bot.Client.SendGroupRichMessage(groupId, 100497308, 1, msgStyle, client.RichClientInfo{ ret, err := bot.Client.SendGroupRichMessage(groupID, 100497308, 1, msgStyle, client.RichClientInfo{
Platform: 1, Platform: 1,
SdkVersion: "0.0.0", SdkVersion: "0.0.0",
PackageName: "com.tencent.qqmusic", PackageName: "com.tencent.qqmusic",
@ -214,18 +224,18 @@ func (bot *CQBot) SendGroupMessage(groupId int64, m *message.SendingMessage) int
}, &message.RichMessage{ }, &message.RichMessage{
Title: i.Title, Title: i.Title,
Summary: i.Summary, Summary: i.Summary,
Url: i.Url, Url: i.URL,
PictureUrl: i.PictureUrl, PictureUrl: i.PictureURL,
MusicUrl: i.MusicUrl, MusicUrl: i.MusicURL,
}) })
if err != nil { if err != nil {
log.Warnf("警告: 群 %v 富文本消息发送失败: %v", groupId, err) log.Warnf("警告: 群 %v 富文本消息发送失败: %v", groupID, err)
return -1 return -1
} }
return bot.InsertGroupMessage(ret) return bot.InsertGroupMessage(ret)
} }
if i, ok := elem.(*CloudMusicElement); ok { if i, ok := elem.(*CloudMusicElement); ok {
ret, err := bot.Client.SendGroupRichMessage(groupId, 100495085, 1, 4, client.RichClientInfo{ ret, err := bot.Client.SendGroupRichMessage(groupID, 100495085, 1, 4, client.RichClientInfo{
Platform: 1, Platform: 1,
SdkVersion: "0.0.0", SdkVersion: "0.0.0",
PackageName: "com.netease.cloudmusic", PackageName: "com.netease.cloudmusic",
@ -233,18 +243,18 @@ func (bot *CQBot) SendGroupMessage(groupId int64, m *message.SendingMessage) int
}, &message.RichMessage{ }, &message.RichMessage{
Title: i.Title, Title: i.Title,
Summary: i.Summary, Summary: i.Summary,
Url: i.Url, Url: i.URL,
PictureUrl: i.PictureUrl, PictureUrl: i.PictureURL,
MusicUrl: i.MusicUrl, MusicUrl: i.MusicURL,
}) })
if err != nil { if err != nil {
log.Warnf("警告: 群 %v 富文本消息发送失败: %v", groupId, err) log.Warnf("警告: 群 %v 富文本消息发送失败: %v", groupID, err)
return -1 return -1
} }
return bot.InsertGroupMessage(ret) return bot.InsertGroupMessage(ret)
} }
if i, ok := elem.(*MiguMusicElement); ok { if i, ok := elem.(*MiguMusicElement); ok {
ret, err := bot.Client.SendGroupRichMessage(groupId, 1101053067, 1, 4, client.RichClientInfo{ ret, err := bot.Client.SendGroupRichMessage(groupID, 1101053067, 1, 4, client.RichClientInfo{
Platform: 1, Platform: 1,
SdkVersion: "0.0.0", SdkVersion: "0.0.0",
PackageName: "cmccwm.mobilemusic", PackageName: "cmccwm.mobilemusic",
@ -252,12 +262,12 @@ func (bot *CQBot) SendGroupMessage(groupId int64, m *message.SendingMessage) int
}, &message.RichMessage{ }, &message.RichMessage{
Title: i.Title, Title: i.Title,
Summary: i.Summary, Summary: i.Summary,
Url: i.Url, Url: i.URL,
PictureUrl: i.PictureUrl, PictureUrl: i.PictureURL,
MusicUrl: i.MusicUrl, MusicUrl: i.MusicURL,
}) })
if err != nil { if err != nil {
log.Warnf("警告: 群 %v 富文本消息发送失败: %v", groupId, err) log.Warnf("警告: 群 %v 富文本消息发送失败: %v", groupID, err)
return -1 return -1
} }
return bot.InsertGroupMessage(ret) return bot.InsertGroupMessage(ret)
@ -270,7 +280,7 @@ func (bot *CQBot) SendGroupMessage(groupId int64, m *message.SendingMessage) int
} }
m.Elements = newElem m.Elements = newElem
bot.checkMedia(newElem) bot.checkMedia(newElem)
ret := bot.Client.SendGroupMessage(groupId, m, ForceFragmented) ret := bot.Client.SendGroupMessage(groupID, m, ForceFragmented)
if ret == nil || ret.Id == -1 { if ret == nil || ret.Id == -1 {
log.Warnf("群消息发送失败: 账号可能被风控.") log.Warnf("群消息发送失败: 账号可能被风控.")
return -1 return -1
@ -278,6 +288,7 @@ func (bot *CQBot) SendGroupMessage(groupId int64, m *message.SendingMessage) int
return bot.InsertGroupMessage(ret) return bot.InsertGroupMessage(ret)
} }
//SendPrivateMessage 发送私聊消息
func (bot *CQBot) SendPrivateMessage(target int64, m *message.SendingMessage) int32 { func (bot *CQBot) SendPrivateMessage(target int64, m *message.SendingMessage) int32 {
var newElem []message.IMessageElement var newElem []message.IMessageElement
for _, elem := range m.Elements { for _, elem := range m.Elements {
@ -314,7 +325,7 @@ func (bot *CQBot) SendPrivateMessage(target int64, m *message.SendingMessage) in
} }
if i, ok := elem.(*QQMusicElement); ok { if i, ok := elem.(*QQMusicElement); ok {
var msgStyle uint32 = 4 var msgStyle uint32 = 4
if i.MusicUrl == "" { if i.MusicURL == "" {
msgStyle = 0 // fix vip song msgStyle = 0 // fix vip song
} }
bot.Client.SendFriendRichMessage(target, 100497308, 1, msgStyle, client.RichClientInfo{ bot.Client.SendFriendRichMessage(target, 100497308, 1, msgStyle, client.RichClientInfo{
@ -325,9 +336,9 @@ func (bot *CQBot) SendPrivateMessage(target int64, m *message.SendingMessage) in
}, &message.RichMessage{ }, &message.RichMessage{
Title: i.Title, Title: i.Title,
Summary: i.Summary, Summary: i.Summary,
Url: i.Url, Url: i.URL,
PictureUrl: i.PictureUrl, PictureUrl: i.PictureURL,
MusicUrl: i.MusicUrl, MusicUrl: i.MusicURL,
}) })
return 0 return 0
} }
@ -340,9 +351,9 @@ func (bot *CQBot) SendPrivateMessage(target int64, m *message.SendingMessage) in
}, &message.RichMessage{ }, &message.RichMessage{
Title: i.Title, Title: i.Title,
Summary: i.Summary, Summary: i.Summary,
Url: i.Url, Url: i.URL,
PictureUrl: i.PictureUrl, PictureUrl: i.PictureURL,
MusicUrl: i.MusicUrl, MusicUrl: i.MusicURL,
}) })
return 0 return 0
} }
@ -355,9 +366,9 @@ func (bot *CQBot) SendPrivateMessage(target int64, m *message.SendingMessage) in
}, &message.RichMessage{ }, &message.RichMessage{
Title: i.Title, Title: i.Title,
Summary: i.Summary, Summary: i.Summary,
Url: i.Url, Url: i.URL,
PictureUrl: i.PictureUrl, PictureUrl: i.PictureURL,
MusicUrl: i.MusicUrl, MusicUrl: i.MusicURL,
}) })
return 0 return 0
} }
@ -392,6 +403,7 @@ func (bot *CQBot) SendPrivateMessage(target int64, m *message.SendingMessage) in
return id return id
} }
//InsertGroupMessage 群聊消息入数据库
func (bot *CQBot) InsertGroupMessage(m *message.GroupMessage) int32 { func (bot *CQBot) InsertGroupMessage(m *message.GroupMessage) int32 {
val := MSG{ val := MSG{
"message-id": m.Id, "message-id": m.Id,
@ -402,7 +414,7 @@ func (bot *CQBot) InsertGroupMessage(m *message.GroupMessage) int32 {
"time": m.Time, "time": m.Time,
"message": ToStringMessage(m.Elements, m.GroupCode, true), "message": ToStringMessage(m.Elements, m.GroupCode, true),
} }
id := ToGlobalId(m.GroupCode, m.Id) id := toGlobalID(m.GroupCode, m.Id)
if bot.db != nil { if bot.db != nil {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
if err := gob.NewEncoder(buf).Encode(val); err != nil { if err := gob.NewEncoder(buf).Encode(val); err != nil {
@ -417,6 +429,7 @@ func (bot *CQBot) InsertGroupMessage(m *message.GroupMessage) int32 {
return id return id
} }
//InsertPrivateMessage 私聊消息入数据库
func (bot *CQBot) InsertPrivateMessage(m *message.PrivateMessage) int32 { func (bot *CQBot) InsertPrivateMessage(m *message.PrivateMessage) int32 {
val := MSG{ val := MSG{
"message-id": m.Id, "message-id": m.Id,
@ -426,7 +439,7 @@ func (bot *CQBot) InsertPrivateMessage(m *message.PrivateMessage) int32 {
"time": m.Time, "time": m.Time,
"message": ToStringMessage(m.Elements, m.Sender.Uin, true), "message": ToStringMessage(m.Elements, m.Sender.Uin, true),
} }
id := ToGlobalId(m.Sender.Uin, m.Id) id := toGlobalID(m.Sender.Uin, m.Id)
if bot.db != nil { if bot.db != nil {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
if err := gob.NewEncoder(buf).Encode(val); err != nil { if err := gob.NewEncoder(buf).Encode(val); err != nil {
@ -441,10 +454,12 @@ func (bot *CQBot) InsertPrivateMessage(m *message.PrivateMessage) int32 {
return id return id
} }
func ToGlobalId(code int64, msgId int32) int32 { //toGlobalID 构建`code`-`msgID`的字符串并返回其CRC32 Checksum的值
return int32(crc32.ChecksumIEEE([]byte(fmt.Sprintf("%d-%d", code, msgId)))) func toGlobalID(code int64, msgID int32) int32 {
return int32(crc32.ChecksumIEEE([]byte(fmt.Sprintf("%d-%d", code, msgID))))
} }
//Release 释放Bot实例
func (bot *CQBot) Release() { func (bot *CQBot) Release() {
if bot.db != nil { if bot.db != nil {
_ = bot.db.Close() _ = bot.db.Close()
@ -535,7 +550,8 @@ func formatMemberName(mem *client.GroupMemberInfo) string {
return fmt.Sprintf("%s(%d)", mem.DisplayName(), mem.Uin) return fmt.Sprintf("%s(%d)", mem.DisplayName(), mem.Uin)
} }
func (m MSG) ToJson() string { //ToJSON 生成JSON字符串
func (m MSG) ToJSON() string {
b, _ := json.Marshal(m) b, _ := json.Marshal(m)
return string(b) return string(b)
} }

View File

@ -34,67 +34,83 @@ var typeReg = regexp.MustCompile(`\[CQ:(\w+)`)
var paramReg = regexp.MustCompile(`,([\w\-.]+?)=([^,\]]+)`) var paramReg = regexp.MustCompile(`,([\w\-.]+?)=([^,\]]+)`)
*/ */
//IgnoreInvalidCQCode 是否忽略无效CQ码
var IgnoreInvalidCQCode = false var IgnoreInvalidCQCode = false
var SplitUrl = false
//SplitURL 是否分割URL
var SplitURL = false
const maxImageSize = 1024 * 1024 * 30 // 30MB const maxImageSize = 1024 * 1024 * 30 // 30MB
const maxVideoSize = 1024 * 1024 * 100 // 100MB const maxVideoSize = 1024 * 1024 * 100 // 100MB
//PokeElement 拍一拍
type PokeElement struct { type PokeElement struct {
Target int64 Target int64
} }
//GiftElement 礼物
type GiftElement struct { type GiftElement struct {
Target int64 Target int64
GiftId message.GroupGift GiftID message.GroupGift
} }
//MusicElement 音乐
type MusicElement struct { type MusicElement struct {
Title string Title string
Summary string Summary string
Url string URL string
PictureUrl string PictureURL string
MusicUrl string MusicURL string
} }
//QQMusicElement QQ音乐
type QQMusicElement struct { type QQMusicElement struct {
MusicElement MusicElement
} }
//CloudMusicElement 网易云音乐
type CloudMusicElement struct { type CloudMusicElement struct {
MusicElement MusicElement
} }
//MiguMusicElement 咪咕音乐
type MiguMusicElement struct { type MiguMusicElement struct {
MusicElement MusicElement
} }
//LocalImageElement 本地图片
type LocalImageElement struct { type LocalImageElement struct {
message.ImageElement message.ImageElement
Stream io.ReadSeeker Stream io.ReadSeeker
File string File string
} }
//LocalVoiceElement 本地语音
type LocalVoiceElement struct { type LocalVoiceElement struct {
message.VoiceElement message.VoiceElement
Stream io.ReadSeeker Stream io.ReadSeeker
} }
//LocalVideoElement 本地视频
type LocalVideoElement struct { type LocalVideoElement struct {
message.ShortVideoElement message.ShortVideoElement
File string File string
thumb io.ReadSeeker thumb io.ReadSeeker
} }
//Type 获取元素类型ID
func (e *GiftElement) Type() message.ElementType { func (e *GiftElement) Type() message.ElementType {
//Make message.IMessageElement Happy
return message.At return message.At
} }
//Type 获取元素类型ID
func (e *MusicElement) Type() message.ElementType { func (e *MusicElement) Type() message.ElementType {
//Make message.IMessageElement Happy
return message.Service return message.Service
} }
var GiftId = [...]message.GroupGift{ //GiftID 礼物ID数组
var GiftID = [...]message.GroupGift{
message.SweetWink, message.SweetWink,
message.HappyCola, message.HappyCola,
message.LuckyBracelet, message.LuckyBracelet,
@ -111,15 +127,18 @@ var GiftId = [...]message.GroupGift{
message.LoveMask, message.LoveMask,
} }
//Type 获取元素类型ID
func (e *PokeElement) Type() message.ElementType { func (e *PokeElement) Type() message.ElementType {
//Make message.IMessageElement Happy
return message.At return message.At
} }
func ToArrayMessage(e []message.IMessageElement, code int64, raw ...bool) (r []MSG) { //ToArrayMessage 将消息元素数组转为MSG数组以用于消息上报
func ToArrayMessage(e []message.IMessageElement, id int64, isRaw ...bool) (r []MSG) {
r = []MSG{} r = []MSG{}
ur := false ur := false
if len(raw) != 0 { if len(isRaw) != 0 {
ur = raw[0] ur = isRaw[0]
} }
m := &message.SendingMessage{Elements: e} m := &message.SendingMessage{Elements: e}
reply := m.FirstOrNil(func(e message.IMessageElement) bool { reply := m.FirstOrNil(func(e message.IMessageElement) bool {
@ -129,7 +148,7 @@ func ToArrayMessage(e []message.IMessageElement, code int64, raw ...bool) (r []M
if reply != nil { if reply != nil {
r = append(r, MSG{ r = append(r, MSG{
"type": "reply", "type": "reply",
"data": map[string]string{"id": fmt.Sprint(ToGlobalId(code, reply.(*message.ReplyElement).ReplySeq))}, "data": map[string]string{"id": fmt.Sprint(toGlobalID(id, reply.(*message.ReplyElement).ReplySeq))},
}) })
} }
for _, elem := range e { for _, elem := range e {
@ -266,10 +285,11 @@ func ToArrayMessage(e []message.IMessageElement, code int64, raw ...bool) (r []M
return return
} }
func ToStringMessage(e []message.IMessageElement, code int64, raw ...bool) (r string) { //ToStringMessage 将消息元素数组转为字符串以用于消息上报
func ToStringMessage(e []message.IMessageElement, id int64, isRaw ...bool) (r string) {
ur := false ur := false
if len(raw) != 0 { if len(isRaw) != 0 {
ur = raw[0] ur = isRaw[0]
} }
// 方便 // 方便
m := &message.SendingMessage{Elements: e} m := &message.SendingMessage{Elements: e}
@ -278,7 +298,7 @@ func ToStringMessage(e []message.IMessageElement, code int64, raw ...bool) (r st
return ok return ok
}) })
if reply != nil { if reply != nil {
r += fmt.Sprintf("[CQ:reply,id=%d]", ToGlobalId(code, reply.(*message.ReplyElement).ReplySeq)) r += fmt.Sprintf("[CQ:reply,id=%d]", toGlobalID(id, reply.(*message.ReplyElement).ReplySeq))
} }
for _, elem := range e { for _, elem := range e {
switch o := elem.(type) { switch o := elem.(type) {
@ -344,7 +364,8 @@ func ToStringMessage(e []message.IMessageElement, code int64, raw ...bool) (r st
return return
} }
func (bot *CQBot) ConvertStringMessage(msg string, group bool) (r []message.IMessageElement) { //ConvertStringMessage 将消息字符串转为消息元素数组
func (bot *CQBot) ConvertStringMessage(msg string, isGroup bool) (r []message.IMessageElement) {
index := 0 index := 0
stat := 0 stat := 0
rMsg := []rune(msg) rMsg := []rune(msg)
@ -369,7 +390,7 @@ func (bot *CQBot) ConvertStringMessage(msg string, group bool) (r []message.IMes
} }
saveTempText := func() { saveTempText := func() {
if len(tempText) != 0 { if len(tempText) != 0 {
if SplitUrl { if SplitURL {
for _, t := range global.SplitURL(CQCodeUnescapeValue(string(tempText))) { for _, t := range global.SplitURL(CQCodeUnescapeValue(string(tempText))) {
r = append(r, message.NewText(t)) r = append(r, message.NewText(t))
} }
@ -421,7 +442,7 @@ func (bot *CQBot) ConvertStringMessage(msg string, group bool) (r []message.IMes
ReplySeq: org["message-id"].(int32), ReplySeq: org["message-id"].(int32),
Sender: org["sender"].(message.Sender).Uin, Sender: org["sender"].(message.Sender).Uin,
Time: org["time"].(int32), Time: org["time"].(int32),
Elements: bot.ConvertStringMessage(org["message"].(string), group), Elements: bot.ConvertStringMessage(org["message"].(string), isGroup),
}, },
}, r...) }, r...)
return return
@ -441,7 +462,7 @@ func (bot *CQBot) ConvertStringMessage(msg string, group bool) (r []message.IMes
ReplySeq: int32(0), ReplySeq: int32(0),
Sender: sender, Sender: sender,
Time: int32(msgTime), Time: int32(msgTime),
Elements: bot.ConvertStringMessage(customText, group), Elements: bot.ConvertStringMessage(customText, isGroup),
}, },
}, r...) }, r...)
return return
@ -453,7 +474,7 @@ func (bot *CQBot) ConvertStringMessage(msg string, group bool) (r []message.IMes
return return
} }
} }
elem, err := bot.ToElement(t, params, group) elem, err := bot.ToElement(t, params, isGroup)
if err != nil { if err != nil {
org := "[CQ:" + string(cqCode) + "]" org := "[CQ:" + string(cqCode) + "]"
if !IgnoreInvalidCQCode { if !IgnoreInvalidCQCode {
@ -500,10 +521,11 @@ func (bot *CQBot) ConvertStringMessage(msg string, group bool) (r []message.IMes
return return
} }
func (bot *CQBot) ConvertObjectMessage(m gjson.Result, group bool) (r []message.IMessageElement) { //ConvertObjectMessage 将消息JSON对象转为消息元素数组
func (bot *CQBot) ConvertObjectMessage(m gjson.Result, isGroup bool) (r []message.IMessageElement) {
convertElem := func(e gjson.Result) { convertElem := func(e gjson.Result) {
t := e.Get("type").Str t := e.Get("type").Str
if t == "reply" && group { if t == "reply" && isGroup {
if len(r) > 0 { if len(r) > 0 {
if _, ok := r[0].(*message.ReplyElement); ok { if _, ok := r[0].(*message.ReplyElement); ok {
log.Warnf("警告: 一条信息只能包含一个 Reply 元素.") log.Warnf("警告: 一条信息只能包含一个 Reply 元素.")
@ -520,7 +542,7 @@ func (bot *CQBot) ConvertObjectMessage(m gjson.Result, group bool) (r []message.
ReplySeq: org["message-id"].(int32), ReplySeq: org["message-id"].(int32),
Sender: org["sender"].(message.Sender).Uin, Sender: org["sender"].(message.Sender).Uin,
Time: org["time"].(int32), Time: org["time"].(int32),
Elements: bot.ConvertStringMessage(org["message"].(string), group), Elements: bot.ConvertStringMessage(org["message"].(string), isGroup),
}, },
}, r...) }, r...)
return return
@ -540,7 +562,7 @@ func (bot *CQBot) ConvertObjectMessage(m gjson.Result, group bool) (r []message.
ReplySeq: int32(0), ReplySeq: int32(0),
Sender: sender, Sender: sender,
Time: int32(msgTime), Time: int32(msgTime),
Elements: bot.ConvertStringMessage(customText, group), Elements: bot.ConvertStringMessage(customText, isGroup),
}, },
}, r...) }, r...)
return return
@ -555,7 +577,7 @@ func (bot *CQBot) ConvertObjectMessage(m gjson.Result, group bool) (r []message.
d[key.Str] = value.String() d[key.Str] = value.String()
return true return true
}) })
elem, err := bot.ToElement(t, d, group) elem, err := bot.ToElement(t, d, isGroup)
if err != nil { if err != nil {
log.Warnf("转换CQ码到MiraiGo Element时出现错误: %v 将忽略本段CQ码.", err) log.Warnf("转换CQ码到MiraiGo Element时出现错误: %v 将忽略本段CQ码.", err)
return return
@ -568,7 +590,7 @@ func (bot *CQBot) ConvertObjectMessage(m gjson.Result, group bool) (r []message.
} }
} }
if m.Type == gjson.String { if m.Type == gjson.String {
return bot.ConvertStringMessage(m.Str, group) return bot.ConvertStringMessage(m.Str, isGroup)
} }
if m.IsArray() { if m.IsArray() {
for _, e := range m.Array() { for _, e := range m.Array() {
@ -582,12 +604,14 @@ func (bot *CQBot) ConvertObjectMessage(m gjson.Result, group bool) (r []message.
} }
// ToElement 将解码后的CQCode转换为Element. // ToElement 将解码后的CQCode转换为Element.
//
// 返回 interface{} 存在三种类型 // 返回 interface{} 存在三种类型
//
// message.IMessageElement []message.IMessageElement nil // message.IMessageElement []message.IMessageElement nil
func (bot *CQBot) ToElement(t string, d map[string]string, group bool) (m interface{}, err error) { func (bot *CQBot) ToElement(t string, d map[string]string, isGroup bool) (m interface{}, err error) {
switch t { switch t {
case "text": case "text":
if SplitUrl { if SplitURL {
var ret []message.IMessageElement var ret []message.IMessageElement
for _, text := range global.SplitURL(d["text"]) { for _, text := range global.SplitURL(d["text"]) {
ret = append(ret, message.NewText(text)) ret = append(ret, message.NewText(text))
@ -596,7 +620,7 @@ func (bot *CQBot) ToElement(t string, d map[string]string, group bool) (m interf
} }
return message.NewText(d["text"]), nil return message.NewText(d["text"]), nil
case "image": case "image":
img, err := bot.makeImageOrVideoElem(d, false, group) img, err := bot.makeImageOrVideoElem(d, false, isGroup)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -605,7 +629,7 @@ func (bot *CQBot) ToElement(t string, d map[string]string, group bool) (m interf
return img, nil return img, nil
} }
if i, ok := img.(*LocalImageElement); ok { // 秀图,闪照什么的就直接传了吧 if i, ok := img.(*LocalImageElement); ok { // 秀图,闪照什么的就直接传了吧
if group { if isGroup {
img, err = bot.UploadLocalImageAsGroup(1, i) img, err = bot.UploadLocalImageAsGroup(1, i)
} else { } else {
img, err = bot.UploadLocalImageAsPrivate(1, i) img, err = bot.UploadLocalImageAsPrivate(1, i)
@ -637,7 +661,7 @@ func (bot *CQBot) ToElement(t string, d map[string]string, group bool) (m interf
t, _ := strconv.ParseInt(d["qq"], 10, 64) t, _ := strconv.ParseInt(d["qq"], 10, 64)
return &PokeElement{Target: t}, nil return &PokeElement{Target: t}, nil
case "gift": case "gift":
if !group { if !isGroup {
return nil, errors.New("private gift unsupported") // no free private gift return nil, errors.New("private gift unsupported") // no free private gift
} }
t, _ := strconv.ParseInt(d["qq"], 10, 64) t, _ := strconv.ParseInt(d["qq"], 10, 64)
@ -645,7 +669,7 @@ func (bot *CQBot) ToElement(t string, d map[string]string, group bool) (m interf
if id < 0 || id >= 14 { if id < 0 || id >= 14 {
return nil, errors.New("invalid gift id") return nil, errors.New("invalid gift id")
} }
return &GiftElement{Target: t, GiftId: GiftId[id]}, nil return &GiftElement{Target: t, GiftID: GiftID[id]}, nil
case "tts": case "tts":
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
@ -703,7 +727,7 @@ func (bot *CQBot) ToElement(t string, d map[string]string, group bool) (m interf
mid := info.Get("track_info.mid").Str mid := info.Get("track_info.mid").Str
albumMid := info.Get("track_info.album.mid").Str albumMid := info.Get("track_info.album.mid").Str
pinfo, _ := global.GetBytes("http://u.y.qq.com/cgi-bin/musicu.fcg?g_tk=2034008533&uin=0&format=json&data={\"comm\":{\"ct\":23,\"cv\":0},\"url_mid\":{\"module\":\"vkey.GetVkeyServer\",\"method\":\"CgiGetVkey\",\"param\":{\"guid\":\"4311206557\",\"songmid\":[\"" + mid + "\"],\"songtype\":[0],\"uin\":\"0\",\"loginflag\":1,\"platform\":\"23\"}}}&_=1599039471576") pinfo, _ := global.GetBytes("http://u.y.qq.com/cgi-bin/musicu.fcg?g_tk=2034008533&uin=0&format=json&data={\"comm\":{\"ct\":23,\"cv\":0},\"url_mid\":{\"module\":\"vkey.GetVkeyServer\",\"method\":\"CgiGetVkey\",\"param\":{\"guid\":\"4311206557\",\"songmid\":[\"" + mid + "\"],\"songtype\":[0],\"uin\":\"0\",\"loginflag\":1,\"platform\":\"23\"}}}&_=1599039471576")
jumpUrl := "https://i.y.qq.com/v8/playsong.html?platform=11&appshare=android_qq&appversion=10030010&hosteuin=oKnlNenz7i-s7c**&songmid=" + mid + "&type=0&appsongtype=1&_wv=1&source=qq&ADTAG=qfshare" jumpURL := "https://i.y.qq.com/v8/playsong.html?platform=11&appshare=android_qq&appversion=10030010&hosteuin=oKnlNenz7i-s7c**&songmid=" + mid + "&type=0&appsongtype=1&_wv=1&source=qq&ADTAG=qfshare"
purl := gjson.ParseBytes(pinfo).Get("url_mid.data.midurlinfo.0.purl").Str purl := gjson.ParseBytes(pinfo).Get("url_mid.data.midurlinfo.0.purl").Str
preview := "http://y.gtimg.cn/music/photo_new/T002R180x180M000" + albumMid + ".jpg" preview := "http://y.gtimg.cn/music/photo_new/T002R180x180M000" + albumMid + ".jpg"
if len(aid) < 2 { if len(aid) < 2 {
@ -716,9 +740,9 @@ func (bot *CQBot) ToElement(t string, d map[string]string, group bool) (m interf
return &QQMusicElement{MusicElement: MusicElement{ return &QQMusicElement{MusicElement: MusicElement{
Title: name, Title: name,
Summary: content, Summary: content,
Url: jumpUrl, URL: jumpURL,
PictureUrl: preview, PictureURL: preview,
MusicUrl: purl, MusicURL: purl,
}}, nil }}, nil
} }
if d["type"] == "163" { if d["type"] == "163" {
@ -730,9 +754,9 @@ func (bot *CQBot) ToElement(t string, d map[string]string, group bool) (m interf
return nil, errors.New("song not found") return nil, errors.New("song not found")
} }
name := info.Get("name").Str name := info.Get("name").Str
jumpUrl := "https://y.music.163.com/m/song/" + d["id"] jumpURL := "https://y.music.163.com/m/song/" + d["id"]
musicUrl := "http://music.163.com/song/media/outer/url?id=" + d["id"] musicURL := "http://music.163.com/song/media/outer/url?id=" + d["id"]
picUrl := info.Get("album.picUrl").Str picURL := info.Get("album.picUrl").Str
artistName := "" artistName := ""
if info.Get("artists.0").Exists() { if info.Get("artists.0").Exists() {
artistName = info.Get("artists.0.name").Str artistName = info.Get("artists.0.name").Str
@ -740,9 +764,9 @@ func (bot *CQBot) ToElement(t string, d map[string]string, group bool) (m interf
return &CloudMusicElement{MusicElement{ return &CloudMusicElement{MusicElement{
Title: name, Title: name,
Summary: artistName, Summary: artistName,
Url: jumpUrl, URL: jumpURL,
PictureUrl: picUrl, PictureURL: picURL,
MusicUrl: musicUrl, MusicURL: musicURL,
}}, nil }}, nil
} }
if d["type"] == "custom" { if d["type"] == "custom" {
@ -750,31 +774,31 @@ func (bot *CQBot) ToElement(t string, d map[string]string, group bool) (m interf
return &QQMusicElement{MusicElement{ return &QQMusicElement{MusicElement{
Title: d["title"], Title: d["title"],
Summary: d["content"], Summary: d["content"],
Url: d["url"], URL: d["url"],
PictureUrl: d["image"], PictureURL: d["image"],
MusicUrl: d["purl"], MusicURL: d["purl"],
}}, nil }}, nil
} }
if d["subtype"] == "163" { if d["subtype"] == "163" {
return &CloudMusicElement{MusicElement{ return &CloudMusicElement{MusicElement{
Title: d["title"], Title: d["title"],
Summary: d["content"], Summary: d["content"],
Url: d["url"], URL: d["url"],
PictureUrl: d["image"], PictureURL: d["image"],
MusicUrl: d["purl"], MusicURL: d["purl"],
}}, nil }}, nil
} }
if d["subtype"] == "migu" { if d["subtype"] == "migu" {
return &MiguMusicElement{MusicElement{ return &MiguMusicElement{MusicElement{
Title: d["title"], Title: d["title"],
Summary: d["content"], Summary: d["content"],
Url: d["url"], URL: d["url"],
PictureUrl: d["image"], PictureURL: d["image"],
MusicUrl: d["purl"], MusicURL: d["purl"],
}}, nil }}, nil
} }
xml := fmt.Sprintf(`<?xml version='1.0' encoding='UTF-8' standalone='yes' ?><msg serviceID="2" templateID="1" action="web" brief="[分享] %s" sourceMsgId="0" url="%s" flag="0" adverSign="0" multiMsgFlag="0"><item layout="2"><audio cover="%s" src="%s"/><title>%s</title><summary>%s</summary></item><source name="音乐" 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 := fmt.Sprintf(`<?xml version='1.0' encoding='UTF-8' standalone='yes' ?><msg serviceID="2" templateID="1" action="web" brief="[分享] %s" sourceMsgId="0" url="%s" flag="0" adverSign="0" multiMsgFlag="0"><item layout="2"><audio cover="%s" src="%s"/><title>%s</title><summary>%s</summary></item><source name="音乐" 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>`,
XmlEscape(d["title"]), d["url"], d["image"], d["audio"], XmlEscape(d["title"]), XmlEscape(d["content"])) XMLEscape(d["title"]), d["url"], d["image"], d["audio"], XMLEscape(d["title"]), XMLEscape(d["content"]))
return &message.ServiceElement{ return &message.ServiceElement{
Id: 60, Id: 60,
Content: xml, Content: xml,
@ -783,14 +807,14 @@ func (bot *CQBot) ToElement(t string, d map[string]string, group bool) (m interf
} }
return nil, errors.New("unsupported music type: " + d["type"]) return nil, errors.New("unsupported music type: " + d["type"])
case "xml": case "xml":
resId := d["resid"] resID := d["resid"]
template := CQCodeEscapeValue(d["data"]) template := CQCodeEscapeValue(d["data"])
i, _ := strconv.ParseInt(resId, 10, 64) i, _ := strconv.ParseInt(resID, 10, 64)
msg := message.NewRichXml(template, i) msg := message.NewRichXml(template, i)
return msg, nil return msg, nil
case "json": case "json":
resId := d["resid"] resID := d["resid"]
i, _ := strconv.ParseInt(resId, 10, 64) i, _ := strconv.ParseInt(resID, 10, 64)
if i == 0 { if i == 0 {
//默认情况下走小程序通道 //默认情况下走小程序通道
msg := message.NewLightApp(CQCodeUnescapeValue(d["data"])) msg := message.NewLightApp(CQCodeUnescapeValue(d["data"]))
@ -818,17 +842,17 @@ func (bot *CQBot) ToElement(t string, d map[string]string, group bool) (m interf
if maxHeight == 0 { if maxHeight == 0 {
maxHeight = 1000 maxHeight = 1000
} }
img, err := bot.makeImageOrVideoElem(d, false, group) img, err := bot.makeImageOrVideoElem(d, false, isGroup)
if err != nil { if err != nil {
return nil, errors.New("send cardimage faild") return nil, errors.New("send cardimage faild")
} }
return bot.makeShowPic(img, source, icon, minWidth, minHeight, maxWidth, maxHeight, group) return bot.makeShowPic(img, source, icon, minWidth, minHeight, maxWidth, maxHeight, isGroup)
case "video": case "video":
cache := d["cache"] cache := d["cache"]
if cache == "" { if cache == "" {
cache = "1" cache = "1"
} }
file, err := bot.makeImageOrVideoElem(d, true, group) file, err := bot.makeImageOrVideoElem(d, true, isGroup)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -876,12 +900,22 @@ func (bot *CQBot) ToElement(t string, d map[string]string, group bool) (m interf
return nil, nil return nil, nil
} }
func XmlEscape(c string) string { //XMLEscape 将字符串c转义为XML字符串
func XMLEscape(c string) string {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
_ = xml2.EscapeText(buf, []byte(c)) _ = xml2.EscapeText(buf, []byte(c))
return buf.String() return buf.String()
} }
/*CQCodeEscapeText 将字符串raw中部分字符转义
& -> &amp;
[ -> &#91;
] -> &#93;
*/
func CQCodeEscapeText(raw string) string { func CQCodeEscapeText(raw string) string {
ret := raw ret := raw
ret = strings.ReplaceAll(ret, "&", "&amp;") ret = strings.ReplaceAll(ret, "&", "&amp;")
@ -890,12 +924,26 @@ func CQCodeEscapeText(raw string) string {
return ret return ret
} }
/*CQCodeEscapeValue 将字符串value中部分字符转义
, -> &#44;
*/
func CQCodeEscapeValue(value string) string { func CQCodeEscapeValue(value string) string {
ret := CQCodeEscapeText(value) ret := CQCodeEscapeText(value)
ret = strings.ReplaceAll(ret, ",", "&#44;") ret = strings.ReplaceAll(ret, ",", "&#44;")
return ret return ret
} }
/*CQCodeUnescapeText 将字符串content中部分字符反转义
&amp; -> &
&#91; -> [
&#93; -> ]
*/
func CQCodeUnescapeText(content string) string { func CQCodeUnescapeText(content string) string {
ret := content ret := content
ret = strings.ReplaceAll(ret, "&#91;", "[") ret = strings.ReplaceAll(ret, "&#91;", "[")
@ -904,13 +952,18 @@ func CQCodeUnescapeText(content string) string {
return ret return ret
} }
/*CQCodeUnescapeValue 将字符串content中部分字符反转义
, -> &#44;
*/
func CQCodeUnescapeValue(content string) string { func CQCodeUnescapeValue(content string) string {
ret := strings.ReplaceAll(content, "&#44;", ",") ret := strings.ReplaceAll(content, "&#44;", ",")
ret = CQCodeUnescapeText(ret) ret = CQCodeUnescapeText(ret)
return ret return ret
} }
// 图片 elem 生成器,单独拎出来,用于公用 //makeImageOrVideoElem 图片 elem 生成器,单独拎出来,用于公用
func (bot *CQBot) makeImageOrVideoElem(d map[string]string, video, group bool) (message.IMessageElement, error) { func (bot *CQBot) makeImageOrVideoElem(d map[string]string, video, group bool) (message.IMessageElement, error) {
f := d["file"] f := d["file"]
if strings.HasPrefix(f, "http") || strings.HasPrefix(f, "https") { if strings.HasPrefix(f, "http") || strings.HasPrefix(f, "https") {
@ -986,9 +1039,8 @@ func (bot *CQBot) makeImageOrVideoElem(d map[string]string, video, group bool) (
Name: r.ReadString(), Name: r.ReadString(),
Uuid: r.ReadAvailable(), Uuid: r.ReadAvailable(),
}}, nil }}, nil
} else {
return &LocalVideoElement{File: rawPath}, nil
} }
return &LocalVideoElement{File: rawPath}, nil
} }
if strings.HasPrefix(f, "base64") { if strings.HasPrefix(f, "base64") {
b, err := base64.StdEncoding.DecodeString(strings.ReplaceAll(f, "base64://", "")) b, err := base64.StdEncoding.DecodeString(strings.ReplaceAll(f, "base64://", ""))

2
coolq/doc.go Normal file
View File

@ -0,0 +1,2 @@
//Package coolq 包含CQBot实例,CQ码处理,消息发送,消息处理等的相关函数与结构体
package coolq

View File

@ -23,11 +23,11 @@ func SetMessageFormat(f string) {
} }
//ToFormattedMessage 将给定[]message.IMessageElement转换为通过coolq.SetMessageFormat所定义的消息上报格式 //ToFormattedMessage 将给定[]message.IMessageElement转换为通过coolq.SetMessageFormat所定义的消息上报格式
func ToFormattedMessage(e []message.IMessageElement, id int64, raw ...bool) (r interface{}) { func ToFormattedMessage(e []message.IMessageElement, id int64, isRaw ...bool) (r interface{}) {
if format == "string" { if format == "string" {
r = ToStringMessage(e, id, raw...) r = ToStringMessage(e, id, isRaw...)
} else if format == "array" { } else if format == "array" {
r = ToArrayMessage(e, id, raw...) r = ToArrayMessage(e, id, isRaw...)
} }
return return
} }
@ -164,7 +164,7 @@ func (bot *CQBot) groupMutedEvent(c *client.QQClient, e *client.GroupMuteEvent)
func (bot *CQBot) groupRecallEvent(c *client.QQClient, e *client.GroupMessageRecalledEvent) { func (bot *CQBot) groupRecallEvent(c *client.QQClient, e *client.GroupMessageRecalledEvent) {
g := c.FindGroup(e.GroupCode) g := c.FindGroup(e.GroupCode)
gid := ToGlobalId(e.GroupCode, e.MessageId) gid := toGlobalID(e.GroupCode, e.MessageId)
log.Infof("群 %v 内 %v 撤回了 %v 的消息: %v.", log.Infof("群 %v 内 %v 撤回了 %v 的消息: %v.",
formatGroupName(g), formatMemberName(g.FindMember(e.OperatorUin)), formatMemberName(g.FindMember(e.AuthorUin)), gid) formatGroupName(g), formatMemberName(g.FindMember(e.OperatorUin)), formatMemberName(g.FindMember(e.AuthorUin)), gid)
bot.dispatchEventMessage(MSG{ bot.dispatchEventMessage(MSG{
@ -258,7 +258,7 @@ func (bot *CQBot) friendNotifyEvent(c *client.QQClient, e client.INotifyEvent) {
func (bot *CQBot) friendRecallEvent(c *client.QQClient, e *client.FriendMessageRecalledEvent) { func (bot *CQBot) friendRecallEvent(c *client.QQClient, e *client.FriendMessageRecalledEvent) {
f := c.FindFriend(e.FriendUin) f := c.FindFriend(e.FriendUin)
gid := ToGlobalId(e.FriendUin, e.MessageId) gid := toGlobalID(e.FriendUin, e.MessageId)
if f != nil { if f != nil {
log.Infof("好友 %v(%v) 撤回了消息: %v", f.Nickname, f.Uin, gid) log.Infof("好友 %v(%v) 撤回了消息: %v", f.Nickname, f.Uin, gid)
} else { } else {

View File

@ -1,6 +1,7 @@
// +build linux windows darwin // +build linux windows darwin
// +build 386 amd64 arm arm64 // +build 386 amd64 arm arm64
//Package codec Slik编码核心模块
package codec package codec
import ( import (

2
global/doc.go Normal file
View File

@ -0,0 +1,2 @@
//Package global 包含文件下载,视频音频编码,本地文件缓存处理,消息过滤器,调用速率限制,gocq主配置等的相关函数与结构体
package global

View File

@ -30,12 +30,16 @@ import (
var json = jsoniter.ConfigCompatibleWithStandardLibrary var json = jsoniter.ConfigCompatibleWithStandardLibrary
//WebInput 网页输入channel
var WebInput = make(chan string, 1) //长度1用于阻塞 var WebInput = make(chan string, 1) //长度1用于阻塞
//Console 控制台channel
var Console = make(chan os.Signal, 1) var Console = make(chan os.Signal, 1)
//Restart 重启信号监听channel
var Restart = make(chan struct{}, 1) var Restart = make(chan struct{}, 1)
//JSONConfig go-cqhttp配置
var JSONConfig *global.JSONConfig var JSONConfig *global.JSONConfig
type webServer struct { type webServer struct {
@ -46,23 +50,25 @@ type webServer struct {
Console *bufio.Reader Console *bufio.Reader
} }
//WebServer Admin子站的Server
var WebServer = &webServer{} var WebServer = &webServer{}
// admin 子站的 路由映射 //APIAdminRoutingTable Admin子站的路由映射
var HttpuriAdmin = map[string]func(s *webServer, c *gin.Context){ var APIAdminRoutingTable = map[string]func(s *webServer, c *gin.Context){
"do_restart": AdminDoRestart, //热重启 "do_restart": AdminDoRestart, //热重启
"do_process_restart": AdminProcessRestart, //进程重启 "do_process_restart": AdminProcessRestart, //进程重启
"get_web_write": AdminWebWrite, //获取是否验证码输入 "get_web_write": AdminWebWrite, //获取是否验证码输入
"do_web_write": AdminDoWebWrite, //web上进行输入操作 "do_web_write": AdminDoWebWrite, //web上进行输入操作
"do_restart_docker": AdminDoRestartDocker, //直接停止依赖supervisord/docker重新拉起 "do_restart_docker": AdminDoRestartDocker, //直接停止依赖supervisord/docker重新拉起
"do_config_base": AdminDoConfigBase, //修改config.json中的基础部分 "do_config_base": AdminDoConfigBase, //修改config.json中的基础部分
"do_config_http": AdminDoConfigHttp, //修改config.json的http部分 "do_config_http": AdminDoConfigHTTP, //修改config.json的http部分
"do_config_ws": AdminDoConfigWs, //修改config.json的正向ws部分 "do_config_ws": AdminDoConfigWS, //修改config.json的正向ws部分
"do_config_reverse": AdminDoConfigReverse, //修改config.json 中的反向ws部分 "do_config_reverse": AdminDoConfigReverseWS, //修改config.json 中的反向ws部分
"do_config_json": AdminDoConfigJson, //直接修改 config.json配置 "do_config_json": AdminDoConfigJSON, //直接修改 config.json配置
"get_config_json": AdminGetConfigJson, //拉取 当前的config.json配置 "get_config_json": AdminGetConfigJSON, //拉取 当前的config.json配置
} }
//Failed 构建失败返回MSG
func Failed(code int, msg string) coolq.MSG { func Failed(code int, msg string) coolq.MSG {
return coolq.MSG{"data": nil, "retcode": code, "status": "failed", "msg": msg} return coolq.MSG{"data": nil, "retcode": code, "status": "failed", "msg": msg}
} }
@ -266,7 +272,7 @@ func (s *webServer) Dologin() {
global.BootFilter() global.BootFilter()
global.InitCodec() global.InitCodec()
coolq.IgnoreInvalidCQCode = conf.IgnoreInvalidCQCode coolq.IgnoreInvalidCQCode = conf.IgnoreInvalidCQCode
coolq.SplitUrl = conf.FixURL coolq.SplitURL = conf.FixURL
coolq.ForceFragmented = conf.ForceFragmented coolq.ForceFragmented = conf.ForceFragmented
log.Info("资源初始化完成, 开始处理信息.") log.Info("资源初始化完成, 开始处理信息.")
log.Info("アトリは、高性能ですから!") log.Info("アトリは、高性能ですから!")
@ -321,14 +327,14 @@ func (s *webServer) Dologin() {
func (s *webServer) admin(c *gin.Context) { func (s *webServer) admin(c *gin.Context) {
action := c.Param("action") action := c.Param("action")
log.Debugf("WebServer接收到cgi调用: %v", action) log.Debugf("WebServer接收到cgi调用: %v", action)
if f, ok := HttpuriAdmin[action]; ok { if f, ok := APIAdminRoutingTable[action]; ok {
f(s, c) f(s, c)
} else { } else {
c.JSON(200, coolq.Failed(404)) c.JSON(200, coolq.Failed(404))
} }
} }
// 获取当前配置文件信息 //GetConf 获取当前配置文件信息
func GetConf() *global.JSONConfig { func GetConf() *global.JSONConfig {
if JSONConfig != nil { if JSONConfig != nil {
return JSONConfig return JSONConfig
@ -337,7 +343,7 @@ func GetConf() *global.JSONConfig {
return conf return conf
} }
// admin 控制器 登录验证 //AuthMiddleWare Admin控制器登录验证
func AuthMiddleWare() gin.HandlerFunc { func AuthMiddleWare() gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
conf := GetConf() conf := GetConf()
@ -431,7 +437,7 @@ func (s *webServer) DoReLogin() { // TODO: 协议层的 ReLogin
s.Dologin() s.Dologin()
//关闭之前的 server //关闭之前的 server
if OldConf.HTTPConfig != nil && OldConf.HTTPConfig.Enabled { if OldConf.HTTPConfig != nil && OldConf.HTTPConfig.Enabled {
HttpServer.ShutDown() cqHTTPServer.ShutDown()
} }
//if OldConf.WSConfig != nil && OldConf.WSConfig.Enabled { //if OldConf.WSConfig != nil && OldConf.WSConfig.Enabled {
// server.WsShutdown() // server.WsShutdown()
@ -444,9 +450,9 @@ func (s *webServer) DoReLogin() { // TODO: 协议层的 ReLogin
func (s *webServer) UpServer() { func (s *webServer) UpServer() {
conf := GetConf() conf := GetConf()
if conf.HTTPConfig != nil && conf.HTTPConfig.Enabled { if conf.HTTPConfig != nil && conf.HTTPConfig.Enabled {
go HttpServer.Run(fmt.Sprintf("%s:%d", conf.HTTPConfig.Host, conf.HTTPConfig.Port), conf.AccessToken, s.bot) go cqHTTPServer.Run(fmt.Sprintf("%s:%d", conf.HTTPConfig.Host, conf.HTTPConfig.Port), conf.AccessToken, s.bot)
for k, v := range conf.HTTPConfig.PostUrls { for k, v := range conf.HTTPConfig.PostUrls {
NewHttpClient().Run(k, v, conf.HTTPConfig.Timeout, s.bot) newHTTPClient().Run(k, v, conf.HTTPConfig.Timeout, s.bot)
} }
} }
if conf.WSConfig != nil && conf.WSConfig.Enabled { if conf.WSConfig != nil && conf.WSConfig.Enabled {
@ -461,9 +467,9 @@ func (s *webServer) UpServer() {
func (s *webServer) ReloadServer() { func (s *webServer) ReloadServer() {
conf := GetConf() conf := GetConf()
if conf.HTTPConfig != nil && conf.HTTPConfig.Enabled { if conf.HTTPConfig != nil && conf.HTTPConfig.Enabled {
go HttpServer.Run(fmt.Sprintf("%s:%d", conf.HTTPConfig.Host, conf.HTTPConfig.Port), conf.AccessToken, s.bot) go cqHTTPServer.Run(fmt.Sprintf("%s:%d", conf.HTTPConfig.Host, conf.HTTPConfig.Port), conf.AccessToken, s.bot)
for k, v := range conf.HTTPConfig.PostUrls { for k, v := range conf.HTTPConfig.PostUrls {
NewHttpClient().Run(k, v, conf.HTTPConfig.Timeout, s.bot) newHTTPClient().Run(k, v, conf.HTTPConfig.Timeout, s.bot)
} }
} }
for _, rc := range conf.ReverseServers { for _, rc := range conf.ReverseServers {
@ -471,7 +477,7 @@ func (s *webServer) ReloadServer() {
} }
} }
// 热重启 //AdminDoRestart 热重启
func AdminDoRestart(s *webServer, c *gin.Context) { func AdminDoRestart(s *webServer, c *gin.Context) {
s.bot.Release() s.bot.Release()
s.bot = nil s.bot = nil
@ -480,19 +486,19 @@ func AdminDoRestart(s *webServer, c *gin.Context) {
c.JSON(200, coolq.OK(coolq.MSG{})) c.JSON(200, coolq.OK(coolq.MSG{}))
} }
// 进程重启 //AdminProcessRestart 进程重启
func AdminProcessRestart(s *webServer, c *gin.Context) { func AdminProcessRestart(s *webServer, c *gin.Context) {
Restart <- struct{}{} Restart <- struct{}{}
c.JSON(200, coolq.OK(coolq.MSG{})) c.JSON(200, coolq.OK(coolq.MSG{}))
} }
// 冷重启 //AdminDoRestartDocker 冷重启
func AdminDoRestartDocker(s *webServer, c *gin.Context) { func AdminDoRestartDocker(s *webServer, c *gin.Context) {
Console <- os.Kill Console <- os.Kill
c.JSON(200, coolq.OK(coolq.MSG{})) c.JSON(200, coolq.OK(coolq.MSG{}))
} }
// web输入 html 页面 //AdminWebWrite web输入html页面
func AdminWebWrite(s *webServer, c *gin.Context) { func AdminWebWrite(s *webServer, c *gin.Context) {
pic := global.ReadAllText("captcha.jpg") pic := global.ReadAllText("captcha.jpg")
var picbase64 string var picbase64 string
@ -509,14 +515,14 @@ func AdminWebWrite(s *webServer, c *gin.Context) {
})) }))
} }
// web输入 处理 //AdminDoWebWrite web输入处理
func AdminDoWebWrite(s *webServer, c *gin.Context) { func AdminDoWebWrite(s *webServer, c *gin.Context) {
input := c.PostForm("input") input := c.PostForm("input")
WebInput <- input WebInput <- input
c.JSON(200, coolq.OK(coolq.MSG{})) c.JSON(200, coolq.OK(coolq.MSG{}))
} }
// 普通配置修改 //AdminDoConfigBase 普通配置修改
func AdminDoConfigBase(s *webServer, c *gin.Context) { func AdminDoConfigBase(s *webServer, c *gin.Context) {
conf := GetConf() conf := GetConf()
conf.Uin, _ = strconv.ParseInt(c.PostForm("uin"), 10, 64) conf.Uin, _ = strconv.ParseInt(c.PostForm("uin"), 10, 64)
@ -536,8 +542,8 @@ func AdminDoConfigBase(s *webServer, c *gin.Context) {
} }
} }
// http配置修改 //AdminDoConfigHTTP HTTP配置修改
func AdminDoConfigHttp(s *webServer, c *gin.Context) { func AdminDoConfigHTTP(s *webServer, c *gin.Context) {
conf := GetConf() conf := GetConf()
p, _ := strconv.ParseUint(c.PostForm("port"), 10, 16) p, _ := strconv.ParseUint(c.PostForm("port"), 10, 16)
conf.HTTPConfig.Port = uint16(p) conf.HTTPConfig.Port = uint16(p)
@ -561,8 +567,8 @@ func AdminDoConfigHttp(s *webServer, c *gin.Context) {
} }
} }
// ws配置修改 //AdminDoConfigWS ws配置修改
func AdminDoConfigWs(s *webServer, c *gin.Context) { func AdminDoConfigWS(s *webServer, c *gin.Context) {
conf := GetConf() conf := GetConf()
p, _ := strconv.ParseUint(c.PostForm("port"), 10, 16) p, _ := strconv.ParseUint(c.PostForm("port"), 10, 16)
conf.WSConfig.Port = uint16(p) conf.WSConfig.Port = uint16(p)
@ -581,8 +587,8 @@ func AdminDoConfigWs(s *webServer, c *gin.Context) {
} }
} }
// 反向ws配置修改 //AdminDoConfigReverseWS 反向ws配置修改
func AdminDoConfigReverse(s *webServer, c *gin.Context) { func AdminDoConfigReverseWS(s *webServer, c *gin.Context) {
conf := GetConf() conf := GetConf()
conf.ReverseServers[0].ReverseAPIURL = c.PostForm("reverse_api_url") conf.ReverseServers[0].ReverseAPIURL = c.PostForm("reverse_api_url")
conf.ReverseServers[0].ReverseURL = c.PostForm("reverse_url") conf.ReverseServers[0].ReverseURL = c.PostForm("reverse_url")
@ -603,11 +609,11 @@ func AdminDoConfigReverse(s *webServer, c *gin.Context) {
} }
} }
// config.json配置修改 //AdminDoConfigJSON config.hjson配置修改
func AdminDoConfigJson(s *webServer, c *gin.Context) { func AdminDoConfigJSON(s *webServer, c *gin.Context) {
conf := GetConf() conf := GetConf()
Json := c.PostForm("json") JSON := c.PostForm("json")
err := json.Unmarshal([]byte(Json), &conf) err := json.Unmarshal([]byte(JSON), &conf)
if err != nil { if err != nil {
log.Warnf("尝试加载配置文件 %v 时出现错误: %v", "config.hjson", err) log.Warnf("尝试加载配置文件 %v 时出现错误: %v", "config.hjson", err)
c.JSON(200, Failed(502, "保存 config.hjson 时出现错误:"+fmt.Sprintf("%v", err))) c.JSON(200, Failed(502, "保存 config.hjson 时出现错误:"+fmt.Sprintf("%v", err)))
@ -622,8 +628,8 @@ func AdminDoConfigJson(s *webServer, c *gin.Context) {
} }
} }
// 拉取config.json配置 //AdminGetConfigJSON 拉取config.hjson配置
func AdminGetConfigJson(s *webServer, c *gin.Context) { func AdminGetConfigJSON(s *webServer, c *gin.Context) {
conf := GetConf() conf := GetConf()
c.JSON(200, coolq.OK(coolq.MSG{"config": conf})) c.JSON(200, coolq.OK(coolq.MSG{"config": conf}))

2
server/doc.go Normal file
View File

@ -0,0 +1,2 @@
//Package server 包含Admin子站,HTTP,WebSocket,反向WebSocket请求处理的相关函数与结构体
package server

View File

@ -24,7 +24,7 @@ import (
type httpServer struct { type httpServer struct {
engine *gin.Engine engine *gin.Engine
bot *coolq.CQBot bot *coolq.CQBot
Http *http.Server HTTP *http.Server
} }
type httpClient struct { type httpClient struct {
@ -34,7 +34,9 @@ type httpClient struct {
timeout int32 timeout int32
} }
var HttpServer = &httpServer{} var cqHTTPServer = &httpServer{}
//Debug 是否启用Debug模式
var Debug = false var Debug = false
func (s *httpServer) Run(addr, authToken string, bot *coolq.CQBot) { func (s *httpServer) Run(addr, authToken string, bot *coolq.CQBot) {
@ -84,11 +86,11 @@ func (s *httpServer) Run(addr, authToken string, bot *coolq.CQBot) {
go func() { go func() {
log.Infof("CQ HTTP 服务器已启动: %v", addr) log.Infof("CQ HTTP 服务器已启动: %v", addr)
s.Http = &http.Server{ s.HTTP = &http.Server{
Addr: addr, Addr: addr,
Handler: s.engine, Handler: s.engine,
} }
if err := s.Http.ListenAndServe(); err != nil && err != http.ErrServerClosed { if err := s.HTTP.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Error(err) log.Error(err)
log.Infof("HTTP 服务启动失败, 请检查端口是否被占用.") log.Infof("HTTP 服务启动失败, 请检查端口是否被占用.")
log.Warnf("将在五秒后退出.") log.Warnf("将在五秒后退出.")
@ -98,7 +100,7 @@ func (s *httpServer) Run(addr, authToken string, bot *coolq.CQBot) {
}() }()
} }
func NewHttpClient() *httpClient { func newHTTPClient() *httpClient {
return &httpClient{} return &httpClient{}
} }
@ -123,7 +125,7 @@ func (c *httpClient) onBotPushEvent(m coolq.MSG) {
} }
if c.secret != "" { if c.secret != "" {
mac := hmac.New(sha1.New, []byte(c.secret)) mac := hmac.New(sha1.New, []byte(c.secret))
_, err := mac.Write([]byte(m.ToJson())) _, err := mac.Write([]byte(m.ToJSON()))
if err != nil { if err != nil {
log.Error(err) log.Error(err)
return nil return nil
@ -141,12 +143,12 @@ func (c *httpClient) onBotPushEvent(m coolq.MSG) {
return nil return nil
}).Do() }).Do()
if err != nil { if err != nil {
log.Warnf("上报Event数据 %v 到 %v 失败: %v", m.ToJson(), c.addr, err) log.Warnf("上报Event数据 %v 到 %v 失败: %v", m.ToJSON(), c.addr, err)
return return
} }
log.Debugf("上报Event数据 %v 到 %v", m.ToJson(), c.addr) log.Debugf("上报Event数据 %v 到 %v", m.ToJSON(), c.addr)
if gjson.Valid(res) { if gjson.Valid(res) {
c.bot.CQHandleQuickOperation(gjson.Parse(m.ToJson()), gjson.Parse(res)) c.bot.CQHandleQuickOperation(gjson.Parse(m.ToJSON()), gjson.Parse(res))
} }
} }
@ -154,7 +156,7 @@ func (s *httpServer) HandleActions(c *gin.Context) {
global.RateLimit(context.Background()) global.RateLimit(context.Background())
action := strings.ReplaceAll(c.Param("action"), "_async", "") action := strings.ReplaceAll(c.Param("action"), "_async", "")
log.Debugf("HTTPServer接收到API调用: %v", action) log.Debugf("HTTPServer接收到API调用: %v", action)
if f, ok := httpApi[action]; ok { if f, ok := httpAPI[action]; ok {
f(s, c) f(s, c)
} else { } else {
c.JSON(200, coolq.Failed(404)) c.JSON(200, coolq.Failed(404))
@ -202,13 +204,13 @@ func GetGroupRootFiles(s *httpServer, c *gin.Context) {
c.JSON(200, s.bot.CQGetGroupRootFiles(gid)) c.JSON(200, s.bot.CQGetGroupRootFiles(gid))
} }
func GetGroupFilesByFolderId(s *httpServer, c *gin.Context) { func GetGroupFilesByFolderID(s *httpServer, c *gin.Context) {
gid, _ := strconv.ParseInt(getParam(c, "group_id"), 10, 64) gid, _ := strconv.ParseInt(getParam(c, "group_id"), 10, 64)
folderId := getParam(c, "folder_id") folderID := getParam(c, "folder_id")
c.JSON(200, s.bot.CQGetGroupFilesByFolderID(gid, folderId)) c.JSON(200, s.bot.CQGetGroupFilesByFolderID(gid, folderID))
} }
func GetGroupFileUrl(s *httpServer, c *gin.Context) { func GetGroupFileURL(s *httpServer, c *gin.Context) {
gid, _ := strconv.ParseInt(getParam(c, "group_id"), 10, 64) gid, _ := strconv.ParseInt(getParam(c, "group_id"), 10, 64)
fid := getParam(c, "file_id") fid := getParam(c, "file_id")
busid, _ := strconv.ParseInt(getParam(c, "busid"), 10, 32) busid, _ := strconv.ParseInt(getParam(c, "busid"), 10, 32)
@ -356,11 +358,11 @@ func SetRestart(s *httpServer, c *gin.Context) {
} }
func GetForwardMessage(s *httpServer, c *gin.Context) { func GetForwardMessage(s *httpServer, c *gin.Context) {
resId := getParam(c, "message_id") resID := getParam(c, "message_id")
if resId == "" { if resID == "" {
resId = getParam(c, "id") resID = getParam(c, "id")
} }
c.JSON(200, s.bot.CQGetForwardMessage(resId)) c.JSON(200, s.bot.CQGetForwardMessage(resID))
} }
func GetGroupSystemMessage(s *httpServer, c *gin.Context) { func GetGroupSystemMessage(s *httpServer, c *gin.Context) {
@ -534,7 +536,7 @@ func getParamWithType(c *gin.Context, k string) (string, gjson.Type) {
return "", gjson.Null return "", gjson.Null
} }
var httpApi = map[string]func(s *httpServer, c *gin.Context){ var httpAPI = map[string]func(s *httpServer, c *gin.Context){
"get_login_info": GetLoginInfo, "get_login_info": GetLoginInfo,
"get_friend_list": GetFriendList, "get_friend_list": GetFriendList,
"get_group_list": GetGroupList, "get_group_list": GetGroupList,
@ -543,8 +545,8 @@ var httpApi = map[string]func(s *httpServer, c *gin.Context){
"get_group_member_info": GetGroupMemberInfo, "get_group_member_info": GetGroupMemberInfo,
"get_group_file_system_info": GetGroupFileSystemInfo, "get_group_file_system_info": GetGroupFileSystemInfo,
"get_group_root_files": GetGroupRootFiles, "get_group_root_files": GetGroupRootFiles,
"get_group_files_by_folder": GetGroupFilesByFolderId, "get_group_files_by_folder": GetGroupFilesByFolderID,
"get_group_file_url": GetGroupFileUrl, "get_group_file_url": GetGroupFileURL,
"send_msg": SendMessage, "send_msg": SendMessage,
"send_group_msg": SendGroupMessage, "send_group_msg": SendGroupMessage,
"send_group_forward_msg": SendGroupForwardMessage, "send_group_forward_msg": SendGroupForwardMessage,
@ -589,7 +591,7 @@ var httpApi = map[string]func(s *httpServer, c *gin.Context){
func (s *httpServer) ShutDown() { func (s *httpServer) ShutDown() {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel() defer cancel()
if err := s.Http.Shutdown(ctx); err != nil { if err := s.HTTP.Shutdown(ctx); err != nil {
log.Fatal("http Server Shutdown:", err) log.Fatal("http Server Shutdown:", err)
} }
<-ctx.Done() <-ctx.Done()

View File

@ -25,7 +25,7 @@ type webSocketServer struct {
handshake string handshake string
} }
//WebSocketClient Websocket客户端实例 //WebSocketClient WebSocket客户端实例
type WebSocketClient struct { type WebSocketClient struct {
conf *global.GoCQReverseWebSocketConfig conf *global.GoCQReverseWebSocketConfig
token string token string
@ -58,7 +58,7 @@ func (s *webSocketServer) Run(addr, authToken string, b *coolq.CQBot) {
http.HandleFunc("/api", s.api) http.HandleFunc("/api", s.api)
http.HandleFunc("/", s.any) http.HandleFunc("/", s.any)
go func() { go func() {
log.Infof("CQ Websocket 服务器已启动: %v", addr) log.Infof("CQ WebSocket 服务器已启动: %v", addr)
log.Fatal(http.ListenAndServe(addr, nil)) log.Fatal(http.ListenAndServe(addr, nil))
}() }()
} }
@ -87,7 +87,7 @@ func (c *WebSocketClient) Run() {
} }
func (c *WebSocketClient) connectAPI() { func (c *WebSocketClient) connectAPI() {
log.Infof("开始尝试连接到反向Websocket API服务器: %v", c.conf.ReverseAPIURL) log.Infof("开始尝试连接到反向WebSocket API服务器: %v", c.conf.ReverseAPIURL)
header := http.Header{ header := http.Header{
"X-Client-Role": []string{"API"}, "X-Client-Role": []string{"API"},
"X-Self-ID": []string{strconv.FormatInt(c.bot.Client.Uin, 10)}, "X-Self-ID": []string{strconv.FormatInt(c.bot.Client.Uin, 10)},
@ -98,20 +98,20 @@ func (c *WebSocketClient) connectAPI() {
} }
conn, _, err := websocket.DefaultDialer.Dial(c.conf.ReverseAPIURL, header) conn, _, err := websocket.DefaultDialer.Dial(c.conf.ReverseAPIURL, header)
if err != nil { if err != nil {
log.Warnf("连接到反向Websocket API服务器 %v 时出现错误: %v", c.conf.ReverseAPIURL, err) log.Warnf("连接到反向WebSocket API服务器 %v 时出现错误: %v", c.conf.ReverseAPIURL, err)
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))
c.connectAPI() c.connectAPI()
} }
return return
} }
log.Infof("已连接到反向Websocket API服务器 %v", c.conf.ReverseAPIURL) log.Infof("已连接到反向WebSocket API服务器 %v", c.conf.ReverseAPIURL)
wrappedConn := &webSocketConn{Conn: conn} wrappedConn := &webSocketConn{Conn: conn}
go c.listenAPI(wrappedConn, false) go c.listenAPI(wrappedConn, false)
} }
func (c *WebSocketClient) connectEvent() { func (c *WebSocketClient) connectEvent() {
log.Infof("开始尝试连接到反向Websocket Event服务器: %v", c.conf.ReverseEventURL) log.Infof("开始尝试连接到反向WebSocket Event服务器: %v", c.conf.ReverseEventURL)
header := http.Header{ header := http.Header{
"X-Client-Role": []string{"Event"}, "X-Client-Role": []string{"Event"},
"X-Self-ID": []string{strconv.FormatInt(c.bot.Client.Uin, 10)}, "X-Self-ID": []string{strconv.FormatInt(c.bot.Client.Uin, 10)},
@ -122,7 +122,7 @@ func (c *WebSocketClient) connectEvent() {
} }
conn, _, err := websocket.DefaultDialer.Dial(c.conf.ReverseEventURL, header) conn, _, err := websocket.DefaultDialer.Dial(c.conf.ReverseEventURL, header)
if err != nil { if err != nil {
log.Warnf("连接到反向Websocket Event服务器 %v 时出现错误: %v", c.conf.ReverseEventURL, err) log.Warnf("连接到反向WebSocket Event服务器 %v 时出现错误: %v", c.conf.ReverseEventURL, err)
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))
c.connectEvent() c.connectEvent()
@ -134,15 +134,15 @@ func (c *WebSocketClient) connectEvent() {
c.bot.Client.Uin, time.Now().Unix()) c.bot.Client.Uin, time.Now().Unix())
err = conn.WriteMessage(websocket.TextMessage, []byte(handshake)) err = conn.WriteMessage(websocket.TextMessage, []byte(handshake))
if err != nil { if err != nil {
log.Warnf("反向Websocket 握手时出现错误: %v", err) log.Warnf("反向WebSocket 握手时出现错误: %v", err)
} }
log.Infof("已连接到反向Websocket Event服务器 %v", c.conf.ReverseEventURL) log.Infof("已连接到反向WebSocket Event服务器 %v", c.conf.ReverseEventURL)
c.eventConn = &webSocketConn{Conn: conn} c.eventConn = &webSocketConn{Conn: conn}
} }
func (c *WebSocketClient) connectUniversal() { func (c *WebSocketClient) connectUniversal() {
log.Infof("开始尝试连接到反向Websocket Universal服务器: %v", c.conf.ReverseURL) log.Infof("开始尝试连接到反向WebSocket Universal服务器: %v", c.conf.ReverseURL)
header := http.Header{ header := http.Header{
"X-Client-Role": []string{"Universal"}, "X-Client-Role": []string{"Universal"},
"X-Self-ID": []string{strconv.FormatInt(c.bot.Client.Uin, 10)}, "X-Self-ID": []string{strconv.FormatInt(c.bot.Client.Uin, 10)},
@ -153,7 +153,7 @@ func (c *WebSocketClient) connectUniversal() {
} }
conn, _, err := websocket.DefaultDialer.Dial(c.conf.ReverseURL, header) conn, _, err := websocket.DefaultDialer.Dial(c.conf.ReverseURL, header)
if err != nil { if err != nil {
log.Warnf("连接到反向Websocket Universal服务器 %v 时出现错误: %v", c.conf.ReverseURL, err) log.Warnf("连接到反向WebSocket Universal服务器 %v 时出现错误: %v", c.conf.ReverseURL, err)
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))
c.connectUniversal() c.connectUniversal()
@ -165,7 +165,7 @@ func (c *WebSocketClient) connectUniversal() {
c.bot.Client.Uin, time.Now().Unix()) c.bot.Client.Uin, time.Now().Unix())
err = conn.WriteMessage(websocket.TextMessage, []byte(handshake)) err = conn.WriteMessage(websocket.TextMessage, []byte(handshake))
if err != nil { if err != nil {
log.Warnf("反向Websocket 握手时出现错误: %v", err) log.Warnf("反向WebSocket 握手时出现错误: %v", err)
} }
wrappedConn := &webSocketConn{Conn: conn} wrappedConn := &webSocketConn{Conn: conn}
@ -195,7 +195,7 @@ func (c *WebSocketClient) listenAPI(conn *webSocketConn, u bool) {
func (c *WebSocketClient) onBotPushEvent(m coolq.MSG) { func (c *WebSocketClient) onBotPushEvent(m coolq.MSG) {
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())
conn := c.eventConn conn := c.eventConn
conn.Lock() conn.Lock()
defer conn.Unlock() defer conn.Unlock()
@ -210,7 +210,7 @@ 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())
conn := c.universalConn conn := c.universalConn
conn.Lock() conn.Lock()
defer conn.Unlock() defer conn.Unlock()
@ -230,7 +230,7 @@ func (s *webSocketServer) event(w http.ResponseWriter, r *http.Request) {
if s.token != "" { if s.token != "" {
if auth := r.URL.Query().Get("access_token"); auth != s.token { if auth := r.URL.Query().Get("access_token"); auth != s.token {
if auth := strings.SplitN(r.Header.Get("Authorization"), " ", 2); len(auth) != 2 || auth[1] != s.token { if auth := strings.SplitN(r.Header.Get("Authorization"), " ", 2); len(auth) != 2 || auth[1] != s.token {
log.Warnf("已拒绝 %v 的 Websocket 请求: Token鉴权失败", r.RemoteAddr) log.Warnf("已拒绝 %v 的 WebSocket 请求: Token鉴权失败", r.RemoteAddr)
w.WriteHeader(401) w.WriteHeader(401)
return return
} }
@ -238,17 +238,17 @@ func (s *webSocketServer) event(w http.ResponseWriter, r *http.Request) {
} }
c, err := upgrader.Upgrade(w, r, nil) c, err := upgrader.Upgrade(w, r, nil)
if err != nil { if err != nil {
log.Warnf("处理 Websocket 请求时出现错误: %v", err) log.Warnf("处理 WebSocket 请求时出现错误: %v", err)
return return
} }
err = c.WriteMessage(websocket.TextMessage, []byte(s.handshake)) err = c.WriteMessage(websocket.TextMessage, []byte(s.handshake))
if err != nil { if err != nil {
log.Warnf("Websocket 握手时出现错误: %v", err) log.Warnf("WebSocket 握手时出现错误: %v", err)
c.Close() c.Close()
return return
} }
log.Infof("接受 Websocket 连接: %v (/event)", r.RemoteAddr) log.Infof("接受 WebSocket 连接: %v (/event)", r.RemoteAddr)
conn := &webSocketConn{Conn: c} conn := &webSocketConn{Conn: c}
@ -261,7 +261,7 @@ func (s *webSocketServer) api(w http.ResponseWriter, r *http.Request) {
if s.token != "" { if s.token != "" {
if auth := r.URL.Query().Get("access_token"); auth != s.token { if auth := r.URL.Query().Get("access_token"); auth != s.token {
if auth := strings.SplitN(r.Header.Get("Authorization"), " ", 2); len(auth) != 2 || auth[1] != s.token { if auth := strings.SplitN(r.Header.Get("Authorization"), " ", 2); len(auth) != 2 || auth[1] != s.token {
log.Warnf("已拒绝 %v 的 Websocket 请求: Token鉴权失败", r.RemoteAddr) log.Warnf("已拒绝 %v 的 WebSocket 请求: Token鉴权失败", r.RemoteAddr)
w.WriteHeader(401) w.WriteHeader(401)
return return
} }
@ -269,10 +269,10 @@ func (s *webSocketServer) api(w http.ResponseWriter, r *http.Request) {
} }
c, err := upgrader.Upgrade(w, r, nil) c, err := upgrader.Upgrade(w, r, nil)
if err != nil { if err != nil {
log.Warnf("处理 Websocket 请求时出现错误: %v", err) log.Warnf("处理 WebSocket 请求时出现错误: %v", err)
return return
} }
log.Infof("接受 Websocket 连接: %v (/api)", r.RemoteAddr) log.Infof("接受 WebSocket 连接: %v (/api)", r.RemoteAddr)
conn := &webSocketConn{Conn: c} conn := &webSocketConn{Conn: c}
go s.listenAPI(conn) go s.listenAPI(conn)
} }
@ -281,7 +281,7 @@ func (s *webSocketServer) any(w http.ResponseWriter, r *http.Request) {
if s.token != "" { if s.token != "" {
if auth := r.URL.Query().Get("access_token"); auth != s.token { if auth := r.URL.Query().Get("access_token"); auth != s.token {
if auth := strings.SplitN(r.Header.Get("Authorization"), " ", 2); len(auth) != 2 || auth[1] != s.token { if auth := strings.SplitN(r.Header.Get("Authorization"), " ", 2); len(auth) != 2 || auth[1] != s.token {
log.Warnf("已拒绝 %v 的 Websocket 请求: Token鉴权失败", r.RemoteAddr) log.Warnf("已拒绝 %v 的 WebSocket 请求: Token鉴权失败", r.RemoteAddr)
w.WriteHeader(401) w.WriteHeader(401)
return return
} }
@ -289,16 +289,16 @@ func (s *webSocketServer) any(w http.ResponseWriter, r *http.Request) {
} }
c, err := upgrader.Upgrade(w, r, nil) c, err := upgrader.Upgrade(w, r, nil)
if err != nil { if err != nil {
log.Warnf("处理 Websocket 请求时出现错误: %v", err) log.Warnf("处理 WebSocket 请求时出现错误: %v", err)
return return
} }
err = c.WriteMessage(websocket.TextMessage, []byte(s.handshake)) err = c.WriteMessage(websocket.TextMessage, []byte(s.handshake))
if err != nil { if err != nil {
log.Warnf("Websocket 握手时出现错误: %v", err) log.Warnf("WebSocket 握手时出现错误: %v", err)
c.Close() c.Close()
return return
} }
log.Infof("接受 Websocket 连接: %v (/)", r.RemoteAddr) log.Infof("接受 WebSocket 连接: %v (/)", r.RemoteAddr)
conn := &webSocketConn{Conn: c} conn := &webSocketConn{Conn: c}
s.eventConn = append(s.eventConn, conn) s.eventConn = append(s.eventConn, conn)
s.listenAPI(conn) s.listenAPI(conn)
@ -353,9 +353,9 @@ func (s *webSocketServer) onBotPushEvent(m coolq.MSG) {
defer s.eventConnMutex.Unlock() defer s.eventConnMutex.Unlock()
for i, l := 0, len(s.eventConn); i < l; i++ { for i, l := 0, len(s.eventConn); i < l; i++ {
conn := s.eventConn[i] conn := s.eventConn[i]
log.Debugf("向WS客户端 %v 推送Event: %v", conn.RemoteAddr().String(), m.ToJson()) log.Debugf("向WS客户端 %v 推送Event: %v", conn.RemoteAddr().String(), m.ToJSON())
conn.Lock() conn.Lock()
if err := conn.WriteMessage(websocket.TextMessage, []byte(m.ToJson())); err != nil { if err := conn.WriteMessage(websocket.TextMessage, []byte(m.ToJSON())); err != nil {
_ = conn.Close() _ = conn.Close()
next := i + 1 next := i + 1
if next >= l { if next >= l {