优化对象的字段的排列

This commit is contained in:
eatMoreApple 2021-04-27 11:12:46 +08:00
parent 7ddcde9ab6
commit d84fbe1681
3 changed files with 302 additions and 303 deletions

322
bot.go
View File

@ -1,223 +1,223 @@
package openwechat
import (
"errors"
"fmt"
"errors"
"fmt"
)
type Bot struct {
Caller *Caller
self *Self
storage *Storage
ScanCallBack func(body []byte)
LoginCallBack func(body []byte)
UUIDCallback func(uuid string)
MessageHandler func(msg *Message)
err error
exit chan bool
ScanCallBack func(body []byte)
LoginCallBack func(body []byte)
UUIDCallback func(uuid string)
MessageHandler func(msg *Message)
err error
exit chan bool
Caller *Caller
self *Self
storage *Storage
}
// 判断当前用户是否正常在线
func (b *Bot) Alive() bool {
if b.self == nil {
return false
}
select {
case <-b.exit:
return false
default:
return true
}
if b.self == nil {
return false
}
select {
case <-b.exit:
return false
default:
return true
}
}
// 获取当前的用户
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
}
// 用户登录
// 该方法会一直阻塞,直到用户扫码登录,或者二维码过期
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:
return b.login(resp.Raw)
case statusScanned:
if b.ScanCallBack != nil {
b.ScanCallBack(resp.Raw)
}
case statusTimeout:
return errors.New("login time out")
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:
return b.login(resp.Raw)
case statusScanned:
if b.ScanCallBack != nil {
b.ScanCallBack(resp.Raw)
}
case statusTimeout:
return errors.New("login time out")
case statusWait:
continue
}
}
}
func (b *Bot) Logout() error {
if b.Alive() {
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() {
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")
}
// 登录逻辑
func (b *Bot) login(data []byte) error {
// 判断是否有登录回调,如果有执行它
if b.LoginCallBack != nil {
b.LoginCallBack(data)
}
// 获取登录的一些基本的信息
info, err := b.Caller.GetLoginInfo(data)
if err != nil {
return err
}
// 判断是否有登录回调,如果有执行它
if b.LoginCallBack != nil {
b.LoginCallBack(data)
}
// 获取登录的一些基本的信息
info, err := b.Caller.GetLoginInfo(data)
if err != nil {
return err
}
// 将LoginInfo存到storage里面
b.storage.LoginInfo = info
// 将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
// 获取初始化的用户信息和一些必要的参数
resp, err := b.Caller.WebInit(request)
if err != nil {
return err
}
// 设置当前的用户
b.self = &Self{Bot: b, User: &resp.User}
b.self.Self = b.self
b.storage.Response = resp
// 将BaseRequest存到storage里面方便后续调用
b.storage.Request = request
// 获取初始化的用户信息和一些必要的参数
resp, err := b.Caller.WebInit(request)
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(request, resp, info); err != nil {
return err
}
// 开启协程,轮训获取是否有新的消息返回
go func() {
b.stopAsyncCALL(b.asyncCall())
}()
return nil
// 通知手机客户端已经登录
if err = b.Caller.WebWxStatusNotify(request, resp, info); err != nil {
return err
}
// 开启协程,轮训获取是否有新的消息返回
go func() {
b.stopAsyncCALL(b.asyncCall())
}()
return nil
}
// 轮训请求
// 根据状态码判断是否有新的请求
func (b *Bot) asyncCall() error {
var (
err error
resp *SyncCheckResponse
)
for b.Alive() {
info := b.storage.LoginInfo
response := b.storage.Response
resp, err = b.Caller.SyncCheck(info, response)
if err != nil {
return err
}
// 如果不是正常的状态码返回,发生了错误,直接退出
if !resp.Success() {
return fmt.Errorf("unknow code got %s", resp.RetCode)
}
// 如果Selector不为0则获取消息
if !resp.NorMal() {
if err = b.getMessage(); err != nil {
return err
}
}
}
return err
var (
err error
resp *SyncCheckResponse
)
for b.Alive() {
info := b.storage.LoginInfo
response := b.storage.Response
resp, err = b.Caller.SyncCheck(info, response)
if err != nil {
return err
}
// 如果不是正常的状态码返回,发生了错误,直接退出
if !resp.Success() {
return fmt.Errorf("unknow code got %s", resp.RetCode)
}
// 如果Selector不为0则获取消息
if !resp.NorMal() {
if err = b.getMessage(); err != nil {
return err
}
}
}
return err
}
func (b *Bot) stopAsyncCALL(err error) {
b.exit <- true
b.err = err
b.self = nil
b.exit <- true
b.err = err
b.self = nil
}
// 获取新的消息
func (b *Bot) getMessage() 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
}
// 当消息同步发生了错误或者用户主动在手机上退出,该方法会立即返回,否则会一直阻塞
func (b *Bot) Block() error {
if b.self == nil {
return errors.New("`Block` must be called after user login")
}
if _, closed := <-b.exit; !closed {
return errors.New("can not call `Block` after user logout")
}
close(b.exit)
return nil
if b.self == nil {
return errors.New("`Block` must be called after user login")
}
if _, closed := <-b.exit; !closed {
return errors.New("can not call `Block` after user logout")
}
close(b.exit)
return nil
}
func NewBot(caller *Caller) *Bot {
return &Bot{Caller: caller, storage: &Storage{}, exit: make(chan bool)}
return &Bot{Caller: caller, storage: &Storage{}, exit: make(chan bool)}
}
func DefaultBot(modes ...mode) *Bot {
var m mode
if len(modes) == 0 {
m = Normal
} else {
m = modes[0]
}
urlManager := GetUrlManagerByMode(m)
return NewBot(DefaultCaller(urlManager))
var m mode
if len(modes) == 0 {
m = Normal
} else {
m = modes[0]
}
urlManager := GetUrlManagerByMode(m)
return NewBot(DefaultCaller(urlManager))
}
type Storage struct {
LoginInfo *LoginInfo
Request *BaseRequest
Response *WebInitResponse
LoginInfo *LoginInfo
Request *BaseRequest
Response *WebInitResponse
}
func GetQrcodeUrl(uuid string) string {
return qrcodeUrl + uuid
return qrcodeUrl + uuid
}
func PrintlnQrcodeUrl(uuid string) {
println("访问下面网址扫描二维码登录")
println(GetQrcodeUrl(uuid))
println("访问下面网址扫描二维码登录")
println(GetQrcodeUrl(uuid))
}

220
items.go
View File

@ -8,173 +8,173 @@ import "fmt"
// 登录信息
type LoginInfo struct {
Ret int `xml:"ret"`
Message string `xml:"message"`
SKey string `xml:"skey"`
WxSid string `xml:"wxsid"`
WxUin int `xml:"wxuin"`
PassTicket string `xml:"pass_ticket"`
IsGrayScale int `xml:"isgrayscale"`
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"`
}
// 初始的请求信息
// 几乎所有的请求都要携带该参数
type BaseRequest struct {
Uin int
Sid, Skey, DeviceID string
Uin int
Sid, Skey, DeviceID string
}
// 大部分返回对象都携带该信息
type BaseResponse struct {
ErrMsg string
Ret int
Ret int
ErrMsg string
}
func (b BaseResponse) Ok() bool {
return b.Ret == 0
return b.Ret == 0
}
func (b BaseResponse) Error() string {
switch b.Ret {
case 0:
return ""
case 1:
return "param error"
case -14:
return "ticket error"
case 1100:
return "not login warn"
case 1101:
return "not login check"
case 1102:
return "cookie invalid error"
case 1203:
return "login env error"
case 1205:
return "opt too often"
default:
return fmt.Sprintf("base response ret code %d", b.Ret)
}
switch b.Ret {
case 0:
return ""
case 1:
return "param error"
case -14:
return "ticket error"
case 1100:
return "not login warn"
case 1101:
return "not login check"
case 1102:
return "cookie invalid error"
case 1203:
return "login env error"
case 1205:
return "opt too often"
default:
return fmt.Sprintf("base response ret code %d", b.Ret)
}
}
type SyncKey struct {
Count int
List []struct{ Key, Val int64 }
Count int
List []struct{ Key, Val int64 }
}
// 初始化的相应信息
type WebInitResponse struct {
BaseResponse BaseResponse
Count int
ChatSet string
SKey string
SyncKey SyncKey
User User
ClientVersion int
SystemTime int64
GrayScale int
InviteStartCount int
MPSubscribeMsgCount int
MPSubscribeMsgList []MPSubscribeMsg
ClickReportInterval int
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
}
// 公众号的订阅信息
type MPSubscribeMsg struct {
UserName string
Time int64
NickName string
MPArticleCount int
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 UserDetailItemList
for _, member := range members {
item := UserDetailItem{UserName: member.UserName, EncryChatRoomId: member.EncryChatRoomId}
list = append(list, item)
}
return list
var list UserDetailItemList
for _, member := range members {
item := UserDetailItem{UserName: member.UserName, EncryChatRoomId: member.EncryChatRoomId}
list = append(list, 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 "param error"
case "-14":
return "ticker error"
case "1100":
return "not login warn"
case "1101":
return "not login check"
case "1102":
return "cookie invalid error"
case "1203":
return "login env error"
case "1205":
return "opt too often"
default:
return fmt.Sprintf("sync check response error code %s", s.RetCode)
}
switch s.RetCode {
case "0":
return ""
case "1":
return "param error"
case "-14":
return "ticker error"
case "1100":
return "not login warn"
case "1101":
return "not login check"
case "1102":
return "cookie invalid error"
case "1203":
return "login env error"
case "1205":
return "opt too often"
default:
return fmt.Sprintf("sync check response error code %s", s.RetCode)
}
}
type WebWxSyncResponse struct {
AddMsgCount int
AddMsgList []*Message
BaseResponse BaseResponse
ContinueFlag int
DelContactCount int
ModChatRoomMemberCount int
ModChatRoomMemberList Members
ModContactCount int
Skey string
SyncCheckKey SyncKey
SyncKey SyncKey
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 {
BaseResponse BaseResponse
MemberCount int
MemberList []*User
Seq int
MemberCount int
Seq int
BaseResponse BaseResponse
MemberList []*User
}
type WebWxBatchContactResponse struct {
BaseResponse BaseResponse
ContactList []*User
Count int
Count int
BaseResponse BaseResponse
ContactList []*User
}
type CheckLoginResponse struct {
Code string
Raw []byte
Code string
Raw []byte
}

View File

@ -13,44 +13,43 @@ import (
)
type Message struct {
IsAt bool
AppInfo struct {
AppID string
Type int
AppID string
}
AppMsgType int
Content string
CreateTime int64
EncryFileName string
FileName string
FileSize string
ForwardFlag int
FromUserName string
HasProductId int
ImgHeight int
ImgStatus int
ImgWidth int
MediaId string
MsgId string
MsgType int
NewMsgId int64
OriContent string
PlayLength int64
RecommendInfo RecommendInfo
Status int
StatusNotifyCode int
StatusNotifyUserName string
SubMsgType int
Ticket string
ToUserName string
Url string
VoiceLength int
IsAt bool
Bot *Bot
AppMsgType int
HasProductId int
ImgHeight int
ImgStatus int
ImgWidth int
ForwardFlag int
MsgType int
Status int
StatusNotifyCode int
SubMsgType int
VoiceLength int
CreateTime int64
NewMsgId int64
PlayLength int64
MediaId string
MsgId string
EncryFileName string
FileName string
FileSize string
Content string
FromUserName string
OriContent string
StatusNotifyUserName string
Ticket string
ToUserName string
Url string
senderInGroupUserName string
RecommendInfo RecommendInfo
Bot *Bot
mu sync.RWMutex
item map[string]interface{}
Context context.Context
item map[string]interface{}
}
// 获取消息的发送者