Browse Source

Rewrote AudioClient, fixed several async issues, removed most sealed keywords.

tags/docs-0.9
RogueException 9 years ago
parent
commit
0db0675cb5
100 changed files with 675 additions and 395 deletions
  1. +5
    -5
      src/Discord.Net.Audio.Net45/Discord.Net.Audio.csproj
  2. +167
    -99
      src/Discord.Net.Audio/AudioClient.cs
  3. +242
    -0
      src/Discord.Net.Audio/AudioClient.cs.old
  4. +70
    -69
      src/Discord.Net.Audio/AudioService.cs
  5. +36
    -26
      src/Discord.Net.Audio/Net/VoiceSocket.cs
  6. +0
    -72
      src/Discord.Net.Audio/SimpleAudioClient.cs
  7. +29
    -0
      src/Discord.Net.Audio/VirtualClient.cs
  8. +2
    -1
      src/Discord.Net.Commands/Command.cs
  9. +12
    -11
      src/Discord.Net.Commands/CommandBuilder.cs
  10. +2
    -2
      src/Discord.Net.Commands/CommandParameter.cs
  11. +1
    -1
      src/Discord.Net.Modules/ModuleManager.cs
  12. +1
    -1
      src/Discord.Net/API/Client/Common/Channel.cs
  13. +1
    -1
      src/Discord.Net/API/Client/Common/ExtendedGuild.cs
  14. +1
    -1
      src/Discord.Net/API/Client/Common/Guild.cs
  15. +1
    -1
      src/Discord.Net/API/Client/Common/InviteReference.cs
  16. +1
    -1
      src/Discord.Net/API/Client/Common/MemberPresence.cs
  17. +5
    -5
      src/Discord.Net/API/Client/Common/Message.cs
  18. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Commands/Heartbeat.cs
  19. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Commands/Identify.cs
  20. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Commands/RequestMembers.cs
  21. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Commands/Resume.cs
  22. +2
    -2
      src/Discord.Net/API/Client/GatewaySocket/Commands/UpdateStatus.cs
  23. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Commands/UpdateVoice.cs
  24. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Events/ChannelCreate.cs
  25. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Events/ChannelDelete.cs
  26. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Events/ChannelUpdate.cs
  27. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Events/GuildBanAdd.cs
  28. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Events/GuildBanRemove.cs
  29. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Events/GuildCreate.cs
  30. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Events/GuildDelete.cs
  31. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Events/GuildEmojisUpdate.cs
  32. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Events/GuildIntegrationsUpdate.cs
  33. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Events/GuildMemberAdd.cs
  34. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Events/GuildMemberRemove.cs
  35. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Events/GuildMemberUpdate.cs
  36. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Events/GuildMembersChunk.cs
  37. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Events/GuildRoleCreate.cs
  38. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Events/GuildRoleDelete.cs
  39. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Events/GuildRoleUpdate.cs
  40. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Events/GuildUpdate.cs
  41. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Events/MessageAck.cs
  42. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Events/MessageCreate.cs
  43. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Events/MessageDelete.cs
  44. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Events/MessageUpdate.cs
  45. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Events/PresenceUpdate.cs
  46. +2
    -2
      src/Discord.Net/API/Client/GatewaySocket/Events/Ready.cs
  47. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Events/Redirect.cs
  48. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Events/Resumed.cs
  49. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Events/TypingStart.cs
  50. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Events/UserSettingsUpdate.cs
  51. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Events/UserUpdate.cs
  52. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Events/VoiceServerUpdate.cs
  53. +1
    -1
      src/Discord.Net/API/Client/GatewaySocket/Events/VoiceStateUpdate.cs
  54. +1
    -1
      src/Discord.Net/API/Client/IWebSocketMessage.cs
  55. +1
    -1
      src/Discord.Net/API/Client/Rest/AcceptInvite.cs
  56. +1
    -1
      src/Discord.Net/API/Client/Rest/AckMessage.cs
  57. +1
    -1
      src/Discord.Net/API/Client/Rest/AddChannelPermission.cs
  58. +1
    -1
      src/Discord.Net/API/Client/Rest/AddGuildBan.cs
  59. +1
    -1
      src/Discord.Net/API/Client/Rest/CreateChannel.cs
  60. +1
    -1
      src/Discord.Net/API/Client/Rest/CreateGuild.cs
  61. +1
    -1
      src/Discord.Net/API/Client/Rest/CreateInvite.cs
  62. +1
    -1
      src/Discord.Net/API/Client/Rest/CreatePrivateChannel.cs
  63. +1
    -1
      src/Discord.Net/API/Client/Rest/CreateRole.cs
  64. +1
    -1
      src/Discord.Net/API/Client/Rest/DeleteChannel.cs
  65. +1
    -1
      src/Discord.Net/API/Client/Rest/DeleteInvite.cs
  66. +1
    -1
      src/Discord.Net/API/Client/Rest/DeleteMessage.cs
  67. +1
    -1
      src/Discord.Net/API/Client/Rest/DeleteRole.cs
  68. +2
    -2
      src/Discord.Net/API/Client/Rest/Gateway.cs
  69. +1
    -1
      src/Discord.Net/API/Client/Rest/GetBans.cs
  70. +1
    -1
      src/Discord.Net/API/Client/Rest/GetInvite.cs
  71. +1
    -1
      src/Discord.Net/API/Client/Rest/GetInvites.cs
  72. +1
    -1
      src/Discord.Net/API/Client/Rest/GetMessages.cs
  73. +2
    -2
      src/Discord.Net/API/Client/Rest/GetVoiceRegions.cs
  74. +5
    -5
      src/Discord.Net/API/Client/Rest/GetWidget.cs
  75. +1
    -1
      src/Discord.Net/API/Client/Rest/KickMember.cs
  76. +1
    -1
      src/Discord.Net/API/Client/Rest/LeaveGuild.cs
  77. +2
    -2
      src/Discord.Net/API/Client/Rest/Login.cs
  78. +1
    -1
      src/Discord.Net/API/Client/Rest/Logout.cs
  79. +2
    -2
      src/Discord.Net/API/Client/Rest/PruneMembers.cs
  80. +1
    -1
      src/Discord.Net/API/Client/Rest/RemoveChannelPermission.cs
  81. +1
    -1
      src/Discord.Net/API/Client/Rest/RemoveGuildBan.cs
  82. +2
    -2
      src/Discord.Net/API/Client/Rest/ReorderChannels.cs
  83. +2
    -2
      src/Discord.Net/API/Client/Rest/ReorderRoles.cs
  84. +1
    -1
      src/Discord.Net/API/Client/Rest/SendFile.cs
  85. +1
    -1
      src/Discord.Net/API/Client/Rest/SendIsTyping.cs
  86. +1
    -1
      src/Discord.Net/API/Client/Rest/SendMessage.cs
  87. +1
    -1
      src/Discord.Net/API/Client/Rest/UpdateChannel.cs
  88. +1
    -1
      src/Discord.Net/API/Client/Rest/UpdateGuild.cs
  89. +1
    -1
      src/Discord.Net/API/Client/Rest/UpdateMember.cs
  90. +1
    -1
      src/Discord.Net/API/Client/Rest/UpdateMessage.cs
  91. +1
    -1
      src/Discord.Net/API/Client/Rest/UpdateProfile.cs
  92. +1
    -1
      src/Discord.Net/API/Client/Rest/UpdateRole.cs
  93. +1
    -1
      src/Discord.Net/API/Client/VoiceSocket/Commands/Heartbeat.cs
  94. +1
    -1
      src/Discord.Net/API/Client/VoiceSocket/Commands/Identify.cs
  95. +2
    -2
      src/Discord.Net/API/Client/VoiceSocket/Commands/SelectProtocol.cs
  96. +1
    -1
      src/Discord.Net/API/Client/VoiceSocket/Commands/SetSpeaking.cs
  97. +1
    -1
      src/Discord.Net/API/Client/VoiceSocket/Events/Ready.cs
  98. +1
    -1
      src/Discord.Net/API/Client/VoiceSocket/Events/SessionDescription.cs
  99. +1
    -1
      src/Discord.Net/API/Client/VoiceSocket/Events/Speaking.cs
  100. +4
    -4
      src/Discord.Net/API/Converters.cs

+ 5
- 5
src/Discord.Net.Audio.Net45/Discord.Net.Audio.csproj View File

@@ -62,8 +62,8 @@
<Compile Include="..\Discord.Net.Audio\InternalIsSpeakingEventArgs.cs"> <Compile Include="..\Discord.Net.Audio\InternalIsSpeakingEventArgs.cs">
<Link>InternalIsSpeakingEventArgs.cs</Link> <Link>InternalIsSpeakingEventArgs.cs</Link>
</Compile> </Compile>
<Compile Include="..\Discord.Net.Audio\Net\VoiceWebSocket.cs">
<Link>Net\VoiceWebSocket.cs</Link>
<Compile Include="..\Discord.Net.Audio\Net\VoiceSocket.cs">
<Link>Net\VoiceSocket.cs</Link>
</Compile> </Compile>
<Compile Include="..\Discord.Net.Audio\Opus\OpusConverter.cs"> <Compile Include="..\Discord.Net.Audio\Opus\OpusConverter.cs">
<Link>Opus\OpusConverter.cs</Link> <Link>Opus\OpusConverter.cs</Link>
@@ -74,15 +74,15 @@
<Compile Include="..\Discord.Net.Audio\Opus\OpusEncoder.cs"> <Compile Include="..\Discord.Net.Audio\Opus\OpusEncoder.cs">
<Link>Opus\OpusEncoder.cs</Link> <Link>Opus\OpusEncoder.cs</Link>
</Compile> </Compile>
<Compile Include="..\Discord.Net.Audio\SimpleAudioClient.cs">
<Link>SimpleAudioClient.cs</Link>
</Compile>
<Compile Include="..\Discord.Net.Audio\Sodium\SecretBox.cs"> <Compile Include="..\Discord.Net.Audio\Sodium\SecretBox.cs">
<Link>Sodium\SecretBox.cs</Link> <Link>Sodium\SecretBox.cs</Link>
</Compile> </Compile>
<Compile Include="..\Discord.Net.Audio\UserIsTalkingEventArgs.cs"> <Compile Include="..\Discord.Net.Audio\UserIsTalkingEventArgs.cs">
<Link>UserIsTalkingEventArgs.cs</Link> <Link>UserIsTalkingEventArgs.cs</Link>
</Compile> </Compile>
<Compile Include="..\Discord.Net.Audio\VirtualClient.cs">
<Link>VirtualClient.cs</Link>
</Compile>
<Compile Include="..\Discord.Net.Audio\VoiceBuffer.cs"> <Compile Include="..\Discord.Net.Audio\VoiceBuffer.cs">
<Link>VoiceBuffer.cs</Link> <Link>VoiceBuffer.cs</Link>
</Compile> </Compile>


+ 167
- 99
src/Discord.Net.Audio/AudioClient.cs View File

@@ -1,9 +1,12 @@
using Discord.API.Client.GatewaySocket; using Discord.API.Client.GatewaySocket;
using Discord.API.Client.Rest;
using Discord.Logging; using Discord.Logging;
using Discord.Net.Rest;
using Discord.Net.WebSockets; using Discord.Net.WebSockets;
using Newtonsoft.Json; using Newtonsoft.Json;
using Nito.AsyncEx; using Nito.AsyncEx;
using System; using System;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@@ -41,124 +44,190 @@ namespace Discord.Audio
} }
} }


private readonly DiscordConfig _config;
private readonly AsyncLock _connectionLock; private readonly AsyncLock _connectionLock;
private readonly JsonSerializer _serializer;
private CancellationTokenSource _cancelTokenSource;
private readonly TaskManager _taskManager;
private ConnectionState _gatewayState;


internal AudioService Service { get; }
internal Logger Logger { get; } internal Logger Logger { get; }

/// <summary> Gets the unique identifier for this client. </summary>
public int Id { get; } public int Id { get; }
/// <summary> Gets the service managing this client. </summary>
public AudioService Service { get; }
/// <summary> Gets the configuration object used to make this client. </summary>
public AudioServiceConfig Config { get; }
/// <summary> Gets the internal RestClient for the Client API endpoint. </summary>
public RestClient ClientAPI { get; }
/// <summary> Gets the internal WebSocket for the Gateway event stream. </summary>
public GatewaySocket GatewaySocket { get; } public GatewaySocket GatewaySocket { get; }
public VoiceWebSocket VoiceSocket { get; }
/// <summary> Gets the internal WebSocket for the Voice control stream. </summary>
public VoiceSocket VoiceSocket { get; }
/// <summary> Gets the JSON serializer used by this client. </summary>
public JsonSerializer Serializer { get; }
/// <summary> </summary>
public Stream OutputStream { get; } public Stream OutputStream { get; }


