using System;
using XGame.Framework.Interfaces;
namespace XGame.Framework.Network
{
internal class MsgSender : IMsgSender, IReset
{
private ISessionContext _context;
private int seqID = -1;
///
/// 消息间隔,默认3秒
///
private const int _interval = 3000;
private long _lastTime = 0;
private int _lastID = -1;
public MsgSender(ISessionContext context)
{
_context = context;
}
public bool IsCanSend(IMessage message, bool useFilter)
{
if (useFilter)
{
var nowTime = _context.Time.GetNowTime();
if (_lastTime == 0 || nowTime - _lastTime > _interval)
{ // 没记录时间 或 已经超时, 刷新时间
_lastTime = nowTime;
}
else
{
return false;
}
}
message.InstanceID = ++seqID;
if (useFilter)
{
_lastID = message.InstanceID;
}
return true;
}
//|<- Head ->|<- Body ->|
//| magic | type | compress | encryption |0000| seqID | protoId| msglength| msg |
//| 1byte | 2bit | 1bit | 1bit |4bit| 4byte | 4byte | 2byte | Nbyte |
//| 0 | 1 | 2 3 4 5 | 6789 | 10 11 | |
public ESessionCode Send(IMessage message, bool openEncrypt)
{
_context.Serializer.Write(message, out var bytes, out var msgOffset, out var msgLength);
//magic
bytes[0] = NetDefine.MAGIC;
//type compress
int type = (int)MsgType.REQUEST << 6;
bool isCompress = (msgLength + NetDefine.HEAD_LENGTH_REQUEST) > NetDefine.CompressThreshold;
int compress = (isCompress ? 1 : 0) << 5;
int encryption = (openEncrypt ? 1 : 0) << 4;
bytes[1] = Convert.ToByte((compress + type + encryption) & 0xFF);
//seqID
bytes[2] = Convert.ToByte(message.InstanceID >> 24 & 0xFF);
bytes[3] = Convert.ToByte(message.InstanceID >> 16 & 0xFF);
bytes[4] = Convert.ToByte(message.InstanceID >> 8 & 0xFF);
bytes[5] = Convert.ToByte(message.InstanceID & 0xFF);
//protoID
bytes[6] = Convert.ToByte(message.ProtocolID >> 24 & 0xFF);
bytes[7] = Convert.ToByte(message.ProtocolID >> 16 & 0xFF);
bytes[8] = Convert.ToByte(message.ProtocolID >> 8 & 0xFF);
bytes[9] = Convert.ToByte(message.ProtocolID & 0xFF);
if (isCompress)
{
_context.Compressor.Compress(ref bytes, ref msgOffset, ref msgLength);
}
if (openEncrypt)//rc4的话 用新数组进行保存
{
_context.Encryptor.Encrypt(ref bytes, ref msgOffset, ref msgLength);
}
//msglengh
bytes[10] = Convert.ToByte(msgLength >> 8 & 0xFF);
bytes[11] = Convert.ToByte(msgLength & 0xFF);
NetLog.LogHexString($"发送消息", bytes, 0, msgLength + NetDefine.HEAD_LENGTH_REQUEST);
var result = _context.Session.Send(bytes, 0, msgLength + NetDefine.HEAD_LENGTH_REQUEST);
return result ? ESessionCode.None : ESessionCode.SendFailed;
}
public void Reset()
{
seqID = -1;
_lastID = -1;
_lastTime = 0;
}
public bool VerifyInstanceID(int instanceID)
{
if (_lastID == instanceID)
{
_lastTime = 0;
return true;
}
return false;
}
//private bool CanSendMsg(IMessage msg)
//{
// if (!_sessionNode.MsgContext.CanSend)//false request 和 response 没有对应
// {
// Log.Debug(string.Format("[Session Send Filter] <{0}> {1} lastSeq: {2} \n消息发送过快,上条消息尚未回复导致消息被过滤,请重发或使用INetModule.Send(string sessionType, IMessage msg, bool isFilter),isFilter设置为false\n{3}", msg.ProtocolID, msg.GetType().Name, _sessionNode.MsgContext.LastID, XJson.ToJson(msg)));
// var args = ObjectPool.Acquire();
// args.Message = msg;
// _sessionNode.Notify(EventDefine.SESSION_MSG_FILTER, args);
// ObjectPool.Recycle(args);
// return false;
// }
// _sessionNode.MsgContext.CanSend = false;
// //计时开始
// _timer?.Cancel();
// _timer = _timeModule.AddDelayTimer(_interval, Timeout);
// return true;
//}
//private void DebugMessage(IMessage message)
//{
// if (_sessionNode.bDebug)
// {
// Log.Info("[Session] Send <{1}> {2}: Seq:{4} Timestamp:{0}\n{3}",
// _timeModule.GetNowTime(ClockType.Client), message.ProtocolID, message.GetType().Name, XJson.ToJson(message), message.InstanceID);
// }
//}
//private void SendFail(IMessage message)
//{
// var args = ObjectPool.Acquire();
// args.message = message;
// if (_sessionNode.bDebug)
// {
// Log.Error("[Session Send Fail] Send <{1}> {2}: Timestamp:{0}\n{3}",
// _timeModule.GetNowTime(ClockType.Client), message.ProtocolID, message.GetType().Name, XJson.ToJson(message));
// }
// _sessionNode.Notify(EventDefine.SESSION_CANT_SEND, args);
// ObjectPool.Recycle(args);
//}
//private void SendEvent(IMessage msg, bool isFilter)
//{
// var args = ObjectPool.Acquire();
// args.protocolID = msg.ProtocolID;
// args.context = msg.Context;
// args.IsFilter = isFilter;
// args.RequestMsg = msg;
// args.seq = msg.InstanceID;
// _sessionNode.Notify(EventDefine.SESSION_REQUEST_SENT, args);
// ObjectPool.Recycle(args);
//}
}
}