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