支持消息撤回

This commit is contained in:
eatMoreApple 2021-04-28 17:26:10 +08:00
parent 314e811961
commit b967eda0d0
10 changed files with 338 additions and 223 deletions

View File

@ -193,12 +193,12 @@ func TestSendMessage(t *testing.T) {
t.Error(err)
return
}
if err = helper.SendText("test message! received ?"); err != nil {
if _, err = helper.SendText("test message! received ?"); err != nil {
t.Error(err)
return
}
time.Sleep(time.Second)
if err = self.SendTextToFriend(helper, "send test message twice ! received?"); err != nil {
if _, err = self.SendTextToFriend(helper, "send test message twice ! received?"); err != nil {
t.Error(err)
return
}
@ -253,5 +253,38 @@ func TestFriendHelper(t *testing.T) {
t.Error(err)
return
}
fh.SendText("test message")
msg, err := fh.SendText("test message")
if err != nil {
t.Error(err)
return
}
t.Log(msg.MsgId)
}
func TestRevokeMessage(t *testing.T) {
bot := defaultBot(Desktop)
if err := bot.Login(); err != nil {
t.Error(err)
return
}
self, err := bot.GetCurrentUser()
if err != nil {
t.Error(err)
return
}
friends, err := self.Friends()
if err != nil {
t.Error(err)
return
}
fs := friends.SearchByRemarkName(1, "1")
ms, err := fs.First().SendText("test")
if err != nil {
t.Error(err)
return
}
time.Sleep(time.Second)
if err := ms.Revoke(); err != nil {
t.Error(err)
}
}

View File

@ -187,9 +187,11 @@ func (c *Caller) WebWxSync(request *BaseRequest, response *WebInitResponse, info
}
// 发送消息接口
func (c *Caller) WebWxSendMsg(msg *SendMessage, info *LoginInfo, request *BaseRequest) error {
func (c *Caller) WebWxSendMsg(msg *SendMessage, info *LoginInfo, request *BaseRequest) (*SentMessage, error) {
resp := NewReturnResponse(c.Client.WebWxSendMsg(msg, info, request))
return parseBaseResponseError(resp)
sendSuccessMsg := &SentMessage{SendMessage: msg}
err := parseMessageResponseError(resp, sendSuccessMsg)
return sendSuccessMsg, err
}
// 修改用户备注接口
@ -199,12 +201,12 @@ func (c *Caller) WebWxOplog(request *BaseRequest, remarkName, toUserName string)
}
// 发送图片消息接口
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) (*SentMessage, error) {
// 首先尝试上传图片
resp := NewReturnResponse(c.Client.WebWxUploadMedia(file, request, info, fromUserName, toUserName, "image/jpeg", "pic"))
// 无错误上传成功之后获取请求结果,判断结果是否正常
if resp.Err() != nil {
return resp.Err()
return nil, resp.Err()
}
defer resp.Body.Close()
var item struct {
@ -212,16 +214,19 @@ func (c *Caller) WebWxSendImageMsg(file *os.File, request *BaseRequest, info *Lo
MediaId string
}
if err := resp.ScanJSON(&item); err != nil {
return err
return nil, err
}
if !item.BaseResponse.Ok() {
return item.BaseResponse
return nil, item.BaseResponse
}
// 构造新的图片类型的信息
msg := NewMediaSendMessage(ImageMessage, fromUserName, toUserName, item.MediaId)
// 发送图片信息
resp = NewReturnResponse(c.Client.WebWxSendMsgImg(msg, request, info))
return parseBaseResponseError(resp)
sendSuccessMsg := &SentMessage{SendMessage: msg}
err := parseMessageResponseError(resp, sendSuccessMsg)
return sendSuccessMsg, err
}
// 用户退出
@ -254,6 +259,12 @@ func (c *Caller) WebWxVerifyUser(storage *Storage, info RecommendInfo, verifyCon
return parseBaseResponseError(resp)
}
// 撤回消息操作
func (c *Caller) WebWxRevokeMsg(msg *SentMessage, request *BaseRequest) error {
resp := NewReturnResponse(c.Client.WebWxRevokeMsg(msg, request))
return parseBaseResponseError(resp)
}
// 处理响应返回的结果是否正常
func parseBaseResponseError(resp *ReturnResponse) error {
if resp.Err() != nil {
@ -269,3 +280,24 @@ func parseBaseResponseError(resp *ReturnResponse) error {
}
return nil
}
func parseMessageResponseError(resp *ReturnResponse, msg *SentMessage) error {
if resp.Err() != nil {
return resp.Err()
}
defer resp.Body.Close()
var messageResp MessageResponse
if err := resp.ScanJSON(&messageResp); err != nil {
return err
}
if !messageResp.BaseResponse.Ok() {
return messageResp.BaseResponse
}
//// 发送成功之后将msgId赋值给SendMessage
msg.MsgId = messageResp.MsgID
return nil
}

View File

@ -494,3 +494,17 @@ func (c *Client) RemoveMemberFromChatRoom(req *BaseRequest, info *LoginInfo, gro
requ.Header.Set("Content-Type", jsonContentType)
return c.Do(requ)
}
// 撤回消息
func (c *Client) WebWxRevokeMsg(msg *SentMessage, request *BaseRequest) (*http.Response, error) {
content := map[string]interface{}{
"BaseRequest": request,
"ClientMsgId": msg.ClientMsgId,
"SvrMsgId": msg.MsgId,
"ToUserName": msg.ToUserName,
}
buffer, _ := ToBuffer(content)
req, _ := http.NewRequest(http.MethodPost, c.webWxRevokeMsg, buffer)
req.Header.Set("Content-Type", jsonContentType)
return c.Do(req)
}

View File

@ -17,5 +17,5 @@ func TestSendEmoji(t *testing.T) {
t.Error(err)
return
}
_ = f.SendText(Emoji.Dagger)
_ , _= f.SendText(Emoji.Dagger)
}

133
global.go
View File

@ -1,99 +1,100 @@
package openwechat
import (
"errors"
"regexp"
"errors"
"regexp"
)
var (
uuidRegexp = regexp.MustCompile(`uuid = "(.*?)";`)
statusCodeRegexp = regexp.MustCompile(`window.code=(\d+);`)
syncCheckRegexp = regexp.MustCompile(`window.synccheck=\{retcode:"(\d+)",selector:"(\d+)"\}`)
redirectUriRegexp = regexp.MustCompile(`window.redirect_uri="(.*?)"`)
uuidRegexp = regexp.MustCompile(`uuid = "(.*?)";`)
statusCodeRegexp = regexp.MustCompile(`window.code=(\d+);`)
syncCheckRegexp = regexp.MustCompile(`window.synccheck=\{retcode:"(\d+)",selector:"(\d+)"\}`)
redirectUriRegexp = regexp.MustCompile(`window.redirect_uri="(.*?)"`)
)
const (
appId = "wx782c26e4c19acffb"
jsLoginUrl = "https://login.wx.qq.com/jslogin"
qrcodeUrl = "https://login.weixin.qq.com/qrcode/"
loginUrl = "https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login"
appId = "wx782c26e4c19acffb"
jsLoginUrl = "https://login.wx.qq.com/jslogin"
qrcodeUrl = "https://login.weixin.qq.com/qrcode/"
loginUrl = "https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login"
// Normal urls
// Normal urls
baseNormalUrl = "https://wx2.qq.com"
webWxNewLoginPageNormalUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage"
webWxInitNormalUrl = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxinit"
webWxStatusNotifyNormalUrl = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxstatusnotify"
webWxSyncNormalUrl = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsync"
webWxSendMsgNormalUrl = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg"
webWxGetContactNormalUrl = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact"
webWxSendMsgImgNormalUrl = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsgimg"
webWxSendAppMsgNormalUrl = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendappmsg"
webWxBatchGetContactNormalUrl = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxbatchgetcontact"
webWxOplogNormalUrl = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxoplog"
webWxVerifyUserNormalUrl = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxverifyuser"
syncCheckNormalUrl = "https://webpush.wx2.qq.com/cgi-bin/mmwebwx-bin/synccheck"
webWxUpLoadMediaNormalUrl = "https://file.wx2.qq.com/cgi-bin/mmwebwx-bin/webwxuploadmedia"
webWxGetMsgImgNormalUrl = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxgetmsgimg"
webWxGetVoiceNormalUrl = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxgetvoice"
webWxGetVideoNormalUrl = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxgetvideo"
webWxLogoutNormalUrl = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxlogout"
webWxGetMediaNormalUrl = "https://file.wx2.qq.com/cgi-bin/mmwebwx-bin/webwxgetmedia"
webWxUpdateChatRoomNormalUrl = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxupdatechatroom"
baseNormalUrl = "https://wx2.qq.com"
webWxNewLoginPageNormalUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage"
webWxInitNormalUrl = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxinit"
webWxStatusNotifyNormalUrl = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxstatusnotify"
webWxSyncNormalUrl = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsync"
webWxSendMsgNormalUrl = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg"
webWxGetContactNormalUrl = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact"
webWxSendMsgImgNormalUrl = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsgimg"
webWxSendAppMsgNormalUrl = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendappmsg"
webWxBatchGetContactNormalUrl = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxbatchgetcontact"
webWxOplogNormalUrl = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxoplog"
webWxVerifyUserNormalUrl = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxverifyuser"
syncCheckNormalUrl = "https://webpush.wx2.qq.com/cgi-bin/mmwebwx-bin/synccheck"
webWxUpLoadMediaNormalUrl = "https://file.wx2.qq.com/cgi-bin/mmwebwx-bin/webwxuploadmedia"
webWxGetMsgImgNormalUrl = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxgetmsgimg"
webWxGetVoiceNormalUrl = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxgetvoice"
webWxGetVideoNormalUrl = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxgetvideo"
webWxLogoutNormalUrl = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxlogout"
webWxGetMediaNormalUrl = "https://file.wx2.qq.com/cgi-bin/mmwebwx-bin/webwxgetmedia"
webWxUpdateChatRoomNormalUrl = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxupdatechatroom"
webWxRevokeMsgNormalUrl = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxrevokemsg"
// Desktop urls
// Desktop urls
baseDesktopUrl = "https://wx.qq.com"
webWxNewLoginPageDesktopUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?mod=desktop"
webWxInitDesktopUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit"
webWxStatusNotifyDesktopUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxstatusnotify"
webWxSyncDesktopUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsync"
webWxSendMsgDesktopUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg"
webWxGetContactDesktopUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact"
webWxSendMsgImgDesktopUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsgimg"
webWxSendAppMsgDesktopUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsendappmsg"
webWxBatchGetContactDesktopUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxbatchgetcontact"
webWxOplogDesktopUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxoplog"
webWxVerifyUserDesktopUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxverifyuser"
syncCheckDesktopUrl = "https://webpush.wx.qq.com/cgi-bin/mmwebwx-bin/synccheck"
webWxUpLoadMediaDesktopUrl = "https://file.wx.qq.com/cgi-bin/mmwebwx-bin/webwxuploadmedia"
webWxGetMsgImgDesktopUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetmsgimg"
webWxGetVoiceDesktopUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetvoice"
webWxGetVideoDesktopUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetvideo"
webWxLogoutDesktopUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxlogout"
webWxGetMediaDesktopUrl = "https://file.wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetmedia"
webWxUpdateChatRoomDesktopUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxupdatechatroom"
baseDesktopUrl = "https://wx.qq.com"
webWxNewLoginPageDesktopUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?mod=desktop"
webWxInitDesktopUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit"
webWxStatusNotifyDesktopUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxstatusnotify"
webWxSyncDesktopUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsync"
webWxSendMsgDesktopUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg"
webWxGetContactDesktopUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact"
webWxSendMsgImgDesktopUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsgimg"
webWxSendAppMsgDesktopUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsendappmsg"
webWxBatchGetContactDesktopUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxbatchgetcontact"
webWxOplogDesktopUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxoplog"
webWxVerifyUserDesktopUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxverifyuser"
syncCheckDesktopUrl = "https://webpush.wx.qq.com/cgi-bin/mmwebwx-bin/synccheck"
webWxUpLoadMediaDesktopUrl = "https://file.wx.qq.com/cgi-bin/mmwebwx-bin/webwxuploadmedia"
webWxGetMsgImgDesktopUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetmsgimg"
webWxGetVoiceDesktopUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetvoice"
webWxGetVideoDesktopUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetvideo"
webWxLogoutDesktopUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxlogout"
webWxGetMediaDesktopUrl = "https://file.wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetmedia"
webWxUpdateChatRoomDesktopUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxupdatechatroom"
webWxRevokeMsgDesktopUrl = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxrevokemsg"
jsonContentType = "application/json; charset=utf-8"
uosPatchClientVersion = "2.0.0"
uosPatchExtspam = "Gp8ICJkIEpkICggwMDAwMDAwMRAGGoAI1GiJSIpeO1RZTq9QBKsRbPJdi84ropi16EYI10WB6g74sGmRwSNXjPQnYUKYotKkvLGpshucCaeWZMOylnc6o2AgDX9grhQQx7fm2DJRTyuNhUlwmEoWhjoG3F0ySAWUsEbH3bJMsEBwoB//0qmFJob74ffdaslqL+IrSy7LJ76/G5TkvNC+J0VQkpH1u3iJJs0uUYyLDzdBIQ6Ogd8LDQ3VKnJLm4g/uDLe+G7zzzkOPzCjXL+70naaQ9medzqmh+/SmaQ6uFWLDQLcRln++wBwoEibNpG4uOJvqXy+ql50DjlNchSuqLmeadFoo9/mDT0q3G7o/80P15ostktjb7h9bfNc+nZVSnUEJXbCjTeqS5UYuxn+HTS5nZsPVxJA2O5GdKCYK4x8lTTKShRstqPfbQpplfllx2fwXcSljuYi3YipPyS3GCAqf5A7aYYwJ7AvGqUiR2SsVQ9Nbp8MGHET1GxhifC692APj6SJxZD3i1drSYZPMMsS9rKAJTGz2FEupohtpf2tgXm6c16nDk/cw+C7K7me5j5PLHv55DFCS84b06AytZPdkFZLj7FHOkcFGJXitHkX5cgww7vuf6F3p0yM/W73SoXTx6GX4G6Hg2rYx3O/9VU2Uq8lvURB4qIbD9XQpzmyiFMaytMnqxcZJcoXCtfkTJ6pI7a92JpRUvdSitg967VUDUAQnCXCM/m0snRkR9LtoXAO1FUGpwlp1EfIdCZFPKNnXMeqev0j9W9ZrkEs9ZWcUEexSj5z+dKYQBhIICviYUQHVqBTZSNy22PlUIeDeIs11j7q4t8rD8LPvzAKWVqXE+5lS1JPZkjg4y5hfX1Dod3t96clFfwsvDP6xBSe1NBcoKbkyGxYK0UvPGtKQEE0Se2zAymYDv41klYE9s+rxp8e94/H8XhrL9oGm8KWb2RmYnAE7ry9gd6e8ZuBRIsISlJAE/e8y8xFmP031S6Lnaet6YXPsFpuFsdQs535IjcFd75hh6DNMBYhSfjv456cvhsb99+fRw/KVZLC3yzNSCbLSyo9d9BI45Plma6V8akURQA/qsaAzU0VyTIqZJkPDTzhuCl92vD2AD/QOhx6iwRSVPAxcRFZcWjgc2wCKh+uCYkTVbNQpB9B90YlNmI3fWTuUOUjwOzQRxJZj11NsimjOJ50qQwTTFj6qQvQ1a/I+MkTx5UO+yNHl718JWcR3AXGmv/aa9rD1eNP8ioTGlOZwPgmr2sor2iBpKTOrB83QgZXP+xRYkb4zVC+LoAXEoIa1+zArywlgREer7DLePukkU6wHTkuSaF+ge5Of1bXuU4i938WJHj0t3D8uQxkJvoFi/EYN/7u2P1zGRLV4dHVUsZMGCCtnO6BBigFMAA="
jsonContentType = "application/json; charset=utf-8"
uosPatchClientVersion = "2.0.0"
uosPatchExtspam = "Gp8ICJkIEpkICggwMDAwMDAwMRAGGoAI1GiJSIpeO1RZTq9QBKsRbPJdi84ropi16EYI10WB6g74sGmRwSNXjPQnYUKYotKkvLGpshucCaeWZMOylnc6o2AgDX9grhQQx7fm2DJRTyuNhUlwmEoWhjoG3F0ySAWUsEbH3bJMsEBwoB//0qmFJob74ffdaslqL+IrSy7LJ76/G5TkvNC+J0VQkpH1u3iJJs0uUYyLDzdBIQ6Ogd8LDQ3VKnJLm4g/uDLe+G7zzzkOPzCjXL+70naaQ9medzqmh+/SmaQ6uFWLDQLcRln++wBwoEibNpG4uOJvqXy+ql50DjlNchSuqLmeadFoo9/mDT0q3G7o/80P15ostktjb7h9bfNc+nZVSnUEJXbCjTeqS5UYuxn+HTS5nZsPVxJA2O5GdKCYK4x8lTTKShRstqPfbQpplfllx2fwXcSljuYi3YipPyS3GCAqf5A7aYYwJ7AvGqUiR2SsVQ9Nbp8MGHET1GxhifC692APj6SJxZD3i1drSYZPMMsS9rKAJTGz2FEupohtpf2tgXm6c16nDk/cw+C7K7me5j5PLHv55DFCS84b06AytZPdkFZLj7FHOkcFGJXitHkX5cgww7vuf6F3p0yM/W73SoXTx6GX4G6Hg2rYx3O/9VU2Uq8lvURB4qIbD9XQpzmyiFMaytMnqxcZJcoXCtfkTJ6pI7a92JpRUvdSitg967VUDUAQnCXCM/m0snRkR9LtoXAO1FUGpwlp1EfIdCZFPKNnXMeqev0j9W9ZrkEs9ZWcUEexSj5z+dKYQBhIICviYUQHVqBTZSNy22PlUIeDeIs11j7q4t8rD8LPvzAKWVqXE+5lS1JPZkjg4y5hfX1Dod3t96clFfwsvDP6xBSe1NBcoKbkyGxYK0UvPGtKQEE0Se2zAymYDv41klYE9s+rxp8e94/H8XhrL9oGm8KWb2RmYnAE7ry9gd6e8ZuBRIsISlJAE/e8y8xFmP031S6Lnaet6YXPsFpuFsdQs535IjcFd75hh6DNMBYhSfjv456cvhsb99+fRw/KVZLC3yzNSCbLSyo9d9BI45Plma6V8akURQA/qsaAzU0VyTIqZJkPDTzhuCl92vD2AD/QOhx6iwRSVPAxcRFZcWjgc2wCKh+uCYkTVbNQpB9B90YlNmI3fWTuUOUjwOzQRxJZj11NsimjOJ50qQwTTFj6qQvQ1a/I+MkTx5UO+yNHl718JWcR3AXGmv/aa9rD1eNP8ioTGlOZwPgmr2sor2iBpKTOrB83QgZXP+xRYkb4zVC+LoAXEoIa1+zArywlgREer7DLePukkU6wHTkuSaF+ge5Of1bXuU4i938WJHj0t3D8uQxkJvoFi/EYN/7u2P1zGRLV4dHVUsZMGCCtnO6BBigFMAA="
)
// 消息类型
const (
TextMessage = 1
ImageMessage = 3
AppMessage = 6
TextMessage = 1
ImageMessage = 3
AppMessage = 6
)
// 登录状态
const (
statusSuccess = "200"
statusScanned = "201"
statusTimeout = "400"
statusWait = "408"
statusSuccess = "200"
statusScanned = "201"
statusTimeout = "400"
statusWait = "408"
)
// errors
var (
noSuchUserFoundError = errors.New("no such user found")
noSuchUserFoundError = errors.New("no such user found")
)
const ALL = 0
// sex
const (
MALE = 1
FEMALE = 2
MALE = 1
FEMALE = 2
)

View File

@ -196,3 +196,9 @@ type CheckLoginResponse struct {
Code string
Raw []byte
}
type MessageResponse struct {
BaseResponse BaseResponse
LocalID string
MsgID string
}

View File

@ -127,7 +127,7 @@ func (m *Message) IsSendByGroup() bool {
}
// 回复消息
func (m *Message) Reply(msgType int, content, mediaId string) error {
func (m *Message) Reply(msgType int, content, mediaId string) (*SentMessage, error) {
msg := NewSendMessage(msgType, content, m.Bot.self.User.UserName, m.FromUserName, mediaId)
info := m.Bot.storage.LoginInfo
request := m.Bot.storage.Request
@ -135,12 +135,12 @@ func (m *Message) Reply(msgType int, content, mediaId string) error {
}
// 回复文本消息
func (m *Message) ReplyText(content string) error {
func (m *Message) ReplyText(content string) (*SentMessage, error) {
return m.Reply(TextMessage, content, "")
}
// 回复图片消息
func (m *Message) ReplyImage(file *os.File) error {
func (m *Message) ReplyImage(file *os.File) (*SentMessage, error) {
info := m.Bot.storage.LoginInfo
request := m.Bot.storage.Request
return m.Bot.Caller.WebWxSendImageMsg(file, request, info, m.Bot.self.UserName, m.FromUserName)
@ -341,7 +341,7 @@ type SendMessage struct {
// SendMessage的构造方法
func NewSendMessage(msgType int, content, fromUserName, toUserName, mediaId string) *SendMessage {
id := strconv.FormatInt(time.Now().Unix()*1e4, 10)
id := strconv.FormatInt(time.Now().UnixNano()/1e2, 10)
return &SendMessage{
Type: msgType,
Content: content,
@ -459,3 +459,15 @@ type RevokeMsg struct {
ReplaceMsg string `xml:"replacemsg"`
} `xml:"revokemsg"`
}
// 已发送的信息
type SentMessage struct {
*SendMessage
Self *Self
MsgId string
}
// 撤回该消息
func (s *SentMessage) Revoke() error {
return s.Self.RevokeMessage(s)
}

View File

@ -19,17 +19,17 @@ func (f *Friend) SetRemarkName(name string) error {
}
// 发送自定义消息
func (f *Friend) SendMsg(msg *SendMessage) error {
func (f *Friend) SendMsg(msg *SendMessage) (*SentMessage, error) {
return f.Self.SendMessageToFriend(f, msg)
}
// 发送文本消息
func (f *Friend) SendText(content string) error {
func (f *Friend) SendText(content string) (*SentMessage, error) {
return f.Self.SendTextToFriend(f, content)
}
// 发送图片消息
func (f *Friend) SendImage(file *os.File) error {
func (f *Friend) SendImage(file *os.File) (*SentMessage, error) {
return f.Self.SendImageToFriend(f, file)
}
@ -106,7 +106,7 @@ func (f Friends) SendMsg(msg *SendMessage, delay ...time.Duration) error {
total := getTotalDuration(delay...)
for _, friend := range f {
time.Sleep(total)
if err := friend.SendMsg(msg); err != nil {
if _, err := friend.SendMsg(msg); err != nil {
return err
}
}
@ -118,7 +118,7 @@ func (f Friends) SendText(text string, delay ...time.Duration) error {
total := getTotalDuration(delay...)
for _, friend := range f {
time.Sleep(total)
if err := friend.SendText(text); err != nil {
if _, err := friend.SendText(text); err != nil {
return err
}
}
@ -130,7 +130,7 @@ func (f Friends) SendImage(file *os.File, delay ...time.Duration) error {
total := getTotalDuration(delay...)
for _, friend := range f {
time.Sleep(total)
if err := friend.SendImage(file); err != nil {
if _, err := friend.SendImage(file); err != nil {
return err
}
}
@ -145,17 +145,17 @@ func (g Group) String() string {
}
// 发行消息给当前的群组
func (g *Group) SendMsg(msg *SendMessage) error {
func (g *Group) SendMsg(msg *SendMessage) (*SentMessage, error) {
return g.Self.SendMessageToGroup(g, msg)
}
// 发行文本消息给当前的群组
func (g *Group) SendText(content string) error {
func (g *Group) SendText(content string) (*SentMessage, error) {
return g.Self.SendTextToGroup(g, content)
}
// 发行图片消息给当前的群组
func (g *Group) SendImage(file *os.File) error {
func (g *Group) SendImage(file *os.File) (*SentMessage, error) {
return g.Self.SendImageToGroup(g, file)
}
@ -208,7 +208,7 @@ func (g Groups) SendMsg(msg *SendMessage, delay ...time.Duration) error {
total := getTotalDuration(delay...)
for _, group := range g {
time.Sleep(total)
if err := group.SendMsg(msg); err != nil {
if _, err := group.SendMsg(msg); err != nil {
return err
}
}
@ -220,7 +220,7 @@ func (g Groups) SendText(text string, delay ...time.Duration) error {
total := getTotalDuration(delay...)
for _, group := range g {
time.Sleep(total)
if err := group.SendText(text); err != nil {
if _, err := group.SendText(text); err != nil {
return err
}
}
@ -232,7 +232,7 @@ func (g Groups) SendImage(file *os.File, delay ...time.Duration) error {
total := getTotalDuration(delay...)
for _, group := range g {
time.Sleep(total)
if err := group.SendImage(file); err != nil {
if _, err := group.SendImage(file); err != nil {
return err
}
}
@ -334,5 +334,3 @@ func (m Mps) Search(limit int, condFuncList ...func(group *Mp) bool) (results Mp
}
return
}

155
url.go
View File

@ -2,76 +2,79 @@ package openwechat
// url信息存储
type UrlManager struct {
baseUrl string
webWxNewLoginPageUrl string
webWxInitUrl string
webWxStatusNotifyUrl string
webWxSyncUrl string
webWxSendMsgUrl string
webWxGetContactUrl string
webWxSendMsgImgUrl string
webWxSendAppMsgUrl string
webWxBatchGetContactUrl string
webWxOplogUrl string
webWxVerifyUserUrl string
syncCheckUrl string
webWxUpLoadMediaUrl string
webWxGetMsgImgUrl string
webWxGetVoiceUrl string
webWxGetVideoUrl string
webWxLogoutUrl string
webWxGetMediaUrl string
webWxUpdateChatRoomUrl string
baseUrl string
webWxNewLoginPageUrl string
webWxInitUrl string
webWxStatusNotifyUrl string
webWxSyncUrl string
webWxSendMsgUrl string
webWxGetContactUrl string
webWxSendMsgImgUrl string
webWxSendAppMsgUrl string
webWxBatchGetContactUrl string
webWxOplogUrl string
webWxVerifyUserUrl string
syncCheckUrl string
webWxUpLoadMediaUrl string
webWxGetMsgImgUrl string
webWxGetVoiceUrl string
webWxGetVideoUrl string
webWxLogoutUrl string
webWxGetMediaUrl string
webWxUpdateChatRoomUrl string
webWxRevokeMsg string
}
var (
// uos版
desktop = UrlManager{
baseUrl: baseDesktopUrl,
webWxNewLoginPageUrl: webWxNewLoginPageDesktopUrl,
webWxInitUrl: webWxInitDesktopUrl,
webWxStatusNotifyUrl: webWxStatusNotifyDesktopUrl,
webWxSyncUrl: webWxSyncDesktopUrl,
webWxSendMsgUrl: webWxSendMsgDesktopUrl,
webWxGetContactUrl: webWxGetContactDesktopUrl,
webWxSendMsgImgUrl: webWxSendMsgImgDesktopUrl,
webWxSendAppMsgUrl: webWxSendAppMsgDesktopUrl,
webWxBatchGetContactUrl: webWxBatchGetContactDesktopUrl,
webWxOplogUrl: webWxOplogDesktopUrl,
webWxVerifyUserUrl: webWxVerifyUserDesktopUrl,
syncCheckUrl: syncCheckDesktopUrl,
webWxUpLoadMediaUrl: webWxUpLoadMediaDesktopUrl,
webWxGetMsgImgUrl: webWxGetMsgImgDesktopUrl,
webWxGetVoiceUrl: webWxGetVoiceDesktopUrl,
webWxGetVideoUrl: webWxGetVideoDesktopUrl,
webWxLogoutUrl: webWxLogoutDesktopUrl,
webWxGetMediaUrl: webWxGetMediaDesktopUrl,
webWxUpdateChatRoomUrl: webWxUpdateChatRoomDesktopUrl,
}
// uos版
desktop = UrlManager{
baseUrl: baseDesktopUrl,
webWxNewLoginPageUrl: webWxNewLoginPageDesktopUrl,
webWxInitUrl: webWxInitDesktopUrl,
webWxStatusNotifyUrl: webWxStatusNotifyDesktopUrl,
webWxSyncUrl: webWxSyncDesktopUrl,
webWxSendMsgUrl: webWxSendMsgDesktopUrl,
webWxGetContactUrl: webWxGetContactDesktopUrl,
webWxSendMsgImgUrl: webWxSendMsgImgDesktopUrl,
webWxSendAppMsgUrl: webWxSendAppMsgDesktopUrl,
webWxBatchGetContactUrl: webWxBatchGetContactDesktopUrl,
webWxOplogUrl: webWxOplogDesktopUrl,
webWxVerifyUserUrl: webWxVerifyUserDesktopUrl,
syncCheckUrl: syncCheckDesktopUrl,
webWxUpLoadMediaUrl: webWxUpLoadMediaDesktopUrl,
webWxGetMsgImgUrl: webWxGetMsgImgDesktopUrl,
webWxGetVoiceUrl: webWxGetVoiceDesktopUrl,
webWxGetVideoUrl: webWxGetVideoDesktopUrl,
webWxLogoutUrl: webWxLogoutDesktopUrl,
webWxGetMediaUrl: webWxGetMediaDesktopUrl,
webWxUpdateChatRoomUrl: webWxUpdateChatRoomDesktopUrl,
webWxRevokeMsg: webWxRevokeMsgDesktopUrl,
}
// 网页版
normal = UrlManager{
baseUrl: baseNormalUrl,
webWxNewLoginPageUrl: webWxNewLoginPageNormalUrl,
webWxInitUrl: webWxInitNormalUrl,
webWxStatusNotifyUrl: webWxStatusNotifyNormalUrl,
webWxSyncUrl: webWxSyncNormalUrl,
webWxSendMsgUrl: webWxSendMsgNormalUrl,
webWxGetContactUrl: webWxGetContactNormalUrl,
webWxSendMsgImgUrl: webWxSendMsgImgNormalUrl,
webWxSendAppMsgUrl: webWxSendAppMsgNormalUrl,
webWxBatchGetContactUrl: webWxBatchGetContactNormalUrl,
webWxOplogUrl: webWxOplogNormalUrl,
webWxVerifyUserUrl: webWxVerifyUserNormalUrl,
syncCheckUrl: syncCheckNormalUrl,
webWxUpLoadMediaUrl: webWxUpLoadMediaNormalUrl,
webWxGetMsgImgUrl: webWxGetMsgImgNormalUrl,
webWxGetVoiceUrl: webWxGetVoiceNormalUrl,
webWxGetVideoUrl: webWxGetVideoNormalUrl,
webWxLogoutUrl: webWxLogoutNormalUrl,
webWxGetMediaUrl: webWxGetMediaNormalUrl,
webWxUpdateChatRoomUrl: webWxUpdateChatRoomNormalUrl,
}
// 网页版
normal = UrlManager{
baseUrl: baseNormalUrl,
webWxNewLoginPageUrl: webWxNewLoginPageNormalUrl,
webWxInitUrl: webWxInitNormalUrl,
webWxStatusNotifyUrl: webWxStatusNotifyNormalUrl,
webWxSyncUrl: webWxSyncNormalUrl,
webWxSendMsgUrl: webWxSendMsgNormalUrl,
webWxGetContactUrl: webWxGetContactNormalUrl,
webWxSendMsgImgUrl: webWxSendMsgImgNormalUrl,
webWxSendAppMsgUrl: webWxSendAppMsgNormalUrl,
webWxBatchGetContactUrl: webWxBatchGetContactNormalUrl,
webWxOplogUrl: webWxOplogNormalUrl,
webWxVerifyUserUrl: webWxVerifyUserNormalUrl,
syncCheckUrl: syncCheckNormalUrl,
webWxUpLoadMediaUrl: webWxUpLoadMediaNormalUrl,
webWxGetMsgImgUrl: webWxGetMsgImgNormalUrl,
webWxGetVoiceUrl: webWxGetVoiceNormalUrl,
webWxGetVideoUrl: webWxGetVideoNormalUrl,
webWxLogoutUrl: webWxLogoutNormalUrl,
webWxGetMediaUrl: webWxGetMediaNormalUrl,
webWxUpdateChatRoomUrl: webWxUpdateChatRoomNormalUrl,
webWxRevokeMsg: webWxRevokeMsgNormalUrl,
}
)
// mode 类型限制
@ -79,17 +82,17 @@ type mode string
// 向外暴露2种模式
const (
Normal mode = "normal"
Desktop mode = "desktop"
Normal mode = "normal"
Desktop mode = "desktop"
)
func GetUrlManagerByMode(m mode) UrlManager {
switch m {
case Desktop:
return desktop
case Normal:
return normal
default:
panic("unsupport mode got")
}
switch m {
case Desktop:
return desktop
case Normal:
return normal
default:
panic("unsupport mode got")
}
}

120
user.go
View File

@ -205,74 +205,36 @@ func (s *Self) UpdateMembersDetail() error {
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.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...)
}
if len(newMembers) > 0 {
newMembers.SetOwner(s)
s.members = newMembers
}
return nil
return members.detail(s)
}
// 抽象发送消息接口
func (s *Self) sendMessageToUser(user *User, msg *SendMessage) error {
func (s *Self) sendMessageToUser(user *User, msg *SendMessage) (*SentMessage, error) {
msg.FromUserName = s.UserName
msg.ToUserName = user.UserName
info := s.Bot.storage.LoginInfo
request := s.Bot.storage.Request
return s.Bot.Caller.WebWxSendMsg(msg, info, request)
successSendMessage, err := s.Bot.Caller.WebWxSendMsg(msg, info, request)
if err != nil {
return nil, err
}
successSendMessage.Self = s
return successSendMessage, nil
}
// 发送消息给好友
func (s *Self) SendMessageToFriend(friend *Friend, msg *SendMessage) error {
func (s *Self) SendMessageToFriend(friend *Friend, msg *SendMessage) (*SentMessage, error) {
return s.sendMessageToUser(friend.User, msg)
}
// 发送文本消息给好友
func (s *Self) SendTextToFriend(friend *Friend, text string) error {
func (s *Self) SendTextToFriend(friend *Friend, text string) (*SentMessage, error) {
msg := NewTextSendMessage(text, s.UserName, friend.UserName)
return s.SendMessageToFriend(friend, msg)
}
// 发送图片消息给好友
func (s *Self) SendImageToFriend(friend *Friend, file *os.File) error {
func (s *Self) SendImageToFriend(friend *Friend, file *os.File) (*SentMessage, error) {
req := s.Bot.storage.Request
info := s.Bot.storage.LoginInfo
return s.Bot.Caller.WebWxSendImageMsg(file, req, info, s.UserName, friend.UserName)
@ -351,23 +313,28 @@ func (s *Self) AddFriendIntoManyGroups(friend *Friend, groups ...*Group) error {
}
// 发送消息给群组
func (s *Self) SendMessageToGroup(group *Group, msg *SendMessage) error {
func (s *Self) SendMessageToGroup(group *Group, msg *SendMessage) (*SentMessage, error) {
return s.sendMessageToUser(group.User, msg)
}
// 发送文本消息给群组
func (s *Self) SendTextToGroup(group *Group, text string) error {
func (s *Self) SendTextToGroup(group *Group, text string) (*SentMessage, error) {
msg := NewTextSendMessage(text, s.UserName, group.UserName)
return s.SendMessageToGroup(group, msg)
}
// 发送图片消息给群组
func (s *Self) SendImageToGroup(group *Group, file *os.File) error {
func (s *Self) SendImageToGroup(group *Group, file *os.File) (*SentMessage, error) {
req := s.Bot.storage.Request
info := s.Bot.storage.LoginInfo
return s.Bot.Caller.WebWxSendImageMsg(file, req, info, s.UserName, group.UserName)
}
// 撤回消息
func (s *Self) RevokeMessage(msg *SentMessage) error {
return s.Bot.Caller.WebWxRevokeMsg(msg, s.Bot.storage.Request)
}
// 抽象的用户组
type Members []*User
@ -477,6 +444,55 @@ func (m Members) MPs() Mps {
return mps
}
func (m Members) detail(self *Self) error {
// 获取他们的数量
members := m
count := members.Count()
// 一次更新50个,分情况讨论
// 获取总的需要更新的次数
var times int
if count < 50 {
times = 1
} else {
times = count / 50
}
var newMembers Members
request := self.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 := self.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 := self.Bot.Caller.WebWxBatchGetContact(pMembers, request)
if err != nil {
return err
}
newMembers = append(newMembers, nMembers...)
}
if len(newMembers) > 0 {
newMembers.SetOwner(self)
self.members = newMembers
}
return nil
}
// 这里为了兼容Desktop版本找不到文件传输助手的问题
// 文件传输助手的微信身份标识符永远是filehelper
// 这种形式的对象可能缺少一些其他属性