373 lines
14 KiB
C#
373 lines
14 KiB
C#
using Chat.Framework.WXSdk.Implement;
|
|
using Google.Protobuf;
|
|
using System;
|
|
using System.Net;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Web.Script.Serialization;
|
|
using WechatProto;
|
|
using System.Linq;
|
|
using System.Text.RegularExpressions;
|
|
using Chat.Framework.WXSdk.Events;
|
|
using Grpc.Core;
|
|
|
|
namespace Chat.Framework.WXSdk.IPAD
|
|
{
|
|
/// <summary>
|
|
/// 协议发送包
|
|
/// </summary>
|
|
public class WechatPack
|
|
{
|
|
public class PackMsg
|
|
{
|
|
//(WechatCmd cmd, bool isAnalysis, object data = null, ByteString longHead = null,string text=""
|
|
public WechatCmd cmd { get; set; }
|
|
public object data { get; set; }
|
|
}
|
|
WXClientImpl_IPAD client;
|
|
JavaScriptSerializer js = new JavaScriptSerializer();
|
|
public WechatPack(WXClientImpl_IPAD client)
|
|
{
|
|
this.client = client;
|
|
this.js.MaxJsonLength = int.MaxValue;
|
|
}
|
|
|
|
public WechatMsg Req { get; private set; }
|
|
private int ReadInt(byte[] buf, int index)
|
|
{
|
|
if (buf.Length >= 16)
|
|
{
|
|
var seqBuf = new byte[4];
|
|
Buffer.BlockCopy(buf, index, seqBuf, 0, 4);
|
|
return IPAddress.NetworkToHostOrder(BitConverter.ToInt32(seqBuf, 0));
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
public byte[] Analysis(int cmd, byte[] data)
|
|
{
|
|
return Send(cmd > 0 ? cmd * -1 : cmd, data);
|
|
}
|
|
public byte[] Analysis(WechatCmd cmd, object data)
|
|
{
|
|
return Send((int)cmd * -1, data);
|
|
}
|
|
public byte[] Analysis(byte[] data)
|
|
{
|
|
int cmd = Req.BaseMsg.Cmd * -1;
|
|
return Send(cmd, data);
|
|
}
|
|
/// <summary>
|
|
/// 发送完整包,并解析微信返回信息
|
|
/// </summary>
|
|
public byte[] SendAll(WechatCmd cmd, bool isAnalysis, object data = null, ByteString longHead = null, string text = "")
|
|
{
|
|
|
|
var _data = Send(cmd, data, longHead);
|
|
if (_data != null && !IsShortResult)//判断数据不为空,并且不是腾讯短连接返回的结果
|
|
{
|
|
_data = SendWx(_data, text: text);
|
|
|
|
}
|
|
if (isAnalysis)
|
|
{
|
|
if (_data == null) return null;
|
|
return this.Analysis(_data);
|
|
}
|
|
return _data;
|
|
}
|
|
private bool IsShortResult { get; set; }
|
|
public byte[] Send(WechatCmd cmd, object data = null, ByteString longHead = null)
|
|
{
|
|
return Send((int)cmd, data, longHead);
|
|
}
|
|
public byte[] Send(WechatCmd cmd, byte[] data, ByteString longHead = null)
|
|
{
|
|
return Send((int)cmd, data, longHead);
|
|
}
|
|
// GrpcClient grpcClient = null;
|
|
private GrpcClient GetGrpcClient(WechatMsg req)
|
|
{
|
|
//if (grpcClient != null && grpcClient.IsConnected) return grpcClient;
|
|
GrpcClient grpcClient = null;
|
|
if (codes.Contains(req.BaseMsg.Cmd))
|
|
{
|
|
grpcClient = client.GetGrpcClient(GrpcType.Huangfan);
|
|
//grpcClient = new GrpcClient(GrpcConfig.Get(GrpcType.Huangfan, false)); //client.GetGrpcClient(GrpcType.Huangfan);
|
|
}
|
|
else
|
|
{
|
|
grpcClient = client.GetGrpcClient(GrpcType.Laoyao);
|
|
}
|
|
return grpcClient;
|
|
}
|
|
public byte[] Send(WechatMsg req)
|
|
{
|
|
int number = 0;
|
|
|
|
//GrpcClient grpc_client = null;
|
|
try
|
|
{
|
|
Next:
|
|
IsShortResult = false;
|
|
number++;
|
|
var msg = req.BaseMsg;
|
|
var grpc = GetGrpcClient(req);
|
|
//WechatMsg _req = SendGRPC(req, client).Result;
|
|
WechatMsg _req = grpc.Send(req, client).Result;
|
|
if (_req != null) Req = _req;
|
|
else
|
|
{
|
|
if (number < 3)
|
|
{
|
|
Thread.Sleep(100);
|
|
goto Next;
|
|
}
|
|
else throw new Exception("无法获取GRPC返回包!");
|
|
}
|
|
|
|
var Data = new byte[Req.BaseMsg.LongHead.Length + Req.BaseMsg.Payloads.Length];
|
|
var Head = Req.BaseMsg.LongHead.ToByteArray();
|
|
var Seq = ReadInt(Head, 12);
|
|
if (msg.Cmd < 0 && (int)WechatCmd.发送图片文件 != msg.Cmd)
|
|
{
|
|
ByteString key = null;
|
|
if (Req.BaseMsg.User.AutoAuthKey.Length != 0)
|
|
{
|
|
key = Req.BaseMsg.User.AutoAuthKey;
|
|
}
|
|
else if (client.User.User.AutoAuthKey.Length != 0)
|
|
key = client.User.User.AutoAuthKey;
|
|
|
|
if (msg.Cmd == -138 || msg.Cmd == -1002 || msg.Cmd == -702 || msg.Cmd == -1001 || msg.Cmd == -380)
|
|
{
|
|
client.User.User = Req.BaseMsg.User;
|
|
}
|
|
if (key != null)
|
|
{
|
|
client.User.User.AutoAuthKey = key;
|
|
}
|
|
|
|
return Req.BaseMsg.Payloads.ToByteArray();
|
|
}
|
|
|
|
if (msg.Cmd == (int)WechatCmd.获取标签 || msg.Cmd == (int)WechatCmd.添加标签 || msg.Cmd == (int)WechatCmd.修改标签 || msg.Cmd == (int)WechatCmd.搜索关键词 || msg.Cmd == 179 || msg.Cmd == (int)WechatCmd.编辑联系人信息 || msg.Cmd == (int)WechatCmd.删除好友 || msg.Cmd == 281 || msg.Cmd == 851 || msg.Cmd == 551 || msg.Cmd == 805 || msg.Cmd == 610 || msg.Cmd == 385 || msg.Cmd == 945 || msg.Cmd == (int)WechatCmd.评论或点赞 || msg.Cmd == (int)WechatCmd.邀请入群 || msg.Cmd == (int)WechatCmd.获取登录短信 || msg.Cmd == (int)WechatCmd.群公告)
|
|
{
|
|
IsShortResult = true;
|
|
var data = client.Socket.SendWeChatPost(Req.BaseMsg.Payloads.ToByteArray(), Req.BaseMsg.CmdUrl, 3);
|
|
//if (data == null)
|
|
//{
|
|
// return this.SendWx(data);
|
|
//}
|
|
//else
|
|
|
|
return data; //byte[] _data = null;
|
|
//CsharpHttpHelper.HttpHelper http = new CsharpHttpHelper.HttpHelper();
|
|
//for (int i = 0; i < 2; i++)
|
|
//{
|
|
// try
|
|
// {
|
|
// var item = new CsharpHttpHelper.HttpItem()
|
|
// {
|
|
// URL = "http://" + client.Host.GetSort() + Req.BaseMsg.CmdUrl,
|
|
// Method = "post",
|
|
// PostdataByte = Req.BaseMsg.Payloads.ToByteArray(),
|
|
// UserAgent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)",
|
|
// ContentType = "application/x-www-form-urlencoded",
|
|
// Allowautoredirect = true,
|
|
// Timeout = 5000,
|
|
// ReadWriteTimeout = 5000,
|
|
// ResultType = CsharpHttpHelper.Enum.ResultType.Byte,
|
|
// PostDataType = CsharpHttpHelper.Enum.PostDataType.Byte
|
|
// };
|
|
// _data = http.GetHtml(item).ResultByte;
|
|
// if (_data == null) continue;
|
|
// if (_data[0] != 191) continue;
|
|
// break;
|
|
// }
|
|
// catch (Exception)
|
|
// {
|
|
// }
|
|
//}
|
|
//return _data;
|
|
}
|
|
|
|
try
|
|
{
|
|
var Body = Req.BaseMsg.Payloads.ToByteArray();
|
|
Buffer.BlockCopy(Head, 0, Data, 0, 16);
|
|
Buffer.BlockCopy(Body, 0, Data, 16, Body.Length);
|
|
return Data;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
if (number < 3)
|
|
{
|
|
Thread.Sleep(100);
|
|
goto Next;
|
|
}
|
|
else throw ex;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw ex;
|
|
}
|
|
}
|
|
|
|
private static int[] codes = new int[] { };//1111, 2222, 702, 3333, 380
|
|
public byte[] Send(int cmd, object data, ByteString longHead = null)
|
|
{
|
|
try
|
|
{
|
|
ByteString param = null;
|
|
if (data != null)
|
|
{
|
|
if (typeof(string) == data.GetType())
|
|
{
|
|
param = ByteString.CopyFrom(Encoding.UTF8.GetBytes(data.ToString()));
|
|
}
|
|
else if (typeof(byte[]) != data.GetType())
|
|
{
|
|
var json = js.Serialize(data);
|
|
param = ByteString.CopyFrom(json, Encoding.UTF8);
|
|
}
|
|
else if (typeof(byte[]) == data.GetType())
|
|
{
|
|
var _data = data as byte[];
|
|
param = ByteString.CopyFrom(_data);
|
|
}
|
|
}
|
|
WechatProto.BaseMsg msg = null;
|
|
if (param != null)
|
|
msg = new BaseMsg() { Cmd = cmd, Payloads = param, User = client.User.User };
|
|
else
|
|
msg = new BaseMsg() { Cmd = cmd, User = client.User.User };
|
|
if (longHead != null) msg.LongHead = longHead;
|
|
Req = new WechatMsg
|
|
{
|
|
Token = WXClientTool.machine_code,
|
|
Version = "7.0.3",
|
|
TimeStamp = Util.GetTimeTotalSeconds(),
|
|
IP = client.clientIp,
|
|
BaseMsg = msg
|
|
};
|
|
return Send(Req);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogHelper.GetSingleObj().Error("发送GRPC-" + cmd, ex.Message);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public byte[] GetResult(int seq)
|
|
{
|
|
var buffers = this.client.Socket.GetResult(seq);
|
|
var start = DateTime.Now;
|
|
while (buffers == null)
|
|
{
|
|
Thread.Sleep(20);
|
|
buffers = this.client.Socket.GetResult(seq);
|
|
if (null == buffers && (DateTime.Now - start).Seconds > 10)//发送文字超时时间设置成40s
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return buffers;
|
|
}
|
|
|
|
public byte[] SendWx(byte[] Data, int Seq = 0, int retry_number = 1, string text = "")
|
|
{
|
|
if (Seq == 0)
|
|
{
|
|
byte[] head = Data;
|
|
Seq = Util.ReadInt(head, 12);
|
|
}
|
|
//执行此方法无须解包 必须删除字典里的未解包
|
|
// this.client.Socket.SendToWeChat(Seq,Data).Result;
|
|
for (int i = 1; i <= retry_number; i++)
|
|
{
|
|
this.client.Socket.SendToWechat(Data, text);
|
|
//if (!string.IsNullOrEmpty(rst))
|
|
//{
|
|
// this.client.WriteLog("发送失败:" + rst);
|
|
// continue;
|
|
//}
|
|
var buffer = GetResult(Seq);
|
|
if (buffer != null) return buffer;
|
|
}
|
|
LogHelper.GetSingleObj().Error("SendWx", $"{(string.IsNullOrEmpty(this.client.WeixinHao) ? string.Empty : this.client.WeixinHao)}执行{Seq},数据包发送失败!");
|
|
return null;
|
|
|
|
|
|
//FastSocket 重构
|
|
//return client.Socket.SendToWeChat(Seq, Data);
|
|
|
|
|
|
// int number = 0;
|
|
//Next:
|
|
// try
|
|
// {
|
|
// number++;
|
|
// var source = new TaskCompletionSource<byte[]>();//
|
|
// byte[] data = null;
|
|
// var seq = Seq == 0 ? Req.BaseMsg.Cmd.ToString() : DateTime.Now.Ticks.ToString();
|
|
// var socket = client.Socket as FastSocket;
|
|
// var request = socket.WeChatClient.NewRequest(seq, Data, 5000 * 3,
|
|
// //绑定异常回调
|
|
// ex =>
|
|
// { //接收超时也会触发断开链接并且重连并自动清除队列
|
|
// //fClient.SocketNote.BeginInvoke(false, null, null);
|
|
// Console.WriteLine("WeChat Socket Error:" + ex.Message);
|
|
// source.TrySetException(ex);
|
|
// },
|
|
|
|
// //绑定返回请求的回调
|
|
// onResultMessage =>
|
|
// {
|
|
// //触发此回调必有数据
|
|
// //不触发则异常 发送收取超时等
|
|
// data = onResultMessage.Msg.BaseMsg.Payloads.ToByteArray();
|
|
// source.TrySetResult(data);
|
|
// }
|
|
// );
|
|
// socket.Send(request);
|
|
// var Body = source.Task.Result;
|
|
// //长链接解包判定
|
|
// if (Body != null && Body.Length > 16 && Body[16] != 191 && number <= 3)
|
|
// {
|
|
// //client.EventManage.OnEvent(this, QrcodeReq.BaseMsg.Cmd + ",非191,重试发包.."+number);
|
|
// goto Next;
|
|
// }
|
|
// return source.Task;
|
|
// }
|
|
|
|
// catch (Exception ex)
|
|
// {
|
|
// client.WriteLog("SendWx(byte[] Data, int Seq = 0) Error:" + ex.Message);
|
|
// throw ex;
|
|
// }
|
|
}
|
|
|
|
private PackMsg NextSendData;
|
|
public void SetNextData(PackMsg nextData)
|
|
{
|
|
this.NextSendData = nextData;
|
|
}
|
|
|
|
public void SendNextData()
|
|
{
|
|
try
|
|
{
|
|
this.SendAll(this.NextSendData.cmd, false, this.NextSendData.data);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|