@@ -10,36 +10,36 @@ using System.Threading.Tasks;
namespace Discord.Net.WebSockets
{
public abstract partial class WebSocket
public abstract partial class WebSocket
{
private readonly AsyncLock _lock;
protected readonly IWebSocketEngine _engine;
protected readonly DiscordConfig _config;
protected readonly ManualResetEventSlim _connectedEvent;
protected readonly DiscordConfig _config;
protected readonly ManualResetEventSlim _connectedEvent;
protected readonly TaskManager _taskManager;
protected readonly JsonSerializer _serializer;
protected CancellationTokenSource _cancelSource;
protected CancellationToken _parentCancelToken;
protected int _heartbeatInterval;
private DateTime _lastHeartbeat;
private DateTime _lastHeartbeat;
/// <summary> Gets the logger used for this client. </summary>
protected internal Logger Logger { get; }
public CancellationToken CancelToken { get; private set; }
public string Host { get; set; }
public string Host { get; set; }
/// <summary> Gets the current connection state of this client. </summary>
public ConnectionState State { get; private set; }
public event EventHandler Connected = delegate { };
private void OnConnected()
=> Connected(this, EventArgs.Empty);
private void OnConnected()
=> Connected(this, EventArgs.Empty);
public event EventHandler<DisconnectedEventArgs> Disconnected = delegate { };
private void OnDisconnected(bool wasUnexpected, Exception error)
private void OnDisconnected(bool wasUnexpected, Exception error)
=> Disconnected(this, new DisconnectedEventArgs(wasUnexpected, error));
public WebSocket(DiscordConfig config, JsonSerializer serializer, Logger logger)
{
public WebSocket(DiscordConfig config, JsonSerializer serializer, Logger logger)
{
_config = config;
_serializer = serializer;
Logger = logger;
@@ -47,30 +47,30 @@ namespace Discord.Net.WebSockets
_lock = new AsyncLock();
_taskManager = new TaskManager(Cleanup);
CancelToken = new CancellationToken(true);
_connectedEvent = new ManualResetEventSlim(false);
_connectedEvent = new ManualResetEventSlim(false);
#if !DOTNET5_4
_engine = new WS4NetEngine(config, _taskManager);
_engine = new WS4NetEngine(config, _taskManager);
#else
_engine = new BuiltInEngine(config);
#endif
_engine.BinaryMessage += (s, e) =>
{
using (var compressed = new MemoryStream(e.Data, 2, e.Data.Length - 2))
using (var decompressed = new MemoryStream())
{
using (var zlib = new DeflateStream(compressed, CompressionMode.Decompress))
zlib.CopyTo(decompressed);
decompressed.Position = 0;
using (var compressed = new MemoryStream(e.Data, 2, e.Data.Length - 2))
using (var decompressed = new MemoryStream())
{
using (var zlib = new DeflateStream(compressed, CompressionMode.Decompress))
zlib.CopyTo(decompressed);
decompressed.Position = 0;
using (var reader = new StreamReader(decompressed))
ProcessMessage(reader.ReadToEnd()).GetAwaiter().GetResult();
}
ProcessMessage(reader.ReadToEnd()).GetAwaiter().GetResult();
}
};
_engine.TextMessage += (s, e) => ProcessMessage(e.Message).Wait();
}
_engine.TextMessage += (s, e) => ProcessMessage(e.Message).Wait();
}
protected async Task BeginConnect(CancellationToken parentCancelToken)
{
protected async Task BeginConnect(CancellationToken parentCancelToken)
{
try
{
using (await _lock.LockAsync().ConfigureAwait(false))
@@ -80,7 +80,7 @@ namespace Discord.Net.WebSockets
await _taskManager.Stop().ConfigureAwait(false);
_taskManager.ClearException();
State = ConnectionState.Connecting;
_cancelSource = new CancellationTokenSource();
CancelToken = CancellationTokenSource.CreateLinkedTokenSource(_cancelSource.Token, parentCancelToken).Token;
_lastHeartbeat = DateTime.UtcNow;
@@ -88,39 +88,39 @@ namespace Discord.Net.WebSockets
await _engine.Connect(Host, CancelToken).ConfigureAwait(false);
await Run().ConfigureAwait(false);
}
}
catch (Exception ex)
{
}
catch (Exception ex)
{
//TODO: Should this be inside the lock?
await _taskManager.SignalError(ex).ConfigureAwait(false);
throw;
}
}
protected async Task EndConnect()
{
try
}
}
protected async Task EndConnect()
{
try
{
State = ConnectionState.Connected;
Logger.Info($"Connected");
OnConnected();
_connectedEvent.Set();
}
catch (Exception ex)
}
catch (Exception ex)
{
await _taskManager.SignalError(ex).ConfigureAwait(false);
}
}
}
protected abstract Task Run();
protected virtual async Task Cleanup()
{
protected abstract Task Run();
protected virtual async Task Cleanup()
{
var oldState = State;
State = ConnectionState.Disconnecting;
await _engine.Disconnect().ConfigureAwait(false);
_cancelSource = null;
_connectedEvent.Reset();
_cancelSource = null;
_connectedEvent.Reset();
if (oldState == ConnectionState.Connecting || oldState == ConnectionState.Connected)
{
@@ -136,35 +136,35 @@ namespace Discord.Net.WebSockets
State = ConnectionState.Disconnected;
}
protected virtual Task ProcessMessage(string json)
{
return TaskHelper.CompletedTask;
}
protected void QueueMessage(IWebSocketMessage message)
{
string json = JsonConvert.SerializeObject(new WebSocketMessage(message));
_engine.QueueMessage(json);
}
protected Task HeartbeatAsync(CancellationToken cancelToken)
{
return Task.Run(async () =>
{
try
{
while (!cancelToken.IsCancellationRequested)
{
if (this.State == ConnectionState.Connected && _heartbeatInterval > 0)
{
protected virtual Task ProcessMessage(string json)
{
return TaskHelper.CompletedTask;
}
protected void QueueMessage(IWebSocketMessage message)
{
string json = JsonConvert.SerializeObject(new WebSocketMessage(message));
_engine.QueueMessage(json);
}
protected Task HeartbeatAsync(CancellationToken cancelToken)
{
return Task.Run(async () =>
{
try
{
while (!cancelToken.IsCancellationRequested)
{
if (this.State == ConnectionState.Connected && _heartbeatInterval > 0)
{
SendHeartbeat();
await Task.Delay(_heartbeatInterval, cancelToken).ConfigureAwait(false);
}
else
await Task.Delay(1000, cancelToken).ConfigureAwait(false);
}
}
catch (OperationCanceledException) { }
});
await Task.Delay(_heartbeatInterval, cancelToken).ConfigureAwait(false);
}
else
await Task.Delay(1000, cancelToken).ConfigureAwait(false);
}
}
catch (OperationCanceledException) { }
});
}
public abstract void SendHeartbeat();
@@ -184,5 +184,5 @@ namespace Discord.Net.WebSockets
throw;
}
}
}
}
}