mirror of
https://github.com/oliverbooth/TcpDotNet
synced 2024-11-09 23:45:41 +00:00
refactor!: use completion source for expected response
This commit changes the constraint on TReceive making it a breaking change!
This commit is contained in:
parent
0a9348fd66
commit
362c51cd09
@ -2,7 +2,6 @@ using System.Collections.Concurrent;
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.Serialization;
|
|
||||||
using Chilkat;
|
using Chilkat;
|
||||||
using TcpDotNet.Protocol;
|
using TcpDotNet.Protocol;
|
||||||
using Stream = System.IO.Stream;
|
using Stream = System.IO.Stream;
|
||||||
@ -16,6 +15,7 @@ namespace TcpDotNet;
|
|||||||
public abstract class ClientNode : Node
|
public abstract class ClientNode : Node
|
||||||
{
|
{
|
||||||
private readonly ConcurrentDictionary<int, List<TaskCompletionSource<Packet>>> _packetCompletionSources = new();
|
private readonly ConcurrentDictionary<int, List<TaskCompletionSource<Packet>>> _packetCompletionSources = new();
|
||||||
|
private readonly ConcurrentDictionary<long, TaskCompletionSource<ResponsePacket>> _callbackCompletionSources = new();
|
||||||
private EndPoint? _remoteEP;
|
private EndPoint? _remoteEP;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -231,38 +231,16 @@ public abstract class ClientNode : Node
|
|||||||
/// <exception cref="ArgumentNullException"><paramref name="packet" /> is <see langword="null" />.</exception>
|
/// <exception cref="ArgumentNullException"><paramref name="packet" /> is <see langword="null" />.</exception>
|
||||||
public async Task<TReceive> SendAndReceiveAsync<TReceive>(RequestPacket packet,
|
public async Task<TReceive> SendAndReceiveAsync<TReceive>(RequestPacket packet,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default)
|
||||||
where TReceive : Packet
|
where TReceive : ResponsePacket
|
||||||
{
|
{
|
||||||
if (packet is null) throw new ArgumentNullException(nameof(packet));
|
if (packet is null) throw new ArgumentNullException(nameof(packet));
|
||||||
|
|
||||||
var attribute = typeof(TReceive).GetCustomAttribute<PacketAttribute>();
|
var completionSource = new TaskCompletionSource<ResponsePacket>();
|
||||||
if (attribute is null)
|
if (!_callbackCompletionSources.TryAdd(packet.CallbackId, completionSource))
|
||||||
throw new ArgumentException($"The packet type {typeof(TReceive).Name} is not a valid packet.");
|
throw new InvalidOperationException("Duplicate packet sent");
|
||||||
|
|
||||||
var completionSource = new TaskCompletionSource<Packet>();
|
|
||||||
if (!_packetCompletionSources.TryGetValue(attribute.Id,
|
|
||||||
out List<TaskCompletionSource<Packet>>? completionSources))
|
|
||||||
{
|
|
||||||
completionSources = new List<TaskCompletionSource<Packet>>();
|
|
||||||
_packetCompletionSources.TryAdd(attribute.Id, completionSources);
|
|
||||||
}
|
|
||||||
|
|
||||||
lock (completionSources)
|
|
||||||
{
|
|
||||||
if (!completionSources.Contains(completionSource))
|
|
||||||
completionSources.Add(completionSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
await SendPacketAsync(packet, cancellationToken);
|
await SendPacketAsync(packet, cancellationToken);
|
||||||
TReceive response;
|
return (TReceive)await completionSource.Task;
|
||||||
do
|
|
||||||
{
|
|
||||||
response = await WaitForPacketAsync<TReceive>(completionSource, cancellationToken);
|
|
||||||
if (response is ResponsePacket responsePacket && responsePacket.CallbackId == packet.CallbackId)
|
|
||||||
break;
|
|
||||||
} while (true);
|
|
||||||
|
|
||||||
return response;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -281,10 +259,8 @@ public abstract class ClientNode : Node
|
|||||||
return WaitForPacketAsync<TPacket>(completionSource, cancellationToken);
|
return WaitForPacketAsync<TPacket>(completionSource, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<TPacket> WaitForPacketAsync<TPacket>(
|
private async Task<TPacket> WaitForPacketAsync<TPacket>(TaskCompletionSource<Packet> completionSource,
|
||||||
TaskCompletionSource<Packet> completionSource,
|
CancellationToken cancellationToken = default)
|
||||||
CancellationToken cancellationToken = default
|
|
||||||
)
|
|
||||||
where TPacket : Packet
|
where TPacket : Packet
|
||||||
{
|
{
|
||||||
var attribute = typeof(TPacket).GetCustomAttribute<PacketAttribute>();
|
var attribute = typeof(TPacket).GetCustomAttribute<PacketAttribute>();
|
||||||
|
@ -6,14 +6,16 @@ namespace TcpDotNet.Protocol.Packets.ClientBound;
|
|||||||
/// Represents a packet which responds to a <see cref="HandshakeRequestPacket" />.
|
/// Represents a packet which responds to a <see cref="HandshakeRequestPacket" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Packet(0x7FFFFFE1)]
|
[Packet(0x7FFFFFE1)]
|
||||||
internal sealed class HandshakeResponsePacket : Packet
|
internal sealed class HandshakeResponsePacket : ResponsePacket
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="HandshakeResponsePacket" /> class.
|
/// Initializes a new instance of the <see cref="HandshakeResponsePacket" /> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="callbackId">The callback ID.</param>
|
||||||
/// <param name="protocolVersion">The requested protocol version.</param>
|
/// <param name="protocolVersion">The requested protocol version.</param>
|
||||||
/// <param name="handshakeResponse">The handshake response.</param>
|
/// <param name="handshakeResponse">The handshake response.</param>
|
||||||
public HandshakeResponsePacket(int protocolVersion, HandshakeResponse handshakeResponse)
|
public HandshakeResponsePacket(long callbackId, int protocolVersion, HandshakeResponse handshakeResponse)
|
||||||
|
: base(callbackId)
|
||||||
{
|
{
|
||||||
ProtocolVersion = protocolVersion;
|
ProtocolVersion = protocolVersion;
|
||||||
HandshakeResponse = handshakeResponse;
|
HandshakeResponse = handshakeResponse;
|
||||||
|
Loading…
Reference in New Issue
Block a user