Supercell.GUT/Supercell.GUT.Server/Network/Connection/ClientConnection.cs
BreadDEV 281d2789ea [v0.1.0] database implementation
not finished. early wip state
2024-03-06 22:00:12 +07:00

99 lines
2.9 KiB
C#

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<byte>(ReceiveBufferSize);
_lastKeepAliveTime = DateTime.Now;
}
public async Task RunAsync()
{
int receiveBufferIndex = 0;
Memory<byte> 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<int> ReceiveAsync(Memory<byte> buffer, int timeoutMs)
{
CancellationTokenSource cts = new(TimeSpan.FromMilliseconds(timeoutMs));
return await ProtocolEntity.ReceiveAsync(buffer, cts.Token);
}
private async ValueTask SendAsync(Memory<byte> buffer)
{
await ProtocolEntity.SendAsync(buffer, default);
}
public void SetNonce(string nonce)
{
_listener.InitEncryption(LogicVersion.GetKey(), nonce);
}
}