private async Task <TResponsePacket> SendAndReceiveAsync <TResponsePacket>(Packet packet, CancellationToken cancellationToken) where TResponsePacket : Packet { cancellationToken.ThrowIfCancellationRequested(); ushort identifier = 0; if (packet is PacketWithId packetWithId) { identifier = packetWithId.PacketId; } var awaiter = _packetDispatcher.AddPacketAwaiter <TResponsePacket>(identifier); try { await SendAsync(packet); using (var timeoutCts = new CancellationTokenSource(_options.Timeout)) using (var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCts.Token)) { linkedCts.Token.Register(() => { if (!awaiter.Task.IsCompleted && !awaiter.Task.IsFaulted && !awaiter.Task.IsCanceled) { awaiter.TrySetCanceled(); } }); try { var result = await awaiter.Task.ConfigureAwait(false); timeoutCts.Cancel(false); return((TResponsePacket)result); } catch (OperationCanceledException exception) { if (timeoutCts.IsCancellationRequested && !cancellationToken.IsCancellationRequested) { throw new MqttTimeoutException(exception); } else { throw; } } } } catch (Exception ex) { throw new MqttException(ex.Message, ex); } finally { _packetDispatcher.RemovePacketAwaiter <TResponsePacket>(identifier); } }
private async Task <TPacket> SendAndReceiveAsync <TPacket>(Packet packet, CancellationToken cancellationToken = default) where TPacket : Packet { cancellationToken.ThrowIfCancellationRequested(); ushort identifier = 0; if (packet is PacketWithId packetWithId) { identifier = packetWithId.PacketId; } var awaiter = _packetDispatcher.AddPacketAwaiter <TPacket>(identifier); await channel.WriteAndFlushAsync(packet); using var timeoutCts = new CancellationTokenSource(Options.Timeout); using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCts.Token); linkedCts.Token.Register(() => { if (!awaiter.Task.IsCompleted && !awaiter.Task.IsFaulted && !awaiter.Task.IsCanceled) { awaiter.TrySetCanceled(); } }); try { var result = await awaiter.Task.ConfigureAwait(false); timeoutCts.Cancel(false); return((TPacket)result); } catch (OperationCanceledException ex) { _logger.LogError(ex, ex.Message); _packetDispatcher.RemovePacketAwaiter <TPacket>(identifier); if (timeoutCts.IsCancellationRequested && !cancellationToken.IsCancellationRequested) { throw new MqttTimeoutException(ex); } else { throw; } } }