diff --git a/src/Discord.Net.Commands/CommandService.cs b/src/Discord.Net.Commands/CommandService.cs
index c21bd2356..bf1785565 100644
--- a/src/Discord.Net.Commands/CommandService.cs
+++ b/src/Discord.Net.Commands/CommandService.cs
@@ -51,14 +51,14 @@ namespace Discord.Commands
.Description("Returns information about commands.")
.Do(async e =>
{
- Channel replyChannel = _config.HelpMode == HelpMode.Public ? e.Channel : await e.User.CreateChannel();
+ Channel replyChannel = _config.HelpMode == HelpMode.Public ? e.Channel : await e.User.CreateChannel().ConfigureAwait(false);
if (e.Args.Length > 0) //Show command help
{
var map = _map.GetItem(string.Join(" ", e.Args));
if (map != null)
- await ShowCommandHelp(map, e.User, e.Channel, replyChannel);
+ await ShowCommandHelp(map, e.User, e.Channel, replyChannel).ConfigureAwait(false);
else
- await replyChannel.SendMessage("Unable to display help: Unknown command.");
+ await replyChannel.SendMessage("Unable to display help: Unknown command.").ConfigureAwait(false);
}
else //Show general help
await ShowGeneralHelp(e.User, e.Channel, replyChannel);
diff --git a/src/Discord.Net.Net45/Discord.Net.csproj b/src/Discord.Net.Net45/Discord.Net.csproj
index 3ec6c67e1..21bdc5dd4 100644
--- a/src/Discord.Net.Net45/Discord.Net.csproj
+++ b/src/Discord.Net.Net45/Discord.Net.csproj
@@ -509,6 +509,9 @@
Net\TimeoutException.cs
+
+ Net\WebSockets\WebSocketException.cs
+
Net\WebSockets\GatewaySocket.cs
diff --git a/src/Discord.Net/API/Client/GatewaySocket/OpCodes.cs b/src/Discord.Net/API/Client/GatewaySocket/OpCodes.cs
index 9942c670e..3a62aa86d 100644
--- a/src/Discord.Net/API/Client/GatewaySocket/OpCodes.cs
+++ b/src/Discord.Net/API/Client/GatewaySocket/OpCodes.cs
@@ -19,6 +19,6 @@
/// C←S - Used to notify a client that they must reconnect to another gateway.
Redirect = 7,
/// C→S - Used to request all members that were withheld by large_threshold
- RequestGuildMembers = 8
+ RequestGuildMembers = 99
}
}
diff --git a/src/Discord.Net/DiscordClient.Obsolete.cs b/src/Discord.Net/DiscordClient.Obsolete.cs
index 153253d40..0c2f77255 100644
--- a/src/Discord.Net/DiscordClient.Obsolete.cs
+++ b/src/Discord.Net/DiscordClient.Obsolete.cs
@@ -159,7 +159,7 @@ namespace Discord.Legacy
if (messages == null) throw new ArgumentNullException(nameof(messages));
foreach (var message in messages)
- await message.Delete();
+ await message.Delete().ConfigureAwait(false);
}
[Obsolete("Use Channel.DownloadMessages")]
diff --git a/src/Discord.Net/DiscordClient.cs b/src/Discord.Net/DiscordClient.cs
index dac7bcfa9..6063b2271 100644
--- a/src/Discord.Net/DiscordClient.cs
+++ b/src/Discord.Net/DiscordClient.cs
@@ -128,7 +128,7 @@ namespace Discord
Connected += async (s, e) =>
{
ClientAPI.CancelToken = CancelToken;
- await SendStatus();
+ await SendStatus().ConfigureAwait(false);
};
//Extensibility
@@ -250,7 +250,7 @@ namespace Discord
}
//Cache other stuff
- var regionsResponse = (await ClientAPI.Send(new GetVoiceRegionsRequest()));
+ var regionsResponse = (await ClientAPI.Send(new GetVoiceRegionsRequest()).ConfigureAwait(false));
_regions = regionsResponse.Select(x => new Region(x.Id, x.Name, x.Hostname, x.Port))
.ToDictionary(x => x.Id);
break;
diff --git a/src/Discord.Net/Models/Channel.cs b/src/Discord.Net/Models/Channel.cs
index c178beec2..8bcc307c8 100644
--- a/src/Discord.Net/Models/Channel.cs
+++ b/src/Discord.Net/Models/Channel.cs
@@ -213,7 +213,7 @@ namespace Discord
#region Invites
/// Gets all active (non-expired) invites to this server.
public async Task> GetInvites()
- => (await Server.GetInvites()).Where(x => x.Channel.Id == Id);
+ => (await Server.GetInvites().ConfigureAwait(false)).Where(x => x.Channel.Id == Id);
/// Creates a new invite to this channel.
/// Time (in seconds) until the invite expires. Set to null to never expire.
diff --git a/src/Discord.Net/Net/WebSocketException.cs b/src/Discord.Net/Net/WebSocketException.cs
new file mode 100644
index 000000000..b845d90c4
--- /dev/null
+++ b/src/Discord.Net/Net/WebSocketException.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Discord.Net
+{
+ public class WebSocketException : Exception
+ {
+ public int Code { get; }
+ public string Reason { get; }
+
+ public WebSocketException(int code, string reason)
+ : base(GenerateMessage(code, reason))
+ {
+ Code = code;
+ Reason = reason;
+ }
+
+ private static string GenerateMessage(int? code, string reason)
+ {
+ if (!String.IsNullOrEmpty(reason))
+ return $"Received close code {code}: {reason}";
+ else
+ return $"Received close code {code}";
+ }
+ }
+}
diff --git a/src/Discord.Net/Net/WebSockets/GatewaySocket.cs b/src/Discord.Net/Net/WebSockets/GatewaySocket.cs
index 14da0fc10..b227c550e 100644
--- a/src/Discord.Net/Net/WebSockets/GatewaySocket.cs
+++ b/src/Discord.Net/Net/WebSockets/GatewaySocket.cs
@@ -13,8 +13,10 @@ namespace Discord.Net.WebSockets
{
private int _lastSequence;
private string _sessionId;
+ private string _token;
+ private int _reconnects;
- public string Token { get; internal set; }
+ public string Token { get { return _token; } internal set { _token = value; _sessionId = null; } }
public GatewaySocket(DiscordClient client, JsonSerializer serializer, Logger logger)
: base(client, serializer, logger)
@@ -29,20 +31,21 @@ namespace Discord.Net.WebSockets
public async Task Connect()
{
await BeginConnect().ConfigureAwait(false);
- SendIdentify(Token);
+ if (_sessionId == null)
+ SendIdentify(Token);
+ else
+ SendResume();
}
- private async Task Redirect()
- {
- await BeginConnect().ConfigureAwait(false);
- SendResume();
- }
private async Task Reconnect()
{
try
{
var cancelToken = ParentCancelToken.Value;
- await Task.Delay(_client.Config.ReconnectDelay, cancelToken).ConfigureAwait(false);
- while (!cancelToken.IsCancellationRequested)
+ if (_reconnects++ == 0)
+ await Task.Delay(_client.Config.ReconnectDelay, cancelToken).ConfigureAwait(false);
+ else
+ await Task.Delay(_client.Config.FailedReconnectDelay, cancelToken).ConfigureAwait(false);
+ while (!cancelToken.IsCancellationRequested)
{
try
{
@@ -69,8 +72,15 @@ namespace Discord.Net.WebSockets
tasks.Add(HeartbeatAsync(CancelToken));
await _taskManager.Start(tasks, _cancelTokenSource).ConfigureAwait(false);
}
+ protected override Task Cleanup()
+ {
+ var ex = _taskManager.Exception;
+ if (ex != null && (ex as WebSocketException)?.Code != 1012)
+ _sessionId = null; //Reset session unless close code 1012
+ return base.Cleanup();
+ }
- protected override async Task ProcessMessage(string json)
+ protected override async Task ProcessMessage(string json)
{
await base.ProcessMessage(json).ConfigureAwait(false);
var msg = JsonConvert.DeserializeObject(json);
@@ -85,9 +95,10 @@ namespace Discord.Net.WebSockets
JToken token = msg.Payload as JToken;
if (msg.Type == "READY")
{
- var payload = token.ToObject(_serializer);
+ _reconnects = 0;
+ var payload = token.ToObject(_serializer);
_sessionId = payload.SessionId;
- _heartbeatInterval = payload.HeartbeatInterval;
+ _heartbeatInterval = payload.HeartbeatInterval;
}
else if (msg.Type == "RESUMED")
{
@@ -106,7 +117,7 @@ namespace Discord.Net.WebSockets
{
Host = payload.Url;
Logger.Info("Redirected to " + payload.Url);
- await Redirect().ConfigureAwait(false);
+ await Reconnect().ConfigureAwait(false);
}
}
break;
diff --git a/src/Discord.Net/Net/WebSockets/WS4NetEngine.cs b/src/Discord.Net/Net/WebSockets/WS4NetEngine.cs
index 54261493a..5c1372d95 100644
--- a/src/Discord.Net/Net/WebSockets/WS4NetEngine.cs
+++ b/src/Discord.Net/Net/WebSockets/WS4NetEngine.cs
@@ -83,13 +83,7 @@ namespace Discord.Net.WebSockets
{
Exception ex;
if (e is ClosedEventArgs)
- {
- int code = (e as ClosedEventArgs).Code;
- string reason = (e as ClosedEventArgs).Reason;
- if (String.IsNullOrEmpty(reason))
- reason = "No reason";
- ex = new Exception($"Received close code {code}: {reason}");
- }
+ ex = new WebSocketException((e as ClosedEventArgs).Code, (e as ClosedEventArgs).Reason);
else
ex = new Exception($"Connection lost");
_taskManager.SignalError(ex, isUnexpected: true);
diff --git a/src/Discord.Net/Net/WebSockets/WebSocket.cs b/src/Discord.Net/Net/WebSockets/WebSocket.cs
index 49e630c75..006c0d180 100644
--- a/src/Discord.Net/Net/WebSockets/WebSocket.cs
+++ b/src/Discord.Net/Net/WebSockets/WebSocket.cs
@@ -125,7 +125,7 @@ namespace Discord.Net.WebSockets
_cancelTokenSource = null;
_connectedEvent.Reset();
- if (oldState == ConnectionState.Connected)
+ if (oldState == ConnectionState.Connecting || oldState == ConnectionState.Connected)
{
var ex = _taskManager.Exception;
if (ex == null)