[perf]: 优化登录检查 (#203)
This commit is contained in:
parent
1eadbf8be6
commit
53478bad19
23
bot.go
23
bot.go
@ -6,19 +6,20 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
"net/url"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Bot struct {
|
type Bot struct {
|
||||||
ScanCallBack func(body []byte) // 扫码回调,可获取扫码用户的头像
|
ScanCallBack func(body CheckLoginResponse) // 扫码回调,可获取扫码用户的头像
|
||||||
LoginCallBack func(body []byte) // 登陆回调
|
LoginCallBack func(body CheckLoginResponse) // 登陆回调
|
||||||
LogoutCallBack func(bot *Bot) // 退出回调
|
LogoutCallBack func(bot *Bot) // 退出回调
|
||||||
UUIDCallback func(uuid string) // 获取UUID的回调函数
|
UUIDCallback func(uuid string) // 获取UUID的回调函数
|
||||||
SyncCheckCallback func(resp SyncCheckResponse) // 心跳回调
|
SyncCheckCallback func(resp SyncCheckResponse) // 心跳回调
|
||||||
MessageHandler MessageHandler // 获取消息成功的handle
|
MessageHandler MessageHandler // 获取消息成功的handle
|
||||||
MessageErrorHandler func(err error) bool // 获取消息发生错误的handle, 返回true则尝试继续监听
|
MessageErrorHandler func(err error) bool // 获取消息发生错误的handle, 返回true则尝试继续监听
|
||||||
once sync.Once
|
once sync.Once
|
||||||
err error
|
err error
|
||||||
context context.Context
|
context context.Context
|
||||||
@ -121,9 +122,9 @@ func (b *Bot) Logout() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HandleLogin 登录逻辑
|
// HandleLogin 登录逻辑
|
||||||
func (b *Bot) HandleLogin(data []byte) error {
|
func (b *Bot) HandleLogin(path *url.URL) error {
|
||||||
// 获取登录的一些基本的信息
|
// 获取登录的一些基本的信息
|
||||||
info, err := b.Caller.GetLoginInfo(data)
|
info, err := b.Caller.GetLoginInfo(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -346,11 +347,11 @@ func DefaultBot(prepares ...BotPreparer) *Bot {
|
|||||||
// 获取二维码回调
|
// 获取二维码回调
|
||||||
bot.UUIDCallback = PrintlnQrcodeUrl
|
bot.UUIDCallback = PrintlnQrcodeUrl
|
||||||
// 扫码回调
|
// 扫码回调
|
||||||
bot.ScanCallBack = func(body []byte) {
|
bot.ScanCallBack = func(_ CheckLoginResponse) {
|
||||||
log.Println("扫码成功,请在手机上确认登录")
|
log.Println("扫码成功,请在手机上确认登录")
|
||||||
}
|
}
|
||||||
// 登录回调
|
// 登录回调
|
||||||
bot.LoginCallBack = func(body []byte) {
|
bot.LoginCallBack = func(_ CheckLoginResponse) {
|
||||||
log.Println("登录成功")
|
log.Println("登录成功")
|
||||||
}
|
}
|
||||||
// 心跳回调函数
|
// 心跳回调函数
|
||||||
|
20
bot_login.go
20
bot_login.go
@ -225,8 +225,8 @@ type LoginChecker struct {
|
|||||||
Bot *Bot
|
Bot *Bot
|
||||||
Tip string
|
Tip string
|
||||||
UUIDCallback func(uuid string)
|
UUIDCallback func(uuid string)
|
||||||
LoginCallBack func(body []byte)
|
LoginCallBack func(body CheckLoginResponse)
|
||||||
ScanCallBack func(body []byte)
|
ScanCallBack func(body CheckLoginResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *LoginChecker) CheckLogin() error {
|
func (l *LoginChecker) CheckLogin() error {
|
||||||
@ -242,23 +242,31 @@ func (l *LoginChecker) CheckLogin() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
code, err := resp.Code()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if tip == "1" {
|
if tip == "1" {
|
||||||
tip = "0"
|
tip = "0"
|
||||||
}
|
}
|
||||||
switch resp.Code {
|
switch code {
|
||||||
case StatusSuccess:
|
case StatusSuccess:
|
||||||
// 判断是否有登录回调,如果有执行它
|
// 判断是否有登录回调,如果有执行它
|
||||||
if err = l.Bot.HandleLogin(resp.Raw); err != nil {
|
redirectURL, err := resp.RedirectURL()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = l.Bot.HandleLogin(redirectURL); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if cb := l.LoginCallBack; cb != nil {
|
if cb := l.LoginCallBack; cb != nil {
|
||||||
cb(resp.Raw)
|
cb(resp)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
case StatusScanned:
|
case StatusScanned:
|
||||||
// 执行扫码回调
|
// 执行扫码回调
|
||||||
if cb := l.ScanCallBack; cb != nil {
|
if cb := l.ScanCallBack; cb != nil {
|
||||||
cb(resp.Raw)
|
cb(resp)
|
||||||
}
|
}
|
||||||
case StatusTimeout:
|
case StatusTimeout:
|
||||||
return ErrLoginTimeout
|
return ErrLoginTimeout
|
||||||
|
24
caller.go
24
caller.go
@ -50,7 +50,7 @@ func (c *Caller) GetLoginUUID() (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CheckLogin 检查是否登录成功
|
// CheckLogin 检查是否登录成功
|
||||||
func (c *Caller) CheckLogin(uuid, tip string) (*CheckLoginResponse, error) {
|
func (c *Caller) CheckLogin(uuid, tip string) (CheckLoginResponse, error) {
|
||||||
resp, err := c.Client.CheckLogin(uuid, tip)
|
resp, err := c.Client.CheckLogin(uuid, tip)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -61,29 +61,13 @@ func (c *Caller) CheckLogin(uuid, tip string) (*CheckLoginResponse, error) {
|
|||||||
if _, err := buffer.ReadFrom(resp.Body); err != nil {
|
if _, err := buffer.ReadFrom(resp.Body); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// 正则匹配检测的code
|
return buffer.Bytes(), nil
|
||||||
// 具体code参考global.go
|
|
||||||
results := statusCodeRegexp.FindSubmatch(buffer.Bytes())
|
|
||||||
if len(results) != 2 {
|
|
||||||
return nil, errors.New("error status code match")
|
|
||||||
}
|
|
||||||
code := string(results[1])
|
|
||||||
return &CheckLoginResponse{Code: code, Raw: buffer.Bytes()}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLoginInfo 获取登录信息
|
// GetLoginInfo 获取登录信息
|
||||||
func (c *Caller) GetLoginInfo(body []byte) (*LoginInfo, error) {
|
func (c *Caller) GetLoginInfo(path *url.URL) (*LoginInfo, error) {
|
||||||
// 从响应体里面获取需要跳转的url
|
// 从响应体里面获取需要跳转的url
|
||||||
results := redirectUriRegexp.FindSubmatch(body)
|
resp, err := c.Client.GetLoginInfo(path)
|
||||||
if len(results) != 2 {
|
|
||||||
return nil, errors.New("redirect url does not match")
|
|
||||||
}
|
|
||||||
path, err := url.Parse(string(results[1]))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
c.Client.Domain = WechatDomain(path.Host)
|
|
||||||
resp, err := c.Client.GetLoginInfo(path.String())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -133,8 +133,9 @@ func (c *Client) CheckLogin(uuid, tip string) (*http.Response, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetLoginInfo 请求获取LoginInfo
|
// GetLoginInfo 请求获取LoginInfo
|
||||||
func (c *Client) GetLoginInfo(path string) (*http.Response, error) {
|
func (c *Client) GetLoginInfo(path *url.URL) (*http.Response, error) {
|
||||||
return c.mode.GetLoginInfo(c, path)
|
c.Domain = WechatDomain(path.Host)
|
||||||
|
return c.mode.GetLoginInfo(c, path.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// WebInit 请求获取初始化信息
|
// WebInit 请求获取初始化信息
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
uuidRegexp = regexp.MustCompile(`uuid = "(.*?)";`)
|
uuidRegexp = regexp.MustCompile(`uuid = "(.*?)";`)
|
||||||
statusCodeRegexp = regexp.MustCompile(`window.code=(\d+);`)
|
statusCodeRegexp = regexp.MustCompile(`window.code=(\d+);`)
|
||||||
|
avatarRegexp = regexp.MustCompile(`window.userAvatar = '(.*)';`)
|
||||||
syncCheckRegexp = regexp.MustCompile(`window.synccheck=\{retcode:"(\d+)",selector:"(\d+)"\}`)
|
syncCheckRegexp = regexp.MustCompile(`window.synccheck=\{retcode:"(\d+)",selector:"(\d+)"\}`)
|
||||||
redirectUriRegexp = regexp.MustCompile(`window.redirect_uri="(.*?)"`)
|
redirectUriRegexp = regexp.MustCompile(`window.redirect_uri="(.*?)"`)
|
||||||
)
|
)
|
||||||
|
48
items.go
48
items.go
@ -2,6 +2,8 @@ package openwechat
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -117,9 +119,49 @@ type WebWxBatchContactResponse struct {
|
|||||||
ContactList []*User
|
ContactList []*User
|
||||||
}
|
}
|
||||||
|
|
||||||
type CheckLoginResponse struct {
|
// CheckLoginResponse 检查登录状态的响应body
|
||||||
Code string
|
type CheckLoginResponse []byte
|
||||||
Raw []byte
|
|
||||||
|
// RedirectURL 重定向的URL
|
||||||
|
func (c CheckLoginResponse) RedirectURL() (*url.URL, error) {
|
||||||
|
code, err := c.Code()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if code != StatusSuccess {
|
||||||
|
return nil, fmt.Errorf("expect status code %s, but got %s", StatusSuccess, code)
|
||||||
|
}
|
||||||
|
results := redirectUriRegexp.FindSubmatch(c)
|
||||||
|
if len(results) != 2 {
|
||||||
|
return nil, errors.New("redirect url does not match")
|
||||||
|
}
|
||||||
|
return url.Parse(string(results[1]))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code 获取当前的登录检查状态的代码
|
||||||
|
func (c CheckLoginResponse) Code() (string, error) {
|
||||||
|
results := statusCodeRegexp.FindSubmatch(c)
|
||||||
|
if len(results) != 2 {
|
||||||
|
return "", errors.New("error status code match")
|
||||||
|
}
|
||||||
|
code := string(results[1])
|
||||||
|
return code, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avatar 获取扫码后的用户头像, base64编码
|
||||||
|
func (c CheckLoginResponse) Avatar() (string, error) {
|
||||||
|
code, err := c.Code()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if code != StatusScanned {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
results := avatarRegexp.FindSubmatch(c)
|
||||||
|
if len(results) != 2 {
|
||||||
|
return "", errors.New("avatar does not match")
|
||||||
|
}
|
||||||
|
return string(results[1]), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type MessageResponse struct {
|
type MessageResponse struct {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user