/// <summary> /// 存储用户微信Cookie标识 /// </summary> /// <param name="redisHelper"></param> /// <param name="userName"></param> /// <param name="cookie"></param> public void SetUserSyncKeys(string wxuin, SyncKey SyncKeys) { var tablename = userRedisKey(wxuin); string keysJson = (JsonConvert.SerializeObject(SyncKeys)); _redisHelper.SetHash(tablename, _synckeys_redis_key_, keysJson); }
/// <summary> /// 消息同步 /// </summary> void wxSync() { string url = String.Format("{0}/cgi-bin/mmwebwx-bin/webwxsync?sid={1}&skey={2}&pass_ticket={3}", gateway, baseRequest.Sid, baseRequest.Skey, passticket); var o = new { BaseRequest = baseRequest, SyncKey = _syncKey, rr = getcurrentseconds() }; var rsp = wc.PostStr(url, Serialize.ToJson(o)); outLog("sync->" + Serialize.ToJson(rsp)); if (rsp.err) { throw new Exception("消息获取失败->" + Serialize.ToJson(rsp)); } _syncKey = Serialize.FromJson <SyncKey>(rsp.data + "", "SyncKey"); var msglist = Serialize.FromJson <List <Msg> >(rsp.data + "", "AddMsgList"); foreach (var m in msglist) { if (m.FromUserName != user.UserName) { outLog("msg->" + user.Uin + "->" + m.Content); NewMsg?.Invoke(m, ukey); } // Debug.WriteLine(user.Uin + "收到消息->" + m.MsgId + "--->>>" + m.Content); } }
public SyncResponse Sync(SyncKey syncKey, string pass_ticket, BaseRequest baseReq) { SetHttpHeader("Accept", "application/json, text/plain, */*"); SetHttpHeader("Connection", "keep-alive"); SetHttpHeader("Accept-Encoding", "gzip, deflate, br"); SetHttpHeader("Origin", this.root_uri); string url = this.root_uri + "/cgi-bin/mmwebwx-bin/webwxsync?sid={0}&skey={1}&lang=zh_CN&pass_ticket={2}"; url = string.Format(url, baseReq.Sid, baseReq.Skey, pass_ticket); SyncRequest req = new SyncRequest(); req.BaseRequest = baseReq; req.SyncKey = syncKey; req.rr = ~getR(); string requestJson = JsonConvert.SerializeObject(req); string repJsonStr = PostString(url, requestJson); if (repJsonStr == null) { return(null); } var rep = JsonConvert.DeserializeObject <SyncResponse>(repJsonStr); return(rep); }
private void HandleSync() { if (mSyncKey == null) { CurrentStatus = ClientStatusType.GetUUID; return; } if (mSyncKey.Count <= 0) { return; } var checkResult = mAPIService.SyncCheck(mSyncKey.List, mBaseReq); if (checkResult.retcode != "0") { CurrentStatus = ClientStatusType.GetUUID; return; } if (checkResult.selector == "0") { return; } var syncResult = mAPIService.Sync(mSyncKey, mPass_ticket, mBaseReq); mSyncKey = syncResult.SyncKey; // 处理同步 ProcessSyncResult(syncResult); }
/// <summary> /// 第六步:获取消息内容 /// </summary> /// <returns></returns> public SyncResult Sync(WechatCookie wechatCookie, string cookieStr, SyncKey syncKey) { if (wechatCookie == null) { throw new Exception("cookie值为空"); } string url = string.Format(WechatUrl.SnycUrl, wechatCookie.Wxsid, wechatCookie.Skey, wechatCookie.Pass_Ticket); SyncParamter param = new SyncParamter(); param.SyncKey = syncKey; param.rr = WechatCommon.GetTicks(); BaseRequest request = new BaseRequest(); request.Uin = wechatCookie.Wxuin; request.DeviceID = DeviceID; request.Sid = wechatCookie.Wxsid; request.Skey = wechatCookie.Skey; param.BaseRequest = request; string postData = JsonConvert.SerializeObject(param); string html = HttpCommon.instance.PostHttp(url, postData, ContentType.json, cookieStr); AppLog.WriteInfo(string.Format("协议:{0},结果:{1}", "Sync", html)); //HttpItem item = new HttpItem() //{ // URL = url,//URL 必需项 // Method = "POST",//URL 可选项 默认为Get // Encoding = Encoding.UTF8, // UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:18.0) Gecko/20100101 Firefox/18.0",//用户的浏览器类型,版本,操作系统 可选项有默认值 // Accept = "text/html, application/xhtml+xml, */*",// 可选项有默认值 // ContentType = "application/json; charset=UTF-8",//返回类型 可选项有默认值 // Cookie = CookieStr,//字符串Cookie 可选项 // Postdata = postData,//Post数据 可选项GET时不需要写 //}; //HttpResult result = http.GetHtml(item); //string html = result.Html; SyncResult sync = new SyncResult(); try { if (!string.IsNullOrEmpty(html) && html != "操作超时") { sync = JsonConvert.DeserializeObject <SyncResult>(html); //SyncKey = sync.SyncKey; //SyncKeyFormat(); //msg = sync.AddMsgList; } } catch (Exception ex) { AppLog.WriteError(ex.Message); } return(sync); }
private void HandleInit() { List <Contact> list = new List <Contact>(); var initResult = client.Init(mPass_ticket, mBaseReq); if (initResult != null && initResult.BaseResponse.ret == 0) { Self = CreateContact(initResult.User); OnGetUser?.Invoke(this, new GetUserEvent() { Self = Self }); foreach (var item in initResult.ContactList) { list.Add(CreateContact(item)); } mSyncKey = initResult.SyncKey; // 开启系统通知 var statusNotifyRep = client.Statusnotify(Self.ID, Self.ID, mPass_ticket, mBaseReq); if (statusNotifyRep != null && statusNotifyRep.BaseResponse != null && statusNotifyRep.BaseResponse.ret == 0) { CurrentStatus = ClientStatusType.WeixinSync; IsLogin = true; } else { LogHandler.i("WechatAPIService", "HandleInit()", statusNotifyRep); CurrentStatus = ClientStatusType.GetUUID; return; } } else { LogHandler.i("WechatAPIService", "HandleInit()", initResult); CurrentStatus = ClientStatusType.GetUUID; return; } if (!InitContactAndGroups()) { CurrentStatus = ClientStatusType.WeixinInit; IsLogin = false; return; } OnInited?.Invoke(this, new InitedEvent() { LastContact = list }); }
public static string SyncKeyFormat(SyncKey syncKey) { StringBuilder result = new StringBuilder(); foreach (var key in syncKey.List) { result.AppendFormat("{0}_{1}|", key.Key, key.Val); } string str = result.ToString().TrimEnd('|'); str = HttpHelper.URLEncode(str); return(str); }
/// <summary> /// 登陆后初始化 /// </summary> void wxInit() { string url = String.Format("{0}/cgi-bin/mmwebwx-bin/webwxinit?pass_ticket={1}&skey={2}&r={3}", gateway, passticket, baseRequest.Skey, getcurrentseconds()); var rsp = wc.PostStr(url, Serialize.ToJson(new { BaseRequest = baseRequest })); outLog("init->" + Serialize.ToJson(rsp)); if (rsp.err) { throw new Exception("初始化失败->" + Serialize.ToJson(rsp)); } user = Serialize.FromJson <Contact>(rsp.data + "", "User"); _syncKey = Serialize.FromJson <SyncKey>(rsp.data + "", "SyncKey"); }
/// <summary> /// 消息同步 /// </summary> void wxSync() { string url = String.Format("{0}/cgi-bin/mmwebwx-bin/webwxsync?sid={1}&skey={2}&pass_ticket={3}", gateway, baseRequest.Sid, baseRequest.Skey, passticket); var o = new { BaseRequest = baseRequest, SyncKey = _syncKey, rr = getcurrentseconds() }; var rsp = wc.PostStr(url, Serialize.ToJson(o)); outLog("sync->" + Serialize.ToJson(rsp)); if (rsp.err) { throw new Exception("消息获取失败->" + Serialize.ToJson(rsp)); } _syncKey = Serialize.FromJson <SyncKey>(rsp.data + "", "SyncKey"); var msglist = Serialize.FromJson <List <Msg> >(rsp.data + "", "AddMsgList"); foreach (var m in msglist) { if (m.FromUserName == user.UserName) { continue; } //outLog("msg->" + user.Uin + "->" + m.Content); //if (m.Content.Contains("你的朋友验证请求,") && m.Content.Contains("可以开始聊天了")) //{ // var rp = db.x_reply.Where(r => r.user_id == lg.user_id); //} //var rps = db.x_reply.FirstOrDefault(o => o.keys) NewMsg?.Invoke(m); } // Debug.WriteLine(user.Uin + "收到消息->" + m.MsgId + "--->>>" + m.Content); }
/// <summary> /// 开始初始化所有关键内容 /// </summary> private void Init() { try { string webwxinitUrl = string.Format(host + "/cgi-bin/mmwebwx-bin/webwxinit?r={0}pass_ticket={1}", Utils.Get_r(), passTicket); JObject postjson = JObject.FromObject(new { BaseRequest = baseRequest }); InitResponse initMsg = httpClient.PostJson <InitResponse>(webwxinitUrl, postjson); if (initMsg.BaseResponse.Ret != 0) { throw new Exception("程序初始化失败"); } //初始化2次,官网也是初始化2次,这样貌似比较稳定 httpClient.PostJson <InitResponse>(webwxinitUrl, postjson); user = initMsg.User; mpSubscribeMsgList = initMsg.MPSubscribeMsgList; syncKey = initMsg.SyncKey; //初始化的时候会返回一个最近联系人列表,但是主要还是以第一次sync获得的最近联系人为准。 asyncOperation.Post( new SendOrPostCallback((list) => { BatchGetContactComplete?.Invoke(this, new TEventArgs <List <Contact> >((List <Contact>)list)); }), initMsg.ContactList); asyncOperation.Post( new SendOrPostCallback((obj) => { LoginComplete?.Invoke(this, new TEventArgs <User>((User)obj)); }), user); } catch (Exception ex) { FileLog.Exception("Init", ex); asyncOperation.Post( new SendOrPostCallback((obj) => { ExceptionCatched?.Invoke(this, new TEventArgs <Exception>((Exception)obj)); }), ex); //throw ex; } }
private void HandleSync() { if (mSyncKey == null)//LogHandler { LogHandler.i("WechatAPIService... HandleSync() ... mSyncKey==null"); CurrentStatus = ClientStatusType.GetUUID; return; } if (mSyncKey.Count <= 0) { return; } var checkResult = client.SyncCheck(mSyncKey.List, mBaseReq, ++mSyncCheckTimes); if (checkResult == null) { return; } if (checkResult.retcode != null && checkResult.retcode != "0") { LogHandler.i("WechatAPIService... HandleSync() ... checkResult=" + checkResult.retcode + "," + checkResult.selector); CurrentStatus = ClientStatusType.GetUUID; return; } if (checkResult.selector == "0") { return; } var syncResult = client.Sync(mSyncKey, mPass_ticket, mBaseReq); if (syncResult == null) { return; } mSyncKey = syncResult.SyncKey; // 处理同步 ProcessSyncResult(syncResult); }
/// <summary> /// 获取消息 /// </summary> /// <param name="sk"></param> /// <returns></returns> public static ResponseMessage GetMessage(SyncKey sk) { var body = new { BaseRequest = new { Uin = long.Parse(_uin), Sid = _sid, Skey = _skey, DeviceID = "e155590153985983" }, SyncKey = sk, rr = long.Parse($"-{DataHelper.GetTimeStamp(10).Substring(0, 9).Negation()}") }.ObjectToJson(); var bytes = new WebHelper().SendPostRequest( string.Format(_get_new_message, _sid, _skey, _pass_ticket), body); var response = bytes.BytesToString().JsonToObject <ResponseMessage>(); return(response); }
public IResult <FetchMessageResponse> FetchMessage(LoginResponse loginResponse, SyncKey syncKey) { var result = new Result <FetchMessageResponse>(); try { var fetchMessageUrl = string.Format(UrlEndPoints.FetchMessageUrl, loginResponse.WxSid, loginResponse.Skey, loginResponse.PassTicket); var request = new FetchMessageRequest() { BaseRequest = new BaseRequest() { DeviceID = SystemInfo.DeviceId, Sid = loginResponse.WxSid, Skey = loginResponse.Skey, Uin = loginResponse.WxUin.ToString() }, SyncKey = syncKey, rr = DateTimeHelper.Default.GetTimestamp(13) }; var postStr = JsonConvert.SerializeObject(request); var content = new StringContent(postStr); content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/x-www-form-urlencoded"); var response = _HttpClient.PostAsync(fetchMessageUrl, content).Result; var respage = response.Content.ReadAsStringAsync().Result; var fetchMessageResponse = JsonConvert.DeserializeObject <FetchMessageResponse>(respage); result.SetSuccess(); result.SetData(fetchMessageResponse); return(result); } catch (Exception ex) { LogHelper.Default.LogDay($"消息拉取异常,{ex}"); LogHelper.Default.LogPrint($"消息拉取异常,{ex.Message}", 4); result.SetFailed(); result.SetDesc($"消息拉取异常,{ex.Message}"); return(result); } }
public static byte[] mergeKeyBuf(byte[] oldbuf, byte[] newbuf) { if ((oldbuf == null) || (oldbuf.Length == 0)) { return(newbuf); } if ((newbuf == null) || (newbuf.Length == 0)) { return(oldbuf); } SyncKey key = null; try { key = SyncKey.ParseFrom(oldbuf); } catch (Exception exception) { Log.e("NetSceneNewInit", "synckey oldbuf is invalid" + exception.Message); return(newbuf); } SyncKey key2 = null; try { key2 = SyncKey.ParseFrom(newbuf); } catch (Exception exception2) { Log.e("NetSceneNewInit", "synckey newbuf is invalid" + exception2.Message); return(oldbuf); } IList <KeyVal> keyList = key.KeyList; IList <KeyVal> list2 = key2.KeyList; Dictionary <uint, uint> dictionary = new Dictionary <uint, uint>(); for (int i = 0; i < keyList.Count; i++) { if (!dictionary.ContainsKey(keyList[i].Key)) { dictionary.Add(keyList[i].Key, keyList[i].Val); } } for (int j = 0; j < list2.Count; j++) { if (dictionary.ContainsKey(list2[j].Key)) { dictionary[list2[j].Key] = list2[j].Val; } else { dictionary.Add(list2[j].Key, list2[j].Val); } } SyncKey defaultInstance = SyncKey.DefaultInstance; SyncKey.Builder builder = new SyncKey.Builder().SetKeyNum((uint)dictionary.Count); foreach (KeyValuePair <uint, uint> pair in dictionary) { KeyVal.Builder introduced17 = KeyVal.CreateBuilder().SetKey(pair.Key); KeyVal item = introduced17.SetVal(pair.Value).Build(); builder.KeyList.Add(item); } return(builder.Build().ToByteArray()); }
/// <summary> /// 心跳检测微信状态 /// </summary> public static void HeartbeatWxStatus(HttpResponse httpResponse, string wxHosts, string wxCookie, PassTicketXmlInfo keys, SyncKey syncKey) { var status = WeiXinHelper.GetWxStatus(wxHosts, wxCookie, keys, syncKey); var wxnews = WeiXinHelper.GetNews(wxHosts, wxCookie, keys, syncKey); if (status) { Thread.Sleep(20000); HeartbeatWxStatus(httpResponse, wxHosts, wxCookie, keys, syncKey); } else { throw new CustomerException(String.Format("当前登录状态消失 时间:", DateTime.Now), -2); } }
public static bool CheckStatus(HttpResponse httpResponse, string wxHosts, string wxCookie, PassTicketXmlInfo keys, SyncKey syncKey) { var status = WeiXinHelper.GetWxStatus(wxHosts, wxCookie, keys, syncKey); if (!status) { AuthCore.DeleteUin(httpResponse); throw new CustomerException("登录过期,请重新登录", -2); } return(status); }
/// <summary> /// 开始轮询检测是否有新消息 /// </summary> private void Sync() { while (syncPolling) { try { string syncCheckUrl = string.Format(pushHost + "/cgi-bin/mmwebwx-bin/synccheck?r={0}&skey={1}&sid={2}&uin={3}&deviceid={4}&synckey={5}&_={6}", Utils.GetJavaTimeStamp(), baseRequest.Skey, baseRequest.Sid, baseRequest.Uin, baseRequest.DeviceID, syncKey.ToString(), syncKey.Step); string syncCheckResult = httpClient.GetString(syncCheckUrl); if (!syncPolling) { return; } MatchCollection matchCollection = Regex.Matches(syncCheckResult, @"\d+"); string retcode = matchCollection[0].Value; string selector = matchCollection[1].Value; Utils.Debug("retcode:" + retcode + " selector:" + selector); switch (retcode) { case "0": if (selector != "0") { //有新消息,拉取信息。 SyncRequest syncRequest = new SyncRequest(); syncRequest.BaseRequest = baseRequest; syncRequest.SyncKey = syncKey; syncRequest.rr = Utils.Get_r(); string syncUrl = string.Format(host + "/cgi-bin/mmwebwx-bin/webwxsync?sid={0}&skey={1}&pass_ticket={2}", baseRequest.Sid, baseRequest.Skey, passTicket); SyncResponse syncResponse = httpClient.PostJson <SyncResponse>(syncUrl, syncRequest); if (!syncPolling) { return; } else { syncKey = syncResponse.SyncKey; //只要不是0,就是有消息,有消息我们处理就行了,不管selector是几 if (syncResponse.AddMsgCount == 0 && syncResponse.DelContactCount == 0 && syncResponse.ModContactCount == 0 && syncResponse.ModChatRoomMemberCount == 0) { //会有这么一种情况,selector=2,但是没有任何消息体,这样会导致持续快速的空交互 //除非下次有新消息,或者主动点击手机触发消息 //为了防止这种情况,做个5秒停顿。 Thread.Sleep(5000); } else { if (syncResponse.AddMsgList.Count > 0) { asyncOperation.Post( new SendOrPostCallback((obj) => { ReceiveMsg?.Invoke(this, new TEventArgs <List <AddMsg> >((List <AddMsg>)obj)); }), syncResponse.AddMsgList); } if (syncResponse.ModContactCount > 0) { asyncOperation.Post( new SendOrPostCallback((obj) => { ModContactListComplete?.Invoke(this, new TEventArgs <List <ModContactItem> >((List <ModContactItem>)obj)); }), syncResponse.ModContactList); } if (syncResponse.DelContactCount > 0) { asyncOperation.Post( new SendOrPostCallback((obj) => { DelContactListComplete?.Invoke(this, new TEventArgs <List <DelContactItem> >((List <DelContactItem>)obj)); }), syncResponse.DelContactList); } if (syncResponse.ModChatRoomMemberCount > 0) { //待分析,这个消息基本没有 } } } } break; case "1100": //登出了微信,很可能是wx.qq.com和wx2.qq.com调用接口不一致导致的,注意登陆时候的跳转地址 Close(); asyncOperation.Post( new SendOrPostCallback((obj) => { LogoutComplete?.Invoke(this, new TEventArgs <User>((User)obj)); }), user); break; case "1101": Close(); asyncOperation.Post( new SendOrPostCallback((obj) => { LogoutComplete?.Invoke(this, new TEventArgs <User>((User)obj)); }), user); throw new Exception("1101可能其他地方登录/登出了 WEB 版微信,请检查手机端已登出WEB微信,然后稍后再试"); break; case "1102": Close(); asyncOperation.Post( new SendOrPostCallback((obj) => { LogoutComplete?.Invoke(this, new TEventArgs <User>((User)obj)); }), user); throw new Exception("1102被强制登出(很可能cookie冲突),请检查手机端已登出WEB微信,然后稍后再试"); break; default: //有其他任何异常,取消轮询 throw new Exception("轮询结果异常,停止轮询:" + syncCheckResult); break; } Thread.Sleep(1000); } catch (Exception ex) { FileLog.Exception("Init", ex); asyncOperation.Post( new SendOrPostCallback((obj) => { ExceptionCatched?.Invoke(this, new TEventArgs <Exception>((Exception)obj)); }), ex); } } }
/// <summary> /// 运行微信Client主逻辑,推荐放在独立的线程中执行这个方法 /// </summary> public void Run() { // 启动流程 // 1.登陆 // 2.初始化 // 3.开启系统通知 // 4.获得联系人列表 // 5.进入同步主循环 // ----------1.登陆 do { Debug.Write("[*] 正在获取Session ...."); string session = api.GetNewQRLoginSessionID(); if (!string.IsNullOrWhiteSpace(session)) { Debug.Write("成功\n"); } else { continue; } Debug.Write("[*] 正在生成二维码 ...."); var QRImg = api.GetQRCodeImage(session); if (QRImg != null) { Debug.Write("成功\n"); } else { continue; } Debug.Write("[*] 正在等待扫码 ...."); OnGetQRCodeImage?.Invoke(QRImg); //login check while (true) { var loginResult = api.Login(session); if (loginResult.code == 200) { // 登录成功 var redirectResult = api.LoginRedirect(loginResult.redirect_uri); mBaseReq = new BaseRequest(); mBaseReq.Skey = redirectResult.skey; mBaseReq.Sid = redirectResult.wxsid; mBaseReq.Uin = redirectResult.wxuin; // 生成DeviceID Random ran = new Random(); int rand1 = ran.Next(10000, 99999); int rand2 = ran.Next(10000, 99999); int rand3 = ran.Next(10000, 99999); mBaseReq.DeviceID = string.Format("e{0}{1}{2}", rand1, rand2, rand3); mPass_ticket = redirectResult.pass_ticket; IsLogin = true; Debug.Write("已确认\n"); break; } else if (loginResult.code == 201) { // 已扫描,但是未确认登录 // convert base64 to image byte[] base64_image_bytes = Convert.FromBase64String(loginResult.UserAvatar); MemoryStream memoryStream = new MemoryStream(base64_image_bytes, 0, base64_image_bytes.Length); memoryStream.Write(base64_image_bytes, 0, base64_image_bytes.Length); var image = Image.FromStream(memoryStream); OnUserScanQRCode?.Invoke(image); Debug.Write("已扫码\n"); Debug.Write("[*] 正在等待确认 ...."); } else { // 超时 Debug.Write("超时\n"); break; } } } while (!IsLogin); // ----------2.初始化 Debug.Write("[*] 正在初始化 ...."); var initResult = api.Init(mPass_ticket, mBaseReq); if (initResult.BaseResponse.ret == 0) { Debug.Write("成功\n"); } else { Debug.Write("失败.错误码:" + initResult.BaseResponse.ret); return; } CurrentUser = initResult.User; // 最近联系人 mRecentContacts.Clear(); if (initResult.ContactList != null) { foreach (var user in initResult.ContactList) { CacheUser(user); mRecentContacts.Add(user.UserName); } } // chatsets 里有需要获取详细信息的联系人. List <string> waitingToCacheUserList = new List <string>(); var chatsets = initResult.ChatSet.Split(','); foreach (var username in chatsets) { if (!username.StartsWith("@")) { continue; } if (!mCachedUsers.ContainsKey(username) && !waitingToCacheUserList.Contains(username)) { waitingToCacheUserList.Add(username); } } // ----------3.开启状态通知 Debug.Write("[*] 正在开启系统通知 ...."); var statusNotifyRep = api.Statusnotify(CurrentUser.UserName, CurrentUser.UserName, mPass_ticket, mBaseReq); if (statusNotifyRep != null && statusNotifyRep.BaseResponse != null && statusNotifyRep.BaseResponse.ret == 0) { Debug.Write("成功\n"); } else { Debug.Write("失败.错误码:" + statusNotifyRep.BaseResponse.ret); return; } // ----------4.获得联系人列表 Debug.Write("[*] 正在获取联系人列表 ...."); var getContactResult = api.GetContact(mPass_ticket, mBaseReq.Skey); if (getContactResult != null && getContactResult.BaseResponse != null && getContactResult.BaseResponse.ret == 0) { Debug.Write("成功\n"); Debug.WriteLine("[*] 共有 " + getContactResult.MemberCount + " 个联系人."); } else { Debug.Write("失败. 错误码:" + getContactResult.BaseResponse.ret); return; } foreach (var user in getContactResult.MemberList) { CacheUser(user); mContactList.Add(user.UserName); } Debug.Write("[*] 正在请求群聊成员详细信息 ....\n"); //-----------5.批量获取群组详细信息 foreach (var user in mCachedUsers.Values) { if (user.UserName.StartsWith("@@")) { RefreshGroupMemberInfo(user.UserName); } } OnLoginSucess?.Invoke(); SyncKey syncKey = initResult.SyncKey; // ----------6.同步主循环 Debug.WriteLine("[*] 进入同步循环 ...."); while (true) { bool hasInitMsg = false; // 同步 if (syncKey.Count > 0) { var syncCheckResult = api.SyncCheck(syncKey.List, mBaseReq); if (syncCheckResult == null) { continue; } if (syncCheckResult.retcode != "0") { Debug.WriteLine("[*] 登陆已失效,请重新登陆 ...."); IsLogin = false; mCachedUsers.Clear(); mRecentContacts.Clear(); mContactList.Clear(); return; } if (syncCheckResult.retcode == "0" && syncCheckResult.selector != "0") { Debug.WriteLine(string.Format("[*] 同步检查 RetCode:{0} Selector:{1}", syncCheckResult.retcode, syncCheckResult.selector)); var syncResult = api.Sync(syncKey, mPass_ticket, mBaseReq); syncKey = syncResult.SyncKey; Debug.WriteLine(string.Format("[*] 同步结果 AddMsgCount:{0} ModContactCount:{1}", syncResult.AddMsgCount, syncResult.ModContactCount)); // addmsg if (syncResult.AddMsgCount > 0) { foreach (var msg in syncResult.AddMsgList) { // 过滤系统信息 if (msg.MsgType != 51) { OnRecvMsg?.Invoke(msg); } else { hasInitMsg = true; } var notifyUserNames = msg.StatusNotifyUserName.Split(','); foreach (var username in notifyUserNames) { if (!username.StartsWith("@")) { continue; } if (!mCachedUsers.ContainsKey(username) && !waitingToCacheUserList.Contains(username)) { waitingToCacheUserList.Add(username); } } } } // modify contact if (syncResult.ModContactList != null) { foreach (var modContact in syncResult.ModContactList) { CacheUser(modContact); } } } } if (waitingToCacheUserList.Count > 0) { // 获得群详细信息 Debug.WriteLine("[*] 正在获取联系人详细信息 ...."); foreach (var userName in waitingToCacheUserList) { if (userName.StartsWith("@@")) { RefreshGroupMemberInfo(userName); } } var batchResult = api.BatchGetContact(waitingToCacheUserList.ToArray(), mPass_ticket, mBaseReq); if (batchResult != null && batchResult.ContactList != null) { foreach (var user in batchResult.ContactList) { CacheUser(user); } Debug.WriteLine("[*] 获取到联系人详细信息 " + batchResult.Count + "个"); } waitingToCacheUserList.Clear(); } // 初始化完成回调 if (hasInitMsg && !firstInited) { firstInited = true; OnInitComplate?.Invoke(); } } }
/// <summary> /// 获取新消息,延长Cookie时间 /// </summary> /// <param name="wxHosts"></param> /// <param name="wxCookie"></param> /// <param name="keys"></param> /// <param name="syncKey"></param> public static string GetNews(string wxHosts, string wxCookie, PassTicketXmlInfo keys, SyncKey syncKey) { var param = new { BaseRequest = new { skey = keys.skey, sid = keys.wxsid, uin = keys.wxuin, deviceid = GetWxDeviceId(), }, SyncKey = syncKey }; var httpHelper = new HttpHelper(param, GetWxCookie(wxCookie)); var result = httpHelper.HttpPost(WxNews(wxHosts, keys.wxsid, keys.skey)); var setcookie = httpHelper.ReturnCookie; return(result); }
public static bool GetWxStatus(string wxHosts, string wxCookie, PassTicketXmlInfo keys, SyncKey syncKey) { var param = new { r = TimeHelper.GetTimeStamp(), skey = keys.skey, sid = keys.wxsid, uin = keys.wxuin, deviceid = GetWxDeviceId(), synckey = String.Join("|", syncKey.List.Select(m => String.Format("{0}_{1}", m.Key, m.Val))) }; var result = new HttpHelper(param, GetWxCookie(wxCookie)).HttpGet(WxStatus(wxHosts)); var statusJson = result.Replace("window.synccheck=", ""); var status = JsonConvert.DeserializeObject <WxStatus>(statusJson); return(status.RetCode.Equals("0")); }
/// <summary> /// /// </summary> /// <param name="list"></param> /// <param name="cts"></param> /// <param name="nks"></param> /// <param name="t"></param> List <object> toContact(List <Contact> list, Dictionary <string, int> nks, long gpid) { var cts = new List <x_contact>(); var gps = new List <object>(); foreach (var c in list) { var n = c.NickName; if (!string.IsNullOrEmpty(c.RemarkName)) { n = c.RemarkName; } if (gpid > 0) { n += gpid; } n += user.Uin; if (nks.ContainsKey(n)) { c.RemarkName = c.NickName + (++nks[n]).ToString("000"); } //SetRemark(c.UserName, c.RemarkName); else { nks.Add(n, 0); c.RemarkName = n; } var no = Secret.MD5(n); var ct = db.x_contact.FirstOrDefault(t => t.no == no && t.uin == user.Uin); if (ct == null) { ct = new x_contact() { uin = user.Uin, no = no } } ; ct.user_id = lg.user_id; ct.remarkname = c.RemarkName; ct.nickname = Tools.RemoveHtml(c.NickName); ct.flag = c.UserName[1] == '@' ? 2 : 1; ct.group_id = gpid; ct.membercount = c.MemberCount; ct.signature = c.Signature; ct.username = c.UserName; ct.imgurl = c.HeadImgUrl; var m = new Regex("(\\d{11})").Match(c.NickName); if (m.Success) { ct.tel = m.Groups[1].Value; } if (ct.contact_id == 0) { cts.Add(ct); } if (c.UserName[1] == '@') { gps.Add(new { EncryChatRoomId = c.EncryChatRoomId, UserName = c.UserName }); } } if (cts.Count > 0) { db.x_contact.InsertAllOnSubmit(cts); } try { db.SubmitChanges(ConflictMode.ContinueOnConflict); db.SubmitChanges(ConflictMode.FailOnFirstConflict); } catch (ChangeConflictException) { foreach (ObjectChangeConflict occ in db.ChangeConflicts) { occ.Resolve(RefreshMode.KeepChanges); } } catch (Exception ex) { outLog("toContact->err:" + ex.Message); } return(gps); } /// <summary> /// 同步检测 /// </summary> void SyncCheck() { var url = String.Format("{0}/cgi-bin/mmwebwx-bin/synccheck?r={1}&sid={2}&uin={3}&skey={4}&deviceid={5}&synckey={6}&_{7}", gateway, getcurrentseconds(), baseRequest.Sid, baseRequest.Uin, baseRequest.Skey, baseRequest.DeviceID, synckey, getcurrentseconds()); var rsp = wc.GetStr(url); outLog("synccheck->" + Serialize.ToJson(rsp)); if (rsp.err) { return; throw new Exception("心跳同步失败->" + Serialize.ToJson(rsp)); } var reg = new Regex("{retcode:\"(\\d+)\",selector:\"(\\d+)\"}"); var m = reg.Match(rsp.data + ""); var rt = int.Parse(m.Groups[1].Value); var sel = int.Parse(m.Groups[2].Value); if (isquit || rt != 0) { exit(1); } else if (sel == 2 || sel == 4 || sel == 6) { wxSync(); } } /// <summary> /// 消息同步 /// </summary> void wxSync() { string url = String.Format("{0}/cgi-bin/mmwebwx-bin/webwxsync?sid={1}&skey={2}&pass_ticket={3}", gateway, baseRequest.Sid, baseRequest.Skey, passticket); var o = new { BaseRequest = baseRequest, SyncKey = _syncKey, rr = getcurrentseconds() }; var rsp = wc.PostStr(url, Serialize.ToJson(o)); outLog("sync->" + Serialize.ToJson(rsp)); if (rsp.err) { throw new Exception("消息获取失败->" + Serialize.ToJson(rsp)); } _syncKey = Serialize.FromJson <SyncKey>(rsp.data + "", "SyncKey"); var msglist = Serialize.FromJson <List <Msg> >(rsp.data + "", "AddMsgList"); foreach (var m in msglist) { if (m.FromUserName == user.UserName) { continue; } outLog("msg->" + user.Uin + "->" + m.Content); if (m.Content.Contains("你的朋友验证请求,") && m.Content.Contains("可以开始聊天了")) { var rp = db.x_reply.Where(r => r.user_id == lg.user_id); } //var rps = db.x_reply.FirstOrDefault(o => o.keys) NewMsg?.Invoke(m); } // Debug.WriteLine(user.Uin + "收到消息->" + m.MsgId + "--->>>" + m.Content); } /// <summary> /// 发送消息 /// </summary> /// <param name="ToUserName"></param> /// <param name="Content"></param> void sendText(string ToUserName, string Content) { string url = String.Format("{0}/cgi-bin/mmwebwx-bin/webwxsendmsg?pass_ticket={1}", gateway, passticket); Content = Content.Replace("<br/>", "\n"); var o = new { BaseRequest = baseRequest, Msg = new { Type = 1, Content = Content, FromUserName = user.UserName, ToUserName = ToUserName, LocalID = getcurrentseconds(), ClientMsgId = getcurrentseconds() } }; var rsp = op.PostStr(url, Serialize.ToJson(o)); outLog("SendMsg->" + Serialize.ToJson(rsp)); } /// <summary> /// 发送图片 /// </summary> /// <param name="ToUserName"></param> /// <param name="url"></param> void sendImg(string ToUserName, string mmid) { //var mmid = uploadImg(ToUserName, url); //if (string.IsNullOrEmpty(mmid)) return; string api = String.Format("{0}/cgi-bin/mmwebwx-bin/webwxsendmsgimg?fun=async&f=json&pass_ticket={1}", gateway, passticket); var o = new { BaseRequest = baseRequest, Msg = new { Type = 3, MediaId = mmid, FromUserName = user.UserName, ToUserName = ToUserName, LocalID = getcurrentseconds(), ClientMsgId = getcurrentseconds() }, Scene = 0 }; var rsp = op.PostStr(api, Serialize.ToJson(o)); if (!(rsp.data + "").Contains("\"Ret\": 0")) { Thread.Sleep(5 * 1000); } outLog("SendImg->" + Serialize.ToJson(rsp)); } /// <summary> /// 上传图片 /// </summary> /// <param name="img"></param> /// <returns></returns> string uploadImg(string img) { var fs = op.GetFile(img); if (fs.err) { return(""); } string url = gateway.Replace("https://", "https://file.") + "/cgi-bin/mmwebwx-bin/webwxuploadmedia?f=json"; var o = new { UploadType = 2, BaseRequest = baseRequest, ClientMediaId = getcurrentseconds(), TotalLen = (fs.data as byte[]).Length, StartPos = 0, DataLen = (fs.data as byte[]).Length, MediaType = 4 }; Dictionary <string, string> dict = new Dictionary <string, string>(); dict.Add("id", "WU_FILE_" + filecount++); dict.Add("name", img.Substring(img.LastIndexOf('/') + 1)); dict.Add("type", Tools.GetMimeType(img.Substring(img.LastIndexOf('.') + 1))); dict.Add("lastModifiedDate", "Wed Sep 07 2016 10:38:12 GMT+0800");//DateTime.Now.ToString("r") dict.Add("size", (fs.data as byte[]).Length + ""); dict.Add("mediatype", "pic"); dict.Add("uploadmediarequest", Serialize.ToJson(o)); dict.Add("webwx_data_ticket", wc.GetCookie("webwx_data_ticket")); dict.Add("pass_ticket", passticket); var rsp = op.PostFile(url, dict, fs.data as byte[]); outLog("UploadImg->" + Serialize.ToJson(rsp)); if (rsp.err) { return(""); } return(Serialize.FromJson <string>(rsp.data + "", "MediaId")); } /// <summary> /// 退出 /// </summary> /// <param name="c"></param> void exit(int c) { outLog("exit"); isquit = true; if (lg != null) { lg.uuid = null; lg.qrcode = null; lg.status = 1; try { db.SubmitChanges(); db.Dispose(); } catch (Exception ex) { outLog("exit->err:" + ex.Message); } } if (c == 1) { Logout?.Invoke(); } }