Reorganize solution structure.

This commit is contained in:
Christian Kratky
2018-06-11 00:00:30 +02:00
parent 6bcfa436ea
commit 20779dfece
163 changed files with 104 additions and 88 deletions
@@ -0,0 +1,108 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace MQTTnet.Internal
{
// Inspired from Stephen Toub (https://blogs.msdn.microsoft.com/pfxteam/2012/02/11/building-async-coordination-primitives-part-2-asyncautoresetevent/) and Chris Gillum (https://stackoverflow.com/a/43012490)
public class AsyncAutoResetEvent
{
private readonly LinkedList<TaskCompletionSource<bool>> _waiters = new LinkedList<TaskCompletionSource<bool>>();
private bool _isSignaled;
public AsyncAutoResetEvent() : this(false)
{ }
public AsyncAutoResetEvent(bool signaled)
{
_isSignaled = signaled;
}
public Task<bool> WaitOneAsync()
{
return WaitOneAsync(CancellationToken.None);
}
public Task<bool> WaitOneAsync(TimeSpan timeout)
{
return WaitOneAsync(timeout, CancellationToken.None);
}
public Task<bool> WaitOneAsync(CancellationToken cancellationToken)
{
return WaitOneAsync(Timeout.InfiniteTimeSpan, cancellationToken);
}
public async Task<bool> WaitOneAsync(TimeSpan timeout, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
TaskCompletionSource<bool> tcs;
lock (_waiters)
{
if (_isSignaled)
{
_isSignaled = false;
return true;
}
else if (timeout == TimeSpan.Zero)
{
return _isSignaled;
}
else
{
tcs = new TaskCompletionSource<bool>();
_waiters.AddLast(tcs);
}
}
Task winner = await Task.WhenAny(tcs.Task, Task.Delay(timeout, cancellationToken)).ConfigureAwait(false);
if (winner == tcs.Task)
{
// The task was signaled.
return true;
}
else
{
// We timed-out; remove our reference to the task.
// This is an O(n) operation since waiters is a LinkedList<T>.
lock (_waiters)
{
_waiters.Remove(tcs);
if (winner.Status == TaskStatus.Canceled)
{
throw new OperationCanceledException(cancellationToken);
}
else
{
throw new TimeoutException();
}
}
}
}
public void Set()
{
TaskCompletionSource<bool> toRelease = null;
lock (_waiters)
{
if (_waiters.Count > 0)
{
// Signal the first task in the waiters list.
toRelease = _waiters.First.Value;
_waiters.RemoveFirst();
}
else if (!_isSignaled)
{
// No tasks are pending
_isSignaled = true;
}
}
toRelease?.SetResult(true);
}
}
}
+48
View File
@@ -0,0 +1,48 @@
using System;
using System.Threading;
using System.Threading.Tasks;
namespace MQTTnet.Internal
{
// From Stephen Toub (https://blogs.msdn.microsoft.com/pfxteam/2012/02/12/building-async-coordination-primitives-part-6-asynclock/)
public class AsyncLock : IDisposable
{
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
private readonly Task<IDisposable> _releaser;
public AsyncLock()
{
_releaser = Task.FromResult((IDisposable)new Releaser(this));
}
public Task<IDisposable> LockAsync(CancellationToken cancellationToken)
{
Task wait = _semaphore.WaitAsync(cancellationToken);
return wait.IsCompleted ?
_releaser :
wait.ContinueWith((_, state) => (IDisposable)state,
_releaser.Result, cancellationToken,
TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
}
public void Dispose()
{
_semaphore?.Dispose();
}
private class Releaser : IDisposable
{
private readonly AsyncLock _toRelease;
internal Releaser(AsyncLock toRelease)
{
_toRelease = toRelease;
}
public void Dispose()
{
_toRelease._semaphore.Release();
}
}
}
}
@@ -0,0 +1,12 @@
using MQTTnet.Exceptions;
namespace MQTTnet.Internal
{
public static class ExceptionHelper
{
public static void ThrowGracefulSocketClose()
{
throw new MqttCommunicationException("Connection gracefully closed from the remote party.");
}
}
}
@@ -0,0 +1,35 @@
using MQTTnet.Packets;
namespace MQTTnet.Internal
{
public static class MqttApplicationMessageExtensions
{
public static MqttApplicationMessage ToApplicationMessage(this MqttPublishPacket publishPacket)
{
return new MqttApplicationMessage
{
Topic = publishPacket.Topic,
Payload = publishPacket.Payload,
QualityOfServiceLevel = publishPacket.QualityOfServiceLevel,
Retain = publishPacket.Retain
};
}
public static MqttPublishPacket ToPublishPacket(this MqttApplicationMessage applicationMessage)
{
if (applicationMessage == null)
{
return null;
}
return new MqttPublishPacket
{
Topic = applicationMessage.Topic,
Payload = applicationMessage.Payload,
QualityOfServiceLevel = applicationMessage.QualityOfServiceLevel,
Retain = applicationMessage.Retain,
Dup = false
};
}
}
}
+58
View File
@@ -0,0 +1,58 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Exceptions;
namespace MQTTnet.Internal
{
public static class TaskExtensions
{
public static async Task TimeoutAfter(Func<CancellationToken, Task> action, TimeSpan timeout, CancellationToken cancellationToken)
{
if (action == null) throw new ArgumentNullException(nameof(action));
using (var timeoutCts = new CancellationTokenSource(timeout))
using (var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(timeoutCts.Token, cancellationToken))
{
try
{
await action(linkedCts.Token).ConfigureAwait(false);
}
catch (OperationCanceledException exception)
{
var timeoutReached = timeoutCts.IsCancellationRequested && !cancellationToken.IsCancellationRequested;
if (timeoutReached)
{
throw new MqttCommunicationTimedOutException(exception);
}
throw;
}
}
}
public static async Task<TResult> TimeoutAfter<TResult>(Func<CancellationToken, Task<TResult>> action, TimeSpan timeout, CancellationToken cancellationToken)
{
if (action == null) throw new ArgumentNullException(nameof(action));
using (var timeoutCts = new CancellationTokenSource(timeout))
using (var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(timeoutCts.Token, cancellationToken))
{
try
{
return await action(linkedCts.Token).ConfigureAwait(false);
}
catch (OperationCanceledException exception)
{
var timeoutReached = timeoutCts.IsCancellationRequested && !cancellationToken.IsCancellationRequested;
if (timeoutReached)
{
throw new MqttCommunicationTimedOutException(exception);
}
throw;
}
}
}
}
}
@@ -0,0 +1,43 @@
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Channel;
namespace MQTTnet.Internal
{
public class TestMqttChannel : IMqttChannel
{
private readonly MemoryStream _stream;
public TestMqttChannel(MemoryStream stream)
{
_stream = stream;
}
public void Dispose()
{
}
public string Endpoint { get; }
public Task ConnectAsync(CancellationToken cancellationToken)
{
return Task.FromResult(0);
}
public Task DisconnectAsync()
{
return Task.FromResult(0);
}
public Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return _stream.ReadAsync(buffer, offset, count, cancellationToken);
}
public Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return _stream.WriteAsync(buffer, offset, count, cancellationToken);
}
}
}