diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 888004f..48c5184 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -26,5 +26,5 @@ jobs:
github_token: ${{ secrets.GITHUB_TOKEN }}
goos: ${{ matrix.goos }}
goarch: ${{ matrix.goarch }}
- ldflags: -w -s -X "github.com/Mrs4s/go-cqhttp/coolq.version=${{ env.RELEASE_VERSION }}"
+ ldflags: -w -s -X "github.com/Mrs4s/go-cqhttp/coolq.Version=${{ env.RELEASE_VERSION }}"
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 48b8bf9..31e3ac6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
vendor/
+.idea
diff --git a/coolq/api.go b/coolq/api.go
index ea4aefa..6be70e9 100644
--- a/coolq/api.go
+++ b/coolq/api.go
@@ -16,7 +16,7 @@ import (
"github.com/tidwall/gjson"
)
-var version = "unknown"
+var Version = "unknown"
// https://cqhttp.cc/docs/4.15/#/API?id=get_login_info-%E8%8E%B7%E5%8F%96%E7%99%BB%E5%BD%95%E5%8F%B7%E4%BF%A1%E6%81%AF
func (bot *CQBot) CQGetLoginInfo() MSG {
@@ -590,7 +590,7 @@ func (bot *CQBot) CQGetVersionInfo() MSG {
"plugin_build_configuration": "release",
"runtime_version": runtime.Version(),
"runtime_os": runtime.GOOS,
- "version": version,
+ "version": Version,
})
}
diff --git a/coolq/bot.go b/coolq/bot.go
index f0b2106..6d34bda 100644
--- a/coolq/bot.go
+++ b/coolq/bot.go
@@ -5,17 +5,19 @@ import (
"encoding/gob"
"encoding/json"
"fmt"
- "github.com/Mrs4s/MiraiGo/binary"
- "github.com/Mrs4s/MiraiGo/client"
- "github.com/Mrs4s/MiraiGo/message"
- "github.com/Mrs4s/go-cqhttp/global"
- log "github.com/sirupsen/logrus"
- "github.com/tidwall/gjson"
- "github.com/xujiajun/nutsdb"
"hash/crc32"
"path"
"sync"
"time"
+
+ "github.com/Mrs4s/MiraiGo/binary"
+ "github.com/Mrs4s/MiraiGo/client"
+ "github.com/Mrs4s/MiraiGo/message"
+ "github.com/Mrs4s/go-cqhttp/global"
+
+ log "github.com/sirupsen/logrus"
+ "github.com/tidwall/gjson"
+ "github.com/xujiajun/nutsdb"
)
type CQBot struct {
@@ -27,10 +29,13 @@ type CQBot struct {
invitedReqCache sync.Map
joinReqCache sync.Map
tempMsgCache sync.Map
+ oneWayMsgCache sync.Map
}
type MSG map[string]interface{}
+var ForceFragmented = false
+
func NewQQBot(cli *client.QQClient, conf *global.JsonConfig) *CQBot {
bot := &CQBot{
Client: cli,
@@ -65,15 +70,20 @@ func NewQQBot(cli *client.QQClient, conf *global.JsonConfig) *CQBot {
bot.Client.OnGroupInvited(bot.groupInvitedEvent)
bot.Client.OnUserWantJoinGroup(bot.groupJoinReqEvent)
go func() {
+ i := conf.HeartbeatInterval
+ if i < 1 {
+ log.Warn("警告: 心跳功能已关闭,若非预期,请检查配置文件。")
+ return
+ }
for {
- time.Sleep(time.Second * 5)
+ time.Sleep(time.Second * i)
bot.dispatchEventMessage(MSG{
"time": time.Now().Unix(),
"self_id": bot.Client.Uin,
"post_type": "meta_event",
"meta_event_type": "heartbeat",
"status": nil,
- "interval": 5000,
+ "interval": 1000 * i,
})
}
}()
@@ -128,7 +138,7 @@ func (bot *CQBot) SendGroupMessage(groupId int64, m *message.SendingMessage) int
newElem = append(newElem, elem)
}
m.Elements = newElem
- ret := bot.Client.SendGroupMessage(groupId, m)
+ ret := bot.Client.SendGroupMessage(groupId, m, ForceFragmented)
if ret == nil || ret.Id == -1 {
log.Warnf("群消息发送失败: 账号可能被风控.")
return -1
@@ -157,12 +167,15 @@ func (bot *CQBot) SendPrivateMessage(target int64, m *message.SendingMessage) in
if msg != nil {
id = msg.Id
}
- } else {
- if code, ok := bot.tempMsgCache.Load(target); ok {
- msg := bot.Client.SendTempMessage(code.(int64), target, m)
- if msg != nil {
- id = msg.Id
- }
+ } else if code, ok := bot.tempMsgCache.Load(target); ok {
+ msg := bot.Client.SendTempMessage(code.(int64), target, m)
+ if msg != nil {
+ id = msg.Id
+ }
+ } else if _, ok := bot.oneWayMsgCache.Load(target); ok {
+ msg := bot.Client.SendPrivateMessage(target, m)
+ if msg != nil {
+ id = msg.Id
}
}
if id == -1 {
diff --git a/coolq/cqcode.go b/coolq/cqcode.go
index 4d01fd4..40ce3c7 100644
--- a/coolq/cqcode.go
+++ b/coolq/cqcode.go
@@ -6,11 +6,6 @@ import (
"encoding/hex"
"errors"
"fmt"
- "github.com/Mrs4s/MiraiGo/binary"
- "github.com/Mrs4s/MiraiGo/message"
- "github.com/Mrs4s/go-cqhttp/global"
- log "github.com/sirupsen/logrus"
- "github.com/tidwall/gjson"
"io/ioutil"
"net/url"
"path"
@@ -18,12 +13,20 @@ import (
"runtime"
"strconv"
"strings"
+
+ "github.com/Mrs4s/MiraiGo/binary"
+ "github.com/Mrs4s/MiraiGo/message"
+ "github.com/Mrs4s/go-cqhttp/global"
+ log "github.com/sirupsen/logrus"
+ "github.com/tidwall/gjson"
)
var matchReg = regexp.MustCompile(`\[CQ:\w+?.*?]`)
var typeReg = regexp.MustCompile(`\[CQ:(\w+)`)
var paramReg = regexp.MustCompile(`,([\w\-.]+?)=([^,\]]+)`)
+var IgnoreInvalidCQCode = false
+
func ToArrayMessage(e []message.IMessageElement, code int64, raw ...bool) (r []MSG) {
ur := false
if len(raw) != 0 {
@@ -198,8 +201,12 @@ func (bot *CQBot) ConvertStringMessage(m string, group bool) (r []message.IMessa
}
elem, err := bot.ToElement(t, d, group)
if err != nil {
- log.Warnf("转换CQ码到MiraiGo Element时出现错误: %v 将原样发送.", err)
- r = append(r, message.NewText(code))
+ if !IgnoreInvalidCQCode {
+ log.Warnf("转换CQ码 %v 到MiraiGo Element时出现错误: %v 将原样发送.", code, err)
+ r = append(r, message.NewText(code))
+ } else {
+ log.Warnf("转换CQ码 %v 到MiraiGo Element时出现错误: %v 将忽略.", code, err)
+ }
continue
}
r = append(r, elem)
@@ -360,12 +367,18 @@ func (bot *CQBot) ToElement(t string, d map[string]string, group bool) (message.
if group {
rsp, err := bot.Client.QueryGroupImage(1, hash, size)
if err != nil {
+ if url != "" {
+ return bot.ToElement(t, map[string]string{"file": url}, group)
+ }
return nil, err
}
return rsp, nil
}
rsp, err := bot.Client.QueryFriendImage(1, hash, size)
if err != nil {
+ if url != "" {
+ return bot.ToElement(t, map[string]string{"file": url}, group)
+ }
return nil, err
}
return rsp, nil
@@ -445,7 +458,7 @@ func (bot *CQBot) ToElement(t string, d map[string]string, group bool) (message.
if len(aid) < 2 {
return nil, errors.New("song error")
}
- xml := fmt.Sprintf(`- %s%s
`,
+ xml := fmt.Sprintf(`- %s%s
`,
name, d["id"], aid[:len(aid)-2], aid, name, "", info.Get("track_info.singer.name").Str)
return &message.ServiceElement{
Id: 60,
@@ -453,6 +466,27 @@ func (bot *CQBot) ToElement(t string, d map[string]string, group bool) (message.
SubType: "music",
}, nil
}
+ if d["type"] == "163" {
+ info, err := global.NeteaseMusicSongInfo(d["id"])
+ if err != nil {
+ return nil, err
+ }
+ if !info.Exists() {
+ return nil, errors.New("song not found")
+ }
+ name := info.Get("name").Str
+ artistName := ""
+ if info.Get("artists.0").Exists() {
+ artistName = info.Get("artists.0.name").Str
+ }
+ xml := fmt.Sprintf(`- %s%s
`,
+ name, d["id"], info.Get("album.picUrl").Str, d["id"], name, artistName)
+ return &message.ServiceElement{
+ Id: 60,
+ Content: xml,
+ SubType: "music",
+ }, nil
+ }
if d["type"] == "custom" {
xml := fmt.Sprintf(`- %s%s
`,
d["title"], d["url"], d["image"], d["audio"], d["title"], d["content"])
@@ -463,6 +497,13 @@ func (bot *CQBot) ToElement(t string, d map[string]string, group bool) (message.
}, nil
}
return nil, errors.New("unsupported music type: " + d["type"])
+ case "xml":
+ resId := d["resid"]
+ template := CQCodeEscapeValue(d["data"])
+ //println(template)
+ i, _ := strconv.ParseInt(resId, 10, 64)
+ msg := global.NewXmlMsg(template, i)
+ return msg, nil
default:
return nil, errors.New("unsupported cq code: " + t)
}
diff --git a/coolq/event.go b/coolq/event.go
index 142e096..e91a0ed 100644
--- a/coolq/event.go
+++ b/coolq/event.go
@@ -32,6 +32,9 @@ func ToFormattedMessage(e []message.IMessageElement, code int64, raw ...bool) (r
func (bot *CQBot) privateMessageEvent(c *client.QQClient, m *message.PrivateMessage) {
bot.checkMedia(m.Elements)
cqm := ToStringMessage(m.Elements, 0, true)
+ if !m.Sender.IsFriend {
+ bot.oneWayMsgCache.Store(m.Sender.Uin, "")
+ }
log.Infof("收到好友 %v(%v) 的消息: %v", m.Sender.DisplayName(), m.Sender.Uin, cqm)
fm := MSG{
"post_type": "message",
diff --git a/docs/config.md b/docs/config.md
index 2ba5612..d3b999c 100644
--- a/docs/config.md
+++ b/docs/config.md
@@ -22,15 +22,21 @@ go-cqhttp 支持导入CQHTTP的配置文件, 具体步骤为:
"password_encrypted": "",
"enable_db": true,
"access_token": "",
- "relogin": false,
- "relogin_delay": 0,
+ "relogin": {
+ "enabled": true,
+ "relogin_delay": 3,
+ "max_relogin_times": 0
+ },
"post_message_format": "string",
+ "ignore_invalid_cqcode": false,
+ "force_fragmented": true,
+ "heartbeat_interval": 5,
"http_config": {
"enabled": true,
"host": "0.0.0.0",
"port": 5700,
- "timeout": 5,
- "post_urls": {"url:port": "secret"},
+ "timeout": 5,
+ "post_urls": {"url:port": "secret"}
},
"ws_config": {
"enabled": true,
@@ -51,18 +57,28 @@ go-cqhttp 支持导入CQHTTP的配置文件, 具体步骤为:
| 字段 | 类型 | 说明 |
| ------------------ | -------- | ------------------------------------------------------------------- |
-| uin | int64 | 登录用QQ号 |
-| password | string | 登录用密码 |
-| encrypt_password | bool | 是否对密码进行加密. |
-| password_encrypted | string | 加密后的密码(请勿修改) |
-| enable_db | bool | 是否开启内置数据库, 关闭后将无法使用 **回复/撤回** 等上下文相关接口 |
-| access_token | string | 同CQHTTP的 `access_token` 用于身份验证 |
-| relogin | bool | 是否自动重新登录 |
-| relogin_delay | int | 重登录延时(秒) |
-| http_config | object | HTTP API配置 |
-| ws_config | object | Websocket API 配置 |
-| ws_reverse_servers | object[] | 反向 Websocket API 配置 |
+| uin | int64 | 登录用QQ号 |
+| password | string | 登录用密码 |
+| encrypt_password | bool | 是否对密码进行加密. |
+| password_encrypted | string | 加密后的密码(请勿修改) |
+| enable_db | bool | 是否开启内置数据库, 关闭后将无法使用 **回复/撤回** 等上下文相关接口 |
+| access_token | string | 同CQHTTP的 `access_token` 用于身份验证 |
+| relogin | bool | 是否自动重新登录 |
+| relogin_delay | int | 重登录延时(秒) |
+| max_relogin_times | uint | 最大重登录次数,若0则不设置上限 |
+| post_message_format | string | 上报信息类型 |
+| ignore_invalid_cqcode| bool | 是否忽略错误的CQ码 |
+| force_fragmented | bool | 是否强制分片发送群长消息 |
+| heartbeat_interval | int64 | 心跳间隔时间,单位秒,若0则关闭心跳 |
+| http_config | object | HTTP API配置 |
+| ws_config | object | Websocket API 配置 |
+| ws_reverse_servers | object[] | 反向 Websocket API 配置 |
+| log_level | string | 指定日志收集级别,将收集的日志单独存放到固定文件中,便于查看日志线索 当前支持 warn,error|
> 注: 开启密码加密后程序将在每次启动时要求输入解密密钥, 密钥错误会导致登录时提示密码错误.
> 解密后密码将储存在内存中,用于自动重连等功能. 所以此加密并不能防止内存读取.
> 解密密钥在使用完成后并不会留存在内存中, 所以可用相对简单的字符串作为密钥
+
+> 注2: 分片发送为原酷Q发送长消息的老方案, 发送速度更优/兼容性更好。关闭后将优先使用新方案, 能发送更长的消息, 但发送速度更慢,在部分老客户端将无法解析.
+
+> 注3:关闭心跳服务可能引起断线,请谨慎关闭
diff --git a/docs/cqhttp.md b/docs/cqhttp.md
index 8cddcc7..a0f5c42 100644
--- a/docs/cqhttp.md
+++ b/docs/cqhttp.md
@@ -119,6 +119,51 @@ Type: `node`
]
````
+### xml支持
+
+Type: `xml`
+
+范围: **发送**
+
+参数:
+
+| 参数名 | 类型 | 说明 |
+| ------ | ------ | ------------------------------------------------------------ |
+| data | string | xml内容,xml中的value部分,记得实体化处理|
+| resid | int32 | 可以不填|
+
+示例: `[CQ:xml,data=xxxx]`
+
+####一些xml样例
+####ps:重要:xml中的value部分,记得html实体化处理后,再打加入到cq码中
+#### qq音乐
+```xml
+- 十年陈奕迅
+```
+#### 网易音乐
+```xml
+- 十年黄梦之
+```
+
+#### 卡片消息1
+```xml
+
+
+- 生死8秒!女司机高速急刹,他一个操作救下一车性命
+
+
+```
+
+#### 卡片消息2
+```xml
+
+
+-
+test title
+
+
+
+```
## API
diff --git a/global/config.go b/global/config.go
index e41f7c4..a69f973 100644
--- a/global/config.go
+++ b/global/config.go
@@ -2,23 +2,32 @@ package global
import (
"encoding/json"
+ "time"
+
log "github.com/sirupsen/logrus"
)
type JsonConfig struct {
- Uin int64 `json:"uin"`
- Password string `json:"password"`
- EncryptPassword bool `json:"encrypt_password"`
- PasswordEncrypted string `json:"password_encrypted"`
- EnableDB bool `json:"enable_db"`
- AccessToken string `json:"access_token"`
- ReLogin bool `json:"relogin"`
- ReLoginDelay int `json:"relogin_delay"`
- HttpConfig *GoCQHttpConfig `json:"http_config"`
- WSConfig *GoCQWebsocketConfig `json:"ws_config"`
- ReverseServers []*GoCQReverseWebsocketConfig `json:"ws_reverse_servers"`
- PostMessageFormat string `json:"post_message_format"`
- Debug bool `json:"debug"`
+ Uin int64 `json:"uin"`
+ Password string `json:"password"`
+ EncryptPassword bool `json:"encrypt_password"`
+ PasswordEncrypted string `json:"password_encrypted"`
+ EnableDB bool `json:"enable_db"`
+ AccessToken string `json:"access_token"`
+ ReLogin struct {
+ Enabled bool `json:"enabled"`
+ ReLoginDelay int `json:"relogin_delay"`
+ MaxReloginTimes uint `json:"max_relogin_times"`
+ } `json:"relogin"`
+ IgnoreInvalidCQCode bool `json:"ignore_invalid_cqcode"`
+ ForceFragmented bool `json:"force_fragmented"`
+ HeartbeatInterval time.Duration `json:"heartbeat_interval"`
+ HttpConfig *GoCQHttpConfig `json:"http_config"`
+ WSConfig *GoCQWebsocketConfig `json:"ws_config"`
+ ReverseServers []*GoCQReverseWebsocketConfig `json:"ws_reverse_servers"`
+ PostMessageFormat string `json:"post_message_format"`
+ Debug bool `json:"debug"`
+ LogLevel string `json:"log_level"`
}
type CQHttpApiConfig struct {
@@ -64,10 +73,18 @@ type GoCQReverseWebsocketConfig struct {
func DefaultConfig() *JsonConfig {
return &JsonConfig{
- EnableDB: true,
- ReLogin: true,
- ReLoginDelay: 3,
+ EnableDB: true,
+ ReLogin: struct {
+ Enabled bool `json:"enabled"`
+ ReLoginDelay int `json:"relogin_delay"`
+ MaxReloginTimes uint `json:"max_relogin_times"`
+ }{
+ Enabled: true,
+ ReLoginDelay: 3,
+ MaxReloginTimes: 0,
+ },
PostMessageFormat: "string",
+ ForceFragmented: true,
HttpConfig: &GoCQHttpConfig{
Enabled: true,
Host: "0.0.0.0",
diff --git a/global/net.go b/global/net.go
index 40aeab8..e394efd 100644
--- a/global/net.go
+++ b/global/net.go
@@ -3,10 +3,14 @@ package global
import (
"bytes"
"compress/gzip"
- "github.com/tidwall/gjson"
+ "fmt"
"io/ioutil"
"net/http"
+ "strconv"
"strings"
+
+ "github.com/Mrs4s/MiraiGo/message"
+ "github.com/tidwall/gjson"
)
func GetBytes(url string) ([]byte, error) {
@@ -41,3 +45,27 @@ func QQMusicSongInfo(id string) (gjson.Result, error) {
}
return gjson.ParseBytes(d).Get("songinfo.data"), nil
}
+
+func NeteaseMusicSongInfo(id string) (gjson.Result, error) {
+ d, err := GetBytes(fmt.Sprintf("http://music.163.com/api/song/detail/?id=%s&ids=%%5B%s%%5D", id, id))
+ if err != nil {
+ return gjson.Result{}, err
+ }
+ return gjson.ParseBytes(d).Get("songs.0"), nil
+}
+
+func NewXmlMsg(template string, ResId int64) *message.ServiceElement {
+ var serviceid string
+ if ResId == 0 {
+ serviceid = "2" //默认值2
+ } else {
+ serviceid = strconv.FormatInt(ResId, 10)
+ }
+ //println(serviceid)
+ return &message.ServiceElement{
+ Id: int32(ResId),
+ Content: template,
+ ResId: serviceid,
+ SubType: "xml",
+ }
+}
diff --git a/go.mod b/go.mod
index 839ecb5..d32cd0f 100644
--- a/go.mod
+++ b/go.mod
@@ -3,7 +3,7 @@ module github.com/Mrs4s/go-cqhttp
go 1.14
require (
- github.com/Mrs4s/MiraiGo v0.0.0-20200823184203-93de1f445681
+ github.com/Mrs4s/MiraiGo v0.0.0-20200827182935-51e155ef20da
github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 // indirect
github.com/gin-gonic/gin v1.6.3
github.com/gorilla/websocket v1.4.2
@@ -13,6 +13,7 @@ require (
github.com/lestrrat-go/file-rotatelogs v2.3.0+incompatible
github.com/lestrrat-go/strftime v1.0.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
+ github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5
github.com/sirupsen/logrus v1.6.0
github.com/t-tomalak/logrus-easy-formatter v0.0.0-20190827215021-c074f06c5816
github.com/tebeka/strftime v0.1.5 // indirect
diff --git a/go.sum b/go.sum
index d78d29d..3eeba5c 100644
--- a/go.sum
+++ b/go.sum
@@ -1,9 +1,7 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/Mrs4s/MiraiGo v0.0.0-20200823075559-507fe33e842d h1:F7ssNQDHqB7NZVwTeADRY+AxKT3eeSlBzfzeZYTUfxM=
-github.com/Mrs4s/MiraiGo v0.0.0-20200823075559-507fe33e842d/go.mod h1:0je03wji/tSw4bUH4QCF2Z4/EjyNWjSJTyy5tliX6EM=
-github.com/Mrs4s/MiraiGo v0.0.0-20200823184203-93de1f445681 h1:hnaJH7BGD+Sb2Xb59SLpRy+f8B3Rx29Qy53ZM0AbIsE=
-github.com/Mrs4s/MiraiGo v0.0.0-20200823184203-93de1f445681/go.mod h1:0je03wji/tSw4bUH4QCF2Z4/EjyNWjSJTyy5tliX6EM=
+github.com/Mrs4s/MiraiGo v0.0.0-20200827182935-51e155ef20da h1:T2Qz4w6sMrBxw+oiwbUa/c996jWYulCAtM+x1L0l3R8=
+github.com/Mrs4s/MiraiGo v0.0.0-20200827182935-51e155ef20da/go.mod h1:0je03wji/tSw4bUH4QCF2Z4/EjyNWjSJTyy5tliX6EM=
github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0=
github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@@ -78,6 +76,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 h1:mZHayPoR0lNmnHyvtYjDeq0zlVHn9K/ZXoy17ylucdo=
+github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5/go.mod h1:GEXHk5HgEKCvEIIrSpFI3ozzG5xOKA2DVlEX/gGnewM=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
diff --git a/main.go b/main.go
index 87b0cc8..f5eae47 100644
--- a/main.go
+++ b/main.go
@@ -7,15 +7,6 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
- "github.com/Mrs4s/MiraiGo/binary"
- "github.com/Mrs4s/MiraiGo/client"
- "github.com/Mrs4s/go-cqhttp/coolq"
- "github.com/Mrs4s/go-cqhttp/global"
- "github.com/Mrs4s/go-cqhttp/server"
- rotatelogs "github.com/lestrrat-go/file-rotatelogs"
- log "github.com/sirupsen/logrus"
- easy "github.com/t-tomalak/logrus-easy-formatter"
- asciiart "github.com/yinghau76/go-ascii-art"
"image"
"io"
"io/ioutil"
@@ -25,6 +16,18 @@ import (
"strconv"
"strings"
"time"
+
+ "github.com/Mrs4s/MiraiGo/binary"
+ "github.com/Mrs4s/MiraiGo/client"
+ "github.com/Mrs4s/go-cqhttp/coolq"
+ "github.com/Mrs4s/go-cqhttp/global"
+ "github.com/Mrs4s/go-cqhttp/server"
+
+ rotatelogs "github.com/lestrrat-go/file-rotatelogs"
+ "github.com/rifflock/lfshook"
+ log "github.com/sirupsen/logrus"
+ easy "github.com/t-tomalak/logrus-easy-formatter"
+ asciiart "github.com/yinghau76/go-ascii-art"
)
func init() {
@@ -133,6 +136,46 @@ func main() {
time.Sleep(time.Second * 5)
return
}
+
+ // log classified by level
+ // Collect all records up to the specified level (default level: warn)
+ logLevel := conf.LogLevel
+ if logLevel != "" {
+ date := time.Now().Format("2006-01-02")
+ var logPathMap lfshook.PathMap
+ switch conf.LogLevel {
+ case "warn":
+ logPathMap = lfshook.PathMap{
+ log.WarnLevel: path.Join("logs", date+"-warn.log"),
+ log.ErrorLevel: path.Join("logs", date+"-warn.log"),
+ log.FatalLevel: path.Join("logs", date+"-warn.log"),
+ log.PanicLevel: path.Join("logs", date+"-warn.log"),
+ }
+ case "error":
+ logPathMap = lfshook.PathMap{
+ log.ErrorLevel: path.Join("logs", date+"-error.log"),
+ log.FatalLevel: path.Join("logs", date+"-error.log"),
+ log.PanicLevel: path.Join("logs", date+"-error.log"),
+ }
+ default:
+ logPathMap = lfshook.PathMap{
+ log.WarnLevel: path.Join("logs", date+"-warn.log"),
+ log.ErrorLevel: path.Join("logs", date+"-warn.log"),
+ log.FatalLevel: path.Join("logs", date+"-warn.log"),
+ log.PanicLevel: path.Join("logs", date+"-warn.log"),
+ }
+ }
+
+ log.AddHook(lfshook.NewHook(
+ logPathMap,
+ &easy.Formatter{
+ TimestampFormat: "2006-01-02 15:04:05",
+ LogFormat: "[%time%] [%lvl%]: %msg% \n",
+ },
+ ))
+ }
+
+ log.Info("当前版本:", coolq.Version)
if conf.Debug {
log.SetLevel(log.DebugLevel)
log.Warnf("已开启Debug模式.")
@@ -171,6 +214,16 @@ func main() {
time.Sleep(time.Second * 5)
log.Info("开始尝试登录并同步消息...")
cli := client.NewClient(conf.Uin, conf.Password)
+ cli.OnLog(func(c *client.QQClient, e *client.LogEvent) {
+ switch e.Type {
+ case "INFO":
+ log.Info("Protocol -> " + e.Message)
+ case "ERROR":
+ log.Error("Protocol -> " + e.Message)
+ case "DEBUG":
+ log.Debug("Protocol -> " + e.Message)
+ }
+ })
rsp, err := cli.Login()
for {
global.Check(err)
@@ -210,6 +263,8 @@ func main() {
} else {
coolq.SetMessageFormat(conf.PostMessageFormat)
}
+ coolq.IgnoreInvalidCQCode = conf.IgnoreInvalidCQCode
+ coolq.ForceFragmented = conf.ForceFragmented
if conf.HttpConfig != nil && conf.HttpConfig.Enabled {
server.HttpServer.Run(fmt.Sprintf("%s:%d", conf.HttpConfig.Host, conf.HttpConfig.Port), conf.AccessToken, b)
for k, v := range conf.HttpConfig.PostUrls {
@@ -225,24 +280,39 @@ func main() {
log.Info("资源初始化完成, 开始处理信息.")
log.Info("アトリは、高性能ですから!")
cli.OnDisconnected(func(bot *client.QQClient, e *client.ClientDisconnectedEvent) {
- if conf.ReLogin {
- log.Warnf("Bot已离线 (%v),将在 %v 秒后尝试重连.", e.Message, conf.ReLoginDelay)
- time.Sleep(time.Second * time.Duration(conf.ReLoginDelay))
- rsp, err := cli.Login()
- if err != nil {
- log.Fatalf("重连失败: %v", err)
- }
- if !rsp.Success {
- switch rsp.Error {
- case client.NeedCaptcha:
- log.Fatalf("重连失败: 需要验证码. (验证码处理正在开发中)")
- case client.UnsafeDeviceError:
- log.Fatalf("重连失败: 设备锁")
- default:
- log.Fatalf("重连失败: %v", rsp.ErrorMessage)
+ if conf.ReLogin.Enabled {
+ var times uint = 1
+ for {
+
+ if conf.ReLogin.MaxReloginTimes == 0 {
+ } else if times > conf.ReLogin.MaxReloginTimes {
+ break
}
+ log.Warnf("Bot已离线 (%v),将在 %v 秒后尝试重连. 重连次数:%v",
+ e.Message, conf.ReLogin.ReLoginDelay, times)
+ times++
+ time.Sleep(time.Second * time.Duration(conf.ReLogin.ReLoginDelay))
+ rsp, err := cli.Login()
+ if err != nil {
+ log.Errorf("重连失败: %v", err)
+ continue
+ }
+ if !rsp.Success {
+ switch rsp.Error {
+ case client.NeedCaptcha:
+ log.Fatalf("重连失败: 需要验证码. (验证码处理正在开发中)")
+ case client.UnsafeDeviceError:
+ log.Fatalf("重连失败: 设备锁")
+ default:
+ log.Errorf("重连失败: %v", rsp.ErrorMessage)
+ continue
+ }
+ }
+ log.Info("重连成功")
+ return
+
}
- return
+ log.Fatal("重连失败: 重连次数达到设置的上限值")
}
b.Release()
log.Fatalf("Bot已离线:%v", e.Message)
diff --git a/server/http.go b/server/http.go
index 168856b..ad864f5 100644
--- a/server/http.go
+++ b/server/http.go
@@ -400,6 +400,7 @@ func getParamOrDefault(c *gin.Context, k, def string) string {
return def
}
+
func getParam(c *gin.Context, k string) string {
p, _ := getParamWithType(c, k)
return p
diff --git a/server/websocket.go b/server/websocket.go
index 8dab69a..7f0cae6 100644
--- a/server/websocket.go
+++ b/server/websocket.go
@@ -319,6 +319,7 @@ func (s *websocketServer) onBotPushEvent(m coolq.MSG) {
for i, l := 0, len(s.eventConn); i < l; i++ {
conn := s.eventConn[i]
log.Debugf("向WS客户端 %v 推送Event: %v", conn.RemoteAddr().String(), m.ToJson())
+ conn.Lock()
if err := conn.WriteMessage(websocket.TextMessage, []byte(m.ToJson())); err != nil {
_ = conn.Close()
next := i + 1
@@ -330,7 +331,9 @@ func (s *websocketServer) onBotPushEvent(m coolq.MSG) {
i--
l--
conn = nil
+ continue
}
+ conn.Unlock()
}
}