From 53478bad197b3b3901ccb8f2ff013bd04f0ebe45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=9A=E5=90=83=E7=82=B9=E8=8B=B9=E6=9E=9C?= <73388495+eatmoreapple@users.noreply.github.com> Date: Fri, 13 Jan 2023 19:44:15 +0800 Subject: [PATCH] =?UTF-8?q?[perf]:=20=E4=BC=98=E5=8C=96=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E6=A3=80=E6=9F=A5=20(#203)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bot.go | 23 ++++++++++++----------- bot_login.go | 20 ++++++++++++++------ caller.go | 24 ++++-------------------- client.go | 5 +++-- global.go | 1 + items.go | 48 +++++++++++++++++++++++++++++++++++++++++++++--- 6 files changed, 79 insertions(+), 42 deletions(-) diff --git a/bot.go b/bot.go index 2908d17..2e64bfd 100644 --- a/bot.go +++ b/bot.go @@ -6,19 +6,20 @@ import ( "errors" "io" "log" + "net/url" "os/exec" "runtime" "sync" ) type Bot struct { - ScanCallBack func(body []byte) // 扫码回调,可获取扫码用户的头像 - LoginCallBack func(body []byte) // 登陆回调 - LogoutCallBack func(bot *Bot) // 退出回调 - UUIDCallback func(uuid string) // 获取UUID的回调函数 - SyncCheckCallback func(resp SyncCheckResponse) // 心跳回调 - MessageHandler MessageHandler // 获取消息成功的handle - MessageErrorHandler func(err error) bool // 获取消息发生错误的handle, 返回true则尝试继续监听 + ScanCallBack func(body CheckLoginResponse) // 扫码回调,可获取扫码用户的头像 + LoginCallBack func(body CheckLoginResponse) // 登陆回调 + LogoutCallBack func(bot *Bot) // 退出回调 + UUIDCallback func(uuid string) // 获取UUID的回调函数 + SyncCheckCallback func(resp SyncCheckResponse) // 心跳回调 + MessageHandler MessageHandler // 获取消息成功的handle + MessageErrorHandler func(err error) bool // 获取消息发生错误的handle, 返回true则尝试继续监听 once sync.Once err error context context.Context @@ -121,9 +122,9 @@ func (b *Bot) Logout() error { } // 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 { return err } @@ -346,11 +347,11 @@ func DefaultBot(prepares ...BotPreparer) *Bot { // 获取二维码回调 bot.UUIDCallback = PrintlnQrcodeUrl // 扫码回调 - bot.ScanCallBack = func(body []byte) { + bot.ScanCallBack = func(_ CheckLoginResponse) { log.Println("扫码成功,请在手机上确认登录") } // 登录回调 - bot.LoginCallBack = func(body []byte) { + bot.LoginCallBack = func(_ CheckLoginResponse) { log.Println("登录成功") } // 心跳回调函数 diff --git a/bot_login.go b/bot_login.go index 18151ba..9fd1ca7 100644 --- a/bot_login.go +++ b/bot_login.go @@ -225,8 +225,8 @@ type LoginChecker struct { Bot *Bot Tip string UUIDCallback func(uuid string) - LoginCallBack func(body []byte) - ScanCallBack func(body []byte) + LoginCallBack func(body CheckLoginResponse) + ScanCallBack func(body CheckLoginResponse) } func (l *LoginChecker) CheckLogin() error { @@ -242,23 +242,31 @@ func (l *LoginChecker) CheckLogin() error { if err != nil { return err } + code, err := resp.Code() + if err != nil { + return err + } if tip == "1" { tip = "0" } - switch resp.Code { + switch code { 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 } if cb := l.LoginCallBack; cb != nil { - cb(resp.Raw) + cb(resp) } return nil case StatusScanned: // 执行扫码回调 if cb := l.ScanCallBack; cb != nil { - cb(resp.Raw) + cb(resp) } case StatusTimeout: return ErrLoginTimeout diff --git a/caller.go b/caller.go index 422feee..916ac51 100644 --- a/caller.go +++ b/caller.go @@ -50,7 +50,7 @@ func (c *Caller) GetLoginUUID() (string, error) { } // 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) if err != nil { return nil, err @@ -61,29 +61,13 @@ func (c *Caller) CheckLogin(uuid, tip string) (*CheckLoginResponse, error) { if _, err := buffer.ReadFrom(resp.Body); err != nil { return nil, err } - // 正则匹配检测的code - // 具体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 + return buffer.Bytes(), nil } // GetLoginInfo 获取登录信息 -func (c *Caller) GetLoginInfo(body []byte) (*LoginInfo, error) { +func (c *Caller) GetLoginInfo(path *url.URL) (*LoginInfo, error) { // 从响应体里面获取需要跳转的url - results := redirectUriRegexp.FindSubmatch(body) - 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()) + resp, err := c.Client.GetLoginInfo(path) if err != nil { return nil, err } diff --git a/client.go b/client.go index d6de48d..5361932 100644 --- a/client.go +++ b/client.go @@ -133,8 +133,9 @@ func (c *Client) CheckLogin(uuid, tip string) (*http.Response, error) { } // GetLoginInfo 请求获取LoginInfo -func (c *Client) GetLoginInfo(path string) (*http.Response, error) { - return c.mode.GetLoginInfo(c, path) +func (c *Client) GetLoginInfo(path *url.URL) (*http.Response, error) { + c.Domain = WechatDomain(path.Host) + return c.mode.GetLoginInfo(c, path.String()) } // WebInit 请求获取初始化信息 diff --git a/global.go b/global.go index 3510c89..bb68cb4 100644 --- a/global.go +++ b/global.go @@ -7,6 +7,7 @@ import ( var ( uuidRegexp = regexp.MustCompile(`uuid = "(.*?)";`) statusCodeRegexp = regexp.MustCompile(`window.code=(\d+);`) + avatarRegexp = regexp.MustCompile(`window.userAvatar = '(.*)';`) syncCheckRegexp = regexp.MustCompile(`window.synccheck=\{retcode:"(\d+)",selector:"(\d+)"\}`) redirectUriRegexp = regexp.MustCompile(`window.redirect_uri="(.*?)"`) ) diff --git a/items.go b/items.go index 485c464..11bd4dd 100644 --- a/items.go +++ b/items.go @@ -2,6 +2,8 @@ package openwechat import ( "errors" + "fmt" + "net/url" ) /* @@ -117,9 +119,49 @@ type WebWxBatchContactResponse struct { ContactList []*User } -type CheckLoginResponse struct { - Code string - Raw []byte +// CheckLoginResponse 检查登录状态的响应body +type CheckLoginResponse []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 {