using Supercell.GUT.Logic; using Supercell.GUT.Logic.Avatar; using Supercell.GUT.Server.Protocol; using Supercell.GUT.Titan.Logic.Message; namespace Supercell.GUT.Server.Network.Connection; internal class ClientConnection { private const int ReceiveBufferSize = 16384; private const int ReceiveTimeoutMs = 30000; private readonly IConnectionListener _listener; private readonly MessageManager _messageManager; public LogicClientAvatar? LogicClientAvatar { get; set; } private readonly byte[] _receiveBuffer; private IProtocolEntity? _protocolEntity; private DateTime _lastKeepAliveTime; public bool IsAlive => (DateTime.Now - _lastKeepAliveTime).TotalSeconds < 30.0f; public ClientConnection(IConnectionListener listener, MessageManager messageManager) { _listener = listener; _listener.OnSend = SendAsync; _listener.RecvCallback = OnMessage; _messageManager = messageManager; _receiveBuffer = GC.AllocateUninitializedArray(ReceiveBufferSize); _lastKeepAliveTime = DateTime.Now; } public async Task RunAsync() { int receiveBufferIndex = 0; Memory receiveBufferMem = _receiveBuffer.AsMemory(); while (true) { int readAmount = await ReceiveAsync(receiveBufferMem[receiveBufferIndex..], ReceiveTimeoutMs); if (readAmount == 0) break; receiveBufferIndex += readAmount; int consumedBytes = await _listener.OnReceive(receiveBufferMem, receiveBufferIndex); if (consumedBytes > 0) { Buffer.BlockCopy(_receiveBuffer, consumedBytes, _receiveBuffer, 0, receiveBufferIndex -= consumedBytes); } else if (consumedBytes < 0) break; } } public async Task SendMessage(PiranhaMessage message) { await _listener.Send(message); } public void RefreshKeepAliveTime() { _lastKeepAliveTime = DateTime.Now; } public void SetProtocolEntity(IProtocolEntity protocolEntity) { _protocolEntity = protocolEntity; } public IProtocolEntity ProtocolEntity { get { return _protocolEntity ?? throw new InvalidOperationException("Trying to access _protocolEntity when it's NULL!"); } } private async Task OnMessage(PiranhaMessage message) { await _messageManager.ReceiveMessage(message); } private async ValueTask ReceiveAsync(Memory buffer, int timeoutMs) { CancellationTokenSource cts = new(TimeSpan.FromMilliseconds(timeoutMs)); return await ProtocolEntity.ReceiveAsync(buffer, cts.Token); } private async ValueTask SendAsync(Memory buffer) { await ProtocolEntity.SendAsync(buffer, default); } public void SetNonce(string nonce) { _listener.InitEncryption(LogicVersion.GetKey(), nonce); } }