/// <summary> Gets a cancellation token that triggers when the client is manually disconnected. </summary>
public CancellationToken CancelToken { get; private set; }
/// <summary> Gets the session id for the current connection. </summary>
public string SessionId { get; private set; }

/// <summary> Gets the current state of this client. </summary>
public ConnectionState State => VoiceSocket.State; public ConnectionState State => VoiceSocket.State;
/// <summary> Gets the server this client is bound to. </summary>
public Server Server => VoiceSocket.Server; public Server Server => VoiceSocket.Server;
/// <summary> Gets the channel </summary>
public Channel Channel => VoiceSocket.Channel; public Channel Channel => VoiceSocket.Channel;


public AudioClient(AudioService service, int clientId, Server server, GatewaySocket gatewaySocket, Logger logger)
public AudioClient(DiscordClient client, Server server, int id)
{ {
Service = service;
_serializer = service.Client.Serializer;
Id = clientId;
GatewaySocket = gatewaySocket;
Logger = logger;
OutputStream = new OutStream(this);
Id = id;
_config = client.Config;
Service = client.Audio();
Config = Service.Config;
Serializer = client.Serializer;
_gatewayState = (int)ConnectionState.Disconnected;


_connectionLock = new AsyncLock();
//Logging
Logger = client.Log.CreateLogger($"AudioClient #{id}");


GatewaySocket.ReceivedDispatch += OnReceivedDispatch;
//Async
_taskManager = new TaskManager(Cleanup, false);
_connectionLock = new AsyncLock();
CancelToken = new CancellationToken(true);


VoiceSocket = new VoiceWebSocket(service.Client, this, logger);
//Networking
if (Config.EnableMultiserver)
{
ClientAPI = new RestClient(_config, DiscordConfig.ClientAPIUrl, client.Log.CreateLogger($"ClientAPI #{id}"));
GatewaySocket = new GatewaySocket(_config, client.Serializer, client.Log.CreateLogger($"Gateway #{id}"));
GatewaySocket.Connected += (s, e) =>
{
if (_gatewayState == ConnectionState.Connecting)
EndGatewayConnect();
};
}
else
GatewaySocket = client.GatewaySocket;
GatewaySocket.ReceivedDispatch += (s, e) => OnReceivedEvent(e);
VoiceSocket = new VoiceSocket(_config, Config, client.Serializer, client.Log.CreateLogger($"Voice #{id}"));
VoiceSocket.Server = server; VoiceSocket.Server = server;

/*_voiceSocket.Connected += (s, e) => RaiseVoiceConnected();
_voiceSocket.Disconnected += async (s, e) =>
{
_voiceSocket.CurrentServerId;
if (voiceServerId != null)
_gatewaySocket.SendLeaveVoice(voiceServerId.Value);
await _voiceSocket.Disconnect().ConfigureAwait(false);
RaiseVoiceDisconnected(socket.CurrentServerId.Value, e);
if (e.WasUnexpected)
await socket.Reconnect().ConfigureAwait(false);
};*/

/*_voiceSocket.IsSpeaking += (s, e) =>
{
if (_voiceSocket.State == WebSocketState.Connected)
{
var user = _users[e.UserId, socket.CurrentServerId];
bool value = e.IsSpeaking;
if (user.IsSpeaking != value)
{
user.IsSpeaking = value;
var channel = _channels[_voiceSocket.CurrentChannelId];
RaiseUserIsSpeaking(user, channel, value);
if (Config.TrackActivity)
user.UpdateActivity();
}
}
};*/

/*this.Connected += (s, e) =>
{
_voiceSocket.ParentCancelToken = _cancelToken;
};*/
OutputStream = new OutStream(this);
} }


public async Task Join(Channel channel)
{
if (channel == null) throw new ArgumentNullException(nameof(channel));
if (channel.Type != ChannelType.Voice)
throw new ArgumentException("Channel must be a voice channel.", nameof(channel));
if (channel.Server != VoiceSocket.Server)
throw new ArgumentException("This is channel is not part of the current server.", nameof(channel));
if (channel == VoiceSocket.Channel) return;
if (VoiceSocket.Server == null)
throw new InvalidOperationException("This client has been closed.");
using (await _connectionLock.LockAsync().ConfigureAwait(false))
/// <summary> Connects to the Discord server with the provided token. </summary>
public async Task Connect()
{
if (Config.EnableMultiserver)
await BeginGatewayConnect().ConfigureAwait(false);
else
{ {
VoiceSocket.Channel = channel;

await Task.Run(() =>
var cancelSource = new CancellationTokenSource();
CancelToken = cancelSource.Token;
await _taskManager.Start(new Task[0], cancelSource).ConfigureAwait(false);
}
}
private async Task BeginGatewayConnect()
{
try
{
using (await _connectionLock.LockAsync().ConfigureAwait(false))
{ {
SendVoiceUpdate();
VoiceSocket.WaitForConnection(_cancelTokenSource.Token);
});
await Disconnect().ConfigureAwait(false);
_taskManager.ClearException();

ClientAPI.Token = Service.Client.ClientAPI.Token;

Stopwatch stopwatch = null;
if (_config.LogLevel >= LogSeverity.Verbose)
stopwatch = Stopwatch.StartNew();
_gatewayState = ConnectionState.Connecting;

var cancelSource = new CancellationTokenSource();
CancelToken = cancelSource.Token;
ClientAPI.CancelToken = CancelToken;
await GatewaySocket.Connect(ClientAPI, CancelToken).ConfigureAwait(false);

await _taskManager.Start(new Task[0], cancelSource).ConfigureAwait(false);
GatewaySocket.WaitForConnection(CancelToken);

if (_config.LogLevel >= LogSeverity.Verbose)
{
stopwatch.Stop();
double seconds = Math.Round(stopwatch.ElapsedTicks / (double)TimeSpan.TicksPerSecond, 2);
Logger.Verbose($"Connection took {seconds} sec");
}
}
}
catch (Exception ex)
{
await _taskManager.SignalError(ex).ConfigureAwait(false);
throw;
} }
} }
private void EndGatewayConnect()
{
_gatewayState = ConnectionState.Connected;
}
public async Task Connect(bool connectGateway)
/// <summary> Disconnects from the Discord server, canceling any pending requests. </summary>
public async Task Disconnect()
{ {
using (await _connectionLock.LockAsync().ConfigureAwait(false))
{
_cancelTokenSource = new CancellationTokenSource();
var cancelToken = _cancelTokenSource.Token;
VoiceSocket.ParentCancelToken = cancelToken;
await _taskManager.Stop(true).ConfigureAwait(false);
if (Config.EnableMultiserver)
ClientAPI.Token = null;
}
private async Task Cleanup()
{
var oldState = _gatewayState;
_gatewayState = ConnectionState.Disconnecting;


if (connectGateway)
if (Config.EnableMultiserver)
{
if (oldState == ConnectionState.Connected)
{ {
GatewaySocket.ParentCancelToken = cancelToken;
await GatewaySocket.Connect().ConfigureAwait(false);
GatewaySocket.WaitForConnection(cancelToken);
try { await ClientAPI.Send(new LogoutRequest()).ConfigureAwait(false); }
catch (OperationCanceledException) { }
} }

await GatewaySocket.Disconnect().ConfigureAwait(false);
ClientAPI.Token = null;
} }

var server = VoiceSocket.Server;
VoiceSocket.Server = null;
VoiceSocket.Channel = null;
if (Config.EnableMultiserver)
await Service.RemoveClient(server, this).ConfigureAwait(false);
SendVoiceUpdate(server.Id, null);

await VoiceSocket.Disconnect().ConfigureAwait(false);
if (Config.EnableMultiserver)
await GatewaySocket.Disconnect().ConfigureAwait(false);

_gatewayState = (int)ConnectionState.Disconnected;
} }


public async Task Disconnect()
public async Task Join(Channel channel)
{ {
if (channel == null) throw new ArgumentNullException(nameof(channel));
if (channel.Type != ChannelType.Voice)
throw new ArgumentException("Channel must be a voice channel.", nameof(channel));
if (channel == VoiceSocket.Channel) return;
var server = channel.Server;
if (server != VoiceSocket.Server)
throw new ArgumentException("This is channel is not part of the current server.", nameof(channel));
if (VoiceSocket.Server == null)
throw new InvalidOperationException("This client has been closed.");

SendVoiceUpdate(channel.Server.Id, channel.Id);
using (await _connectionLock.LockAsync().ConfigureAwait(false)) using (await _connectionLock.LockAsync().ConfigureAwait(false))
{
await Service.RemoveClient(VoiceSocket.Server, this).ConfigureAwait(false);
VoiceSocket.Channel = null;
SendVoiceUpdate();
await VoiceSocket.Disconnect();
}
await Task.Run(() => VoiceSocket.WaitForConnection(CancelToken));
} }


