mirror of
https://github.com/Mrs4s/go-cqhttp.git
synced 2025-06-18 21:45:04 +08:00
optimize(qisgn): async operations
FYI: @1umine
This commit is contained in:
parent
79a194fbb0
commit
fd6ef4a2b8
@ -163,7 +163,6 @@ func LoginInteract() {
|
|||||||
log.Fatalf("加载设备信息失败: %v", err)
|
log.Fatalf("加载设备信息失败: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
initSignServersConfig()
|
|
||||||
signServer, err := getAvaliableSignServer() // 获取可用签名服务器
|
signServer, err := getAvaliableSignServer() // 获取可用签名服务器
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn(err)
|
log.Warn(err)
|
||||||
|
@ -24,76 +24,59 @@ import (
|
|||||||
"github.com/Mrs4s/go-cqhttp/modules/config"
|
"github.com/Mrs4s/go-cqhttp/modules/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
type currentSignServer struct {
|
type currentSignServer atomic.Pointer[config.SignServer]
|
||||||
server *config.SignServer
|
|
||||||
ok bool
|
func (c *currentSignServer) get() *config.SignServer {
|
||||||
lock sync.RWMutex
|
return (*atomic.Pointer[config.SignServer])(c).Load()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *currentSignServer) getServer() *config.SignServer {
|
func (c *currentSignServer) set(server *config.SignServer) {
|
||||||
c.lock.RLock()
|
(*atomic.Pointer[config.SignServer])(c).Store(server)
|
||||||
defer c.lock.RUnlock()
|
|
||||||
return c.server
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *currentSignServer) isOK() bool {
|
|
||||||
c.lock.RLock()
|
|
||||||
defer c.lock.RUnlock()
|
|
||||||
return c.ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *currentSignServer) setServer(server *config.SignServer, status bool) {
|
|
||||||
c.lock.Lock()
|
|
||||||
defer c.lock.Unlock()
|
|
||||||
if server != nil {
|
|
||||||
c.server = server
|
|
||||||
}
|
|
||||||
c.ok = status
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 当前签名服务器
|
// 当前签名服务器
|
||||||
var curSignServer *currentSignServer
|
var ss currentSignServer
|
||||||
var errorCount = uintptr(0)
|
|
||||||
var checkLock sync.Mutex
|
|
||||||
|
|
||||||
func initSignServersConfig() {
|
// 失败计数
|
||||||
if len(base.SignServers) == 0 {
|
type errconut atomic.Uintptr
|
||||||
log.Warn("no configured sign-server")
|
|
||||||
return
|
func (ec *errconut) hasOver(count uintptr) bool {
|
||||||
}
|
return (*atomic.Uintptr)(ec).Load() > count
|
||||||
if len(base.SignServers) > 5 {
|
|
||||||
base.SignServers = base.SignServers[:5]
|
|
||||||
log.Warn("签名服务器数量配置过多,可能导致不可用时检查时间过久,已取前 5 个")
|
|
||||||
}
|
|
||||||
curSignServer = ¤tSignServer{
|
|
||||||
server: &base.SignServers[0],
|
|
||||||
ok: true,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *errconut) inc() {
|
||||||
|
(*atomic.Uintptr)(ec).Add(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var errn errconut
|
||||||
|
|
||||||
// getAvaliableSignServer 获取可用的签名服务器,没有则返回空和相应错误
|
// getAvaliableSignServer 获取可用的签名服务器,没有则返回空和相应错误
|
||||||
func getAvaliableSignServer() (config.SignServer, error) {
|
func getAvaliableSignServer() (*config.SignServer, error) {
|
||||||
if curSignServer.isOK() {
|
cs := ss.get()
|
||||||
return *curSignServer.getServer(), nil
|
if cs != nil {
|
||||||
|
return cs, nil
|
||||||
|
}
|
||||||
|
if len(base.SignServers) == 0 {
|
||||||
|
return nil, errors.New("no sign server configured")
|
||||||
}
|
}
|
||||||
maxCount := base.Account.MaxCheckCount
|
maxCount := base.Account.MaxCheckCount
|
||||||
if maxCount == 0 && atomic.LoadUintptr(&errorCount) >= 3 {
|
if maxCount == 0 {
|
||||||
|
if errn.hasOver(3) {
|
||||||
log.Warn("已连续 3 次获取不到可用签名服务器,将固定使用主签名服务器")
|
log.Warn("已连续 3 次获取不到可用签名服务器,将固定使用主签名服务器")
|
||||||
curSignServer.setServer(&base.SignServers[0], true)
|
ss.set(&base.SignServers[0])
|
||||||
return *curSignServer.getServer(), nil
|
return ss.get(), nil
|
||||||
}
|
}
|
||||||
if maxCount > 0 && int(atomic.LoadUintptr(&errorCount)) >= maxCount {
|
} else if errn.hasOver(uintptr(maxCount)) {
|
||||||
log.Fatalf("获取可用签名服务器失败次数超过 %v 次, 正在离线", maxCount)
|
log.Fatalf("获取可用签名服务器失败次数超过 %v 次, 正在离线", maxCount)
|
||||||
}
|
}
|
||||||
if checkLock.TryLock() {
|
if len(cs.URL) > 0 {
|
||||||
defer checkLock.Unlock()
|
|
||||||
cs := curSignServer.getServer()
|
|
||||||
if len(cs.URL) > 1 {
|
|
||||||
log.Warnf("当前签名服务器 %v 不可用,正在查找可用服务器", cs.URL)
|
log.Warnf("当前签名服务器 %v 不可用,正在查找可用服务器", cs.URL)
|
||||||
}
|
}
|
||||||
return syncCheckServer(base.SignServers)
|
cs = asyncCheckServer(base.SignServers)
|
||||||
|
if cs == nil {
|
||||||
|
return nil, errors.New("no usable sign server")
|
||||||
}
|
}
|
||||||
return config.SignServer{}, errors.New("checking sign-servers")
|
return cs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func isServerAvaliable(signServer string) bool {
|
func isServerAvaliable(signServer string) bool {
|
||||||
@ -108,25 +91,31 @@ func isServerAvaliable(signServer string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// syncCheckServer 按同步顺序检查所有签名服务器直到找到可用的
|
// asyncCheckServer 按同步顺序检查所有签名服务器直到找到可用的
|
||||||
func syncCheckServer(servers []config.SignServer) (config.SignServer, error) {
|
func asyncCheckServer(servers []config.SignServer) *config.SignServer {
|
||||||
for i, server := range servers {
|
doRegister := sync.Once{}
|
||||||
|
wg := sync.WaitGroup{}
|
||||||
|
wg.Add(len(servers))
|
||||||
|
for i, s := range servers {
|
||||||
|
go func(i int, server config.SignServer) {
|
||||||
|
defer wg.Done()
|
||||||
log.Infof("检查签名服务器:%v (%v/%v)", server.URL, i+1, len(servers))
|
log.Infof("检查签名服务器:%v (%v/%v)", server.URL, i+1, len(servers))
|
||||||
if len(server.URL) < 4 {
|
if len(server.URL) < 4 {
|
||||||
continue
|
return
|
||||||
}
|
}
|
||||||
if isServerAvaliable(server.URL) {
|
if isServerAvaliable(server.URL) {
|
||||||
atomic.StoreUintptr(&errorCount, 0)
|
doRegister.Do(func() {
|
||||||
curSignServer.setServer(&server, true)
|
ss.set(&server)
|
||||||
log.Infof("使用签名服务器 url=%v, key=%v, auth=%v", server.URL, server.Key, server.Authorization)
|
log.Infof("使用签名服务器 url=%v, key=%v, auth=%v", server.URL, server.Key, server.Authorization)
|
||||||
if base.Account.AutoRegister {
|
if base.Account.AutoRegister {
|
||||||
// 若配置了自动注册实例则在切换后注册实例,否则不需要注册,签名时由qsign自动注册
|
// 若配置了自动注册实例则在切换后注册实例,否则不需要注册,签名时由qsign自动注册
|
||||||
signRegister(base.Account.Uin, device.AndroidId, device.Guid, device.QImei36, server.Key)
|
signRegister(base.Account.Uin, device.AndroidId, device.Guid, device.QImei36, server.Key)
|
||||||
}
|
}
|
||||||
return server, nil
|
})
|
||||||
}
|
}
|
||||||
|
}(i, s)
|
||||||
}
|
}
|
||||||
return config.SignServer{}, errors.New("no avaliable sign-server")
|
return ss.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -137,10 +126,10 @@ func syncCheckServer(servers []config.SignServer) (config.SignServer, error) {
|
|||||||
*/
|
*/
|
||||||
func requestSignServer(method string, url string, headers map[string]string, body io.Reader) (string, []byte, error) {
|
func requestSignServer(method string, url string, headers map[string]string, body io.Reader) (string, []byte, error) {
|
||||||
signServer, e := getAvaliableSignServer()
|
signServer, e := getAvaliableSignServer()
|
||||||
if e != nil && len(signServer.URL) <= 1 { // 没有可用的
|
if e != nil && len(signServer.URL) == 0 { // 没有可用的
|
||||||
log.Warnf("获取可用签名服务器出错:%v, 将使用主签名服务器进行签名", e)
|
log.Warnf("获取可用签名服务器出错:%v, 将使用主签名服务器进行签名", e)
|
||||||
atomic.AddUintptr(&errorCount, 1)
|
errn.inc()
|
||||||
signServer = base.SignServers[0] // 没有获取到时使用第一个
|
signServer = &base.SignServers[0] // 没有获取到时使用第一个
|
||||||
}
|
}
|
||||||
if !strings.HasPrefix(url, signServer.URL) {
|
if !strings.HasPrefix(url, signServer.URL) {
|
||||||
url = strings.TrimSuffix(signServer.URL, "/") + "/" + strings.TrimPrefix(url, "/")
|
url = strings.TrimSuffix(signServer.URL, "/") + "/" + strings.TrimPrefix(url, "/")
|
||||||
@ -160,7 +149,7 @@ func requestSignServer(method string, url string, headers map[string]string, bod
|
|||||||
}.WithTimeout(time.Duration(base.SignServerTimeout) * time.Second)
|
}.WithTimeout(time.Duration(base.SignServerTimeout) * time.Second)
|
||||||
resp, err := req.Bytes()
|
resp, err := req.Bytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
curSignServer.setServer(nil, false) // 标记为不可用
|
ss.set(nil) // 标记为不可用
|
||||||
}
|
}
|
||||||
return signServer.URL, resp, err
|
return signServer.URL, resp, err
|
||||||
}
|
}
|
||||||
@ -298,7 +287,7 @@ var lastToken = ""
|
|||||||
func sign(seq uint64, uin string, cmd string, qua string, buff []byte) (sign []byte, extra []byte, token []byte, err error) {
|
func sign(seq uint64, uin string, cmd string, qua string, buff []byte) (sign []byte, extra []byte, token []byte, err error) {
|
||||||
i := 0
|
i := 0
|
||||||
for {
|
for {
|
||||||
cs := curSignServer.getServer()
|
cs := ss.get()
|
||||||
sign, extra, token, err = signRequset(seq, uin, cmd, qua, buff)
|
sign, extra, token, err = signRequset(seq, uin, cmd, qua, buff)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("获取sso sign时出现错误: %v. server: %v", err, cs.URL)
|
log.Warnf("获取sso sign时出现错误: %v. server: %v", err, cs.URL)
|
||||||
@ -343,7 +332,7 @@ func sign(seq uint64, uin string, cmd string, qua string, buff []byte) (sign []b
|
|||||||
}
|
}
|
||||||
rule := base.Account.RuleChangeSignServer
|
rule := base.Account.RuleChangeSignServer
|
||||||
if (len(sign) == 0 && rule >= 1) || (len(token) == 0 && rule >= 2) {
|
if (len(sign) == 0 && rule >= 1) || (len(token) == 0 && rule >= 2) {
|
||||||
curSignServer.setServer(nil, false)
|
ss.set(nil)
|
||||||
}
|
}
|
||||||
return sign, extra, token, err
|
return sign, extra, token, err
|
||||||
}
|
}
|
||||||
@ -358,7 +347,7 @@ func signServerDestroy(uin string) error {
|
|||||||
}
|
}
|
||||||
signServer, resp, err := requestSignServer(
|
signServer, resp, err := requestSignServer(
|
||||||
http.MethodGet,
|
http.MethodGet,
|
||||||
"destroy"+fmt.Sprintf("?uin=%v&key=%v", uin, curSignServer.getServer().Key),
|
"destroy"+fmt.Sprintf("?uin=%v&key=%v", uin, ss.get().Key),
|
||||||
nil, nil,
|
nil, nil,
|
||||||
)
|
)
|
||||||
if err != nil || gjson.GetBytes(resp, "code").Int() != 0 {
|
if err != nil || gjson.GetBytes(resp, "code").Int() != 0 {
|
||||||
@ -396,9 +385,9 @@ func signStartRefreshToken(interval int64) {
|
|||||||
qqstr := strconv.FormatInt(base.Account.Uin, 10)
|
qqstr := strconv.FormatInt(base.Account.Uin, 10)
|
||||||
defer t.Stop()
|
defer t.Stop()
|
||||||
for range t.C {
|
for range t.C {
|
||||||
cs, master := curSignServer.getServer(), base.SignServers[0]
|
cs, master := ss.get(), base.SignServers[0]
|
||||||
if cs.URL != master.URL && isServerAvaliable(master.URL) {
|
if cs.URL != master.URL && isServerAvaliable(master.URL) {
|
||||||
curSignServer.setServer(&master, true)
|
ss.set(&master)
|
||||||
log.Infof("主签名服务器可用,已切换至主签名服务器 %v", cs.URL)
|
log.Infof("主签名服务器可用,已切换至主签名服务器 %v", cs.URL)
|
||||||
}
|
}
|
||||||
err := signRefreshToken(qqstr)
|
err := signRefreshToken(qqstr)
|
||||||
|
@ -93,7 +93,7 @@ func Init() {
|
|||||||
SignServers = conf.Account.SignServers
|
SignServers = conf.Account.SignServers
|
||||||
IsBelow110 = conf.Account.IsBelow110
|
IsBelow110 = conf.Account.IsBelow110
|
||||||
HTTPTimeout = conf.Message.HTTPTimeout
|
HTTPTimeout = conf.Message.HTTPTimeout
|
||||||
SignServerTimeout = conf.Account.SignServerTimeout
|
SignServerTimeout = int(conf.Account.SignServerTimeout)
|
||||||
}
|
}
|
||||||
{ // others
|
{ // others
|
||||||
Proxy = conf.Message.ProxyRewrite
|
Proxy = conf.Message.ProxyRewrite
|
||||||
|
@ -37,8 +37,8 @@ type Account struct {
|
|||||||
AllowTempSession bool `yaml:"allow-temp-session"`
|
AllowTempSession bool `yaml:"allow-temp-session"`
|
||||||
SignServers []SignServer `yaml:"sign-servers"`
|
SignServers []SignServer `yaml:"sign-servers"`
|
||||||
RuleChangeSignServer int `yaml:"rule-change-sign-server"`
|
RuleChangeSignServer int `yaml:"rule-change-sign-server"`
|
||||||
MaxCheckCount int `yaml:"max-check-count"`
|
MaxCheckCount uint `yaml:"max-check-count"`
|
||||||
SignServerTimeout int `yaml:"sign-server-timeout"`
|
SignServerTimeout uint `yaml:"sign-server-timeout"`
|
||||||
IsBelow110 bool `yaml:"is-below-110"`
|
IsBelow110 bool `yaml:"is-below-110"`
|
||||||
AutoRegister bool `yaml:"auto-register"`
|
AutoRegister bool `yaml:"auto-register"`
|
||||||
AutoRefreshToken bool `yaml:"auto-refresh-token"`
|
AutoRefreshToken bool `yaml:"auto-refresh-token"`
|
||||||
|
Loading…
x
Reference in New Issue
Block a user