删除storage接口的依赖
This commit is contained in:
parent
1c885a9182
commit
f80cb2ebd2
321
bot.go
321
bot.go
@ -1,221 +1,216 @@
|
||||
package openwechat
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Bot struct {
|
||||
Caller *Caller
|
||||
self *Self
|
||||
storage WechatStorage
|
||||
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
|
||||
ScanCallBack func(body []byte)
|
||||
LoginCallBack func(body []byte)
|
||||
UUIDCallback func(uuid string)
|
||||
MessageHandler func(msg *Message)
|
||||
err error
|
||||
exit chan bool
|
||||
}
|
||||
|
||||
// 判断当前用户是否正常在线
|
||||
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 {
|
||||
b.prepare()
|
||||
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.GetLoginInfo()
|
||||
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.SetLoginInfo(*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.SetBaseRequest(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.SetWebInitResponse(*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.GetLoginInfo()
|
||||
response := b.storage.GetWebInitResponse()
|
||||
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 {
|
||||
info := b.storage.GetLoginInfo()
|
||||
response := b.storage.GetWebInitResponse()
|
||||
request := b.storage.GetBaseRequest()
|
||||
resp, err := b.Caller.WebWxSync(request, response, info)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 更新SyncKey并且重新存入storage
|
||||
response.SyncKey = resp.SyncKey
|
||||
b.storage.SetWebInitResponse(response)
|
||||
// 遍历所有的新的消息,依次处理
|
||||
for _, message := range resp.AddMsgList {
|
||||
// 根据不同的消息类型来进行处理,方便后续统一调用
|
||||
message.init(b)
|
||||
// 调用自定义的处理方法
|
||||
if handler := b.MessageHandler; handler != nil {
|
||||
handler(message)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Bot) prepare() {
|
||||
if b.storage == nil {
|
||||
b.storage = NewSimpleWechatStorage()
|
||||
}
|
||||
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, storage WechatStorage) *Bot {
|
||||
return &Bot{Caller: caller, storage: storage, exit: make(chan bool)}
|
||||
func NewBot(caller *Caller) *Bot {
|
||||
return &Bot{Caller: caller, storage: &Storage{}, exit: make(chan bool)}
|
||||
}
|
||||
|
||||
func DefaultBot() *Bot {
|
||||
return NewBot(DefaultCaller(), NewSimpleWechatStorage())
|
||||
return NewBot(DefaultCaller())
|
||||
}
|
||||
|
||||
type Storage struct {
|
||||
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))
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ func TestDefaultBot(t *testing.T) {
|
||||
return
|
||||
}
|
||||
self, _ := bot.GetCurrentUser()
|
||||
self.SaveAvatar("2.png")
|
||||
fileHelper, _ := self.FileHelper()
|
||||
fileHelper.SendText("6666")
|
||||
group, _ := self.Groups()
|
||||
|
20
caller.go
20
caller.go
@ -84,7 +84,7 @@ func (c *Caller) GetLoginInfo(body []byte) (*LoginInfo, error) {
|
||||
}
|
||||
|
||||
// 获取初始化信息
|
||||
func (c *Caller) WebInit(request BaseRequest) (*WebInitResponse, error) {
|
||||
func (c *Caller) WebInit(request *BaseRequest) (*WebInitResponse, error) {
|
||||
resp := NewReturnResponse(c.Client.WebInit(request))
|
||||
if resp.Err() != nil {
|
||||
return nil, resp.Err()
|
||||
@ -98,7 +98,7 @@ func (c *Caller) WebInit(request BaseRequest) (*WebInitResponse, error) {
|
||||
}
|
||||
|
||||
// 通知手机已登录
|
||||
func (c *Caller) WebWxStatusNotify(request BaseRequest, response WebInitResponse, info LoginInfo) error {
|
||||
func (c *Caller) WebWxStatusNotify(request *BaseRequest, response *WebInitResponse, info *LoginInfo) error {
|
||||
resp := NewReturnResponse(c.Client.WebWxStatusNotify(request, response, info))
|
||||
if resp.Err() != nil {
|
||||
return resp.Err()
|
||||
@ -115,7 +115,7 @@ func (c *Caller) WebWxStatusNotify(request BaseRequest, response WebInitResponse
|
||||
}
|
||||
|
||||
// 异步获取是否有新的消息
|
||||
func (c *Caller) SyncCheck(info LoginInfo, response WebInitResponse) (*SyncCheckResponse, error) {
|
||||
func (c *Caller) SyncCheck(info *LoginInfo, response *WebInitResponse) (*SyncCheckResponse, error) {
|
||||
resp := NewReturnResponse(c.Client.SyncCheck(info, response))
|
||||
if resp.Err() != nil {
|
||||
return nil, resp.Err()
|
||||
@ -135,7 +135,7 @@ func (c *Caller) SyncCheck(info LoginInfo, response WebInitResponse) (*SyncCheck
|
||||
}
|
||||
|
||||
// 获取所有的联系人
|
||||
func (c *Caller) WebWxGetContact(info LoginInfo) (Members, error) {
|
||||
func (c *Caller) WebWxGetContact(info *LoginInfo) (Members, error) {
|
||||
resp := NewReturnResponse(c.Client.WebWxGetContact(info))
|
||||
if resp.Err() != nil {
|
||||
return nil, resp.Err()
|
||||
@ -153,7 +153,7 @@ func (c *Caller) WebWxGetContact(info LoginInfo) (Members, error) {
|
||||
|
||||
// 获取联系人的详情
|
||||
// 注: Members参数的长度不要大于50
|
||||
func (c *Caller) WebWxBatchGetContact(members Members, request BaseRequest) (Members, error) {
|
||||
func (c *Caller) WebWxBatchGetContact(members Members, request *BaseRequest) (Members, error) {
|
||||
resp := NewReturnResponse(c.Client.WebWxBatchGetContact(members, request))
|
||||
if resp.Err() != nil {
|
||||
return nil, resp.Err()
|
||||
@ -170,7 +170,7 @@ func (c *Caller) WebWxBatchGetContact(members Members, request BaseRequest) (Mem
|
||||
}
|
||||
|
||||
// 获取新的消息接口
|
||||
func (c *Caller) WebWxSync(request BaseRequest, response WebInitResponse, info LoginInfo) (*WebWxSyncResponse, error) {
|
||||
func (c *Caller) WebWxSync(request *BaseRequest, response *WebInitResponse, info *LoginInfo) (*WebWxSyncResponse, error) {
|
||||
resp := NewReturnResponse(c.Client.WebWxSync(request, response, info))
|
||||
if resp.Err() != nil {
|
||||
return nil, resp.Err()
|
||||
@ -184,19 +184,19 @@ func (c *Caller) WebWxSync(request BaseRequest, response WebInitResponse, info L
|
||||
}
|
||||
|
||||
// 发送消息接口
|
||||
func (c *Caller) WebWxSendMsg(msg *SendMessage, info LoginInfo, request BaseRequest) error {
|
||||
func (c *Caller) WebWxSendMsg(msg *SendMessage, info *LoginInfo, request *BaseRequest) error {
|
||||
resp := NewReturnResponse(c.Client.WebWxSendMsg(msg, info, request))
|
||||
return parseBaseResponseError(resp)
|
||||
}
|
||||
|
||||
// 修改用户备注接口
|
||||
func (c *Caller) WebWxOplog(request BaseRequest, remarkName, toUserName string) error {
|
||||
func (c *Caller) WebWxOplog(request *BaseRequest, remarkName, toUserName string) error {
|
||||
resp := NewReturnResponse(c.Client.WebWxOplog(request, remarkName, toUserName))
|
||||
return parseBaseResponseError(resp)
|
||||
}
|
||||
|
||||
// 发送图片消息接口
|
||||
func (c *Caller) WebWxSendImageMsg(file *os.File, request BaseRequest, info LoginInfo, fromUserName, toUserName string) error {
|
||||
func (c *Caller) WebWxSendImageMsg(file *os.File, request *BaseRequest, info *LoginInfo, fromUserName, toUserName string) error {
|
||||
// 首先尝试上传图片
|
||||
resp := NewReturnResponse(c.Client.WebWxUploadMedia(file, request, info, fromUserName, toUserName, "image/jpeg", "pic"))
|
||||
// 无错误上传成功之后获取请求结果,判断结果是否正常
|
||||
@ -222,7 +222,7 @@ func (c *Caller) WebWxSendImageMsg(file *os.File, request BaseRequest, info Logi
|
||||
}
|
||||
|
||||
// 用户退出
|
||||
func (c *Caller) Logout(info LoginInfo) error {
|
||||
func (c *Caller) Logout(info *LoginInfo) error {
|
||||
resp := NewReturnResponse(c.Client.Logout(info))
|
||||
return parseBaseResponseError(resp)
|
||||
}
|
||||
|
628
client.go
628
client.go
@ -1,18 +1,18 @@
|
||||
package openwechat
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// http请求客户端
|
||||
@ -21,387 +21,387 @@ import (
|
||||
type Client struct{ *http.Client }
|
||||
|
||||
func NewClient(client *http.Client) *Client {
|
||||
return &Client{Client: client}
|
||||
return &Client{Client: client}
|
||||
}
|
||||
|
||||
// 自动存储cookie
|
||||
// 设置客户端不自动跳转
|
||||
func DefaultClient() *Client {
|
||||
jar, _ := cookiejar.New(nil)
|
||||
client := &http.Client{
|
||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||
return http.ErrUseLastResponse
|
||||
},
|
||||
Jar: jar,
|
||||
}
|
||||
return NewClient(client)
|
||||
jar, _ := cookiejar.New(nil)
|
||||
client := &http.Client{
|
||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||
return http.ErrUseLastResponse
|
||||
},
|
||||
Jar: jar,
|
||||
}
|
||||
return NewClient(client)
|
||||
}
|
||||
|
||||
// 获取登录的uuid
|
||||
func (c *Client) GetLoginUUID() (*http.Response, error) {
|
||||
path, _ := url.Parse(jsLoginUrl)
|
||||
params := url.Values{}
|
||||
params.Add("appid", appId)
|
||||
params.Add("redirect_uri", webWxNewLoginPage)
|
||||
params.Add("fun", "new")
|
||||
params.Add("lang", "zh_CN")
|
||||
params.Add("_", strconv.FormatInt(time.Now().Unix(), 10))
|
||||
path.RawQuery = params.Encode()
|
||||
return c.Get(path.String())
|
||||
path, _ := url.Parse(jsLoginUrl)
|
||||
params := url.Values{}
|
||||
params.Add("appid", appId)
|
||||
params.Add("redirect_uri", webWxNewLoginPage)
|
||||
params.Add("fun", "new")
|
||||
params.Add("lang", "zh_CN")
|
||||
params.Add("_", strconv.FormatInt(time.Now().Unix(), 10))
|
||||
path.RawQuery = params.Encode()
|
||||
return c.Get(path.String())
|
||||
}
|
||||
|
||||
// 获取登录的二维吗
|
||||
func (c *Client) GetLoginQrcode(uuid string) (*http.Response, error) {
|
||||
path := qrcodeUrl + uuid
|
||||
return c.Get(path)
|
||||
path := qrcodeUrl + uuid
|
||||
return c.Get(path)
|
||||
}
|
||||
|
||||
// 检查是否登录
|
||||
func (c *Client) CheckLogin(uuid string) (*http.Response, error) {
|
||||
path, _ := url.Parse(loginUrl)
|
||||
now := time.Now().Unix()
|
||||
params := url.Values{}
|
||||
params.Add("r", strconv.FormatInt(now/1579, 10))
|
||||
params.Add("_", strconv.FormatInt(now, 10))
|
||||
params.Add("loginicon", "true")
|
||||
params.Add("uuid", uuid)
|
||||
params.Add("tip", "0")
|
||||
path.RawQuery = params.Encode()
|
||||
return c.Get(path.String())
|
||||
path, _ := url.Parse(loginUrl)
|
||||
now := time.Now().Unix()
|
||||
params := url.Values{}
|
||||
params.Add("r", strconv.FormatInt(now/1579, 10))
|
||||
params.Add("_", strconv.FormatInt(now, 10))
|
||||
params.Add("loginicon", "true")
|
||||
params.Add("uuid", uuid)
|
||||
params.Add("tip", "0")
|
||||
path.RawQuery = params.Encode()
|
||||
return c.Get(path.String())
|
||||
}
|
||||
|
||||
// 请求获取LoginInfo
|
||||
func (c *Client) GetLoginInfo(path string) (*http.Response, error) {
|
||||
return c.Get(path)
|
||||
return c.Get(path)
|
||||
}
|
||||
|
||||
// 请求获取初始化信息
|
||||
func (c *Client) WebInit(request BaseRequest) (*http.Response, error) {
|
||||
path, _ := url.Parse(webWxInitUrl)
|
||||
params := url.Values{}
|
||||
params.Add("_", fmt.Sprintf("%d", time.Now().Unix()))
|
||||
path.RawQuery = params.Encode()
|
||||
content := struct{ BaseRequest BaseRequest }{BaseRequest: request}
|
||||
body, err := ToBuffer(content)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.Post(path.String(), jsonContentType, body)
|
||||
func (c *Client) WebInit(request *BaseRequest) (*http.Response, error) {
|
||||
path, _ := url.Parse(webWxInitUrl)
|
||||
params := url.Values{}
|
||||
params.Add("_", fmt.Sprintf("%d", time.Now().Unix()))
|
||||
path.RawQuery = params.Encode()
|
||||
content := struct{ BaseRequest *BaseRequest }{BaseRequest: request}
|
||||
body, err := ToBuffer(content)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.Post(path.String(), jsonContentType, body)
|
||||
}
|
||||
|
||||
// 通知手机已登录
|
||||
func (c *Client) WebWxStatusNotify(request BaseRequest, response WebInitResponse, info LoginInfo) (*http.Response, error) {
|
||||
path, _ := url.Parse(webWxStatusNotifyUrl)
|
||||
params := url.Values{}
|
||||
params.Add("lang", "zh_CN")
|
||||
params.Add("pass_ticket", info.PassTicket)
|
||||
username := response.User.UserName
|
||||
content := map[string]interface{}{
|
||||
"BaseRequest": request,
|
||||
"ClientMsgId": time.Now().Unix(),
|
||||
"Code": 3,
|
||||
"FromUserName": username,
|
||||
"ToUserName": username,
|
||||
}
|
||||
path.RawQuery = params.Encode()
|
||||
buffer, _ := ToBuffer(content)
|
||||
req, _ := http.NewRequest(http.MethodPost, path.String(), buffer)
|
||||
req.Header.Add("Content-Type", jsonContentType)
|
||||
return c.Do(req)
|
||||
func (c *Client) WebWxStatusNotify(request *BaseRequest, response *WebInitResponse, info *LoginInfo) (*http.Response, error) {
|
||||
path, _ := url.Parse(webWxStatusNotifyUrl)
|
||||
params := url.Values{}
|
||||
params.Add("lang", "zh_CN")
|
||||
params.Add("pass_ticket", info.PassTicket)
|
||||
username := response.User.UserName
|
||||
content := map[string]interface{}{
|
||||
"BaseRequest": request,
|
||||
"ClientMsgId": time.Now().Unix(),
|
||||
"Code": 3,
|
||||
"FromUserName": username,
|
||||
"ToUserName": username,
|
||||
}
|
||||
path.RawQuery = params.Encode()
|
||||
buffer, _ := ToBuffer(content)
|
||||
req, _ := http.NewRequest(http.MethodPost, path.String(), buffer)
|
||||
req.Header.Add("Content-Type", jsonContentType)
|
||||
return c.Do(req)
|
||||
}
|
||||
|
||||
// 异步检查是否有新的消息返回
|
||||
func (c *Client) SyncCheck(info LoginInfo, response WebInitResponse) (*http.Response, error) {
|
||||
path, _ := url.Parse(syncCheckUrl)
|
||||
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("_", strconv.FormatInt(time.Now().Unix(), 10))
|
||||
var syncKeyStringSlice []string
|
||||
// 将SyncKey里面的元素按照特定的格式拼接起来
|
||||
for _, item := range response.SyncKey.List {
|
||||
i := fmt.Sprintf("%d_%d", item.Key, item.Val)
|
||||
syncKeyStringSlice = append(syncKeyStringSlice, i)
|
||||
}
|
||||
syncKey := strings.Join(syncKeyStringSlice, "|")
|
||||
params.Add("synckey", syncKey)
|
||||
path.RawQuery = params.Encode()
|
||||
req, _ := http.NewRequest(http.MethodGet, path.String(), nil)
|
||||
return c.Do(req)
|
||||
func (c *Client) SyncCheck(info *LoginInfo, response *WebInitResponse) (*http.Response, error) {
|
||||
path, _ := url.Parse(syncCheckUrl)
|
||||
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("_", strconv.FormatInt(time.Now().Unix(), 10))
|
||||
var syncKeyStringSlice []string
|
||||
// 将SyncKey里面的元素按照特定的格式拼接起来
|
||||
for _, item := range response.SyncKey.List {
|
||||
i := fmt.Sprintf("%d_%d", item.Key, item.Val)
|
||||
syncKeyStringSlice = append(syncKeyStringSlice, i)
|
||||
}
|
||||
syncKey := strings.Join(syncKeyStringSlice, "|")
|
||||
params.Add("synckey", syncKey)
|
||||
path.RawQuery = params.Encode()
|
||||
req, _ := http.NewRequest(http.MethodGet, path.String(), nil)
|
||||
return c.Do(req)
|
||||
}
|
||||
|
||||
// 获取联系人信息
|
||||
func (c *Client) WebWxGetContact(info LoginInfo) (*http.Response, error) {
|
||||
path, _ := url.Parse(webWxGetContactUrl)
|
||||
params := url.Values{}
|
||||
params.Add("r", strconv.FormatInt(time.Now().Unix(), 10))
|
||||
params.Add("skey", info.SKey)
|
||||
params.Add("req", "0")
|
||||
path.RawQuery = params.Encode()
|
||||
return c.Get(path.String())
|
||||
func (c *Client) WebWxGetContact(info *LoginInfo) (*http.Response, error) {
|
||||
path, _ := url.Parse(webWxGetContactUrl)
|
||||
params := url.Values{}
|
||||
params.Add("r", strconv.FormatInt(time.Now().Unix(), 10))
|
||||
params.Add("skey", info.SKey)
|
||||
params.Add("req", "0")
|
||||
path.RawQuery = params.Encode()
|
||||
return c.Get(path.String())
|
||||
}
|
||||
|
||||
// 获取联系人详情
|
||||
func (c *Client) WebWxBatchGetContact(members Members, request BaseRequest) (*http.Response, error) {
|
||||
path, _ := url.Parse(webWxBatchGetContactUrl)
|
||||
params := url.Values{}
|
||||
params.Add("type", "ex")
|
||||
params.Add("r", strconv.FormatInt(time.Now().Unix(), 10))
|
||||
path.RawQuery = params.Encode()
|
||||
list := NewUserDetailItemList(members)
|
||||
content := map[string]interface{}{
|
||||
"BaseRequest": request,
|
||||
"Count": members.Count(),
|
||||
"List": list,
|
||||
}
|
||||
body, _ := ToBuffer(content)
|
||||
req, _ := http.NewRequest(http.MethodPost, path.String(), body)
|
||||
req.Header.Add("Content-Type", jsonContentType)
|
||||
return c.Do(req)
|
||||
func (c *Client) WebWxBatchGetContact(members Members, request *BaseRequest) (*http.Response, error) {
|
||||
path, _ := url.Parse(webWxBatchGetContactUrl)
|
||||
params := url.Values{}
|
||||
params.Add("type", "ex")
|
||||
params.Add("r", strconv.FormatInt(time.Now().Unix(), 10))
|
||||
path.RawQuery = params.Encode()
|
||||
list := NewUserDetailItemList(members)
|
||||
content := map[string]interface{}{
|
||||
"BaseRequest": request,
|
||||
"Count": members.Count(),
|
||||
"List": list,
|
||||
}
|
||||
body, _ := ToBuffer(content)
|
||||
req, _ := http.NewRequest(http.MethodPost, path.String(), body)
|
||||
req.Header.Add("Content-Type", jsonContentType)
|
||||
return c.Do(req)
|
||||
}
|
||||
|
||||
// 获取消息接口
|
||||
func (c *Client) WebWxSync(request BaseRequest, response WebInitResponse, info LoginInfo) (*http.Response, error) {
|
||||
path, _ := url.Parse(webWxSyncUrl)
|
||||
params := url.Values{}
|
||||
params.Add("sid", info.WxSid)
|
||||
params.Add("skey", info.SKey)
|
||||
params.Add("pass_ticket", info.PassTicket)
|
||||
path.RawQuery = params.Encode()
|
||||
content := map[string]interface{}{
|
||||
"BaseRequest": request,
|
||||
"SyncKey": response.SyncKey,
|
||||
"rr": strconv.FormatInt(time.Now().Unix(), 10),
|
||||
}
|
||||
data, _ := json.Marshal(content)
|
||||
body := bytes.NewBuffer(data)
|
||||
req, _ := http.NewRequest(http.MethodPost, path.String(), body)
|
||||
req.Header.Add("Content-Type", jsonContentType)
|
||||
return c.Do(req)
|
||||
func (c *Client) WebWxSync(request *BaseRequest, response *WebInitResponse, info *LoginInfo) (*http.Response, error) {
|
||||
path, _ := url.Parse(webWxSyncUrl)
|
||||
params := url.Values{}
|
||||
params.Add("sid", info.WxSid)
|
||||
params.Add("skey", info.SKey)
|
||||
params.Add("pass_ticket", info.PassTicket)
|
||||
path.RawQuery = params.Encode()
|
||||
content := map[string]interface{}{
|
||||
"BaseRequest": request,
|
||||
"SyncKey": response.SyncKey,
|
||||
"rr": strconv.FormatInt(time.Now().Unix(), 10),
|
||||
}
|
||||
data, _ := json.Marshal(content)
|
||||
body := bytes.NewBuffer(data)
|
||||
req, _ := http.NewRequest(http.MethodPost, path.String(), body)
|
||||
req.Header.Add("Content-Type", jsonContentType)
|
||||
return c.Do(req)
|
||||
}
|
||||
|
||||
// 发送消息
|
||||
func (c *Client) sendMessage(request BaseRequest, url string, msg *SendMessage) (*http.Response, error) {
|
||||
content := map[string]interface{}{
|
||||
"BaseRequest": request,
|
||||
"Msg": msg,
|
||||
"Scene": 0,
|
||||
}
|
||||
body, _ := ToBuffer(content)
|
||||
req, _ := http.NewRequest(http.MethodPost, url, body)
|
||||
req.Header.Add("Content-Type", jsonContentType)
|
||||
return c.Do(req)
|
||||
func (c *Client) sendMessage(request *BaseRequest, url string, msg *SendMessage) (*http.Response, error) {
|
||||
content := map[string]interface{}{
|
||||
"BaseRequest": request,
|
||||
"Msg": msg,
|
||||
"Scene": 0,
|
||||
}
|
||||
body, _ := ToBuffer(content)
|
||||
req, _ := http.NewRequest(http.MethodPost, url, body)
|
||||
req.Header.Add("Content-Type", jsonContentType)
|
||||
return c.Do(req)
|
||||
}
|
||||
|
||||
// 发送文本消息
|
||||
func (c *Client) WebWxSendMsg(msg *SendMessage, info LoginInfo, request BaseRequest) (*http.Response, error) {
|
||||
msg.Type = TextMessage
|
||||
path, _ := url.Parse(webWxSendMsgUrl)
|
||||
params := url.Values{}
|
||||
params.Add("lang", "zh_CN")
|
||||
params.Add("pass_ticket", info.PassTicket)
|
||||
path.RawQuery = params.Encode()
|
||||
return c.sendMessage(request, path.String(), msg)
|
||||
func (c *Client) WebWxSendMsg(msg *SendMessage, info *LoginInfo, request *BaseRequest) (*http.Response, error) {
|
||||
msg.Type = TextMessage
|
||||
path, _ := url.Parse(webWxSendMsgUrl)
|
||||
params := url.Values{}
|
||||
params.Add("lang", "zh_CN")
|
||||
params.Add("pass_ticket", info.PassTicket)
|
||||
path.RawQuery = params.Encode()
|
||||
return c.sendMessage(request, path.String(), msg)
|
||||
}
|
||||
|
||||
// 获取用户的头像
|
||||
func (c *Client) WebWxGetHeadImg(headImageUrl string) (*http.Response, error) {
|
||||
path := baseUrl + headImageUrl
|
||||
return c.Get(path)
|
||||
path := baseUrl + headImageUrl
|
||||
return c.Get(path)
|
||||
}
|
||||
|
||||
// 上传文件
|
||||
func (c *Client) WebWxUploadMedia(file *os.File, request BaseRequest, info LoginInfo, forUserName, toUserName, contentType, mediaType string) (*http.Response, error) {
|
||||
path, _ := url.Parse(webWxUpLoadMediaUrl)
|
||||
params := url.Values{}
|
||||
params.Add("f", "json")
|
||||
path.RawQuery = params.Encode()
|
||||
sate, err := file.Stat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buffer := bytes.Buffer{}
|
||||
if _, err := buffer.ReadFrom(file); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data := buffer.Bytes()
|
||||
fileMd5 := fmt.Sprintf("%x", md5.Sum(data))
|
||||
cookies := c.Jar.Cookies(path)
|
||||
uploadMediaRequest := map[string]interface{}{
|
||||
"UploadType": 2,
|
||||
"BaseRequest": request,
|
||||
"ClientMediaId": time.Now().Unix() * 1e4,
|
||||
"TotalLen": sate.Size(),
|
||||
"StartPos": 0,
|
||||
"DataLen": sate.Size(),
|
||||
"MediaType": 4,
|
||||
"FromUserName": forUserName,
|
||||
"ToUserName": toUserName,
|
||||
"FileMd5": fileMd5,
|
||||
}
|
||||
uploadMediaRequestByte, err := json.Marshal(uploadMediaRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
content := map[string]interface{}{
|
||||
"id": "WU_FILE_0",
|
||||
"name": file.Name(),
|
||||
"type": contentType,
|
||||
"lastModifiedDate": time.Now().Format(http.TimeFormat),
|
||||
"size": sate.Size(),
|
||||
"mediatype": mediaType,
|
||||
"webwx_data_ticket": getWebWxDataTicket(cookies),
|
||||
"pass_ticket": info.PassTicket,
|
||||
}
|
||||
body, err := ToBuffer(content)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
writer := multipart.NewWriter(body)
|
||||
if err = writer.WriteField("uploadmediarequest", string(uploadMediaRequestByte)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if w, err := writer.CreateFormFile("filename", file.Name()); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
if _, err = w.Write(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
ct := writer.FormDataContentType()
|
||||
if err = writer.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.Post(path.String(), ct, body)
|
||||
func (c *Client) WebWxUploadMedia(file *os.File, request *BaseRequest, info *LoginInfo, forUserName, toUserName, contentType, mediaType string) (*http.Response, error) {
|
||||
path, _ := url.Parse(webWxUpLoadMediaUrl)
|
||||
params := url.Values{}
|
||||
params.Add("f", "json")
|
||||
path.RawQuery = params.Encode()
|
||||
sate, err := file.Stat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buffer := bytes.Buffer{}
|
||||
if _, err := buffer.ReadFrom(file); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data := buffer.Bytes()
|
||||
fileMd5 := fmt.Sprintf("%x", md5.Sum(data))
|
||||
cookies := c.Jar.Cookies(path)
|
||||
uploadMediaRequest := map[string]interface{}{
|
||||
"UploadType": 2,
|
||||
"BaseRequest": request,
|
||||
"ClientMediaId": time.Now().Unix() * 1e4,
|
||||
"TotalLen": sate.Size(),
|
||||
"StartPos": 0,
|
||||
"DataLen": sate.Size(),
|
||||
"MediaType": 4,
|
||||
"FromUserName": forUserName,
|
||||
"ToUserName": toUserName,
|
||||
"FileMd5": fileMd5,
|
||||
}
|
||||
uploadMediaRequestByte, err := json.Marshal(uploadMediaRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
content := map[string]interface{}{
|
||||
"id": "WU_FILE_0",
|
||||
"name": file.Name(),
|
||||
"type": contentType,
|
||||
"lastModifiedDate": time.Now().Format(http.TimeFormat),
|
||||
"size": sate.Size(),
|
||||
"mediatype": mediaType,
|
||||
"webwx_data_ticket": getWebWxDataTicket(cookies),
|
||||
"pass_ticket": info.PassTicket,
|
||||
}
|
||||
body, err := ToBuffer(content)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
writer := multipart.NewWriter(body)
|
||||
if err = writer.WriteField("uploadmediarequest", string(uploadMediaRequestByte)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if w, err := writer.CreateFormFile("filename", file.Name()); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
if _, err = w.Write(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
ct := writer.FormDataContentType()
|
||||
if err = writer.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.Post(path.String(), ct, body)
|
||||
}
|
||||
|
||||
// 发送图片
|
||||
// 这个接口依赖上传文件的接口
|
||||
// 发送的图片必须是已经成功上传的图片
|
||||
func (c *Client) WebWxSendMsgImg(msg *SendMessage, request BaseRequest, info LoginInfo) (*http.Response, error) {
|
||||
msg.Type = ImageMessage
|
||||
path, _ := url.Parse(webWxSendMsgImgUrl)
|
||||
params := url.Values{}
|
||||
params.Add("fun", "async")
|
||||
params.Add("f", "json")
|
||||
params.Add("lang", "zh_CN")
|
||||
params.Add("pass_ticket", info.PassTicket)
|
||||
path.RawQuery = params.Encode()
|
||||
return c.sendMessage(request, path.String(), msg)
|
||||
func (c *Client) WebWxSendMsgImg(msg *SendMessage, request *BaseRequest, info *LoginInfo) (*http.Response, error) {
|
||||
msg.Type = ImageMessage
|
||||
path, _ := url.Parse(webWxSendMsgImgUrl)
|
||||
params := url.Values{}
|
||||
params.Add("fun", "async")
|
||||
params.Add("f", "json")
|
||||
params.Add("lang", "zh_CN")
|
||||
params.Add("pass_ticket", info.PassTicket)
|
||||
path.RawQuery = params.Encode()
|
||||
return c.sendMessage(request, path.String(), msg)
|
||||
}
|
||||
|
||||
// 发送文件信息
|
||||
func (c *Client) WebWxSendAppMsg(msg *SendMessage, request BaseRequest) (*http.Response, error) {
|
||||
msg.Type = AppMessage
|
||||
path, _ := url.Parse(webWxSendAppMsgUrl)
|
||||
params := url.Values{}
|
||||
params.Add("fun", "async")
|
||||
params.Add("f", "json")
|
||||
path.RawQuery = params.Encode()
|
||||
return c.sendMessage(request, path.String(), msg)
|
||||
func (c *Client) WebWxSendAppMsg(msg *SendMessage, request *BaseRequest) (*http.Response, error) {
|
||||
msg.Type = AppMessage
|
||||
path, _ := url.Parse(webWxSendAppMsgUrl)
|
||||
params := url.Values{}
|
||||
params.Add("fun", "async")
|
||||
params.Add("f", "json")
|
||||
path.RawQuery = params.Encode()
|
||||
return c.sendMessage(request, path.String(), msg)
|
||||
}
|
||||
|
||||
// 用户重命名接口
|
||||
func (c *Client) WebWxOplog(request BaseRequest, remarkName, userName string, ) (*http.Response, error) {
|
||||
path, _ := url.Parse(webWxOplogUrl)
|
||||
params := url.Values{}
|
||||
params.Add("lang", "zh_CN")
|
||||
path.RawQuery = params.Encode()
|
||||
content := map[string]interface{}{
|
||||
"BaseRequest": request,
|
||||
"CmdId": 2,
|
||||
"RemarkName": remarkName,
|
||||
"UserName": userName,
|
||||
}
|
||||
body, _ := ToBuffer(content)
|
||||
req, _ := http.NewRequest(http.MethodPost, path.String(), body)
|
||||
req.Header.Add("Content-Type", jsonContentType)
|
||||
return c.Do(req)
|
||||
func (c *Client) WebWxOplog(request *BaseRequest, remarkName, userName string, ) (*http.Response, error) {
|
||||
path, _ := url.Parse(webWxOplogUrl)
|
||||
params := url.Values{}
|
||||
params.Add("lang", "zh_CN")
|
||||
path.RawQuery = params.Encode()
|
||||
content := map[string]interface{}{
|
||||
"BaseRequest": request,
|
||||
"CmdId": 2,
|
||||
"RemarkName": remarkName,
|
||||
"UserName": userName,
|
||||
}
|
||||
body, _ := ToBuffer(content)
|
||||
req, _ := http.NewRequest(http.MethodPost, path.String(), body)
|
||||
req.Header.Add("Content-Type", jsonContentType)
|
||||
return c.Do(req)
|
||||
}
|
||||
|
||||
// 添加用户为好友接口
|
||||
func (c *Client) WebWxVerifyUser(storage WechatStorage, info RecommendInfo, verifyContent string) (*http.Response, error) {
|
||||
loginInfo := storage.GetLoginInfo()
|
||||
path, _ := url.Parse(webWxVerifyUserUrl)
|
||||
params := url.Values{}
|
||||
params.Add("r", strconv.FormatInt(time.Now().Unix(), 10))
|
||||
params.Add("lang", "zh_CN")
|
||||
params.Add("pass_ticket", loginInfo.PassTicket)
|
||||
path.RawQuery = params.Encode()
|
||||
content := map[string]interface{}{
|
||||
"BaseRequest": storage.GetBaseRequest(),
|
||||
"Opcode": 3,
|
||||
"SceneList": []int{33},
|
||||
"SceneListCount": 1,
|
||||
"VerifyContent": verifyContent,
|
||||
"VerifyUserList": []interface{}{map[string]string{
|
||||
"Value": info.UserName,
|
||||
"VerifyUserTicket": info.Ticket,
|
||||
}},
|
||||
"VerifyUserListSize": 1,
|
||||
"skey": loginInfo.SKey,
|
||||
}
|
||||
body, _ := ToBuffer(content)
|
||||
req, _ := http.NewRequest(http.MethodPost, path.String(), body)
|
||||
req.Header.Add("Content-Type", jsonContentType)
|
||||
return c.Do(req)
|
||||
func (c *Client) WebWxVerifyUser(storage *Storage, info RecommendInfo, verifyContent string) (*http.Response, error) {
|
||||
loginInfo := storage.LoginInfo
|
||||
path, _ := url.Parse(webWxVerifyUserUrl)
|
||||
params := url.Values{}
|
||||
params.Add("r", strconv.FormatInt(time.Now().Unix(), 10))
|
||||
params.Add("lang", "zh_CN")
|
||||
params.Add("pass_ticket", loginInfo.PassTicket)
|
||||
path.RawQuery = params.Encode()
|
||||
content := map[string]interface{}{
|
||||
"BaseRequest": storage.Request,
|
||||
"Opcode": 3,
|
||||
"SceneList": []int{33},
|
||||
"SceneListCount": 1,
|
||||
"VerifyContent": verifyContent,
|
||||
"VerifyUserList": []interface{}{map[string]string{
|
||||
"Value": info.UserName,
|
||||
"VerifyUserTicket": info.Ticket,
|
||||
}},
|
||||
"VerifyUserListSize": 1,
|
||||
"skey": loginInfo.SKey,
|
||||
}
|
||||
body, _ := ToBuffer(content)
|
||||
req, _ := http.NewRequest(http.MethodPost, path.String(), body)
|
||||
req.Header.Add("Content-Type", jsonContentType)
|
||||
return c.Do(req)
|
||||
}
|
||||
|
||||
// 获取图片消息的图片响应
|
||||
func (c *Client) WebWxGetMsgImg(msg *Message, info LoginInfo) (*http.Response, error) {
|
||||
path, _ := url.Parse(webWxGetMsgImgUrl)
|
||||
params := url.Values{}
|
||||
params.Add("MsgID", msg.MsgId)
|
||||
params.Add("skey", info.SKey)
|
||||
params.Add("type", "slave")
|
||||
path.RawQuery = params.Encode()
|
||||
return c.Get(path.String())
|
||||
func (c *Client) WebWxGetMsgImg(msg *Message, info *LoginInfo) (*http.Response, error) {
|
||||
path, _ := url.Parse(webWxGetMsgImgUrl)
|
||||
params := url.Values{}
|
||||
params.Add("MsgID", msg.MsgId)
|
||||
params.Add("skey", info.SKey)
|
||||
params.Add("type", "slave")
|
||||
path.RawQuery = params.Encode()
|
||||
return c.Get(path.String())
|
||||
}
|
||||
|
||||
// 获取语音消息的语音响应
|
||||
func (c *Client) WebWxGetVoice(msg *Message, info LoginInfo) (*http.Response, error) {
|
||||
path, _ := url.Parse(webWxGetVoiceUrl)
|
||||
params := url.Values{}
|
||||
params.Add("msgid", msg.MsgId)
|
||||
params.Add("skey", info.SKey)
|
||||
path.RawQuery = params.Encode()
|
||||
return c.Get(path.String())
|
||||
func (c *Client) WebWxGetVoice(msg *Message, info *LoginInfo) (*http.Response, error) {
|
||||
path, _ := url.Parse(webWxGetVoiceUrl)
|
||||
params := url.Values{}
|
||||
params.Add("msgid", msg.MsgId)
|
||||
params.Add("skey", info.SKey)
|
||||
path.RawQuery = params.Encode()
|
||||
return c.Get(path.String())
|
||||
}
|
||||
|
||||
// 获取视频消息的视频响应
|
||||
func (c *Client) WebWxGetVideo(msg *Message, info LoginInfo) (*http.Response, error) {
|
||||
path, _ := url.Parse(webWxGetVideoUrl)
|
||||
params := url.Values{}
|
||||
params.Add("msgid", msg.MsgId)
|
||||
params.Add("skey", info.SKey)
|
||||
path.RawQuery = params.Encode()
|
||||
return c.Get(path.String())
|
||||
func (c *Client) WebWxGetVideo(msg *Message, info *LoginInfo) (*http.Response, error) {
|
||||
path, _ := url.Parse(webWxGetVideoUrl)
|
||||
params := url.Values{}
|
||||
params.Add("msgid", msg.MsgId)
|
||||
params.Add("skey", info.SKey)
|
||||
path.RawQuery = params.Encode()
|
||||
return c.Get(path.String())
|
||||
}
|
||||
|
||||
// 获取文件消息的文件响应
|
||||
func (c *Client) WebWxGetMedia(msg *Message, info LoginInfo) (*http.Response, error) {
|
||||
path, _ := url.Parse(webWxGetMediaUrl)
|
||||
params := url.Values{}
|
||||
params.Add("sender", msg.FromUserName)
|
||||
params.Add("mediaid", msg.MediaId)
|
||||
params.Add("encryfilename", msg.EncryFileName)
|
||||
params.Add("fromuser", fmt.Sprintf("%d", info.WxUin))
|
||||
params.Add("pass_ticket", info.PassTicket)
|
||||
params.Add("webwx_data_ticket", getWebWxDataTicket(c.Jar.Cookies(path)))
|
||||
path.RawQuery = params.Encode()
|
||||
return c.Get(path.String())
|
||||
func (c *Client) WebWxGetMedia(msg *Message, info *LoginInfo) (*http.Response, error) {
|
||||
path, _ := url.Parse(webWxGetMediaUrl)
|
||||
params := url.Values{}
|
||||
params.Add("sender", msg.FromUserName)
|
||||
params.Add("mediaid", msg.MediaId)
|
||||
params.Add("encryfilename", msg.EncryFileName)
|
||||
params.Add("fromuser", fmt.Sprintf("%d", info.WxUin))
|
||||
params.Add("pass_ticket", info.PassTicket)
|
||||
params.Add("webwx_data_ticket", getWebWxDataTicket(c.Jar.Cookies(path)))
|
||||
path.RawQuery = params.Encode()
|
||||
return c.Get(path.String())
|
||||
}
|
||||
|
||||
// 用户退出
|
||||
func (c *Client) Logout(info LoginInfo) (*http.Response, error) {
|
||||
path, _ := url.Parse(webWxLogoutUrl)
|
||||
params := url.Values{}
|
||||
params.Add("redirect", "1")
|
||||
params.Add("type", "1")
|
||||
params.Add("skey", info.SKey)
|
||||
path.RawQuery = params.Encode()
|
||||
return c.Get(path.String())
|
||||
func (c *Client) Logout(info *LoginInfo) (*http.Response, error) {
|
||||
path, _ := url.Parse(webWxLogoutUrl)
|
||||
params := url.Values{}
|
||||
params.Add("redirect", "1")
|
||||
params.Add("type", "1")
|
||||
params.Add("skey", info.SKey)
|
||||
path.RawQuery = params.Encode()
|
||||
return c.Get(path.String())
|
||||
}
|
||||
|
16
message.go
16
message.go
@ -127,8 +127,8 @@ func (m *Message) IsSendByGroup() bool {
|
||||
// 回复消息
|
||||
func (m *Message) Reply(msgType int, content, mediaId string) error {
|
||||
msg := NewSendMessage(msgType, content, m.Bot.self.User.UserName, m.FromUserName, mediaId)
|
||||
info := m.Bot.storage.GetLoginInfo()
|
||||
request := m.Bot.storage.GetBaseRequest()
|
||||
info := m.Bot.storage.LoginInfo
|
||||
request := m.Bot.storage.Request
|
||||
return m.Bot.Caller.WebWxSendMsg(msg, info, request)
|
||||
}
|
||||
|
||||
@ -139,8 +139,8 @@ func (m *Message) ReplyText(content string) error {
|
||||
|
||||
// 回复图片消息
|
||||
func (m *Message) ReplyImage(file *os.File) error {
|
||||
info := m.Bot.storage.GetLoginInfo()
|
||||
request := m.Bot.storage.GetBaseRequest()
|
||||
info := m.Bot.storage.LoginInfo
|
||||
request := m.Bot.storage.Request
|
||||
return m.Bot.Caller.WebWxSendImageMsg(file, request, info, m.Bot.self.UserName, m.FromUserName)
|
||||
}
|
||||
|
||||
@ -199,16 +199,16 @@ func (m *Message) GetFile() (*http.Response, error) {
|
||||
return nil, errors.New("invalid message type")
|
||||
}
|
||||
if m.IsPicture() {
|
||||
return m.Bot.Caller.Client.WebWxGetMsgImg(m, m.Bot.storage.GetLoginInfo())
|
||||
return m.Bot.Caller.Client.WebWxGetMsgImg(m, m.Bot.storage.LoginInfo)
|
||||
}
|
||||
if m.IsVoice() {
|
||||
return m.Bot.Caller.Client.WebWxGetVoice(m, m.Bot.storage.GetLoginInfo())
|
||||
return m.Bot.Caller.Client.WebWxGetVoice(m, m.Bot.storage.LoginInfo)
|
||||
}
|
||||
if m.IsVideo() {
|
||||
return m.Bot.Caller.Client.WebWxGetVideo(m, m.Bot.storage.GetLoginInfo())
|
||||
return m.Bot.Caller.Client.WebWxGetVideo(m, m.Bot.storage.LoginInfo)
|
||||
}
|
||||
if m.IsMedia() {
|
||||
return m.Bot.Caller.Client.WebWxGetMedia(m, m.Bot.storage.GetLoginInfo())
|
||||
return m.Bot.Caller.Client.WebWxGetMedia(m, m.Bot.storage.LoginInfo)
|
||||
}
|
||||
return nil, errors.New("unsupported type")
|
||||
}
|
||||
|
46
stroage.go
46
stroage.go
@ -1,49 +1,3 @@
|
||||
|
||||
package openwechat
|
||||
|
||||
// WechatStorage
|
||||
// 可以根据自己的情况来实现该接口
|
||||
type WechatStorage interface {
|
||||
SetLoginInfo(loginInfo LoginInfo)
|
||||
SetBaseRequest(baseRequest BaseRequest)
|
||||
SetWebInitResponse(webInitResponse WebInitResponse)
|
||||
GetLoginInfo() LoginInfo
|
||||
GetBaseRequest() BaseRequest
|
||||
GetWebInitResponse() WebInitResponse
|
||||
}
|
||||
|
||||
// implement WechatStorage
|
||||
// WechatStorage接口的实现
|
||||
type SimpleWechatStorage struct {
|
||||
loginInfo LoginInfo
|
||||
baseRequest BaseRequest
|
||||
webInitResponse WebInitResponse
|
||||
}
|
||||
|
||||
func NewSimpleWechatStorage() *SimpleWechatStorage {
|
||||
return &SimpleWechatStorage{}
|
||||
}
|
||||
|
||||
func (s *SimpleWechatStorage) SetLoginInfo(loginInfo LoginInfo) {
|
||||
s.loginInfo = loginInfo
|
||||
}
|
||||
|
||||
func (s *SimpleWechatStorage) SetBaseRequest(baseRequest BaseRequest) {
|
||||
s.baseRequest = baseRequest
|
||||
}
|
||||
|
||||
func (s *SimpleWechatStorage) SetWebInitResponse(webInitResponse WebInitResponse) {
|
||||
s.webInitResponse = webInitResponse
|
||||
}
|
||||
|
||||
func (s *SimpleWechatStorage) GetLoginInfo() LoginInfo {
|
||||
return s.loginInfo
|
||||
}
|
||||
|
||||
func (s *SimpleWechatStorage) GetBaseRequest() BaseRequest {
|
||||
return s.baseRequest
|
||||
}
|
||||
|
||||
func (s *SimpleWechatStorage) GetWebInitResponse() WebInitResponse {
|
||||
return s.webInitResponse
|
||||
}
|
||||
|
508
user.go
508
user.go
@ -1,349 +1,355 @@
|
||||
package openwechat
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
Uin int
|
||||
HideInputBarFlag int
|
||||
StarFriend int
|
||||
Sex int
|
||||
AppAccountFlag int
|
||||
VerifyFlag int
|
||||
ContactFlag int
|
||||
WebWxPluginSwitch int
|
||||
HeadImgFlag int
|
||||
SnsFlag int
|
||||
UserName string
|
||||
NickName string
|
||||
HeadImgUrl string
|
||||
RemarkName string
|
||||
PYInitial string
|
||||
PYQuanPin string
|
||||
RemarkPYInitial string
|
||||
RemarkPYQuanPin string
|
||||
Signature string
|
||||
MemberCount int
|
||||
MemberList Members
|
||||
OwnerUin int
|
||||
Statues int
|
||||
AttrStatus int
|
||||
Province string
|
||||
City string
|
||||
Alias string
|
||||
UniFriend int
|
||||
DisplayName string
|
||||
ChatRoomId int
|
||||
KeyWord string
|
||||
EncryChatRoomId string
|
||||
IsOwner int
|
||||
Uin int
|
||||
HideInputBarFlag int
|
||||
StarFriend int
|
||||
Sex int
|
||||
AppAccountFlag int
|
||||
VerifyFlag int
|
||||
ContactFlag int
|
||||
WebWxPluginSwitch int
|
||||
HeadImgFlag int
|
||||
SnsFlag int
|
||||
UserName string
|
||||
NickName string
|
||||
HeadImgUrl string
|
||||
RemarkName string
|
||||
PYInitial string
|
||||
PYQuanPin string
|
||||
RemarkPYInitial string
|
||||
RemarkPYQuanPin string
|
||||
Signature string
|
||||
MemberCount int
|
||||
MemberList Members
|
||||
OwnerUin int
|
||||
Statues int
|
||||
AttrStatus int
|
||||
Province string
|
||||
City string
|
||||
Alias string
|
||||
UniFriend int
|
||||
DisplayName string
|
||||
ChatRoomId int
|
||||
KeyWord string
|
||||
EncryChatRoomId string
|
||||
IsOwner int
|
||||
|
||||
Self *Self
|
||||
Self *Self
|
||||
}
|
||||
|
||||
// implement fmt.Stringer
|
||||
func (u *User) String() string {
|
||||
return fmt.Sprintf("<User:%s>", u.NickName)
|
||||
return fmt.Sprintf("<User:%s>", u.NickName)
|
||||
}
|
||||
|
||||
// 获取用户头像
|
||||
func (u *User) GetAvatarResponse() (*http.Response, error) {
|
||||
return u.Self.Bot.Caller.Client.WebWxGetHeadImg(u.HeadImgUrl)
|
||||
return u.Self.Bot.Caller.Client.WebWxGetHeadImg(u.HeadImgUrl)
|
||||
}
|
||||
|
||||
// 下载用户头像
|
||||
func (u *User) SaveAvatar(filename string) error {
|
||||
resp, err := u.GetAvatarResponse()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
buffer := bytes.Buffer{}
|
||||
if _, err := buffer.ReadFrom(resp.Body); err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(filename, buffer.Bytes(), os.ModePerm)
|
||||
resp, err := u.GetAvatarResponse()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
buffer := bytes.Buffer{}
|
||||
if _, err := buffer.ReadFrom(resp.Body); err != nil {
|
||||
return err
|
||||
}
|
||||
file, err := os.Create(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
_, err = file.Write(buffer.Bytes())
|
||||
return err
|
||||
}
|
||||
|
||||
func (u *User) sendMsg(msg *SendMessage) error {
|
||||
msg.FromUserName = u.Self.UserName
|
||||
msg.ToUserName = u.UserName
|
||||
info := u.Self.Bot.storage.GetLoginInfo()
|
||||
request := u.Self.Bot.storage.GetBaseRequest()
|
||||
return u.Self.Bot.Caller.WebWxSendMsg(msg, info, request)
|
||||
msg.FromUserName = u.Self.UserName
|
||||
msg.ToUserName = u.UserName
|
||||
info := u.Self.Bot.storage.LoginInfo
|
||||
request := u.Self.Bot.storage.Request
|
||||
return u.Self.Bot.Caller.WebWxSendMsg(msg, info, request)
|
||||
}
|
||||
|
||||
func (u *User) sendText(content string) error {
|
||||
msg := NewTextSendMessage(content, u.Self.UserName, u.UserName)
|
||||
return u.sendMsg(msg)
|
||||
msg := NewTextSendMessage(content, u.Self.UserName, u.UserName)
|
||||
return u.sendMsg(msg)
|
||||
}
|
||||
|
||||
func (u *User) sendImage(file *os.File) error {
|
||||
request := u.Self.Bot.storage.GetBaseRequest()
|
||||
info := u.Self.Bot.storage.GetLoginInfo()
|
||||
return u.Self.Bot.Caller.WebWxSendImageMsg(file, request, info, u.Self.UserName, u.UserName)
|
||||
request := u.Self.Bot.storage.Request
|
||||
info := u.Self.Bot.storage.LoginInfo
|
||||
return u.Self.Bot.Caller.WebWxSendImageMsg(file, request, info, u.Self.UserName, u.UserName)
|
||||
}
|
||||
|
||||
func (u *User) setRemarkName(remarkName string) error {
|
||||
request := u.Self.Bot.storage.GetBaseRequest()
|
||||
return u.Self.Bot.Caller.WebWxOplog(request, remarkName, u.UserName)
|
||||
request := u.Self.Bot.storage.Request
|
||||
return u.Self.Bot.Caller.WebWxOplog(request, remarkName, u.UserName)
|
||||
}
|
||||
|
||||
// 获取用户的详情
|
||||
func (u *User) Detail() (*User, error) {
|
||||
members := Members{u}
|
||||
request := u.Self.Bot.storage.GetBaseRequest()
|
||||
newMembers, err := u.Self.Bot.Caller.WebWxBatchGetContact(members, request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
user := newMembers.First()
|
||||
user.Self = u.Self
|
||||
return user, nil
|
||||
members := Members{u}
|
||||
request := u.Self.Bot.storage.Request
|
||||
newMembers, err := u.Self.Bot.Caller.WebWxBatchGetContact(members, request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
user := newMembers.First()
|
||||
user.Self = u.Self
|
||||
return user, nil
|
||||
}
|
||||
|
||||
type Self struct {
|
||||
*User
|
||||
Bot *Bot
|
||||
fileHelper *Friend
|
||||
members Members
|
||||
friends Friends
|
||||
groups Groups
|
||||
*User
|
||||
Bot *Bot
|
||||
fileHelper *Friend
|
||||
members Members
|
||||
friends Friends
|
||||
groups Groups
|
||||
}
|
||||
|
||||
// 获取所有的好友、群组、公众号信息
|
||||
func (s *Self) Members(update ...bool) (Members, error) {
|
||||
// 首先判断缓存里有没有,如果没有则去更新缓存
|
||||
if s.members == nil {
|
||||
if err := s.updateMembers(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.members, nil
|
||||
}
|
||||
// 判断是否需要更新,如果传入的参数不为nil,则取最后一个
|
||||
var isUpdate bool
|
||||
if len(update) > 0 {
|
||||
isUpdate = update[len(update)-1]
|
||||
}
|
||||
// 如果需要更新,则直接更新缓存
|
||||
if isUpdate {
|
||||
if err := s.updateMembers(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return s.members, nil
|
||||
// 首先判断缓存里有没有,如果没有则去更新缓存
|
||||
if s.members == nil {
|
||||
if err := s.updateMembers(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.members, nil
|
||||
}
|
||||
// 判断是否需要更新,如果传入的参数不为nil,则取最后一个
|
||||
var isUpdate bool
|
||||
if len(update) > 0 {
|
||||
isUpdate = update[len(update)-1]
|
||||
}
|
||||
// 如果需要更新,则直接更新缓存
|
||||
if isUpdate {
|
||||
if err := s.updateMembers(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return s.members, nil
|
||||
}
|
||||
|
||||
// 更新联系人处理
|
||||
func (s *Self) updateMembers() error {
|
||||
info := s.Bot.storage.GetLoginInfo()
|
||||
members, err := s.Bot.Caller.WebWxGetContact(info)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
members.SetOwner(s)
|
||||
s.members = members
|
||||
return nil
|
||||
info := s.Bot.storage.LoginInfo
|
||||
members, err := s.Bot.Caller.WebWxGetContact(info)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
members.SetOwner(s)
|
||||
s.members = members
|
||||
return nil
|
||||
}
|
||||
|
||||
// 获取文件传输助手对象,封装成Friend返回
|
||||
func (s *Self) FileHelper() (*Friend, error) {
|
||||
// 如果缓存里有,直接返回,否则去联系人里面找
|
||||
if s.fileHelper != nil {
|
||||
return s.fileHelper, nil
|
||||
}
|
||||
members, err := s.Members()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
users := members.SearchByUserName(1, "filehelper")
|
||||
if users == nil {
|
||||
return nil, noSuchUserFoundError
|
||||
}
|
||||
s.fileHelper = &Friend{users.First()}
|
||||
return s.fileHelper, nil
|
||||
// 如果缓存里有,直接返回,否则去联系人里面找
|
||||
if s.fileHelper != nil {
|
||||
return s.fileHelper, nil
|
||||
}
|
||||
members, err := s.Members()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
users := members.SearchByUserName(1, "filehelper")
|
||||
if users == nil {
|
||||
return nil, noSuchUserFoundError
|
||||
}
|
||||
s.fileHelper = &Friend{users.First()}
|
||||
return s.fileHelper, nil
|
||||
}
|
||||
|
||||
// 获取所有的好友
|
||||
func (s *Self) Friends(update ...bool) (Friends, error) {
|
||||
if s.friends == nil {
|
||||
if err := s.updateFriends(true); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return s.friends, nil
|
||||
if s.friends == nil {
|
||||
if err := s.updateFriends(true); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return s.friends, nil
|
||||
}
|
||||
|
||||
// 获取所有的群组
|
||||
func (s *Self) Groups(update ...bool) (Groups, error) {
|
||||
if s.groups == nil {
|
||||
if err := s.updateGroups(update...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return s.groups, nil
|
||||
if s.groups == nil {
|
||||
if err := s.updateGroups(update...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return s.groups, nil
|
||||
}
|
||||
|
||||
// 更新好友处理
|
||||
func (s *Self) updateFriends(update ...bool) error {
|
||||
var isUpdate bool
|
||||
if len(update) > 0 {
|
||||
isUpdate = update[len(update)-1]
|
||||
}
|
||||
if isUpdate || s.members == nil {
|
||||
if err := s.updateMembers(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
var friends Friends
|
||||
for _, member := range s.members {
|
||||
if isFriend(*member) {
|
||||
friend := &Friend{member}
|
||||
friend.Self = s
|
||||
friends = append(friends, friend)
|
||||
}
|
||||
}
|
||||
s.friends = friends
|
||||
return nil
|
||||
var isUpdate bool
|
||||
if len(update) > 0 {
|
||||
isUpdate = update[len(update)-1]
|
||||
}
|
||||
if isUpdate || s.members == nil {
|
||||
if err := s.updateMembers(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
var friends Friends
|
||||
for _, member := range s.members {
|
||||
if isFriend(*member) {
|
||||
friend := &Friend{member}
|
||||
friend.Self = s
|
||||
friends = append(friends, friend)
|
||||
}
|
||||
}
|
||||
s.friends = friends
|
||||
return nil
|
||||
}
|
||||
|
||||
// 更新群组处理
|
||||
func (s *Self) updateGroups(update ...bool) error {
|
||||
var isUpdate bool
|
||||
if len(update) > 0 {
|
||||
isUpdate = update[len(update)-1]
|
||||
}
|
||||
if isUpdate || s.members == nil {
|
||||
if err := s.updateMembers(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
var groups Groups
|
||||
for _, member := range s.members {
|
||||
if isGroup(*member) {
|
||||
group := &Group{member}
|
||||
groups = append(groups, group)
|
||||
}
|
||||
}
|
||||
s.groups = groups
|
||||
return nil
|
||||
var isUpdate bool
|
||||
if len(update) > 0 {
|
||||
isUpdate = update[len(update)-1]
|
||||
}
|
||||
if isUpdate || s.members == nil {
|
||||
if err := s.updateMembers(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
var groups Groups
|
||||
for _, member := range s.members {
|
||||
if isGroup(*member) {
|
||||
group := &Group{member}
|
||||
groups = append(groups, group)
|
||||
}
|
||||
}
|
||||
s.groups = groups
|
||||
return nil
|
||||
}
|
||||
|
||||
// 更新所有的联系人信息
|
||||
func (s *Self) UpdateMembersDetail() error {
|
||||
// 先获取所有的联系人
|
||||
members, err := s.Members()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 获取他们的数量
|
||||
count := members.Count()
|
||||
// 一次更新50个,分情况讨论
|
||||
// 先获取所有的联系人
|
||||
members, err := s.Members()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 获取他们的数量
|
||||
count := members.Count()
|
||||
// 一次更新50个,分情况讨论
|
||||
|
||||
// 获取总的需要更新的次数
|
||||
var times int
|
||||
if count < 50 {
|
||||
times = 1
|
||||
} else {
|
||||
times = count / 50
|
||||
}
|
||||
var newMembers Members
|
||||
request := s.Bot.storage.GetBaseRequest()
|
||||
var pMembers Members
|
||||
// 分情况依次更新
|
||||
for i := 1; i <= times; i++ {
|
||||
if times == 1 {
|
||||
pMembers = members
|
||||
} else {
|
||||
pMembers = members[(i-1)*50 : i*50]
|
||||
}
|
||||
nMembers, err := s.Bot.Caller.WebWxBatchGetContact(pMembers, request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newMembers = append(newMembers, nMembers...)
|
||||
}
|
||||
// 最后判断是否全部更新完毕
|
||||
total := times * 50
|
||||
if total < count {
|
||||
// 将全部剩余的更新完毕
|
||||
left := count - total
|
||||
pMembers = members[total : total+left]
|
||||
nMembers, err := s.Bot.Caller.WebWxBatchGetContact(pMembers, request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newMembers = append(newMembers, nMembers...)
|
||||
}
|
||||
newMembers.SetOwner(s)
|
||||
s.members = newMembers
|
||||
return nil
|
||||
// 获取总的需要更新的次数
|
||||
var times int
|
||||
if count < 50 {
|
||||
times = 1
|
||||
} else {
|
||||
times = count / 50
|
||||
}
|
||||
var newMembers Members
|
||||
request := s.Bot.storage.Request
|
||||
var pMembers Members
|
||||
// 分情况依次更新
|
||||
for i := 1; i <= times; i++ {
|
||||
if times == 1 {
|
||||
pMembers = members
|
||||
} else {
|
||||
pMembers = members[(i-1)*50 : i*50]
|
||||
}
|
||||
nMembers, err := s.Bot.Caller.WebWxBatchGetContact(pMembers, request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newMembers = append(newMembers, nMembers...)
|
||||
}
|
||||
// 最后判断是否全部更新完毕
|
||||
total := times * 50
|
||||
if total < count {
|
||||
// 将全部剩余的更新完毕
|
||||
left := count - total
|
||||
pMembers = members[total : total+left]
|
||||
nMembers, err := s.Bot.Caller.WebWxBatchGetContact(pMembers, request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newMembers = append(newMembers, nMembers...)
|
||||
}
|
||||
newMembers.SetOwner(s)
|
||||
s.members = newMembers
|
||||
return nil
|
||||
}
|
||||
|
||||
type Members []*User
|
||||
|
||||
func (m Members) Count() int {
|
||||
return len(m)
|
||||
return len(m)
|
||||
}
|
||||
|
||||
func (m Members) First() *User {
|
||||
if m.Count() > 0 {
|
||||
return m[0]
|
||||
}
|
||||
return nil
|
||||
if m.Count() > 0 {
|
||||
return m[0]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m Members) Last() *User {
|
||||
if m.Count() > 0 {
|
||||
return m[m.Count()-1]
|
||||
}
|
||||
return nil
|
||||
if m.Count() > 0 {
|
||||
return m[m.Count()-1]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m Members) SetOwner(s *Self) {
|
||||
for _, member := range m {
|
||||
member.Self = s
|
||||
}
|
||||
for _, member := range m {
|
||||
member.Self = s
|
||||
}
|
||||
}
|
||||
|
||||
func (m Members) SearchByUserName(limit int, username string) (results Members) {
|
||||
return m.Search(limit, func(user *User) bool { return user.UserName == username })
|
||||
return m.Search(limit, func(user *User) bool { return user.UserName == username })
|
||||
}
|
||||
|
||||
func (m Members) SearchByNickName(limit int, nickName string) (results Members) {
|
||||
return m.Search(limit, func(user *User) bool { return user.NickName == nickName })
|
||||
return m.Search(limit, func(user *User) bool { return user.NickName == nickName })
|
||||
}
|
||||
|
||||
func (m Members) SearchByRemarkName(limit int, remarkName string) (results Members) {
|
||||
return m.Search(limit, func(user *User) bool { return user.RemarkName == remarkName })
|
||||
return m.Search(limit, func(user *User) bool { return user.RemarkName == remarkName })
|
||||
}
|
||||
|
||||
func (m Members) Search(limit int, condFuncList ...func(user *User) bool) (results Members) {
|
||||
if condFuncList == nil {
|
||||
return m
|
||||
}
|
||||
if limit <= 0 {
|
||||
limit = m.Count()
|
||||
}
|
||||
for _, member := range m {
|
||||
if results.Count() == limit {
|
||||
break
|
||||
}
|
||||
var passCount int
|
||||
for _, condFunc := range condFuncList {
|
||||
if condFunc(member) {
|
||||
passCount++
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
if passCount == len(condFuncList) {
|
||||
results = append(results, member)
|
||||
}
|
||||
}
|
||||
return
|
||||
if condFuncList == nil {
|
||||
return m
|
||||
}
|
||||
if limit <= 0 {
|
||||
limit = m.Count()
|
||||
}
|
||||
for _, member := range m {
|
||||
if results.Count() == limit {
|
||||
break
|
||||
}
|
||||
var passCount int
|
||||
for _, condFunc := range condFuncList {
|
||||
if condFunc(member) {
|
||||
passCount++
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
if passCount == len(condFuncList) {
|
||||
results = append(results, member)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user