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) }