initial commit
This commit is contained in:
@@ -0,0 +1,280 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user