Browse Source

Split DiscordClient into DiscordBaseClient and DiscordClient. Several fixes.

tags/docs-0.9
RogueException 9 years ago
parent
commit
a8ca994667
15 changed files with 868 additions and 767 deletions
  1. +6
    -0
      src/Discord.Net.Net45/Discord.Net.csproj
  2. +107
    -0
      src/Discord.Net/DiscordBaseClient.Events.cs
  3. +272
    -0
      src/Discord.Net/DiscordBaseClient.cs
  4. +5
    -6
      src/Discord.Net/DiscordClient.API.cs
  5. +0
    -101
      src/Discord.Net/DiscordClient.Events.cs
  6. +17
    -15
      src/Discord.Net/DiscordClient.Voice.cs
  7. +401
    -607
      src/Discord.Net/DiscordClient.cs
  8. +27
    -1
      src/Discord.Net/Helpers/TaskHelper.cs
  9. +0
    -10
      src/Discord.Net/Models/Channel.cs
  10. +1
    -1
      src/Discord.Net/WebSockets/Data/DataWebSocket.cs
  11. +1
    -1
      src/Discord.Net/WebSockets/Data/DataWebSockets.Events.cs
  12. +1
    -1
      src/Discord.Net/WebSockets/Voice/VoiceWebSocket.Events.cs
  13. +23
    -17
      src/Discord.Net/WebSockets/Voice/VoiceWebSocket.cs
  14. +1
    -1
      src/Discord.Net/WebSockets/WebSocket.Events.cs
  15. +6
    -6
      src/Discord.Net/WebSockets/WebSocket.cs

+ 6
- 0
src/Discord.Net.Net45/Discord.Net.csproj View File

@@ -136,6 +136,12 @@
<Compile Include="..\Discord.Net\DiscordAPIClient.cs">
<Link>DiscordAPIClient.cs</Link>
</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">
<Link>DiscordClient.API.cs</Link>
</Compile>


+ 107
- 0
src/Discord.Net/DiscordBaseClient.Events.cs View 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
- 0
src/Discord.Net/DiscordBaseClient.cs View 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;
}
}
}

+ 5
- 6
src/Discord.Net/DiscordClient.API.cs View File

@@ -1,5 +1,4 @@
using Discord.API;
using Discord.Helpers;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -98,7 +97,7 @@ namespace Discord
channel = user.PrivateChannel;
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.Update(response);
}
@@ -266,13 +265,13 @@ namespace Discord
var nonce = GenerateNonce();
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];
msg.Update(new API.Message
{
Content = blockText,
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,
IsTextToSpeech = isTextToSpeech
});
@@ -513,13 +512,13 @@ namespace Discord
}

//Profile
public Task<EditProfileResponse> EditProfile(string currentPassword,
public Task<EditProfileResponse> EditProfile(string currentPassword = "",
string username = null, string email = null, string password = null,
AvatarImageType avatarType = AvatarImageType.Png, byte[] avatar = null)
{
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);
}



+ 0
- 101
src/Discord.Net/DiscordClient.Events.cs View File

@@ -2,50 +2,6 @@

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 Server Server { get; }
@@ -148,45 +104,9 @@ namespace Discord
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
{
//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
public event EventHandler<ServerEventArgs> ServerCreated;
private void RaiseServerCreated(Server server)
@@ -342,26 +262,5 @@ namespace Discord
if (UserIsSpeaking != null)
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);
}
}
}

+ 17
- 15
src/Discord.Net/DiscordClient.Voice.cs View File

@@ -1,6 +1,7 @@
using Discord.Helpers;
using Discord.WebSockets;
using System;
using System.Threading;
using System.Threading.Tasks;

namespace Discord
@@ -8,30 +9,31 @@ namespace Discord
public partial class DiscordClient
{
public Task JoinVoiceServer(Channel channel)
=> JoinVoiceServer(channel?.Server, channel);
public Task JoinVoiceServer(string serverId, string channelId)
=> JoinVoiceServer(_servers[serverId], _channels[channelId]);
=> JoinVoiceServer(channel?.ServerId, channel?.Id);
public Task JoinVoiceServer(Server server, string channelId)
=> JoinVoiceServer(server, _channels[channelId]);
private async Task JoinVoiceServer(Server server, Channel channel)
=> JoinVoiceServer(server?.Id, channelId);
public async Task JoinVoiceServer(string serverId, string channelId)
{
CheckReady(checkVoice: true);
if (server == null) throw new ArgumentNullException(nameof(server));
if (channel == null) throw new ArgumentNullException(nameof(channel));
if (serverId == null) throw new ArgumentNullException(nameof(serverId));
if (channelId == null) throw new ArgumentNullException(nameof(channelId));

await LeaveVoiceServer().ConfigureAwait(false);
_voiceSocket.SetChannel(server, channel);
_dataSocket.SendJoinVoice(server.Id, channel.Id);
_voiceSocket.SetChannel(serverId, channelId);
_dataSocket.SendJoinVoice(serverId, channelId);

CancellationTokenSource tokenSource = new CancellationTokenSource();
try
{
await Task.Run(() => _voiceSocket.WaitForConnection())
.Timeout(_config.ConnectionTimeout)
await Task.Run(() => _voiceSocket.WaitForConnection(tokenSource.Token))
.Timeout(_config.ConnectionTimeout, tokenSource)
.ConfigureAwait(false);
}
catch (TaskCanceledException)
catch (TimeoutException)
{
tokenSource.Cancel();
await LeaveVoiceServer().ConfigureAwait(false);
throw;
}
}
public async Task LeaveVoiceServer()
@@ -40,11 +42,11 @@ namespace Discord

if (_voiceSocket.State != WebSocketState.Disconnected)
{
var server = _voiceSocket.CurrentVoiceServer;
if (server != null)
var serverId = _voiceSocket.CurrentServerId;
if (serverId != null)
{
await _voiceSocket.Disconnect().ConfigureAwait(false);
_dataSocket.SendLeaveVoice(server.Id);
_dataSocket.SendLeaveVoice(serverId);
}
}
}


