Split DiscordClient into DiscordBaseClient and DiscordClient. Several fixes.
This commit is contained in:
@@ -136,6 +136,12 @@
|
|||||||
<Compile Include="..\Discord.Net\DiscordAPIClient.cs">
|
<Compile Include="..\Discord.Net\DiscordAPIClient.cs">
|
||||||
<Link>DiscordAPIClient.cs</Link>
|
<Link>DiscordAPIClient.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="..\Discord.Net\DiscordBaseClient.cs">
|
||||||
|
<Link>DiscordBaseClient.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Discord.Net\DiscordBaseClient.Events.cs">
|
||||||
|
<Link>DiscordBaseClient.Events.cs</Link>
|
||||||
|
</Compile>
|
||||||
<Compile Include="..\Discord.Net\DiscordClient.API.cs">
|
<Compile Include="..\Discord.Net\DiscordClient.API.cs">
|
||||||
<Link>DiscordClient.API.cs</Link>
|
<Link>DiscordClient.API.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
|||||||
107
src/Discord.Net/DiscordBaseClient.Events.cs
Normal file
107
src/Discord.Net/DiscordBaseClient.Events.cs
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Discord
|
||||||
|
{
|
||||||
|
public enum LogMessageSeverity : byte
|
||||||
|
{
|
||||||
|
Error = 1,
|
||||||
|
Warning = 2,
|
||||||
|
Info = 3,
|
||||||
|
Verbose = 4,
|
||||||
|
Debug = 5
|
||||||
|
}
|
||||||
|
public enum LogMessageSource : byte
|
||||||
|
{
|
||||||
|
Unknown = 0,
|
||||||
|
Cache,
|
||||||
|
Client,
|
||||||
|
DataWebSocket,
|
||||||
|
MessageQueue,
|
||||||
|
Rest,
|
||||||
|
VoiceWebSocket,
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DisconnectedEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
public readonly bool WasUnexpected;
|
||||||
|
public readonly Exception Error;
|
||||||
|
|
||||||
|
internal DisconnectedEventArgs(bool wasUnexpected, Exception error)
|
||||||
|
{
|
||||||
|
WasUnexpected = wasUnexpected;
|
||||||
|
Error = error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public sealed class LogMessageEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
public LogMessageSeverity Severity { get; }
|
||||||
|
public LogMessageSource Source { get; }
|
||||||
|
public string Message { get; }
|
||||||
|
|
||||||
|
internal LogMessageEventArgs(LogMessageSeverity severity, LogMessageSource source, string msg)
|
||||||
|
{
|
||||||
|
Severity = severity;
|
||||||
|
Source = source;
|
||||||
|
Message = msg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class VoicePacketEventArgs
|
||||||
|
{
|
||||||
|
public string UserId { get; }
|
||||||
|
public string ChannelId { get; }
|
||||||
|
public byte[] Buffer { get; }
|
||||||
|
public int Offset { get; }
|
||||||
|
public int Count { get; }
|
||||||
|
|
||||||
|
internal VoicePacketEventArgs(string userId, string channelId, byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
UserId = userId;
|
||||||
|
Buffer = buffer;
|
||||||
|
Offset = offset;
|
||||||
|
Count = count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract partial class DiscordBaseClient
|
||||||
|
{
|
||||||
|
public event EventHandler Connected;
|
||||||
|
private void RaiseConnected()
|
||||||
|
{
|
||||||
|
if (Connected != null)
|
||||||
|
RaiseEvent(nameof(Connected), () => Connected(this, EventArgs.Empty));
|
||||||
|
}
|
||||||
|
public event EventHandler<DisconnectedEventArgs> Disconnected;
|
||||||
|
private void RaiseDisconnected(DisconnectedEventArgs e)
|
||||||
|
{
|
||||||
|
if (Disconnected != null)
|
||||||
|
RaiseEvent(nameof(Disconnected), () => Disconnected(this, e));
|
||||||
|
}
|
||||||
|
public event EventHandler<LogMessageEventArgs> LogMessage;
|
||||||
|
internal void RaiseOnLog(LogMessageSeverity severity, LogMessageSource source, string message)
|
||||||
|
{
|
||||||
|
if (LogMessage != null)
|
||||||
|
RaiseEvent(nameof(LogMessage), () => LogMessage(this, new LogMessageEventArgs(severity, source, message)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler VoiceConnected;
|
||||||
|
private void RaiseVoiceConnected()
|
||||||
|
{
|
||||||
|
if (VoiceConnected != null)
|
||||||
|
RaiseEvent(nameof(VoiceConnected), () => VoiceConnected(this, EventArgs.Empty));
|
||||||
|
}
|
||||||
|
public event EventHandler<DisconnectedEventArgs> VoiceDisconnected;
|
||||||
|
private void RaiseVoiceDisconnected(DisconnectedEventArgs e)
|
||||||
|
{
|
||||||
|
if (VoiceDisconnected != null)
|
||||||
|
RaiseEvent(nameof(VoiceDisconnected), () => VoiceDisconnected(this, e));
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler<VoicePacketEventArgs> OnVoicePacket;
|
||||||
|
internal void RaiseOnVoicePacket(VoicePacketEventArgs e)
|
||||||
|
{
|
||||||
|
if (OnVoicePacket != null)
|
||||||
|
OnVoicePacket(this, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
272
src/Discord.Net/DiscordBaseClient.cs
Normal file
272
src/Discord.Net/DiscordBaseClient.cs
Normal file
@@ -0,0 +1,272 @@
|
|||||||
|
using Discord.API;
|
||||||
|
using Discord.Collections;
|
||||||
|
using Discord.Helpers;
|
||||||
|
using Discord.WebSockets.Data;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Net;
|
||||||
|
using System.Runtime.ExceptionServices;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using VoiceWebSocket = Discord.WebSockets.Voice.VoiceWebSocket;
|
||||||
|
|
||||||
|
namespace Discord
|
||||||
|
{
|
||||||
|
public enum DiscordClientState : byte
|
||||||
|
{
|
||||||
|
Disconnected,
|
||||||
|
Connecting,
|
||||||
|
Connected,
|
||||||
|
Disconnecting
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Provides a barebones connection to the Discord service </summary>
|
||||||
|
public partial class DiscordBaseClient
|
||||||
|
{
|
||||||
|
internal readonly DataWebSocket _dataSocket;
|
||||||
|
internal readonly VoiceWebSocket _voiceSocket;
|
||||||
|
protected readonly ManualResetEvent _disconnectedEvent;
|
||||||
|
protected readonly ManualResetEventSlim _connectedEvent;
|
||||||
|
private Task _runTask;
|
||||||
|
private string _gateway, _token;
|
||||||
|
|
||||||
|
protected ExceptionDispatchInfo _disconnectReason;
|
||||||
|
private bool _wasDisconnectUnexpected;
|
||||||
|
|
||||||
|
/// <summary> Returns the id of the current logged-in user. </summary>
|
||||||
|
public string CurrentUserId => _currentUserId;
|
||||||
|
private string _currentUserId;
|
||||||
|
/*/// <summary> Returns the server this user is currently connected to for voice. </summary>
|
||||||
|
public string CurrentVoiceServerId => _voiceSocket.CurrentServerId;*/
|
||||||
|
|
||||||
|
/// <summary> Returns the current connection state of this client. </summary>
|
||||||
|
public DiscordClientState State => (DiscordClientState)_state;
|
||||||
|
private int _state;
|
||||||
|
|
||||||
|
/// <summary> Returns the configuration object used to make this client. Note that this object cannot be edited directly - to change the configuration of this client, use the DiscordClient(DiscordClientConfig config) constructor. </summary>
|
||||||
|
public DiscordClientConfig Config => _config;
|
||||||
|
protected readonly DiscordClientConfig _config;
|
||||||
|
|
||||||
|
public CancellationToken CancelToken => _cancelToken;
|
||||||
|
private CancellationTokenSource _cancelTokenSource;
|
||||||
|
private CancellationToken _cancelToken;
|
||||||
|
|
||||||
|
/// <summary> Initializes a new instance of the DiscordClient class. </summary>
|
||||||
|
public DiscordBaseClient(DiscordClientConfig config = null)
|
||||||
|
{
|
||||||
|
_config = config ?? new DiscordClientConfig();
|
||||||
|
_config.Lock();
|
||||||
|
|
||||||
|
_state = (int)DiscordClientState.Disconnected;
|
||||||
|
_cancelToken = new CancellationToken(true);
|
||||||
|
_disconnectedEvent = new ManualResetEvent(true);
|
||||||
|
_connectedEvent = new ManualResetEventSlim(false);
|
||||||
|
|
||||||
|
_dataSocket = new DataWebSocket(this);
|
||||||
|
_dataSocket.Connected += (s, e) => { if (_state == (int)DiscordClientState.Connecting) CompleteConnect(); };
|
||||||
|
_dataSocket.Disconnected += async (s, e) =>
|
||||||
|
{
|
||||||
|
RaiseDisconnected(e);
|
||||||
|
if (e.WasUnexpected)
|
||||||
|
await _dataSocket.Reconnect(_token);
|
||||||
|
};
|
||||||
|
if (Config.VoiceMode != DiscordVoiceMode.Disabled)
|
||||||
|
{
|
||||||
|
_voiceSocket = new VoiceWebSocket(this);
|
||||||
|
_voiceSocket.Connected += (s, e) => RaiseVoiceConnected();
|
||||||
|
_voiceSocket.Disconnected += async (s, e) =>
|
||||||
|
{
|
||||||
|
RaiseVoiceDisconnected(e);
|
||||||
|
if (e.WasUnexpected)
|
||||||
|
await _voiceSocket.Reconnect();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
_dataSocket.LogMessage += (s, e) => RaiseOnLog(e.Severity, LogMessageSource.DataWebSocket, e.Message);
|
||||||
|
if (_config.VoiceMode != DiscordVoiceMode.Disabled)
|
||||||
|
_voiceSocket.LogMessage += (s, e) => RaiseOnLog(e.Severity, LogMessageSource.VoiceWebSocket, e.Message);
|
||||||
|
if (_config.LogLevel >= LogMessageSeverity.Info)
|
||||||
|
{
|
||||||
|
_dataSocket.Connected += (s, e) => RaiseOnLog(LogMessageSeverity.Info, LogMessageSource.DataWebSocket, "Connected");
|
||||||
|
_dataSocket.Disconnected += (s, e) => RaiseOnLog(LogMessageSeverity.Info, LogMessageSource.DataWebSocket, "Disconnected");
|
||||||
|
if (_config.VoiceMode != DiscordVoiceMode.Disabled)
|
||||||
|
{
|
||||||
|
_voiceSocket.Connected += (s, e) => RaiseOnLog(LogMessageSeverity.Info, LogMessageSource.VoiceWebSocket, "Connected");
|
||||||
|
_voiceSocket.Disconnected += (s, e) => RaiseOnLog(LogMessageSeverity.Info, LogMessageSource.VoiceWebSocket, "Disconnected");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_dataSocket.ReceivedEvent += (s, e) => OnReceivedEvent(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Connection
|
||||||
|
protected async Task<string> Connect(string gateway, string token)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_state = (int)DiscordClientState.Connecting;
|
||||||
|
_disconnectedEvent.Reset();
|
||||||
|
|
||||||
|
_gateway = gateway;
|
||||||
|
_token = token;
|
||||||
|
|
||||||
|
_cancelTokenSource = new CancellationTokenSource();
|
||||||
|
_cancelToken = _cancelTokenSource.Token;
|
||||||
|
|
||||||
|
_dataSocket.Host = gateway;
|
||||||
|
_dataSocket.ParentCancelToken = _cancelToken;
|
||||||
|
await _dataSocket.Login(token).ConfigureAwait(false);
|
||||||
|
|
||||||
|
_runTask = RunTasks();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//Cancel if either Disconnect is called, data socket errors or timeout is reached
|
||||||
|
var cancelToken = CancellationTokenSource.CreateLinkedTokenSource(_cancelToken, _dataSocket.CancelToken).Token;
|
||||||
|
_connectedEvent.Wait(cancelToken);
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
_dataSocket.ThrowError(); //Throws data socket's internal error if any occured
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
//_state = (int)DiscordClientState.Connected;
|
||||||
|
_token = token;
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
|
||||||
|
await Disconnect().ConfigureAwait(false);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected void CompleteConnect()
|
||||||
|
{
|
||||||
|
_state = (int)DiscordClientState.Connected;
|
||||||
|
_connectedEvent.Set();
|
||||||
|
RaiseConnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Disconnects from the Discord server, canceling any pending requests. </summary>
|
||||||
|
public Task Disconnect() => DisconnectInternal(new Exception("Disconnect was requested by user."), isUnexpected: false);
|
||||||
|
protected Task DisconnectInternal(Exception ex = null, bool isUnexpected = true, bool skipAwait = false)
|
||||||
|
{
|
||||||
|
int oldState;
|
||||||
|
bool hasWriterLock;
|
||||||
|
|
||||||
|
//If in either connecting or connected state, get a lock by being the first to switch to disconnecting
|
||||||
|
oldState = Interlocked.CompareExchange(ref _state, (int)DiscordClientState.Disconnecting, (int)DiscordClientState.Connecting);
|
||||||
|
if (oldState == (int)DiscordClientState.Disconnected) return TaskHelper.CompletedTask; //Already disconnected
|
||||||
|
hasWriterLock = oldState == (int)DiscordClientState.Connecting; //Caused state change
|
||||||
|
if (!hasWriterLock)
|
||||||
|
{
|
||||||
|
oldState = Interlocked.CompareExchange(ref _state, (int)DiscordClientState.Disconnecting, (int)DiscordClientState.Connected);
|
||||||
|
if (oldState == (int)DiscordClientState.Disconnected) return TaskHelper.CompletedTask; //Already disconnected
|
||||||
|
hasWriterLock = oldState == (int)DiscordClientState.Connected; //Caused state change
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasWriterLock)
|
||||||
|
{
|
||||||
|
_wasDisconnectUnexpected = isUnexpected;
|
||||||
|
_disconnectReason = ex != null ? ExceptionDispatchInfo.Capture(ex) : null;
|
||||||
|
|
||||||
|
_cancelTokenSource.Cancel();
|
||||||
|
/*if (_state == DiscordClientState.Connecting) //_runTask was never made
|
||||||
|
await Cleanup().ConfigureAwait(false);*/
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!skipAwait)
|
||||||
|
return _runTask ?? TaskHelper.CompletedTask;
|
||||||
|
else
|
||||||
|
return TaskHelper.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RunTasks()
|
||||||
|
{
|
||||||
|
Task[] tasks = Run();
|
||||||
|
Task firstTask = Task.WhenAny(tasks);
|
||||||
|
Task allTasks = Task.WhenAll(tasks);
|
||||||
|
|
||||||
|
//Wait until the first task ends/errors and capture the error
|
||||||
|
try { await firstTask.ConfigureAwait(false); }
|
||||||
|
catch (Exception ex) { await DisconnectInternal(ex: ex, skipAwait: true).ConfigureAwait(false); }
|
||||||
|
|
||||||
|
//Ensure all other tasks are signaled to end.
|
||||||
|
await DisconnectInternal(skipAwait: true);
|
||||||
|
|
||||||
|
//Wait for the remaining tasks to complete
|
||||||
|
try { await allTasks.ConfigureAwait(false); }
|
||||||
|
catch { }
|
||||||
|
|
||||||
|
//Start cleanup
|
||||||
|
var wasDisconnectUnexpected = _wasDisconnectUnexpected;
|
||||||
|
_wasDisconnectUnexpected = false;
|
||||||
|
|
||||||
|
await Cleanup().ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (!wasDisconnectUnexpected)
|
||||||
|
{
|
||||||
|
_state = (int)DiscordClientState.Disconnected;
|
||||||
|
_disconnectedEvent.Set();
|
||||||
|
}
|
||||||
|
_connectedEvent.Reset();
|
||||||
|
_runTask = null;
|
||||||
|
}
|
||||||
|
protected virtual Task[] Run()
|
||||||
|
{
|
||||||
|
return new Task[] { _cancelToken.Wait() };
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual async Task Cleanup()
|
||||||
|
{
|
||||||
|
await _dataSocket.Disconnect().ConfigureAwait(false);
|
||||||
|
if (_config.VoiceMode != DiscordVoiceMode.Disabled)
|
||||||
|
await _voiceSocket.Disconnect().ConfigureAwait(false);
|
||||||
|
|
||||||
|
_currentUserId = null;
|
||||||
|
_gateway = null;
|
||||||
|
_token = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Helpers
|
||||||
|
/// <summary> Blocking call that will not return until client has been stopped. This is mainly intended for use in console applications. </summary>
|
||||||
|
public void Block()
|
||||||
|
{
|
||||||
|
_disconnectedEvent.WaitOne();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void CheckReady(bool checkVoice = false)
|
||||||
|
{
|
||||||
|
switch (_state)
|
||||||
|
{
|
||||||
|
case (int)DiscordClientState.Disconnecting:
|
||||||
|
throw new InvalidOperationException("The client is disconnecting.");
|
||||||
|
case (int)DiscordClientState.Disconnected:
|
||||||
|
throw new InvalidOperationException("The client is not connected to Discord");
|
||||||
|
case (int)DiscordClientState.Connecting:
|
||||||
|
throw new InvalidOperationException("The client is connecting.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checkVoice && _config.VoiceMode == DiscordVoiceMode.Disabled)
|
||||||
|
throw new InvalidOperationException("Voice is not enabled for this client.");
|
||||||
|
}
|
||||||
|
protected void RaiseEvent(string name, Action action)
|
||||||
|
{
|
||||||
|
try { action(); }
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
RaiseOnLog(LogMessageSeverity.Error, LogMessageSource.Client,
|
||||||
|
$"{name} event handler raised an exception: ${ex.GetBaseException().Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal virtual Task OnReceivedEvent(WebSocketEventEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Type == "READY")
|
||||||
|
_currentUserId = e.Payload["user"].Value<string>("id");
|
||||||
|
return TaskHelper.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using Discord.API;
|
using Discord.API;
|
||||||
using Discord.Helpers;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -98,7 +97,7 @@ namespace Discord
|
|||||||
channel = user.PrivateChannel;
|
channel = user.PrivateChannel;
|
||||||
if (channel == null)
|
if (channel == null)
|
||||||
{
|
{
|
||||||
var response = await _api.CreatePMChannel(_currentUserId, userId).ConfigureAwait(false);
|
var response = await _api.CreatePMChannel(CurrentUserId, userId).ConfigureAwait(false);
|
||||||
channel = _channels.GetOrAdd(response.Id, response.GuildId, response.Recipient?.Id);
|
channel = _channels.GetOrAdd(response.Id, response.GuildId, response.Recipient?.Id);
|
||||||
channel.Update(response);
|
channel.Update(response);
|
||||||
}
|
}
|
||||||
@@ -266,13 +265,13 @@ namespace Discord
|
|||||||
var nonce = GenerateNonce();
|
var nonce = GenerateNonce();
|
||||||
if (_config.UseMessageQueue)
|
if (_config.UseMessageQueue)
|
||||||
{
|
{
|
||||||
var msg = _messages.GetOrAdd("nonce_" + nonce, channel.Id, _currentUserId);
|
var msg = _messages.GetOrAdd("nonce_" + nonce, channel.Id, CurrentUserId);
|
||||||
var currentMember = _members[msg.UserId, channel.ServerId];
|
var currentMember = _members[msg.UserId, channel.ServerId];
|
||||||
msg.Update(new API.Message
|
msg.Update(new API.Message
|
||||||
{
|
{
|
||||||
Content = blockText,
|
Content = blockText,
|
||||||
Timestamp = DateTime.UtcNow,
|
Timestamp = DateTime.UtcNow,
|
||||||
Author = new UserReference { Avatar = currentMember.AvatarId, Discriminator = currentMember.Discriminator, Id = _currentUserId, Username = currentMember.Name },
|
Author = new UserReference { Avatar = currentMember.AvatarId, Discriminator = currentMember.Discriminator, Id = CurrentUserId, Username = currentMember.Name },
|
||||||
ChannelId = channel.Id,
|
ChannelId = channel.Id,
|
||||||
IsTextToSpeech = isTextToSpeech
|
IsTextToSpeech = isTextToSpeech
|
||||||
});
|
});
|
||||||
@@ -513,13 +512,13 @@ namespace Discord
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Profile
|
//Profile
|
||||||
public Task<EditProfileResponse> EditProfile(string currentPassword,
|
public Task<EditProfileResponse> EditProfile(string currentPassword = "",
|
||||||
string username = null, string email = null, string password = null,
|
string username = null, string email = null, string password = null,
|
||||||
AvatarImageType avatarType = AvatarImageType.Png, byte[] avatar = null)
|
AvatarImageType avatarType = AvatarImageType.Png, byte[] avatar = null)
|
||||||
{
|
{
|
||||||
if (currentPassword == null) throw new ArgumentNullException(nameof(currentPassword));
|
if (currentPassword == null) throw new ArgumentNullException(nameof(currentPassword));
|
||||||
|
|
||||||
return _api.EditProfile(currentPassword, username: username, email: email, password: password,
|
return _api.EditProfile(currentPassword: currentPassword, username: username, email: email, password: password,
|
||||||
avatarType: avatarType, avatar: avatar);
|
avatarType: avatarType, avatar: avatar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,50 +2,6 @@
|
|||||||
|
|
||||||
namespace Discord
|
namespace Discord
|
||||||
{
|
{
|
||||||
public enum LogMessageSeverity : byte
|
|
||||||
{
|
|
||||||
Error = 1,
|
|
||||||
Warning = 2,
|
|
||||||
Info = 3,
|
|
||||||
Verbose = 4,
|
|
||||||
Debug = 5
|
|
||||||
}
|
|
||||||
public enum LogMessageSource : byte
|
|
||||||
{
|
|
||||||
Unknown = 0,
|
|
||||||
Cache,
|
|
||||||
Client,
|
|
||||||
DataWebSocket,
|
|
||||||
MessageQueue,
|
|
||||||
Rest,
|
|
||||||
VoiceWebSocket,
|
|
||||||
}
|
|
||||||
|
|
||||||
public class DisconnectedEventArgs : EventArgs
|
|
||||||
{
|
|
||||||
public readonly bool WasUnexpected;
|
|
||||||
public readonly Exception Error;
|
|
||||||
|
|
||||||
internal DisconnectedEventArgs(bool wasUnexpected, Exception error)
|
|
||||||
{
|
|
||||||
WasUnexpected = wasUnexpected;
|
|
||||||
Error = error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public sealed class LogMessageEventArgs : EventArgs
|
|
||||||
{
|
|
||||||
public LogMessageSeverity Severity { get; }
|
|
||||||
public LogMessageSource Source { get; }
|
|
||||||
public string Message { get; }
|
|
||||||
|
|
||||||
internal LogMessageEventArgs(LogMessageSeverity severity, LogMessageSource source, string msg)
|
|
||||||
{
|
|
||||||
Severity = severity;
|
|
||||||
Source = source;
|
|
||||||
Message = msg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ServerEventArgs : EventArgs
|
public sealed class ServerEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public Server Server { get; }
|
public Server Server { get; }
|
||||||
@@ -148,45 +104,9 @@ namespace Discord
|
|||||||
IsSpeaking = isSpeaking;
|
IsSpeaking = isSpeaking;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public sealed class VoicePacketEventArgs
|
|
||||||
{
|
|
||||||
public string UserId { get; }
|
|
||||||
public string ChannelId { get; }
|
|
||||||
public byte[] Buffer { get; }
|
|
||||||
public int Offset { get; }
|
|
||||||
public int Count { get; }
|
|
||||||
|
|
||||||
internal VoicePacketEventArgs(string userId, string channelId, byte[] buffer, int offset, int count)
|
|
||||||
{
|
|
||||||
UserId = userId;
|
|
||||||
Buffer = buffer;
|
|
||||||
Offset = offset;
|
|
||||||
Count = count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public partial class DiscordClient
|
public partial class DiscordClient
|
||||||
{
|
{
|
||||||
//General
|
|
||||||
public event EventHandler Connected;
|
|
||||||
private void RaiseConnected()
|
|
||||||
{
|
|
||||||
if (Connected != null)
|
|
||||||
RaiseEvent(nameof(Connected), () => Connected(this, EventArgs.Empty));
|
|
||||||
}
|
|
||||||
public event EventHandler<DisconnectedEventArgs> Disconnected;
|
|
||||||
private void RaiseDisconnected(DisconnectedEventArgs e)
|
|
||||||
{
|
|
||||||
if (Disconnected != null)
|
|
||||||
RaiseEvent(nameof(Disconnected), () => Disconnected(this, e));
|
|
||||||
}
|
|
||||||
public event EventHandler<LogMessageEventArgs> LogMessage;
|
|
||||||
internal void RaiseOnLog(LogMessageSeverity severity, LogMessageSource source, string message)
|
|
||||||
{
|
|
||||||
if (LogMessage != null)
|
|
||||||
RaiseEvent(nameof(LogMessage), () => LogMessage(this, new LogMessageEventArgs(severity, source, message)));
|
|
||||||
}
|
|
||||||
|
|
||||||
//Server
|
//Server
|
||||||
public event EventHandler<ServerEventArgs> ServerCreated;
|
public event EventHandler<ServerEventArgs> ServerCreated;
|
||||||
private void RaiseServerCreated(Server server)
|
private void RaiseServerCreated(Server server)
|
||||||
@@ -342,26 +262,5 @@ namespace Discord
|
|||||||
if (UserIsSpeaking != null)
|
if (UserIsSpeaking != null)
|
||||||
RaiseEvent(nameof(UserIsSpeaking), () => UserIsSpeaking(this, new UserIsSpeakingEventArgs(member, isSpeaking)));
|
RaiseEvent(nameof(UserIsSpeaking), () => UserIsSpeaking(this, new UserIsSpeakingEventArgs(member, isSpeaking)));
|
||||||
}
|
}
|
||||||
|
|
||||||
//Voice
|
|
||||||
public event EventHandler VoiceConnected;
|
|
||||||
private void RaiseVoiceConnected()
|
|
||||||
{
|
|
||||||
if (VoiceConnected != null)
|
|
||||||
RaiseEvent(nameof(UserIsSpeaking), () => VoiceConnected(this, EventArgs.Empty));
|
|
||||||
}
|
|
||||||
public event EventHandler<DisconnectedEventArgs> VoiceDisconnected;
|
|
||||||
private void RaiseVoiceDisconnected(DisconnectedEventArgs e)
|
|
||||||
{
|
|
||||||
if (VoiceDisconnected != null)
|
|
||||||
RaiseEvent(nameof(UserIsSpeaking), () => VoiceDisconnected(this, e));
|
|
||||||
}
|
|
||||||
|
|
||||||
public event EventHandler<VoicePacketEventArgs> OnVoicePacket;
|
|
||||||
internal void RaiseOnVoicePacket(VoicePacketEventArgs e)
|
|
||||||
{
|
|
||||||
if (OnVoicePacket != null)
|
|
||||||
OnVoicePacket(this, e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using Discord.Helpers;
|
using Discord.Helpers;
|
||||||
using Discord.WebSockets;
|
using Discord.WebSockets;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Discord
|
namespace Discord
|
||||||
@@ -8,30 +9,31 @@ namespace Discord
|
|||||||
public partial class DiscordClient
|
public partial class DiscordClient
|
||||||
{
|
{
|
||||||
public Task JoinVoiceServer(Channel channel)
|
public Task JoinVoiceServer(Channel channel)
|
||||||
=> JoinVoiceServer(channel?.Server, channel);
|
=> JoinVoiceServer(channel?.ServerId, channel?.Id);
|
||||||
public Task JoinVoiceServer(string serverId, string channelId)
|
|
||||||
=> JoinVoiceServer(_servers[serverId], _channels[channelId]);
|
|
||||||
public Task JoinVoiceServer(Server server, string channelId)
|
public Task JoinVoiceServer(Server server, string channelId)
|
||||||
=> JoinVoiceServer(server, _channels[channelId]);
|
=> JoinVoiceServer(server?.Id, channelId);
|
||||||
private async Task JoinVoiceServer(Server server, Channel channel)
|
public async Task JoinVoiceServer(string serverId, string channelId)
|
||||||
{
|
{
|
||||||
CheckReady(checkVoice: true);
|
CheckReady(checkVoice: true);
|
||||||
if (server == null) throw new ArgumentNullException(nameof(server));
|
if (serverId == null) throw new ArgumentNullException(nameof(serverId));
|
||||||
if (channel == null) throw new ArgumentNullException(nameof(channel));
|
if (channelId == null) throw new ArgumentNullException(nameof(channelId));
|
||||||
|
|
||||||
await LeaveVoiceServer().ConfigureAwait(false);
|
await LeaveVoiceServer().ConfigureAwait(false);
|
||||||
_voiceSocket.SetChannel(server, channel);
|
_voiceSocket.SetChannel(serverId, channelId);
|
||||||
_dataSocket.SendJoinVoice(server.Id, channel.Id);
|
_dataSocket.SendJoinVoice(serverId, channelId);
|
||||||
|
|
||||||
|
CancellationTokenSource tokenSource = new CancellationTokenSource();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await Task.Run(() => _voiceSocket.WaitForConnection())
|
await Task.Run(() => _voiceSocket.WaitForConnection(tokenSource.Token))
|
||||||
.Timeout(_config.ConnectionTimeout)
|
.Timeout(_config.ConnectionTimeout, tokenSource)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (TaskCanceledException)
|
catch (TimeoutException)
|
||||||
{
|
{
|
||||||
|
tokenSource.Cancel();
|
||||||
await LeaveVoiceServer().ConfigureAwait(false);
|
await LeaveVoiceServer().ConfigureAwait(false);
|
||||||
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public async Task LeaveVoiceServer()
|
public async Task LeaveVoiceServer()
|
||||||
@@ -40,11 +42,11 @@ namespace Discord
|
|||||||
|
|
||||||
if (_voiceSocket.State != WebSocketState.Disconnected)
|
if (_voiceSocket.State != WebSocketState.Disconnected)
|
||||||
{
|
{
|
||||||
var server = _voiceSocket.CurrentVoiceServer;
|
var serverId = _voiceSocket.CurrentServerId;
|
||||||
if (server != null)
|
if (serverId != null)
|
||||||
{
|
{
|
||||||
await _voiceSocket.Disconnect().ConfigureAwait(false);
|
await _voiceSocket.Disconnect().ConfigureAwait(false);
|
||||||
_dataSocket.SendLeaveVoice(server.Id);
|
_dataSocket.SendLeaveVoice(serverId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,6 @@
|
|||||||
using System.Threading.Tasks;
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Discord.Helpers
|
namespace Discord.Helpers
|
||||||
{
|
{
|
||||||
@@ -32,5 +34,29 @@ namespace Discord.Helpers
|
|||||||
else
|
else
|
||||||
return await self.ConfigureAwait(false);
|
return await self.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
public static async Task Timeout(this Task self, int milliseconds, CancellationTokenSource cancelToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
cancelToken.CancelAfter(milliseconds);
|
||||||
|
await self;
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
throw new TimeoutException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static async Task<T> Timeout<T>(this Task<T> self, int milliseconds, CancellationTokenSource cancelToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
cancelToken.CancelAfter(milliseconds);
|
||||||
|
return await self;
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
throw new TimeoutException();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ namespace Discord
|
|||||||
|
|
||||||
private readonly DiscordClient _client;
|
private readonly DiscordClient _client;
|
||||||
private ConcurrentDictionary<string, bool> _messages;
|
private ConcurrentDictionary<string, bool> _messages;
|
||||||
private ConcurrentDictionary<uint, string> _ssrcMapping;
|
|
||||||
|
|
||||||
/// <summary> Returns the unique identifier for this channel. </summary>
|
/// <summary> Returns the unique identifier for this channel. </summary>
|
||||||
public string Id { get; }
|
public string Id { get; }
|
||||||
@@ -70,8 +69,6 @@ namespace Discord
|
|||||||
{
|
{
|
||||||
Name = model.Name;
|
Name = model.Name;
|
||||||
Type = model.Type;
|
Type = model.Type;
|
||||||
if (Type == ChannelTypes.Voice && _ssrcMapping == null)
|
|
||||||
_ssrcMapping = new ConcurrentDictionary<uint, string>();
|
|
||||||
}
|
}
|
||||||
internal void Update(API.ChannelInfo model)
|
internal void Update(API.ChannelInfo model)
|
||||||
{
|
{
|
||||||
@@ -104,12 +101,5 @@ namespace Discord
|
|||||||
bool ignored;
|
bool ignored;
|
||||||
return _messages.TryRemove(messageId, out ignored);
|
return _messages.TryRemove(messageId, out ignored);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal string GetUserId(uint ssrc)
|
|
||||||
{
|
|
||||||
string userId = null;
|
|
||||||
_ssrcMapping.TryGetValue(ssrc, out userId);
|
|
||||||
return userId;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ namespace Discord.WebSockets.Data
|
|||||||
public string SessionId => _sessionId;
|
public string SessionId => _sessionId;
|
||||||
private string _sessionId;
|
private string _sessionId;
|
||||||
|
|
||||||
public DataWebSocket(DiscordClient client)
|
public DataWebSocket(DiscordBaseClient client)
|
||||||
: base(client)
|
: base(client)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace Discord.WebSockets.Data
|
|||||||
|
|
||||||
internal partial class DataWebSocket
|
internal partial class DataWebSocket
|
||||||
{
|
{
|
||||||
public event EventHandler<WebSocketEventEventArgs> ReceivedEvent;
|
internal event EventHandler<WebSocketEventEventArgs> ReceivedEvent;
|
||||||
private void RaiseReceivedEvent(string type, JToken payload)
|
private void RaiseReceivedEvent(string type, JToken payload)
|
||||||
{
|
{
|
||||||
if (ReceivedEvent != null)
|
if (ReceivedEvent != null)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace Discord.WebSockets.Voice
|
namespace Discord.WebSockets.Voice
|
||||||
{
|
{
|
||||||
public sealed class IsTalkingEventArgs : EventArgs
|
internal sealed class IsTalkingEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public readonly string UserId;
|
public readonly string UserId;
|
||||||
public readonly bool IsSpeaking;
|
public readonly bool IsSpeaking;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace Discord.WebSockets.Voice
|
namespace Discord.WebSockets.Voice
|
||||||
{
|
{
|
||||||
internal partial class VoiceWebSocket : WebSocket
|
internal partial class VoiceWebSocket : WebSocket
|
||||||
{
|
{
|
||||||
private const int MaxOpusSize = 4000;
|
private const int MaxOpusSize = 4000;
|
||||||
private const string EncryptedMode = "xsalsa20_poly1305";
|
private const string EncryptedMode = "xsalsa20_poly1305";
|
||||||
@@ -27,6 +27,7 @@ namespace Discord.WebSockets.Voice
|
|||||||
private readonly ConcurrentDictionary<uint, OpusDecoder> _decoders;
|
private readonly ConcurrentDictionary<uint, OpusDecoder> _decoders;
|
||||||
private ManualResetEventSlim _connectWaitOnLogin;
|
private ManualResetEventSlim _connectWaitOnLogin;
|
||||||
private uint _ssrc;
|
private uint _ssrc;
|
||||||
|
private ConcurrentDictionary<uint, string> _ssrcMapping;
|
||||||
|
|
||||||
private ConcurrentQueue<byte[]> _sendQueue;
|
private ConcurrentQueue<byte[]> _sendQueue;
|
||||||
private ManualResetEventSlim _sendQueueWait, _sendQueueEmptyWait;
|
private ManualResetEventSlim _sendQueueWait, _sendQueueEmptyWait;
|
||||||
@@ -35,17 +36,16 @@ namespace Discord.WebSockets.Voice
|
|||||||
private bool _isClearing, _isEncrypted;
|
private bool _isClearing, _isEncrypted;
|
||||||
private byte[] _secretKey, _encodingBuffer;
|
private byte[] _secretKey, _encodingBuffer;
|
||||||
private ushort _sequence;
|
private ushort _sequence;
|
||||||
private string _userId, _sessionId, _token, _encryptionMode;
|
private string _serverId, _channelId, _userId, _sessionId, _token, _encryptionMode;
|
||||||
private Server _server;
|
|
||||||
private Channel _channel;
|
|
||||||
|
|
||||||
#if USE_THREAD
|
#if USE_THREAD
|
||||||
private Thread _sendThread;
|
private Thread _sendThread, _receiveThread;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public Server CurrentVoiceServer => _server;
|
public string CurrentServerId => _serverId;
|
||||||
|
public string CurrentChannelId => _channelId;
|
||||||
|
|
||||||
public VoiceWebSocket(DiscordClient client)
|
public VoiceWebSocket(DiscordBaseClient client)
|
||||||
: base(client)
|
: base(client)
|
||||||
{
|
{
|
||||||
_rand = new Random();
|
_rand = new Random();
|
||||||
@@ -56,12 +56,14 @@ namespace Discord.WebSockets.Voice
|
|||||||
_sendQueueEmptyWait = new ManualResetEventSlim(true);
|
_sendQueueEmptyWait = new ManualResetEventSlim(true);
|
||||||
_targetAudioBufferLength = client.Config.VoiceBufferLength / 20; //20 ms frames
|
_targetAudioBufferLength = client.Config.VoiceBufferLength / 20; //20 ms frames
|
||||||
_encodingBuffer = new byte[MaxOpusSize];
|
_encodingBuffer = new byte[MaxOpusSize];
|
||||||
|
_ssrcMapping = new ConcurrentDictionary<uint, string>();
|
||||||
|
_encoder = new OpusEncoder(48000, 1, 20, Opus.Application.Audio);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetChannel(Server server, Channel channel)
|
public void SetChannel(string serverId, string channelId)
|
||||||
{
|
{
|
||||||
_server = server;
|
_serverId = serverId;
|
||||||
_channel = channel;
|
_channelId = channelId;
|
||||||
}
|
}
|
||||||
public async Task Login(string userId, string sessionId, string token, CancellationToken cancelToken)
|
public async Task Login(string userId, string sessionId, string token, CancellationToken cancelToken)
|
||||||
{
|
{
|
||||||
@@ -113,7 +115,7 @@ namespace Discord.WebSockets.Voice
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
LoginCommand msg = new LoginCommand();
|
LoginCommand msg = new LoginCommand();
|
||||||
msg.Payload.ServerId = _server.Id;
|
msg.Payload.ServerId = _serverId;
|
||||||
msg.Payload.SessionId = _sessionId;
|
msg.Payload.SessionId = _sessionId;
|
||||||
msg.Payload.Token = _token;
|
msg.Payload.Token = _token;
|
||||||
msg.Payload.UserId = _userId;
|
msg.Payload.UserId = _userId;
|
||||||
@@ -122,6 +124,8 @@ namespace Discord.WebSockets.Voice
|
|||||||
#if USE_THREAD
|
#if USE_THREAD
|
||||||
_sendThread = new Thread(new ThreadStart(() => SendVoiceAsync(_cancelToken)));
|
_sendThread = new Thread(new ThreadStart(() => SendVoiceAsync(_cancelToken)));
|
||||||
_sendThread.Start();
|
_sendThread.Start();
|
||||||
|
_receiveThread = new Thread(new ThreadStart(() => ReceiveVoiceAsync(_cancelToken)));
|
||||||
|
_receiveThread.Start();
|
||||||
#if !DNXCORE50
|
#if !DNXCORE50
|
||||||
return new Task[] { WatcherAsync() }.Concat(base.Run()).ToArray();
|
return new Task[] { WatcherAsync() }.Concat(base.Run()).ToArray();
|
||||||
#else
|
#else
|
||||||
@@ -141,7 +145,9 @@ namespace Discord.WebSockets.Voice
|
|||||||
{
|
{
|
||||||
#if USE_THREAD
|
#if USE_THREAD
|
||||||
_sendThread.Join();
|
_sendThread.Join();
|
||||||
|
_receiveThread.Join();
|
||||||
_sendThread = null;
|
_sendThread = null;
|
||||||
|
_receiveThread = null;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
OpusDecoder decoder;
|
OpusDecoder decoder;
|
||||||
@@ -274,9 +280,9 @@ namespace Discord.WebSockets.Voice
|
|||||||
/*if (_logLevel >= LogMessageSeverity.Debug)
|
/*if (_logLevel >= LogMessageSeverity.Debug)
|
||||||
RaiseOnLog(LogMessageSeverity.Debug, $"Received {buffer.Length - 12} bytes.");*/
|
RaiseOnLog(LogMessageSeverity.Debug, $"Received {buffer.Length - 12} bytes.");*/
|
||||||
|
|
||||||
string userId = _channel.GetUserId(ssrc);
|
string userId;
|
||||||
if (userId != null)
|
if (_ssrcMapping.TryGetValue(ssrc, out userId))
|
||||||
RaiseOnPacket(userId, _channel.Id, result, resultOffset, resultLength);
|
RaiseOnPacket(userId, _channelId, result, resultOffset, resultLength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if USE_THREAD || DNXCORE50
|
#if USE_THREAD || DNXCORE50
|
||||||
@@ -568,9 +574,9 @@ namespace Discord.WebSockets.Voice
|
|||||||
{
|
{
|
||||||
_sendQueueEmptyWait.Wait(_cancelToken);
|
_sendQueueEmptyWait.Wait(_cancelToken);
|
||||||
}
|
}
|
||||||
public void WaitForConnection()
|
public void WaitForConnection(CancellationToken cancelToken)
|
||||||
{
|
{
|
||||||
_connectedEvent.Wait();
|
_connectedEvent.Wait(cancelToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace Discord.WebSockets
|
namespace Discord.WebSockets
|
||||||
{
|
{
|
||||||
internal partial class WebSocket
|
internal abstract partial class WebSocket
|
||||||
{
|
{
|
||||||
public event EventHandler Connected;
|
public event EventHandler Connected;
|
||||||
private void RaiseConnected()
|
private void RaiseConnected()
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ namespace Discord.WebSockets
|
|||||||
internal abstract partial class WebSocket
|
internal abstract partial class WebSocket
|
||||||
{
|
{
|
||||||
protected readonly IWebSocketEngine _engine;
|
protected readonly IWebSocketEngine _engine;
|
||||||
protected readonly DiscordClient _client;
|
protected readonly DiscordBaseClient _client;
|
||||||
protected readonly LogMessageSeverity _logLevel;
|
protected readonly LogMessageSeverity _logLevel;
|
||||||
protected readonly ManualResetEventSlim _connectedEvent;
|
protected readonly ManualResetEventSlim _connectedEvent;
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ namespace Discord.WebSockets
|
|||||||
public WebSocketState State => (WebSocketState)_state;
|
public WebSocketState State => (WebSocketState)_state;
|
||||||
protected int _state;
|
protected int _state;
|
||||||
|
|
||||||
public WebSocket(DiscordClient client)
|
public WebSocket(DiscordBaseClient client)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
_logLevel = client.Config.LogLevel;
|
_logLevel = client.Config.LogLevel;
|
||||||
@@ -131,9 +131,9 @@ namespace Discord.WebSockets
|
|||||||
_disconnectState = (WebSocketState)oldState;
|
_disconnectState = (WebSocketState)oldState;
|
||||||
_disconnectReason = ex != null ? ExceptionDispatchInfo.Capture(ex) : null;
|
_disconnectReason = ex != null ? ExceptionDispatchInfo.Capture(ex) : null;
|
||||||
|
|
||||||
if (_disconnectState == WebSocketState.Connecting) //_runTask was never made
|
|
||||||
await Cleanup();
|
|
||||||
_cancelTokenSource.Cancel();
|
_cancelTokenSource.Cancel();
|
||||||
|
if (_disconnectState == WebSocketState.Connecting) //_runTask was never made
|
||||||
|
await Cleanup().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!skipAwait)
|
if (!skipAwait)
|
||||||
@@ -162,7 +162,7 @@ namespace Discord.WebSockets
|
|||||||
try { await allTasks.ConfigureAwait(false); }
|
try { await allTasks.ConfigureAwait(false); }
|
||||||
catch { }
|
catch { }
|
||||||
|
|
||||||
//Clean up state variables and raise disconnect event
|
//Start cleanup
|
||||||
await Cleanup().ConfigureAwait(false);
|
await Cleanup().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
protected virtual Task[] Run()
|
protected virtual Task[] Run()
|
||||||
|
|||||||
Reference in New Issue
Block a user