diff --git a/coolq/api.go b/coolq/api.go
index 457f5c8..db2b339 100644
--- a/coolq/api.go
+++ b/coolq/api.go
@@ -71,7 +71,22 @@ func (bot *CQBot) CQGetGroupList(noCache bool) MSG {
func (bot *CQBot) CQGetGroupInfo(groupID int64, noCache bool) MSG {
group := bot.Client.FindGroup(groupID)
if group == nil {
- return Failed(100, "GROUP_NOT_FOUND", "群聊不存在")
+ gid := strconv.FormatInt(groupID, 10)
+ info, err := bot.Client.SearchGroupByKeyword(gid)
+ if err != nil {
+ return Failed(100, "GROUP_SEARCH_ERROR", "群聊搜索失败")
+ }
+ for _, g := range info {
+ if g.Code == groupID {
+ return OK(MSG{
+ "group_id": g.Code,
+ "group_name": g.Name,
+ "max_member_count": 0,
+ "member_count": 0,
+ })
+ }
+ }
+ return Failed(100, "GROUP_NOT_FOUND", "群聊不存在失败")
}
if noCache {
var err error
@@ -955,6 +970,7 @@ func (bot *CQBot) CQGetGroupMessageHistory(groupID int64, seq int64) MSG {
var ms []MSG
for _, m := range msg {
id := m.Id
+ bot.checkMedia(m.Elements)
if bot.db != nil {
id = bot.InsertGroupMessage(m)
}
@@ -1083,6 +1099,68 @@ func (bot *CQBot) CQGetStatus() MSG {
})
}
+// CQSetEssenceMessage 设置精华消息
+func (bot *CQBot) CQSetEssenceMessage(messageID int32) MSG {
+ msg := bot.GetMessage(messageID)
+ if msg == nil {
+ return Failed(100, "MESSAGE_NOT_FOUND", "消息不存在")
+ }
+ if _, ok := msg["group"]; ok {
+ if err := bot.Client.SetEssenceMessage(msg["group"].(int64), msg["message-id"].(int32), msg["internal-id"].(int32)); err != nil {
+ log.Warnf("设置精华消息 %v 失败: %v", messageID, err)
+ return Failed(100, "SET_ESSENCE_MSG_ERROR", err.Error())
+ }
+ } else {
+ log.Warnf("设置精华消息 %v 失败: 非群聊", messageID)
+ return Failed(100, "SET_ESSENCE_MSG_ERROR", "非群聊")
+ }
+ return OK(nil)
+}
+
+// CQDeleteEssenceMessage 移出精华消息
+func (bot *CQBot) CQDeleteEssenceMessage(messageID int32) MSG {
+ msg := bot.GetMessage(messageID)
+ if msg == nil {
+ return Failed(100, "MESSAGE_NOT_FOUND", "消息不存在")
+ }
+ if _, ok := msg["group"]; ok {
+ if err := bot.Client.DeleteEssenceMessage(msg["group"].(int64), msg["message-id"].(int32), msg["internal-id"].(int32)); err != nil {
+ log.Warnf("移出精华消息 %v 失败: %v", messageID, err)
+ return Failed(100, "DEL_ESSENCE_MSG_ERROR", err.Error())
+ }
+ } else {
+ log.Warnf("移出精华消息 %v 失败: 非群聊", messageID)
+ return Failed(100, "DEL_ESSENCE_MSG_ERROR", "非群聊")
+ }
+ return OK(nil)
+}
+
+// CQGetEssenceMessageList 获取精华消息列表
+func (bot *CQBot) CQGetEssenceMessageList(groupCode int64) MSG {
+ g := bot.Client.FindGroup(groupCode)
+ if g == nil {
+ return Failed(100, "GROUP_NOT_FOUND", "群聊不存在")
+ }
+ msgList, err := bot.Client.GetGroupEssenceMsgList(groupCode)
+ if err != nil {
+ return Failed(100, "GET_ESSENCE_LIST_FOUND", err.Error())
+ }
+ list := make([]MSG, 0)
+ for _, m := range msgList {
+ var msg = MSG{
+ "sender_nick": m.SenderNick,
+ "sender_time": m.SenderTime,
+ "operator_time": m.AddDigestTime,
+ "operator_nick": m.AddDigestNick,
+ }
+ msg["sender_id"], _ = strconv.ParseUint(m.SenderUin, 10, 64)
+ msg["operator_id"], _ = strconv.ParseUint(m.AddDigestUin, 10, 64)
+ msg["message_id"] = toGlobalID(groupCode, int32(m.MessageID))
+ list = append(list, msg)
+ }
+ return OK(list)
+}
+
//CQGetVersionInfo : 获取版本信息
//
//https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_version_info-%E8%8E%B7%E5%8F%96%E7%89%88%E6%9C%AC%E4%BF%A1%E6%81%AF
diff --git a/coolq/bot.go b/coolq/bot.go
index 557cef5..191626e 100644
--- a/coolq/bot.go
+++ b/coolq/bot.go
@@ -82,6 +82,7 @@ func NewQQBot(cli *client.QQClient, conf *global.JSONConfig) *CQBot {
bot.Client.OnGroupInvited(bot.groupInvitedEvent)
bot.Client.OnUserWantJoinGroup(bot.groupJoinReqEvent)
bot.Client.OnOtherClientStatusChanged(bot.otherClientStatusChangedEvent)
+ bot.Client.OnGroupDigest(bot.groupEssenceMsg)
go func() {
i := conf.HeartbeatInterval
if i < 0 {
@@ -211,61 +212,8 @@ func (bot *CQBot) SendGroupMessage(groupID int64, m *message.SendingMessage) int
bot.Client.SendGroupGift(uint64(groupID), uint64(i.Target), i.GiftID)
return 0
}
- if i, ok := elem.(*QQMusicElement); ok {
- var msgStyle uint32 = 4
- if i.MusicURL == "" {
- msgStyle = 0 // fix vip song
- }
- ret, err := bot.Client.SendGroupRichMessage(groupID, 100497308, 1, msgStyle, client.RichClientInfo{
- Platform: 1,
- SdkVersion: "0.0.0",
- PackageName: "com.tencent.qqmusic",
- Signature: "cbd27cd7c861227d013a25b2d10f0799",
- }, &message.RichMessage{
- Title: i.Title,
- Summary: i.Summary,
- Url: i.URL,
- PictureUrl: i.PictureURL,
- MusicUrl: i.MusicURL,
- })
- if err != nil {
- log.Warnf("警告: 群 %v 富文本消息发送失败: %v", groupID, err)
- return -1
- }
- return bot.InsertGroupMessage(ret)
- }
- if i, ok := elem.(*CloudMusicElement); ok {
- ret, err := bot.Client.SendGroupRichMessage(groupID, 100495085, 1, 4, client.RichClientInfo{
- Platform: 1,
- SdkVersion: "0.0.0",
- PackageName: "com.netease.cloudmusic",
- Signature: "da6b069da1e2982db3e386233f68d76d",
- }, &message.RichMessage{
- Title: i.Title,
- Summary: i.Summary,
- Url: i.URL,
- PictureUrl: i.PictureURL,
- MusicUrl: i.MusicURL,
- })
- if err != nil {
- log.Warnf("警告: 群 %v 富文本消息发送失败: %v", groupID, err)
- return -1
- }
- return bot.InsertGroupMessage(ret)
- }
- if i, ok := elem.(*MiguMusicElement); ok {
- ret, err := bot.Client.SendGroupRichMessage(groupID, 1101053067, 1, 4, client.RichClientInfo{
- Platform: 1,
- SdkVersion: "0.0.0",
- PackageName: "cmccwm.mobilemusic",
- Signature: "6cdc72a439cef99a3418d2a78aa28c73",
- }, &message.RichMessage{
- Title: i.Title,
- Summary: i.Summary,
- Url: i.URL,
- PictureUrl: i.PictureURL,
- MusicUrl: i.MusicURL,
- })
+ if i, ok := elem.(*message.MusicShareElement); ok {
+ ret, err := bot.Client.SendGroupMusicShare(groupID, i)
if err != nil {
log.Warnf("警告: 群 %v 富文本消息发送失败: %v", groupID, err)
return -1
@@ -323,53 +271,8 @@ func (bot *CQBot) SendPrivateMessage(target int64, m *message.SendingMessage) in
newElem = append(newElem, gv)
continue
}
- if i, ok := elem.(*QQMusicElement); ok {
- var msgStyle uint32 = 4
- if i.MusicURL == "" {
- msgStyle = 0 // fix vip song
- }
- bot.Client.SendFriendRichMessage(target, 100497308, 1, msgStyle, client.RichClientInfo{
- Platform: 1,
- SdkVersion: "0.0.0",
- PackageName: "com.tencent.qqmusic",
- Signature: "cbd27cd7c861227d013a25b2d10f0799",
- }, &message.RichMessage{
- Title: i.Title,
- Summary: i.Summary,
- Url: i.URL,
- PictureUrl: i.PictureURL,
- MusicUrl: i.MusicURL,
- })
- return 0
- }
- if i, ok := elem.(*CloudMusicElement); ok {
- bot.Client.SendFriendRichMessage(target, 100495085, 1, 4, client.RichClientInfo{
- Platform: 1,
- SdkVersion: "0.0.0",
- PackageName: "com.netease.cloudmusic",
- Signature: "da6b069da1e2982db3e386233f68d76d",
- }, &message.RichMessage{
- Title: i.Title,
- Summary: i.Summary,
- Url: i.URL,
- PictureUrl: i.PictureURL,
- MusicUrl: i.MusicURL,
- })
- return 0
- }
- if i, ok := elem.(*MiguMusicElement); ok {
- bot.Client.SendFriendRichMessage(target, 1101053067, 1, 4, client.RichClientInfo{
- Platform: 1,
- SdkVersion: "0.0.0",
- PackageName: "cmccwm.mobilemusic",
- Signature: "6cdc72a439cef99a3418d2a78aa28c73",
- }, &message.RichMessage{
- Title: i.Title,
- Summary: i.Summary,
- Url: i.URL,
- PictureUrl: i.PictureURL,
- MusicUrl: i.MusicURL,
- })
+ if i, ok := elem.(*message.MusicShareElement); ok {
+ bot.Client.SendFriendMusicShare(target, i)
return 0
}
newElem = append(newElem, elem)
diff --git a/coolq/cqcode.go b/coolq/cqcode.go
index 82debbb..7712ef5 100644
--- a/coolq/cqcode.go
+++ b/coolq/cqcode.go
@@ -53,30 +53,6 @@ type GiftElement struct {
GiftID message.GroupGift
}
-//MusicElement 音乐
-type MusicElement struct {
- Title string
- Summary string
- URL string
- PictureURL string
- MusicURL string
-}
-
-//QQMusicElement QQ音乐
-type QQMusicElement struct {
- MusicElement
-}
-
-//CloudMusicElement 网易云音乐
-type CloudMusicElement struct {
- MusicElement
-}
-
-//MiguMusicElement 咪咕音乐
-type MiguMusicElement struct {
- MusicElement
-}
-
//LocalImageElement 本地图片
type LocalImageElement struct {
message.ImageElement
@@ -103,12 +79,6 @@ func (e *GiftElement) Type() message.ElementType {
return message.At
}
-//Type 获取元素类型ID
-func (e *MusicElement) Type() message.ElementType {
- //Make message.IMessageElement Happy
- return message.Service
-}
-
//GiftID 礼物ID数组
var GiftID = [...]message.GroupGift{
message.SweetWink,
@@ -723,7 +693,7 @@ func (bot *CQBot) ToElement(t string, d map[string]string, isGroup bool) (m inte
return nil, errors.New("song not found")
}
aid := strconv.FormatInt(info.Get("track_info.album.id").Int(), 10)
- name := info.Get("track_info.name").Str + " - " + info.Get("track_info.singer.0.name").Str
+ name := info.Get("track_info.name").Str
mid := info.Get("track_info.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")
@@ -733,17 +703,18 @@ func (bot *CQBot) ToElement(t string, d map[string]string, isGroup bool) (m inte
if len(aid) < 2 {
return nil, errors.New("song error")
}
- content := "来自go-cqhttp"
+ content := info.Get("track_info.singer.0.name").Str
if d["content"] != "" {
content = d["content"]
}
- return &QQMusicElement{MusicElement: MusicElement{
+ return &message.MusicShareElement{
+ MusicType: message.QQMusic,
Title: name,
Summary: content,
- URL: jumpURL,
- PictureURL: preview,
- MusicURL: purl,
- }}, nil
+ Url: jumpURL,
+ PictureUrl: preview,
+ MusicUrl: purl,
+ }, nil
}
if d["type"] == "163" {
info, err := global.NeteaseMusicSongInfo(d["id"])
@@ -761,41 +732,36 @@ func (bot *CQBot) ToElement(t string, d map[string]string, isGroup bool) (m inte
if info.Get("artists.0").Exists() {
artistName = info.Get("artists.0.name").Str
}
- return &CloudMusicElement{MusicElement{
+ return &message.MusicShareElement{
+ MusicType: message.CloudMusic,
Title: name,
Summary: artistName,
- URL: jumpURL,
- PictureURL: picURL,
- MusicURL: musicURL,
- }}, nil
+ Url: jumpURL,
+ PictureUrl: picURL,
+ MusicUrl: musicURL,
+ }, nil
}
if d["type"] == "custom" {
- if d["subtype"] == "qq" {
- return &QQMusicElement{MusicElement{
+ if d["subtype"] != "" {
+ var subtype = map[string]int{
+ "qq": message.QQMusic,
+ "163": message.CloudMusic,
+ "migu": message.MiguMusic,
+ "kugou": message.KugouMusic,
+ "kuwo": message.KuwoMusic,
+ }
+ var musicType = 0
+ if tp, ok := subtype[d["subtype"]]; ok {
+ musicType = tp
+ }
+ return &message.MusicShareElement{
+ MusicType: musicType,
Title: d["title"],
Summary: d["content"],
- URL: d["url"],
- PictureURL: d["image"],
- MusicURL: d["purl"],
- }}, nil
- }
- if d["subtype"] == "163" {
- return &CloudMusicElement{MusicElement{
- Title: d["title"],
- Summary: d["content"],
- URL: d["url"],
- PictureURL: d["image"],
- MusicURL: d["purl"],
- }}, nil
- }
- if d["subtype"] == "migu" {
- return &MiguMusicElement{MusicElement{
- Title: d["title"],
- Summary: d["content"],
- URL: d["url"],
- PictureURL: d["image"],
- MusicURL: d["purl"],
- }}, nil
+ Url: d["url"],
+ PictureUrl: d["image"],
+ MusicUrl: d["purl"],
+ }, nil
}
xml := fmt.Sprintf(`- %s%s
`,
XMLEscape(d["title"]), d["url"], d["image"], d["audio"], XMLEscape(d["title"]), XMLEscape(d["content"]))
diff --git a/coolq/event.go b/coolq/event.go
index 56a3d74..5c050eb 100644
--- a/coolq/event.go
+++ b/coolq/event.go
@@ -431,7 +431,47 @@ func (bot *CQBot) otherClientStatusChangedEvent(c *client.QQClient, e *client.Ot
"self_id": c.Uin,
"time": time.Now().Unix(),
})
+}
+func (bot *CQBot) groupEssenceMsg(c *client.QQClient, e *client.GroupDigestEvent) {
+ g := c.FindGroup(e.GroupCode)
+ gid := toGlobalID(e.GroupCode, e.MessageID)
+ if e.OperationType == 1 {
+ log.Infof(
+ "群 %v 内 %v 将 %v 的消息(%v)设为了精华消息.",
+ formatGroupName(g),
+ formatMemberName(g.FindMember(e.OperatorUin)),
+ formatMemberName(g.FindMember(e.SenderUin)),
+ gid,
+ )
+ } else {
+ log.Infof(
+ "群 %v 内 %v 将 %v 的消息(%v)移出了精华消息.",
+ formatGroupName(g),
+ formatMemberName(g.FindMember(e.OperatorUin)),
+ formatMemberName(g.FindMember(e.SenderUin)),
+ gid,
+ )
+ }
+ if e.OperatorUin == bot.Client.Uin {
+ return
+ }
+ bot.dispatchEventMessage(MSG{
+ "post_type": "notice",
+ "group_id": e.GroupCode,
+ "notice_type": "essence",
+ "sub_type": func() string {
+ if e.OperationType == 1 {
+ return "add"
+ }
+ return "delete"
+ }(),
+ "self_id": c.Uin,
+ "sender_id": e.SenderUin,
+ "operator_id": e.OperatorUin,
+ "time": time.Now().Unix(),
+ "message_id": gid,
+ })
}
func (bot *CQBot) groupIncrease(groupCode, operatorUin, userUin int64) MSG {
diff --git a/docs/cqhttp.md b/docs/cqhttp.md
index f660e64..4c29eb2 100644
--- a/docs/cqhttp.md
+++ b/docs/cqhttp.md
@@ -39,6 +39,9 @@
- [获取群子目录文件列表](#设置群名)
- [获取用户VIP信息](#获取用户VIP信息)
- [发送群公告](#发送群公告)
+- [设置精华消息](#设置精华消息)
+- [移出精华消息](#移出精华消息)
+- [获取精华消息列表](#获取精华消息列表)
- [重载事件过滤器](#重载事件过滤器)
##### 事件
@@ -50,6 +53,7 @@
- [群成员荣誉变更提示](#群成员荣誉变更提示)
- [群成员名片更新](#群成员名片更新)
- [接收到离线文件](#接收到离线文件)
+- [群精华消息](#精华消息)
@@ -111,6 +115,54 @@ Type : `reply`
\
自定义回复示例: `[CQ:reply,text=Hello World,qq=10086,time=3376656000]`
+### 音乐分享
+
+```json
+{
+ "type": "music",
+ "data": {
+ "type": "163",
+ "id": "28949129"
+ }
+}
+```
+
+```
+[CQ:music,type=163,id=28949129]
+```
+
+| 参数名 | 收 | 发 | 可能的值 | 说明 |
+| --- | --- | --- | --- | --- |
+| `type` | | ✓ | `qq` `163` | 分别表示使用 QQ 音乐、网易云音乐 |
+| `id` | | ✓ | - | 歌曲 ID |
+
+### 音乐自定义分享
+
+```json
+{
+ "type": "music",
+ "data": {
+ "type": "custom",
+ "url": "http://baidu.com",
+ "audio": "http://baidu.com/1.mp3",
+ "title": "音乐标题"
+ }
+}
+```
+
+```
+[CQ:music,type=custom,url=http://baidu.com,audio=http://baidu.com/1.mp3,title=音乐标题]
+```
+
+| 参数名 | 收 | 发 | 可能的值 | 说明 |
+| --- | --- | --- | --- | --- |
+| `type` | | ✓ | `custom` | 表示音乐自定义分享 |
+| `subtype` | | ✓ | `qq,163,migu,kugou,kuwo` | 表示分享类型,不填写发送为xml卡片,推荐填写提高稳定性 |
+| `url` | | ✓ | - | 点击后跳转目标 URL |
+| `audio` | | ✓ | - | 音乐 URL |
+| `title` | | ✓ | - | 标题 |
+| `content` | | ✓ | - | 内容描述 |
+| `image` | | ✓ | - | 图片 URL |
### 红包
@@ -572,11 +624,63 @@ Type: `tts`
| -------- | -------- | ---- |
| `slices` | string[] | 词组 |
+### 设置精华消息
+
+终结点: `/set_essence_msg`
+
+**参数**
+
+| 字段 | 类型 | 说明 |
+| --------- | ------ | ---- |
+| `message_id` | int32 | 消息ID |
+
+**响应数据**
+
+无
+
+### 移出精华消息
+
+终结点: `/delete_essence_msg`
+
+**参数**
+
+| 字段 | 类型 | 说明 |
+| --------- | ------ | ---- |
+| `message_id` | int32 | 消息ID |
+
+**响应数据**
+
+无
+
+### 获取精华消息列表
+
+终结点: `/get_essence_msg_list`
+
+**参数**
+
+| 字段 | 类型 | 说明 |
+| --------- | ------ | ---- |
+| `group_id` | int64 | 群号 |
+
+**响应数据**
+
+响应内容为 JSON 数组,每个元素如下:
+
+| 字段名 | 数据类型 | 说明 |
+| ----- | ------- | --- |
+| `sender_id` |int64 | 发送者QQ 号 |
+| `sender_nick` | string | 发送者昵称 |
+| `sender_time` | int64 | 消息发送时间 |
+| `operator_id` |int64 | 发送者QQ 号 |
+| `operator_nick` | string | 发送者昵称 |
+| `operator_time` | int64 | 消息发送时间|
+| `message_id` | int32 | 消息ID |
+
### 图片OCR
> 注意: 目前图片OCR接口仅支持接受的图片
-终结点: `/.ocr_image`
+终结点: `/ocr_image`
**参数**
@@ -1047,4 +1151,17 @@ JSON数组:
| `post_type` | string | `notice` | 上报类型 |
| `notice_type` | string | `client_status` | 消息类型 |
| `client` | Device | | 客户端信息 |
-| `online` | bool | | 当前是否在线 |
\ No newline at end of file
+| `online` | bool | | 当前是否在线 |
+
+### 精华消息
+
+**上报数据**
+
+| 字段 | 类型 | 可能的值 | 说明 |
+| ------------- | ------ | -------------- | -------- |
+| `post_type` | string | `notice` | 上报类型 |
+| `notice_type` | string | `essence` | 消息类型 |
+| `sub_type` | string | `add`,`delete` | 添加为`add`,移出为`delete` |
+| `sender_id` | int64 | | 消息发送者ID |
+| `operator_id` | int64 | | 操作者ID |
+| `message_id` | int32 | | 消息ID |
diff --git a/global/codec.go b/global/codec.go
index 188504f..1a6b35f 100644
--- a/global/codec.go
+++ b/global/codec.go
@@ -2,13 +2,13 @@ package global
import (
"crypto/md5"
- "errors"
"fmt"
"io/ioutil"
"os/exec"
"path"
"github.com/Mrs4s/go-cqhttp/global/codec"
+ "github.com/pkg/errors"
log "github.com/sirupsen/logrus"
)
@@ -32,7 +32,7 @@ func EncoderSilk(data []byte) ([]byte, error) {
h := md5.New()
_, err := h.Write(data)
if err != nil {
- return nil, err
+ return nil, errors.Wrap(err, "calc md5 failed")
}
tempName := fmt.Sprintf("%x", h.Sum(nil))
if silkPath := path.Join("data/cache", tempName+".silk"); PathExists(silkPath) {
@@ -40,7 +40,7 @@ func EncoderSilk(data []byte) ([]byte, error) {
}
slk, err := codec.EncodeToSilk(data, tempName, true)
if err != nil {
- return nil, err
+ return nil, errors.Wrap(err, "encode silk failed")
}
return slk, nil
}
@@ -51,7 +51,7 @@ func EncodeMP4(src string, dst string) error { // -y 覆盖文件
err := cmd1.Run()
if err != nil {
cmd2 := exec.Command("ffmpeg", "-i", src, "-y", "-c:v", "h264", "-c:a", "mp3", dst)
- return cmd2.Run()
+ return errors.Wrap(cmd2.Run(), "convert mp4 failed")
}
return err
}
@@ -59,5 +59,5 @@ func EncodeMP4(src string, dst string) error { // -y 覆盖文件
//ExtractCover 获取给定视频文件的Cover
func ExtractCover(src string, target string) error {
cmd := exec.Command("ffmpeg", "-i", src, "-y", "-r", "1", "-f", "image2", target)
- return cmd.Run()
+ return errors.Wrap(cmd.Run(), "extract video cover failed")
}
diff --git a/global/codec/codec.go b/global/codec/codec.go
index e515644..41877a4 100644
--- a/global/codec/codec.go
+++ b/global/codec/codec.go
@@ -5,7 +5,7 @@
package codec
import (
- "errors"
+ "github.com/pkg/errors"
"io/ioutil"
"net/http"
"os"
@@ -64,7 +64,7 @@ func EncodeToSilk(record []byte, tempName string, useCache bool) ([]byte, error)
rawPath := path.Join(silkCachePath, tempName+".wav")
err := ioutil.WriteFile(rawPath, record, os.ModePerm)
if err != nil {
- return nil, err
+ return nil, errors.Wrap(err, "write temp file error")
}
defer os.Remove(rawPath)
@@ -72,7 +72,7 @@ func EncodeToSilk(record []byte, tempName string, useCache bool) ([]byte, error)
pcmPath := path.Join(silkCachePath, tempName+".pcm")
cmd := exec.Command("ffmpeg", "-i", rawPath, "-f", "s16le", "-ar", "24000", "-ac", "1", pcmPath)
if err = cmd.Run(); err != nil {
- return nil, err
+ return nil, errors.Wrap(err, "convert pcm file error")
}
defer os.Remove(pcmPath)
@@ -80,7 +80,7 @@ func EncodeToSilk(record []byte, tempName string, useCache bool) ([]byte, error)
silkPath := path.Join(silkCachePath, tempName+".silk")
cmd = exec.Command(getEncoderFilePath(), pcmPath, silkPath, "-rate", "24000", "-quiet", "-tencent")
if err = cmd.Run(); err != nil {
- return nil, err
+ return nil, errors.Wrap(err, "convert silk file error")
}
if !useCache {
defer os.Remove(silkPath)
diff --git a/global/config.go b/global/config.go
index 0396534..0abf933 100644
--- a/global/config.go
+++ b/global/config.go
@@ -119,8 +119,8 @@ var DefaultConfigWithComments = `
use_sso_address: false
// 是否启用 DEBUG
debug: false
- // 日志等级
- log_level: ""
+ // 日志等级 trace,debug,info,warn,error
+ log_level: "info"
// WebUi 设置
web_ui: {
// 是否启用 WebUi
@@ -135,6 +135,9 @@ var DefaultConfigWithComments = `
}
`
+//PasswordHash 存储QQ密码哈希供登录使用
+var PasswordHash [16]byte
+
//JSONConfig Config对应的结构体
type JSONConfig struct {
Uin int64 `json:"uin"`
@@ -274,8 +277,8 @@ func DefaultConfig() *JSONConfig {
}
}
-//Load 加载配置文件
-func Load(p string) *JSONConfig {
+//LoadConfig 加载配置文件
+func LoadConfig(p string) *JSONConfig {
if !PathExists(p) {
log.Warnf("尝试加载配置文件 %v 失败: 文件不存在", p)
return nil
diff --git a/global/filter.go b/global/filter.go
index ef8588a..fdcf5fb 100644
--- a/global/filter.go
+++ b/global/filter.go
@@ -25,12 +25,18 @@ func (m MSG) Get(s string) MSG {
}
return MSG{"__str__": v} // 用这个名字应该没问题吧
}
- return MSG{}
+ return nil // 不存在为空
}
//String 将消息Map转化为String。若Map存在key "__str__",则返回此key对应的值,否则将输出整张消息Map对应的JSON字符串
func (m MSG) String() string {
+ if m == nil {
+ return "" // 空 JSON
+ }
if str, ok := m["__str__"]; ok {
+ if str == nil {
+ return "" // 空 JSON
+ }
return fmt.Sprint(str)
}
str, _ := json.MarshalToString(m)
diff --git a/global/log_hook.go b/global/log_hook.go
new file mode 100644
index 0000000..63865f8
--- /dev/null
+++ b/global/log_hook.go
@@ -0,0 +1,153 @@
+package global
+
+import (
+ "fmt"
+ "github.com/sirupsen/logrus"
+ "io"
+ "os"
+ "path/filepath"
+ "reflect"
+ "sync"
+)
+
+type LocalHook struct {
+ lock *sync.Mutex
+ levels []logrus.Level // hook级别
+ formatter logrus.Formatter // 格式
+ path string // 写入path
+ writer io.Writer // io
+}
+
+// ref: logrus/hooks.go. impl Hook interface
+func (hook *LocalHook) Levels() []logrus.Level {
+ if len(hook.levels) == 0 {
+ return logrus.AllLevels
+ }
+ return hook.levels
+}
+
+func (hook *LocalHook) ioWrite(entry *logrus.Entry) error {
+ log, err := hook.formatter.Format(entry)
+ if err != nil {
+ return err
+ }
+
+ _, err = hook.writer.Write(log)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (hook *LocalHook) pathWrite(entry *logrus.Entry) error {
+ dir := filepath.Dir(hook.path)
+ if err := os.MkdirAll(dir, os.ModePerm); err != nil {
+ return err
+ }
+
+ fd, err := os.OpenFile(hook.path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
+ if err != nil {
+ return err
+ }
+ defer fd.Close()
+
+ log, err := hook.formatter.Format(entry)
+
+ if err != nil {
+ return err
+ }
+
+ _, err = fd.Write(log)
+ return err
+}
+
+func (hook *LocalHook) Fire(entry *logrus.Entry) error {
+ hook.lock.Lock()
+ defer hook.lock.Unlock()
+
+ if hook.writer != nil {
+ return hook.ioWrite(entry)
+ }
+
+ if hook.path != "" {
+ return hook.pathWrite(entry)
+ }
+
+ return nil
+}
+
+func (hook *LocalHook) SetFormatter(formatter logrus.Formatter) {
+ hook.lock.Lock()
+ defer hook.lock.Unlock()
+
+ if formatter == nil {
+ // 用默认的
+ formatter = &logrus.TextFormatter{DisableColors: true}
+ } else {
+ switch f := formatter.(type) {
+ case *logrus.TextFormatter:
+ textFormatter := f
+ textFormatter.DisableColors = true
+ default:
+ // todo
+ }
+ }
+ logrus.SetFormatter(formatter)
+ hook.formatter = formatter
+}
+
+func (hook *LocalHook) SetWriter(writer io.Writer) {
+ hook.lock.Lock()
+ defer hook.lock.Unlock()
+ hook.writer = writer
+}
+
+func (hook *LocalHook) SetPath(path string) {
+ hook.lock.Lock()
+ defer hook.lock.Unlock()
+ hook.path = path
+}
+
+func NewLocalHook(args interface{}, formatter logrus.Formatter, levels ...logrus.Level) *LocalHook {
+ hook := &LocalHook{
+ lock: new(sync.Mutex),
+ }
+ hook.SetFormatter(formatter)
+ hook.levels = append(hook.levels, levels...)
+
+ switch arg := args.(type) {
+ case string:
+ hook.SetPath(arg)
+ case io.Writer:
+ hook.SetWriter(arg)
+ default:
+ panic(fmt.Sprintf("unsupported type: %v", reflect.TypeOf(args)))
+ }
+
+ return hook
+}
+
+func GetLogLevel(level string) []logrus.Level {
+ switch level {
+ case "trace":
+ return []logrus.Level{logrus.TraceLevel, logrus.DebugLevel,
+ logrus.InfoLevel, logrus.WarnLevel, logrus.ErrorLevel,
+ logrus.FatalLevel, logrus.PanicLevel}
+ case "debug":
+ return []logrus.Level{logrus.DebugLevel, logrus.InfoLevel,
+ logrus.WarnLevel, logrus.ErrorLevel,
+ logrus.FatalLevel, logrus.PanicLevel}
+ case "info":
+ return []logrus.Level{logrus.InfoLevel, logrus.WarnLevel,
+ logrus.ErrorLevel, logrus.FatalLevel, logrus.PanicLevel}
+ case "warn":
+ return []logrus.Level{logrus.WarnLevel, logrus.ErrorLevel,
+ logrus.FatalLevel, logrus.PanicLevel}
+ case "error":
+ return []logrus.Level{logrus.ErrorLevel, logrus.FatalLevel,
+ logrus.PanicLevel}
+ default:
+ return []logrus.Level{logrus.InfoLevel, logrus.WarnLevel,
+ logrus.ErrorLevel, logrus.FatalLevel, logrus.PanicLevel}
+ }
+}
diff --git a/go.mod b/go.mod
index d115e41..5fc6b11 100644
--- a/go.mod
+++ b/go.mod
@@ -3,7 +3,7 @@ module github.com/Mrs4s/go-cqhttp
go 1.15
require (
- github.com/Mrs4s/MiraiGo v0.0.0-20210124201115-fb93c5c73169
+ github.com/Mrs4s/MiraiGo v0.0.0-20210202135946-553229fea92e
github.com/dustin/go-humanize v1.0.0
github.com/gin-contrib/pprof v1.3.0
github.com/gin-gonic/gin v1.6.3
@@ -27,7 +27,6 @@ require (
github.com/onsi/ginkgo v1.14.2 // indirect
github.com/onsi/gomega v1.10.4 // indirect
github.com/pkg/errors v0.9.1
- github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5
github.com/sirupsen/logrus v1.7.0
github.com/stretchr/testify v1.7.0 // indirect
github.com/syndtr/goleveldb v1.0.0
@@ -35,9 +34,7 @@ require (
github.com/tidwall/gjson v1.6.7
github.com/ugorji/go v1.2.3 // indirect
github.com/yinghau76/go-ascii-art v0.0.0-20190517192627-e7f465a30189
- golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad // indirect
- golang.org/x/net v0.0.0-20210119194325-5f4716e94777 // indirect
- golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c // indirect
+ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf
golang.org/x/text v0.3.5 // indirect
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324
diff --git a/go.sum b/go.sum
index 1e063db..dac6632 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/LXY1226/fastrand v0.0.0-20210121160840-7a3db3e79031 h1:DnoCySrXUFvtngW2kSkuBeZoPfvOgctJXjTulCn7eV0=
-github.com/LXY1226/fastrand v0.0.0-20210121160840-7a3db3e79031/go.mod h1:mEFi4jHUsE2sqQGSJ7eQfXnO8esMzEYcftiCGG+L/OE=
-github.com/Mrs4s/MiraiGo v0.0.0-20210124201115-fb93c5c73169 h1:Znh5aJ8an9kC93HMLB5BVni2MzIup+1t86bbbKdqdzw=
-github.com/Mrs4s/MiraiGo v0.0.0-20210124201115-fb93c5c73169/go.mod h1:JBm2meosyXAASbl8mZ+mFZEkE/2cC7zNZdIOBe7+QhY=
+github.com/Mrs4s/MiraiGo v0.0.0-20210202135946-553229fea92e h1:5rZXeo+KW1vNq5fM7DowITQgm8r7HuH6w9tScWJ5GQQ=
+github.com/Mrs4s/MiraiGo v0.0.0-20210202135946-553229fea92e/go.mod h1:yhqA0NyKxUf7I/0HR/1OMchveFggX8wde04gqdGrNfU=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
@@ -14,7 +12,6 @@ github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
@@ -32,7 +29,6 @@ github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8c
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
-github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
@@ -50,7 +46,6 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.2 h1:aeE13tS0IiQgFjYdoL8qN3K1N2bXXtI6Vi51/y7BpMw=
github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
@@ -58,12 +53,10 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -73,7 +66,6 @@ github.com/guonaihong/gout v0.1.4 h1:uBBoyztMX9okC27OQxqhn6bZ0ROkGyvnEIHwtp3TM4g
github.com/guonaihong/gout v0.1.4/go.mod h1:0rFYAYyzbcxEg11eY2qUbffJs7hHRPeugAnlVYSp8Ic=
github.com/hjson/hjson-go v3.1.0+incompatible h1:DY/9yE8ey8Zv22bY+mHV1uk2yRy0h8tKhZ77hEdi0Aw=
github.com/hjson/hjson-go v3.1.0+incompatible/go.mod h1:qsetwF8NlsTsOTwZTApNlTCerV+b2GjYRRcIk4JMFio=
-github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ=
github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
@@ -86,7 +78,6 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
@@ -101,28 +92,22 @@ github.com/lestrrat-go/strftime v1.0.4 h1:T1Rb9EPkAhgxKqbcMIPguPq8glqXTA1koF8n9B
github.com/lestrrat-go/strftime v1.0.4/go.mod h1:E1nN3pCbtMSu1yjSVeyuRFVm/U0xoR76fd03sz+Qz4g=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
-github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
-github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.6 h1:11TGpSHY7Esh/i/qnq02Jo5oVrI1Gue8Slbq0ujPZFQ=
github.com/nxadm/tail v1.4.6/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.12.1 h1:mFwc4LvZ0xpSvDZ3E+k8Yte0hLOMxXUlP+yXtJqkYfQ=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.2 h1:8mVmC9kjFFmA8H4pKMUhcblgifdkOIXPvbhN1T36q1M=
github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
-github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
@@ -134,17 +119,13 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
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.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
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 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
@@ -159,11 +140,9 @@ github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE=
github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU=
github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
-github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go v1.2.3 h1:WbFSXLxDFKVN69Sk8t+XHGzVCD7R8UoAATR8NqZgTbk=
github.com/ugorji/go v1.2.3/go.mod h1:5l8GZ8hZvmL4uMdy+mhCO1LjswGRYco9Q3HfuisB21A=
-github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/ugorji/go/codec v1.2.3 h1:/mVYEV+Jo3IZKeA5gBngN0AvNnQltEDkR+eQikkWQu0=
github.com/ugorji/go/codec v1.2.3/go.mod h1:5FxzDJIgeiWJZslYHPj+LS1dq1ZBQVelZFnjsFGI/Uc=
@@ -172,8 +151,6 @@ github.com/yinghau76/go-ascii-art v0.0.0-20190517192627-e7f465a30189/go.mod h1:r
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
-golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@@ -184,13 +161,10 @@ 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-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa h1:F+8P+gmewFQYRk6JoLQLwjBCTu3mcIURZfNkVweuRKA=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 h1:AeiKBIuRw3UomYXSbLy0Mc2dDLfdtbT/IVn4keq83P0=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb h1:eBmm0M9fYhWpKZLjQUUKka/LtIxf46G4fxeEz5KJr9U=
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=
-golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
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=
@@ -210,13 +184,8 @@ golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
-golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
-golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M=
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -228,9 +197,7 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135 h1:5Beo0mZN8dRzgrMMkDp0jc8YXQKx9DiJ2k1dkvGsn5A=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -248,16 +215,13 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
-gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
@@ -268,7 +232,6 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
-gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/main.go b/main.go
index 63a756c..327663b 100644
--- a/main.go
+++ b/main.go
@@ -2,8 +2,11 @@ package main
import (
"bufio"
+ "crypto/aes"
"crypto/md5"
+ "crypto/sha1"
"encoding/base64"
+ "encoding/hex"
"fmt"
"io"
"io/ioutil"
@@ -22,6 +25,7 @@ import (
"github.com/Mrs4s/go-cqhttp/server"
"github.com/guonaihong/gout"
"github.com/tidwall/gjson"
+ "golang.org/x/crypto/pbkdf2"
"golang.org/x/term"
"github.com/Mrs4s/MiraiGo/binary"
@@ -30,42 +34,15 @@ import (
"github.com/Mrs4s/go-cqhttp/global"
jsoniter "github.com/json-iterator/go"
rotatelogs "github.com/lestrrat-go/file-rotatelogs"
- "github.com/rifflock/lfshook"
log "github.com/sirupsen/logrus"
easy "github.com/t-tomalak/logrus-easy-formatter"
)
var json = jsoniter.ConfigCompatibleWithStandardLibrary
+var conf *global.JSONConfig
+var isFastStart = false
func init() {
- log.SetFormatter(&easy.Formatter{
- TimestampFormat: "2006-01-02 15:04:05",
- LogFormat: "[%time%] [%lvl%]: %msg% \n",
- })
- w, err := rotatelogs.New(path.Join("logs", "%Y-%m-%d.log"), rotatelogs.WithRotationTime(time.Hour*24))
- if err == nil {
- log.SetOutput(io.MultiWriter(os.Stderr, w))
- }
- if !global.PathExists(global.ImagePath) {
- if err := os.MkdirAll(global.ImagePath, 0755); err != nil {
- log.Fatalf("创建图片缓存文件夹失败: %v", err)
- }
- }
- if !global.PathExists(global.VoicePath) {
- if err := os.MkdirAll(global.VoicePath, 0755); err != nil {
- log.Fatalf("创建语音缓存文件夹失败: %v", err)
- }
- }
- if !global.PathExists(global.VideoPath) {
- if err := os.MkdirAll(global.VideoPath, 0755); err != nil {
- log.Fatalf("创建视频缓存文件夹失败: %v", err)
- }
- }
- if !global.PathExists(global.CachePath) {
- if err := os.MkdirAll(global.CachePath, 0755); err != nil {
- log.Fatalf("创建发送图片缓存文件夹失败: %v", err)
- }
- }
if global.PathExists("cqhttp.json") {
log.Info("发现 cqhttp.json 将在五秒后尝试导入配置,按 Ctrl+C 取消.")
log.Warn("警告: 该操作会删除 cqhttp.json 并覆盖 config.hjson 文件.")
@@ -95,12 +72,54 @@ func init() {
}
_ = os.Remove("cqhttp.json")
}
+
+ conf = getConfig()
+ if conf == nil {
+ os.Exit(1)
+ }
+
+ logFormatter := &easy.Formatter{
+ TimestampFormat: "2006-01-02 15:04:05",
+ LogFormat: "[%time%] [%lvl%]: %msg% \n",
+ }
+ w, err := rotatelogs.New(path.Join("logs", "%Y-%m-%d.log"), rotatelogs.WithRotationTime(time.Hour*24))
+ if err != nil {
+ log.Errorf("rotatelogs init err: %v", err)
+ panic(err)
+ }
+
+ // 在debug模式下,将在标准输出中打印当前执行行数
+ if conf.Debug {
+ log.SetReportCaller(true)
+ }
+
+ log.AddHook(global.NewLocalHook(w, logFormatter, global.GetLogLevel(conf.LogLevel)...))
+
+ if !global.PathExists(global.ImagePath) {
+ if err := os.MkdirAll(global.ImagePath, 0755); err != nil {
+ log.Fatalf("创建图片缓存文件夹失败: %v", err)
+ }
+ }
+ if !global.PathExists(global.VoicePath) {
+ if err := os.MkdirAll(global.VoicePath, 0755); err != nil {
+ log.Fatalf("创建语音缓存文件夹失败: %v", err)
+ }
+ }
+ if !global.PathExists(global.VideoPath) {
+ if err := os.MkdirAll(global.VideoPath, 0755); err != nil {
+ log.Fatalf("创建视频缓存文件夹失败: %v", err)
+ }
+ }
+ if !global.PathExists(global.CachePath) {
+ if err := os.MkdirAll(global.CachePath, 0755); err != nil {
+ log.Fatalf("创建发送图片缓存文件夹失败: %v", err)
+ }
+ }
}
func main() {
var byteKey []byte
- var isFastStart = false
arg := os.Args
if len(arg) > 1 {
for i := range arg {
@@ -122,91 +141,12 @@ func main() {
}
}
- var conf *global.JSONConfig
- if global.PathExists("config.json") {
- conf = global.Load("config.json")
- _ = conf.Save("config.hjson")
- _ = os.Remove("config.json")
- } else if os.Getenv("UIN") != "" {
- log.Infof("将从环境变量加载配置.")
- uin, _ := strconv.ParseInt(os.Getenv("UIN"), 10, 64)
- pwd := os.Getenv("PASS")
- post := os.Getenv("HTTP_POST")
- conf = &global.JSONConfig{
- Uin: uin,
- Password: pwd,
- HTTPConfig: &global.GoCQHTTPConfig{
- Enabled: true,
- Host: "0.0.0.0",
- Port: 5700,
- PostUrls: map[string]string{},
- },
- WSConfig: &global.GoCQWebSocketConfig{
- Enabled: true,
- Host: "0.0.0.0",
- Port: 6700,
- },
- PostMessageFormat: "string",
- Debug: os.Getenv("DEBUG") == "true",
- }
- if post != "" {
- conf.HTTPConfig.PostUrls[post] = os.Getenv("HTTP_SECRET")
- }
- } else {
- conf = global.Load("config.hjson")
- }
- if conf == nil {
- err := global.WriteAllText("config.hjson", global.DefaultConfigWithComments)
- if err != nil {
- log.Fatalf("创建默认配置文件时出现错误: %v", err)
- return
- }
- log.Infof("默认配置文件已生成, 请编辑 config.hjson 后重启程序.")
- time.Sleep(time.Second * 5)
- return
- }
if conf.Uin == 0 || (conf.Password == "" && conf.PasswordEncrypted == "") {
log.Warnf("请修改 config.hjson 以添加账号密码.")
- 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"),
- }
+ if !isFastStart {
+ time.Sleep(time.Second * 5)
}
-
- log.AddHook(lfshook.NewHook(
- logPathMap,
- &easy.Formatter{
- TimestampFormat: "2006-01-02 15:04:05",
- LogFormat: "[%time%] [%lvl%]: %msg% \n",
- },
- ))
+ return
}
log.Info("当前版本:", coolq.Version)
@@ -233,15 +173,11 @@ func main() {
}
if conf.EncryptPassword && conf.PasswordEncrypted == "" {
log.Infof("密码加密已启用, 请输入Key对密码进行加密: (Enter 提交)")
- byteKey, _ := term.ReadPassword(int(os.Stdin.Fd()))
- key := md5.Sum(byteKey)
- if encrypted := EncryptPwd(conf.Password, key[:]); encrypted != "" {
- conf.Password = ""
- conf.PasswordEncrypted = encrypted
- _ = conf.Save("config.hjson")
- } else {
- log.Warnf("加密时出现问题.")
- }
+ byteKey, _ = term.ReadPassword(int(os.Stdin.Fd()))
+ global.PasswordHash = md5.Sum([]byte(conf.Password))
+ conf.Password = ""
+ conf.PasswordEncrypted = "AES:" + PasswordHashEncrypt(global.PasswordHash[:], byteKey)
+ _ = conf.Save("config.hjson")
}
if conf.PasswordEncrypted != "" {
if len(byteKey) == 0 {
@@ -262,8 +198,25 @@ func main() {
} else {
log.Infof("密码加密已启用, 使用运行时传递的参数进行解密,按 Ctrl+C 取消.")
}
- key := md5.Sum(byteKey)
- conf.Password = DecryptPwd(conf.PasswordEncrypted, key[:])
+
+ //升级客户端密码加密方案,MD5+TEA 加密密码 -> PBKDF2+AES 加密 MD5
+ //升级后的 PasswordEncrypted 字符串以"AES:"开始,其后为 Hex 编码的16字节加密 MD5
+ if !strings.HasPrefix(conf.PasswordEncrypted, "AES:") {
+ password := OldPasswordDecrypt(conf.PasswordEncrypted, byteKey)
+ passwordHash := md5.Sum([]byte(password))
+ newPasswordHash := PasswordHashEncrypt(passwordHash[:], byteKey)
+ conf.PasswordEncrypted = "AES:" + newPasswordHash
+ _ = conf.Save("config.hjson")
+ log.Debug("密码加密方案升级完成")
+ }
+
+ ph, err := PasswordHashDecrypt(conf.PasswordEncrypted[4:], byteKey)
+ if err != nil {
+ log.Fatalf("加密存储的密码损坏,请尝试重新配置密码")
+ }
+ copy(global.PasswordHash[:], ph)
+ } else {
+ global.PasswordHash = md5.Sum([]byte(conf.Password))
}
if !isFastStart {
log.Info("Bot将在5秒后登录并开始信息处理, 按 Ctrl+C 取消.")
@@ -283,7 +236,7 @@ func main() {
}
return "未知"
}())
- cli := client.NewClient(conf.Uin, conf.Password)
+ cli := client.NewClientMd5(conf.Uin, global.PasswordHash)
cli.OnLog(func(c *client.QQClient, e *client.LogEvent) {
switch e.Type {
case "INFO":
@@ -340,27 +293,50 @@ func main() {
}
}
-//EncryptPwd 通过给定key加密给定pwd
-func EncryptPwd(pwd string, key []byte) string {
- tea := binary.NewTeaCipher(key)
- if tea == nil {
- return ""
+// PasswordHashEncrypt 使用key加密给定passwordHash
+func PasswordHashEncrypt(passwordHash []byte, key []byte) string {
+ if len(passwordHash) != 16 {
+ panic("密码加密参数错误")
}
- return base64.StdEncoding.EncodeToString(tea.Encrypt([]byte(pwd)))
+
+ key = pbkdf2.Key(key, key, 114514, 32, sha1.New)
+
+ cipher, _ := aes.NewCipher(key)
+ result := make([]byte, 16)
+ cipher.Encrypt(result, passwordHash)
+
+ return hex.EncodeToString(result)
}
-//DecryptPwd 通过给定key解密给定ePwd
-func DecryptPwd(ePwd string, key []byte) string {
+// PasswordHashDecrypt 使用key解密给定passwordHash
+func PasswordHashDecrypt(encryptedPasswordHash string, key []byte) ([]byte, error) {
+ ciphertext, err := hex.DecodeString(encryptedPasswordHash)
+ if err != nil {
+ return nil, err
+ }
+
+ key = pbkdf2.Key(key, key, 114514, 32, sha1.New)
+
+ cipher, _ := aes.NewCipher(key)
+ result := make([]byte, 16)
+ cipher.Decrypt(result, ciphertext)
+
+ return result, nil
+}
+
+// OldPasswordDecrypt 使用key解密老password,仅供兼容使用
+func OldPasswordDecrypt(encryptedPassword string, key []byte) string {
defer func() {
if pan := recover(); pan != nil {
log.Fatalf("密码解密失败: %v", pan)
}
}()
- encrypted, err := base64.StdEncoding.DecodeString(ePwd)
+ encKey := md5.Sum(key)
+ encrypted, err := base64.StdEncoding.DecodeString(encryptedPassword)
if err != nil {
panic(err)
}
- tea := binary.NewTeaCipher(key)
+ tea := binary.NewTeaCipher(encKey[:])
if tea == nil {
panic("密钥错误")
}
@@ -491,3 +467,52 @@ func restart(Args []string) {
}
_ = cmd.Start()
}
+
+func getConfig() *global.JSONConfig {
+ var conf *global.JSONConfig
+ if global.PathExists("config.json") {
+ conf = global.LoadConfig("config.json")
+ _ = conf.Save("config.hjson")
+ _ = os.Remove("config.json")
+ } else if os.Getenv("UIN") != "" {
+ log.Infof("将从环境变量加载配置.")
+ uin, _ := strconv.ParseInt(os.Getenv("UIN"), 10, 64)
+ pwd := os.Getenv("PASS")
+ post := os.Getenv("HTTP_POST")
+ conf = &global.JSONConfig{
+ Uin: uin,
+ Password: pwd,
+ HTTPConfig: &global.GoCQHTTPConfig{
+ Enabled: true,
+ Host: "0.0.0.0",
+ Port: 5700,
+ PostUrls: map[string]string{},
+ },
+ WSConfig: &global.GoCQWebSocketConfig{
+ Enabled: true,
+ Host: "0.0.0.0",
+ Port: 6700,
+ },
+ PostMessageFormat: "string",
+ Debug: os.Getenv("DEBUG") == "true",
+ }
+ if post != "" {
+ conf.HTTPConfig.PostUrls[post] = os.Getenv("HTTP_SECRET")
+ }
+ } else {
+ conf = global.LoadConfig("config.hjson")
+ }
+ if conf == nil {
+ err := global.WriteAllText("config.hjson", global.DefaultConfigWithComments)
+ if err != nil {
+ log.Fatalf("创建默认配置文件时出现错误: %v", err)
+ return nil
+ }
+ log.Infof("默认配置文件已生成, 请编辑 config.hjson 后重启程序.")
+ if !isFastStart {
+ time.Sleep(time.Second * 5)
+ }
+ return nil
+ }
+ return conf
+}
diff --git a/server/apiAdmin.go b/server/apiAdmin.go
index 50d8fcf..37b78ee 100644
--- a/server/apiAdmin.go
+++ b/server/apiAdmin.go
@@ -339,7 +339,7 @@ func GetConf() *global.JSONConfig {
if JSONConfig != nil {
return JSONConfig
}
- conf := global.Load("config.hjson")
+ conf := global.LoadConfig("config.hjson")
return conf
}
diff --git a/server/http.go b/server/http.go
index fad621f..8bd30d8 100644
--- a/server/http.go
+++ b/server/http.go
@@ -488,6 +488,21 @@ func SetGroupPortrait(s *httpServer, c *gin.Context) {
c.JSON(200, s.bot.CQSetGroupPortrait(gid, file, cache))
}
+func SetEssenceMsg(s *httpServer, c *gin.Context) {
+ mid, _ := strconv.ParseInt(getParam(c, "message_id"), 10, 64)
+ c.JSON(200, s.bot.CQSetEssenceMessage(int32(mid)))
+}
+
+func DeleteEssenceMsg(s *httpServer, c *gin.Context) {
+ mid, _ := strconv.ParseInt(getParam(c, "message_id"), 10, 64)
+ c.JSON(200, s.bot.CQDeleteEssenceMessage(int32(mid)))
+}
+
+func GetEssenceMsgList(s *httpServer, c *gin.Context) {
+ gid, _ := strconv.ParseInt(getParam(c, "group_id"), 10, 64)
+ c.JSON(200, s.bot.CQGetEssenceMessageList(gid))
+}
+
func getParamOrDefault(c *gin.Context, k, def string) string {
r := getParam(c, k)
if r != "" {
@@ -547,11 +562,13 @@ var httpAPI = map[string]func(s *httpServer, c *gin.Context){
"get_group_root_files": GetGroupRootFiles,
"get_group_files_by_folder": GetGroupFilesByFolderID,
"get_group_file_url": GetGroupFileURL,
+ "get_essence_msg_list": GetEssenceMsgList,
"send_msg": SendMessage,
"send_group_msg": SendGroupMessage,
"send_group_forward_msg": SendGroupForwardMessage,
"send_private_msg": SendPrivateMessage,
"delete_msg": DeleteMessage,
+ "delete_essence_msg": DeleteEssenceMsg,
"set_friend_add_request": ProcessFriendRequest,
"set_group_add_request": ProcessGroupRequest,
"set_group_card": SetGroupCard,
@@ -561,6 +578,7 @@ var httpAPI = map[string]func(s *httpServer, c *gin.Context){
"set_group_whole_ban": SetWholeBan,
"set_group_name": SetGroupName,
"set_group_admin": SetGroupAdmin,
+ "set_essence_msg": SetEssenceMsg,
"set_restart": SetRestart,
"_send_group_notice": SendGroupNotice,
"set_group_leave": SetGroupLeave,
diff --git a/server/websocket.go b/server/websocket.go
index 06f8a6b..1447fd7 100644
--- a/server/websocket.go
+++ b/server/websocket.go
@@ -589,6 +589,15 @@ var wsAPI = map[string]func(*coolq.CQBot, gjson.Result) coolq.MSG{
"set_group_portrait": func(bot *coolq.CQBot, p gjson.Result) coolq.MSG {
return bot.CQSetGroupPortrait(p.Get("group_id").Int(), p.Get("file").String(), p.Get("cache").String())
},
+ "set_essence_msg": func(bot *coolq.CQBot, p gjson.Result) coolq.MSG {
+ return bot.CQSetEssenceMessage(int32(p.Get("message_id").Int()))
+ },
+ "delete_essence_msg": func(bot *coolq.CQBot, p gjson.Result) coolq.MSG {
+ return bot.CQDeleteEssenceMessage(int32(p.Get("message_id").Int()))
+ },
+ "get_essence_msg_list": func(bot *coolq.CQBot, p gjson.Result) coolq.MSG {
+ return bot.CQGetEssenceMessageList(p.Get("group_id").Int())
+ },
"set_group_anonymous_ban": func(bot *coolq.CQBot, p gjson.Result) coolq.MSG {
obj := p.Get("anonymous")
flag := p.Get("anonymous_flag")