Don't capture the UI thread for async methods. Use Task.Run instead of Task.Factory.StartNew.
This commit is contained in:
@@ -21,15 +21,15 @@ namespace Discord.API
|
||||
=> _http.Get<APIResponses.Gateway>(Endpoints.Gateway);
|
||||
public async Task<APIResponses.AuthRegister> LoginAnonymous(string username)
|
||||
{
|
||||
var fingerprintResponse = await _http.Post<APIResponses.AuthFingerprint>(Endpoints.AuthFingerprint);
|
||||
var fingerprintResponse = await _http.Post<APIResponses.AuthFingerprint>(Endpoints.AuthFingerprint).ConfigureAwait(false);
|
||||
var registerRequest = new APIRequests.AuthRegisterRequest { Fingerprint = fingerprintResponse.Fingerprint, Username = username };
|
||||
var registerResponse = await _http.Post<APIResponses.AuthRegister>(Endpoints.AuthRegister, registerRequest);
|
||||
var registerResponse = await _http.Post<APIResponses.AuthRegister>(Endpoints.AuthRegister, registerRequest).ConfigureAwait(false);
|
||||
return registerResponse;
|
||||
}
|
||||
public async Task<APIResponses.AuthLogin> Login(string email, string password)
|
||||
{
|
||||
var request = new APIRequests.AuthLogin { Email = email, Password = password };
|
||||
var response = await _http.Post<APIResponses.AuthLogin>(Endpoints.AuthLogin, request);
|
||||
var response = await _http.Post<APIResponses.AuthLogin>(Endpoints.AuthLogin, request).ConfigureAwait(false);
|
||||
return response;
|
||||
}
|
||||
public Task Logout()
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Discord
|
||||
if (name == null) throw new ArgumentNullException(nameof(name));
|
||||
if (region == null) throw new ArgumentNullException(nameof(region));
|
||||
|
||||
var response = await _api.CreateServer(name, region);
|
||||
var response = await _api.CreateServer(name, region).ConfigureAwait(false);
|
||||
return _servers.Update(response.Id, response);
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace Discord
|
||||
CheckReady();
|
||||
if (serverId == null) throw new ArgumentNullException(nameof(serverId));
|
||||
|
||||
try { await _api.LeaveServer(serverId); }
|
||||
try { await _api.LeaveServer(serverId).ConfigureAwait(false); }
|
||||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { }
|
||||
return _servers.Remove(serverId);
|
||||
}
|
||||
@@ -54,7 +54,7 @@ namespace Discord
|
||||
if (name == null) throw new ArgumentNullException(nameof(name));
|
||||
if (type == null) throw new ArgumentNullException(nameof(type));
|
||||
|
||||
var response = await _api.CreateChannel(serverId, name, type);
|
||||
var response = await _api.CreateChannel(serverId, name, type).ConfigureAwait(false);
|
||||
return _channels.Update(response.Id, serverId, response);
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace Discord
|
||||
CheckReady();
|
||||
if (channelId == null) throw new ArgumentNullException(nameof(channelId));
|
||||
|
||||
try { await _api.DestroyChannel(channelId); }
|
||||
try { await _api.DestroyChannel(channelId).ConfigureAwait(false); }
|
||||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { }
|
||||
return _channels.Remove(channelId);
|
||||
}
|
||||
@@ -108,7 +108,7 @@ namespace Discord
|
||||
if (serverId == null) throw new ArgumentNullException(nameof(serverId));
|
||||
if (userId == null) throw new ArgumentNullException(nameof(userId));
|
||||
|
||||
try { await _api.Unban(serverId, userId); }
|
||||
try { await _api.Unban(serverId, userId).ConfigureAwait(false); }
|
||||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { }
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ namespace Discord
|
||||
if (maxAge <= 0) throw new ArgumentOutOfRangeException(nameof(maxAge));
|
||||
if (maxUses <= 0) throw new ArgumentOutOfRangeException(nameof(maxUses));
|
||||
|
||||
var response = await _api.CreateInvite(channelId, maxAge, maxUses, isTemporary, hasXkcdPass);
|
||||
var response = await _api.CreateInvite(channelId, maxAge, maxUses, isTemporary, hasXkcdPass).ConfigureAwait(false);
|
||||
_channels.Update(response.Channel.Id, response.Server.Id, response.Channel);
|
||||
_servers.Update(response.Server.Id, response.Server);
|
||||
_users.Update(response.Inviter.Id, response.Inviter);
|
||||
@@ -163,7 +163,7 @@ namespace Discord
|
||||
CheckReady();
|
||||
if (id == null) throw new ArgumentNullException(nameof(id));
|
||||
|
||||
var response = await _api.GetInvite(id);
|
||||
var response = await _api.GetInvite(id).ConfigureAwait(false);
|
||||
return new Invite(response.Code, response.XkcdPass, this)
|
||||
{
|
||||
ChannelId = response.Channel.Id,
|
||||
@@ -195,8 +195,8 @@ namespace Discord
|
||||
id = id.Substring(0, id.Length - 1);
|
||||
|
||||
//Check if this is a human-readable link and get its ID
|
||||
var response = await _api.GetInvite(id);
|
||||
await _api.AcceptInvite(response.Code);
|
||||
var response = await _api.GetInvite(id).ConfigureAwait(false);
|
||||
await _api.AcceptInvite(response.Code).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary> Deletes the provided invite. </summary>
|
||||
@@ -208,8 +208,8 @@ namespace Discord
|
||||
try
|
||||
{
|
||||
//Check if this is a human-readable link and get its ID
|
||||
var response = await _api.GetInvite(id);
|
||||
await _api.DeleteInvite(response.Code);
|
||||
var response = await _api.GetInvite(id).ConfigureAwait(false);
|
||||
await _api.DeleteInvite(response.Code).ConfigureAwait(false);
|
||||
}
|
||||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { }
|
||||
}
|
||||
@@ -257,31 +257,28 @@ namespace Discord
|
||||
}
|
||||
else
|
||||
{
|
||||
var msg = await _api.SendMessage(channelId, blockText, mentions, nonce);
|
||||
var msg = await _api.SendMessage(channelId, blockText, mentions, nonce).ConfigureAwait(false);
|
||||
result[i] = _messages.Update(msg.Id, channelId, msg);
|
||||
result[i].Nonce = nonce;
|
||||
try { RaiseMessageSent(result[i]); } catch { }
|
||||
}
|
||||
await Task.Delay(1000);
|
||||
await Task.Delay(1000).ConfigureAwait(false);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary> Sends a private message to the provided channel. </summary>
|
||||
public async Task<Message[]> SendPrivateMessage(User user, string text)
|
||||
=> await SendMessage(await GetPMChannel(user), text, new string[0]);
|
||||
{
|
||||
var channel = await GetPMChannel(user).ConfigureAwait(false);
|
||||
return await SendMessage(channel, text, new string[0]).ConfigureAwait(false);
|
||||
}
|
||||
/// <summary> Sends a private message to the provided channel. </summary>
|
||||
public async Task<Message[]> SendPrivateMessage(string userId, string text)
|
||||
=> await SendMessage(await GetPMChannel(userId), text, new string[0]);
|
||||
/*/// <summary> Sends a private message to the provided user, mentioning certain users. </summary>
|
||||
/// <remarks> While not required, it is recommended to include a mention reference in the text (see User.Mention). </remarks>
|
||||
public async Task<Message[]> SendPrivateMessage(User user, string text, string[] mentions)
|
||||
=> SendMessage(await GetOrCreatePMChannel(user), text, mentions);
|
||||
/// <summary> Sends a private message to the provided user, mentioning certain users. </summary>
|
||||
/// <remarks> While not required, it is recommended to include a mention reference in the text (see User.Mention). </remarks>
|
||||
public async Task<Message[]> SendPrivateMessage(string userId, string text, string[] mentions)
|
||||
=> SendMessage(await GetOrCreatePMChannel(userId), text, mentions);*/
|
||||
|
||||
{
|
||||
var channel = await GetPMChannel(userId).ConfigureAwait(false);
|
||||
return await SendMessage(channel, text, new string[0]).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary> Edits a message the provided message. </summary>
|
||||
public Task EditMessage(Message message, string text)
|
||||
@@ -313,7 +310,7 @@ namespace Discord
|
||||
if (text.Length > DiscordAPI.MaxMessageSize)
|
||||
text = text.Substring(0, DiscordAPI.MaxMessageSize);
|
||||
|
||||
var msg = await _api.EditMessage(channelId, messageId, text, mentions);
|
||||
var msg = await _api.EditMessage(channelId, messageId, text, mentions).ConfigureAwait(false);
|
||||
_messages.Update(msg.Id, channelId, msg);
|
||||
}
|
||||
|
||||
@@ -329,7 +326,7 @@ namespace Discord
|
||||
|
||||
try
|
||||
{
|
||||
await _api.DeleteMessage(channelId, msgId);
|
||||
await _api.DeleteMessage(channelId, msgId).ConfigureAwait(false);
|
||||
_messages.Remove(msgId);
|
||||
}
|
||||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { }
|
||||
@@ -343,7 +340,7 @@ namespace Discord
|
||||
{
|
||||
try
|
||||
{
|
||||
await _api.DeleteMessage(msg.ChannelId, msg.Id);
|
||||
await _api.DeleteMessage(msg.ChannelId, msg.Id).ConfigureAwait(false);
|
||||
}
|
||||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { }
|
||||
}
|
||||
@@ -357,7 +354,7 @@ namespace Discord
|
||||
{
|
||||
try
|
||||
{
|
||||
await _api.DeleteMessage(channelId, msgId);
|
||||
await _api.DeleteMessage(channelId, msgId).ConfigureAwait(false);
|
||||
}
|
||||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { }
|
||||
}
|
||||
@@ -404,7 +401,7 @@ namespace Discord
|
||||
{
|
||||
try
|
||||
{
|
||||
var msgs = await _api.GetMessages(channel.Id, count);
|
||||
var msgs = await _api.GetMessages(channel.Id, count).ConfigureAwait(false);
|
||||
return msgs.OrderBy(x => x.Timestamp)
|
||||
.Select(x =>
|
||||
{
|
||||
@@ -503,21 +500,21 @@ namespace Discord
|
||||
public async Task ChangeUsername(string newName, string currentEmail, string currentPassword)
|
||||
{
|
||||
CheckReady();
|
||||
var response = await _api.ChangeUsername(newName, currentEmail, currentPassword);
|
||||
var response = await _api.ChangeUsername(newName, currentEmail, currentPassword).ConfigureAwait(false);
|
||||
_users.Update(response.Id, response);
|
||||
}
|
||||
/// <summary> Changes your email to newEmail. </summary>
|
||||
public async Task ChangeEmail(string newEmail, string currentPassword)
|
||||
{
|
||||
CheckReady();
|
||||
var response = await _api.ChangeEmail(newEmail, currentPassword);
|
||||
var response = await _api.ChangeEmail(newEmail, currentPassword).ConfigureAwait(false);
|
||||
_users.Update(response.Id, response);
|
||||
}
|
||||
/// <summary> Changes your password to newPassword. </summary>
|
||||
public async Task ChangePassword(string newPassword, string currentEmail, string currentPassword)
|
||||
{
|
||||
CheckReady();
|
||||
var response = await _api.ChangePassword(newPassword, currentEmail, currentPassword);
|
||||
var response = await _api.ChangePassword(newPassword, currentEmail, currentPassword).ConfigureAwait(false);
|
||||
_users.Update(response.Id, response);
|
||||
}
|
||||
|
||||
@@ -526,7 +523,7 @@ namespace Discord
|
||||
public async Task ChangeAvatar(AvatarImageType imageType, byte[] bytes, string currentEmail, string currentPassword)
|
||||
{
|
||||
CheckReady();
|
||||
var response = await _api.ChangeAvatar(imageType, bytes, currentEmail, currentPassword);
|
||||
var response = await _api.ChangeAvatar(imageType, bytes, currentEmail, currentPassword).ConfigureAwait(false);
|
||||
_users.Update(response.Id, response);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -403,14 +403,14 @@ namespace Discord
|
||||
var channel = user.PrivateChannel;
|
||||
if (channel != null)
|
||||
return channel;
|
||||
return await CreatePMChannel(user?.Id);
|
||||
return await CreatePMChannel(user?.Id).ConfigureAwait(false);
|
||||
}
|
||||
private async Task<Channel> CreatePMChannel(string userId)
|
||||
{
|
||||
CheckReady();
|
||||
if (userId == null) throw new ArgumentNullException(nameof(userId));
|
||||
|
||||
var response = await _api.CreatePMChannel(_myId, userId);
|
||||
var response = await _api.CreatePMChannel(_myId, userId).ConfigureAwait(false);
|
||||
return _channels.Update(response.Id, response);
|
||||
}
|
||||
|
||||
|
||||
@@ -107,21 +107,21 @@ namespace Discord
|
||||
//Reconnect if we didn't cause the disconnect
|
||||
if (e.WasUnexpected)
|
||||
{
|
||||
await Task.Delay(_config.ReconnectDelay);
|
||||
await Task.Delay(_config.ReconnectDelay).ConfigureAwait(false);
|
||||
while (!_disconnectToken.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _webSocket.ReconnectAsync();
|
||||
await _webSocket.ReconnectAsync().ConfigureAwait(false);
|
||||
if (_http.Token != null)
|
||||
await _webSocket.Login(_http.Token);
|
||||
await _webSocket.Login(_http.Token).ConfigureAwait(false);
|
||||
break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
RaiseOnDebugMessage(DebugMessageType.Connection, $"DataSocket reconnect failed: {ex.Message}");
|
||||
//Net is down? We can keep trying to reconnect until the user runs Disconnect()
|
||||
await Task.Delay(_config.FailedReconnectDelay);
|
||||
await Task.Delay(_config.FailedReconnectDelay).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -141,12 +141,12 @@ namespace Discord
|
||||
//Reconnect if we didn't cause the disconnect
|
||||
if (e.WasUnexpected)
|
||||
{
|
||||
await Task.Delay(_config.ReconnectDelay);
|
||||
await Task.Delay(_config.ReconnectDelay).ConfigureAwait(false);
|
||||
while (!_disconnectToken.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _voiceWebSocket.ReconnectAsync();
|
||||
await _voiceWebSocket.ReconnectAsync().ConfigureAwait(false);
|
||||
break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -154,7 +154,7 @@ namespace Discord
|
||||
if (_isDebugMode)
|
||||
RaiseOnDebugMessage(DebugMessageType.Connection, $"VoiceSocket reconnect failed: {ex.Message}");
|
||||
//Net is down? We can keep trying to reconnect until the user runs Disconnect()
|
||||
await Task.Delay(_config.FailedReconnectDelay);
|
||||
await Task.Delay(_config.FailedReconnectDelay).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -426,7 +426,7 @@ namespace Discord
|
||||
if (_config.EnableVoice)
|
||||
{
|
||||
_voiceWebSocket.SetSessionData(data.ServerId, _myId, _sessionId, data.Token);
|
||||
await _voiceWebSocket.ConnectAsync("wss://" + data.Endpoint.Split(':')[0]);
|
||||
await _voiceWebSocket.ConnectAsync("wss://" + data.Endpoint.Split(':')[0]).ConfigureAwait(false);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -469,7 +469,7 @@ namespace Discord
|
||||
APIResponses.SendMessage apiMsg = null;
|
||||
try
|
||||
{
|
||||
apiMsg = await _api.SendMessage(msg.ChannelId, msg.RawText, msg.MentionIds, msg.Nonce);
|
||||
apiMsg = await _api.SendMessage(msg.ChannelId, msg.RawText, msg.MentionIds, msg.Nonce).ConfigureAwait(false);
|
||||
}
|
||||
catch (WebException) { break; }
|
||||
catch (HttpException) { hasFailed = true; }
|
||||
@@ -483,7 +483,7 @@ namespace Discord
|
||||
msg.HasFailed = hasFailed;
|
||||
try { RaiseMessageSent(msg); } catch { }
|
||||
}
|
||||
await Task.Delay(_config.MessageQueueInterval);
|
||||
await Task.Delay(_config.MessageQueueInterval).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
@@ -499,49 +499,36 @@ namespace Discord
|
||||
/// <summary> Connects to the Discord server with the provided token. </summary>
|
||||
public async Task Connect(string token)
|
||||
{
|
||||
await Disconnect();
|
||||
await Disconnect().ConfigureAwait(false);
|
||||
|
||||
if (_isDebugMode)
|
||||
RaiseOnDebugMessage(DebugMessageType.Connection, $"DataSocket is using cached token.");
|
||||
|
||||
await ConnectInternal(token);
|
||||
await ConnectInternal(token).ConfigureAwait(false);
|
||||
}
|
||||
/// <summary> Connects to the Discord server with the provided email and password. </summary>
|
||||
/// <returns> Returns a token for future connections. </returns>
|
||||
public async Task<string> Connect(string email, string password)
|
||||
{
|
||||
await Disconnect();
|
||||
await Disconnect().ConfigureAwait(false);
|
||||
|
||||
var response = await _api.Login(email, password);
|
||||
var response = await _api.Login(email, password).ConfigureAwait(false);
|
||||
if (_isDebugMode)
|
||||
RaiseOnDebugMessage(DebugMessageType.Connection, $"DataSocket got token.");
|
||||
|
||||
return await ConnectInternal(response.Token);
|
||||
return await ConnectInternal(response.Token).ConfigureAwait(false);
|
||||
}
|
||||
/// <summary> Connects to the Discord server as an anonymous user with the provided username. </summary>
|
||||
/// <returns> Returns a token for future connections. </returns>
|
||||
/*public async Task<string> ConnectAnonymous(string username)
|
||||
{
|
||||
await Disconnect();
|
||||
|
||||
var response = await _api.LoginAnonymous(username);
|
||||
if (_isDebugMode)
|
||||
RaiseOnDebugMessage(DebugMessageType.Connection, $"DataSocket got anonymous token.");
|
||||
_http.Token = response.Token;
|
||||
|
||||
return await ConnectInternal(response.Token);
|
||||
}*/
|
||||
|
||||
private async Task<string> ConnectInternal(string token)
|
||||
{
|
||||
_blockEvent.Reset();
|
||||
_http.Token = token;
|
||||
string url = (await _api.GetWebSocketEndpoint()).Url;
|
||||
string url = (await _api.GetWebSocketEndpoint().ConfigureAwait(false)).Url;
|
||||
if (_isDebugMode)
|
||||
RaiseOnDebugMessage(DebugMessageType.Connection, $"DataSocket got endpoint.");
|
||||
|
||||
await _webSocket.ConnectAsync(url);
|
||||
await _webSocket.Login(token);
|
||||
await _webSocket.ConnectAsync(url).ConfigureAwait(false);
|
||||
await _webSocket.Login(token).ConfigureAwait(false);
|
||||
|
||||
_disconnectToken = new CancellationTokenSource();
|
||||
if (_config.UseMessageQueue)
|
||||
@@ -550,10 +537,10 @@ namespace Discord
|
||||
_mainTask = _disconnectToken.Wait();
|
||||
_mainTask = _mainTask.ContinueWith(async x =>
|
||||
{
|
||||
await _webSocket.DisconnectAsync();
|
||||
await _webSocket.DisconnectAsync().ConfigureAwait(false);
|
||||
#if !DNXCORE50
|
||||
if (_config.EnableVoice)
|
||||
await _voiceWebSocket.DisconnectAsync();
|
||||
await _voiceWebSocket.DisconnectAsync().ConfigureAwait(false);
|
||||
#endif
|
||||
|
||||
//Clear send queue
|
||||
@@ -569,7 +556,7 @@ namespace Discord
|
||||
_blockEvent.Set();
|
||||
_mainTask = null;
|
||||
}).Unwrap();
|
||||
_isConnected = true;
|
||||
_isConnected = true;
|
||||
return token;
|
||||
}
|
||||
/// <summary> Disconnects from the Discord server, canceling any pending requests. </summary>
|
||||
@@ -578,7 +565,7 @@ namespace Discord
|
||||
if (_mainTask != null)
|
||||
{
|
||||
try { _disconnectToken.Cancel(); } catch (NullReferenceException) { }
|
||||
try { await _mainTask; } catch (NullReferenceException) { }
|
||||
try { await _mainTask.ConfigureAwait(false); } catch (NullReferenceException) { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -591,13 +578,13 @@ namespace Discord
|
||||
CheckVoice();
|
||||
if (channel == null) throw new ArgumentNullException(nameof(channel));
|
||||
|
||||
await LeaveVoiceServer();
|
||||
await LeaveVoiceServer().ConfigureAwait(false);
|
||||
//_currentVoiceServerId = channel.ServerId;
|
||||
_webSocket.JoinVoice(channel);
|
||||
#if !DNXCORE50
|
||||
await _voiceWebSocket.BeginConnect();
|
||||
await _voiceWebSocket.BeginConnect().ConfigureAwait(false);
|
||||
#else
|
||||
await Task.CompletedTask;
|
||||
await Task.CompletedTask.ConfigureAwait(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -607,9 +594,9 @@ namespace Discord
|
||||
CheckVoice();
|
||||
|
||||
#if !DNXCORE50
|
||||
await _voiceWebSocket.DisconnectAsync();
|
||||
await _voiceWebSocket.DisconnectAsync().ConfigureAwait(false);
|
||||
#else
|
||||
await Task.CompletedTask;
|
||||
await Task.CompletedTask.ConfigureAwait(false);
|
||||
#endif
|
||||
//if (_voiceWebSocket.CurrentVoiceServerId != null)
|
||||
_webSocket.LeaveVoice();
|
||||
@@ -654,7 +641,7 @@ namespace Discord
|
||||
#if !DNXCORE50
|
||||
_voiceWebSocket.Wait();
|
||||
#endif
|
||||
await TaskHelper.CompletedTask;
|
||||
await TaskHelper.CompletedTask.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
//Helpers
|
||||
|
||||
@@ -27,8 +27,8 @@ namespace Discord
|
||||
_lastSeq = 0;
|
||||
_lastSession = null;
|
||||
_redirectServer = null;
|
||||
await BeginConnect();
|
||||
await base.ConnectAsync(url);
|
||||
await BeginConnect().ConfigureAwait(false);
|
||||
await base.ConnectAsync(url).ConfigureAwait(false);
|
||||
}
|
||||
public async Task Login(string token)
|
||||
{
|
||||
@@ -44,7 +44,7 @@ namespace Discord
|
||||
msg.Payload.Properties["$device"] = "Discord.Net";
|
||||
msg.Payload.Properties["$referrer"] = "";
|
||||
msg.Payload.Properties["$referring_domain"] = "";
|
||||
await SendMessage(msg, cancelToken);
|
||||
await SendMessage(msg, cancelToken).ConfigureAwait(false);
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
@@ -14,6 +14,7 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Text;
|
||||
using WebSocketMessage = Discord.API.Models.VoiceWebSocketCommands.WebSocketMessage;
|
||||
using Discord.Helpers;
|
||||
|
||||
namespace Discord
|
||||
{
|
||||
@@ -65,29 +66,26 @@ namespace Discord
|
||||
_isClearing = false;
|
||||
|
||||
var cancelToken = _disconnectToken.Token;
|
||||
Task.Factory.StartNew(async () =>
|
||||
Task.Run(async () =>
|
||||
{
|
||||
_connectWaitOnLogin.Reset();
|
||||
|
||||
VoiceWebSocketCommands.Login msg = new VoiceWebSocketCommands.Login();
|
||||
msg.Payload.ServerId = _serverId;
|
||||
msg.Payload.SessionId = _sessionId;
|
||||
msg.Payload.Token = _token;
|
||||
msg.Payload.UserId = _userId;
|
||||
await SendMessage(msg, cancelToken);
|
||||
|
||||
try
|
||||
{
|
||||
_connectWaitOnLogin.Reset();
|
||||
|
||||
VoiceWebSocketCommands.Login msg = new VoiceWebSocketCommands.Login();
|
||||
msg.Payload.ServerId = _serverId;
|
||||
msg.Payload.SessionId = _sessionId;
|
||||
msg.Payload.Token = _token;
|
||||
msg.Payload.UserId = _userId;
|
||||
await SendMessage(msg, cancelToken).ConfigureAwait(false);
|
||||
|
||||
if (!_connectWaitOnLogin.Wait(_timeout, cancelToken))
|
||||
return;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SetConnected();
|
||||
});
|
||||
SetConnected();
|
||||
}
|
||||
catch (OperationCanceledException) { }
|
||||
}, _disconnectToken.Token);
|
||||
}
|
||||
protected override void OnDisconnect()
|
||||
{
|
||||
@@ -128,41 +126,45 @@ namespace Discord
|
||||
|
||||
public new async Task BeginConnect()
|
||||
{
|
||||
await base.BeginConnect();
|
||||
await base.BeginConnect().ConfigureAwait(false);
|
||||
var cancelToken = _disconnectToken.Token;
|
||||
|
||||
await Task.Yield();
|
||||
try
|
||||
await Task.Factory.StartNew(() =>
|
||||
{
|
||||
if (!_connectWaitOnLogin.Wait(_timeout, cancelToken)) //Waiting on JoinServer message
|
||||
throw new Exception("No reply from Discord server");
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
if (_disconnectReason == null)
|
||||
throw new Exception("An unknown websocket error occurred.");
|
||||
else
|
||||
_disconnectReason.Throw();
|
||||
}
|
||||
try
|
||||
{
|
||||
if (!_connectWaitOnLogin.Wait(_timeout, cancelToken)) //Waiting on JoinServer message
|
||||
throw new Exception("No reply from Discord server");
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
if (_disconnectReason == null)
|
||||
throw new Exception("An unknown websocket error occurred.");
|
||||
else
|
||||
_disconnectReason.Throw();
|
||||
}
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task ReceiveVoiceAsync()
|
||||
{
|
||||
var cancelSource = _disconnectToken;
|
||||
var cancelToken = cancelSource.Token;
|
||||
await Task.Yield();
|
||||
|
||||
try
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
while (!cancelToken.IsCancellationRequested)
|
||||
try
|
||||
{
|
||||
var result = await _udp.ReceiveAsync();
|
||||
ProcessUdpMessage(result);
|
||||
while (!cancelToken.IsCancellationRequested)
|
||||
{
|
||||
var result = await _udp.ReceiveAsync().ConfigureAwait(false);
|
||||
ProcessUdpMessage(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException) { }
|
||||
catch (ObjectDisposedException) { }
|
||||
catch (Exception ex) { DisconnectInternal(ex); }
|
||||
catch (OperationCanceledException) { }
|
||||
catch (ObjectDisposedException) { }
|
||||
catch (Exception ex) { DisconnectInternal(ex); }
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
#if USE_THREAD
|
||||
@@ -170,11 +172,12 @@ namespace Discord
|
||||
{
|
||||
var cancelToken = cancelSource.Token;
|
||||
#else
|
||||
private async Task SendVoiceAsync()
|
||||
private Task SendVoiceAsync()
|
||||
{
|
||||
var cancelSource = _disconnectToken;
|
||||
var cancelToken = cancelSource.Token;
|
||||
await Task.Yield();
|
||||
return Task.Run(() =>
|
||||
{
|
||||
#endif
|
||||
|
||||
byte[] packet;
|
||||
@@ -224,7 +227,7 @@ namespace Discord
|
||||
#if USE_THREAD
|
||||
_udp.Send(rtpPacket, packet.Length + 12);
|
||||
#else
|
||||
await _udp.SendAsync(rtpPacket, packet.Length + 12);
|
||||
await _udp.SendAsync(rtpPacket, packet.Length + 12).ConfigureAwait(false);
|
||||
#endif
|
||||
}
|
||||
timestamp = unchecked(timestamp + samplesPerFrame);
|
||||
@@ -247,24 +250,23 @@ namespace Discord
|
||||
#if USE_THREAD
|
||||
Thread.Sleep(1);
|
||||
#else
|
||||
await Task.Delay(1);
|
||||
await Task.Delay(1).ConfigureAwait(false);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException) { }
|
||||
catch (ObjectDisposedException) { }
|
||||
catch (Exception ex) { DisconnectInternal(ex); }
|
||||
}
|
||||
//Closes the UDP socket when _disconnectToken is triggered, since UDPClient doesn't allow passing a canceltoken
|
||||
private async Task WatcherAsync()
|
||||
#if !USE_THREAD
|
||||
}).ConfigureAwait(false);
|
||||
#endif
|
||||
}
|
||||
//Closes the UDP socket when _disconnectToken is triggered, since UDPClient doesn't allow passing a canceltoken
|
||||
private Task WatcherAsync()
|
||||
{
|
||||
var cancelToken = _disconnectToken.Token;
|
||||
try
|
||||
{
|
||||
await Task.Delay(-1, cancelToken);
|
||||
}
|
||||
catch (OperationCanceledException) { }
|
||||
finally { _udp.Close(); }
|
||||
return cancelToken.Wait()
|
||||
.ContinueWith(_ => _udp.Close());
|
||||
}
|
||||
|
||||
protected override async Task ProcessMessage(string json)
|
||||
@@ -279,7 +281,7 @@ namespace Discord
|
||||
var payload = (msg.Payload as JToken).ToObject<VoiceWebSocketEvents.Ready>();
|
||||
_heartbeatInterval = payload.HeartbeatInterval;
|
||||
_ssrc = payload.SSRC;
|
||||
_endpoint = new IPEndPoint((await Dns.GetHostAddressesAsync(_host.Replace("wss://", ""))).FirstOrDefault(), payload.Port);
|
||||
_endpoint = new IPEndPoint((await Dns.GetHostAddressesAsync(_host.Replace("wss://", "")).ConfigureAwait(false)).FirstOrDefault(), payload.Port);
|
||||
//_mode = payload.Modes.LastOrDefault();
|
||||
_mode = "plain";
|
||||
_udp.Connect(_endpoint);
|
||||
@@ -295,7 +297,7 @@ namespace Discord
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, 70);
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, 70).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -42,19 +42,17 @@ namespace Discord
|
||||
|
||||
protected virtual async Task BeginConnect()
|
||||
{
|
||||
await DisconnectAsync();
|
||||
await DisconnectAsync().ConfigureAwait(false);
|
||||
_disconnectToken = new CancellationTokenSource();
|
||||
_disconnectReason = null;
|
||||
}
|
||||
public virtual async Task ConnectAsync(string url)
|
||||
{
|
||||
//await DisconnectAsync();
|
||||
|
||||
var cancelToken = _disconnectToken.Token;
|
||||
|
||||
_webSocket = new ClientWebSocket();
|
||||
_webSocket.Options.KeepAliveInterval = TimeSpan.Zero;
|
||||
await _webSocket.ConnectAsync(new Uri(url), cancelToken);
|
||||
await _webSocket.ConnectAsync(new Uri(url), cancelToken).ConfigureAwait(false);
|
||||
_host = url;
|
||||
|
||||
if (_isDebug)
|
||||
@@ -99,7 +97,7 @@ namespace Discord
|
||||
if (_task != null)
|
||||
{
|
||||
try { DisconnectInternal(new Exception("Disconnect requested by user."), false); } catch (NullReferenceException) { }
|
||||
try { await _task; } catch (NullReferenceException) { }
|
||||
try { await _task.ConfigureAwait(false); } catch (NullReferenceException) { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,90 +129,94 @@ namespace Discord
|
||||
};
|
||||
}
|
||||
|
||||
private async Task ReceiveAsync()
|
||||
private Task ReceiveAsync()
|
||||
{
|
||||
var cancelSource = _disconnectToken;
|
||||
var cancelToken = cancelSource.Token;
|
||||
await Task.Yield();
|
||||
|
||||
var buffer = new byte[ReceiveChunkSize];
|
||||
var builder = new StringBuilder();
|
||||
|
||||
try
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
while (_webSocket.State == WebSocketState.Open && !cancelToken.IsCancellationRequested)
|
||||
var buffer = new byte[ReceiveChunkSize];
|
||||
var builder = new StringBuilder();
|
||||
|
||||
try
|
||||
{
|
||||
WebSocketReceiveResult result = null;
|
||||
do
|
||||
while (_webSocket.State == WebSocketState.Open && !cancelToken.IsCancellationRequested)
|
||||
{
|
||||
if (_webSocket.State != WebSocketState.Open || cancelToken.IsCancellationRequested)
|
||||
return;
|
||||
WebSocketReceiveResult result = null;
|
||||
do
|
||||
{
|
||||
if (_webSocket.State != WebSocketState.Open || cancelToken.IsCancellationRequested)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
result = await _webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), cancelToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (Win32Exception ex)
|
||||
when (ex.HResult == HR_TIMEOUT)
|
||||
{
|
||||
string msg = $"Connection timed out.";
|
||||
RaiseOnDebugMessage(DebugMessageType.Connection, msg);
|
||||
DisconnectInternal(new Exception(msg));
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.MessageType == WebSocketMessageType.Close)
|
||||
{
|
||||
string msg = $"Got Close Message ({result.CloseStatus?.ToString() ?? "Unexpected"}, {result.CloseStatusDescription ?? "No Reason"})";
|
||||
RaiseOnDebugMessage(DebugMessageType.Connection, msg);
|
||||
DisconnectInternal(new Exception(msg));
|
||||
await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
else
|
||||
builder.Append(Encoding.UTF8.GetString(buffer, 0, result.Count));
|
||||
|
||||
try
|
||||
{
|
||||
result = await _webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), cancelToken);
|
||||
}
|
||||
catch (Win32Exception ex)
|
||||
when (ex.HResult == HR_TIMEOUT)
|
||||
{
|
||||
string msg = $"Connection timed out.";
|
||||
RaiseOnDebugMessage(DebugMessageType.Connection, msg);
|
||||
DisconnectInternal(new Exception(msg));
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.MessageType == WebSocketMessageType.Close)
|
||||
{
|
||||
string msg = $"Got Close Message ({result.CloseStatus?.ToString() ?? "Unexpected"}, {result.CloseStatusDescription ?? "No Reason"})";
|
||||
RaiseOnDebugMessage(DebugMessageType.Connection, msg);
|
||||
DisconnectInternal(new Exception(msg));
|
||||
await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
|
||||
return;
|
||||
}
|
||||
else
|
||||
builder.Append(Encoding.UTF8.GetString(buffer, 0, result.Count));
|
||||
|
||||
}
|
||||
while (result == null || !result.EndOfMessage);
|
||||
while (result == null || !result.EndOfMessage);
|
||||
|
||||
#if DEBUG
|
||||
System.Diagnostics.Debug.WriteLine(">>> " + builder.ToString());
|
||||
System.Diagnostics.Debug.WriteLine(">>> " + builder.ToString());
|
||||
#endif
|
||||
await ProcessMessage(builder.ToString());
|
||||
await ProcessMessage(builder.ToString()).ConfigureAwait(false);
|
||||
|
||||
builder.Clear();
|
||||
builder.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException) { }
|
||||
catch (Exception ex) { DisconnectInternal(ex); }
|
||||
}
|
||||
private async Task SendAsync()
|
||||
catch (OperationCanceledException) { }
|
||||
catch (Exception ex) { DisconnectInternal(ex); }
|
||||
});
|
||||
}
|
||||
private Task SendAsync()
|
||||
{
|
||||
var cancelSource = _disconnectToken;
|
||||
var cancelToken = cancelSource.Token;
|
||||
await Task.Yield();
|
||||
|
||||
try
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
byte[] bytes;
|
||||
while (_webSocket.State == WebSocketState.Open && !cancelToken.IsCancellationRequested)
|
||||
try
|
||||
{
|
||||
if (_heartbeatInterval > 0)
|
||||
byte[] bytes;
|
||||
while (_webSocket.State == WebSocketState.Open && !cancelToken.IsCancellationRequested)
|
||||
{
|
||||
DateTime now = DateTime.UtcNow;
|
||||
if ((now - _lastHeartbeat).TotalMilliseconds > _heartbeatInterval)
|
||||
if (_heartbeatInterval > 0)
|
||||
{
|
||||
await SendMessage(GetKeepAlive(), cancelToken);
|
||||
_lastHeartbeat = now;
|
||||
DateTime now = DateTime.UtcNow;
|
||||
if ((now - _lastHeartbeat).TotalMilliseconds > _heartbeatInterval)
|
||||
{
|
||||
await SendMessage(GetKeepAlive(), cancelToken).ConfigureAwait(false);
|
||||
_lastHeartbeat = now;
|
||||
}
|
||||
}
|
||||
while (_sendQueue.TryDequeue(out bytes))
|
||||
await SendMessage(bytes, cancelToken).ConfigureAwait(false);
|
||||
await Task.Delay(_sendInterval, cancelToken).ConfigureAwait(false);
|
||||
}
|
||||
while (_sendQueue.TryDequeue(out bytes))
|
||||
await SendMessage(bytes, cancelToken);
|
||||
await Task.Delay(_sendInterval, cancelToken);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException) { }
|
||||
catch (Exception ex) { DisconnectInternal(ex); }
|
||||
catch (OperationCanceledException) { }
|
||||
catch (Exception ex) { DisconnectInternal(ex); }
|
||||
});
|
||||
}
|
||||
|
||||
protected abstract Task ProcessMessage(string json);
|
||||
@@ -252,7 +254,7 @@ namespace Discord
|
||||
|
||||
try
|
||||
{
|
||||
await _webSocket.SendAsync(new ArraySegment<byte>(message, offset, count), WebSocketMessageType.Text, isLast, cancelToken);
|
||||
await _webSocket.SendAsync(new ArraySegment<byte>(message, offset, count), WebSocketMessageType.Text, isLast, cancelToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (Win32Exception ex)
|
||||
when (ex.HResult == HR_TIMEOUT)
|
||||
|
||||
@@ -9,12 +9,12 @@ namespace Discord.Helpers
|
||||
public static async Task Wait(this CancellationTokenSource tokenSource)
|
||||
{
|
||||
var token = tokenSource.Token;
|
||||
try { await Task.Delay(-1, token); }
|
||||
try { await Task.Delay(-1, token).ConfigureAwait(false); }
|
||||
catch (OperationCanceledException) { }
|
||||
}
|
||||
public static async Task Wait(this CancellationToken token)
|
||||
{
|
||||
try { await Task.Delay(-1, token); }
|
||||
try { await Task.Delay(-1, token).ConfigureAwait(false); }
|
||||
catch (OperationCanceledException) { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ namespace Discord.Helpers
|
||||
private async Task<ResponseT> Send<ResponseT>(HttpMethod method, string path, HttpContent content)
|
||||
where ResponseT : class
|
||||
{
|
||||
string responseJson = await SendRequest(method, path, content, true);
|
||||
string responseJson = await SendRequest(method, path, content, true).ConfigureAwait(false);
|
||||
#if TEST_RESPONSES
|
||||
if (path.StartsWith(Endpoints.BaseApi))
|
||||
return JsonConvert.DeserializeObject<ResponseT>(responseJson, _settings);
|
||||
@@ -127,7 +127,7 @@ namespace Discord.Helpers
|
||||
#if TEST_RESPONSES
|
||||
private async Task<string> Send(HttpMethod method, string path, HttpContent content)
|
||||
{
|
||||
string responseJson = await SendRequest(method, path, content, true);
|
||||
string responseJson = await SendRequest(method, path, content, true).ConfigureAwait(false);
|
||||
if (path.StartsWith(Endpoints.BaseApi) && !string.IsNullOrEmpty(responseJson))
|
||||
throw new Exception("API check failed: Response is not empty.");
|
||||
return responseJson;
|
||||
@@ -146,12 +146,12 @@ namespace Discord.Helpers
|
||||
{
|
||||
if (content is StringContent)
|
||||
{
|
||||
string json = await (content as StringContent).ReadAsStringAsync();
|
||||
string json = await (content as StringContent).ReadAsStringAsync().ConfigureAwait(false);
|
||||
RaiseOnDebugMessage(DebugMessageType.XHRRawOutput, $"{method} {path}: {json}");
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] bytes = await content.ReadAsByteArrayAsync();
|
||||
byte[] bytes = await content.ReadAsByteArrayAsync().ConfigureAwait(false);
|
||||
RaiseOnDebugMessage(DebugMessageType.XHRRawOutput, $"{method} {path}: {bytes.Length} bytes");
|
||||
}
|
||||
}
|
||||
@@ -167,14 +167,14 @@ namespace Discord.Helpers
|
||||
HttpResponseMessage response;
|
||||
if (hasResponse)
|
||||
{
|
||||
response = await _client.SendAsync(msg, HttpCompletionOption.ResponseContentRead);
|
||||
response = await _client.SendAsync(msg, HttpCompletionOption.ResponseContentRead).ConfigureAwait(false);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
throw new HttpException(response.StatusCode);
|
||||
result = await response.Content.ReadAsStringAsync();
|
||||
result = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
response = await _client.SendAsync(msg, HttpCompletionOption.ResponseHeadersRead);
|
||||
response = await _client.SendAsync(msg, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
throw new HttpException(response.StatusCode);
|
||||
result = null;
|
||||
|
||||
Reference in New Issue
Block a user