382 lines
16 KiB
Go
382 lines
16 KiB
Go
|
package core
|
|||
|
|
|||
|
import (
|
|||
|
"bytes"
|
|||
|
"fmt"
|
|||
|
"github.com/goWxHook/goWxHook/utils/json"
|
|||
|
"io"
|
|||
|
"log/slog"
|
|||
|
"net/http"
|
|||
|
"time"
|
|||
|
)
|
|||
|
|
|||
|
const (
|
|||
|
MtDebugLog = 11024 // debug消息
|
|||
|
loginSuccessMsg = 11025 // 登录成功
|
|||
|
MtUserLogin = 11025 // 登录消息
|
|||
|
MtUserLogout = 11026 // 注销消息
|
|||
|
MtSqlQuery = 11027 // 数据库查询消息
|
|||
|
MtDataOwnerMsg = 11028 // 获取我的信息消息
|
|||
|
MtDataWxidMsg = 11029 // 获取单个好友信息
|
|||
|
MtDataFriendsMsg = 11030 // 获取好友列表消息
|
|||
|
MtDataChatroomsMsg = 11031 // 获取群聊列表消息
|
|||
|
MtDataChatroomMembersMsg = 11032 // 获取群成员消息
|
|||
|
MtDataPublicsMsg = 11033 // 获取公众号消息
|
|||
|
MtUpdateWxidMsg = 11034 // 从网络更新单个好友信息消息
|
|||
|
MtUpdateRoomMemberMsg = 11035 // 从网络更新群成员信息消息
|
|||
|
MtSendTextmsg = 11036 // 发送文本消息
|
|||
|
MtSendChatroomAtmsg = 11037 // 发送群@消息
|
|||
|
MtSendCardmsg = 11038 // 发送名片消息
|
|||
|
MtSendLinkmsg = 11039 // 发送链接消息
|
|||
|
MtSendImgmsg = 11040 // 发送图片消息
|
|||
|
MtSendFilemsg = 11041 // 发送文件消息
|
|||
|
MtSendVideomsg = 11042 // 发送视频消息
|
|||
|
MtSendGifmsg = 11043 // 发送gif消息
|
|||
|
MtRecvTextMsg = 11046 // 接收文本消息
|
|||
|
MtRecvPictureMsg = 11047 // 接收图片消息
|
|||
|
MtRecvVoiceMsg = 11048 // 接收视频消息
|
|||
|
MtRecvFriendMsg = 11049 // 接收申请好友消息
|
|||
|
MtRecvCardMsg = 11050 // 接收名片消息
|
|||
|
MtRecvVideoMsg = 11051 // 接收视频消息
|
|||
|
MtRecvEmojiMsg = 11052 // 接收表情消息
|
|||
|
MtRecvLocationMsg = 11053 // 接收位置消息
|
|||
|
MtRecvLinkMsg = 11054 // 接收链接消息
|
|||
|
MtRecvFileMsg = 11055 // 接收文件消息
|
|||
|
MtRecvMiniappMsg = 11056 // 接收小程序消息
|
|||
|
MtRecvWcpayMsg = 11057 // 接收好友转账消息
|
|||
|
MtRecvSystemMsg = 11058 // 接收系统消息
|
|||
|
MtRecvRevokeMsg = 11059 // 接收撤回消息
|
|||
|
MtRecvOtherMsg = 11060 // 接收其他未知消息
|
|||
|
MtRecvOtherAppMsg = 11061 // 接收应用类型未知消息
|
|||
|
MtAddFriendMsg = 11062 // 发送加好友消息
|
|||
|
MtModFriendRemarkMsg = 11063 // 发送修改好友备注消息
|
|||
|
MtDelFriendMsg = 11064 // 发送删除好友消息
|
|||
|
MtAcceptFriendMsg = 11065 // 发送同意加好友申请消息
|
|||
|
MtAcceptWcpayMsg = 11066 // 发送接收好友转帐消息
|
|||
|
MtAcceptRoomMsg = 11067 // 发送同意进群邀请消息
|
|||
|
MtCreateRoomMsg = 11068 // 发送创建群聊消息
|
|||
|
MtInviteToRoomMsg = 11069 // 发送邀请好友进群消息,40人以下
|
|||
|
MtInviteToRoomReqMsg = 11070 // 发送邀请好友进群消息,40人以上
|
|||
|
MtDelRoomMemberMsg = 11071 // 发送删除群成员消息
|
|||
|
MtModRoomNameMsg = 11072 // 发送修改群名称消息
|
|||
|
MtModRoomNoticeMsg = 11073 // 发送修改群通知消息
|
|||
|
MtModRoomMemberNameMsg = 11074 // 发送修改我在本群的昵称消息
|
|||
|
MtModRoomShowNameMsg = 11075 // 发送修改显示群昵称消息
|
|||
|
MtSaveRoomToContactMsg = 11076 // 发送保存到联系人消息
|
|||
|
MtQuitDelRoomMsg = 11077 // 发送退出并删除群消息
|
|||
|
MtModRecvNotifyMsg = 11078 // 发送消息免打扰消息
|
|||
|
MtModChatSessionTopMsg = 11079 // 发送置顶消息
|
|||
|
MtZombieCheckMsg = 11080 // 发送无痕清粉消息
|
|||
|
MtAutoAcceptFriendMsg = 11081 // 发送自动同意好友申请消息
|
|||
|
MtAutoAcceptWcpayMsg = 11082 // 发送自动同意好友转帐消息
|
|||
|
MtAutoAcceptRoomMsg = 11083 // 发送自动进群邀请消息
|
|||
|
MtAutoAcceptCardMsg = 11084 // 发送自动加名片消息
|
|||
|
MtDecryptImgMsg = 11085 // 发送解密图片消息
|
|||
|
MtOpenBrowserMsg = 11086 // 发送打开浏览器消息
|
|||
|
MtRefreshLoginQrcode = 11087 // 刷新登录二维码
|
|||
|
MtSwitchSessionMsg = 11090 // 发送切换当前会话消息
|
|||
|
MtSearchWxUserMsg = 11096 // 搜索微信用户
|
|||
|
MtAddSearchUserMsg = 11097 // 添加搜索的微信用户
|
|||
|
MtVoiceToTextMsg = 11112 // 语音消息转文本(旧)
|
|||
|
MtSendXmlMsg = 11113 // 发送XML原始消息
|
|||
|
MtLogoutMsg = 11104 // 发送注销登录消息
|
|||
|
MtExitMsg = 11105 // 发送退出微信消息
|
|||
|
MtClearChatRecordMsg = 11108 // 清除聊天记录
|
|||
|
MtGetCollectListMsg = 11109 // 获取收藏列表
|
|||
|
MtSendCollectMsg = 11110 // 发送收藏(旧)
|
|||
|
MtSendCollectMsgByMsgId = 11111 // 收藏指定消息(旧)
|
|||
|
MtGetWorkWxChatRoomMsg = 11129 // 获取企业微信群
|
|||
|
MtGetWorkWxChatRoomMemberMsg = 11130 //获取企业微信群成员
|
|||
|
MtGetWorkWxUserListMsg = 11132 // 获取企业微信好友
|
|||
|
MtGetChatRoomInviteRelationMsg = 11134 // 获取群成员邀请关系(协议)
|
|||
|
MtGetA8KeyMsg = 11135 // A8Key接口
|
|||
|
MtGetMiniProgramCodeMsg = 11136 // 获取小程序授权code
|
|||
|
MtAddTagMsg = 11137 // 添加标签
|
|||
|
MtDeleteTagMsg = 11138 // 删除标签
|
|||
|
MtModifyTagMsg = 11139 // 修改标签
|
|||
|
MtAddTagToUserMsg = 11140 // 批量给用户加标签
|
|||
|
MtGetTagListByWxidMsg = 11141 // 获取指定好友的所有标签
|
|||
|
MtGetTagListMsg = 11142 // 获取标签列表
|
|||
|
MtGetMomentMsg = 11145 // 获取朋友圈
|
|||
|
MtCommentMomentMsg = 11146 // 朋友圈评论
|
|||
|
MtLikeMomentMsg = 11147 // 朋友圈点赞
|
|||
|
MtSendMomentMsg = 11148 // 朋友圈发表
|
|||
|
MtUploadMomentImageMsg = 11149 // 朋友圈上传图片
|
|||
|
MtGetFriendMomentMsg = 11150 // 获取好友朋友圈
|
|||
|
MtVideoMomentInitMsg = 11160 // 视频号初始化
|
|||
|
MtVideoMomentSearchMsg = 11161 // 视频号搜索
|
|||
|
MtLiveEnterMsg = 11162 //进入直播间
|
|||
|
MtLiveGetChangeInfoMsg = 11163 // 获取直播间变动信息(人气,实时发言等)
|
|||
|
MtLiveSendMsg = 11164 // 发送直播间消息
|
|||
|
MtVideoMomentFollowMsg = 11167 // 关注博主
|
|||
|
MtVideoMomentLikeMsg = 11168 // 视频号点赞
|
|||
|
MtVideoMomentVideoDetailMsg = 11169 // 查看视频详细信息(包含评论)
|
|||
|
MtVideoMomentUserHomeMsg = 11170 // 视频号用户主页
|
|||
|
MtLiveGetOnlineUserMsg = 11172 // 获取直播间在线人员
|
|||
|
MtGetFriendDetailMsg = 11174 // 获取好友详细信息(协议)
|
|||
|
MtLiveGetShelfMsg = 11186 // 获取直播间货架
|
|||
|
MtVideoMomentCreateVirtualNickNameMsg = 11194 // 视频号创建虚拟昵称
|
|||
|
MtVideoMomentSwitchVirtualNickNameMsg = 11195 // 视频号切换虚拟昵称
|
|||
|
MtVideoMomentDeleteVirtualNickNameMsg = 11197 // 视频号删除虚拟昵称
|
|||
|
MtVideoMomentGetSessionIdMsg = 11202 // 获取视频号私信sessionId
|
|||
|
MtVideoMomentSendMsg = 11203 // 发送视频号私信
|
|||
|
MtCdnSendXmlMsg = 11214 // 发送XML原始消息
|
|||
|
MtCdnInitialMsg = 11228 // CDN初始化
|
|||
|
MtCdnUploadFileMsg = 11229 // CDN上传
|
|||
|
MtCdnDownloadFileMsg = 11230 // CDN下载
|
|||
|
MtCdnSendImageMsg = 11231 // 发送图片消息
|
|||
|
MtCdnSendVideoMsg = 11233 // 发送视频消息
|
|||
|
MtCdnSendFileMsg = 11235 // 发送文件消息
|
|||
|
MtCdnSendCardLinkMsg = 11236 // 发送链接卡片消息
|
|||
|
MtCdnSendTextMsg = 11237 // 发送文本消息
|
|||
|
MtCdnSendLocationMsg = 11238 // 发送位置
|
|||
|
MtCdnSendCardMsg = 11239 // 发送名片
|
|||
|
MtCdnSendAtTextMsg = 11240 // 发送At消息
|
|||
|
MtCdnSendGifMsg = 11241 // 发送动图消息
|
|||
|
MtCdnSendMiniProgramMsg = 11242 // 发送小程序
|
|||
|
MtCdnSendVideoMomentMsg = 11243 // 发送视频号
|
|||
|
MtCdnSendRevokeMsg = 11244 // 撤回消息
|
|||
|
MtForwardMsg = 11245 // 转发任意类型消息
|
|||
|
MtCreateRoomByProtocolMsg = 11246 // 创建群聊(协议)
|
|||
|
MtWorkWxCdnDownloadMsg = 11253 // 企业微信CDN
|
|||
|
MtCdnSendGifMsgNew = 11254 // 发送动图消息New
|
|||
|
)
|
|||
|
|
|||
|
type RespJson struct {
|
|||
|
Error int `json:"error"`
|
|||
|
Msg string `json:"msg"`
|
|||
|
Data any `json:"data"`
|
|||
|
}
|
|||
|
|
|||
|
type WxApi struct {
|
|||
|
UserInfo UserClientInfo
|
|||
|
TimeOut int // 上传大文件时记得手动拉长超时
|
|||
|
}
|
|||
|
|
|||
|
func debugOutput(msg string) {
|
|||
|
if GlobalDebug {
|
|||
|
slog.Debug(msg)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Ping 📡 微信与服务的健康脉动,轻触即刻,安心无边
|
|||
|
// 骑上代码的独角兽,驰骋在微信与服务的和谐旋律中;
|
|||
|
// 若路遇荆棘(错误翩翩),WxError的信使将携谜团(-1)翩然而至。
|
|||
|
func (*WxApi) Ping() error {
|
|||
|
// 抛出魔法飞毯,直抵全球通讯站(GlobalCallUrl)/ping
|
|||
|
resp, err := http.Get(GlobalCallUrl + "/ping")
|
|||
|
if err != nil {
|
|||
|
// 魔法失效,WxError的封印(-1)悄然降临,记录下不解之谜
|
|||
|
return WxError{-1, err.Error()}
|
|||
|
}
|
|||
|
defer resp.Body.Close() // 隐身术,抹去所有痕迹,不留下一丝涟漪
|
|||
|
|
|||
|
// 倾听回响,秘密文字在耳边低语
|
|||
|
data, err := io.ReadAll(resp.Body)
|
|||
|
if err != nil {
|
|||
|
// 文字破碎,WxError的警告(-2)再次响起
|
|||
|
return WxError{-2, err.Error()}
|
|||
|
}
|
|||
|
|
|||
|
// 古卷解读,将回响化为RespJson的智慧之光
|
|||
|
rjson := RespJson{}
|
|||
|
json.Unmarshal(data, &rjson)
|
|||
|
|
|||
|
// 密文比对,10000是神秘的共鸣密码
|
|||
|
if rjson.Error != 10000 {
|
|||
|
// 密码失真,WxError的困惑(-rjson.Error)引领着归途
|
|||
|
return WxError{rjson.Error, rjson.Msg}
|
|||
|
}
|
|||
|
|
|||
|
// 脉动稳健,旅程圆满,一切安好
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
// GetUserWeChatVersion 探索微信的奥秘维度
|
|||
|
// 跨越星辰大海,追寻新版图的圣杯传说;
|
|||
|
// 若遭逢风暴,空荡的圣杯将裹挟WxError的失落归来。
|
|||
|
func (*WxApi) GetUserWeChatVersion() (string, error) {
|
|||
|
// 出发,以光年速度驶向微信版本的时空节点
|
|||
|
resp, err := http.Get(GlobalCallUrl + "/GetUserWeChatVersion")
|
|||
|
if err != nil {
|
|||
|
// 时空乱流,WxError的幻影(-1)携破碎梦想现身
|
|||
|
return "", WxError{-1, err.Error()}
|
|||
|
}
|
|||
|
defer resp.Body.Close() // 关闭时空裂隙,以防异界侵袭
|
|||
|
|
|||
|
// 接纳圣杯的微光,倾听宇宙的低语
|
|||
|
data, err := io.ReadAll(resp.Body)
|
|||
|
if err != nil {
|
|||
|
// 信息迷失,WxError(-2)的哀歌在虚空中回荡
|
|||
|
return "", WxError{-2, err.Error()}
|
|||
|
}
|
|||
|
|
|||
|
// 古老符文解析,揭示RespJson的宇宙密语
|
|||
|
rjson := RespJson{}
|
|||
|
_ = json.Unmarshal(data, &rjson)
|
|||
|
|
|||
|
// 密令确认,10000是真理的指引
|
|||
|
if rjson.Error != 10000 {
|
|||
|
// 光芒黯淡,WxError(-rjson.Error)载着谜团回归
|
|||
|
return "", WxError{rjson.Error, rjson.Msg}
|
|||
|
}
|
|||
|
|
|||
|
// 圣杯显现,微信版图的最新座标(version)闪耀而出
|
|||
|
return rjson.Data.(map[string]any)["version"].(string), nil
|
|||
|
}
|
|||
|
|
|||
|
// InjectWeChat 微信灵魂注入术,让微信与服务融为一体
|
|||
|
// 邀请全球通讯站,完成神秘仪式;
|
|||
|
// 若召唤失败,WxError的诅咒将随之降临。
|
|||
|
func (w *WxApi) InjectWeChat() (u *UserClientInfo, r error) {
|
|||
|
sl := make(chan int)
|
|||
|
wait := wxInitiativeCallQueue.GetWithSetDefault(loginSuccessMsg, &wxCallQueue{
|
|||
|
Send: make(chan string),
|
|||
|
Resp: make(chan string),
|
|||
|
})
|
|||
|
go func() {
|
|||
|
go func() {
|
|||
|
wait.Send <- "1"
|
|||
|
}()
|
|||
|
|
|||
|
const timeout = 99999
|
|||
|
|
|||
|
// 等待密信,或迎接时间的审判
|
|||
|
select {
|
|||
|
case message := <-wait.Resp:
|
|||
|
sr := WxLoginInfoResp{}
|
|||
|
err := json.Unmarshal([]byte(message), &sr)
|
|||
|
if err != nil {
|
|||
|
r = WxError{-3, "login timeout"}
|
|||
|
sl <- 0
|
|||
|
break
|
|||
|
}
|
|||
|
w.UserInfo = sr.Data
|
|||
|
registerPid[sr.Data.Pid] = true
|
|||
|
sl <- 1
|
|||
|
// return &w.UserInfo, nil
|
|||
|
break
|
|||
|
case <-time.After(time.Duration(timeout) * time.Second):
|
|||
|
r = WxError{-3, "login timeout"}
|
|||
|
sl <- 0
|
|||
|
break
|
|||
|
}
|
|||
|
//if w.UserInfo.Wxid != "" || r != nil {
|
|||
|
// break
|
|||
|
//}
|
|||
|
}()
|
|||
|
// 释放灵能,向宇宙宣告召唤
|
|||
|
resp, err := http.Get(GlobalCallUrl + "/InjectWeChat")
|
|||
|
if err != nil {
|
|||
|
// 灵能消散,WxError的阴霾笼罩(-1)
|
|||
|
return nil, WxError{-1, err.Error()}
|
|||
|
}
|
|||
|
defer resp.Body.Close() // 收敛气息,防止泄露
|
|||
|
|
|||
|
// 汇聚反馈,领悟回应的奥秘
|
|||
|
data, err := io.ReadAll(resp.Body)
|
|||
|
if err != nil {
|
|||
|
close(wait.Send)
|
|||
|
close(wait.Resp)
|
|||
|
wxInitiativeCallQueue.Delete(loginSuccessMsg)
|
|||
|
// 奥秘难解,WxError的迷雾笼罩(-2)
|
|||
|
return nil, WxError{-2, err.Error()}
|
|||
|
}
|
|||
|
<-sl
|
|||
|
if r != nil {
|
|||
|
return nil, r
|
|||
|
}
|
|||
|
|
|||
|
// 解析神秘符号,揭示RespJson的真谛
|
|||
|
var rjson RespJson
|
|||
|
_ = json.Unmarshal(data, &rjson)
|
|||
|
|
|||
|
// 检验仪式成功,10000为灵能共鸣的证明
|
|||
|
if rjson.Error != 10000 {
|
|||
|
// 引力失衡,WxError的警告回荡
|
|||
|
return nil, WxError{rjson.Error, rjson.Msg}
|
|||
|
}
|
|||
|
|
|||
|
// 仪式圆满,灵能注入,无误返回
|
|||
|
return &w.UserInfo, nil
|
|||
|
}
|
|||
|
|
|||
|
// sendWeChatData 📨 内部秘法,向微信投递加密情报
|
|||
|
// 注册ID、客户端ID、JSON数据及超时时限,编织跨越次元的信使;
|
|||
|
// 若信使迷失,WxError的幽灵将悄然而至,揭示暗影的谜团。
|
|||
|
func (*WxApi) sendWeChatData(registerID, ClientID int, JsonData string, timeout int) (rstr string, rerr error) {
|
|||
|
// 符文编织,信使的护甲,信息封存
|
|||
|
jsonBytes, _ := json.Marshal(map[string]interface{}{
|
|||
|
"ClientId": ClientID,
|
|||
|
"JsonData": JsonData,
|
|||
|
})
|
|||
|
var wait *wxCallQueue
|
|||
|
if registerID != 0 {
|
|||
|
wait = wxInitiativeCallQueue.GetWithSetDefault(registerID, &wxCallQueue{
|
|||
|
Send: make(chan string),
|
|||
|
Resp: make(chan string),
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
go func() {
|
|||
|
go func() {
|
|||
|
if registerID != 0 {
|
|||
|
wait.Send <- "1"
|
|||
|
}
|
|||
|
}()
|
|||
|
// 飞翔吧,信使!目标:全球通讯站/SendWeChatData
|
|||
|
url := GlobalCallUrl + "/SendWeChatData"
|
|||
|
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBytes))
|
|||
|
if err != nil {
|
|||
|
rerr = WxError{
|
|||
|
ErrorCode: -1,
|
|||
|
Message: fmt.Sprintf("Error crafting message: %v", err),
|
|||
|
}
|
|||
|
return
|
|||
|
}
|
|||
|
client := &http.Client{}
|
|||
|
resp, err := client.Do(req)
|
|||
|
if err != nil {
|
|||
|
rerr = WxError{
|
|||
|
ErrorCode: -2,
|
|||
|
Message: fmt.Sprintf("Error delivering message: %v", err),
|
|||
|
}
|
|||
|
return
|
|||
|
}
|
|||
|
defer resp.Body.Close()
|
|||
|
|
|||
|
}()
|
|||
|
if registerID != 0 {
|
|||
|
if timeout == 0 {
|
|||
|
timeout = 999999
|
|||
|
}
|
|||
|
if timeout > 0 {
|
|||
|
select {
|
|||
|
case message := <-wait.Resp:
|
|||
|
return message, nil
|
|||
|
case <-time.After(time.Duration(timeout) * time.Second):
|
|||
|
return "", WxError{-3, "request timeout"}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// internalCall
|
|||
|
func (w *WxApi) internalCall(registerID, timeout, Type int, JsonData any, trace any) (string, error) {
|
|||
|
send := map[string]interface{}{
|
|||
|
"type": Type,
|
|||
|
}
|
|||
|
if JsonData != nil {
|
|||
|
send["data"] = JsonData
|
|||
|
}
|
|||
|
if trace != nil {
|
|||
|
send["trace"] = trace
|
|||
|
}
|
|||
|
|
|||
|
jsonBytes, _ := json.Marshal(send)
|
|||
|
|
|||
|
return w.sendWeChatData(registerID, 1, string(jsonBytes), timeout)
|
|||
|
}
|