+ 401
- 607
src/Discord.Net/DiscordClient.cs
File diff suppressed because it is too large
View File


+ 27
- 1
src/Discord.Net/Helpers/TaskHelper.cs View File

@@ -1,4 +1,6 @@
using System.Threading.Tasks;
using System;
using System.Threading;
using System.Threading.Tasks;

namespace Discord.Helpers
{
@@ -32,5 +34,29 @@ namespace Discord.Helpers
else
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();
}
}
}
}

+ 0
- 10
src/Discord.Net/Models/Channel.cs View File

@@ -17,7 +17,6 @@ namespace Discord

private readonly DiscordClient _client;
private ConcurrentDictionary<string, bool> _messages;
private ConcurrentDictionary<uint, string> _ssrcMapping;

/// <summary> Returns the unique identifier for this channel. </summary>
public string Id { get; }
@@ -70,8 +69,6 @@ namespace Discord
{
Name = model.Name;
Type = model.Type;
if (Type == ChannelTypes.Voice && _ssrcMapping == null)
_ssrcMapping = new ConcurrentDictionary<uint, string>();
}
internal void Update(API.ChannelInfo model)
{
@@ -104,12 +101,5 @@ namespace Discord
bool ignored;
return _messages.TryRemove(messageId, out ignored);
}

internal string GetUserId(uint ssrc)
{
string userId = null;
_ssrcMapping.TryGetValue(ssrc, out userId);
return userId;
}
}
}

+ 1
- 1
src/Discord.Net/WebSockets/Data/DataWebSocket.cs View File

@@ -12,7 +12,7 @@ namespace Discord.WebSockets.Data
public string SessionId => _sessionId;
private string _sessionId;

public DataWebSocket(DiscordClient client)
public DataWebSocket(DiscordBaseClient client)
: base(client)
{
}


+ 1
- 1
src/Discord.Net/WebSockets/Data/DataWebSockets.Events.cs View File

@@ -16,7 +16,7 @@ namespace Discord.WebSockets.Data

