diff --git a/coolq/api.go b/coolq/api.go index 4ba4ad6..af68a3e 100644 --- a/coolq/api.go +++ b/coolq/api.go @@ -23,6 +23,7 @@ import ( "github.com/Mrs4s/go-cqhttp/global" "github.com/Mrs4s/go-cqhttp/internal/base" + "github.com/Mrs4s/go-cqhttp/internal/param" ) // CQGetLoginInfo 获取登录号信息 @@ -945,7 +946,7 @@ func (bot *CQBot) CQHandleQuickOperation(context, operation gjson.Result) global reply := operation.Get("reply") if reply.Exists() { - autoEscape := global.EnsureBool(operation.Get("auto_escape"), false) + autoEscape := param.EnsureBool(operation.Get("auto_escape"), false) at := operation.Get("at_sender").Bool() && !isAnonymous && msgType == "group" if at && reply.IsArray() { // 在 reply 数组头部插入CQ码 diff --git a/coolq/bot.go b/coolq/bot.go index f92744c..228faf3 100644 --- a/coolq/bot.go +++ b/coolq/bot.go @@ -27,6 +27,7 @@ import ( "github.com/Mrs4s/go-cqhttp/global" "github.com/Mrs4s/go-cqhttp/global/config" + "github.com/Mrs4s/go-cqhttp/internal/base" ) // CQBot CQBot结构体,存储Bot实例相关配置 @@ -69,12 +70,6 @@ func (e *Event) JSONString() string { return utils.B2S(e.buffer.Bytes()) } -// ForceFragmented 是否启用强制分片 -var ForceFragmented = false - -// SkipMimeScan 是否跳过Mime扫描 -var SkipMimeScan bool - // keep sync with /docs/file.md#MINE var lawfulImageTypes = [...]string{ "image/bmp", @@ -296,7 +291,7 @@ func (bot *CQBot) SendGroupMessage(groupID int64, m *message.SendingMessage) int } m.Elements = newElem bot.checkMedia(newElem) - ret := bot.Client.SendGroupMessage(groupID, m, ForceFragmented) + ret := bot.Client.SendGroupMessage(groupID, m, base.ForceFragmented) if ret == nil || ret.Id == -1 { log.Warnf("群消息发送失败: 账号可能被风控.") return -1 @@ -619,7 +614,7 @@ func (bot *CQBot) uploadMedia(raw message.IMessageElement, target int64, group b // 返回 是否合法, 实际Mime // 判断后会自动将 Stream Seek 至 0 func IsLawfulImage(r io.ReadSeeker) (bool, string) { - if SkipMimeScan { + if base.SkipMimeScan { return true, "" } _, _ = r.Seek(0, io.SeekStart) diff --git a/coolq/cqcode.go b/coolq/cqcode.go index 28c81e1..55296a7 100644 --- a/coolq/cqcode.go +++ b/coolq/cqcode.go @@ -26,6 +26,8 @@ import ( "github.com/Mrs4s/go-cqhttp/global" "github.com/Mrs4s/go-cqhttp/global/codec" + "github.com/Mrs4s/go-cqhttp/internal/base" + "github.com/Mrs4s/go-cqhttp/internal/param" ) /* @@ -34,18 +36,6 @@ var typeReg = regexp.MustCompile(`\[CQ:(\w+)`) var paramReg = regexp.MustCompile(`,([\w\-.]+?)=([^,\]]+)`) */ -// RemoveReplyAt 是否删除reply后的at -var RemoveReplyAt bool - -// ExtraReplyData 是否上报额外reply信息 -var ExtraReplyData bool - -// IgnoreInvalidCQCode 是否忽略无效CQ码 -var IgnoreInvalidCQCode = false - -// SplitURL 是否分割URL -var SplitURL = false - const ( maxImageSize = 1024 * 1024 * 30 // 30MB maxVideoSize = 1024 * 1024 * 100 // 100MB @@ -137,7 +127,7 @@ func ToArrayMessage(e []message.IMessageElement, groupID int64) (r []global.MSG) if rid == 0 { rid = replyElem.Sender } - if ExtraReplyData { + if base.ExtraReplyData { r = append(r, global.MSG{ "type": "reply", "data": map[string]string{ @@ -159,7 +149,7 @@ func ToArrayMessage(e []message.IMessageElement, groupID int64) (r []global.MSG) var m global.MSG switch o := elem.(type) { case *message.ReplyElement: - if RemoveReplyAt && i+1 < len(e) { + if base.RemoveReplyAt && i+1 < len(e) { elem, ok := e[i+1].(*message.AtElement) if ok && elem.Target == o.Sender { e[i+1] = nil @@ -279,7 +269,7 @@ func ToStringMessage(e []message.IMessageElement, groupID int64, isRaw ...bool) if rid == 0 { rid = replyElem.Sender } - if ExtraReplyData { + if base.ExtraReplyData { write("[CQ:reply,id=%d,seq=%d,qq=%d,time=%d,text=%s]", toGlobalID(rid, replyElem.ReplySeq), replyElem.ReplySeq, replyElem.Sender, replyElem.Time, @@ -291,7 +281,7 @@ func ToStringMessage(e []message.IMessageElement, groupID int64, isRaw ...bool) for i, elem := range e { switch o := elem.(type) { case *message.ReplyElement: - if RemoveReplyAt && len(e) > i+1 { + if base.RemoveReplyAt && len(e) > i+1 { elem, ok := e[i+1].(*message.AtElement) if ok && elem.Target == o.Sender { e[i+1] = nil @@ -454,7 +444,7 @@ func (bot *CQBot) ConvertStringMessage(raw string, isGroup bool) (r []message.IM org += "," + k + "=" + v } org += "]" - if !IgnoreInvalidCQCode { + if !base.IgnoreInvalidCQCode { log.Warnf("转换CQ码 %v 时出现错误: %v 将原样发送.", org, err) r = append(r, message.NewText(org)) } else { @@ -476,8 +466,8 @@ func (bot *CQBot) ConvertStringMessage(raw string, isGroup bool) (r []message.IM i++ } if i > 0 { - if SplitURL { - for _, txt := range global.SplitURL(CQCodeUnescapeText(raw[:i])) { + if base.SplitURL { + for _, txt := range param.SplitURL(CQCodeUnescapeText(raw[:i])) { r = append(r, message.NewText(txt)) } } else { @@ -662,9 +652,9 @@ func (bot *CQBot) ConvertObjectMessage(m gjson.Result, isGroup bool) (r []messag func (bot *CQBot) ToElement(t string, d map[string]string, isGroup bool) (m interface{}, err error) { switch t { case "text": - if SplitURL { + if base.SplitURL { var ret []message.IMessageElement - for _, text := range global.SplitURL(d["text"]) { + for _, text := range param.SplitURL(d["text"]) { ret = append(ret, message.NewText(text)) } return ret, nil @@ -735,7 +725,7 @@ func (bot *CQBot) ToElement(t string, d map[string]string, isGroup bool) (m inte if err != nil { return nil, err } - if !SkipMimeScan && !global.IsAMRorSILK(data) { + if !base.SkipMimeScan && !global.IsAMRorSILK(data) { mt := mimetype.Detect(data) lawful := false for _, lt := range lawfulAudioTypes { @@ -1117,7 +1107,7 @@ func (bot *CQBot) makeImageOrVideoElem(d map[string]string, video, group bool) ( return &LocalImageElement{File: fu.Path}, nil } if strings.HasPrefix(f, "base64") && !video { - b, err := global.Base64DecodeString(strings.TrimPrefix(f, "base64://")) + b, err := param.Base64DecodeString(strings.TrimPrefix(f, "base64://")) if err != nil { return nil, err } diff --git a/global/codec/codec.go b/global/codec/codec.go index f44120a..7563518 100644 --- a/global/codec/codec.go +++ b/global/codec/codec.go @@ -13,6 +13,8 @@ import ( "github.com/pkg/errors" "github.com/wdvxdr1123/go-silk" + + "github.com/Mrs4s/go-cqhttp/internal/base" ) const silkCachePath = "data/cache" @@ -30,7 +32,7 @@ func EncodeToSilk(record []byte, tempName string, useCache bool) (silkWav []byte // 2.转换pcm pcmPath := path.Join(silkCachePath, tempName+".pcm") cmd := exec.Command("ffmpeg", "-i", rawPath, "-f", "s16le", "-ar", "24000", "-ac", "1", pcmPath) - if Debug { + if base.Debug { cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr } diff --git a/global/codec/stubs.go b/global/codec/stubs.go deleted file mode 100644 index 9821aa3..0000000 --- a/global/codec/stubs.go +++ /dev/null @@ -1,4 +0,0 @@ -package codec - -// Debug mode controls the ffmpeg output. -var Debug bool diff --git a/global/config/config.go b/global/config/config.go index d403758..c5defa6 100644 --- a/global/config/config.go +++ b/global/config/config.go @@ -11,7 +11,7 @@ import ( "strings" "sync" - "github.com/Mrs4s/go-cqhttp/global" + "github.com/Mrs4s/go-cqhttp/internal/param" log "github.com/sirupsen/logrus" "gopkg.in/yaml.v3" @@ -168,13 +168,13 @@ func Get() *Config { } // load config from environment variable - global.SetAtDefault(&config.Account.Uin, toInt64(os.Getenv("GCQ_UIN")), int64(0)) - global.SetAtDefault(&config.Account.Password, os.Getenv("GCQ_PWD"), "") - global.SetAtDefault(&config.Account.Status, int32(toInt64(os.Getenv("GCQ_STATUS"))), int32(0)) - global.SetAtDefault(&config.Account.ReLogin.Disabled, !global.EnsureBool(os.Getenv("GCQ_RELOGIN_DISABLED"), true), false) - global.SetAtDefault(&config.Account.ReLogin.Delay, uint(toInt64(os.Getenv("GCQ_RELOGIN_DELAY"))), uint(0)) - global.SetAtDefault(&config.Account.ReLogin.MaxTimes, uint(toInt64(os.Getenv("GCQ_RELOGIN_MAX_TIMES"))), uint(0)) - dbConf := &LevelDBConfig{Enable: global.EnsureBool(os.Getenv("GCQ_LEVELDB"), true)} + param.SetAtDefault(&config.Account.Uin, toInt64(os.Getenv("GCQ_UIN")), int64(0)) + param.SetAtDefault(&config.Account.Password, os.Getenv("GCQ_PWD"), "") + param.SetAtDefault(&config.Account.Status, int32(toInt64(os.Getenv("GCQ_STATUS"))), int32(0)) + param.SetAtDefault(&config.Account.ReLogin.Disabled, !param.EnsureBool(os.Getenv("GCQ_RELOGIN_DISABLED"), true), false) + param.SetAtDefault(&config.Account.ReLogin.Delay, uint(toInt64(os.Getenv("GCQ_RELOGIN_DELAY"))), uint(0)) + param.SetAtDefault(&config.Account.ReLogin.MaxTimes, uint(toInt64(os.Getenv("GCQ_RELOGIN_MAX_TIMES"))), uint(0)) + dbConf := &LevelDBConfig{Enable: param.EnsureBool(os.Getenv("GCQ_LEVELDB"), true)} if config.Database == nil { config.Database = make(map[string]yaml.Node) } @@ -193,9 +193,9 @@ func Get() *Config { AccessToken: accessTokenEnv, }, } - global.SetExcludeDefault(&httpConf.Disabled, global.EnsureBool(os.Getenv("GCQ_HTTP_DISABLE"), false), false) - global.SetExcludeDefault(&httpConf.Host, os.Getenv("GCQ_HTTP_HOST"), "") - global.SetExcludeDefault(&httpConf.Port, int(toInt64(os.Getenv("GCQ_HTTP_PORT"))), 0) + param.SetExcludeDefault(&httpConf.Disabled, param.EnsureBool(os.Getenv("GCQ_HTTP_DISABLE"), false), false) + param.SetExcludeDefault(&httpConf.Host, os.Getenv("GCQ_HTTP_HOST"), "") + param.SetExcludeDefault(&httpConf.Port, int(toInt64(os.Getenv("GCQ_HTTP_PORT"))), 0) if os.Getenv("GCQ_HTTP_POST_URL") != "" { httpConf.Post = append(httpConf.Post, struct { URL string `yaml:"url"` @@ -214,9 +214,9 @@ func Get() *Config { AccessToken: accessTokenEnv, }, } - global.SetExcludeDefault(&wsServerConf.Disabled, global.EnsureBool(os.Getenv("GCQ_WS_DISABLE"), false), false) - global.SetExcludeDefault(&wsServerConf.Host, os.Getenv("GCQ_WS_HOST"), "") - global.SetExcludeDefault(&wsServerConf.Port, int(toInt64(os.Getenv("GCQ_WS_PORT"))), 0) + param.SetExcludeDefault(&wsServerConf.Disabled, param.EnsureBool(os.Getenv("GCQ_WS_DISABLE"), false), false) + param.SetExcludeDefault(&wsServerConf.Host, os.Getenv("GCQ_WS_HOST"), "") + param.SetExcludeDefault(&wsServerConf.Port, int(toInt64(os.Getenv("GCQ_WS_PORT"))), 0) _ = node.Encode(wsServerConf) config.Servers = append(config.Servers, map[string]yaml.Node{"ws": *node}) } @@ -227,10 +227,10 @@ func Get() *Config { AccessToken: accessTokenEnv, }, } - global.SetExcludeDefault(&rwsConf.Disabled, global.EnsureBool(os.Getenv("GCQ_RWS_DISABLE"), false), false) - global.SetExcludeDefault(&rwsConf.API, os.Getenv("GCQ_RWS_API"), "") - global.SetExcludeDefault(&rwsConf.Event, os.Getenv("GCQ_RWS_EVENT"), "") - global.SetExcludeDefault(&rwsConf.Universal, os.Getenv("GCQ_RWS_UNIVERSAL"), "") + param.SetExcludeDefault(&rwsConf.Disabled, param.EnsureBool(os.Getenv("GCQ_RWS_DISABLE"), false), false) + param.SetExcludeDefault(&rwsConf.API, os.Getenv("GCQ_RWS_API"), "") + param.SetExcludeDefault(&rwsConf.Event, os.Getenv("GCQ_RWS_EVENT"), "") + param.SetExcludeDefault(&rwsConf.Universal, os.Getenv("GCQ_RWS_UNIVERSAL"), "") _ = node.Encode(rwsConf) config.Servers = append(config.Servers, map[string]yaml.Node{"ws-reverse": *node}) } diff --git a/global/fs.go b/global/fs.go index bd6bf1d..700a177 100644 --- a/global/fs.go +++ b/global/fs.go @@ -15,6 +15,8 @@ import ( "github.com/Mrs4s/MiraiGo/utils" log "github.com/sirupsen/logrus" + + "github.com/Mrs4s/go-cqhttp/internal/param" ) const ( @@ -97,7 +99,7 @@ func FindFile(file, cache, p string) (data []byte, err error) { return nil, err } case strings.HasPrefix(file, "base64"): - data, err = Base64DecodeString(strings.TrimPrefix(file, "base64://")) + data, err = param.Base64DecodeString(strings.TrimPrefix(file, "base64://")) if err != nil { return nil, err } diff --git a/global/net.go b/global/net.go index 2020ffd..541c54c 100644 --- a/global/net.go +++ b/global/net.go @@ -16,16 +16,18 @@ import ( "github.com/pkg/errors" "github.com/tidwall/gjson" + + "github.com/Mrs4s/go-cqhttp/internal/base" ) var ( client = &http.Client{ Transport: &http.Transport{ Proxy: func(request *http.Request) (u *url.URL, e error) { - if Proxy == "" { + if base.Proxy == "" { return http.ProxyFromEnvironment(request) } - return url.Parse(Proxy) + return url.Parse(base.Proxy) }, ForceAttemptHTTP2: true, MaxConnsPerHost: 0, @@ -34,9 +36,6 @@ var ( }, } - // Proxy 存储Config.proxy_rewrite,用于设置代理 - Proxy string - // ErrOverSize 响应主体过大时返回此错误 ErrOverSize = errors.New("oversize") diff --git a/global/param.go b/global/param.go index 39cf565..f23879a 100644 --- a/global/param.go +++ b/global/param.go @@ -1,64 +1,15 @@ package global import ( - "math" - "reflect" "regexp" "strconv" - "strings" - "sync" - "github.com/Mrs4s/MiraiGo/utils" - "github.com/segmentio/asm/base64" log "github.com/sirupsen/logrus" - "github.com/tidwall/gjson" ) // MSG 消息Map type MSG map[string]interface{} -// EnsureBool 判断给定的p是否可表示为合法Bool类型,否则返回defaultVal -// -// 支持的合法类型有 -// -// type bool -// -// type gjson.True or gjson.False -// -// type string "true","yes","1" or "false","no","0" (case insensitive) -func EnsureBool(p interface{}, defaultVal bool) bool { - var str string - if b, ok := p.(bool); ok { - return b - } - if j, ok := p.(gjson.Result); ok { - if !j.Exists() { - return defaultVal - } - switch j.Type { // nolint - case gjson.True: - return true - case gjson.False: - return false - case gjson.String: - str = j.Str - default: - return defaultVal - } - } else if s, ok := p.(string); ok { - str = s - } - str = strings.ToLower(str) - switch str { - case "true", "yes", "1": - return true - case "false", "no", "0": - return false - default: - return defaultVal - } -} - // VersionNameCompare 检查版本名是否需要更新, 仅适用于 go-cqhttp 的版本命名规则 // // 例: v0.9.29-fix2 == v0.9.29-fix2 -> false @@ -93,77 +44,3 @@ func VersionNameCompare(current, remote string) bool { } return cur[4] < re[4] } - -// SetAtDefault 在变量 variable 为默认值 defaultValue 的时候修改为 value -func SetAtDefault(variable, value, defaultValue interface{}) { - v := reflect.ValueOf(variable) - v2 := reflect.ValueOf(value) - if v.Kind() != reflect.Ptr || v.IsNil() { - return - } - v = v.Elem() - if v.Interface() != defaultValue { - return - } - if v.Kind() != v2.Kind() { - return - } - v.Set(v2) -} - -// SetExcludeDefault 在目标值 value 不为默认值 defaultValue 时修改 variable 为 value -func SetExcludeDefault(variable, value, defaultValue interface{}) { - v := reflect.ValueOf(variable) - v2 := reflect.ValueOf(value) - if v.Kind() != reflect.Ptr || v.IsNil() { - return - } - v = v.Elem() - if reflect.Indirect(v2).Interface() != defaultValue { - return - } - if v.Kind() != v2.Kind() { - return - } - v.Set(v2) -} - -var ( - // once lazy compile the reg - once sync.Once - // reg is splitURL regex pattern. - reg *regexp.Regexp -) - -// SplitURL 将给定URL字符串分割为两部分,用于URL预处理防止风控 -func SplitURL(s string) []string { - once.Do(func() { // lazy init. - reg = regexp.MustCompile(`(?i)[a-z\d][-a-z\d]{0,62}(\.[a-z\d][-a-z\d]{0,62})+\.?`) - }) - idx := reg.FindAllStringIndex(s, -1) - if len(idx) == 0 { - return []string{s} - } - var result []string - last := 0 - for i := 0; i < len(idx); i++ { - if len(idx[i]) != 2 { - continue - } - m := int(math.Abs(float64(idx[i][0]-idx[i][1]))/1.5) + idx[i][0] - result = append(result, s[last:m]) - last = m - } - result = append(result, s[last:]) - return result -} - -// Base64DecodeString decode base64 with avx2 -// see https://github.com/segmentio/asm/issues/50 -// avoid incorrect unsafe usage in origin library -func Base64DecodeString(s string) ([]byte, error) { - e := base64.StdEncoding - dst := make([]byte, e.DecodedLen(len(s))) - n, err := e.Decode(dst, utils.S2B(s)) - return dst[:n], err -} diff --git a/internal/base/flag.go b/internal/base/flag.go new file mode 100644 index 0000000..d5673dc --- /dev/null +++ b/internal/base/flag.go @@ -0,0 +1,34 @@ +// Package base provides base config for go-cqhttp +package base + +import "github.com/Mrs4s/go-cqhttp/global/config" + +var ( + Debug bool // 是否开启 debug 模式 + RemoveReplyAt bool // 是否删除reply后的at + ExtraReplyData bool // 是否上报额外reply信息 + IgnoreInvalidCQCode bool // 是否忽略无效CQ码 + SplitURL bool // 是否分割URL + ForceFragmented bool // 是否启用强制分片 + SkipMimeScan bool // 是否跳过Mime扫描 + + Proxy string // 存储 proxy_rewrite,用于设置代理 + PasswordHash [16]byte // 存储QQ密码哈希供登录使用 + AccountToken []byte // 存储AccountToken供登录使用 +) + +func Parse() { + conf := config.Get() + { // bool config + Debug = conf.Output.Debug + IgnoreInvalidCQCode = conf.Message.IgnoreInvalidCQCode + SplitURL = conf.Message.FixURL + RemoveReplyAt = conf.Message.RemoveReplyAt + ExtraReplyData = conf.Message.ExtraReplyData + ForceFragmented = conf.Message.ForceFragment + SkipMimeScan = conf.Message.SkipMimeScan + } + { // string + Proxy = conf.Message.ProxyRewrite + } +} diff --git a/internal/param/param.go b/internal/param/param.go new file mode 100644 index 0000000..0b70967 --- /dev/null +++ b/internal/param/param.go @@ -0,0 +1,130 @@ +// Package param provide some util for param parse +package param + +import ( + "math" + "reflect" + "regexp" + "strings" + "sync" + + "github.com/Mrs4s/MiraiGo/utils" + "github.com/segmentio/asm/base64" + "github.com/tidwall/gjson" +) + +// EnsureBool 判断给定的p是否可表示为合法Bool类型,否则返回defaultVal +// +// 支持的合法类型有 +// +// type bool +// +// type gjson.True or gjson.False +// +// type string "true","yes","1" or "false","no","0" (case insensitive) +func EnsureBool(p interface{}, defaultVal bool) bool { + var str string + if b, ok := p.(bool); ok { + return b + } + if j, ok := p.(gjson.Result); ok { + if !j.Exists() { + return defaultVal + } + switch j.Type { // nolint + case gjson.True: + return true + case gjson.False: + return false + case gjson.String: + str = j.Str + default: + return defaultVal + } + } else if s, ok := p.(string); ok { + str = s + } + str = strings.ToLower(str) + switch str { + case "true", "yes", "1": + return true + case "false", "no", "0": + return false + default: + return defaultVal + } +} + +var ( + // once lazy compile the reg + once sync.Once + // reg is splitURL regex pattern. + reg *regexp.Regexp +) + +// SplitURL 将给定URL字符串分割为两部分,用于URL预处理防止风控 +func SplitURL(s string) []string { + once.Do(func() { // lazy init. + reg = regexp.MustCompile(`(?i)[a-z\d][-a-z\d]{0,62}(\.[a-z\d][-a-z\d]{0,62})+\.?`) + }) + idx := reg.FindAllStringIndex(s, -1) + if len(idx) == 0 { + return []string{s} + } + var result []string + last := 0 + for i := 0; i < len(idx); i++ { + if len(idx[i]) != 2 { + continue + } + m := int(math.Abs(float64(idx[i][0]-idx[i][1]))/1.5) + idx[i][0] + result = append(result, s[last:m]) + last = m + } + result = append(result, s[last:]) + return result +} + +// Base64DecodeString decode base64 with avx2 +// see https://github.com/segmentio/asm/issues/50 +// avoid incorrect unsafe usage in origin library +func Base64DecodeString(s string) ([]byte, error) { + e := base64.StdEncoding + dst := make([]byte, e.DecodedLen(len(s))) + n, err := e.Decode(dst, utils.S2B(s)) + return dst[:n], err +} + +// SetAtDefault 在变量 variable 为默认值 defaultValue 的时候修改为 value +func SetAtDefault(variable, value, defaultValue interface{}) { + v := reflect.ValueOf(variable) + v2 := reflect.ValueOf(value) + if v.Kind() != reflect.Ptr || v.IsNil() { + return + } + v = v.Elem() + if v.Interface() != defaultValue { + return + } + if v.Kind() != v2.Kind() { + return + } + v.Set(v2) +} + +// SetExcludeDefault 在目标值 value 不为默认值 defaultValue 时修改 variable 为 value +func SetExcludeDefault(variable, value, defaultValue interface{}) { + v := reflect.ValueOf(variable) + v2 := reflect.ValueOf(value) + if v.Kind() != reflect.Ptr || v.IsNil() { + return + } + v = v.Elem() + if reflect.Indirect(v2).Interface() != defaultValue { + return + } + if v.Kind() != v2.Kind() { + return + } + v.Set(v2) +} diff --git a/login.go b/login.go index 5e6c064..cdf39cb 100644 --- a/login.go +++ b/login.go @@ -18,7 +18,7 @@ import ( var console = bufio.NewReader(os.Stdin) -var readLine = func() (str string) { +func readLine() (str string) { str, _ = console.ReadString('\n') str = strings.TrimSpace(str) return diff --git a/main.go b/main.go index fbd17aa..ed0de4e 100644 --- a/main.go +++ b/main.go @@ -29,21 +29,16 @@ import ( "github.com/Mrs4s/go-cqhttp/coolq" "github.com/Mrs4s/go-cqhttp/global" - "github.com/Mrs4s/go-cqhttp/global/codec" "github.com/Mrs4s/go-cqhttp/global/config" "github.com/Mrs4s/go-cqhttp/global/terminal" "github.com/Mrs4s/go-cqhttp/global/update" + "github.com/Mrs4s/go-cqhttp/internal/base" "github.com/Mrs4s/go-cqhttp/server" ) var ( conf *config.Config isFastStart = false - // PasswordHash 存储QQ密码哈希供登录使用 - PasswordHash [16]byte - - // AccountToken 存储AccountToken供登录使用 - AccountToken []byte // 允许通过配置文件设置的状态列表 allowStatus = [...]client.UserOnlineStatus{ @@ -62,6 +57,7 @@ func main() { wd := flag.String("w", "", "cover the working directory") debug := flag.Bool("D", false, "debug mode") flag.Parse() + // todo: maybe move flag to internal/base? switch { case *h: @@ -78,9 +74,9 @@ func main() { if *debug { conf.Output.Debug = true } - if conf.Output.Debug { + base.Parse() + if base.Debug { log.SetReportCaller(true) - codec.Debug = true } rotateOptions := []rotatelogs.Option{ @@ -155,8 +151,8 @@ func main() { } } - log.Info("当前版本:", coolq.Version) - if conf.Output.Debug { + log.Info("当前版本:", base.Version) + if base.Debug { log.SetLevel(log.DebugLevel) log.Warnf("已开启Debug模式.") log.Debugf("开发交流群: 192548878") @@ -183,8 +179,8 @@ func main() { } log.Infof("密码加密已启用, 请输入Key对密码进行加密: (Enter 提交)") byteKey, _ = term.ReadPassword(int(os.Stdin.Fd())) - PasswordHash = md5.Sum([]byte(conf.Account.Password)) - _ = os.WriteFile("password.encrypt", []byte(PasswordHashEncrypt(PasswordHash[:], byteKey)), 0o644) + base.PasswordHash = md5.Sum([]byte(conf.Account.Password)) + _ = os.WriteFile("password.encrypt", []byte(PasswordHashEncrypt(base.PasswordHash[:], byteKey)), 0o644) log.Info("密码已加密,为了您的账号安全,请删除配置文件中的密码后重新启动.") readLine() os.Exit(0) @@ -221,10 +217,10 @@ func main() { if err != nil { log.Fatalf("加密存储的密码损坏,请尝试重新配置密码") } - copy(PasswordHash[:], ph) + copy(base.PasswordHash[:], ph) } } else if len(conf.Account.Password) > 0 { - PasswordHash = md5.Sum([]byte(conf.Account.Password)) + base.PasswordHash = md5.Sum([]byte(conf.Account.Password)) } if !isFastStart { log.Info("Bot将在5秒后登录并开始信息处理, 按 Ctrl+C 取消.") @@ -247,12 +243,11 @@ func main() { return "未知" }()) cli = newClient() - global.Proxy = conf.Message.ProxyRewrite isQRCodeLogin := (conf.Account.Uin == 0 || len(conf.Account.Password) == 0) && !conf.Account.Encrypt isTokenLogin := false saveToken := func() { - AccountToken = cli.GenToken() - _ = os.WriteFile("session.token", AccountToken, 0o644) + base.AccountToken = cli.GenToken() + _ = os.WriteFile("session.token", base.AccountToken, 0o644) } if global.PathExists("session.token") { token, err := os.ReadFile("session.token") @@ -285,9 +280,9 @@ func main() { } } } - if conf.Account.Uin != 0 && PasswordHash != [16]byte{} { + if conf.Account.Uin != 0 && base.PasswordHash != [16]byte{} { cli.Uin = conf.Account.Uin - cli.PasswordMd5 = PasswordHash + cli.PasswordMd5 = base.PasswordHash } if !isTokenLogin { if !isQRCodeLogin { @@ -331,7 +326,7 @@ func main() { break } log.Warnf("尝试重连...") - err := cli.TokenLogin(AccountToken) + err := cli.TokenLogin(base.AccountToken) if err == nil { saveToken() return @@ -371,12 +366,6 @@ func main() { } else { coolq.SetMessageFormat(conf.Message.PostFormat) } - coolq.IgnoreInvalidCQCode = conf.Message.IgnoreInvalidCQCode - coolq.SplitURL = conf.Message.FixURL - coolq.ForceFragmented = conf.Message.ForceFragment - coolq.RemoveReplyAt = conf.Message.RemoveReplyAt - coolq.ExtraReplyData = conf.Message.ExtraReplyData - coolq.SkipMimeScan = conf.Message.SkipMimeScan for _, m := range conf.Servers { if h, ok := m["http"]; ok { hc := new(config.HTTPServer) @@ -460,7 +449,7 @@ func PasswordHashDecrypt(encryptedPasswordHash string, key []byte) ([]byte, erro func checkUpdate() { log.Infof("正在检查更新.") - if coolq.Version == "(devel)" { + if base.Version == "(devel)" { log.Warnf("检查更新失败: 使用的 Actions 测试版或自编译版本.") return } @@ -470,9 +459,9 @@ func checkUpdate() { return } info := gjson.Parse(utils.B2S(r)) - if global.VersionNameCompare(coolq.Version, info.Get("tag_name").Str) { + if global.VersionNameCompare(base.Version, info.Get("tag_name").Str) { log.Infof("当前有更新的 go-cqhttp 可供更新, 请前往 https://github.com/Mrs4s/go-cqhttp/releases 下载.") - log.Infof("当前版本: %v 最新版本: %v", coolq.Version, info.Get("tag_name").Str) + log.Infof("当前版本: %v 最新版本: %v", base.Version, info.Get("tag_name").Str) return } log.Infof("检查更新完成. 当前已运行最新版本.") @@ -488,7 +477,7 @@ func selfUpdate(imageURL string) { } info := gjson.Parse(utils.B2S(res)) version := info.Get("tag_name").Str - if coolq.Version == version { + if base.Version == version { log.Info("当前版本已经是最新版本!") goto wait } @@ -556,39 +545,6 @@ wait: os.Exit(0) } -/* -func restart(args []string) { - var cmd *exec.Cmd - if runtime.GOOS == "windows" { - file, err := exec.LookPath(args[0]) - if err != nil { - log.Errorf("重启失败:%s", err.Error()) - return - } - path, err := filepath.Abs(file) - if err != nil { - log.Errorf("重启失败:%s", err.Error()) - } - args = append([]string{"/c", "start ", path, "faststart"}, args[1:]...) - cmd = &exec.Cmd{ - Path: "cmd.exe", - Args: args, - Stderr: os.Stderr, - Stdout: os.Stdout, - } - } else { - args = append(args, "faststart") - cmd = &exec.Cmd{ - Path: args[0], - Args: args, - Stderr: os.Stderr, - Stdout: os.Stdout, - } - } - _ = cmd.Start() -} -*/ - // help cli命令行-h的帮助提示 func help() { fmt.Printf(`go-cqhttp service @@ -599,7 +555,7 @@ Usage: server [OPTIONS] Options: -`, coolq.Version) +`, base.Version) flag.PrintDefaults() os.Exit(0) diff --git a/server/api.go b/server/api.go index f4f1002..126a76e 100644 --- a/server/api.go +++ b/server/api.go @@ -5,6 +5,7 @@ import ( "github.com/Mrs4s/go-cqhttp/coolq" "github.com/Mrs4s/go-cqhttp/global" + "github.com/Mrs4s/go-cqhttp/internal/param" "github.com/tidwall/gjson" ) @@ -63,7 +64,7 @@ func getGroupMemberInfo(bot *coolq.CQBot, p resultGetter) global.MSG { } func sendMSG(bot *coolq.CQBot, p resultGetter) global.MSG { - autoEscape := global.EnsureBool(p.Get("auto_escape"), false) + autoEscape := param.EnsureBool(p.Get("auto_escape"), false) if p.Get("message_type").Str == "private" { return bot.CQSendPrivateMessage(p.Get("user_id").Int(), p.Get("group_id").Int(), p.Get("message"), autoEscape) } @@ -81,7 +82,7 @@ func sendMSG(bot *coolq.CQBot, p resultGetter) global.MSG { func sendGroupMSG(bot *coolq.CQBot, p resultGetter) global.MSG { return bot.CQSendGroupMessage(p.Get("group_id").Int(), p.Get("message"), - global.EnsureBool(p.Get("auto_escape"), false)) + param.EnsureBool(p.Get("auto_escape"), false)) } func sendGroupForwardMSG(bot *coolq.CQBot, p resultGetter) global.MSG { @@ -90,7 +91,7 @@ func sendGroupForwardMSG(bot *coolq.CQBot, p resultGetter) global.MSG { func sendPrivateMSG(bot *coolq.CQBot, p resultGetter) global.MSG { return bot.CQSendPrivateMessage(p.Get("user_id").Int(), p.Get("group_id").Int(), p.Get("message"), - global.EnsureBool(p.Get("auto_escape"), false)) + param.EnsureBool(p.Get("auto_escape"), false)) } func deleteMSG(bot *coolq.CQBot, p resultGetter) global.MSG {