private async void OnReceivedDispatch(object sender, WebSocketEventEventArgs e)
private async void OnReceivedEvent(WebSocketEventEventArgs e)
{ {
try try
{ {
@@ -166,11 +235,11 @@ namespace Discord.Audio
{ {
case "VOICE_STATE_UPDATE": case "VOICE_STATE_UPDATE":
{ {
var data = e.Payload.ToObject<VoiceStateUpdateEvent>(_serializer);
var data = e.Payload.ToObject<VoiceStateUpdateEvent>(Serializer);
if (data.GuildId == VoiceSocket.Server?.Id && data.UserId == Service.Client.CurrentUser?.Id) if (data.GuildId == VoiceSocket.Server?.Id && data.UserId == Service.Client.CurrentUser?.Id)
{ {
if (data.ChannelId == null) if (data.ChannelId == null)
await Disconnect();
await Disconnect().ConfigureAwait(false);
else else
{ {
var channel = Service.Client.GetChannel(data.ChannelId.Value); var channel = Service.Client.GetChannel(data.ChannelId.Value);
@@ -179,7 +248,7 @@ namespace Discord.Audio
else else
{ {
Logger.Warning("VOICE_STATE_UPDATE referenced an unknown channel, disconnecting."); Logger.Warning("VOICE_STATE_UPDATE referenced an unknown channel, disconnecting.");
await Disconnect();
await Disconnect().ConfigureAwait(false);
} }
} }
} }
@@ -187,13 +256,16 @@ namespace Discord.Audio
break; break;
case "VOICE_SERVER_UPDATE": case "VOICE_SERVER_UPDATE":
{ {
var data = e.Payload.ToObject<VoiceServerUpdateEvent>(_serializer);
var data = e.Payload.ToObject<VoiceServerUpdateEvent>(Serializer);
if (data.GuildId == VoiceSocket.Server?.Id) if (data.GuildId == VoiceSocket.Server?.Id)
{ {
var client = Service.Client; var client = Service.Client;
VoiceSocket.Token = data.Token;
VoiceSocket.Host = "wss://" + e.Payload.Value<string>("endpoint").Split(':')[0];
await VoiceSocket.Connect().ConfigureAwait(false);
var id = client.CurrentUser?.Id;
if (id != null)
{
var host = "wss://" + e.Payload.Value<string>("endpoint").Split(':')[0];
await VoiceSocket.Connect(host, data.Token, id.Value, GatewaySocket.SessionId, CancelToken).ConfigureAwait(false);
}
} }
} }
break; break;
@@ -233,15 +305,11 @@ namespace Discord.Audio
VoiceSocket.WaitForQueue(); VoiceSocket.WaitForQueue();
} }


private void SendVoiceUpdate()
public void SendVoiceUpdate(ulong? serverId, ulong? channelId)
{ {
var serverId = VoiceSocket.Server?.Id;
if (serverId != null)
{
GatewaySocket.SendUpdateVoice(serverId, VoiceSocket.Channel?.Id,
(Service.Config.Mode | AudioMode.Outgoing) == 0,
(Service.Config.Mode | AudioMode.Incoming) == 0);
}
GatewaySocket.SendUpdateVoice(serverId, channelId,
(Service.Config.Mode | AudioMode.Outgoing) == 0,
(Service.Config.Mode | AudioMode.Incoming) == 0);
} }
} }
} }

+ 242
- 0
src/Discord.Net.Audio/AudioClient.cs.old View File

@@ -0,0 +1,242 @@
using Discord.API.Client.GatewaySocket;
using Discord.Logging;
using Discord.Net.Rest;
using Discord.Net.WebSockets;
using Newtonsoft.Json;
using Nito.AsyncEx;
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace Discord.Audio
{
internal class AudioClient : IAudioClient
{
private class OutStream : Stream
{
public override bool CanRead => false;
public override bool CanSeek => false;
public override bool CanWrite => true;

private readonly AudioClient _client;

internal OutStream(AudioClient client)
{
_client = client;
}

public override long Length { get { throw new InvalidOperationException(); } }
public override long Position
{
get { throw new InvalidOperationException(); }
set { throw new InvalidOperationException(); }
}
public override void Flush() { throw new InvalidOperationException(); }
public override long Seek(long offset, SeekOrigin origin) { throw new InvalidOperationException(); }
public override void SetLength(long value) { throw new InvalidOperationException(); }
public override int Read(byte[] buffer, int offset, int count) { throw new InvalidOperationException(); }
public override void Write(byte[] buffer, int offset, int count)
{
_client.Send(buffer, offset, count);
}
}
private readonly JsonSerializer _serializer;
private readonly bool _ownsGateway;
private TaskManager _taskManager;
private CancellationToken _cancelToken;

internal AudioService Service { get; }
internal Logger Logger { get; }
public int Id { get; }
public GatewaySocket GatewaySocket { get; }
public VoiceSocket VoiceSocket { get; }
public Stream OutputStream { get; }

public ConnectionState State => VoiceSocket.State;
public Server Server => VoiceSocket.Server;
public Channel Channel => VoiceSocket.Channel;

public AudioClient(AudioService service, int clientId, Server server, GatewaySocket gatewaySocket, bool ownsGateway, Logger logger)
{
Service = service;
_serializer = service.Client.Serializer;
Id = clientId;
GatewaySocket = gatewaySocket;
_ownsGateway = ownsGateway;
Logger = logger;
OutputStream = new OutStream(this);
_taskManager = new TaskManager(Cleanup, true);

GatewaySocket.ReceivedDispatch += OnReceivedDispatch;

VoiceSocket = new VoiceSocket(service.Client.Config, service.Config, service.Client.Serializer, logger);
VoiceSocket.Server = server;

/*_voiceSocket.Connected += (s, e) => RaiseVoiceConnected();
_voiceSocket.Disconnected += async (s, e) =>
{
_voiceSocket.CurrentServerId;
if (voiceServerId != null)
_gatewaySocket.SendLeaveVoice(voiceServerId.Value);
await _voiceSocket.Disconnect().ConfigureAwait(false);
RaiseVoiceDisconnected(socket.CurrentServerId.Value, e);
if (e.WasUnexpected)
await socket.Reconnect().ConfigureAwait(false);
};*/

/*_voiceSocket.IsSpeaking += (s, e) =>
{
if (_voiceSocket.State == WebSocketState.Connected)
{
var user = _users[e.UserId, socket.CurrentServerId];
bool value = e.IsSpeaking;
if (user.IsSpeaking != value)
{
user.IsSpeaking = value;
var channel = _channels[_voiceSocket.CurrentChannelId];
RaiseUserIsSpeaking(user, channel, value);
if (Config.TrackActivity)
user.UpdateActivity();
}
}
};*/

/*this.Connected += (s, e) =>
{
_voiceSocket.ParentCancelToken = _cancelToken;
};*/
}

public async Task Join(Channel channel)
{
if (channel == null) throw new ArgumentNullException(nameof(channel));
if (channel.Type != ChannelType.Voice)
throw new ArgumentException("Channel must be a voice channel.", nameof(channel));
if (channel.Server != VoiceSocket.Server)
throw new ArgumentException("This is channel is not part of the current server.", nameof(channel));
if (channel == VoiceSocket.Channel) return;
if (VoiceSocket.Server == null)
throw new InvalidOperationException("This client has been closed.");

SendVoiceUpdate(channel.Server.Id, channel.Id);
await Task.Run(() => VoiceSocket.WaitForConnection(_cancelToken));
}
public async Task Connect(RestClient rest = null)
{
var cancelSource = new CancellationTokenSource();
_cancelToken = cancelSource.Token;

Task[] tasks;
if (rest != null)
tasks = new Task[] { GatewaySocket.Connect(rest, _cancelToken) };
else
tasks = new Task[0];

await _taskManager.Start(tasks, cancelSource);
}

public Task Disconnect() => _taskManager.Stop(true);

private async Task Cleanup()
{
var server = VoiceSocket.Server;
VoiceSocket.Server = null;
VoiceSocket.Channel = null;

await Service.RemoveClient(server, this).ConfigureAwait(false);
SendVoiceUpdate(server.Id, null);

await VoiceSocket.Disconnect().ConfigureAwait(false);
if (_ownsGateway)
await GatewaySocket.Disconnect().ConfigureAwait(false);
}

private async void OnReceivedDispatch(object sender, WebSocketEventEventArgs e)
{
try
{
switch (e.Type)
{
case "VOICE_STATE_UPDATE":
{
var data = e.Payload.ToObject<VoiceStateUpdateEvent>(_serializer);
if (data.GuildId == VoiceSocket.Server?.Id && data.UserId == Service.Client.CurrentUser?.Id)
{
if (data.ChannelId == null)
await Disconnect().ConfigureAwait(false);
else
{
var channel = Service.Client.GetChannel(data.ChannelId.Value);
if (channel != null)
VoiceSocket.Channel = channel;
else
{
Logger.Warning("VOICE_STATE_UPDATE referenced an unknown channel, disconnecting.");
await Disconnect().ConfigureAwait(false);
}
}
}
}
break;
case "VOICE_SERVER_UPDATE":
{
var data = e.Payload.ToObject<VoiceServerUpdateEvent>(_serializer);
if (data.GuildId == VoiceSocket.Server?.Id)
{
var client = Service.Client;
var id = client.CurrentUser?.Id;
if (id != null)
{
var host = "wss://" + e.Payload.Value<string>("endpoint").Split(':')[0];
await VoiceSocket.Connect(host, data.Token, id.Value, GatewaySocket.SessionId, _cancelToken).ConfigureAwait(false);
}
}
}
break;
}
}
catch (Exception ex)
{
Logger.Error($"Error handling {e.Type} event", ex);
}
}

/// <summary> Sends a PCM frame to the voice server. Will block until space frees up in the outgoing buffer. </summary>
/// <param name="data">PCM frame to send. This must be a single or collection of uncompressed 48Kz monochannel 20ms PCM frames. </param>
/// <param name="count">Number of bytes in this frame. </param>
public void Send(byte[] data, int offset, int count)
{
if (data == null) throw new ArgumentException(nameof(data));
if (count < 0) throw new ArgumentOutOfRangeException(nameof(count));
if (offset < 0) throw new ArgumentOutOfRangeException(nameof(count));
if (VoiceSocket.Server == null) return; //Has been closed
if (count == 0) return;

VoiceSocket.SendPCMFrames(data, offset, count);
}

/// <summary> Clears the PCM buffer. </summary>
public void Clear()
{
if (VoiceSocket.Server == null) return; //Has been closed
VoiceSocket.ClearPCMFrames();
}

/// <summary> Returns a task that completes once the voice output buffer is empty. </summary>
public void Wait()
{
if (VoiceSocket.Server == null) return; //Has been closed
VoiceSocket.WaitForQueue();
}

public void SendVoiceUpdate(ulong? serverId, ulong? channelId)
{
GatewaySocket.SendUpdateVoice(serverId, channelId,
(Service.Config.Mode | AudioMode.Outgoing) == 0,
(Service.Config.Mode | AudioMode.Incoming) == 0);
}
}
}

+ 70
- 69
src/Discord.Net.Audio/AudioService.cs View File

@@ -1,4 +1,4 @@
using Discord.Net.WebSockets;
using Nito.AsyncEx;
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Linq; using System.Linq;
@@ -8,8 +8,10 @@ namespace Discord.Audio
{ {
public class AudioService : IService public class AudioService : IService
{ {
private AudioClient _defaultClient;
private ConcurrentDictionary<ulong, IAudioClient> _voiceClients;
private readonly AsyncLock _asyncLock;
private AudioClient _defaultClient; //Only used for single server
private VirtualClient _currentClient; //Only used for single server
private ConcurrentDictionary<ulong, AudioClient> _voiceClients;
private ConcurrentDictionary<User, bool> _talkingUsers; private ConcurrentDictionary<User, bool> _talkingUsers;
private int _nextClientId; private int _nextClientId;


@@ -30,18 +32,20 @@ namespace Discord.Audio
public AudioService(AudioServiceConfig config) public AudioService(AudioServiceConfig config)
{ {
Config = config; Config = config;
}
_asyncLock = new AsyncLock();

}
void IService.Install(DiscordClient client) void IService.Install(DiscordClient client)
{ {
Client = client; Client = client;
Config.Lock(); Config.Lock();


if (Config.EnableMultiserver) if (Config.EnableMultiserver)
_voiceClients = new ConcurrentDictionary<ulong, IAudioClient>();
_voiceClients = new ConcurrentDictionary<ulong, AudioClient>();
else else
{ {
var logger = Client.Log.CreateLogger("Voice"); var logger = Client.Log.CreateLogger("Voice");
_defaultClient = new SimpleAudioClient(this, 0, logger);
_defaultClient = new AudioClient(Client, null, 0);
} }
_talkingUsers = new ConcurrentDictionary<User, bool>(); _talkingUsers = new ConcurrentDictionary<User, bool>();


@@ -75,68 +79,30 @@ namespace Discord.Audio
{ {
if (server == null) throw new ArgumentNullException(nameof(server)); if (server == null) throw new ArgumentNullException(nameof(server));


if (!Config.EnableMultiserver)
if (Config.EnableMultiserver)
{ {
if (server == _defaultClient.Server)
return (_defaultClient as SimpleAudioClient).CurrentClient;
AudioClient client;
if (_voiceClients.TryGetValue(server.Id, out client))
return client;
else else
return null; return null;
} }
else else
{ {
IAudioClient client;
if (_voiceClients.TryGetValue(server.Id, out client))
return client;
if (server == _currentClient.Server)
return _currentClient;
else else
return null; return null;
} }
} }
private async Task<IAudioClient> CreateClient(Server server)
{
var client = _voiceClients.GetOrAdd(server.Id, _ => null); //Placeholder, so we can't have two clients connecting at once

if (client == null)
{
int id = unchecked(++_nextClientId);

var gatewayLogger = Client.Log.CreateLogger($"Gateway #{id}");
var voiceLogger = Client.Log.CreateLogger($"Voice #{id}");
var gatewaySocket = new GatewaySocket(Client, gatewayLogger);
var voiceClient = new AudioClient(this, id, server, Client.GatewaySocket, voiceLogger);

await voiceClient.Connect(true).ConfigureAwait(false);

/*voiceClient.VoiceSocket.FrameReceived += (s, e) =>
{
OnFrameReceieved(e);
};
voiceClient.VoiceSocket.UserIsSpeaking += (s, e) =>
{
var user = server.GetUser(e.UserId);
OnUserIsSpeakingUpdated(user, e.IsSpeaking);
};*/

//Update the placeholder only it still exists (RemoveClient wasnt called)
if (!_voiceClients.TryUpdate(server.Id, voiceClient, null))
{
//If it was, cleanup
await voiceClient.Disconnect().ConfigureAwait(false); ;
await gatewaySocket.Disconnect().ConfigureAwait(false); ;
}
}
return client;
}

//TODO: This isn't threadsafe
internal async Task RemoveClient(Server server, IAudioClient client)
//Called from AudioClient.Disconnect
internal async Task RemoveClient(Server server, AudioClient client)
{ {
if (Config.EnableMultiserver && server != null)
using (await _asyncLock.LockAsync().ConfigureAwait(false))
{ {
if (_voiceClients.TryRemove(server.Id, out client))
{
await client.Disconnect();
await (client as AudioClient).GatewaySocket.Disconnect();
}
if (_voiceClients.TryUpdate(server.Id, null, client))
_voiceClients.TryRemove(server.Id, out client);
} }
} }


@@ -144,16 +110,48 @@ namespace Discord.Audio
{ {
if (channel == null) throw new ArgumentNullException(nameof(channel)); if (channel == null) throw new ArgumentNullException(nameof(channel));
if (!Config.EnableMultiserver)
{
await (_defaultClient as SimpleAudioClient).Connect(channel, false).ConfigureAwait(false);
return _defaultClient;
}
else
var server = channel.Server;
using (await _asyncLock.LockAsync().ConfigureAwait(false))
{ {
var client = await CreateClient(channel.Server).ConfigureAwait(false);
await client.Join(channel).ConfigureAwait(false);
return client;
if (Config.EnableMultiserver)
{
AudioClient client;
if (!_voiceClients.TryGetValue(server.Id, out client))
{
client = new AudioClient(Client, server, unchecked(++_nextClientId));
_voiceClients[server.Id] = client;

await client.Connect().ConfigureAwait(false);

/*voiceClient.VoiceSocket.FrameReceived += (s, e) =>
{
OnFrameReceieved(e);
};
voiceClient.VoiceSocket.UserIsSpeaking += (s, e) =>
{
var user = server.GetUser(e.UserId);
OnUserIsSpeakingUpdated(user, e.IsSpeaking);
};*/
}

await client.Join(channel).ConfigureAwait(false);
return client;
}
else
{
if (_defaultClient.Server != server)
{
await _defaultClient.Disconnect();
_defaultClient.VoiceSocket.Server = server;
await _defaultClient.Connect().ConfigureAwait(false);
}
var client = new VirtualClient(_defaultClient, server);
_currentClient = client;

await client.Join(channel).ConfigureAwait(false);
return client;
}

} }
} }
@@ -163,15 +161,18 @@ namespace Discord.Audio


if (Config.EnableMultiserver) if (Config.EnableMultiserver)
{ {
IAudioClient client;
AudioClient client;
if (_voiceClients.TryRemove(server.Id, out client)) if (_voiceClients.TryRemove(server.Id, out client))
await client.Disconnect().ConfigureAwait(false); await client.Disconnect().ConfigureAwait(false);
} }
else else
{ {
IAudioClient client = GetClient(server);
if (client != null)
await (_defaultClient as SimpleAudioClient).Leave(client as SimpleAudioClient.VirtualClient).ConfigureAwait(false);
using (await _asyncLock.LockAsync().ConfigureAwait(false))
{
var client = GetClient(server) as VirtualClient;
if (client != null)
await _defaultClient.Disconnect().ConfigureAwait(false);
}
} }
} }
} }


src/Discord.Net.Audio/Net/VoiceWebSocket.cs → src/Discord.Net.Audio/Net/VoiceSocket.cs View File

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


namespace Discord.Net.WebSockets namespace Discord.Net.WebSockets
{ {
public partial class VoiceWebSocket : WebSocket
public partial class VoiceSocket : WebSocket
{ {
private const int MaxOpusSize = 4000; private const int MaxOpusSize = 4000;
private const string EncryptedMode = "xsalsa20_poly1305"; private const string EncryptedMode = "xsalsa20_poly1305";
@@ -27,8 +27,7 @@ namespace Discord.Net.WebSockets


private readonly int _targetAudioBufferLength; private readonly int _targetAudioBufferLength;
private readonly ConcurrentDictionary<uint, OpusDecoder> _decoders; private readonly ConcurrentDictionary<uint, OpusDecoder> _decoders;
private readonly AudioClient _audioClient;
private readonly AudioServiceConfig _config;
private readonly AudioServiceConfig _audioConfig;
private Task _sendTask, _receiveTask; private Task _sendTask, _receiveTask;
private VoiceBuffer _sendBuffer; private VoiceBuffer _sendBuffer;
private OpusEncoder _encoder; private OpusEncoder _encoder;
@@ -41,6 +40,8 @@ namespace Discord.Net.WebSockets
private ushort _sequence; private ushort _sequence;
private string _encryptionMode; private string _encryptionMode;
private int _ping; private int _ping;
private ulong? _userId;
private string _sessionId;


public string Token { get; internal set; } public string Token { get; internal set; }
public Server Server { get; internal set; } public Server Server { get; internal set; }
@@ -57,32 +58,37 @@ namespace Discord.Net.WebSockets
internal void OnFrameReceived(ulong userId, ulong channelId, byte[] buffer, int offset, int count) internal void OnFrameReceived(ulong userId, ulong channelId, byte[] buffer, int offset, int count)
=> FrameReceived(this, new InternalFrameEventArgs(userId, channelId, buffer, offset, count)); => FrameReceived(this, new InternalFrameEventArgs(userId, channelId, buffer, offset, count));


internal VoiceWebSocket(DiscordClient client, AudioClient audioClient, Logger logger)
: base(client, logger)
internal VoiceSocket(DiscordConfig config, AudioServiceConfig audioConfig, JsonSerializer serializer, Logger logger)
: base(config, serializer, logger)
{ {
_audioClient = audioClient;
_config = client.Audio().Config;
_audioConfig = audioConfig;
_decoders = new ConcurrentDictionary<uint, OpusDecoder>(); _decoders = new ConcurrentDictionary<uint, OpusDecoder>();
_targetAudioBufferLength = _config.BufferLength / 20; //20 ms frames
_targetAudioBufferLength = _audioConfig.BufferLength / 20; //20 ms frames
_encodingBuffer = new byte[MaxOpusSize]; _encodingBuffer = new byte[MaxOpusSize];
_ssrcMapping = new ConcurrentDictionary<uint, ulong>(); _ssrcMapping = new ConcurrentDictionary<uint, ulong>();
_encoder = new OpusEncoder(48000, _config.Channels, 20, _config.Bitrate, OpusApplication.MusicOrMixed);
_sendBuffer = new VoiceBuffer((int)Math.Ceiling(_config.BufferLength / (double)_encoder.FrameLength), _encoder.FrameSize);
_encoder = new OpusEncoder(48000, _audioConfig.Channels, 20, _audioConfig.Bitrate, OpusApplication.MusicOrMixed);
_sendBuffer = new VoiceBuffer((int)Math.Ceiling(_audioConfig.BufferLength / (double)_encoder.FrameLength), _encoder.FrameSize);
} }


public Task Connect()
=> BeginConnect();
public Task Connect(string host, string token, ulong userId, string sessionId, CancellationToken parentCancelToken)
{
Host = host;
Token = token;
_userId = userId;
_sessionId = sessionId;
return BeginConnect(parentCancelToken);
}
private async Task Reconnect() private async Task Reconnect()
{ {
try try
{ {
var cancelToken = ParentCancelToken.Value;
await Task.Delay(_client.Config.ReconnectDelay, cancelToken).ConfigureAwait(false);
var cancelToken = _parentCancelToken;
await Task.Delay(_config.ReconnectDelay, cancelToken).ConfigureAwait(false);
while (!cancelToken.IsCancellationRequested) while (!cancelToken.IsCancellationRequested)
{ {
try try
{ {
await Connect().ConfigureAwait(false);
await BeginConnect(_parentCancelToken).ConfigureAwait(false);
break; break;
} }
catch (OperationCanceledException) { throw; } catch (OperationCanceledException) { throw; }
@@ -90,31 +96,35 @@ namespace Discord.Net.WebSockets
{ {
Logger.Error("Reconnect failed", ex); Logger.Error("Reconnect failed", ex);
//Net is down? We can keep trying to reconnect until the user runs Disconnect() //Net is down? We can keep trying to reconnect until the user runs Disconnect()
await Task.Delay(_client.Config.FailedReconnectDelay, cancelToken).ConfigureAwait(false);
await Task.Delay(_config.FailedReconnectDelay, cancelToken).ConfigureAwait(false);
} }
} }
} }
catch (OperationCanceledException) { } catch (OperationCanceledException) { }
} }
public Task Disconnect() => _taskManager.Stop(true);
public async Task Disconnect()
{
await _taskManager.Stop(true).ConfigureAwait(false);
_userId = null;
}


protected override async Task Run() protected override async Task Run()
{ {
_udp = new UdpClient(new IPEndPoint(IPAddress.Any, 0)); _udp = new UdpClient(new IPEndPoint(IPAddress.Any, 0));


List<Task> tasks = new List<Task>(); List<Task> tasks = new List<Task>();
if (_config.Mode.HasFlag(AudioMode.Outgoing))
if (_audioConfig.Mode.HasFlag(AudioMode.Outgoing))
_sendTask = Task.Run(() => SendVoiceAsync(CancelToken)); _sendTask = Task.Run(() => SendVoiceAsync(CancelToken));
_receiveTask = Task.Run(() => ReceiveVoiceAsync(CancelToken)); _receiveTask = Task.Run(() => ReceiveVoiceAsync(CancelToken));


SendIdentify();
SendIdentify(_userId.Value, _sessionId);


#if !DOTNET5_4 #if !DOTNET5_4
tasks.Add(WatcherAsync()); tasks.Add(WatcherAsync());
#endif #endif
tasks.AddRange(_engine.GetTasks(CancelToken)); tasks.AddRange(_engine.GetTasks(CancelToken));
tasks.Add(HeartbeatAsync(CancelToken)); tasks.Add(HeartbeatAsync(CancelToken));
await _taskManager.Start(tasks, _cancelTokenSource).ConfigureAwait(false);
await _taskManager.Start(tasks, _cancelSource).ConfigureAwait(false);
} }
protected override async Task Cleanup() protected override async Task Cleanup()
{ {
@@ -148,7 +158,7 @@ namespace Discord.Net.WebSockets
int packetLength, resultOffset, resultLength; int packetLength, resultOffset, resultLength;
IPEndPoint endpoint = new IPEndPoint(IPAddress.Any, 0); IPEndPoint endpoint = new IPEndPoint(IPAddress.Any, 0);


if ((_config.Mode & AudioMode.Incoming) != 0)
if ((_audioConfig.Mode & AudioMode.Incoming) != 0)
{ {
decodingBuffer = new byte[MaxOpusSize]; decodingBuffer = new byte[MaxOpusSize];
nonce = new byte[24]; nonce = new byte[24];
@@ -184,7 +194,7 @@ namespace Discord.Net.WebSockets
int port = packet[68] | packet[69] << 8; int port = packet[68] | packet[69] << 8;


SendSelectProtocol(ip, port); SendSelectProtocol(ip, port);
if ((_config.Mode & AudioMode.Incoming) == 0)
if ((_audioConfig.Mode & AudioMode.Incoming) == 0)
return; //We dont need this thread anymore return; //We dont need this thread anymore
} }
else else
@@ -395,7 +405,7 @@ namespace Discord.Net.WebSockets
var address = (await Dns.GetHostAddressesAsync(Host.Replace("wss://", "")).ConfigureAwait(false)).FirstOrDefault(); var address = (await Dns.GetHostAddressesAsync(Host.Replace("wss://", "")).ConfigureAwait(false)).FirstOrDefault();
_endpoint = new IPEndPoint(address, payload.Port); _endpoint = new IPEndPoint(address, payload.Port);


if (_config.EnableEncryption)
if (_audioConfig.EnableEncryption)
{ {
if (payload.Modes.Contains(EncryptedMode)) if (payload.Modes.Contains(EncryptedMode))
{ {
@@ -467,12 +477,12 @@ namespace Discord.Net.WebSockets


public override void SendHeartbeat() public override void SendHeartbeat()
=> QueueMessage(new HeartbeatCommand()); => QueueMessage(new HeartbeatCommand());
public void SendIdentify()
public void SendIdentify(ulong id, string sessionId)
=> QueueMessage(new IdentifyCommand => QueueMessage(new IdentifyCommand
{ {
GuildId = Server.Id, GuildId = Server.Id,
UserId = _client.CurrentUser.Id,
SessionId = _client.SessionId,
UserId = id,
SessionId = sessionId,
Token = Token Token = Token
}); });
public void SendSelectProtocol(string externalAddress, int externalPort) public void SendSelectProtocol(string externalAddress, int externalPort)

+ 0
- 72
src/Discord.Net.Audio/SimpleAudioClient.cs View File

@@ -1,72 +0,0 @@
using Discord.Logging;
using Nito.AsyncEx;
using System.IO;
using System.Threading.Tasks;

namespace Discord.Audio
{
internal class SimpleAudioClient : AudioClient
{
internal class VirtualClient : IAudioClient
{
private readonly SimpleAudioClient _client;

ConnectionState IAudioClient.State => _client.VoiceSocket.State;
Server IAudioClient.Server => _client.VoiceSocket.Server;
Channel IAudioClient.Channel => _client.VoiceSocket.Channel;
Stream IAudioClient.OutputStream => _client.OutputStream;

public VirtualClient(SimpleAudioClient client)
{
_client = client;
}

Task IAudioClient.Disconnect() => _client.Leave(this);
Task IAudioClient.Join(Channel channel) => _client.Join(channel);

void IAudioClient.Send(byte[] data, int offset, int count) => _client.Send(data, offset, count);
void IAudioClient.Clear() => _client.Clear();
void IAudioClient.Wait() => _client.Wait();
}

private readonly AsyncLock _connectionLock;

internal VirtualClient CurrentClient { get; private set; }

public SimpleAudioClient(AudioService service, int id, Logger logger)
: base(service, id, null, service.Client.GatewaySocket, logger)
{
_connectionLock = new AsyncLock();
}

//Only disconnects if is current a member of this server
public async Task Leave(VirtualClient client)
{
using (await _connectionLock.LockAsync().ConfigureAwait(false))
{
if (CurrentClient == client)
{
CurrentClient = null;
await Disconnect().ConfigureAwait(false);
}
}
}

internal async Task<IAudioClient> Connect(Channel channel, bool connectGateway)
{
using (await _connectionLock.LockAsync().ConfigureAwait(false))
{
bool changeServer = channel.Server != VoiceSocket.Server;
if (changeServer || CurrentClient == null)
{
await Disconnect().ConfigureAwait(false);
CurrentClient = new VirtualClient(this);
VoiceSocket.Server = channel.Server;
await Connect(connectGateway).ConfigureAwait(false);
}
await Join(channel).ConfigureAwait(false);
return CurrentClient;
}
}
}
}

+ 29
- 0
src/Discord.Net.Audio/VirtualClient.cs View File

@@ -0,0 +1,29 @@
using System.IO;
using System.Threading.Tasks;

namespace Discord.Audio
{
internal class VirtualClient : IAudioClient
{
private readonly AudioClient _client;

public Server Server { get; }

public ConnectionState State => _client.VoiceSocket.Server == Server ? _client.VoiceSocket.State : ConnectionState.Disconnected;
public Channel Channel => _client.VoiceSocket.Server == Server ? _client.VoiceSocket.Channel : null;
public Stream OutputStream => _client.VoiceSocket.Server == Server ? _client.OutputStream : null;

public VirtualClient(AudioClient client, Server server)
{
_client = client;
Server = server;
}

public Task Disconnect() => _client.Service.Leave(Server);
public Task Join(Channel channel) => _client.Join(channel);

public void Send(byte[] data, int offset, int count) => _client.Send(data, offset, count);
public void Clear() => _client.Clear();
public void Wait() => _client.Wait();
}
}

+ 2
- 1
src/Discord.Net.Commands/Command.cs View File

@@ -5,7 +5,8 @@ using System.Threading.Tasks;


namespace Discord.Commands namespace Discord.Commands
{ {
public sealed class Command
//TODO: Make this more friendly and expose it to be extendable
public class Command
{ {
private string[] _aliases; private string[] _aliases;
internal CommandParameter[] _parameters; internal CommandParameter[] _parameters;


+ 12
- 11
src/Discord.Net.Commands/CommandBuilder.cs View File

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


namespace Discord.Commands namespace Discord.Commands
{ {
//TODO: Make this more friendly and expose it to be extendable
public sealed class CommandBuilder public sealed class CommandBuilder
{ {
private readonly CommandService _service; private readonly CommandService _service;
@@ -18,17 +19,20 @@ namespace Discord.Commands


public CommandService Service => _service; public CommandService Service => _service;


internal CommandBuilder(CommandService service, Command command, string prefix = "", string category = "", IEnumerable<IPermissionChecker> initialChecks = null)
internal CommandBuilder(CommandService service, string text, string prefix = "", string category = "", IEnumerable<IPermissionChecker> initialChecks = null)
{ {
_service = service;
_command = command;
_command.Category = category;
_params = new List<CommandParameter>();
_service = service;
_prefix = prefix;

_command = new Command(AppendPrefix(prefix, text));
_command.Category = category;

if (initialChecks != null) if (initialChecks != null)
_checks = new List<IPermissionChecker>(initialChecks); _checks = new List<IPermissionChecker>(initialChecks);
else else
_checks = new List<IPermissionChecker>(); _checks = new List<IPermissionChecker>();
_prefix = prefix;

_params = new List<CommandParameter>();
_aliases = new List<string>(); _aliases = new List<string>();


_allowRequiredParams = true; _allowRequiredParams = true;
@@ -112,7 +116,7 @@ namespace Discord.Commands
return prefix; return prefix;
} }
} }
public sealed class CommandGroupBuilder
public class CommandGroupBuilder
{ {
private readonly CommandService _service; private readonly CommandService _service;
private readonly string _prefix; private readonly string _prefix;
@@ -154,9 +158,6 @@ namespace Discord.Commands
public CommandBuilder CreateCommand() public CommandBuilder CreateCommand()
=> CreateCommand(""); => CreateCommand("");
public CommandBuilder CreateCommand(string cmd) public CommandBuilder CreateCommand(string cmd)
{
var command = new Command(CommandBuilder.AppendPrefix(_prefix, cmd));
return new CommandBuilder(_service, command, _prefix, _category, _checks);
}
=> new CommandBuilder(_service, cmd, _prefix, _category, _checks);
} }
} }

+ 2
- 2
src/Discord.Net.Commands/CommandParameter.cs View File

@@ -11,13 +11,13 @@
/// <summary> Catches all remaining text as a single optional parameter. </summary> /// <summary> Catches all remaining text as a single optional parameter. </summary>
Unparsed Unparsed
} }
public sealed class CommandParameter
public class CommandParameter
{ {
public string Name { get; } public string Name { get; }
public int Id { get; internal set; } public int Id { get; internal set; }
public ParameterType Type { get; } public ParameterType Type { get; }


public CommandParameter(string name, ParameterType type)
internal CommandParameter(string name, ParameterType type)
{ {
Name = name; Name = name;
Type = type; Type = type;


+ 1
- 1
src/Discord.Net.Modules/ModuleManager.cs View File

@@ -7,7 +7,7 @@ using System.Linq;


namespace Discord.Modules namespace Discord.Modules
{ {
public sealed class ModuleManager
public class ModuleManager
{ {
public event EventHandler<ServerEventArgs> ServerEnabled = delegate { }; public event EventHandler<ServerEventArgs> ServerEnabled = delegate { };
public event EventHandler<ServerEventArgs> ServerDisabled = delegate { }; public event EventHandler<ServerEventArgs> ServerDisabled = delegate { };


+ 1
- 1
src/Discord.Net/API/Client/Common/Channel.cs View File

@@ -5,7 +5,7 @@ namespace Discord.API.Client
{ {
public class Channel : ChannelReference public class Channel : ChannelReference
{ {
public sealed class PermissionOverwrite
public class PermissionOverwrite
{ {
[JsonProperty("type")] [JsonProperty("type")]
public string Type { get; set; } public string Type { get; set; }


+ 1
- 1
src/Discord.Net/API/Client/Common/ExtendedGuild.cs View File

@@ -4,7 +4,7 @@ namespace Discord.API.Client
{ {
public class ExtendedGuild : Guild public class ExtendedGuild : Guild
{ {
public sealed class ExtendedMemberInfo : Member
public class ExtendedMemberInfo : Member
{ {
[JsonProperty("mute")] [JsonProperty("mute")]
public bool? IsServerMuted { get; set; } public bool? IsServerMuted { get; set; }


+ 1
- 1
src/Discord.Net/API/Client/Common/Guild.cs View File

@@ -6,7 +6,7 @@ namespace Discord.API.Client
{ {
public class Guild : GuildReference public class Guild : GuildReference
{ {
public sealed class EmojiData
public class EmojiData
{ {
[JsonProperty("id")] [JsonProperty("id")]
public string Id { get; set; } public string Id { get; set; }


+ 1
- 1
src/Discord.Net/API/Client/Common/InviteReference.cs View File

@@ -4,7 +4,7 @@ namespace Discord.API.Client
{ {
public class InviteReference public class InviteReference
{ {
public sealed class GuildData : GuildReference
public class GuildData : GuildReference
{ {
[JsonProperty("splash_hash")] [JsonProperty("splash_hash")]
public string Splash { get; set; } public string Splash { get; set; }


+ 1
- 1
src/Discord.Net/API/Client/Common/MemberPresence.cs View File

@@ -5,7 +5,7 @@ namespace Discord.API.Client
{ {
public class MemberPresence : MemberReference public class MemberPresence : MemberReference
{ {
public sealed class GameInfo
public class GameInfo
{ {
[JsonProperty("name")] [JsonProperty("name")]
public string Name { get; set; } public string Name { get; set; }


+ 5
- 5
src/Discord.Net/API/Client/Common/Message.cs View File

@@ -5,7 +5,7 @@ namespace Discord.API.Client
{ {
public class Message : MessageReference public class Message : MessageReference
{ {
public sealed class Attachment
public class Attachment
{ {
[JsonProperty("id")] [JsonProperty("id")]
public string Id { get; set; } public string Id { get; set; }
@@ -23,9 +23,9 @@ namespace Discord.API.Client
public int Height { get; set; } public int Height { get; set; }
} }


public sealed class Embed
public class Embed
{ {
public sealed class Reference
public class Reference
{ {
[JsonProperty("url")] [JsonProperty("url")]
public string Url { get; set; } public string Url { get; set; }
@@ -33,7 +33,7 @@ namespace Discord.API.Client
public string Name { get; set; } public string Name { get; set; }
} }


public sealed class ThumbnailInfo
public class ThumbnailInfo
{ {
[JsonProperty("url")] [JsonProperty("url")]
public string Url { get; set; } public string Url { get; set; }
@@ -44,7 +44,7 @@ namespace Discord.API.Client
[JsonProperty("height")] [JsonProperty("height")]
public int Height { get; set; } public int Height { get; set; }
} }
public sealed class VideoInfo
public class VideoInfo
{ {
[JsonProperty("url")] [JsonProperty("url")]
public string Url { get; set; } public string Url { get; set; }


+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Commands/Heartbeat.cs View File

@@ -3,7 +3,7 @@
namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class HeartbeatCommand : IWebSocketMessage
public class HeartbeatCommand : IWebSocketMessage
{ {
int IWebSocketMessage.OpCode => (int)OpCodes.Heartbeat; int IWebSocketMessage.OpCode => (int)OpCodes.Heartbeat;
object IWebSocketMessage.Payload => EpochTime.GetMilliseconds(); object IWebSocketMessage.Payload => EpochTime.GetMilliseconds();


+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Commands/Identify.cs View File

@@ -4,7 +4,7 @@ using System.Collections.Generic;
namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class IdentifyCommand : IWebSocketMessage
public class IdentifyCommand : IWebSocketMessage
{ {
int IWebSocketMessage.OpCode => (int)OpCodes.Identify; int IWebSocketMessage.OpCode => (int)OpCodes.Identify;
object IWebSocketMessage.Payload => this; object IWebSocketMessage.Payload => this;


+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Commands/RequestMembers.cs View File

@@ -4,7 +4,7 @@ using Newtonsoft.Json;
namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class RequestMembersCommand : IWebSocketMessage
public class RequestMembersCommand : IWebSocketMessage
{ {
int IWebSocketMessage.OpCode => (int)OpCodes.RequestGuildMembers; int IWebSocketMessage.OpCode => (int)OpCodes.RequestGuildMembers;
object IWebSocketMessage.Payload => this; object IWebSocketMessage.Payload => this;


+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Commands/Resume.cs View File

@@ -3,7 +3,7 @@
namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class ResumeCommand : IWebSocketMessage
public class ResumeCommand : IWebSocketMessage
{ {
int IWebSocketMessage.OpCode => (int)OpCodes.Resume; int IWebSocketMessage.OpCode => (int)OpCodes.Resume;
object IWebSocketMessage.Payload => this; object IWebSocketMessage.Payload => this;


+ 2
- 2
src/Discord.Net/API/Client/GatewaySocket/Commands/UpdateStatus.cs View File

@@ -3,13 +3,13 @@
namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class UpdateStatusCommand : IWebSocketMessage
public class UpdateStatusCommand : IWebSocketMessage
{ {
int IWebSocketMessage.OpCode => (int)OpCodes.StatusUpdate; int IWebSocketMessage.OpCode => (int)OpCodes.StatusUpdate;
object IWebSocketMessage.Payload => this; object IWebSocketMessage.Payload => this;
bool IWebSocketMessage.IsPrivate => false; bool IWebSocketMessage.IsPrivate => false;


public sealed class GameInfo
public class GameInfo
{ {
[JsonProperty("name")] [JsonProperty("name")]
public string Name { get; set; } public string Name { get; set; }


+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Commands/UpdateVoice.cs View File

@@ -4,7 +4,7 @@ using Newtonsoft.Json;
namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class UpdateVoiceCommand : IWebSocketMessage
public class UpdateVoiceCommand : IWebSocketMessage
{ {
int IWebSocketMessage.OpCode => (int)OpCodes.VoiceStateUpdate; int IWebSocketMessage.OpCode => (int)OpCodes.VoiceStateUpdate;
object IWebSocketMessage.Payload => this; object IWebSocketMessage.Payload => this;


+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Events/ChannelCreate.cs View File

@@ -1,4 +1,4 @@
namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
public sealed class ChannelCreateEvent : Channel { }
public class ChannelCreateEvent : Channel { }
} }

+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Events/ChannelDelete.cs View File

@@ -1,4 +1,4 @@
namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
public sealed class ChannelDeleteEvent : Channel { }
public class ChannelDeleteEvent : Channel { }
} }

+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Events/ChannelUpdate.cs View File

@@ -1,4 +1,4 @@
namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
public sealed class ChannelUpdateEvent : Channel { }
public class ChannelUpdateEvent : Channel { }
} }

+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Events/GuildBanAdd.cs View File

@@ -1,4 +1,4 @@
namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
public sealed class GuildBanAddEvent : MemberReference { }
public class GuildBanAddEvent : MemberReference { }
} }

+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Events/GuildBanRemove.cs View File

@@ -1,4 +1,4 @@
namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
public sealed class GuildBanRemoveEvent : MemberReference { }
public class GuildBanRemoveEvent : MemberReference { }
} }

+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Events/GuildCreate.cs View File

@@ -1,4 +1,4 @@
namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
public sealed class GuildCreateEvent : ExtendedGuild { }
public class GuildCreateEvent : ExtendedGuild { }
} }

+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Events/GuildDelete.cs View File

@@ -1,4 +1,4 @@
namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
public sealed class GuildDeleteEvent : ExtendedGuild { }
public class GuildDeleteEvent : ExtendedGuild { }
} }

+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Events/GuildEmojisUpdate.cs View File

@@ -1,4 +1,4 @@
namespace Discord.API.Client.GatewaySocket.Events namespace Discord.API.Client.GatewaySocket.Events
{ {
//public sealed class GuildEmojisUpdateEvent { }
//public class GuildEmojisUpdateEvent { }
} }

+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Events/GuildIntegrationsUpdate.cs View File

@@ -1,4 +1,4 @@
namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
//public sealed class GuildIntegrationsUpdateEvent { }
//public class GuildIntegrationsUpdateEvent { }
} }

+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Events/GuildMemberAdd.cs View File

@@ -1,4 +1,4 @@
namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
public sealed class GuildMemberAddEvent : Member { }
public class GuildMemberAddEvent : Member { }
} }

+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Events/GuildMemberRemove.cs View File

@@ -1,4 +1,4 @@
namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
public sealed class GuildMemberRemoveEvent : Member { }
public class GuildMemberRemoveEvent : Member { }
} }

+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Events/GuildMemberUpdate.cs View File

@@ -1,4 +1,4 @@
namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
public sealed class GuildMemberUpdateEvent : Member { }
public class GuildMemberUpdateEvent : Member { }
} }

+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Events/GuildMembersChunk.cs View File

@@ -3,7 +3,7 @@ using Newtonsoft.Json;


namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
public sealed class GuildMembersChunkEvent
public class GuildMembersChunkEvent
{ {
[JsonProperty("guild_id"), JsonConverter(typeof(LongStringConverter))] [JsonProperty("guild_id"), JsonConverter(typeof(LongStringConverter))]
public ulong GuildId { get; set; } public ulong GuildId { get; set; }


+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Events/GuildRoleCreate.cs View File

@@ -3,7 +3,7 @@ using Newtonsoft.Json;


namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
public sealed class GuildRoleCreateEvent
public class GuildRoleCreateEvent
{ {
[JsonProperty("guild_id"), JsonConverter(typeof(LongStringConverter))] [JsonProperty("guild_id"), JsonConverter(typeof(LongStringConverter))]
public ulong GuildId { get; set; } public ulong GuildId { get; set; }


+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Events/GuildRoleDelete.cs View File

@@ -1,4 +1,4 @@
namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
public sealed class GuildRoleDeleteEvent : RoleReference { }
public class GuildRoleDeleteEvent : RoleReference { }
} }

+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Events/GuildRoleUpdate.cs View File

@@ -3,7 +3,7 @@ using Newtonsoft.Json;


namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
public sealed class GuildRoleUpdateEvent
public class GuildRoleUpdateEvent
{ {
[JsonProperty("guild_id"), JsonConverter(typeof(LongStringConverter))] [JsonProperty("guild_id"), JsonConverter(typeof(LongStringConverter))]
public ulong GuildId { get; set; } public ulong GuildId { get; set; }


+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Events/GuildUpdate.cs View File

@@ -1,4 +1,4 @@
namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
public sealed class GuildUpdateEvent : Guild { }
public class GuildUpdateEvent : Guild { }
} }

+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Events/MessageAck.cs View File

@@ -1,4 +1,4 @@
namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
public sealed class MessageAckEvent : MessageReference { }
public class MessageAckEvent : MessageReference { }
} }

+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Events/MessageCreate.cs View File

@@ -1,4 +1,4 @@
namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
public sealed class MessageCreateEvent : Message { }
public class MessageCreateEvent : Message { }
} }

+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Events/MessageDelete.cs View File

@@ -1,4 +1,4 @@
namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
public sealed class MessageDeleteEvent : MessageReference { }
public class MessageDeleteEvent : MessageReference { }
} }

+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Events/MessageUpdate.cs View File

@@ -1,4 +1,4 @@
namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
public sealed class MessageUpdateEvent : Message { }
public class MessageUpdateEvent : Message { }
} }

+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Events/PresenceUpdate.cs View File

@@ -1,4 +1,4 @@
namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
public sealed class PresenceUpdateEvent : MemberPresence { }
public class PresenceUpdateEvent : MemberPresence { }
} }

+ 2
- 2
src/Discord.Net/API/Client/GatewaySocket/Events/Ready.cs View File

@@ -2,9 +2,9 @@


namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
public sealed class ReadyEvent
public class ReadyEvent
{ {
public sealed class ReadState
public class ReadState
{ {
[JsonProperty("id")] [JsonProperty("id")]
public string ChannelId { get; set; } public string ChannelId { get; set; }


+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Events/Redirect.cs View File

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


namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
public sealed class RedirectEvent
public class RedirectEvent
{ {
[JsonProperty("url")] [JsonProperty("url")]
public string Url { get; set; } public string Url { get; set; }


+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Events/Resumed.cs View File

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


namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
public sealed class ResumedEvent
public class ResumedEvent
{ {
[JsonProperty("heartbeat_interval")] [JsonProperty("heartbeat_interval")]
public int HeartbeatInterval { get; set; } public int HeartbeatInterval { get; set; }


+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Events/TypingStart.cs View File

@@ -3,7 +3,7 @@ using Newtonsoft.Json;


namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
public sealed class TypingStartEvent
public class TypingStartEvent
{ {
[JsonProperty("user_id"), JsonConverter(typeof(LongStringConverter))] [JsonProperty("user_id"), JsonConverter(typeof(LongStringConverter))]
public ulong UserId { get; set; } public ulong UserId { get; set; }


+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Events/UserSettingsUpdate.cs View File

@@ -1,4 +1,4 @@
namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
//public sealed class UserSettingsUpdateEvent { }
//public class UserSettingsUpdateEvent { }
} }

+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Events/UserUpdate.cs View File

@@ -1,4 +1,4 @@
namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
public sealed class UserUpdateEvent : User { }
public class UserUpdateEvent : User { }
} }

+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Events/VoiceServerUpdate.cs View File

@@ -3,7 +3,7 @@ using Newtonsoft.Json;


namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
public sealed class VoiceServerUpdateEvent
public class VoiceServerUpdateEvent
{ {
[JsonProperty("guild_id"), JsonConverter(typeof(LongStringConverter))] [JsonProperty("guild_id"), JsonConverter(typeof(LongStringConverter))]
public ulong GuildId { get; set; } public ulong GuildId { get; set; }


+ 1
- 1
src/Discord.Net/API/Client/GatewaySocket/Events/VoiceStateUpdate.cs View File

@@ -1,4 +1,4 @@
namespace Discord.API.Client.GatewaySocket namespace Discord.API.Client.GatewaySocket
{ {
public sealed class VoiceStateUpdateEvent : MemberVoiceState { }
public class VoiceStateUpdateEvent : MemberVoiceState { }
} }

+ 1
- 1
src/Discord.Net/API/Client/IWebSocketMessage.cs View File

@@ -8,7 +8,7 @@ namespace Discord.API.Client
object Payload { get; } object Payload { get; }
bool IsPrivate { get; } bool IsPrivate { get; }
} }
public sealed class WebSocketMessage
public class WebSocketMessage
{ {
[JsonProperty("op")] [JsonProperty("op")]
public int? Operation { get; set; } public int? Operation { get; set; }


+ 1
- 1
src/Discord.Net/API/Client/Rest/AcceptInvite.cs View File

@@ -3,7 +3,7 @@
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class AcceptInviteRequest : IRestRequest<InviteReference>
public class AcceptInviteRequest : IRestRequest<InviteReference>
{ {
string IRestRequest.Method => "POST"; string IRestRequest.Method => "POST";
string IRestRequest.Endpoint => $"invite/{InviteId}"; string IRestRequest.Endpoint => $"invite/{InviteId}";


+ 1
- 1
src/Discord.Net/API/Client/Rest/AckMessage.cs View File

@@ -3,7 +3,7 @@
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class AckMessageRequest : IRestRequest
public class AckMessageRequest : IRestRequest
{ {
string IRestRequest.Method => "POST"; string IRestRequest.Method => "POST";
string IRestRequest.Endpoint => $"channels/{ChannelId}/messages/{MessageId}/ack"; string IRestRequest.Endpoint => $"channels/{ChannelId}/messages/{MessageId}/ack";


+ 1
- 1
src/Discord.Net/API/Client/Rest/AddChannelPermission.cs View File

@@ -4,7 +4,7 @@ using Newtonsoft.Json;
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class AddChannelPermissionsRequest : IRestRequest
public class AddChannelPermissionsRequest : IRestRequest
{ {
string IRestRequest.Method => "PUT"; string IRestRequest.Method => "PUT";
string IRestRequest.Endpoint => $"channels/{ChannelId}/permissions/{TargetId}"; string IRestRequest.Endpoint => $"channels/{ChannelId}/permissions/{TargetId}";


+ 1
- 1
src/Discord.Net/API/Client/Rest/AddGuildBan.cs View File

@@ -3,7 +3,7 @@
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class AddGuildBanRequest : IRestRequest
public class AddGuildBanRequest : IRestRequest
{ {
string IRestRequest.Method => "PUT"; string IRestRequest.Method => "PUT";
string IRestRequest.Endpoint => $"guilds/{GuildId}/bans/{UserId}?delete-message-days={PruneDays}"; string IRestRequest.Endpoint => $"guilds/{GuildId}/bans/{UserId}?delete-message-days={PruneDays}";


+ 1
- 1
src/Discord.Net/API/Client/Rest/CreateChannel.cs View File

@@ -3,7 +3,7 @@
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class CreateChannelRequest : IRestRequest<Channel>
public class CreateChannelRequest : IRestRequest<Channel>
{ {
string IRestRequest.Method => "POST"; string IRestRequest.Method => "POST";
string IRestRequest.Endpoint => $"guilds/{GuildId}/channels"; string IRestRequest.Endpoint => $"guilds/{GuildId}/channels";


+ 1
- 1
src/Discord.Net/API/Client/Rest/CreateGuild.cs View File

@@ -3,7 +3,7 @@
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class CreateGuildRequest : IRestRequest<Guild>
public class CreateGuildRequest : IRestRequest<Guild>
{ {
string IRestRequest.Method => "POST"; string IRestRequest.Method => "POST";
string IRestRequest.Endpoint => $"guilds"; string IRestRequest.Endpoint => $"guilds";


+ 1
- 1
src/Discord.Net/API/Client/Rest/CreateInvite.cs View File

@@ -3,7 +3,7 @@
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class CreateInviteRequest : IRestRequest<Invite>
public class CreateInviteRequest : IRestRequest<Invite>
{ {
string IRestRequest.Method => "POST"; string IRestRequest.Method => "POST";
string IRestRequest.Endpoint => $"channels/{ChannelId}/invites"; string IRestRequest.Endpoint => $"channels/{ChannelId}/invites";


+ 1
- 1
src/Discord.Net/API/Client/Rest/CreatePrivateChannel.cs View File

@@ -4,7 +4,7 @@ using Newtonsoft.Json;
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class CreatePrivateChannelRequest : IRestRequest<Channel>
public class CreatePrivateChannelRequest : IRestRequest<Channel>
{ {
string IRestRequest.Method => "POST"; string IRestRequest.Method => "POST";
string IRestRequest.Endpoint => $"users/@me/channels"; string IRestRequest.Endpoint => $"users/@me/channels";


+ 1
- 1
src/Discord.Net/API/Client/Rest/CreateRole.cs View File

@@ -3,7 +3,7 @@
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class CreateRoleRequest : IRestRequest<Role>
public class CreateRoleRequest : IRestRequest<Role>
{ {
string IRestRequest.Method => "POST"; string IRestRequest.Method => "POST";
string IRestRequest.Endpoint => $"guilds/{GuildId}/roles"; string IRestRequest.Endpoint => $"guilds/{GuildId}/roles";


+ 1
- 1
src/Discord.Net/API/Client/Rest/DeleteChannel.cs View File

@@ -3,7 +3,7 @@
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class DeleteChannelRequest : IRestRequest<Channel>
public class DeleteChannelRequest : IRestRequest<Channel>
{ {
string IRestRequest.Method => "DELETE"; string IRestRequest.Method => "DELETE";
string IRestRequest.Endpoint => $"channels/{ChannelId}"; string IRestRequest.Endpoint => $"channels/{ChannelId}";


+ 1
- 1
src/Discord.Net/API/Client/Rest/DeleteInvite.cs View File

@@ -3,7 +3,7 @@
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class DeleteInviteRequest : IRestRequest<Invite>
public class DeleteInviteRequest : IRestRequest<Invite>
{ {
string IRestRequest.Method => "DELETE"; string IRestRequest.Method => "DELETE";
string IRestRequest.Endpoint => $"invite/{InviteCode}"; string IRestRequest.Endpoint => $"invite/{InviteCode}";


+ 1
- 1
src/Discord.Net/API/Client/Rest/DeleteMessage.cs View File

@@ -3,7 +3,7 @@
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class DeleteMessageRequest : IRestRequest
public class DeleteMessageRequest : IRestRequest
{ {
string IRestRequest.Method => "DELETE"; string IRestRequest.Method => "DELETE";
string IRestRequest.Endpoint => $"channels/{ChannelId}/messages/{MessageId}"; string IRestRequest.Endpoint => $"channels/{ChannelId}/messages/{MessageId}";


+ 1
- 1
src/Discord.Net/API/Client/Rest/DeleteRole.cs View File

@@ -3,7 +3,7 @@
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class DeleteRoleRequest : IRestRequest
public class DeleteRoleRequest : IRestRequest
{ {
string IRestRequest.Method => "DELETE"; string IRestRequest.Method => "DELETE";
string IRestRequest.Endpoint => $"guilds/{GuildId}/roles/{RoleId}"; string IRestRequest.Endpoint => $"guilds/{GuildId}/roles/{RoleId}";


+ 2
- 2
src/Discord.Net/API/Client/Rest/Gateway.cs View File

@@ -3,7 +3,7 @@
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class GatewayRequest : IRestRequest<GatewayResponse>
public class GatewayRequest : IRestRequest<GatewayResponse>
{ {
string IRestRequest.Method => "GET"; string IRestRequest.Method => "GET";
string IRestRequest.Endpoint => $"gateway"; string IRestRequest.Endpoint => $"gateway";
@@ -11,7 +11,7 @@ namespace Discord.API.Client.Rest
bool IRestRequest.IsPrivate => false; bool IRestRequest.IsPrivate => false;
} }
public sealed class GatewayResponse
public class GatewayResponse
{ {
[JsonProperty("url")] [JsonProperty("url")]
public string Url { get; set; } public string Url { get; set; }


+ 1
- 1
src/Discord.Net/API/Client/Rest/GetBans.cs View File

@@ -3,7 +3,7 @@
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class GetBansRequest : IRestRequest<UserReference[]>
public class GetBansRequest : IRestRequest<UserReference[]>
{ {
string IRestRequest.Method => "GET"; string IRestRequest.Method => "GET";
string IRestRequest.Endpoint => $"guilds/{GuildId}/bans"; string IRestRequest.Endpoint => $"guilds/{GuildId}/bans";


+ 1
- 1
src/Discord.Net/API/Client/Rest/GetInvite.cs View File

@@ -3,7 +3,7 @@
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class GetInviteRequest : IRestRequest<InviteReference>
public class GetInviteRequest : IRestRequest<InviteReference>
{ {
string IRestRequest.Method => "GET"; string IRestRequest.Method => "GET";
string IRestRequest.Endpoint => $"invite/{InviteCode}"; string IRestRequest.Endpoint => $"invite/{InviteCode}";


+ 1
- 1
src/Discord.Net/API/Client/Rest/GetInvites.cs View File

@@ -3,7 +3,7 @@
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class GetInvitesRequest : IRestRequest<InviteReference[]>
public class GetInvitesRequest : IRestRequest<InviteReference[]>
{ {
string IRestRequest.Method => "GET"; string IRestRequest.Method => "GET";
string IRestRequest.Endpoint => $"guilds/{GuildId}/invites"; string IRestRequest.Endpoint => $"guilds/{GuildId}/invites";


+ 1
- 1
src/Discord.Net/API/Client/Rest/GetMessages.cs View File

@@ -4,7 +4,7 @@ using System.Text;
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class GetMessagesRequest : IRestRequest<Message[]>
public class GetMessagesRequest : IRestRequest<Message[]>
{ {
string IRestRequest.Method => "GET"; string IRestRequest.Method => "GET";
string IRestRequest.Endpoint string IRestRequest.Endpoint


+ 2
- 2
src/Discord.Net/API/Client/Rest/GetVoiceRegions.cs View File

@@ -3,7 +3,7 @@
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class GetVoiceRegionsRequest : IRestRequest<GetVoiceRegionsResponse[]>
public class GetVoiceRegionsRequest : IRestRequest<GetVoiceRegionsResponse[]>
{ {
string IRestRequest.Method => "GET"; string IRestRequest.Method => "GET";
string IRestRequest.Endpoint => $"voice/regions"; string IRestRequest.Endpoint => $"voice/regions";
@@ -11,7 +11,7 @@ namespace Discord.API.Client.Rest
bool IRestRequest.IsPrivate => false; bool IRestRequest.IsPrivate => false;
} }
public sealed class GetVoiceRegionsResponse
public class GetVoiceRegionsResponse
{ {
[JsonProperty("sample_hostname")] [JsonProperty("sample_hostname")]
public string Hostname { get; set; } public string Hostname { get; set; }


+ 5
- 5
src/Discord.Net/API/Client/Rest/GetWidget.cs View File

@@ -4,7 +4,7 @@ using Newtonsoft.Json;
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class GetWidgetRequest : IRestRequest<GetWidgetResponse>
public class GetWidgetRequest : IRestRequest<GetWidgetResponse>
{ {
string IRestRequest.Method => "GET"; string IRestRequest.Method => "GET";
string IRestRequest.Endpoint => $"servers/{GuildId}/widget.json"; string IRestRequest.Endpoint => $"servers/{GuildId}/widget.json";
@@ -19,9 +19,9 @@ namespace Discord.API.Client.Rest
} }
} }


public sealed class GetWidgetResponse
public class GetWidgetResponse
{ {
public sealed class Channel
public class Channel
{ {
[JsonProperty("id"), JsonConverter(typeof(LongStringConverter))] [JsonProperty("id"), JsonConverter(typeof(LongStringConverter))]
public ulong Id { get; set; } public ulong Id { get; set; }
@@ -30,7 +30,7 @@ namespace Discord.API.Client.Rest
[JsonProperty("position")] [JsonProperty("position")]
public int Position { get; set; } public int Position { get; set; }
} }
public sealed class User : UserReference
public class User : UserReference
{ {
[JsonProperty("avatar_url")] [JsonProperty("avatar_url")]
public string AvatarUrl { get; set; } public string AvatarUrl { get; set; }
@@ -39,7 +39,7 @@ namespace Discord.API.Client.Rest
[JsonProperty("game")] [JsonProperty("game")]
public UserGame Game { get; set; } public UserGame Game { get; set; }
} }
public sealed class UserGame
public class UserGame
{ {
[JsonProperty("id")] [JsonProperty("id")]
public int Id { get; set; } public int Id { get; set; }


+ 1
- 1
src/Discord.Net/API/Client/Rest/KickMember.cs View File

@@ -3,7 +3,7 @@
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class KickMemberRequest : IRestRequest
public class KickMemberRequest : IRestRequest
{ {
string IRestRequest.Method => "DELETE"; string IRestRequest.Method => "DELETE";
string IRestRequest.Endpoint => $"guilds/{GuildId}/members/{UserId}"; string IRestRequest.Endpoint => $"guilds/{GuildId}/members/{UserId}";


+ 1
- 1
src/Discord.Net/API/Client/Rest/LeaveGuild.cs View File

@@ -3,7 +3,7 @@
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class LeaveGuildRequest : IRestRequest<Guild>
public class LeaveGuildRequest : IRestRequest<Guild>
{ {
string IRestRequest.Method => "DELETE"; string IRestRequest.Method => "DELETE";
string IRestRequest.Endpoint => $"guilds/{GuildId}"; string IRestRequest.Endpoint => $"guilds/{GuildId}";


+ 2
- 2
src/Discord.Net/API/Client/Rest/Login.cs View File

@@ -3,7 +3,7 @@
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class LoginRequest : IRestRequest<LoginResponse>
public class LoginRequest : IRestRequest<LoginResponse>
{ {
string IRestRequest.Method => Email != null ? "POST" : "GET"; string IRestRequest.Method => Email != null ? "POST" : "GET";
string IRestRequest.Endpoint => $"auth/login"; string IRestRequest.Endpoint => $"auth/login";
@@ -16,7 +16,7 @@ namespace Discord.API.Client.Rest
public string Password { get; set; } public string Password { get; set; }
} }


public sealed class LoginResponse
public class LoginResponse
{ {
[JsonProperty("token")] [JsonProperty("token")]
public string Token { get; set; } public string Token { get; set; }


+ 1
- 1
src/Discord.Net/API/Client/Rest/Logout.cs View File

@@ -3,7 +3,7 @@
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class LogoutRequest : IRestRequest
public class LogoutRequest : IRestRequest
{ {
string IRestRequest.Method => "POST"; string IRestRequest.Method => "POST";
string IRestRequest.Endpoint => $"auth/logout"; string IRestRequest.Endpoint => $"auth/logout";


+ 2
- 2
src/Discord.Net/API/Client/Rest/PruneMembers.cs View File

@@ -3,7 +3,7 @@
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class PruneMembersRequest : IRestRequest<PruneMembersResponse>
public class PruneMembersRequest : IRestRequest<PruneMembersResponse>
{ {
string IRestRequest.Method => IsSimulation ? "GET" : "POST"; string IRestRequest.Method => IsSimulation ? "GET" : "POST";
string IRestRequest.Endpoint => $"guilds/{GuildId}/prune?days={Days}"; string IRestRequest.Endpoint => $"guilds/{GuildId}/prune?days={Days}";
@@ -21,7 +21,7 @@ namespace Discord.API.Client.Rest
} }
} }


public sealed class PruneMembersResponse
public class PruneMembersResponse
{ {
[JsonProperty("pruned")] [JsonProperty("pruned")]
public int Pruned { get; set; } public int Pruned { get; set; }


+ 1
- 1
src/Discord.Net/API/Client/Rest/RemoveChannelPermission.cs View File

@@ -3,7 +3,7 @@
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class RemoveChannelPermissionsRequest : IRestRequest
public class RemoveChannelPermissionsRequest : IRestRequest
{ {
string IRestRequest.Method => "DELETE"; string IRestRequest.Method => "DELETE";
string IRestRequest.Endpoint => $"channels/{ChannelId}/permissions/{TargetId}"; string IRestRequest.Endpoint => $"channels/{ChannelId}/permissions/{TargetId}";


+ 1
- 1
src/Discord.Net/API/Client/Rest/RemoveGuildBan.cs View File

@@ -3,7 +3,7 @@
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class RemoveGuildBanRequest : IRestRequest
public class RemoveGuildBanRequest : IRestRequest
{ {
string IRestRequest.Method => "DELETE"; string IRestRequest.Method => "DELETE";
string IRestRequest.Endpoint => $"guilds/{GuildId}/bans/{UserId}"; string IRestRequest.Endpoint => $"guilds/{GuildId}/bans/{UserId}";


+ 2
- 2
src/Discord.Net/API/Client/Rest/ReorderChannels.cs View File

@@ -5,7 +5,7 @@ using System.Linq;
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class ReorderChannelsRequest : IRestRequest
public class ReorderChannelsRequest : IRestRequest
{ {
string IRestRequest.Method => "PATCH"; string IRestRequest.Method => "PATCH";
string IRestRequest.Endpoint => $"guilds/{GuildId}/channels"; string IRestRequest.Endpoint => $"guilds/{GuildId}/channels";
@@ -19,7 +19,7 @@ namespace Discord.API.Client.Rest
} }
bool IRestRequest.IsPrivate => false; bool IRestRequest.IsPrivate => false;


public sealed class Channel
public class Channel
{ {
[JsonProperty("id"), JsonConverter(typeof(LongStringConverter))] [JsonProperty("id"), JsonConverter(typeof(LongStringConverter))]
public ulong Id { get; set; } public ulong Id { get; set; }


+ 2
- 2
src/Discord.Net/API/Client/Rest/ReorderRoles.cs View File

@@ -5,7 +5,7 @@ using System.Linq;
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class ReorderRolesRequest : IRestRequest<Role[]>
public class ReorderRolesRequest : IRestRequest<Role[]>
{ {
string IRestRequest.Method => "PATCH"; string IRestRequest.Method => "PATCH";
string IRestRequest.Endpoint => $"guilds/{GuildId}/roles"; string IRestRequest.Endpoint => $"guilds/{GuildId}/roles";
@@ -19,7 +19,7 @@ namespace Discord.API.Client.Rest
} }
bool IRestRequest.IsPrivate => false; bool IRestRequest.IsPrivate => false;


public sealed class Role
public class Role
{ {
[JsonProperty("id"), JsonConverter(typeof(LongStringConverter))] [JsonProperty("id"), JsonConverter(typeof(LongStringConverter))]
public ulong Id { get; set; } public ulong Id { get; set; }


+ 1
- 1
src/Discord.Net/API/Client/Rest/SendFile.cs View File

@@ -4,7 +4,7 @@ using System.IO;
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class SendFileRequest : IRestFileRequest<Message>
public class SendFileRequest : IRestFileRequest<Message>
{ {
string IRestRequest.Method => "POST"; string IRestRequest.Method => "POST";
string IRestRequest.Endpoint => $"channels/{ChannelId}/messages"; string IRestRequest.Endpoint => $"channels/{ChannelId}/messages";


+ 1
- 1
src/Discord.Net/API/Client/Rest/SendIsTyping.cs View File

@@ -3,7 +3,7 @@
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class SendIsTypingRequest : IRestRequest
public class SendIsTypingRequest : IRestRequest
{ {
string IRestRequest.Method => "POST"; string IRestRequest.Method => "POST";
string IRestRequest.Endpoint => $"channels/{ChannelId}/typing"; string IRestRequest.Endpoint => $"channels/{ChannelId}/typing";


+ 1
- 1
src/Discord.Net/API/Client/Rest/SendMessage.cs View File

@@ -3,7 +3,7 @@
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class SendMessageRequest : IRestRequest<Message>
public class SendMessageRequest : IRestRequest<Message>
{ {
string IRestRequest.Method => "POST"; string IRestRequest.Method => "POST";
string IRestRequest.Endpoint => $"channels/{ChannelId}/messages"; string IRestRequest.Endpoint => $"channels/{ChannelId}/messages";


+ 1
- 1
src/Discord.Net/API/Client/Rest/UpdateChannel.cs View File

@@ -3,7 +3,7 @@
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class UpdateChannelRequest : IRestRequest<Channel>
public class UpdateChannelRequest : IRestRequest<Channel>
{ {
string IRestRequest.Method => "PATCH"; string IRestRequest.Method => "PATCH";
string IRestRequest.Endpoint => $"channels/{ChannelId}"; string IRestRequest.Endpoint => $"channels/{ChannelId}";


+ 1
- 1
src/Discord.Net/API/Client/Rest/UpdateGuild.cs View File

@@ -4,7 +4,7 @@ using Newtonsoft.Json;
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class UpdateGuildRequest : IRestRequest<Guild>
public class UpdateGuildRequest : IRestRequest<Guild>
{ {
string IRestRequest.Method => "PATCH"; string IRestRequest.Method => "PATCH";
string IRestRequest.Endpoint => $"guilds/{GuildId}"; string IRestRequest.Endpoint => $"guilds/{GuildId}";


+ 1
- 1
src/Discord.Net/API/Client/Rest/UpdateMember.cs View File

@@ -5,7 +5,7 @@ using System.Collections.Generic;
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class UpdateMemberRequest : IRestRequest
public class UpdateMemberRequest : IRestRequest
{ {
string IRestRequest.Method => "PATCH"; string IRestRequest.Method => "PATCH";
string IRestRequest.Endpoint => $"guilds/{GuildId}/members/{UserId}"; string IRestRequest.Endpoint => $"guilds/{GuildId}/members/{UserId}";


+ 1
- 1
src/Discord.Net/API/Client/Rest/UpdateMessage.cs View File

@@ -4,7 +4,7 @@ using Newtonsoft.Json;
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class UpdateMessageRequest : IRestRequest<Message>
public class UpdateMessageRequest : IRestRequest<Message>
{ {
string IRestRequest.Method => "PATCH"; string IRestRequest.Method => "PATCH";
string IRestRequest.Endpoint => $"channels/{ChannelId}/messages/{MessageId}"; string IRestRequest.Endpoint => $"channels/{ChannelId}/messages/{MessageId}";


+ 1
- 1
src/Discord.Net/API/Client/Rest/UpdateProfile.cs View File

@@ -3,7 +3,7 @@
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class UpdateProfileRequest : IRestRequest<User>
public class UpdateProfileRequest : IRestRequest<User>
{ {
string IRestRequest.Method => "PATCH"; string IRestRequest.Method => "PATCH";
string IRestRequest.Endpoint => $"users/@me"; string IRestRequest.Endpoint => $"users/@me";


+ 1
- 1
src/Discord.Net/API/Client/Rest/UpdateRole.cs View File

@@ -3,7 +3,7 @@
namespace Discord.API.Client.Rest namespace Discord.API.Client.Rest
{ {
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public sealed class UpdateRoleRequest : IRestRequest<Role>
public class UpdateRoleRequest : IRestRequest<Role>
{ {
string IRestRequest.Method => "PATCH"; string IRestRequest.Method => "PATCH";
string IRestRequest.Endpoint => $"guilds/{GuildId}/roles/{RoleId}"; string IRestRequest.Endpoint => $"guilds/{GuildId}/roles/{RoleId}";


+ 1
- 1
src/Discord.Net/API/Client/VoiceSocket/Commands/Heartbeat.cs View File

@@ -1,6 +1,6 @@
namespace Discord.API.Client.VoiceSocket namespace Discord.API.Client.VoiceSocket
{ {
public sealed class HeartbeatCommand : IWebSocketMessage
public class HeartbeatCommand : IWebSocketMessage
{ {
int IWebSocketMessage.OpCode => (int)OpCodes.Heartbeat; int IWebSocketMessage.OpCode => (int)OpCodes.Heartbeat;
object IWebSocketMessage.Payload => EpochTime.GetMilliseconds(); object IWebSocketMessage.Payload => EpochTime.GetMilliseconds();


+ 1
- 1
src/Discord.Net/API/Client/VoiceSocket/Commands/Identify.cs View File

@@ -3,7 +3,7 @@ using Newtonsoft.Json;


namespace Discord.API.Client.VoiceSocket namespace Discord.API.Client.VoiceSocket
{ {
public sealed class IdentifyCommand : IWebSocketMessage
public class IdentifyCommand : IWebSocketMessage
{ {
int IWebSocketMessage.OpCode => (int)OpCodes.Identify; int IWebSocketMessage.OpCode => (int)OpCodes.Identify;
object IWebSocketMessage.Payload => this; object IWebSocketMessage.Payload => this;


+ 2
- 2
src/Discord.Net/API/Client/VoiceSocket/Commands/SelectProtocol.cs View File

@@ -2,13 +2,13 @@


namespace Discord.API.Client.VoiceSocket namespace Discord.API.Client.VoiceSocket
{ {
public sealed class SelectProtocolCommand : IWebSocketMessage
public class SelectProtocolCommand : IWebSocketMessage
{ {
int IWebSocketMessage.OpCode => (int)OpCodes.SelectProtocol; int IWebSocketMessage.OpCode => (int)OpCodes.SelectProtocol;
object IWebSocketMessage.Payload => this; object IWebSocketMessage.Payload => this;
bool IWebSocketMessage.IsPrivate => false; bool IWebSocketMessage.IsPrivate => false;


public sealed class Data
public class Data
{ {
[JsonProperty("address")] [JsonProperty("address")]
public string Address { get; set; } public string Address { get; set; }


+ 1
- 1
src/Discord.Net/API/Client/VoiceSocket/Commands/SetSpeaking.cs View File

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


namespace Discord.API.Client.VoiceSocket namespace Discord.API.Client.VoiceSocket
{ {
public sealed class SetSpeakingCommand : IWebSocketMessage
public class SetSpeakingCommand : IWebSocketMessage
{ {
int IWebSocketMessage.OpCode => (int)OpCodes.Speaking; int IWebSocketMessage.OpCode => (int)OpCodes.Speaking;
object IWebSocketMessage.Payload => this; object IWebSocketMessage.Payload => this;


+ 1
- 1
src/Discord.Net/API/Client/VoiceSocket/Events/Ready.cs View File

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


namespace Discord.API.Client.VoiceSocket namespace Discord.API.Client.VoiceSocket
{ {
public sealed class ReadyEvent
public class ReadyEvent
{ {
[JsonProperty("ssrc")] [JsonProperty("ssrc")]
public uint SSRC { get; set; } public uint SSRC { get; set; }


+ 1
- 1
src/Discord.Net/API/Client/VoiceSocket/Events/SessionDescription.cs View File

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


namespace Discord.API.Client.VoiceSocket namespace Discord.API.Client.VoiceSocket
{ {
public sealed class SessionDescriptionEvent
public class SessionDescriptionEvent
{ {
[JsonProperty("secret_key")] [JsonProperty("secret_key")]
public byte[] SecretKey { get; set; } public byte[] SecretKey { get; set; }


+ 1
- 1
src/Discord.Net/API/Client/VoiceSocket/Events/Speaking.cs View File

@@ -3,7 +3,7 @@ using Newtonsoft.Json;


namespace Discord.API.Client.VoiceSocket namespace Discord.API.Client.VoiceSocket
{ {
public sealed class SpeakingEvent
public class SpeakingEvent
{ {
[JsonProperty("user_id"), JsonConverter(typeof(LongStringConverter))] [JsonProperty("user_id"), JsonConverter(typeof(LongStringConverter))]
public ulong UserId { get; set; } public ulong UserId { get; set; }


+ 4
- 4
src/Discord.Net/API/Converters.cs View File

@@ -4,7 +4,7 @@ using System.Collections.Generic;


namespace Discord.API.Converters namespace Discord.API.Converters
{ {
public sealed class LongStringConverter : JsonConverter
public class LongStringConverter : JsonConverter
{ {
public override bool CanConvert(Type objectType) public override bool CanConvert(Type objectType)
=> objectType == typeof(ulong); => objectType == typeof(ulong);
@@ -14,7 +14,7 @@ namespace Discord.API.Converters
=> writer.WriteValue(((ulong)value).ToIdString()); => writer.WriteValue(((ulong)value).ToIdString());
} }


public sealed class NullableLongStringConverter : JsonConverter
public class NullableLongStringConverter : JsonConverter
{ {
public override bool CanConvert(Type objectType) public override bool CanConvert(Type objectType)
=> objectType == typeof(ulong?); => objectType == typeof(ulong?);
@@ -24,7 +24,7 @@ namespace Discord.API.Converters
=> writer.WriteValue(((ulong?)value).ToIdString()); => writer.WriteValue(((ulong?)value).ToIdString());
} }


/*public sealed class LongStringEnumerableConverter : JsonConverter
/*public class LongStringEnumerableConverter : JsonConverter
{ {
public override bool CanConvert(Type objectType) => objectType == typeof(IEnumerable<ulong>); public override bool CanConvert(Type objectType) => objectType == typeof(IEnumerable<ulong>);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
@@ -55,7 +55,7 @@ namespace Discord.API.Converters
} }
}*/ }*/


internal sealed class LongStringArrayConverter : JsonConverter
internal class LongStringArrayConverter : JsonConverter
{ {
public override bool CanConvert(Type objectType) => objectType == typeof(IEnumerable<ulong[]>); public override bool CanConvert(Type objectType) => objectType == typeof(IEnumerable<ulong[]>);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save