From 93564fabb530da01c213528ca1090ff352aed55d Mon Sep 17 00:00:00 2001 From: eatmoreapple <15055461510@163.com> Date: Mon, 23 Aug 2021 20:53:39 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=90=8C=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E6=97=B6=E7=9A=84deviceId?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bot.go | 494 ++++++++++++++++++++++++++--------------------------- caller.go | 4 +- client.go | 4 +- items.go | 286 +++++++++++++++---------------- stroage.go | 88 +++++----- 5 files changed, 438 insertions(+), 438 deletions(-) diff --git a/bot.go b/bot.go index 1276649..ea961b5 100644 --- a/bot.go +++ b/bot.go @@ -1,43 +1,43 @@ package openwechat import ( - "context" - "encoding/json" - "errors" - "log" - "net/url" - "sync" + "context" + "encoding/json" + "errors" + "log" + "net/url" + "sync" ) type Bot struct { - ScanCallBack func(body []byte) // 扫码回调,可获取扫码用户的头像 - LoginCallBack func(body []byte) // 登陆回调 - LogoutCallBack func(bot *Bot) // 退出回调 - UUIDCallback func(uuid string) // 获取UUID的回调函数 - MessageHandler MessageHandler // 获取消息成功的handle - GetMessageErrorHandler func(err error) // 获取消息发生错误的handle - IsHot bool // 是否为热登录模式 - once sync.Once - err error - context context.Context - cancel context.CancelFunc - Caller *Caller - self *Self - Storage *Storage - HotReloadStorage HotReloadStorage + ScanCallBack func(body []byte) // 扫码回调,可获取扫码用户的头像 + LoginCallBack func(body []byte) // 登陆回调 + LogoutCallBack func(bot *Bot) // 退出回调 + UUIDCallback func(uuid string) // 获取UUID的回调函数 + MessageHandler MessageHandler // 获取消息成功的handle + GetMessageErrorHandler func(err error) // 获取消息发生错误的handle + IsHot bool // 是否为热登录模式 + once sync.Once + err error + context context.Context + cancel context.CancelFunc + Caller *Caller + self *Self + Storage *Storage + HotReloadStorage HotReloadStorage } // Alive 判断当前用户是否正常在线 func (b *Bot) Alive() bool { - if b.self == nil { - return false - } - select { - case <-b.context.Done(): - return false - default: - return true - } + if b.self == nil { + return false + } + select { + case <-b.context.Done(): + return false + default: + return true + } } // GetCurrentUser 获取当前的用户 @@ -47,10 +47,10 @@ func (b *Bot) Alive() bool { // } // fmt.Println(self.NickName) func (b *Bot) GetCurrentUser() (*Self, error) { - if b.self == nil { - return nil, errors.New("user not login") - } - return b.self, nil + if b.self == nil { + return nil, errors.New("user not login") + } + return b.self, nil } // HotLogin 热登录,可实现重复登录, @@ -59,314 +59,314 @@ func (b *Bot) GetCurrentUser() (*Self, error) { // err := bot.HotLogin(Storage, true) // fmt.Println(err) func (b *Bot) HotLogin(storage HotReloadStorage, retry ...bool) error { - b.IsHot = true - b.HotReloadStorage = storage + b.IsHot = true + b.HotReloadStorage = storage - var err error + var err error - // 如果load出错了,就执行正常登陆逻辑 - // 第一次没有数据load都会出错的 - item, err := NewHotReloadStorageItem(storage) + // 如果load出错了,就执行正常登陆逻辑 + // 第一次没有数据load都会出错的 + item, err := NewHotReloadStorageItem(storage) - if err != nil { - return b.Login() - } + if err != nil { + return b.Login() + } - defer storage.Close() + defer storage.Close() - if err = b.hotLoginInit(*item); err != nil { - return err - } + if err = b.hotLoginInit(*item); err != nil { + return err + } - // 如果webInit出错,则说明可能身份信息已经失效 - // 如果retry为True的话,则进行正常登陆 - if err = b.WebInit(); err != nil { - if len(retry) > 0 && retry[0] { - return b.Login() - } - } - return err + // 如果webInit出错,则说明可能身份信息已经失效 + // 如果retry为True的话,则进行正常登陆 + if err = b.WebInit(); err != nil { + if len(retry) > 0 && retry[0] { + return b.Login() + } + } + return err } // 热登陆初始化 func (b *Bot) hotLoginInit(item HotReloadStorageItem) error { - cookies := item.Cookies - for u, ck := range cookies { - path, err := url.Parse(u) - if err != nil { - return err - } - b.Caller.Client.Jar.SetCookies(path, ck) - } - b.Storage.LoginInfo = item.LoginInfo - b.Storage.Request = item.BaseRequest - b.Caller.Client.Domain = item.WechatDomain - return nil + cookies := item.Cookies + for u, ck := range cookies { + path, err := url.Parse(u) + if err != nil { + return err + } + b.Caller.Client.Jar.SetCookies(path, ck) + } + b.Storage.LoginInfo = item.LoginInfo + b.Storage.Request = item.BaseRequest + b.Caller.Client.Domain = item.WechatDomain + return nil } // Login 用户登录 // 该方法会一直阻塞,直到用户扫码登录,或者二维码过期 func (b *Bot) Login() error { - uuid, err := b.Caller.GetLoginUUID() - if err != nil { - return err - } - // 二维码获取回调 - if b.UUIDCallback != nil { - b.UUIDCallback(uuid) - } - for { - // 长轮询检查是否扫码登录 - resp, err := b.Caller.CheckLogin(uuid) - if err != nil { - return err - } - switch resp.Code { - case StatusSuccess: - // 判断是否有登录回调,如果有执行它 - if b.LoginCallBack != nil { - b.LoginCallBack(resp.Raw) - } - return b.HandleLogin(resp.Raw) - case StatusScanned: - // 执行扫码回调 - if b.ScanCallBack != nil { - b.ScanCallBack(resp.Raw) - } - case StatusTimeout: - return ErrLoginTimeout - case StatusWait: - continue - } - } + uuid, err := b.Caller.GetLoginUUID() + if err != nil { + return err + } + // 二维码获取回调 + if b.UUIDCallback != nil { + b.UUIDCallback(uuid) + } + for { + // 长轮询检查是否扫码登录 + resp, err := b.Caller.CheckLogin(uuid) + if err != nil { + return err + } + switch resp.Code { + case StatusSuccess: + // 判断是否有登录回调,如果有执行它 + if b.LoginCallBack != nil { + b.LoginCallBack(resp.Raw) + } + return b.HandleLogin(resp.Raw) + case StatusScanned: + // 执行扫码回调 + if b.ScanCallBack != nil { + b.ScanCallBack(resp.Raw) + } + case StatusTimeout: + return ErrLoginTimeout + case StatusWait: + continue + } + } } // Logout 用户退出 func (b *Bot) Logout() error { - if b.Alive() { - if b.LogoutCallBack != nil { - b.LogoutCallBack(b) - } - info := b.Storage.LoginInfo - if err := b.Caller.Logout(info); err != nil { - return err - } - b.stopAsyncCALL(errors.New("logout")) - return nil - } - return errors.New("user not login") + if b.Alive() { + if b.LogoutCallBack != nil { + b.LogoutCallBack(b) + } + info := b.Storage.LoginInfo + if err := b.Caller.Logout(info); err != nil { + return err + } + b.stopAsyncCALL(errors.New("logout")) + return nil + } + return errors.New("user not login") } // HandleLogin 登录逻辑 func (b *Bot) HandleLogin(data []byte) error { - // 获取登录的一些基本的信息 - info, err := b.Caller.GetLoginInfo(data) - if err != nil { - return err - } - // 将LoginInfo存到storage里面 - b.Storage.LoginInfo = info + // 获取登录的一些基本的信息 + info, err := b.Caller.GetLoginInfo(data) + if err != nil { + return err + } + // 将LoginInfo存到storage里面 + b.Storage.LoginInfo = info - // 构建BaseRequest - request := &BaseRequest{ - Uin: info.WxUin, - Sid: info.WxSid, - Skey: info.SKey, - DeviceID: GetRandomDeviceId(), - } + // 构建BaseRequest + request := &BaseRequest{ + Uin: info.WxUin, + Sid: info.WxSid, + Skey: info.SKey, + DeviceID: GetRandomDeviceId(), + } - // 将BaseRequest存到storage里面方便后续调用 - b.Storage.Request = request + // 将BaseRequest存到storage里面方便后续调用 + b.Storage.Request = request - // 如果是热登陆,则将当前的重要信息写入hotReloadStorage - if b.IsHot { - if err = b.DumpHotReloadStorage(); err != nil { - return err - } - } + // 如果是热登陆,则将当前的重要信息写入hotReloadStorage + if b.IsHot { + if err = b.DumpHotReloadStorage(); err != nil { + return err + } + } - return b.WebInit() + return b.WebInit() } // WebInit 根据有效凭证获取和初始化用户信息 func (b *Bot) WebInit() error { - req := b.Storage.Request - info := b.Storage.LoginInfo - // 获取初始化的用户信息和一些必要的参数 - resp, err := b.Caller.WebInit(req) - if err != nil { - return err - } - // 设置当前的用户 - b.self = &Self{Bot: b, User: &resp.User} - b.self.Self = b.self - b.Storage.Response = resp + req := b.Storage.Request + info := b.Storage.LoginInfo + // 获取初始化的用户信息和一些必要的参数 + resp, err := b.Caller.WebInit(req) + if err != nil { + return err + } + // 设置当前的用户 + b.self = &Self{Bot: b, User: &resp.User} + b.self.Self = b.self + b.Storage.Response = resp - // 通知手机客户端已经登录 - if err = b.Caller.WebWxStatusNotify(req, resp, info); err != nil { - return err - } - // 开启协程,轮询获取是否有新的消息返回 + // 通知手机客户端已经登录 + if err = b.Caller.WebWxStatusNotify(req, resp, info); err != nil { + return err + } + // 开启协程,轮询获取是否有新的消息返回 - // FIX: 当bot在线的情况下执行热登录,会开启多次事件监听 - go b.once.Do(func() { - if b.GetMessageErrorHandler == nil { - b.GetMessageErrorHandler = b.stopAsyncCALL - } - if err = b.asyncCall(); err != nil { - b.GetMessageErrorHandler(err) - } - }) - return nil + // FIX: 当bot在线的情况下执行热登录,会开启多次事件监听 + go b.once.Do(func() { + if b.GetMessageErrorHandler == nil { + b.GetMessageErrorHandler = b.stopAsyncCALL + } + if err = b.asyncCall(); err != nil { + b.GetMessageErrorHandler(err) + } + }) + return nil } // 轮询请求 // 根据状态码判断是否有新的请求 func (b *Bot) asyncCall() error { - var ( - err error - resp *SyncCheckResponse - ) - for b.Alive() { - // 长轮询检查是否有消息返回 - resp, err = b.Caller.SyncCheck(b.Storage.LoginInfo, b.Storage.Response) - if err != nil { - return err - } - // 如果不是正常的状态码返回,发生了错误,直接退出 - if !resp.Success() { - return resp - } - // 如果Selector不为0,则获取消息 - if !resp.NorMal() { - if err = b.getNewWechatMessage(); err != nil { - return err - } - } - } - return err + var ( + err error + resp *SyncCheckResponse + ) + for b.Alive() { + // 长轮询检查是否有消息返回 + resp, err = b.Caller.SyncCheck(b.Storage.Request, b.Storage.LoginInfo, b.Storage.Response) + if err != nil { + return err + } + // 如果不是正常的状态码返回,发生了错误,直接退出 + if !resp.Success() { + return resp + } + // 如果Selector不为0,则获取消息 + if !resp.NorMal() { + if err = b.getNewWechatMessage(); err != nil { + return err + } + } + } + return err } // 当获取消息发生错误时, 默认的错误处理行为 func (b *Bot) stopAsyncCALL(err error) { - b.cancel() - b.err = err - b.self = nil - log.Printf("exit with : %s", err.Error()) + b.cancel() + b.err = err + b.self = nil + log.Printf("exit with : %s", err.Error()) } // 获取新的消息 func (b *Bot) getNewWechatMessage() error { - resp, err := b.Caller.WebWxSync(b.Storage.Request, b.Storage.Response, b.Storage.LoginInfo) - if err != nil { - return err - } - // 更新SyncKey并且重新存入storage - b.Storage.Response.SyncKey = resp.SyncKey - // 遍历所有的新的消息,依次处理 - for _, message := range resp.AddMsgList { - // 根据不同的消息类型来进行处理,方便后续统一调用 - message.init(b) - // 调用自定义的处理方法 - if handler := b.MessageHandler; handler != nil { - handler(message) - } - } - return nil + resp, err := b.Caller.WebWxSync(b.Storage.Request, b.Storage.Response, b.Storage.LoginInfo) + if err != nil { + return err + } + // 更新SyncKey并且重新存入storage + b.Storage.Response.SyncKey = resp.SyncKey + // 遍历所有的新的消息,依次处理 + for _, message := range resp.AddMsgList { + // 根据不同的消息类型来进行处理,方便后续统一调用 + message.init(b) + // 调用自定义的处理方法 + if handler := b.MessageHandler; handler != nil { + handler(message) + } + } + return nil } // Block 当消息同步发生了错误或者用户主动在手机上退出,该方法会立即返回,否则会一直阻塞 func (b *Bot) Block() error { - if b.self == nil { - return errors.New("`Block` must be called after user login") - } - <-b.context.Done() - return nil + if b.self == nil { + return errors.New("`Block` must be called after user login") + } + <-b.context.Done() + return nil } // CrashReason 获取当前Bot崩溃的原因 func (b *Bot) CrashReason() error { - return b.err + return b.err } // MessageOnSuccess setter for Bot.MessageHandler func (b *Bot) MessageOnSuccess(h func(msg *Message)) { - b.MessageHandler = h + b.MessageHandler = h } // MessageOnError setter for Bot.GetMessageErrorHandler func (b *Bot) MessageOnError(h func(err error)) { - b.GetMessageErrorHandler = h + b.GetMessageErrorHandler = h } // DumpHotReloadStorage 写入HotReloadStorage func (b *Bot) DumpHotReloadStorage() error { - if b.HotReloadStorage == nil { - return errors.New("HotReloadStorage can not be nil") - } - cookies := b.Caller.Client.GetCookieMap() - item := HotReloadStorageItem{ - BaseRequest: b.Storage.Request, - Cookies: cookies, - LoginInfo: b.Storage.LoginInfo, - WechatDomain: b.Caller.Client.Domain, - } + if b.HotReloadStorage == nil { + return errors.New("HotReloadStorage can not be nil") + } + cookies := b.Caller.Client.GetCookieMap() + item := HotReloadStorageItem{ + BaseRequest: b.Storage.Request, + Cookies: cookies, + LoginInfo: b.Storage.LoginInfo, + WechatDomain: b.Caller.Client.Domain, + } - data, err := json.Marshal(item) - if err != nil { - return err - } - if _, err = b.HotReloadStorage.Write(data); err != nil { - return err - } - return b.HotReloadStorage.Close() + data, err := json.Marshal(item) + if err != nil { + return err + } + if _, err = b.HotReloadStorage.Write(data); err != nil { + return err + } + return b.HotReloadStorage.Close() } // OnLogin is a setter for LoginCallBack func (b *Bot) OnLogin(f func(body []byte)) { - b.LoginCallBack = f + b.LoginCallBack = f } // OnScanned is a setter for ScanCallBack func (b *Bot) OnScanned(f func(body []byte)) { - b.ScanCallBack = f + b.ScanCallBack = f } // OnLogout is a setter for LogoutCallBack func (b *Bot) OnLogout(f func(bot *Bot)) { - b.LogoutCallBack = f + b.LogoutCallBack = f } // NewBot Bot的构造方法,需要自己传入Caller func NewBot(caller *Caller) *Bot { - ctx, cancel := context.WithCancel(context.Background()) - return &Bot{Caller: caller, Storage: &Storage{}, context: ctx, cancel: cancel} + ctx, cancel := context.WithCancel(context.Background()) + return &Bot{Caller: caller, Storage: &Storage{}, context: ctx, cancel: cancel} } // DefaultBot 默认的Bot的构造方法, // mode不传入默认为openwechat.Normal,详情见mode // bot := openwechat.DefaultBot(openwechat.Desktop) func DefaultBot(modes ...mode) *Bot { - var m mode - if len(modes) == 0 { - m = Normal - } else { - m = modes[0] - } - caller := DefaultCaller() - caller.Client.mode = m - bot := NewBot(caller) - bot.UUIDCallback = PrintlnQrcodeUrl - return bot + var m mode + if len(modes) == 0 { + m = Normal + } else { + m = modes[0] + } + caller := DefaultCaller() + caller.Client.mode = m + bot := NewBot(caller) + bot.UUIDCallback = PrintlnQrcodeUrl + return bot } // GetQrcodeUrl 通过uuid获取登录二维码的url func GetQrcodeUrl(uuid string) string { - return qrcode + uuid + return qrcode + uuid } // PrintlnQrcodeUrl 打印登录二维码 func PrintlnQrcodeUrl(uuid string) { - println("访问下面网址扫描二维码登录") - println(GetQrcodeUrl(uuid)) + println("访问下面网址扫描二维码登录") + println(GetQrcodeUrl(uuid)) } diff --git a/caller.go b/caller.go index f443654..fcc8f37 100644 --- a/caller.go +++ b/caller.go @@ -135,8 +135,8 @@ func (c *Caller) WebWxStatusNotify(request *BaseRequest, response *WebInitRespon } // SyncCheck 异步获取是否有新的消息 -func (c *Caller) SyncCheck(info *LoginInfo, response *WebInitResponse) (*SyncCheckResponse, error) { - resp, err := c.Client.SyncCheck(info, response) +func (c *Caller) SyncCheck(request *BaseRequest, info *LoginInfo, response *WebInitResponse) (*SyncCheckResponse, error) { + resp, err := c.Client.SyncCheck(request, info, response) if err != nil { return nil, err } diff --git a/client.go b/client.go index aa7a9de..305394c 100644 --- a/client.go +++ b/client.go @@ -195,14 +195,14 @@ func (c *Client) WebWxStatusNotify(request *BaseRequest, response *WebInitRespon } // SyncCheck 异步检查是否有新的消息返回 -func (c *Client) SyncCheck(info *LoginInfo, response *WebInitResponse) (*http.Response, error) { +func (c *Client) SyncCheck(request *BaseRequest, info *LoginInfo, response *WebInitResponse) (*http.Response, error) { path, _ := url.Parse(c.Domain.SyncHost() + synccheck) params := url.Values{} params.Add("r", strconv.FormatInt(time.Now().Unix(), 10)) params.Add("skey", info.SKey) params.Add("sid", info.WxSid) params.Add("uin", strconv.Itoa(info.WxUin)) - params.Add("deviceid", GetRandomDeviceId()) + params.Add("deviceid", request.DeviceID) params.Add("_", strconv.FormatInt(time.Now().Unix(), 10)) var syncKeyStringSlice = make([]string, response.SyncKey.Count) // 将SyncKey里面的元素按照特定的格式拼接起来 diff --git a/items.go b/items.go index 7ff7de8..e977a9e 100644 --- a/items.go +++ b/items.go @@ -1,8 +1,8 @@ package openwechat import ( - "errors" - "fmt" + "errors" + "fmt" ) /* @@ -11,232 +11,232 @@ import ( // LoginInfo 登录信息 type LoginInfo struct { - Ret int `xml:"ret"` - WxUin int `xml:"wxuin"` - IsGrayScale int `xml:"isgrayscale"` - Message string `xml:"message"` - SKey string `xml:"skey"` - WxSid string `xml:"wxsid"` - PassTicket string `xml:"pass_ticket"` + Ret int `xml:"ret"` + WxUin int `xml:"wxuin"` + IsGrayScale int `xml:"isgrayscale"` + Message string `xml:"message"` + SKey string `xml:"skey"` + WxSid string `xml:"wxsid"` + PassTicket string `xml:"pass_ticket"` } // errors const ( - errParamError = "param error" - errTicketError = "ticket error" - errLoginEnvError = "login env error" - errLoginFailedWarn = "failed login warn" - errLoginFailedCheck = "failed login check" - errCookieInvalidError = "cookie invalid error" - errOptTooOften = "opt too often" + errParamError = "param error" + errTicketError = "ticket error" + errLoginEnvError = "login env error" + errLoginFailedWarn = "failed login warn" + errLoginFailedCheck = "failed login check" + errCookieInvalidError = "cookie invalid error" + errOptTooOften = "opt too often" ) var ( - ErrParamError = errors.New(errParamError) - ErrTicketError = errors.New(errTicketError) - ErrLoginEnvError = errors.New(errLoginEnvError) - ErrLoginFailedWarn = errors.New(errLoginFailedWarn) - ErrLoginFailedCheck = errors.New(errLoginFailedCheck) - ErrCookieInvalidError = errors.New(errCookieInvalidError) - ErrOptTooOften = errors.New(errOptTooOften) - ErrBaseResponseError error + ErrParamError = errors.New(errParamError) + ErrTicketError = errors.New(errTicketError) + ErrLoginEnvError = errors.New(errLoginEnvError) + ErrLoginFailedWarn = errors.New(errLoginFailedWarn) + ErrLoginFailedCheck = errors.New(errLoginFailedCheck) + ErrCookieInvalidError = errors.New(errCookieInvalidError) + ErrOptTooOften = errors.New(errOptTooOften) + ErrBaseResponseError error ) func (l LoginInfo) Ok() bool { - return l.Ret == 0 + return l.Ret == 0 } func (l LoginInfo) Error() string { - return l.Message + return l.Message } // BaseRequest 初始的请求信息 // 几乎所有的请求都要携带该参数 type BaseRequest struct { - Uin int - Sid, Skey, DeviceID string + Uin int + Sid, Skey, DeviceID string } // BaseResponse 大部分返回对象都携带该信息 type BaseResponse struct { - Ret int - ErrMsg string + Ret int + ErrMsg string } func (b BaseResponse) Ok() bool { - return b.Ret == 0 + return b.Ret == 0 } func (b BaseResponse) Error() string { - if err := getResponseErrorWithRetCode(b.Ret); err != nil { - return err.Error() - } - return "" + if err := getResponseErrorWithRetCode(b.Ret); err != nil { + return err.Error() + } + return "" } func getResponseErrorWithRetCode(code int) error { - switch code { - case 0: - return nil - case 1: - return ErrParamError - case -14: - return ErrTicketError - case 1100: - return ErrLoginFailedWarn - case 1101: - return ErrLoginFailedCheck - case 1102: - return ErrCookieInvalidError - case 1203: - return ErrLoginEnvError - case 1205: - return ErrOptTooOften - default: - ErrBaseResponseError = fmt.Errorf("base response ret code %d", code) - return ErrBaseResponseError - } + switch code { + case 0: + return nil + case 1: + return ErrParamError + case -14: + return ErrTicketError + case 1100: + return ErrLoginFailedWarn + case 1101: + return ErrLoginFailedCheck + case 1102: + return ErrCookieInvalidError + case 1203: + return ErrLoginEnvError + case 1205: + return ErrOptTooOften + default: + ErrBaseResponseError = fmt.Errorf("base response ret code %d", code) + return ErrBaseResponseError + } } type SyncKey struct { - Count int - List []struct{ Key, Val int64 } + Count int + List []struct{ Key, Val int64 } } // WebInitResponse 初始化的相应信息 type WebInitResponse struct { - Count int - ClientVersion int - GrayScale int - InviteStartCount int - MPSubscribeMsgCount int - ClickReportInterval int - SystemTime int64 - ChatSet string - SKey string - BaseResponse BaseResponse - SyncKey SyncKey - User User - MPSubscribeMsgList []MPSubscribeMsg - ContactList []User + Count int + ClientVersion int + GrayScale int + InviteStartCount int + MPSubscribeMsgCount int + ClickReportInterval int + SystemTime int64 + ChatSet string + SKey string + BaseResponse BaseResponse + SyncKey SyncKey + User User + MPSubscribeMsgList []MPSubscribeMsg + ContactList []User } // MPSubscribeMsg 公众号的订阅信息 type MPSubscribeMsg struct { - MPArticleCount int - Time int64 - UserName string - NickName string - MPArticleList []struct { - Title string - Cover string - Digest string - Url string - } + MPArticleCount int + Time int64 + UserName string + NickName string + MPArticleList []struct { + Title string + Cover string + Digest string + Url string + } } type UserDetailItem struct { - UserName string - EncryChatRoomId string + UserName string + EncryChatRoomId string } type UserDetailItemList []UserDetailItem func NewUserDetailItemList(members Members) UserDetailItemList { - var list = make(UserDetailItemList, len(members)) - for index, member := range members { - item := UserDetailItem{UserName: member.UserName, EncryChatRoomId: member.EncryChatRoomId} - list[index] = item - } - return list + var list = make(UserDetailItemList, len(members)) + for index, member := range members { + item := UserDetailItem{UserName: member.UserName, EncryChatRoomId: member.EncryChatRoomId} + list[index] = item + } + return list } type SyncCheckResponse struct { - RetCode string - Selector string + RetCode string + Selector string } func (s *SyncCheckResponse) Success() bool { - return s.RetCode == "0" + return s.RetCode == "0" } func (s *SyncCheckResponse) NorMal() bool { - return s.Success() && s.Selector == "0" + return s.Success() && s.Selector == "0" } // 实现error接口 func (s *SyncCheckResponse) Error() string { - switch s.RetCode { - case "0": - return "" - case "1": - return errParamError - case "-14": - return errTicketError - case "1100": - return errLoginFailedWarn - case "1101": - return errLoginFailedCheck - case "1102": - return errCookieInvalidError - case "1203": - return errLoginEnvError - case "1205": - return errOptTooOften - default: - return fmt.Sprintf("sync check response error code %s", s.RetCode) - } + switch s.RetCode { + case "0": + return "" + case "1": + return errParamError + case "-14": + return errTicketError + case "1100": + return errLoginFailedWarn + case "1101": + return errLoginFailedCheck + case "1102": + return errCookieInvalidError + case "1203": + return errLoginEnvError + case "1205": + return errOptTooOften + default: + return fmt.Sprintf("sync check response error code %s", s.RetCode) + } } type WebWxSyncResponse struct { - AddMsgCount int - ContinueFlag int - DelContactCount int - ModChatRoomMemberCount int - ModContactCount int - Skey string - SyncCheckKey SyncKey - SyncKey SyncKey - BaseResponse BaseResponse - ModChatRoomMemberList Members - AddMsgList []*Message + AddMsgCount int + ContinueFlag int + DelContactCount int + ModChatRoomMemberCount int + ModContactCount int + Skey string + SyncCheckKey SyncKey + SyncKey SyncKey + BaseResponse BaseResponse + ModChatRoomMemberList Members + AddMsgList []*Message } type WebWxContactResponse struct { - MemberCount int - Seq int - BaseResponse BaseResponse - MemberList []*User + MemberCount int + Seq int + BaseResponse BaseResponse + MemberList []*User } type WebWxBatchContactResponse struct { - Count int - BaseResponse BaseResponse - ContactList []*User + Count int + BaseResponse BaseResponse + ContactList []*User } type CheckLoginResponse struct { - Code string - Raw []byte + Code string + Raw []byte } type MessageResponse struct { - BaseResponse BaseResponse - LocalID string - MsgID string + BaseResponse BaseResponse + LocalID string + MsgID string } type UploadResponse struct { - BaseResponse BaseResponse - MediaId string + BaseResponse BaseResponse + MediaId string } type PushLoginResponse struct { - Ret string `json:"ret"` - Msg string `json:"msg"` - UUID string `json:"uuid"` + Ret string `json:"ret"` + Msg string `json:"msg"` + UUID string `json:"uuid"` } func (p PushLoginResponse) Ok() bool { - return p.Ret == "0" && p.UUID != "" + return p.Ret == "0" && p.UUID != "" } diff --git a/stroage.go b/stroage.go index 424e16d..35045d8 100644 --- a/stroage.go +++ b/stroage.go @@ -1,26 +1,26 @@ package openwechat import ( - "bytes" - "encoding/json" - "errors" - "io" - "net/http" - "os" + "bytes" + "encoding/json" + "errors" + "io" + "net/http" + "os" ) // Storage 身份信息, 维持整个登陆的Session会话 type Storage struct { - LoginInfo *LoginInfo - Request *BaseRequest - Response *WebInitResponse + LoginInfo *LoginInfo + Request *BaseRequest + Response *WebInitResponse } type HotReloadStorageItem struct { - Cookies map[string][]*http.Cookie - BaseRequest *BaseRequest - LoginInfo *LoginInfo - WechatDomain WechatDomain + Cookies map[string][]*http.Cookie + BaseRequest *BaseRequest + LoginInfo *LoginInfo + WechatDomain WechatDomain } // HotReloadStorage 热登陆存储接口 @@ -29,53 +29,53 @@ type HotReloadStorage io.ReadWriteCloser // JsonFileHotReloadStorage 实现HotReloadStorage接口 // 默认以json文件的形式存储 type JsonFileHotReloadStorage struct { - FileName string - file *os.File + FileName string + file *os.File } func (j *JsonFileHotReloadStorage) Read(p []byte) (n int, err error) { - if j.file == nil { - j.file, err = os.Open(j.FileName) - if err != nil { - return 0, err - } - } - return j.file.Read(p) + if j.file == nil { + j.file, err = os.Open(j.FileName) + if err != nil { + return 0, err + } + } + return j.file.Read(p) } func (j *JsonFileHotReloadStorage) Write(p []byte) (n int, err error) { - j.file, err = os.Create(j.FileName) - if err != nil { - return 0, err - } - return j.file.Write(p) + j.file, err = os.Create(j.FileName) + if err != nil { + return 0, err + } + return j.file.Write(p) } func (j *JsonFileHotReloadStorage) Close() error { - if j.file != nil { - return j.file.Close() - } - return nil + if j.file != nil { + return j.file.Close() + } + return nil } func NewJsonFileHotReloadStorage(filename string) HotReloadStorage { - return &JsonFileHotReloadStorage{FileName: filename} + return &JsonFileHotReloadStorage{FileName: filename} } var _ HotReloadStorage = &JsonFileHotReloadStorage{} func NewHotReloadStorageItem(storage HotReloadStorage) (*HotReloadStorageItem, error) { - if storage == nil { - return nil, errors.New("storage can't be nil") - } - var buffer bytes.Buffer - if _, err := buffer.ReadFrom(storage); err != nil { - return nil, err - } - var item HotReloadStorageItem + if storage == nil { + return nil, errors.New("storage can't be nil") + } + var buffer bytes.Buffer + if _, err := buffer.ReadFrom(storage); err != nil { + return nil, err + } + var item HotReloadStorageItem - if err := json.NewDecoder(&buffer).Decode(&item); err != nil { - return nil, err - } - return &item, nil + if err := json.NewDecoder(&buffer).Decode(&item); err != nil { + return nil, err + } + return &item, nil }