internal partial class DataWebSocket
{
public event EventHandler<WebSocketEventEventArgs> ReceivedEvent;
internal event EventHandler<WebSocketEventEventArgs> ReceivedEvent;
private void RaiseReceivedEvent(string type, JToken payload)
{
if (ReceivedEvent != null)


+ 1
- 1
src/Discord.Net/WebSockets/Voice/VoiceWebSocket.Events.cs View File

@@ -2,7 +2,7 @@

namespace Discord.WebSockets.Voice
{
public sealed class IsTalkingEventArgs : EventArgs
internal sealed class IsTalkingEventArgs : EventArgs
{
public readonly string UserId;
public readonly bool IsSpeaking;


+ 23
- 17
src/Discord.Net/WebSockets/Voice/VoiceWebSocket.cs View File

@@ -15,7 +15,7 @@ using System.Threading.Tasks;

namespace Discord.WebSockets.Voice
{
internal partial class VoiceWebSocket : WebSocket
internal partial class VoiceWebSocket : WebSocket
{
private const int MaxOpusSize = 4000;
private const string EncryptedMode = "xsalsa20_poly1305";
@@ -27,6 +27,7 @@ namespace Discord.WebSockets.Voice
private readonly ConcurrentDictionary<uint, OpusDecoder> _decoders;
private ManualResetEventSlim _connectWaitOnLogin;
private uint _ssrc;
private ConcurrentDictionary<uint, string> _ssrcMapping;

private ConcurrentQueue<byte[]> _sendQueue;
private ManualResetEventSlim _sendQueueWait, _sendQueueEmptyWait;
@@ -35,17 +36,16 @@ namespace Discord.WebSockets.Voice
private bool _isClearing, _isEncrypted;
private byte[] _secretKey, _encodingBuffer;
private ushort _sequence;
private string _userId, _sessionId, _token, _encryptionMode;
private Server _server;
private Channel _channel;
private string _serverId, _channelId, _userId, _sessionId, _token, _encryptionMode;

#if USE_THREAD
private Thread _sendThread;
private Thread _sendThread, _receiveThread;
#endif

public Server CurrentVoiceServer => _server;
public string CurrentServerId => _serverId;
public string CurrentChannelId => _channelId;

public VoiceWebSocket(DiscordClient client)
public VoiceWebSocket(DiscordBaseClient client)
: base(client)
{
_rand = new Random();
@@ -56,12 +56,14 @@ namespace Discord.WebSockets.Voice
_sendQueueEmptyWait = new ManualResetEventSlim(true);
_targetAudioBufferLength = client.Config.VoiceBufferLength / 20; //20 ms frames
_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;
_channel = channel;
_serverId = serverId;
_channelId = channelId;
}
public async Task Login(string userId, string sessionId, string token, CancellationToken cancelToken)
{
@@ -113,7 +115,7 @@ namespace Discord.WebSockets.Voice
#endif
LoginCommand msg = new LoginCommand();
msg.Payload.ServerId = _server.Id;
msg.Payload.ServerId = _serverId;
msg.Payload.SessionId = _sessionId;
msg.Payload.Token = _token;
msg.Payload.UserId = _userId;
@@ -122,6 +124,8 @@ namespace Discord.WebSockets.Voice
#if USE_THREAD
_sendThread = new Thread(new ThreadStart(() => SendVoiceAsync(_cancelToken)));
_sendThread.Start();
_receiveThread = new Thread(new ThreadStart(() => ReceiveVoiceAsync(_cancelToken)));
_receiveThread.Start();
#if !DNXCORE50
return new Task[] { WatcherAsync() }.Concat(base.Run()).ToArray();
#else
@@ -141,9 +145,11 @@ namespace Discord.WebSockets.Voice
{
#if USE_THREAD
_sendThread.Join();
_receiveThread.Join();
_sendThread = null;
_receiveThread = null;
#endif
OpusDecoder decoder;
foreach (var pair in _decoders)
{
@@ -274,9 +280,9 @@ namespace Discord.WebSockets.Voice
/*if (_logLevel >= LogMessageSeverity.Debug)
RaiseOnLog(LogMessageSeverity.Debug, $"Received {buffer.Length - 12} bytes.");*/

string userId = _channel.GetUserId(ssrc);
if (userId != null)
RaiseOnPacket(userId, _channel.Id, result, resultOffset, resultLength);
string userId;
if (_ssrcMapping.TryGetValue(ssrc, out userId))
RaiseOnPacket(userId, _channelId, result, resultOffset, resultLength);
}
}
#if USE_THREAD || DNXCORE50
@@ -568,9 +574,9 @@ namespace Discord.WebSockets.Voice
{
_sendQueueEmptyWait.Wait(_cancelToken);
}
public void WaitForConnection()
public void WaitForConnection(CancellationToken cancelToken)
{
_connectedEvent.Wait();
_connectedEvent.Wait(cancelToken);
}
}
}

+ 1
- 1
src/Discord.Net/WebSockets/WebSocket.Events.cs View File

@@ -2,7 +2,7 @@

namespace Discord.WebSockets
{
internal partial class WebSocket
internal abstract partial class WebSocket
{
public event EventHandler Connected;
private void RaiseConnected()


+ 6
- 6
src/Discord.Net/WebSockets/WebSocket.cs View File

@@ -35,7 +35,7 @@ namespace Discord.WebSockets
internal abstract partial class WebSocket
{
protected readonly IWebSocketEngine _engine;
protected readonly DiscordClient _client;
protected readonly DiscordBaseClient _client;
protected readonly LogMessageSeverity _logLevel;
protected readonly ManualResetEventSlim _connectedEvent;

@@ -57,7 +57,7 @@ namespace Discord.WebSockets
public WebSocketState State => (WebSocketState)_state;
protected int _state;

public WebSocket(DiscordClient client)
public WebSocket(DiscordBaseClient client)
{
_client = client;
_logLevel = client.Config.LogLevel;
@@ -131,9 +131,9 @@ namespace Discord.WebSockets
_disconnectState = (WebSocketState)oldState;
_disconnectReason = ex != null ? ExceptionDispatchInfo.Capture(ex) : null;

if (_disconnectState == WebSocketState.Connecting) //_runTask was never made
await Cleanup();
_cancelTokenSource.Cancel();
if (_disconnectState == WebSocketState.Connecting) //_runTask was never made
await Cleanup().ConfigureAwait(false);
}

if (!skipAwait)
@@ -161,8 +161,8 @@ namespace Discord.WebSockets
//Wait for the remaining tasks to complete
try { await allTasks.ConfigureAwait(false); }
catch { }
//Clean up state variables and raise disconnect event
//Start cleanup
await Cleanup().ConfigureAwait(false);
}
protected virtual Task[] Run()


Loading…
Cancel
Save