Browse Source

Merge branch 'dev' of https://github.com/RogueException/Discord.Net into dev

tags/1.0-rc
Christopher F 8 years ago
parent
commit
1510616057
100 changed files with 809 additions and 756 deletions
  1. +42
    -81
      src/Discord.Net.Commands/CommandService.cs
  2. +0
    -1
      src/Discord.Net.Commands/Map/CommandMap.cs
  3. +36
    -0
      src/Discord.Net.Commands/PrimitiveParsers.cs
  4. +2
    -20
      src/Discord.Net.Commands/Readers/EnumTypeReader.cs
  5. +0
    -17
      src/Discord.Net.Commands/Readers/GenericTypeReader.cs
  6. +23
    -0
      src/Discord.Net.Commands/Readers/SimpleTypeReader.cs
  7. +1
    -1
      src/Discord.Net.Commands/ReflectionUtils.cs
  8. +5
    -5
      src/Discord.Net/API/CDN.cs
  9. +58
    -58
      src/Discord.Net/API/DiscordAPIClient.cs
  10. +1
    -0
      src/Discord.Net/API/Gateway/IdentifyParams.cs
  11. +4
    -3
      src/Discord.Net/API/Gateway/RequestMembersParams.cs
  12. +1
    -0
      src/Discord.Net/API/Gateway/ResumeParams.cs
  13. +1
    -0
      src/Discord.Net/API/Gateway/StatusUpdateParams.cs
  14. +1
    -0
      src/Discord.Net/API/Gateway/UpdateStatusParams.cs
  15. +4
    -4
      src/Discord.Net/API/Gateway/VoiceStateUpdateParams.cs
  16. +0
    -11
      src/Discord.Net/API/Rest/ApplicationInfo.cs
  17. +12
    -4
      src/Discord.Net/API/Rest/CreateChannelInviteParams.cs
  18. +4
    -3
      src/Discord.Net/API/Rest/CreateDMChannelParams.cs
  19. +3
    -1
      src/Discord.Net/API/Rest/CreateGuildBanParams.cs
  20. +8
    -3
      src/Discord.Net/API/Rest/CreateGuildChannelParams.cs
  21. +4
    -2
      src/Discord.Net/API/Rest/CreateGuildIntegrationParams.cs
  22. +6
    -9
      src/Discord.Net/API/Rest/CreateGuildParams.cs
  23. +10
    -5
      src/Discord.Net/API/Rest/CreateMessageParams.cs
  24. +4
    -3
      src/Discord.Net/API/Rest/DeleteMessagesParams.cs
  25. +6
    -4
      src/Discord.Net/API/Rest/GetChannelMessagesParams.cs
  26. +5
    -2
      src/Discord.Net/API/Rest/GetGuildMembersParams.cs
  27. +2
    -1
      src/Discord.Net/API/Rest/GuildPruneParams.cs
  28. +4
    -2
      src/Discord.Net/API/Rest/ModifyChannelPermissionsParams.cs
  29. +2
    -1
      src/Discord.Net/API/Rest/ModifyCurrentUserNickParams.cs
  30. +5
    -14
      src/Discord.Net/API/Rest/ModifyCurrentUserParams.cs
  31. +6
    -2
      src/Discord.Net/API/Rest/ModifyGuildChannelParams.cs
  32. +4
    -2
      src/Discord.Net/API/Rest/ModifyGuildChannelsParams.cs
  33. +6
    -4
      src/Discord.Net/API/Rest/ModifyGuildEmbedParams.cs
  34. +9
    -3
      src/Discord.Net/API/Rest/ModifyGuildIntegrationParams.cs
  35. +15
    -9
      src/Discord.Net/API/Rest/ModifyGuildMemberParams.cs
  36. +27
    -38
      src/Discord.Net/API/Rest/ModifyGuildParams.cs
  37. +15
    -5
      src/Discord.Net/API/Rest/ModifyGuildRoleParams.cs
  38. +2
    -1
      src/Discord.Net/API/Rest/ModifyGuildRolesParams.cs
  39. +3
    -1
      src/Discord.Net/API/Rest/ModifyMessageParams.cs
  40. +5
    -2
      src/Discord.Net/API/Rest/ModifyPresenceParams.cs
  41. +3
    -1
      src/Discord.Net/API/Rest/ModifyTextChannelParams.cs
  42. +6
    -2
      src/Discord.Net/API/Rest/ModifyVoiceChannelParams.cs
  43. +20
    -13
      src/Discord.Net/API/Rest/UploadFileParams.cs
  44. +2
    -2
      src/Discord.Net/Audio/AudioClient.cs
  45. +38
    -38
      src/Discord.Net/Data/DataStore.cs
  46. +3
    -19
      src/Discord.Net/DiscordConfig.cs
  47. +6
    -6
      src/Discord.Net/DiscordRestClient.cs
  48. +20
    -0
      src/Discord.Net/DiscordRestConfig.cs
  49. +38
    -44
      src/Discord.Net/DiscordSocketClient.cs
  50. +3
    -8
      src/Discord.Net/DiscordSocketConfig.cs
  51. +2
    -2
      src/Discord.Net/Entities/Application.cs
  52. +2
    -2
      src/Discord.Net/Entities/Channels/DMChannel.cs
  53. +2
    -2
      src/Discord.Net/Entities/Channels/GroupChannel.cs
  54. +3
    -3
      src/Discord.Net/Entities/Channels/GuildChannel.cs
  55. +3
    -4
      src/Discord.Net/Entities/Channels/IMessageChannel.cs
  56. +1
    -1
      src/Discord.Net/Entities/Channels/IPrivateChannel.cs
  57. +2
    -2
      src/Discord.Net/Entities/Channels/TextChannel.cs
  58. +2
    -2
      src/Discord.Net/Entities/Channels/VoiceChannel.cs
  59. +3
    -2
      src/Discord.Net/Entities/Entity.cs
  60. +7
    -7
      src/Discord.Net/Entities/Guilds/Guild.cs
  61. +1
    -1
      src/Discord.Net/Entities/Guilds/GuildIntegration.cs
  62. +2
    -2
      src/Discord.Net/Entities/Guilds/UserGuild.cs
  63. +4
    -4
      src/Discord.Net/Entities/Invites/Invite.cs
  64. +1
    -1
      src/Discord.Net/Entities/Invites/InviteMetadata.cs
  65. +1
    -1
      src/Discord.Net/Entities/Messages/Message.cs
  66. +2
    -1
      src/Discord.Net/Entities/Roles/Role.cs
  67. +4
    -2
      src/Discord.Net/Entities/Users/GroupUser.cs
  68. +18
    -10
      src/Discord.Net/Entities/Users/GuildUser.cs
  69. +9
    -9
      src/Discord.Net/Entities/Users/SelfUser.cs
  70. +1
    -1
      src/Discord.Net/Entities/Users/User.cs
  71. +0
    -17
      src/Discord.Net/Entities/WebSocket/CachedMessage.cs
  72. +0
    -19
      src/Discord.Net/Entities/WebSocket/CachedSelfUser.cs
  73. +2
    -2
      src/Discord.Net/Entities/WebSocket/Channels/ISocketChannel.cs
  74. +7
    -0
      src/Discord.Net/Entities/WebSocket/Channels/ISocketGuildChannel.cs
  75. +16
    -0
      src/Discord.Net/Entities/WebSocket/Channels/ISocketMessageChannel.cs
  76. +9
    -0
      src/Discord.Net/Entities/WebSocket/Channels/ISocketPrivateChannel.cs
  77. +14
    -14
      src/Discord.Net/Entities/WebSocket/Channels/MessageCache.cs
  78. +23
    -22
      src/Discord.Net/Entities/WebSocket/Channels/MessageManager.cs
  79. +16
    -14
      src/Discord.Net/Entities/WebSocket/Channels/SocketDMChannel.cs
  80. +23
    -21
      src/Discord.Net/Entities/WebSocket/Channels/SocketGroupChannel.cs
  81. +17
    -15
      src/Discord.Net/Entities/WebSocket/Channels/SocketTextChannel.cs
  82. +7
    -5
      src/Discord.Net/Entities/WebSocket/Channels/SocketVoiceChannel.cs
  83. +31
    -29
      src/Discord.Net/Entities/WebSocket/Guilds/SocketGuild.cs
  84. +0
    -7
      src/Discord.Net/Entities/WebSocket/ICachedEntity.cs
  85. +0
    -7
      src/Discord.Net/Entities/WebSocket/ICachedGuildChannel.cs
  86. +0
    -16
      src/Discord.Net/Entities/WebSocket/ICachedMessageChannel.cs
  87. +0
    -9
      src/Discord.Net/Entities/WebSocket/ICachedPrivateChannel.cs
  88. +0
    -9
      src/Discord.Net/Entities/WebSocket/ICachedUser.cs
  89. +19
    -0
      src/Discord.Net/Entities/WebSocket/Messages/SocketMessage.cs
  90. +9
    -0
      src/Discord.Net/Entities/WebSocket/Users/ISocketUser.cs
  91. +0
    -0
      src/Discord.Net/Entities/WebSocket/Users/Presence.cs
  92. +8
    -6
      src/Discord.Net/Entities/WebSocket/Users/SocketDMUser.cs
  93. +7
    -5
      src/Discord.Net/Entities/WebSocket/Users/SocketGlobalUser.cs
  94. +9
    -7
      src/Discord.Net/Entities/WebSocket/Users/SocketGroupUser.cs
  95. +10
    -8
      src/Discord.Net/Entities/WebSocket/Users/SocketGuildUser.cs
  96. +21
    -0
      src/Discord.Net/Entities/WebSocket/Users/SocketSelfUser.cs
  97. +3
    -3
      src/Discord.Net/Entities/WebSocket/Users/VoiceState.cs
  98. +1
    -1
      src/Discord.Net/Extensions/DiscordClientExtensions.cs
  99. +2
    -2
      src/Discord.Net/Extensions/GuildUserExtensions.cs
  100. +0
    -4
      src/Discord.Net/IDiscordClient.cs

+ 42
- 81
src/Discord.Net.Commands/CommandService.cs View File

@@ -2,7 +2,6 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Globalization;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Threading; using System.Threading;
@@ -27,94 +26,56 @@ namespace Discord.Commands
_map = new CommandMap(); _map = new CommandMap();
_typeReaders = new ConcurrentDictionary<Type, TypeReader> _typeReaders = new ConcurrentDictionary<Type, TypeReader>
{ {
[typeof(string)] = new GenericTypeReader((m, s) => Task.FromResult(TypeReaderResult.FromSuccess(s))),
[typeof(byte)] = new GenericTypeReader((m, s) =>
{
byte value;
if (byte.TryParse(s, out value)) return Task.FromResult(TypeReaderResult.FromSuccess(value));
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Failed to parse Byte"));
}),
[typeof(sbyte)] = new GenericTypeReader((m, s) =>
{
sbyte value;
if (sbyte.TryParse(s, out value)) return Task.FromResult(TypeReaderResult.FromSuccess(value));
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Failed to parse SByte"));
}),
[typeof(ushort)] = new GenericTypeReader((m, s) =>
{
ushort value;
if (ushort.TryParse(s, out value)) return Task.FromResult(TypeReaderResult.FromSuccess(value));
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Failed to parse UInt16"));
}),
[typeof(short)] = new GenericTypeReader((m, s) =>
{
short value;
if (short.TryParse(s, out value)) return Task.FromResult(TypeReaderResult.FromSuccess(value));
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Failed to parse Int16"));
}),
[typeof(uint)] = new GenericTypeReader((m, s) =>
{
uint value;
if (uint.TryParse(s, out value)) return Task.FromResult(TypeReaderResult.FromSuccess(value));
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Failed to parse UInt32"));
}),
[typeof(int)] = new GenericTypeReader((m, s) =>
{
int value;
if (int.TryParse(s, out value)) return Task.FromResult(TypeReaderResult.FromSuccess(value));
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Failed to parse Int32"));
}),
[typeof(ulong)] = new GenericTypeReader((m, s) =>
{
ulong value;
if (ulong.TryParse(s, out value)) return Task.FromResult(TypeReaderResult.FromSuccess(value));
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Failed to parse UInt64"));
}),
[typeof(long)] = new GenericTypeReader((m, s) =>
{
long value;
if (long.TryParse(s, out value)) return Task.FromResult(TypeReaderResult.FromSuccess(value));
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Failed to parse Int64"));
}),
[typeof(float)] = new GenericTypeReader((m, s) =>
{
float value;
if (float.TryParse(s, out value)) return Task.FromResult(TypeReaderResult.FromSuccess(value));
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Failed to parse Single"));
}),
[typeof(double)] = new GenericTypeReader((m, s) =>
{
double value;
if (double.TryParse(s, out value)) return Task.FromResult(TypeReaderResult.FromSuccess(value));
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Failed to parse Double"));
}),
[typeof(decimal)] = new GenericTypeReader((m, s) =>
{
decimal value;
if (decimal.TryParse(s, out value)) return Task.FromResult(TypeReaderResult.FromSuccess(value));
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Failed to parse Decimal"));
}),
[typeof(DateTime)] = new GenericTypeReader((m, s) =>
{
DateTime value;
if (DateTime.TryParse(s, out value)) return Task.FromResult(TypeReaderResult.FromSuccess(value));
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Failed to parse DateTime"));
}),
[typeof(DateTimeOffset)] = new GenericTypeReader((m, s) =>
{
DateTimeOffset value;
if (DateTimeOffset.TryParse(s, out value)) return Task.FromResult(TypeReaderResult.FromSuccess(value));
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Failed to parse DateTimeOffset"));
}),
[typeof(string)] = new SimpleTypeReader<string>(),
[typeof(byte)] = new SimpleTypeReader<byte>(),
[typeof(sbyte)] = new SimpleTypeReader<sbyte>(),
[typeof(ushort)] = new SimpleTypeReader<ushort>(),
[typeof(short)] = new SimpleTypeReader<short>(),
[typeof(uint)] = new SimpleTypeReader<uint>(),
[typeof(int)] = new SimpleTypeReader<int>(),
[typeof(ulong)] = new SimpleTypeReader<ulong>(),
[typeof(long)] = new SimpleTypeReader<long>(),
[typeof(float)] = new SimpleTypeReader<float>(),
[typeof(double)] = new SimpleTypeReader<double>(),
[typeof(decimal)] = new SimpleTypeReader<decimal>(),
[typeof(DateTime)] = new SimpleTypeReader<DateTime>(),
[typeof(DateTimeOffset)] = new SimpleTypeReader<DateTimeOffset>(),

//TODO: Do we want to support any other interfaces?

//[typeof(IMentionable)] = new GeneralTypeReader(),
//[typeof(ISnowflakeEntity)] = new GeneralTypeReader(),
//[typeof(IEntity<ulong>)] = new GeneralTypeReader(),


[typeof(IMessage)] = new MessageTypeReader(), [typeof(IMessage)] = new MessageTypeReader(),
//[typeof(IAttachment)] = new xxx(),
//[typeof(IEmbed)] = new xxx(),

[typeof(IChannel)] = new ChannelTypeReader<IChannel>(), [typeof(IChannel)] = new ChannelTypeReader<IChannel>(),
[typeof(IDMChannel)] = new ChannelTypeReader<IDMChannel>(),
[typeof(IGroupChannel)] = new ChannelTypeReader<IGroupChannel>(),
[typeof(IGuildChannel)] = new ChannelTypeReader<IGuildChannel>(), [typeof(IGuildChannel)] = new ChannelTypeReader<IGuildChannel>(),
[typeof(IMessageChannel)] = new ChannelTypeReader<IMessageChannel>(),
[typeof(IPrivateChannel)] = new ChannelTypeReader<IPrivateChannel>(),
[typeof(ITextChannel)] = new ChannelTypeReader<ITextChannel>(), [typeof(ITextChannel)] = new ChannelTypeReader<ITextChannel>(),
[typeof(IVoiceChannel)] = new ChannelTypeReader<IVoiceChannel>(), [typeof(IVoiceChannel)] = new ChannelTypeReader<IVoiceChannel>(),

//[typeof(IGuild)] = new GuildTypeReader<IGuild>(),
//[typeof(IUserGuild)] = new GuildTypeReader<IUserGuild>(),
//[typeof(IGuildIntegration)] = new xxx(),

[typeof(IRole)] = new RoleTypeReader(), [typeof(IRole)] = new RoleTypeReader(),

//[typeof(IInvite)] = new InviteTypeReader<IInvite>(),
//[typeof(IInviteMetadata)] = new InviteTypeReader<IInviteMetadata>(),

[typeof(IUser)] = new UserTypeReader<IUser>(), [typeof(IUser)] = new UserTypeReader<IUser>(),
[typeof(IGuildUser)] = new UserTypeReader<IGuildUser>()
[typeof(IGroupUser)] = new UserTypeReader<IGroupUser>(),
[typeof(IGuildUser)] = new UserTypeReader<IGuildUser>(),
//[typeof(ISelfUser)] = new UserTypeReader<ISelfUser>(),
//[typeof(IPresence)] = new UserTypeReader<IPresence>(),
//[typeof(IVoiceState)] = new UserTypeReader<IVoiceState>(),
//[typeof(IConnection)] = new xxx(),
}; };
} }




+ 0
- 1
src/Discord.Net.Commands/Map/CommandMap.cs View File

@@ -1,6 +1,5 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq; using System.Linq;


namespace Discord.Commands namespace Discord.Commands


+ 36
- 0
src/Discord.Net.Commands/PrimitiveParsers.cs View File

@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;

namespace Discord.Commands
{
internal delegate bool TryParseDelegate<T>(string str, out T value);

internal static class PrimitiveParsers
{
private static readonly IReadOnlyDictionary<Type, Delegate> _parsers;

static PrimitiveParsers()
{
var parserBuilder = ImmutableDictionary.CreateBuilder<Type, Delegate>();
parserBuilder[typeof(string)] = (TryParseDelegate<string>)delegate(string str, out string value) { value = str; return true; };
parserBuilder[typeof(sbyte)] = (TryParseDelegate<sbyte>)sbyte.TryParse;
parserBuilder[typeof(byte)] = (TryParseDelegate<byte>)byte.TryParse;
parserBuilder[typeof(short)] = (TryParseDelegate<short>)short.TryParse;
parserBuilder[typeof(ushort)] = (TryParseDelegate<ushort>)ushort.TryParse;
parserBuilder[typeof(int)] = (TryParseDelegate<int>)int.TryParse;
parserBuilder[typeof(uint)] = (TryParseDelegate<uint>)uint.TryParse;
parserBuilder[typeof(long)] = (TryParseDelegate<long>)long.TryParse;
parserBuilder[typeof(ulong)] = (TryParseDelegate<ulong>)ulong.TryParse;
parserBuilder[typeof(float)] = (TryParseDelegate<float>)float.TryParse;
parserBuilder[typeof(double)] = (TryParseDelegate<double>)double.TryParse;
parserBuilder[typeof(decimal)] = (TryParseDelegate<decimal>)decimal.TryParse;
parserBuilder[typeof(DateTime)] = (TryParseDelegate<DateTime>)DateTime.TryParse;
parserBuilder[typeof(DateTimeOffset)] = (TryParseDelegate<DateTimeOffset>)DateTimeOffset.TryParse;
_parsers = parserBuilder.ToImmutable();
}

public static TryParseDelegate<T> Get<T>() => (TryParseDelegate<T>)_parsers[typeof(T)];
public static Delegate Get(Type type) => _parsers[type];
}
}

+ 2
- 20
src/Discord.Net.Commands/Readers/EnumTypeReader.cs View File

@@ -7,31 +7,13 @@ using System.Threading.Tasks;


namespace Discord.Commands namespace Discord.Commands
{ {
delegate bool TryParseDelegate<T>(string str, out T value);

internal static class EnumTypeReader internal static class EnumTypeReader
{
private static readonly IReadOnlyDictionary<Type, object> _parsers;

static EnumTypeReader()
{
var parserBuilder = ImmutableDictionary.CreateBuilder<Type, object>();
parserBuilder[typeof(sbyte)] = (TryParseDelegate<sbyte>)sbyte.TryParse;
parserBuilder[typeof(byte)] = (TryParseDelegate<byte>)byte.TryParse;
parserBuilder[typeof(short)] = (TryParseDelegate<short>)short.TryParse;
parserBuilder[typeof(ushort)] = (TryParseDelegate<ushort>)ushort.TryParse;
parserBuilder[typeof(int)] = (TryParseDelegate<int>)int.TryParse;
parserBuilder[typeof(uint)] = (TryParseDelegate<uint>)uint.TryParse;
parserBuilder[typeof(long)] = (TryParseDelegate<long>)long.TryParse;
parserBuilder[typeof(ulong)] = (TryParseDelegate<ulong>)ulong.TryParse;
_parsers = parserBuilder.ToImmutable();
}

{
public static TypeReader GetReader(Type type) public static TypeReader GetReader(Type type)
{ {
Type baseType = Enum.GetUnderlyingType(type); Type baseType = Enum.GetUnderlyingType(type);
var constructor = typeof(EnumTypeReader<>).MakeGenericType(baseType).GetTypeInfo().DeclaredConstructors.First(); var constructor = typeof(EnumTypeReader<>).MakeGenericType(baseType).GetTypeInfo().DeclaredConstructors.First();
return (TypeReader)constructor.Invoke(new object[] { type, _parsers[baseType] });
return (TypeReader)constructor.Invoke(new object[] { type, PrimitiveParsers.Get(baseType) });
} }
} }




+ 0
- 17
src/Discord.Net.Commands/Readers/GenericTypeReader.cs View File

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

namespace Discord.Commands
{
internal class GenericTypeReader : TypeReader
{
private readonly Func<IMessage, string, Task<TypeReaderResult>> _action;

public GenericTypeReader(Func<IMessage, string, Task<TypeReaderResult>> action)
{
_action = action;
}

public override Task<TypeReaderResult> Read(IMessage context, string input) => _action(context, input);
}
}

+ 23
- 0
src/Discord.Net.Commands/Readers/SimpleTypeReader.cs View File

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

namespace Discord.Commands
{
internal class SimpleTypeReader<T> : TypeReader
{
private readonly TryParseDelegate<T> _tryParse;

public SimpleTypeReader()
{
_tryParse = PrimitiveParsers.Get<T>();
}

public override Task<TypeReaderResult> Read(IMessage context, string input)
{
T value;
if (_tryParse(input, out value))
return Task.FromResult(TypeReaderResult.FromSuccess(value));
else
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, $"Failed to parse {typeof(T).Name}"));
}
}
}

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

@@ -8,7 +8,7 @@ namespace Discord.Commands
{ {
internal static object CreateObject(TypeInfo typeInfo, CommandService service, IDependencyMap map = null) internal static object CreateObject(TypeInfo typeInfo, CommandService service, IDependencyMap map = null)
{ {
var constructors = typeInfo.DeclaredConstructors.ToArray();
var constructors = typeInfo.DeclaredConstructors.Where(x => !x.IsStatic).ToArray();
if (constructors.Length == 0) if (constructors.Length == 0)
throw new InvalidOperationException($"No constructor found for \"{typeInfo.FullName}\""); throw new InvalidOperationException($"No constructor found for \"{typeInfo.FullName}\"");
else if (constructors.Length > 1) else if (constructors.Length > 1)


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

@@ -3,14 +3,14 @@
internal static class CDN internal static class CDN
{ {
public static string GetApplicationIconUrl(ulong appId, string iconId) public static string GetApplicationIconUrl(ulong appId, string iconId)
=> iconId != null ? $"{DiscordConfig.CDNUrl}app-icons/{appId}/{iconId}.jpg" : null;
=> iconId != null ? $"{DiscordRestConfig.CDNUrl}app-icons/{appId}/{iconId}.jpg" : null;
public static string GetUserAvatarUrl(ulong userId, string avatarId) public static string GetUserAvatarUrl(ulong userId, string avatarId)
=> avatarId != null ? $"{DiscordConfig.CDNUrl}avatars/{userId}/{avatarId}.jpg" : null;
=> avatarId != null ? $"{DiscordRestConfig.CDNUrl}avatars/{userId}/{avatarId}.jpg" : null;
public static string GetGuildIconUrl(ulong guildId, string iconId) public static string GetGuildIconUrl(ulong guildId, string iconId)
=> iconId != null ? $"{DiscordConfig.CDNUrl}icons/{guildId}/{iconId}.jpg" : null;
=> iconId != null ? $"{DiscordRestConfig.CDNUrl}icons/{guildId}/{iconId}.jpg" : null;
public static string GetGuildSplashUrl(ulong guildId, string splashId) public static string GetGuildSplashUrl(ulong guildId, string splashId)
=> splashId != null ? $"{DiscordConfig.CDNUrl}splashes/{guildId}/{splashId}.jpg" : null;
=> splashId != null ? $"{DiscordRestConfig.CDNUrl}splashes/{guildId}/{splashId}.jpg" : null;
public static string GetChannelIconUrl(ulong channelId, string iconId) public static string GetChannelIconUrl(ulong channelId, string iconId)
=> iconId != null ? $"{DiscordConfig.CDNUrl}channel-icons/{channelId}/{iconId}.jpg" : null;
=> iconId != null ? $"{DiscordRestConfig.CDNUrl}channel-icons/{channelId}/{iconId}.jpg" : null;
} }
} }

+ 58
- 58
src/Discord.Net/API/DiscordAPIClient.cs View File

@@ -55,9 +55,9 @@ namespace Discord.API


_requestQueue = requestQueue ?? new RequestQueue(); _requestQueue = requestQueue ?? new RequestQueue();


_restClient = restClientProvider(DiscordConfig.ClientAPIUrl);
_restClient = restClientProvider(DiscordRestConfig.ClientAPIUrl);
_restClient.SetHeader("accept", "*/*"); _restClient.SetHeader("accept", "*/*");
_restClient.SetHeader("user-agent", DiscordConfig.UserAgent);
_restClient.SetHeader("user-agent", DiscordRestConfig.UserAgent);
if (webSocketProvider != null) if (webSocketProvider != null)
{ {
_gatewayClient = webSocketProvider(); _gatewayClient = webSocketProvider();
@@ -211,7 +211,7 @@ namespace Discord.API
if (_gatewayUrl == null) if (_gatewayUrl == null)
{ {
var gatewayResponse = await GetGatewayAsync().ConfigureAwait(false); var gatewayResponse = await GetGatewayAsync().ConfigureAwait(false);
_gatewayUrl = $"{gatewayResponse.Url}?v={DiscordConfig.APIVersion}&encoding={DiscordConfig.GatewayEncoding}";
_gatewayUrl = $"{gatewayResponse.Url}?v={DiscordConfig.APIVersion}&encoding={DiscordSocketConfig.GatewayEncoding}";
} }
await _gatewayClient.ConnectAsync(_gatewayUrl).ConfigureAwait(false); await _gatewayClient.ConnectAsync(_gatewayUrl).ConfigureAwait(false);


@@ -461,8 +461,8 @@ namespace Discord.API
{ {
Preconditions.NotEqual(guildId, 0, nameof(guildId)); Preconditions.NotEqual(guildId, 0, nameof(guildId));
Preconditions.NotNull(args, nameof(args)); Preconditions.NotNull(args, nameof(args));
Preconditions.GreaterThan(args.Bitrate, 0, nameof(args.Bitrate));
Preconditions.NotNullOrWhitespace(args.Name, nameof(args.Name));
Preconditions.GreaterThan(args._bitrate, 0, nameof(args.Bitrate));
Preconditions.NotNullOrWhitespace(args._name, nameof(args.Name));


return await SendAsync<Channel>("POST", $"guilds/{guildId}/channels", args, options: options).ConfigureAwait(false); return await SendAsync<Channel>("POST", $"guilds/{guildId}/channels", args, options: options).ConfigureAwait(false);
} }
@@ -476,8 +476,8 @@ namespace Discord.API
{ {
Preconditions.NotEqual(channelId, 0, nameof(channelId)); Preconditions.NotEqual(channelId, 0, nameof(channelId));
Preconditions.NotNull(args, nameof(args)); Preconditions.NotNull(args, nameof(args));
Preconditions.AtLeast(args.Position, 0, nameof(args.Position));
Preconditions.NotNullOrEmpty(args.Name, nameof(args.Name));
Preconditions.AtLeast(args._position, 0, nameof(args.Position));
Preconditions.NotNullOrEmpty(args._name, nameof(args.Name));


return await SendAsync<Channel>("PATCH", $"channels/{channelId}", args, options: options).ConfigureAwait(false); return await SendAsync<Channel>("PATCH", $"channels/{channelId}", args, options: options).ConfigureAwait(false);
} }
@@ -485,8 +485,8 @@ namespace Discord.API
{ {
Preconditions.NotEqual(channelId, 0, nameof(channelId)); Preconditions.NotEqual(channelId, 0, nameof(channelId));
Preconditions.NotNull(args, nameof(args)); Preconditions.NotNull(args, nameof(args));
Preconditions.AtLeast(args.Position, 0, nameof(args.Position));
Preconditions.NotNullOrEmpty(args.Name, nameof(args.Name));
Preconditions.AtLeast(args._position, 0, nameof(args.Position));
Preconditions.NotNullOrEmpty(args._name, nameof(args.Name));


return await SendAsync<Channel>("PATCH", $"channels/{channelId}", args, options: options).ConfigureAwait(false); return await SendAsync<Channel>("PATCH", $"channels/{channelId}", args, options: options).ConfigureAwait(false);
} }
@@ -494,10 +494,10 @@ namespace Discord.API
{ {
Preconditions.NotEqual(channelId, 0, nameof(channelId)); Preconditions.NotEqual(channelId, 0, nameof(channelId));
Preconditions.NotNull(args, nameof(args)); Preconditions.NotNull(args, nameof(args));
Preconditions.GreaterThan(args.Bitrate, 0, nameof(args.Bitrate));
Preconditions.AtLeast(args.UserLimit, 0, nameof(args.Bitrate));
Preconditions.AtLeast(args.Position, 0, nameof(args.Position));
Preconditions.NotNullOrEmpty(args.Name, nameof(args.Name));
Preconditions.GreaterThan(args._bitrate, 0, nameof(args.Bitrate));
Preconditions.AtLeast(args._userLimit, 0, nameof(args.Bitrate));
Preconditions.AtLeast(args._position, 0, nameof(args.Position));
Preconditions.NotNullOrEmpty(args._name, nameof(args.Name));


return await SendAsync<Channel>("PATCH", $"channels/{channelId}", args, options: options).ConfigureAwait(false); return await SendAsync<Channel>("PATCH", $"channels/{channelId}", args, options: options).ConfigureAwait(false);
} }
@@ -606,11 +606,11 @@ namespace Discord.API
{ {
Preconditions.NotEqual(guildId, 0, nameof(guildId)); Preconditions.NotEqual(guildId, 0, nameof(guildId));
Preconditions.NotNull(args, nameof(args)); Preconditions.NotNull(args, nameof(args));
Preconditions.NotEqual(args.AFKChannelId, 0, nameof(args.AFKChannelId));
Preconditions.AtLeast(args.AFKTimeout, 0, nameof(args.AFKTimeout));
Preconditions.NotNullOrEmpty(args.Name, nameof(args.Name));
Preconditions.GreaterThan(args.OwnerId, 0, nameof(args.OwnerId));
Preconditions.NotNull(args.Region, nameof(args.Region));
Preconditions.NotEqual(args._afkChannelId, 0, nameof(args.AFKChannelId));
Preconditions.AtLeast(args._afkTimeout, 0, nameof(args.AFKTimeout));
Preconditions.NotNullOrEmpty(args._name, nameof(args.Name));
Preconditions.GreaterThan(args._ownerId, 0, nameof(args.OwnerId));
Preconditions.NotNull(args._region, nameof(args.Region));


return await SendAsync<Guild>("PATCH", $"guilds/{guildId}", args, options: options).ConfigureAwait(false); return await SendAsync<Guild>("PATCH", $"guilds/{guildId}", args, options: options).ConfigureAwait(false);
} }
@@ -643,7 +643,7 @@ namespace Discord.API
Preconditions.NotEqual(guildId, 0, nameof(guildId)); Preconditions.NotEqual(guildId, 0, nameof(guildId));
Preconditions.NotEqual(userId, 0, nameof(userId)); Preconditions.NotEqual(userId, 0, nameof(userId));
Preconditions.NotNull(args, nameof(args)); Preconditions.NotNull(args, nameof(args));
Preconditions.AtLeast(args.PruneDays, 0, nameof(args.PruneDays));
Preconditions.AtLeast(args._deleteMessageDays, 0, nameof(args.DeleteMessageDays));


await SendAsync("PUT", $"guilds/{guildId}/bans/{userId}", args, options: options).ConfigureAwait(false); await SendAsync("PUT", $"guilds/{guildId}/bans/{userId}", args, options: options).ConfigureAwait(false);
} }
@@ -701,8 +701,8 @@ namespace Discord.API
Preconditions.NotEqual(guildId, 0, nameof(guildId)); Preconditions.NotEqual(guildId, 0, nameof(guildId));
Preconditions.NotEqual(integrationId, 0, nameof(integrationId)); Preconditions.NotEqual(integrationId, 0, nameof(integrationId));
Preconditions.NotNull(args, nameof(args)); Preconditions.NotNull(args, nameof(args));
Preconditions.AtLeast(args.ExpireBehavior, 0, nameof(args.ExpireBehavior));
Preconditions.AtLeast(args.ExpireGracePeriod, 0, nameof(args.ExpireGracePeriod));
Preconditions.AtLeast(args._expireBehavior, 0, nameof(args.ExpireBehavior));
Preconditions.AtLeast(args._expireGracePeriod, 0, nameof(args.ExpireGracePeriod));


return await SendAsync<Integration>("PATCH", $"guilds/{guildId}/integrations/{integrationId}", args, options: options).ConfigureAwait(false); return await SendAsync<Integration>("PATCH", $"guilds/{guildId}/integrations/{integrationId}", args, options: options).ConfigureAwait(false);
} }
@@ -749,8 +749,8 @@ namespace Discord.API
{ {
Preconditions.NotEqual(channelId, 0, nameof(channelId)); Preconditions.NotEqual(channelId, 0, nameof(channelId));
Preconditions.NotNull(args, nameof(args)); Preconditions.NotNull(args, nameof(args));
Preconditions.AtLeast(args.MaxAge, 0, nameof(args.MaxAge));
Preconditions.AtLeast(args.MaxUses, 0, nameof(args.MaxUses));
Preconditions.AtLeast(args._maxAge, 0, nameof(args.MaxAge));
Preconditions.AtLeast(args._maxUses, 0, nameof(args.MaxUses));


return await SendAsync<InviteMetadata>("POST", $"channels/{channelId}/invites", args, options: options).ConfigureAwait(false); return await SendAsync<InviteMetadata>("POST", $"channels/{channelId}/invites", args, options: options).ConfigureAwait(false);
} }
@@ -783,21 +783,21 @@ namespace Discord.API
{ {
Preconditions.NotEqual(guildId, 0, nameof(guildId)); Preconditions.NotEqual(guildId, 0, nameof(guildId));
Preconditions.NotNull(args, nameof(args)); Preconditions.NotNull(args, nameof(args));
Preconditions.GreaterThan(args.Limit, 0, nameof(args.Limit));
Preconditions.GreaterThan(args.AfterUserId, 0, nameof(args.AfterUserId));
Preconditions.GreaterThan(args._limit, 0, nameof(args.Limit));
Preconditions.GreaterThan(args._afterUserId, 0, nameof(args.AfterUserId));


int limit = args.Limit.GetValueOrDefault(int.MaxValue);
ulong afterUserId = args.AfterUserId.GetValueOrDefault(0);
int limit = args._limit.GetValueOrDefault(int.MaxValue);
ulong afterUserId = args._afterUserId.GetValueOrDefault(0);


List<GuildMember[]> result; List<GuildMember[]> result;
if (args.Limit.IsSpecified)
result = new List<GuildMember[]>((limit + DiscordConfig.MaxUsersPerBatch - 1) / DiscordConfig.MaxUsersPerBatch);
if (args._limit.IsSpecified)
result = new List<GuildMember[]>((limit + DiscordRestConfig.MaxUsersPerBatch - 1) / DiscordRestConfig.MaxUsersPerBatch);
else else
result = new List<GuildMember[]>(); result = new List<GuildMember[]>();


while (true) while (true)
{ {
int runLimit = (limit >= DiscordConfig.MaxUsersPerBatch) ? DiscordConfig.MaxUsersPerBatch : limit;
int runLimit = (limit >= DiscordRestConfig.MaxUsersPerBatch) ? DiscordRestConfig.MaxUsersPerBatch : limit;
string endpoint = $"guilds/{guildId}/members?limit={runLimit}&after={afterUserId}"; string endpoint = $"guilds/{guildId}/members?limit={runLimit}&after={afterUserId}";
var models = await SendAsync<GuildMember[]>("GET", endpoint, options: options).ConfigureAwait(false); var models = await SendAsync<GuildMember[]>("GET", endpoint, options: options).ConfigureAwait(false);


@@ -806,11 +806,11 @@ namespace Discord.API


result.Add(models); result.Add(models);


limit -= DiscordConfig.MaxUsersPerBatch;
limit -= DiscordRestConfig.MaxUsersPerBatch;
afterUserId = models[models.Length - 1].User.Id; afterUserId = models[models.Length - 1].User.Id;


//Was this an incomplete (the last) batch? //Was this an incomplete (the last) batch?
if (models.Length != DiscordConfig.MaxUsersPerBatch) break;
if (models.Length != DiscordRestConfig.MaxUsersPerBatch) break;
} }


if (result.Count > 1) if (result.Count > 1)
@@ -861,9 +861,9 @@ namespace Discord.API
Preconditions.NotEqual(guildId, 0, nameof(guildId)); Preconditions.NotEqual(guildId, 0, nameof(guildId));
Preconditions.NotEqual(roleId, 0, nameof(roleId)); Preconditions.NotEqual(roleId, 0, nameof(roleId));
Preconditions.NotNull(args, nameof(args)); Preconditions.NotNull(args, nameof(args));
Preconditions.AtLeast(args.Color, 0, nameof(args.Color));
Preconditions.NotNullOrEmpty(args.Name, nameof(args.Name));
Preconditions.AtLeast(args.Position, 0, nameof(args.Position));
Preconditions.AtLeast(args._color, 0, nameof(args.Color));
Preconditions.NotNullOrEmpty(args._name, nameof(args.Name));
Preconditions.AtLeast(args._position, 0, nameof(args.Position));


return await SendAsync<Role>("PATCH", $"guilds/{guildId}/roles/{roleId}", args, options: options).ConfigureAwait(false); return await SendAsync<Role>("PATCH", $"guilds/{guildId}/roles/{roleId}", args, options: options).ConfigureAwait(false);
} }
@@ -903,7 +903,7 @@ namespace Discord.API
Preconditions.AtLeast(args.Limit, 0, nameof(args.Limit)); Preconditions.AtLeast(args.Limit, 0, nameof(args.Limit));


int limit = args.Limit; int limit = args.Limit;
ulong? relativeId = args.RelativeMessageId.IsSpecified ? args.RelativeMessageId.Value : (ulong?)null;
ulong? relativeId = args._relativeMessageId.IsSpecified ? args._relativeMessageId.Value : (ulong?)null;
string relativeDir; string relativeDir;


switch (args.RelativeDirection) switch (args.RelativeDirection)
@@ -920,14 +920,14 @@ namespace Discord.API
break; break;
} }
int runs = (limit + DiscordConfig.MaxMessagesPerBatch - 1) / DiscordConfig.MaxMessagesPerBatch;
int lastRunCount = limit - (runs - 1) * DiscordConfig.MaxMessagesPerBatch;
int runs = (limit + DiscordRestConfig.MaxMessagesPerBatch - 1) / DiscordRestConfig.MaxMessagesPerBatch;
int lastRunCount = limit - (runs - 1) * DiscordRestConfig.MaxMessagesPerBatch;
var result = new API.Message[runs][]; var result = new API.Message[runs][];


int i = 0; int i = 0;
for (; i < runs; i++) for (; i < runs; i++)
{ {
int runCount = i == (runs - 1) ? lastRunCount : DiscordConfig.MaxMessagesPerBatch;
int runCount = i == (runs - 1) ? lastRunCount : DiscordRestConfig.MaxMessagesPerBatch;
string endpoint; string endpoint;
if (relativeId != null) if (relativeId != null)
endpoint = $"channels/{channelId}/messages?limit={runCount}&{relativeDir}={relativeId}"; endpoint = $"channels/{channelId}/messages?limit={runCount}&{relativeDir}={relativeId}";
@@ -966,7 +966,7 @@ namespace Discord.API
} }


//Was this an incomplete (the last) batch? //Was this an incomplete (the last) batch?
if (models.Length != DiscordConfig.MaxMessagesPerBatch) { i++; break; }
if (models.Length != DiscordRestConfig.MaxMessagesPerBatch) { i++; break; }
} }


if (i > 1) if (i > 1)
@@ -1010,9 +1010,9 @@ namespace Discord.API
{ {
Preconditions.NotEqual(channelId, 0, nameof(channelId)); Preconditions.NotEqual(channelId, 0, nameof(channelId));
Preconditions.NotNull(args, nameof(args)); Preconditions.NotNull(args, nameof(args));
Preconditions.NotNullOrEmpty(args.Content, nameof(args.Content));
if (args.Content.Length > DiscordConfig.MaxMessageSize)
throw new ArgumentException($"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", nameof(args.Content));
Preconditions.NotNullOrEmpty(args._content, nameof(args.Content));
if (args._content.Length > DiscordRestConfig.MaxMessageSize)
throw new ArgumentException($"Message content is too long, length must be less or equal to {DiscordRestConfig.MaxMessageSize}.", nameof(args.Content));


if (guildId != 0) if (guildId != 0)
return await SendAsync<Message>("POST", $"channels/{channelId}/messages", args, GuildBucket.SendEditMessage, guildId, options: options).ConfigureAwait(false); return await SendAsync<Message>("POST", $"channels/{channelId}/messages", args, GuildBucket.SendEditMessage, guildId, options: options).ConfigureAwait(false);
@@ -1034,14 +1034,14 @@ namespace Discord.API
Preconditions.NotNull(args, nameof(args)); Preconditions.NotNull(args, nameof(args));
Preconditions.NotEqual(channelId, 0, nameof(channelId)); Preconditions.NotEqual(channelId, 0, nameof(channelId));
if (args.Content.GetValueOrDefault(null) == null)
args.Content = "";
else if (args.Content.IsSpecified)
if (args._content.GetValueOrDefault(null) == null)
args._content = "";
else if (args._content.IsSpecified)
{ {
if (args.Content.Value == null)
args.Content = "";
if (args.Content.Value?.Length > DiscordConfig.MaxMessageSize)
throw new ArgumentOutOfRangeException($"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", nameof(args.Content));
if (args._content.Value == null)
args._content = "";
if (args._content.Value?.Length > DiscordRestConfig.MaxMessageSize)
throw new ArgumentOutOfRangeException($"Message content is too long, length must be less or equal to {DiscordRestConfig.MaxMessageSize}.", nameof(args.Content));
} }


if (guildId != 0) if (guildId != 0)
@@ -1084,8 +1084,8 @@ namespace Discord.API
Preconditions.NotEqual(channelId, 0, nameof(channelId)); Preconditions.NotEqual(channelId, 0, nameof(channelId));
Preconditions.NotNull(args, nameof(args)); Preconditions.NotNull(args, nameof(args));


var messageIds = args.MessageIds?.ToArray();
Preconditions.NotNull(args.MessageIds, nameof(args.MessageIds));
var messageIds = args._messages;
Preconditions.NotNull(args._messages, nameof(args.MessageIds));
Preconditions.AtMost(messageIds.Length, 100, nameof(messageIds.Length)); Preconditions.AtMost(messageIds.Length, 100, nameof(messageIds.Length));


switch (messageIds.Length) switch (messageIds.Length)
@@ -1118,11 +1118,11 @@ namespace Discord.API
Preconditions.NotEqual(channelId, 0, nameof(channelId)); Preconditions.NotEqual(channelId, 0, nameof(channelId));
Preconditions.NotEqual(messageId, 0, nameof(messageId)); Preconditions.NotEqual(messageId, 0, nameof(messageId));
Preconditions.NotNull(args, nameof(args)); Preconditions.NotNull(args, nameof(args));
if (args.Content.IsSpecified)
if (args._content.IsSpecified)
{ {
Preconditions.NotNullOrEmpty(args.Content, nameof(args.Content));
if (args.Content.Value.Length > DiscordConfig.MaxMessageSize)
throw new ArgumentOutOfRangeException($"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", nameof(args.Content));
Preconditions.NotNullOrEmpty(args._content, nameof(args.Content));
if (args._content.Value.Length > DiscordRestConfig.MaxMessageSize)
throw new ArgumentOutOfRangeException($"Message content is too long, length must be less or equal to {DiscordRestConfig.MaxMessageSize}.", nameof(args.Content));
} }


if (guildId != 0) if (guildId != 0)
@@ -1195,7 +1195,7 @@ namespace Discord.API
public async Task<User> ModifySelfAsync(ModifyCurrentUserParams args, RequestOptions options = null) public async Task<User> ModifySelfAsync(ModifyCurrentUserParams args, RequestOptions options = null)
{ {
Preconditions.NotNull(args, nameof(args)); Preconditions.NotNull(args, nameof(args));
Preconditions.NotNullOrEmpty(args.Username, nameof(args.Username));
Preconditions.NotNullOrEmpty(args._username, nameof(args.Username));


return await SendAsync<User>("PATCH", "users/@me", args, options: options).ConfigureAwait(false); return await SendAsync<User>("PATCH", "users/@me", args, options: options).ConfigureAwait(false);
} }
@@ -1209,7 +1209,7 @@ namespace Discord.API
public async Task<Channel> CreateDMChannelAsync(CreateDMChannelParams args, RequestOptions options = null) public async Task<Channel> CreateDMChannelAsync(CreateDMChannelParams args, RequestOptions options = null)
{ {
Preconditions.NotNull(args, nameof(args)); Preconditions.NotNull(args, nameof(args));
Preconditions.GreaterThan(args.RecipientId, 0, nameof(args.Recipient));
Preconditions.GreaterThan(args._recipientId, 0, nameof(args.Recipient));


return await SendAsync<Channel>("POST", $"users/@me/channels", args, options: options).ConfigureAwait(false); return await SendAsync<Channel>("POST", $"users/@me/channels", args, options: options).ConfigureAwait(false);
} }


+ 1
- 0
src/Discord.Net/API/Gateway/IdentifyParams.cs View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;


namespace Discord.API.Gateway namespace Discord.API.Gateway
{ {
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class IdentifyParams public class IdentifyParams
{ {
[JsonProperty("token")] [JsonProperty("token")]


+ 4
- 3
src/Discord.Net/API/Gateway/RequestMembersParams.cs View File

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


namespace Discord.API.Gateway namespace Discord.API.Gateway
{ {
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class RequestMembersParams public class RequestMembersParams
{ {
[JsonProperty("query")] [JsonProperty("query")]
@@ -12,8 +13,8 @@ namespace Discord.API.Gateway
public int Limit { get; set; } public int Limit { get; set; }


[JsonProperty("guild_id")] [JsonProperty("guild_id")]
public IEnumerable<ulong> GuildIds { get; set; }
[JsonIgnore]
public IEnumerable<IGuild> Guilds { set { GuildIds = value.Select(x => x.Id); } }
private ulong[] _guildIds;
public IEnumerable<ulong> GuildIds { set { _guildIds = value.ToArray(); } }
public IEnumerable<IGuild> Guilds { set { _guildIds = value.Select(x => x.Id).ToArray(); } }
} }
} }

+ 1
- 0
src/Discord.Net/API/Gateway/ResumeParams.cs View File

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


namespace Discord.API.Gateway namespace Discord.API.Gateway
{ {
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class ResumeParams public class ResumeParams
{ {
[JsonProperty("token")] [JsonProperty("token")]


+ 1
- 0
src/Discord.Net/API/Gateway/StatusUpdateParams.cs View File

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


namespace Discord.API.Gateway namespace Discord.API.Gateway
{ {
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class StatusUpdateParams public class StatusUpdateParams
{ {
[JsonProperty("idle_since"), Int53] [JsonProperty("idle_since"), Int53]


+ 1
- 0
src/Discord.Net/API/Gateway/UpdateStatusParams.cs View File

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


namespace Discord.API.Gateway namespace Discord.API.Gateway
{ {
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class UpdateStatusParams public class UpdateStatusParams
{ {
[JsonProperty("idle_since")] [JsonProperty("idle_since")]


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

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


namespace Discord.API.Gateway namespace Discord.API.Gateway
{ {
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class VoiceStateUpdateParams public class VoiceStateUpdateParams
{ {
[JsonProperty("self_mute")] [JsonProperty("self_mute")]
@@ -10,12 +11,11 @@ namespace Discord.API.Gateway
public bool SelfDeaf { get; set; } public bool SelfDeaf { get; set; }


[JsonProperty("guild_id")] [JsonProperty("guild_id")]
public ulong GuildId { get; set; }
[JsonIgnore]
public IGuild Guild { set { GuildId = value.Id; } }
public ulong? GuildId { get; set; }
public IGuild Guild { set { GuildId = value?.Id; } }
[JsonProperty("channel_id")] [JsonProperty("channel_id")]
public ulong? ChannelId { get; set; } public ulong? ChannelId { get; set; }
[JsonIgnore]
public IChannel Channel { set { ChannelId = value?.Id; } } public IChannel Channel { set { ChannelId = value?.Id; } }
} }
} }

+ 0
- 11
src/Discord.Net/API/Rest/ApplicationInfo.cs View File

@@ -1,11 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Discord.API.Rest
{
public class ApplicationInfo
{
}
}

+ 12
- 4
src/Discord.Net/API/Rest/CreateChannelInviteParams.cs View File

@@ -2,15 +2,23 @@


namespace Discord.API.Rest namespace Discord.API.Rest
{ {
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class CreateChannelInviteParams public class CreateChannelInviteParams
{ {
[JsonProperty("max_age")] [JsonProperty("max_age")]
public Optional<int> MaxAge { get; set; }
internal Optional<int> _maxAge { get; set; }
public int MaxAge { set { _maxAge = value; } }

[JsonProperty("max_uses")] [JsonProperty("max_uses")]
public Optional<int> MaxUses { get; set; }
internal Optional<int> _maxUses { get; set; }
public int MaxUses { set { _maxUses = value; } }

[JsonProperty("temporary")] [JsonProperty("temporary")]
public Optional<bool> Temporary { get; set; }
internal Optional<bool> _temporary { get; set; }
public bool Temporary { set { _temporary = value; } }

[JsonProperty("xkcdpass")] [JsonProperty("xkcdpass")]
public Optional<bool> XkcdPass { get; set; }
internal Optional<bool> _xkcdPass { get; set; }
public bool XkcdPass { set { _xkcdPass = value; } }
} }
} }

+ 4
- 3
src/Discord.Net/API/Rest/CreateDMChannelParams.cs View File

@@ -2,11 +2,12 @@


namespace Discord.API.Rest namespace Discord.API.Rest
{ {
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class CreateDMChannelParams public class CreateDMChannelParams
{ {
[JsonProperty("recipient_id")] [JsonProperty("recipient_id")]
public ulong RecipientId { get; set; }
[JsonIgnore]
public IUser Recipient { set { RecipientId = value.Id; } }
internal ulong _recipientId { get; set; }
public ulong RecipientId { set { _recipientId = value; } }
public IUser Recipient { set { _recipientId = value.Id; } }
} }
} }

+ 3
- 1
src/Discord.Net/API/Rest/CreateGuildBanParams.cs View File

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


namespace Discord.API.Rest namespace Discord.API.Rest
{ {
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class CreateGuildBanParams public class CreateGuildBanParams
{ {
[JsonProperty("delete-message-days")] [JsonProperty("delete-message-days")]
public Optional<int> PruneDays { get; set; }
internal Optional<int> _deleteMessageDays { get; set; }
public int DeleteMessageDays { set { _deleteMessageDays = value; } }
} }
} }

+ 8
- 3
src/Discord.Net/API/Rest/CreateGuildChannelParams.cs View File

@@ -2,14 +2,19 @@


namespace Discord.API.Rest namespace Discord.API.Rest
{ {
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class CreateGuildChannelParams public class CreateGuildChannelParams
{ {
[JsonProperty("name")] [JsonProperty("name")]
public string Name { get; set; }
internal string _name { get; set; }
public string Name { set { _name = value; } }

[JsonProperty("type")] [JsonProperty("type")]
public ChannelType Type { get; set; }
internal ChannelType _type { get; set; }
public ChannelType Type { set { _type = value; } }


[JsonProperty("bitrate")] [JsonProperty("bitrate")]
public Optional<int> Bitrate { get; set; }
internal Optional<int> _bitrate { get; set; }
public int Bitrate { set { _bitrate = value; } }
} }
} }

+ 4
- 2
src/Discord.Net/API/Rest/CreateGuildIntegrationParams.cs View File

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


namespace Discord.API.Rest namespace Discord.API.Rest
{ {
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class CreateGuildIntegrationParams public class CreateGuildIntegrationParams
{ {
[JsonProperty("id")] [JsonProperty("id")]
public ulong Id { get; set; }
public ulong Id { internal get; set; }

[JsonProperty("type")] [JsonProperty("type")]
public string Type { get; set; }
public string Type { internal get; set; }
} }
} }

+ 6
- 9
src/Discord.Net/API/Rest/CreateGuildParams.cs View File

@@ -3,20 +3,17 @@ using System.IO;


namespace Discord.API.Rest namespace Discord.API.Rest
{ {
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class CreateGuildParams public class CreateGuildParams
{ {
[JsonProperty("name")] [JsonProperty("name")]
public string Name { get; set; }
public string Name { internal get; set; }

[JsonProperty("region")] [JsonProperty("region")]
public string Region { get; set; }
public string Region { internal get; set; }


[JsonProperty("icon")] [JsonProperty("icon")]
private Optional<Image> _icon { get; set; }
[JsonIgnore]
public Optional<Stream> Icon
{
get { return _icon.IsSpecified ? _icon.Value.Stream : null; }
set { _icon = value.IsSpecified ? new Image(value.Value) : Optional.Create<Image>(); }
}
internal Optional<Image?> _icon { get; set; }
public Stream Icon { set { _icon = value != null ? new Image(value) : (Image?)null; } }
} }
} }

+ 10
- 5
src/Discord.Net/API/Rest/CreateMessageParams.cs View File

@@ -2,14 +2,19 @@


namespace Discord.API.Rest namespace Discord.API.Rest
{ {
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class CreateMessageParams public class CreateMessageParams
{ {
[JsonProperty("content")] [JsonProperty("content")]
public string Content { get; set; } = "";
internal string _content { get; set; }
public string Content { set { _content = value; } }


[JsonProperty("nonce", NullValueHandling = NullValueHandling.Ignore)]
public Optional<string> Nonce { get; set; }
[JsonProperty("tts", DefaultValueHandling = DefaultValueHandling.Ignore)]
public Optional<bool> IsTTS { get; set; }
[JsonProperty("nonce")]
internal Optional<string> _nonce { get; set; }
public string Nonce { set { _nonce = value; } }

[JsonProperty("tts")]
internal Optional<bool> _tts { get; set; }
public bool IsTTS { set { _tts = value; } }
} }
} }

+ 4
- 3
src/Discord.Net/API/Rest/DeleteMessagesParams.cs View File

@@ -4,11 +4,12 @@ using System.Linq;


namespace Discord.API.Rest namespace Discord.API.Rest
{ {
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class DeleteMessagesParams public class DeleteMessagesParams
{ {
[JsonProperty("messages")] [JsonProperty("messages")]
public IEnumerable<ulong> MessageIds { get; set; }
[JsonIgnore]
public IEnumerable<IMessage> Messages { set { MessageIds = value.Select(x => x.Id); } }
internal ulong[] _messages { get; set; }
public IEnumerable<ulong> MessageIds { set { _messages = value.ToArray(); } }
public IEnumerable<IMessage> Messages { set { _messages = value.Select(x => x.Id).ToArray(); } }
} }
} }

+ 6
- 4
src/Discord.Net/API/Rest/GetChannelMessagesParams.cs View File

@@ -2,10 +2,12 @@
{ {
public class GetChannelMessagesParams public class GetChannelMessagesParams
{ {
public int Limit { get; set; } = DiscordConfig.MaxMessagesPerBatch;
public Direction RelativeDirection { get; set; } = Direction.Before;
public int Limit { internal get; set; } = DiscordRestConfig.MaxMessagesPerBatch;


public Optional<ulong> RelativeMessageId { get; set; }
public Optional<IMessage> RelativeMessage { set { RelativeMessageId = value.IsSpecified ? value.Value.Id : Optional.Create<ulong>(); } }
public Direction RelativeDirection { internal get; set; } = Direction.Before;

internal Optional<ulong> _relativeMessageId { get; set; }
public ulong RelativeMessageId { set { _relativeMessageId = value; } }
public IMessage RelativeMessage { set { _relativeMessageId = value.Id; } }
} }
} }

+ 5
- 2
src/Discord.Net/API/Rest/GetGuildMembersParams.cs View File

@@ -2,7 +2,10 @@
{ {
public class GetGuildMembersParams public class GetGuildMembersParams
{ {
public Optional<int> Limit { get; set; }
public Optional<ulong> AfterUserId { get; set; }
internal Optional<int> _limit { get; set; }
public int Limit { set { _limit = value; } }

internal Optional<ulong> _afterUserId { get; set; }
public ulong AfterUserId { set { _afterUserId = value; } }
} }
} }

+ 2
- 1
src/Discord.Net/API/Rest/GuildPruneParams.cs View File

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


namespace Discord.API.Rest namespace Discord.API.Rest
{ {
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class GuildPruneParams public class GuildPruneParams
{ {
[JsonProperty("days")] [JsonProperty("days")]
public int Days = 30;
public int Days { internal get; set; }
} }
} }

+ 4
- 2
src/Discord.Net/API/Rest/ModifyChannelPermissionsParams.cs View File

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


namespace Discord.API.Rest namespace Discord.API.Rest
{ {
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class ModifyChannelPermissionsParams public class ModifyChannelPermissionsParams
{ {
[JsonProperty("allow")] [JsonProperty("allow")]
public Optional<ulong> Allow { get; set; }
public ulong Allow { internal get; set; }

[JsonProperty("deny")] [JsonProperty("deny")]
public Optional<ulong> Deny { get; set; }
public ulong Deny { internal get; set; }
} }
} }

+ 2
- 1
src/Discord.Net/API/Rest/ModifyCurrentUserNickParams.cs View File

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


namespace Discord.API.Rest namespace Discord.API.Rest
{ {
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class ModifyCurrentUserNickParams public class ModifyCurrentUserNickParams
{ {
[JsonProperty("nick")] [JsonProperty("nick")]
public string Nickname { get; set; }
public string Nickname { internal get; set; }
} }
} }

+ 5
- 14
src/Discord.Net/API/Rest/ModifyCurrentUserParams.cs View File

@@ -3,24 +3,15 @@ using System.IO;


namespace Discord.API.Rest namespace Discord.API.Rest
{ {
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class ModifyCurrentUserParams public class ModifyCurrentUserParams
{ {
[JsonProperty("username")] [JsonProperty("username")]
public Optional<string> Username { get; set; }
internal Optional<string> _username { get; set; }
public string Username { set { _username = value; } }


[JsonProperty("avatar")] [JsonProperty("avatar")]
private Optional<Image> _avatar { get; set; }
[JsonIgnore]
public Optional<Stream> Avatar
{
get { return _avatar.IsSpecified ? _avatar.Value.Stream : null; }
set { _avatar = value.IsSpecified ? new Image(value.Value) : Optional.Create<Image>(); }
}
[JsonIgnore]
internal Optional<string> AvatarHash
{
get { return _avatar.IsSpecified ? _avatar.Value.Hash : null; }
set { _avatar = value.IsSpecified ? new Image(value.Value) : Optional.Create<Image>(); }
}
internal Optional<Image> _avatar { get; set; }
public Stream Avatar { set { _avatar = new Image(value); } }
} }
} }

+ 6
- 2
src/Discord.Net/API/Rest/ModifyGuildChannelParams.cs View File

@@ -2,11 +2,15 @@


namespace Discord.API.Rest namespace Discord.API.Rest
{ {
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class ModifyGuildChannelParams public class ModifyGuildChannelParams
{ {
[JsonProperty("name")] [JsonProperty("name")]
public Optional<string> Name { get; set; }
internal Optional<string> _name { get; set; }
public string Name { set { _name = value; } }

[JsonProperty("position")] [JsonProperty("position")]
public Optional<int> Position { get; set; }
internal Optional<int> _position { get; set; }
public int Position { set { _position = value; } }
} }
} }

+ 4
- 2
src/Discord.Net/API/Rest/ModifyGuildChannelsParams.cs View File

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


namespace Discord.API.Rest namespace Discord.API.Rest
{ {
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class ModifyGuildChannelsParams public class ModifyGuildChannelsParams
{ {
[JsonProperty("id")] [JsonProperty("id")]
public ulong Id { get; set; }
public ulong Id { internal get; set; }

[JsonProperty("position")] [JsonProperty("position")]
public Optional<int> Position { get; set; }
public int Position { internal get; set; }
} }
} }

+ 6
- 4
src/Discord.Net/API/Rest/ModifyGuildEmbedParams.cs View File

@@ -2,14 +2,16 @@


namespace Discord.API.Rest namespace Discord.API.Rest
{ {
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class ModifyGuildEmbedParams public class ModifyGuildEmbedParams
{ {
[JsonProperty("enabled")] [JsonProperty("enabled")]
public Optional<bool> Enabled { get; set; }
internal Optional<bool> _enabled { get; set; }
public bool Enabled { set { _enabled = value; } }


[JsonProperty("channel")] [JsonProperty("channel")]
public Optional<ulong> ChannelId { get; set; }
[JsonIgnore]
public Optional<IVoiceChannel> Channel { set { ChannelId = value.IsSpecified ? value.Value.Id : Optional.Create<ulong>(); } }
internal Optional<ulong?> _channelId { get; set; }
public ulong? ChannelId { set { _channelId = value; } }
public IVoiceChannel Channel { set { _channelId = value != null ? value.Id : (ulong?)null; } }
} }
} }

+ 9
- 3
src/Discord.Net/API/Rest/ModifyGuildIntegrationParams.cs View File

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


namespace Discord.API.Rest namespace Discord.API.Rest
{ {
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class ModifyGuildIntegrationParams public class ModifyGuildIntegrationParams
{ {
[JsonProperty("expire_behavior")] [JsonProperty("expire_behavior")]
public Optional<int> ExpireBehavior { get; set; }
internal Optional<int> _expireBehavior { get; set; }
public int ExpireBehavior { set { _expireBehavior = value; } }

[JsonProperty("expire_grace_period")] [JsonProperty("expire_grace_period")]
public Optional<int> ExpireGracePeriod { get; set; }
internal Optional<int> _expireGracePeriod { get; set; }
public int ExpireGracePeriod { set { _expireGracePeriod = value; } }

[JsonProperty("enable_emoticons")] [JsonProperty("enable_emoticons")]
public Optional<bool> EnableEmoticons { get; set; }
internal Optional<bool> _enableEmoticons { get; set; }
public bool EnableEmoticons { set { _enableEmoticons = value; } }
} }
} }

+ 15
- 9
src/Discord.Net/API/Rest/ModifyGuildMemberParams.cs View File

@@ -4,23 +4,29 @@ using System.Linq;


namespace Discord.API.Rest namespace Discord.API.Rest
{ {
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class ModifyGuildMemberParams public class ModifyGuildMemberParams
{ {
[JsonProperty("mute")] [JsonProperty("mute")]
public Optional<bool> Mute { get; set; }
internal Optional<bool> _mute { get; set; }
public bool Mute { set { _mute = value; } }

[JsonProperty("deaf")] [JsonProperty("deaf")]
public Optional<bool> Deaf { get; set; }
internal Optional<bool> _deaf { get; set; }
public bool Deaf { set { _deaf = value; } }

[JsonProperty("nick")] [JsonProperty("nick")]
public Optional<string> Nickname { get; set; }
internal Optional<string> _nickname { get; set; }
public string Nickname { set { _nickname = value; } }


[JsonProperty("roles")] [JsonProperty("roles")]
public Optional<IEnumerable<ulong>> RoleIds { get; set; }
[JsonIgnore]
public Optional<IEnumerable<IRole>> Roles { set { RoleIds = value.IsSpecified ? Optional.Create(value.Value.Select(x => x.Id)) : Optional.Create<IEnumerable<ulong>>(); } }
internal Optional<ulong[]> _roleIds { get; set; }
public IEnumerable<ulong> RoleIds { set { _roleIds = value.ToArray(); } }
public IEnumerable<IRole> Roles { set { _roleIds = value.Select(x => x.Id).ToArray(); } }


[JsonProperty("channel_id")] [JsonProperty("channel_id")]
public Optional<ulong> VoiceChannelId { get; set; }
[JsonIgnore]
public Optional<IVoiceChannel> VoiceChannel { set { VoiceChannelId = value.IsSpecified ? value.Value.Id : Optional.Create<ulong>(); } }
internal Optional<ulong> _channelId { get; set; }
public ulong VoiceChannelId { set { _channelId = value; } }
public IVoiceChannel VoiceChannel { set { _channelId = value.Id; } }
} }
} }

+ 27
- 38
src/Discord.Net/API/Rest/ModifyGuildParams.cs View File

@@ -3,60 +3,49 @@ using System.IO;


namespace Discord.API.Rest namespace Discord.API.Rest
{ {
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class ModifyGuildParams public class ModifyGuildParams
{ {
[JsonProperty("username")] [JsonProperty("username")]
public Optional<string> Username { get; set; }
internal Optional<string> _username { get; set; }
public string Username { set { _username = value; } }


[JsonProperty("name")] [JsonProperty("name")]
public Optional<string> Name { get; set; }
internal Optional<string> _name { get; set; }
public string Name { set { _name = value; } }

[JsonProperty("region")] [JsonProperty("region")]
public Optional<IVoiceRegion> Region { get; set; }
internal Optional<IVoiceRegion> _region { get; set; }
public IVoiceRegion Region { set { _region = Optional.Create(value); } }

[JsonProperty("verification_level")] [JsonProperty("verification_level")]
public Optional<VerificationLevel> VerificationLevel { get; set; }
internal Optional<VerificationLevel> _verificationLevel { get; set; }
public VerificationLevel VerificationLevel { set { _verificationLevel = value; } }

[JsonProperty("default_message_notifications")] [JsonProperty("default_message_notifications")]
public Optional<DefaultMessageNotifications> DefaultMessageNotifications { get; set; }
internal Optional<DefaultMessageNotifications> _defaultMessageNotifications { get; set; }
public DefaultMessageNotifications DefaultMessageNotifications { set { _defaultMessageNotifications = value; } }

[JsonProperty("afk_timeout")] [JsonProperty("afk_timeout")]
public Optional<int> AFKTimeout { get; set; }
internal Optional<int> _afkTimeout { get; set; }
public int AFKTimeout { set { _afkTimeout = value; } }


[JsonProperty("icon")] [JsonProperty("icon")]
private Optional<Image> _icon { get; set; }
[JsonIgnore]
public Optional<Stream> Icon
{
get { return _icon.IsSpecified ? _icon.Value.Stream : null; }
set { _icon = value.IsSpecified ? new Image(value.Value) : Optional.Create<Image>(); }
}
[JsonIgnore]
internal Optional<string> IconHash
{
get { return _icon.IsSpecified ? _icon.Value.Hash : null; }
set { _icon = value.IsSpecified ? new Image(value.Value) : Optional.Create<Image>(); }
}
internal Optional<Image?> _icon { get; set; }
public Stream Icon { set { _icon = value != null ? new Image(value) : (Image?)null; } }


[JsonProperty("splash")] [JsonProperty("splash")]
private Optional<Image> _splash { get; set; }
[JsonIgnore]
public Optional<Stream> Splash
{
get { return _splash.IsSpecified ? _splash.Value.Stream : null; }
set { _splash = value.IsSpecified ? new Image(value.Value) : Optional.Create<Image>(); }
}
[JsonIgnore]
internal Optional<string> SplashHash
{
get { return _splash.IsSpecified ? _splash.Value.Hash : null; }
set { _splash = value.IsSpecified ? new Image(value.Value) : Optional.Create<Image>(); }
}
internal Optional<Image?> _splash { get; set; }
public Stream Splash { set { _splash = value != null ? new Image(value) : (Image?)null; } }


[JsonProperty("afk_channel_id")] [JsonProperty("afk_channel_id")]
public Optional<ulong?> AFKChannelId { get; set; }
[JsonIgnore]
public Optional<IVoiceChannel> AFKChannel { set { OwnerId = value.IsSpecified ? value.Value.Id : Optional.Create<ulong>(); } }
internal Optional<ulong?> _afkChannelId { get; set; }
public ulong? AFKChannelId { set { _afkChannelId = value; } }
public IVoiceChannel AFKChannel { set { _afkChannelId = value?.Id; } }


[JsonProperty("owner_id")] [JsonProperty("owner_id")]
public Optional<ulong> OwnerId { get; set; }
[JsonIgnore]
public Optional<IGuildUser> Owner { set { OwnerId = value.IsSpecified ? value.Value.Id : Optional.Create<ulong>(); } }
internal Optional<ulong> _ownerId { get; set; }
public ulong OwnerId { set { _ownerId = value; } }
public IGuildUser Owner { set { _ownerId = value.Id; } }
} }
} }

+ 15
- 5
src/Discord.Net/API/Rest/ModifyGuildRoleParams.cs View File

@@ -2,17 +2,27 @@


namespace Discord.API.Rest namespace Discord.API.Rest
{ {
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class ModifyGuildRoleParams public class ModifyGuildRoleParams
{ {
[JsonProperty("name")] [JsonProperty("name")]
public Optional<string> Name { get; set; }
internal Optional<string> _name { get; set; }
public string Name { set { _name = value; } }

[JsonProperty("permissions")] [JsonProperty("permissions")]
public Optional<ulong> Permissions { get; set; }
internal Optional<ulong> _permissions { get; set; }
public ulong Permissions { set { _permissions = value; } }

[JsonProperty("position")] [JsonProperty("position")]
public Optional<int> Position { get; set; }
internal Optional<int> _position { get; set; }
public int Position { set { _position = value; } }

[JsonProperty("color")] [JsonProperty("color")]
public Optional<uint> Color { get; set; }
internal Optional<uint> _color { get; set; }
public uint Color { set { _color = value; } }

[JsonProperty("hoist")] [JsonProperty("hoist")]
public Optional<bool> Hoist { get; set; }
internal Optional<bool> _hoist { get; set; }
public bool Hoist { set { _hoist = value; } }
} }
} }

+ 2
- 1
src/Discord.Net/API/Rest/ModifyGuildRolesParams.cs View File

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


namespace Discord.API.Rest namespace Discord.API.Rest
{ {
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class ModifyGuildRolesParams : ModifyGuildRoleParams public class ModifyGuildRolesParams : ModifyGuildRoleParams
{ {
[JsonProperty("id")] [JsonProperty("id")]
public ulong Id { get; set; }
public ulong Id { internal get; set; }
} }
} }

+ 3
- 1
src/Discord.Net/API/Rest/ModifyMessageParams.cs View File

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


namespace Discord.API.Rest namespace Discord.API.Rest
{ {
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class ModifyMessageParams public class ModifyMessageParams
{ {
[JsonProperty("content")] [JsonProperty("content")]
public Optional<string> Content { get; set; } = "";
internal Optional<string> _content { get; set; }
public string Content { set { _content = value; } }
} }
} }

+ 5
- 2
src/Discord.Net/API/Rest/ModifyPresenceParams.cs View File

@@ -2,7 +2,10 @@
{ {
public class ModifyPresenceParams public class ModifyPresenceParams
{ {
public Optional<UserStatus> Status { get; set; }
public Optional<Discord.Game> Game { get; set; }
internal Optional<UserStatus> _status { get; set; }
public UserStatus Status { set { _status = value; } }

internal Optional<Discord.Game> _game { get; set; }
public Discord.Game Game { set { _game = value; } }
} }
} }

+ 3
- 1
src/Discord.Net/API/Rest/ModifyTextChannelParams.cs View File

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


namespace Discord.API.Rest namespace Discord.API.Rest
{ {
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class ModifyTextChannelParams : ModifyGuildChannelParams public class ModifyTextChannelParams : ModifyGuildChannelParams
{ {
[JsonProperty("topic")] [JsonProperty("topic")]
public Optional<string> Topic { get; set; }
internal Optional<string> _topic { get; set; }
public string Topic { set { _topic = value; } }
} }
} }

+ 6
- 2
src/Discord.Net/API/Rest/ModifyVoiceChannelParams.cs View File

@@ -2,11 +2,15 @@


namespace Discord.API.Rest namespace Discord.API.Rest
{ {
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class ModifyVoiceChannelParams : ModifyGuildChannelParams public class ModifyVoiceChannelParams : ModifyGuildChannelParams
{ {
[JsonProperty("bitrate")] [JsonProperty("bitrate")]
public Optional<int> Bitrate { get; set; }
internal Optional<int> _bitrate { get; set; }
public int Bitrate { set { _bitrate = value; } }

[JsonProperty("user_limit")] [JsonProperty("user_limit")]
public Optional<int> UserLimit { get; set; }
internal Optional<int> _userLimit { get; set; }
public int UserLimit { set { _userLimit = value; } }
} }
} }

+ 20
- 13
src/Discord.Net/API/Rest/UploadFileParams.cs View File

@@ -6,28 +6,35 @@ namespace Discord.API.Rest
{ {
public class UploadFileParams public class UploadFileParams
{ {
public Stream File { get; set; }
public string Filename { get; set; } = "unknown.dat";
public Stream File { internal get; set; }


public Optional<string> Content { get; set; }
public Optional<string> Nonce { get; set; }
public Optional<bool> IsTTS { get; set; }
internal Optional<string> _filename { get; set; }
public string Filename { set { _filename = value; } }

internal Optional<string> _content { get; set; }
public string Content { set { _content = value; } }

internal Optional<string> _nonce { get; set; }
public string Nonce { set { _nonce = value; } }

internal Optional<bool> _isTTS { get; set; }
public bool IsTTS { set { _isTTS = value; } }


public UploadFileParams(Stream file) public UploadFileParams(Stream file)
{ {
File = file; File = file;
} }


public IReadOnlyDictionary<string, object> ToDictionary()
internal IReadOnlyDictionary<string, object> ToDictionary()
{ {
var d = new Dictionary<string, object>(); var d = new Dictionary<string, object>();
d["file"] = new MultipartFile(File, Filename);
if (Content.IsSpecified)
d["content"] = Content.Value;
if (IsTTS.IsSpecified)
d["tts"] = IsTTS.Value.ToString();
if (Nonce.IsSpecified)
d["nonce"] = Nonce.Value;
d["file"] = new MultipartFile(File, _filename.GetValueOrDefault("unknown.dat"));
if (_content.IsSpecified)
d["content"] = _content.Value;
if (_isTTS.IsSpecified)
d["tts"] = _isTTS.Value.ToString();
if (_nonce.IsSpecified)
d["nonce"] = _nonce.Value;
return d; return d;
} }
} }


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

@@ -49,7 +49,7 @@ namespace Discord.Audio
private uint _ssrc; private uint _ssrc;
private byte[] _secretKey; private byte[] _secretKey;


public CachedGuild Guild { get; }
public SocketGuild Guild { get; }
public DiscordVoiceAPIClient ApiClient { get; private set; } public DiscordVoiceAPIClient ApiClient { get; private set; }
public ConnectionState ConnectionState { get; private set; } public ConnectionState ConnectionState { get; private set; }
public int Latency { get; private set; } public int Latency { get; private set; }
@@ -57,7 +57,7 @@ namespace Discord.Audio
private DiscordSocketClient Discord => Guild.Discord; private DiscordSocketClient Discord => Guild.Discord;


/// <summary> Creates a new REST/WebSocket discord client. </summary> /// <summary> Creates a new REST/WebSocket discord client. </summary>
public AudioClient(CachedGuild guild, int id)
public AudioClient(SocketGuild guild, int id)
{ {
Guild = guild; Guild = guild;




+ 38
- 38
src/Discord.Net/Data/DataStore.cs View File

@@ -13,76 +13,76 @@ namespace Discord
private const double AverageUsersPerGuild = 47.78; //Source: Googie2149 private const double AverageUsersPerGuild = 47.78; //Source: Googie2149
private const double CollectionMultiplier = 1.05; //Add 5% buffer to handle growth private const double CollectionMultiplier = 1.05; //Add 5% buffer to handle growth


private readonly ConcurrentDictionary<ulong, ICachedChannel> _channels;
private readonly ConcurrentDictionary<ulong, CachedDMChannel> _dmChannels;
private readonly ConcurrentDictionary<ulong, CachedGuild> _guilds;
private readonly ConcurrentDictionary<ulong, CachedGlobalUser> _users;
private readonly ConcurrentDictionary<ulong, ISocketChannel> _channels;
private readonly ConcurrentDictionary<ulong, SocketDMChannel> _dmChannels;
private readonly ConcurrentDictionary<ulong, SocketGuild> _guilds;
private readonly ConcurrentDictionary<ulong, SocketGlobalUser> _users;
private readonly ConcurrentHashSet<ulong> _groupChannels; private readonly ConcurrentHashSet<ulong> _groupChannels;


internal IReadOnlyCollection<ICachedChannel> Channels => _channels.ToReadOnlyCollection();
internal IReadOnlyCollection<CachedDMChannel> DMChannels => _dmChannels.ToReadOnlyCollection();
internal IReadOnlyCollection<CachedGroupChannel> GroupChannels => _groupChannels.Select(x => GetChannel(x) as CachedGroupChannel).ToReadOnlyCollection(_groupChannels);
internal IReadOnlyCollection<CachedGuild> Guilds => _guilds.ToReadOnlyCollection();
internal IReadOnlyCollection<CachedGlobalUser> Users => _users.ToReadOnlyCollection();
internal IReadOnlyCollection<ISocketChannel> Channels => _channels.ToReadOnlyCollection();
internal IReadOnlyCollection<SocketDMChannel> DMChannels => _dmChannels.ToReadOnlyCollection();
internal IReadOnlyCollection<SocketGroupChannel> GroupChannels => _groupChannels.Select(x => GetChannel(x) as SocketGroupChannel).ToReadOnlyCollection(_groupChannels);
internal IReadOnlyCollection<SocketGuild> Guilds => _guilds.ToReadOnlyCollection();
internal IReadOnlyCollection<SocketGlobalUser> Users => _users.ToReadOnlyCollection();


internal IReadOnlyCollection<ICachedPrivateChannel> PrivateChannels =>
_dmChannels.Select(x => x.Value as ICachedPrivateChannel).Concat(
_groupChannels.Select(x => GetChannel(x) as ICachedPrivateChannel))
internal IReadOnlyCollection<ISocketPrivateChannel> PrivateChannels =>
_dmChannels.Select(x => x.Value as ISocketPrivateChannel).Concat(
_groupChannels.Select(x => GetChannel(x) as ISocketPrivateChannel))
.ToReadOnlyCollection(() => _dmChannels.Count + _groupChannels.Count); .ToReadOnlyCollection(() => _dmChannels.Count + _groupChannels.Count);


public DataStore(int guildCount, int dmChannelCount) public DataStore(int guildCount, int dmChannelCount)
{ {
double estimatedChannelCount = guildCount * AverageChannelsPerGuild + dmChannelCount; double estimatedChannelCount = guildCount * AverageChannelsPerGuild + dmChannelCount;
double estimatedUsersCount = guildCount * AverageUsersPerGuild; double estimatedUsersCount = guildCount * AverageUsersPerGuild;
_channels = new ConcurrentDictionary<ulong, ICachedChannel>(CollectionConcurrencyLevel, (int)(estimatedChannelCount * CollectionMultiplier));
_dmChannels = new ConcurrentDictionary<ulong, CachedDMChannel>(CollectionConcurrencyLevel, (int)(dmChannelCount * CollectionMultiplier));
_guilds = new ConcurrentDictionary<ulong, CachedGuild>(CollectionConcurrencyLevel, (int)(guildCount * CollectionMultiplier));
_users = new ConcurrentDictionary<ulong, CachedGlobalUser>(CollectionConcurrencyLevel, (int)(estimatedUsersCount * CollectionMultiplier));
_channels = new ConcurrentDictionary<ulong, ISocketChannel>(CollectionConcurrencyLevel, (int)(estimatedChannelCount * CollectionMultiplier));
_dmChannels = new ConcurrentDictionary<ulong, SocketDMChannel>(CollectionConcurrencyLevel, (int)(dmChannelCount * CollectionMultiplier));
_guilds = new ConcurrentDictionary<ulong, SocketGuild>(CollectionConcurrencyLevel, (int)(guildCount * CollectionMultiplier));
_users = new ConcurrentDictionary<ulong, SocketGlobalUser>(CollectionConcurrencyLevel, (int)(estimatedUsersCount * CollectionMultiplier));
_groupChannels = new ConcurrentHashSet<ulong>(CollectionConcurrencyLevel, (int)(10 * CollectionMultiplier)); _groupChannels = new ConcurrentHashSet<ulong>(CollectionConcurrencyLevel, (int)(10 * CollectionMultiplier));
} }


internal ICachedChannel GetChannel(ulong id)
internal ISocketChannel GetChannel(ulong id)
{ {
ICachedChannel channel;
ISocketChannel channel;
if (_channels.TryGetValue(id, out channel)) if (_channels.TryGetValue(id, out channel))
return channel; return channel;
return null; return null;
} }
internal CachedDMChannel GetDMChannel(ulong userId)
internal SocketDMChannel GetDMChannel(ulong userId)
{ {
CachedDMChannel channel;
SocketDMChannel channel;
if (_dmChannels.TryGetValue(userId, out channel)) if (_dmChannels.TryGetValue(userId, out channel))
return channel; return channel;
return null; return null;
} }
internal void AddChannel(ICachedChannel channel)
internal void AddChannel(ISocketChannel channel)
{ {
_channels[channel.Id] = channel; _channels[channel.Id] = channel;


var dmChannel = channel as CachedDMChannel;
var dmChannel = channel as SocketDMChannel;
if (dmChannel != null) if (dmChannel != null)
_dmChannels[dmChannel.Recipient.Id] = dmChannel; _dmChannels[dmChannel.Recipient.Id] = dmChannel;
else else
{ {
var groupChannel = channel as CachedGroupChannel;
var groupChannel = channel as SocketGroupChannel;
if (groupChannel != null) if (groupChannel != null)
_groupChannels.TryAdd(groupChannel.Id); _groupChannels.TryAdd(groupChannel.Id);
} }
} }
internal ICachedChannel RemoveChannel(ulong id)
internal ISocketChannel RemoveChannel(ulong id)
{ {
ICachedChannel channel;
ISocketChannel channel;
if (_channels.TryRemove(id, out channel)) if (_channels.TryRemove(id, out channel))
{ {
var dmChannel = channel as CachedDMChannel;
var dmChannel = channel as SocketDMChannel;
if (dmChannel != null) if (dmChannel != null)
{ {
CachedDMChannel ignored;
SocketDMChannel ignored;
_dmChannels.TryRemove(dmChannel.Recipient.Id, out ignored); _dmChannels.TryRemove(dmChannel.Recipient.Id, out ignored);
} }
else else
{ {
var groupChannel = channel as CachedGroupChannel;
var groupChannel = channel as SocketGroupChannel;
if (groupChannel != null) if (groupChannel != null)
_groupChannels.TryRemove(id); _groupChannels.TryRemove(id);
} }
@@ -91,39 +91,39 @@ namespace Discord
return null; return null;
} }


internal CachedGuild GetGuild(ulong id)
internal SocketGuild GetGuild(ulong id)
{ {
CachedGuild guild;
SocketGuild guild;
if (_guilds.TryGetValue(id, out guild)) if (_guilds.TryGetValue(id, out guild))
return guild; return guild;
return null; return null;
} }
internal void AddGuild(CachedGuild guild)
internal void AddGuild(SocketGuild guild)
{ {
_guilds[guild.Id] = guild; _guilds[guild.Id] = guild;
} }
internal CachedGuild RemoveGuild(ulong id)
internal SocketGuild RemoveGuild(ulong id)
{ {
CachedGuild guild;
SocketGuild guild;
if (_guilds.TryRemove(id, out guild)) if (_guilds.TryRemove(id, out guild))
return guild; return guild;
return null; return null;
} }


internal CachedGlobalUser GetUser(ulong id)
internal SocketGlobalUser GetUser(ulong id)
{ {
CachedGlobalUser user;
SocketGlobalUser user;
if (_users.TryGetValue(id, out user)) if (_users.TryGetValue(id, out user))
return user; return user;
return null; return null;
} }
internal CachedGlobalUser GetOrAddUser(ulong id, Func<ulong, CachedGlobalUser> userFactory)
internal SocketGlobalUser GetOrAddUser(ulong id, Func<ulong, SocketGlobalUser> userFactory)
{ {
return _users.GetOrAdd(id, userFactory); return _users.GetOrAdd(id, userFactory);
} }
internal CachedGlobalUser RemoveUser(ulong id)
internal SocketGlobalUser RemoveUser(ulong id)
{ {
CachedGlobalUser user;
SocketGlobalUser user;
if (_users.TryRemove(id, out user)) if (_users.TryRemove(id, out user))
return user; return user;
return null; return null;


+ 3
- 19
src/Discord.Net/DiscordConfig.cs View File

@@ -1,33 +1,17 @@
using Discord.Net.Rest;
using System.Reflection;
using System.Reflection;


namespace Discord namespace Discord
{ {
public class DiscordConfig public class DiscordConfig
{ {
public static string Version { get; } = typeof(DiscordConfig).GetTypeInfo().Assembly?.GetName().Version.ToString(3) ?? "Unknown";
public static string FullVersion { get; } = typeof(DiscordConfig).GetTypeInfo().Assembly?.GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion ?? "Unknown";
public static string UserAgent { get; } = $"DiscordBot (https://github.com/RogueException/Discord.Net, v{Version})";

public const int APIVersion = 6;
public const string GatewayEncoding = "json";
public const int APIVersion = 6;
public static string Version { get; } = typeof(DiscordRestConfig).GetTypeInfo().Assembly?.GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion ?? "Unknown";


public static readonly string ClientAPIUrl = $"https://discordapp.com/api/v{APIVersion}/"; public static readonly string ClientAPIUrl = $"https://discordapp.com/api/v{APIVersion}/";
public const string CDNUrl = "https://cdn.discordapp.com/"; public const string CDNUrl = "https://cdn.discordapp.com/";
public const string InviteUrl = "https://discord.gg/"; public const string InviteUrl = "https://discord.gg/";


public const int MaxMessageSize = 2000;
public const int MaxMessagesPerBatch = 100;
public const int MaxUsersPerBatch = 1000;

internal const int RestTimeout = 10000;
internal const int MessageQueueInterval = 100;
internal const int WebSocketQueueInterval = 100;

/// <summary> Gets or sets the minimum log level severity that will be sent to the LogMessage event. </summary> /// <summary> Gets or sets the minimum log level severity that will be sent to the LogMessage event. </summary>
public LogSeverity LogLevel { get; set; } = LogSeverity.Info; public LogSeverity LogLevel { get; set; } = LogSeverity.Info;

/// <summary> Gets or sets the provider used to generate new REST connections. </summary>
public RestClientProvider RestClientProvider { get; set; } = url => new DefaultRestClient(url);
} }
} }

src/Discord.Net/DiscordClient.cs → src/Discord.Net/DiscordRestClient.cs View File

@@ -10,11 +10,10 @@ using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Collections.Concurrent;


namespace Discord namespace Discord
{ {
public class DiscordClient : IDiscordClient
public class DiscordRestClient : IDiscordClient
{ {
private readonly object _eventLock = new object(); private readonly object _eventLock = new object();


@@ -38,9 +37,9 @@ namespace Discord
public LoginState LoginState { get; private set; } public LoginState LoginState { get; private set; }


/// <summary> Creates a new REST-only discord client. </summary> /// <summary> Creates a new REST-only discord client. </summary>
public DiscordClient() : this(new DiscordConfig()) { }
public DiscordRestClient() : this(new DiscordRestConfig()) { }
/// <summary> Creates a new REST-only discord client. </summary> /// <summary> Creates a new REST-only discord client. </summary>
public DiscordClient(DiscordConfig config)
public DiscordRestClient(DiscordRestConfig config)
{ {
LogManager = new LogManager(config.LogLevel); LogManager = new LogManager(config.LogLevel);
LogManager.Message += async msg => await _logEvent.InvokeAsync(msg).ConfigureAwait(false); LogManager.Message += async msg => await _logEvent.InvokeAsync(msg).ConfigureAwait(false);
@@ -305,9 +304,10 @@ namespace Discord
private async Task WriteInitialLog() private async Task WriteInitialLog()
{ {
if (this is DiscordSocketClient) if (this is DiscordSocketClient)
await _clientLogger.InfoAsync($"DiscordSocketClient v{DiscordConfig.FullVersion} (API v{DiscordConfig.APIVersion}, {DiscordConfig.GatewayEncoding})").ConfigureAwait(false);
await _clientLogger.InfoAsync($"DiscordSocketClient v{DiscordConfig.Version} (API v{DiscordConfig.APIVersion}, {DiscordSocketConfig.GatewayEncoding})").ConfigureAwait(false);
else else
await _clientLogger.InfoAsync($"DiscordClient v{DiscordConfig.FullVersion} (API v{DiscordConfig.APIVersion})").ConfigureAwait(false);
await _clientLogger.InfoAsync($"DiscordRestClient v{DiscordConfig.Version} (API v{DiscordConfig.APIVersion})").ConfigureAwait(false);

await _clientLogger.VerboseAsync($"Runtime: {RuntimeInformation.FrameworkDescription.Trim()} ({ToArchString(RuntimeInformation.ProcessArchitecture)})").ConfigureAwait(false); await _clientLogger.VerboseAsync($"Runtime: {RuntimeInformation.FrameworkDescription.Trim()} ({ToArchString(RuntimeInformation.ProcessArchitecture)})").ConfigureAwait(false);
await _clientLogger.VerboseAsync($"OS: {RuntimeInformation.OSDescription.Trim()} ({ToArchString(RuntimeInformation.OSArchitecture)})").ConfigureAwait(false); await _clientLogger.VerboseAsync($"OS: {RuntimeInformation.OSDescription.Trim()} ({ToArchString(RuntimeInformation.OSArchitecture)})").ConfigureAwait(false);
await _clientLogger.VerboseAsync($"Processors: {Environment.ProcessorCount}").ConfigureAwait(false); await _clientLogger.VerboseAsync($"Processors: {Environment.ProcessorCount}").ConfigureAwait(false);

+ 20
- 0
src/Discord.Net/DiscordRestConfig.cs View File

@@ -0,0 +1,20 @@
using Discord.Net.Rest;

namespace Discord
{
public class DiscordRestConfig : DiscordConfig
{
public static string UserAgent { get; } = $"DiscordBot (https://github.com/RogueException/Discord.Net, v{Version})";

public const int MaxMessageSize = 2000;
public const int MaxMessagesPerBatch = 100;
public const int MaxUsersPerBatch = 1000;

internal const int RestTimeout = 10000;
internal const int MessageQueueInterval = 100;
internal const int WebSocketQueueInterval = 100;

/// <summary> Gets or sets the provider used to generate new REST connections. </summary>
public RestClientProvider RestClientProvider { get; set; } = url => new DefaultRestClient(url);
}
}

+ 38
- 44
src/Discord.Net/DiscordSocketClient.cs View File

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


namespace Discord namespace Discord
{ {
public partial class DiscordSocketClient : DiscordClient, IDiscordClient
public partial class DiscordSocketClient : DiscordRestClient, IDiscordClient
{ {
private readonly ConcurrentQueue<ulong> _largeGuilds; private readonly ConcurrentQueue<ulong> _largeGuilds;
private readonly ILogger _gatewayLogger; private readonly ILogger _gatewayLogger;
@@ -44,19 +44,16 @@ namespace Discord
/// <summary> Gets the estimated round-trip latency, in milliseconds, to the gateway server. </summary> /// <summary> Gets the estimated round-trip latency, in milliseconds, to the gateway server. </summary>
public int Latency { get; private set; } public int Latency { get; private set; }


//From DiscordConfig
//From DiscordSocketConfig
internal int TotalShards { get; private set; } internal int TotalShards { get; private set; }
internal int ConnectionTimeout { get; private set; }
internal int ReconnectDelay { get; private set; }
internal int FailedReconnectDelay { get; private set; }
internal int MessageCacheSize { get; private set; } internal int MessageCacheSize { get; private set; }
internal int LargeThreshold { get; private set; } internal int LargeThreshold { get; private set; }
internal AudioMode AudioMode { get; private set; } internal AudioMode AudioMode { get; private set; }
internal DataStore DataStore { get; private set; } internal DataStore DataStore { get; private set; }
internal WebSocketProvider WebSocketProvider { get; private set; } internal WebSocketProvider WebSocketProvider { get; private set; }


internal CachedSelfUser CurrentUser => _currentUser as CachedSelfUser;
internal IReadOnlyCollection<CachedGuild> Guilds => DataStore.Guilds;
internal SocketSelfUser CurrentUser => _currentUser as SocketSelfUser;
internal IReadOnlyCollection<SocketGuild> Guilds => DataStore.Guilds;
internal IReadOnlyCollection<VoiceRegion> VoiceRegions => _voiceRegions.ToReadOnlyCollection(); internal IReadOnlyCollection<VoiceRegion> VoiceRegions => _voiceRegions.ToReadOnlyCollection();


/// <summary> Creates a new REST/WebSocket discord client. </summary> /// <summary> Creates a new REST/WebSocket discord client. </summary>
@@ -67,9 +64,6 @@ namespace Discord
{ {
ShardId = config.ShardId; ShardId = config.ShardId;
TotalShards = config.TotalShards; TotalShards = config.TotalShards;
ConnectionTimeout = config.ConnectionTimeout;
ReconnectDelay = config.ReconnectDelay;
FailedReconnectDelay = config.FailedReconnectDelay;
MessageCacheSize = config.MessageCacheSize; MessageCacheSize = config.MessageCacheSize;
LargeThreshold = config.LargeThreshold; LargeThreshold = config.LargeThreshold;
AudioMode = config.AudioMode; AudioMode = config.AudioMode;
@@ -340,15 +334,15 @@ namespace Discord
{ {
return Task.FromResult<IReadOnlyCollection<IGuild>>(Guilds); return Task.FromResult<IReadOnlyCollection<IGuild>>(Guilds);
} }
internal CachedGuild AddGuild(ExtendedGuild model, DataStore dataStore)
internal SocketGuild AddGuild(ExtendedGuild model, DataStore dataStore)
{ {
var guild = new CachedGuild(this, model, dataStore);
var guild = new SocketGuild(this, model, dataStore);
dataStore.AddGuild(guild); dataStore.AddGuild(guild);
if (model.Large) if (model.Large)
_largeGuilds.Enqueue(model.Id); _largeGuilds.Enqueue(model.Id);
return guild; return guild;
} }
internal CachedGuild RemoveGuild(ulong id)
internal SocketGuild RemoveGuild(ulong id)
{ {
var guild = DataStore.RemoveGuild(id); var guild = DataStore.RemoveGuild(id);
foreach (var channel in guild.Channels) foreach (var channel in guild.Channels)
@@ -367,7 +361,7 @@ namespace Discord
{ {
return Task.FromResult<IReadOnlyCollection<IPrivateChannel>>(DataStore.PrivateChannels); return Task.FromResult<IReadOnlyCollection<IPrivateChannel>>(DataStore.PrivateChannels);
} }
internal ICachedChannel AddPrivateChannel(API.Channel model, DataStore dataStore)
internal ISocketChannel AddPrivateChannel(API.Channel model, DataStore dataStore)
{ {
switch (model.Type) switch (model.Type)
{ {
@@ -375,13 +369,13 @@ namespace Discord
{ {
var recipients = model.Recipients.Value; var recipients = model.Recipients.Value;
var user = GetOrAddUser(recipients[0], dataStore); var user = GetOrAddUser(recipients[0], dataStore);
var channel = new CachedDMChannel(this, new CachedDMUser(user), model);
var channel = new SocketDMChannel(this, new SocketDMUser(user), model);
dataStore.AddChannel(channel); dataStore.AddChannel(channel);
return channel; return channel;
} }
case ChannelType.Group: case ChannelType.Group:
{ {
var channel = new CachedGroupChannel(this, model);
var channel = new SocketGroupChannel(this, model);
channel.UpdateUsers(model.Recipients.Value, UpdateSource.Creation, dataStore); channel.UpdateUsers(model.Recipients.Value, UpdateSource.Creation, dataStore);
dataStore.AddChannel(channel); dataStore.AddChannel(channel);
return channel; return channel;
@@ -390,9 +384,9 @@ namespace Discord
throw new InvalidOperationException($"Unexpected channel type: {model.Type}"); throw new InvalidOperationException($"Unexpected channel type: {model.Type}");
} }
} }
internal ICachedChannel RemovePrivateChannel(ulong id)
internal ISocketChannel RemovePrivateChannel(ulong id)
{ {
var channel = DataStore.RemoveChannel(id) as ICachedPrivateChannel;
var channel = DataStore.RemoveChannel(id) as ISocketPrivateChannel;
foreach (var recipient in channel.Recipients) foreach (var recipient in channel.Recipients)
recipient.User.RemoveRef(this); recipient.User.RemoveRef(this);
return channel; return channel;
@@ -413,13 +407,13 @@ namespace Discord
{ {
return Task.FromResult<ISelfUser>(_currentUser); return Task.FromResult<ISelfUser>(_currentUser);
} }
internal CachedGlobalUser GetOrAddUser(API.User model, DataStore dataStore)
internal SocketGlobalUser GetOrAddUser(API.User model, DataStore dataStore)
{ {
var user = dataStore.GetOrAddUser(model.Id, _ => new CachedGlobalUser(model));
var user = dataStore.GetOrAddUser(model.Id, _ => new SocketGlobalUser(model));
user.AddRef(); user.AddRef();
return user; return user;
} }
internal CachedGlobalUser RemoveUser(ulong id)
internal SocketGlobalUser RemoveUser(ulong id)
{ {
return DataStore.RemoveUser(id); return DataStore.RemoveUser(id);
} }
@@ -429,10 +423,10 @@ namespace Discord
=> DownloadUsersAsync(DataStore.Guilds.Where(x => !x.HasAllMembers)); => DownloadUsersAsync(DataStore.Guilds.Where(x => !x.HasAllMembers));
/// <summary> Downloads the users list for the provided guilds, if they don't have a complete list. </summary> /// <summary> Downloads the users list for the provided guilds, if they don't have a complete list. </summary>
public Task DownloadUsersAsync(IEnumerable<IGuild> guilds) public Task DownloadUsersAsync(IEnumerable<IGuild> guilds)
=> DownloadUsersAsync(guilds.Select(x => x as CachedGuild).Where(x => x != null));
=> DownloadUsersAsync(guilds.Select(x => x as SocketGuild).Where(x => x != null));
public Task DownloadUsersAsync(params IGuild[] guilds) public Task DownloadUsersAsync(params IGuild[] guilds)
=> DownloadUsersAsync(guilds.Select(x => x as CachedGuild).Where(x => x != null));
private async Task DownloadUsersAsync(IEnumerable<CachedGuild> guilds)
=> DownloadUsersAsync(guilds.Select(x => x as SocketGuild).Where(x => x != null));
private async Task DownloadUsersAsync(IEnumerable<SocketGuild> guilds)
{ {
var cachedGuilds = guilds.ToArray(); var cachedGuilds = guilds.ToArray();
if (cachedGuilds.Length == 0) return; if (cachedGuilds.Length == 0) return;
@@ -559,7 +553,7 @@ namespace Discord
var data = (payload as JToken).ToObject<ReadyEvent>(_serializer); var data = (payload as JToken).ToObject<ReadyEvent>(_serializer);
var dataStore = new DataStore(data.Guilds.Length, data.PrivateChannels.Length); var dataStore = new DataStore(data.Guilds.Length, data.PrivateChannels.Length);


var currentUser = new CachedSelfUser(this, data.User);
var currentUser = new SocketSelfUser(this, data.User);
int unavailableGuilds = 0; int unavailableGuilds = 0;
for (int i = 0; i < data.Guilds.Length; i++) for (int i = 0; i < data.Guilds.Length; i++)
{ {
@@ -625,7 +619,7 @@ namespace Discord
} }
await _gatewayLogger.DebugAsync($"Received Dispatch ({type})").ConfigureAwait(false); await _gatewayLogger.DebugAsync($"Received Dispatch ({type})").ConfigureAwait(false);


CachedGuild guild;
SocketGuild guild;
if (data.Unavailable != false) if (data.Unavailable != false)
{ {
guild = AddGuild(data, DataStore); guild = AddGuild(data, DataStore);
@@ -751,7 +745,7 @@ namespace Discord
await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_CREATE)").ConfigureAwait(false); await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_CREATE)").ConfigureAwait(false);


var data = (payload as JToken).ToObject<API.Channel>(_serializer); var data = (payload as JToken).ToObject<API.Channel>(_serializer);
ICachedChannel channel = null;
ISocketChannel channel = null;
if (data.GuildId.IsSpecified) if (data.GuildId.IsSpecified)
{ {
var guild = DataStore.GetGuild(data.GuildId.Value); var guild = DataStore.GetGuild(data.GuildId.Value);
@@ -789,7 +783,7 @@ namespace Discord
var before = channel.Clone(); var before = channel.Clone();
channel.Update(data, UpdateSource.WebSocket); channel.Update(data, UpdateSource.WebSocket);


if (!((channel as ICachedGuildChannel)?.Guild.IsSynced ?? true))
if (!((channel as ISocketGuildChannel)?.Guild.IsSynced ?? true))
{ {
await _gatewayLogger.DebugAsync("Ignored CHANNEL_UPDATE, guild is not synced yet.").ConfigureAwait(false); await _gatewayLogger.DebugAsync("Ignored CHANNEL_UPDATE, guild is not synced yet.").ConfigureAwait(false);
return; return;
@@ -808,7 +802,7 @@ namespace Discord
{ {
await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_DELETE)").ConfigureAwait(false); await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_DELETE)").ConfigureAwait(false);


ICachedChannel channel = null;
ISocketChannel channel = null;
var data = (payload as JToken).ToObject<API.Channel>(_serializer); var data = (payload as JToken).ToObject<API.Channel>(_serializer);
if (data.GuildId.IsSpecified) if (data.GuildId.IsSpecified)
{ {
@@ -978,7 +972,7 @@ namespace Discord
await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_RECIPIENT_ADD)").ConfigureAwait(false); await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_RECIPIENT_ADD)").ConfigureAwait(false);


var data = (payload as JToken).ToObject<RecipientEvent>(_serializer); var data = (payload as JToken).ToObject<RecipientEvent>(_serializer);
var channel = DataStore.GetChannel(data.ChannelId) as CachedGroupChannel;
var channel = DataStore.GetChannel(data.ChannelId) as SocketGroupChannel;
if (channel != null) if (channel != null)
{ {
var user = channel.AddUser(data.User, DataStore); var user = channel.AddUser(data.User, DataStore);
@@ -996,7 +990,7 @@ namespace Discord
await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_RECIPIENT_REMOVE)").ConfigureAwait(false); await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_RECIPIENT_REMOVE)").ConfigureAwait(false);


var data = (payload as JToken).ToObject<RecipientEvent>(_serializer); var data = (payload as JToken).ToObject<RecipientEvent>(_serializer);
var channel = DataStore.GetChannel(data.ChannelId) as CachedGroupChannel;
var channel = DataStore.GetChannel(data.ChannelId) as SocketGroupChannel;
if (channel != null) if (channel != null)
{ {
var user = channel.RemoveUser(data.User.Id); var user = channel.RemoveUser(data.User.Id);
@@ -1166,10 +1160,10 @@ namespace Discord
await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_CREATE)").ConfigureAwait(false); await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_CREATE)").ConfigureAwait(false);


var data = (payload as JToken).ToObject<API.Message>(_serializer); var data = (payload as JToken).ToObject<API.Message>(_serializer);
var channel = DataStore.GetChannel(data.ChannelId) as ICachedMessageChannel;
var channel = DataStore.GetChannel(data.ChannelId) as ISocketMessageChannel;
if (channel != null) if (channel != null)
{ {
if (!((channel as ICachedGuildChannel)?.Guild.IsSynced ?? true))
if (!((channel as ISocketGuildChannel)?.Guild.IsSynced ?? true))
{ {
await _gatewayLogger.DebugAsync("Ignored MESSAGE_CREATE, guild is not synced yet.").ConfigureAwait(false); await _gatewayLogger.DebugAsync("Ignored MESSAGE_CREATE, guild is not synced yet.").ConfigureAwait(false);
return; return;
@@ -1200,17 +1194,17 @@ namespace Discord
await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_UPDATE)").ConfigureAwait(false); await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_UPDATE)").ConfigureAwait(false);


var data = (payload as JToken).ToObject<API.Message>(_serializer); var data = (payload as JToken).ToObject<API.Message>(_serializer);
var channel = DataStore.GetChannel(data.ChannelId) as ICachedMessageChannel;
var channel = DataStore.GetChannel(data.ChannelId) as ISocketMessageChannel;
if (channel != null) if (channel != null)
{ {
if (!((channel as ICachedGuildChannel)?.Guild.IsSynced ?? true))
if (!((channel as ISocketGuildChannel)?.Guild.IsSynced ?? true))
{ {
await _gatewayLogger.DebugAsync("Ignored MESSAGE_UPDATE, guild is not synced yet.").ConfigureAwait(false); await _gatewayLogger.DebugAsync("Ignored MESSAGE_UPDATE, guild is not synced yet.").ConfigureAwait(false);
return; return;
} }


IMessage before = null, after = null; IMessage before = null, after = null;
CachedMessage cachedMsg = channel.GetMessage(data.Id);
SocketMessage cachedMsg = channel.GetMessage(data.Id);
if (cachedMsg != null) if (cachedMsg != null)
{ {
before = cachedMsg.Clone(); before = cachedMsg.Clone();
@@ -1239,10 +1233,10 @@ namespace Discord
await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_DELETE)").ConfigureAwait(false); await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_DELETE)").ConfigureAwait(false);
var data = (payload as JToken).ToObject<API.Message>(_serializer); var data = (payload as JToken).ToObject<API.Message>(_serializer);
var channel = DataStore.GetChannel(data.ChannelId) as ICachedMessageChannel;
var channel = DataStore.GetChannel(data.ChannelId) as ISocketMessageChannel;
if (channel != null) if (channel != null)
{ {
if (!((channel as ICachedGuildChannel)?.Guild.IsSynced ?? true))
if (!((channel as ISocketGuildChannel)?.Guild.IsSynced ?? true))
{ {
await _gatewayLogger.DebugAsync("Ignored MESSAGE_DELETE, guild is not synced yet.").ConfigureAwait(false); await _gatewayLogger.DebugAsync("Ignored MESSAGE_DELETE, guild is not synced yet.").ConfigureAwait(false);
return; return;
@@ -1266,10 +1260,10 @@ namespace Discord
await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_DELETE_BULK)").ConfigureAwait(false); await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_DELETE_BULK)").ConfigureAwait(false);


var data = (payload as JToken).ToObject<MessageDeleteBulkEvent>(_serializer); var data = (payload as JToken).ToObject<MessageDeleteBulkEvent>(_serializer);
var channel = DataStore.GetChannel(data.ChannelId) as ICachedMessageChannel;
var channel = DataStore.GetChannel(data.ChannelId) as ISocketMessageChannel;
if (channel != null) if (channel != null)
{ {
if (!((channel as ICachedGuildChannel)?.Guild.IsSynced ?? true))
if (!((channel as ISocketGuildChannel)?.Guild.IsSynced ?? true))
{ {
await _gatewayLogger.DebugAsync("Ignored MESSAGE_DELETE_BULK, guild is not synced yet.").ConfigureAwait(false); await _gatewayLogger.DebugAsync("Ignored MESSAGE_DELETE_BULK, guild is not synced yet.").ConfigureAwait(false);
return; return;
@@ -1341,10 +1335,10 @@ namespace Discord
await _gatewayLogger.DebugAsync("Received Dispatch (TYPING_START)").ConfigureAwait(false); await _gatewayLogger.DebugAsync("Received Dispatch (TYPING_START)").ConfigureAwait(false);


var data = (payload as JToken).ToObject<TypingStartEvent>(_serializer); var data = (payload as JToken).ToObject<TypingStartEvent>(_serializer);
var channel = DataStore.GetChannel(data.ChannelId) as ICachedMessageChannel;
var channel = DataStore.GetChannel(data.ChannelId) as ISocketMessageChannel;
if (channel != null) if (channel != null)
{ {
if (!((channel as ICachedGuildChannel)?.Guild.IsSynced ?? true))
if (!((channel as ISocketGuildChannel)?.Guild.IsSynced ?? true))
{ {
await _gatewayLogger.DebugAsync("Ignored TYPING_START, guild is not synced yet.").ConfigureAwait(false); await _gatewayLogger.DebugAsync("Ignored TYPING_START, guild is not synced yet.").ConfigureAwait(false);
return; return;
@@ -1385,7 +1379,7 @@ namespace Discord
var data = (payload as JToken).ToObject<API.VoiceState>(_serializer); var data = (payload as JToken).ToObject<API.VoiceState>(_serializer);
if (data.GuildId.HasValue) if (data.GuildId.HasValue)
{ {
ICachedUser user;
ISocketUser user;
VoiceState before, after; VoiceState before, after;
if (data.GuildId != null) if (data.GuildId != null)
{ {
@@ -1418,7 +1412,7 @@ namespace Discord
} }
else else
{ {
var groupChannel = DataStore.GetChannel(data.ChannelId.Value) as CachedGroupChannel;
var groupChannel = DataStore.GetChannel(data.ChannelId.Value) as SocketGroupChannel;
if (groupChannel != null) if (groupChannel != null)
{ {
if (data.ChannelId != null) if (data.ChannelId != null)


+ 3
- 8
src/Discord.Net/DiscordSocketConfig.cs View File

@@ -3,20 +3,15 @@ using Discord.Net.WebSockets;


namespace Discord namespace Discord
{ {
public class DiscordSocketConfig : DiscordConfig
public class DiscordSocketConfig : DiscordRestConfig
{ {
public const string GatewayEncoding = "json";

/// <summary> Gets or sets the id for this shard. Must be less than TotalShards. </summary> /// <summary> Gets or sets the id for this shard. Must be less than TotalShards. </summary>
public int ShardId { get; set; } = 0; public int ShardId { get; set; } = 0;
/// <summary> Gets or sets the total number of shards for this application. </summary> /// <summary> Gets or sets the total number of shards for this application. </summary>
public int TotalShards { get; set; } = 1; public int TotalShards { get; set; } = 1;


/// <summary> Gets or sets the time (in milliseconds) to wait for the websocket to connect and initialize. </summary>
public int ConnectionTimeout { get; set; } = 30000;
/// <summary> Gets or sets the time (in milliseconds) to wait after an unexpected disconnect before reconnecting. </summary>
public int ReconnectDelay { get; set; } = 1000;
/// <summary> Gets or sets the time (in milliseconds) to wait after an reconnect fails before retrying. </summary>
public int FailedReconnectDelay { get; set; } = 15000;

/// <summary> Gets or sets the number of messages per channel that should be kept in cache. Setting this to zero disables the message cache entirely. </summary> /// <summary> Gets or sets the number of messages per channel that should be kept in cache. Setting this to zero disables the message cache entirely. </summary>
public int MessageCacheSize { get; set; } = 0; public int MessageCacheSize { get; set; } = 0;
/*/// <summary> /*/// <summary>


+ 2
- 2
src/Discord.Net/Entities/Application.cs View File

@@ -13,12 +13,12 @@ namespace Discord
public string[] RPCOrigins { get; private set; } public string[] RPCOrigins { get; private set; }
public ulong Flags { get; private set; } public ulong Flags { get; private set; }


public override DiscordClient Discord { get; }
public override DiscordRestClient Discord { get; }
public IUser Owner { get; private set; } public IUser Owner { get; private set; }


public string IconUrl => API.CDN.GetApplicationIconUrl(Id, _iconId); public string IconUrl => API.CDN.GetApplicationIconUrl(Id, _iconId);


public Application(DiscordClient discord, Model model)
public Application(DiscordRestClient discord, Model model)
: base(model.Id) : base(model.Id)
{ {
Discord = discord; Discord = discord;


+ 2
- 2
src/Discord.Net/Entities/Channels/DMChannel.cs View File

@@ -13,13 +13,13 @@ namespace Discord
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] [DebuggerDisplay(@"{DebuggerDisplay,nq}")]
internal class DMChannel : SnowflakeEntity, IDMChannel internal class DMChannel : SnowflakeEntity, IDMChannel
{ {
public override DiscordClient Discord { get; }
public override DiscordRestClient Discord { get; }
public IUser Recipient { get; private set; } public IUser Recipient { get; private set; }


public virtual IReadOnlyCollection<IMessage> CachedMessages => ImmutableArray.Create<IMessage>(); public virtual IReadOnlyCollection<IMessage> CachedMessages => ImmutableArray.Create<IMessage>();
IReadOnlyCollection<IUser> IPrivateChannel.Recipients => ImmutableArray.Create(Recipient); IReadOnlyCollection<IUser> IPrivateChannel.Recipients => ImmutableArray.Create(Recipient);


public DMChannel(DiscordClient discord, IUser recipient, Model model)
public DMChannel(DiscordRestClient discord, IUser recipient, Model model)
: base(model.Id) : base(model.Id)
{ {
Discord = discord; Discord = discord;


+ 2
- 2
src/Discord.Net/Entities/Channels/GroupChannel.cs View File

@@ -18,14 +18,14 @@ namespace Discord
protected ConcurrentDictionary<ulong, GroupUser> _users; protected ConcurrentDictionary<ulong, GroupUser> _users;
private string _iconId; private string _iconId;
public override DiscordClient Discord { get; }
public override DiscordRestClient Discord { get; }
public string Name { get; private set; } public string Name { get; private set; }


public IReadOnlyCollection<IUser> Recipients => _users.ToReadOnlyCollection(); public IReadOnlyCollection<IUser> Recipients => _users.ToReadOnlyCollection();
public virtual IReadOnlyCollection<IMessage> CachedMessages => ImmutableArray.Create<IMessage>(); public virtual IReadOnlyCollection<IMessage> CachedMessages => ImmutableArray.Create<IMessage>();
public string IconUrl => API.CDN.GetChannelIconUrl(Id, _iconId); public string IconUrl => API.CDN.GetChannelIconUrl(Id, _iconId);


public GroupChannel(DiscordClient discord, Model model)
public GroupChannel(DiscordRestClient discord, Model model)
: base(model.Id) : base(model.Id)
{ {
Discord = discord; Discord = discord;


+ 3
- 3
src/Discord.Net/Entities/Channels/GuildChannel.cs View File

@@ -19,7 +19,7 @@ namespace Discord


public Guild Guild { get; private set; } public Guild Guild { get; private set; }


public override DiscordClient Discord => Guild.Discord;
public override DiscordRestClient Discord => Guild.Discord;


public GuildChannel(Guild guild, Model model) public GuildChannel(Guild guild, Model model)
: base(model.Id) : base(model.Id)
@@ -56,8 +56,8 @@ namespace Discord
var args = new ModifyGuildChannelParams(); var args = new ModifyGuildChannelParams();
func(args); func(args);


if (!args.Name.IsSpecified)
args.Name = Name;
if (!args._name.IsSpecified)
args._name = Name;


var model = await Discord.ApiClient.ModifyGuildChannelAsync(Id, args).ConfigureAwait(false); var model = await Discord.ApiClient.ModifyGuildChannelAsync(Id, args).ConfigureAwait(false);
Update(model, UpdateSource.Rest); Update(model, UpdateSource.Rest);


+ 3
- 4
src/Discord.Net/Entities/Channels/IMessageChannel.cs View File

@@ -20,12 +20,11 @@ namespace Discord
/// <summary> Gets the message from this channel's cache with the given id, or null if not found. </summary> /// <summary> Gets the message from this channel's cache with the given id, or null if not found. </summary>
IMessage GetCachedMessage(ulong id); IMessage GetCachedMessage(ulong id);
/// <summary> Gets the last N messages from this message channel. </summary> /// <summary> Gets the last N messages from this message channel. </summary>
Task<IReadOnlyCollection<IMessage>> GetMessagesAsync(int limit = DiscordConfig.MaxMessagesPerBatch);
Task<IReadOnlyCollection<IMessage>> GetMessagesAsync(int limit = DiscordRestConfig.MaxMessagesPerBatch);
/// <summary> Gets a collection of messages in this channel. </summary> /// <summary> Gets a collection of messages in this channel. </summary>
Task<IReadOnlyCollection<IMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch);
Task<IReadOnlyCollection<IMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = DiscordRestConfig.MaxMessagesPerBatch);
/// <summary> Bulk deletes multiple messages. </summary> /// <summary> Bulk deletes multiple messages. </summary>
Task DeleteMessagesAsync(IEnumerable<IMessage> messages);
Task DeleteMessagesAsync(IEnumerable<IMessage> messages);


/// <summary> Broadcasts the "user is typing" message to all users in this channel, lasting 10 seconds.</summary> /// <summary> Broadcasts the "user is typing" message to all users in this channel, lasting 10 seconds.</summary>
Task TriggerTypingAsync(); Task TriggerTypingAsync();


+ 1
- 1
src/Discord.Net/Entities/Channels/IPrivateChannel.cs View File

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


namespace Discord namespace Discord
{ {
public interface IPrivateChannel
public interface IPrivateChannel : IChannel
{ {
IReadOnlyCollection<IUser> Recipients { get; } IReadOnlyCollection<IUser> Recipients { get; }
} }


+ 2
- 2
src/Discord.Net/Entities/Channels/TextChannel.cs View File

@@ -37,8 +37,8 @@ namespace Discord
var args = new ModifyTextChannelParams(); var args = new ModifyTextChannelParams();
func(args); func(args);


if (!args.Name.IsSpecified)
args.Name = Name;
if (!args._name.IsSpecified)
args._name = Name;


var model = await Discord.ApiClient.ModifyGuildChannelAsync(Id, args).ConfigureAwait(false); var model = await Discord.ApiClient.ModifyGuildChannelAsync(Id, args).ConfigureAwait(false);
Update(model, UpdateSource.Rest); Update(model, UpdateSource.Rest);


+ 2
- 2
src/Discord.Net/Entities/Channels/VoiceChannel.cs View File

@@ -34,8 +34,8 @@ namespace Discord
var args = new ModifyVoiceChannelParams(); var args = new ModifyVoiceChannelParams();
func(args); func(args);


if (!args.Name.IsSpecified)
args.Name = Name;
if (!args._name.IsSpecified)
args._name = Name;


var model = await Discord.ApiClient.ModifyGuildChannelAsync(Id, args).ConfigureAwait(false); var model = await Discord.ApiClient.ModifyGuildChannelAsync(Id, args).ConfigureAwait(false);
Update(model, UpdateSource.Rest); Update(model, UpdateSource.Rest);


+ 3
- 2
src/Discord.Net/Entities/Entity.cs View File

@@ -4,9 +4,10 @@
{ {
public T Id { get; } public T Id { get; }


public abstract DiscordClient Discord { get; }
public abstract DiscordRestClient Discord { get; }


public bool IsAttached => this is ICachedEntity<T>;
internal virtual bool IsAttached => false;
bool IEntity<T>.IsAttached => IsAttached;


public Entity(T id) public Entity(T id)
{ {


+ 7
- 7
src/Discord.Net/Entities/Guilds/Guild.cs View File

@@ -27,7 +27,7 @@ namespace Discord
public MfaLevel MfaLevel { get; private set; } public MfaLevel MfaLevel { get; private set; }
public DefaultMessageNotifications DefaultMessageNotifications { get; private set; } public DefaultMessageNotifications DefaultMessageNotifications { get; private set; }


public override DiscordClient Discord { get; }
public override DiscordRestClient Discord { get; }
public ulong? AFKChannelId { get; private set; } public ulong? AFKChannelId { get; private set; }
public ulong? EmbedChannelId { get; private set; } public ulong? EmbedChannelId { get; private set; }
public ulong OwnerId { get; private set; } public ulong OwnerId { get; private set; }
@@ -42,7 +42,7 @@ namespace Discord
public Role EveryoneRole => GetRole(Id); public Role EveryoneRole => GetRole(Id);
public IReadOnlyCollection<IRole> Roles => _roles.ToReadOnlyCollection(); public IReadOnlyCollection<IRole> Roles => _roles.ToReadOnlyCollection();


public Guild(DiscordClient discord, Model model)
public Guild(DiscordRestClient discord, Model model)
: base(model.Id) : base(model.Id)
{ {
Discord = discord; Discord = discord;
@@ -122,10 +122,10 @@ namespace Discord
var args = new ModifyGuildParams(); var args = new ModifyGuildParams();
func(args); func(args);


if (args.Splash.IsSpecified && _splashId != null)
args.SplashHash = _splashId;
if (args.Icon.IsSpecified && _iconId != null)
args.IconHash = _iconId;
if (args._splash.IsSpecified && _splashId != null)
args._splash = new API.Image(_splashId);
if (args._icon.IsSpecified && _iconId != null)
args._icon = new API.Image(_iconId);


var model = await Discord.ApiClient.ModifyGuildAsync(Id, args).ConfigureAwait(false); var model = await Discord.ApiClient.ModifyGuildAsync(Id, args).ConfigureAwait(false);
Update(model, UpdateSource.Rest); Update(model, UpdateSource.Rest);
@@ -165,7 +165,7 @@ namespace Discord
public Task AddBanAsync(IUser user, int pruneDays = 0) => AddBanAsync(user, pruneDays); public Task AddBanAsync(IUser user, int pruneDays = 0) => AddBanAsync(user, pruneDays);
public async Task AddBanAsync(ulong userId, int pruneDays = 0) public async Task AddBanAsync(ulong userId, int pruneDays = 0)
{ {
var args = new CreateGuildBanParams() { PruneDays = pruneDays };
var args = new CreateGuildBanParams() { DeleteMessageDays = pruneDays };
await Discord.ApiClient.CreateGuildBanAsync(Id, userId, args).ConfigureAwait(false); await Discord.ApiClient.CreateGuildBanAsync(Id, userId, args).ConfigureAwait(false);
} }
public Task RemoveBanAsync(IUser user) => RemoveBanAsync(user.Id); public Task RemoveBanAsync(IUser user) => RemoveBanAsync(user.Id);


+ 1
- 1
src/Discord.Net/Entities/Guilds/GuildIntegration.cs View File

@@ -23,7 +23,7 @@ namespace Discord
public User User { get; private set; } public User User { get; private set; }
public IntegrationAccount Account { get; private set; } public IntegrationAccount Account { get; private set; }


public override DiscordClient Discord => Guild.Discord;
public override DiscordRestClient Discord => Guild.Discord;
public DateTimeOffset SyncedAt => DateTimeUtils.FromTicks(_syncedAtTicks); public DateTimeOffset SyncedAt => DateTimeUtils.FromTicks(_syncedAtTicks);


public GuildIntegration(Guild guild, Model model) public GuildIntegration(Guild guild, Model model)


+ 2
- 2
src/Discord.Net/Entities/Guilds/UserGuild.cs View File

@@ -13,11 +13,11 @@ namespace Discord
public bool IsOwner { get; private set; } public bool IsOwner { get; private set; }
public GuildPermissions Permissions { get; private set; } public GuildPermissions Permissions { get; private set; }


public override DiscordClient Discord { get; }
public override DiscordRestClient Discord { get; }


public string IconUrl => API.CDN.GetGuildIconUrl(Id, _iconId); public string IconUrl => API.CDN.GetGuildIconUrl(Id, _iconId);


public UserGuild(DiscordClient discord, Model model)
public UserGuild(DiscordRestClient discord, Model model)
: base(model.Id) : base(model.Id)
{ {
Discord = discord; Discord = discord;


+ 4
- 4
src/Discord.Net/Entities/Invites/Invite.cs View File

@@ -13,13 +13,13 @@ namespace Discord


public ulong ChannelId { get; private set; } public ulong ChannelId { get; private set; }
public ulong GuildId { get; private set; } public ulong GuildId { get; private set; }
public override DiscordClient Discord { get; }
public override DiscordRestClient Discord { get; }


public string Code => Id; public string Code => Id;
public string Url => $"{DiscordConfig.InviteUrl}/{XkcdCode ?? Code}";
public string XkcdUrl => XkcdCode != null ? $"{DiscordConfig.InviteUrl}/{XkcdCode}" : null;
public string Url => $"{DiscordRestConfig.InviteUrl}/{XkcdCode ?? Code}";
public string XkcdUrl => XkcdCode != null ? $"{DiscordRestConfig.InviteUrl}/{XkcdCode}" : null;


public Invite(DiscordClient discord, Model model)
public Invite(DiscordRestClient discord, Model model)
: base(model.Code) : base(model.Code)
{ {
Discord = discord; Discord = discord;


+ 1
- 1
src/Discord.Net/Entities/Invites/InviteMetadata.cs View File

@@ -16,7 +16,7 @@ namespace Discord


public DateTimeOffset CreatedAt => DateTimeUtils.FromTicks(_createdAtTicks); public DateTimeOffset CreatedAt => DateTimeUtils.FromTicks(_createdAtTicks);


public InviteMetadata(DiscordClient client, Model model)
public InviteMetadata(DiscordRestClient client, Model model)
: base(client, model) : base(client, model)
{ {
Update(model, UpdateSource.Creation); Update(model, UpdateSource.Creation);


+ 1
- 1
src/Discord.Net/Entities/Messages/Message.cs View File

@@ -29,7 +29,7 @@ namespace Discord
public IReadOnlyCollection<IRole> MentionedRoles { get; private set; } public IReadOnlyCollection<IRole> MentionedRoles { get; private set; }
public IReadOnlyCollection<IUser> MentionedUsers { get; private set; } public IReadOnlyCollection<IUser> MentionedUsers { get; private set; }


public override DiscordClient Discord => (Channel as Entity<ulong>).Discord;
public override DiscordRestClient Discord => (Channel as Entity<ulong>).Discord;
public DateTimeOffset? EditedTimestamp => DateTimeUtils.FromTicks(_editedTimestampTicks); public DateTimeOffset? EditedTimestamp => DateTimeUtils.FromTicks(_editedTimestampTicks);
public DateTimeOffset Timestamp => DateTimeUtils.FromTicks(_timestampTicks); public DateTimeOffset Timestamp => DateTimeUtils.FromTicks(_timestampTicks);




+ 2
- 1
src/Discord.Net/Entities/Roles/Role.cs View File

@@ -23,7 +23,7 @@ namespace Discord
public bool IsEveryone => Id == Guild.Id; public bool IsEveryone => Id == Guild.Id;
public string Mention => MentionUtils.Mention(this); public string Mention => MentionUtils.Mention(this);
public override DiscordClient Discord => Guild.Discord;
public override DiscordRestClient Discord => Guild.Discord;


public Role(Guild guild, Model model) public Role(Guild guild, Model model)
: base(model.Id) : base(model.Id)
@@ -51,6 +51,7 @@ namespace Discord
var args = new ModifyGuildRoleParams(); var args = new ModifyGuildRoleParams();
func(args); func(args);
var response = await Discord.ApiClient.ModifyGuildRoleAsync(Guild.Id, Id, args).ConfigureAwait(false); var response = await Discord.ApiClient.ModifyGuildRoleAsync(Guild.Id, Id, args).ConfigureAwait(false);

Update(response, UpdateSource.Rest); Update(response, UpdateSource.Rest);
} }
public async Task DeleteAsync() public async Task DeleteAsync()


+ 4
- 2
src/Discord.Net/Entities/Users/GroupUser.cs View File

@@ -6,6 +6,9 @@ namespace Discord
{ {
internal class GroupUser : IGroupUser internal class GroupUser : IGroupUser
{ {
internal virtual bool IsAttached => false;
bool IEntity<ulong>.IsAttached => IsAttached;

public GroupChannel Channel { get; private set; } public GroupChannel Channel { get; private set; }
public User User { get; private set; } public User User { get; private set; }


@@ -14,7 +17,6 @@ namespace Discord
public DateTimeOffset CreatedAt => User.CreatedAt; public DateTimeOffset CreatedAt => User.CreatedAt;
public string Discriminator => User.Discriminator; public string Discriminator => User.Discriminator;
public ushort DiscriminatorValue => User.DiscriminatorValue; public ushort DiscriminatorValue => User.DiscriminatorValue;
public bool IsAttached => User.IsAttached;
public bool IsBot => User.IsBot; public bool IsBot => User.IsBot;
public string Username => User.Username; public string Username => User.Username;
public string Mention => MentionUtils.Mention(this, false); public string Mention => MentionUtils.Mention(this, false);
@@ -22,7 +24,7 @@ namespace Discord
public virtual UserStatus Status => UserStatus.Unknown; public virtual UserStatus Status => UserStatus.Unknown;
public virtual Game Game => null; public virtual Game Game => null;


public DiscordClient Discord => Channel.Discord;
public DiscordRestClient Discord => Channel.Discord;


public GroupUser(GroupChannel channel, User user) public GroupUser(GroupChannel channel, User user)
{ {


+ 18
- 10
src/Discord.Net/Entities/Users/GuildUser.cs View File

@@ -13,6 +13,9 @@ namespace Discord
[DebuggerDisplay("{DebuggerDisplay,nq}")] [DebuggerDisplay("{DebuggerDisplay,nq}")]
internal class GuildUser : IGuildUser, ISnowflakeEntity internal class GuildUser : IGuildUser, ISnowflakeEntity
{ {
internal virtual bool IsAttached => false;
bool IEntity<ulong>.IsAttached => IsAttached;

private long? _joinedAtTicks; private long? _joinedAtTicks;
public string Nickname { get; private set; } public string Nickname { get; private set; }
@@ -27,7 +30,6 @@ namespace Discord
public DateTimeOffset CreatedAt => User.CreatedAt; public DateTimeOffset CreatedAt => User.CreatedAt;
public string Discriminator => User.Discriminator; public string Discriminator => User.Discriminator;
public ushort DiscriminatorValue => User.DiscriminatorValue; public ushort DiscriminatorValue => User.DiscriminatorValue;
public bool IsAttached => User.IsAttached;
public bool IsBot => User.IsBot; public bool IsBot => User.IsBot;
public string Mention => MentionUtils.Mention(this, Nickname != null); public string Mention => MentionUtils.Mention(this, Nickname != null);
public string Username => User.Username; public string Username => User.Username;
@@ -35,7 +37,7 @@ namespace Discord
public virtual UserStatus Status => UserStatus.Unknown; public virtual UserStatus Status => UserStatus.Unknown;
public virtual Game Game => null; public virtual Game Game => null;


public DiscordClient Discord => Guild.Discord;
public DiscordRestClient Discord => Guild.Discord;
public DateTimeOffset? JoinedAt => DateTimeUtils.FromTicks(_joinedAtTicks); public DateTimeOffset? JoinedAt => DateTimeUtils.FromTicks(_joinedAtTicks);


public GuildUser(Guild guild, User user) public GuildUser(Guild guild, User user)
@@ -75,6 +77,15 @@ namespace Discord
if (model.Nick.IsSpecified) if (model.Nick.IsSpecified)
Nickname = model.Nick.Value; Nickname = model.Nick.Value;
} }
private void Update(ModifyGuildMemberParams args, UpdateSource source)
{
if (source == UpdateSource.Rest && IsAttached) return;

if (args._roleIds.IsSpecified)
Roles = args._roleIds.Value.Select(x => Guild.GetRole(x)).Where(x => x != null).ToImmutableArray();
if (args._nickname.IsSpecified)
Nickname = args._nickname.Value ?? "";
}
private void UpdateRoles(ulong[] roleIds) private void UpdateRoles(ulong[] roleIds)
{ {
var roles = ImmutableArray.CreateBuilder<Role>(roleIds.Length + 1); var roles = ImmutableArray.CreateBuilder<Role>(roleIds.Length + 1);
@@ -104,20 +115,17 @@ namespace Discord
func(args); func(args);


bool isCurrentUser = (await Discord.GetCurrentUserAsync().ConfigureAwait(false)).Id == Id; bool isCurrentUser = (await Discord.GetCurrentUserAsync().ConfigureAwait(false)).Id == Id;
if (isCurrentUser && args.Nickname.IsSpecified)
if (isCurrentUser && args._nickname.IsSpecified)
{ {
var nickArgs = new ModifyCurrentUserNickParams { Nickname = args.Nickname.Value ?? "" };
var nickArgs = new ModifyCurrentUserNickParams { Nickname = args._nickname.Value ?? "" };
await Discord.ApiClient.ModifyMyNickAsync(Guild.Id, nickArgs).ConfigureAwait(false); await Discord.ApiClient.ModifyMyNickAsync(Guild.Id, nickArgs).ConfigureAwait(false);
args.Nickname = new Optional<string>(); //Remove
args._nickname = Optional.Create<string>(); //Remove
} }


if (!isCurrentUser || args.Deaf.IsSpecified || args.Mute.IsSpecified || args.RoleIds.IsSpecified)
if (!isCurrentUser || args._deaf.IsSpecified || args._mute.IsSpecified || args._roleIds.IsSpecified)
{ {
await Discord.ApiClient.ModifyGuildMemberAsync(Guild.Id, Id, args).ConfigureAwait(false); await Discord.ApiClient.ModifyGuildMemberAsync(Guild.Id, Id, args).ConfigureAwait(false);
if (args.Nickname.IsSpecified)
Nickname = args.Nickname.Value ?? "";
if (args.RoleIds.IsSpecified)
Roles = args.RoleIds.Value.Select(x => Guild.GetRole(x)).Where(x => x != null).ToImmutableArray();
Update(args, UpdateSource.Rest);
} }
} }
public async Task KickAsync() public async Task KickAsync()


+ 9
- 9
src/Discord.Net/Entities/Users/SelfUser.cs View File

@@ -18,9 +18,9 @@ namespace Discord
public override UserStatus Status => _status; public override UserStatus Status => _status;
public override Game Game => _game; public override Game Game => _game;


public override DiscordClient Discord { get; }
public override DiscordRestClient Discord { get; }


public SelfUser(DiscordClient discord, Model model)
public SelfUser(DiscordRestClient discord, Model model)
: base(model) : base(model)
{ {
Discord = discord; Discord = discord;
@@ -53,10 +53,10 @@ namespace Discord
var args = new ModifyCurrentUserParams(); var args = new ModifyCurrentUserParams();
func(args); func(args);


if (!args.Username.IsSpecified)
args.Username = Username;
if (args.Avatar.IsSpecified && _avatarId != null)
args.AvatarHash = _avatarId;
if (!args._username.IsSpecified)
args._username = Username;
if (!args._avatar.IsSpecified && _avatarId != null)
args._avatar = new API.Image(_avatarId);


var model = await Discord.ApiClient.ModifySelfAsync(args).ConfigureAwait(false); var model = await Discord.ApiClient.ModifySelfAsync(args).ConfigureAwait(false);
Update(model, UpdateSource.Rest); Update(model, UpdateSource.Rest);
@@ -68,13 +68,13 @@ namespace Discord
var args = new ModifyPresenceParams(); var args = new ModifyPresenceParams();
func(args); func(args);


var game = args.Game.GetValueOrDefault(_game);
var status = args.Status.GetValueOrDefault(_status);
var game = args._game.GetValueOrDefault(_game);
var status = args._status.GetValueOrDefault(_status);


long idleSince = _idleSince; long idleSince = _idleSince;
if (status == UserStatus.Idle && _status != UserStatus.Idle) if (status == UserStatus.Idle && _status != UserStatus.Idle)
idleSince = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); idleSince = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
var apiGame = new API.Game { Name = game.Name, StreamType = game.StreamType, StreamUrl = game.StreamUrl };
var apiGame = game != null ? new API.Game { Name = game.Name, StreamType = game.StreamType, StreamUrl = game.StreamUrl } : null;


await Discord.ApiClient.SendStatusUpdateAsync(status == UserStatus.Idle ? _idleSince : (long?)null, apiGame).ConfigureAwait(false); await Discord.ApiClient.SendStatusUpdateAsync(status == UserStatus.Idle ? _idleSince : (long?)null, apiGame).ConfigureAwait(false);


+ 1
- 1
src/Discord.Net/Entities/Users/User.cs View File

@@ -13,7 +13,7 @@ namespace Discord
public string Username { get; private set; } public string Username { get; private set; }
public ushort DiscriminatorValue { get; private set; } public ushort DiscriminatorValue { get; private set; }


public override DiscordClient Discord { get { throw new NotSupportedException(); } }
public override DiscordRestClient Discord { get { throw new NotSupportedException(); } }


public string AvatarUrl => API.CDN.GetUserAvatarUrl(Id, _avatarId); public string AvatarUrl => API.CDN.GetUserAvatarUrl(Id, _avatarId);
public string Discriminator => DiscriminatorValue.ToString("D4"); public string Discriminator => DiscriminatorValue.ToString("D4");


+ 0
- 17
src/Discord.Net/Entities/WebSocket/CachedMessage.cs View File

@@ -1,17 +0,0 @@
using Model = Discord.API.Message;

namespace Discord
{
internal class CachedMessage : Message, ICachedEntity<ulong>
{
public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient;
public new ICachedMessageChannel Channel => base.Channel as ICachedMessageChannel;

public CachedMessage(ICachedMessageChannel channel, IUser author, Model model)
: base(channel, author, model)
{
}

public CachedMessage Clone() => MemberwiseClone() as CachedMessage;
}
}

+ 0
- 19
src/Discord.Net/Entities/WebSocket/CachedSelfUser.cs View File

@@ -1,19 +0,0 @@
using System;
using Model = Discord.API.User;

namespace Discord
{
internal class CachedSelfUser : SelfUser, ICachedUser
{
public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient;
CachedGlobalUser ICachedUser.User { get { throw new NotSupportedException(); } }

public CachedSelfUser(DiscordSocketClient discord, Model model)
: base(discord, model)
{
}

public CachedSelfUser Clone() => MemberwiseClone() as CachedSelfUser;
ICachedUser ICachedUser.Clone() => Clone();
}
}

src/Discord.Net/Entities/WebSocket/ICachedChannel.cs → src/Discord.Net/Entities/WebSocket/Channels/ISocketChannel.cs View File

@@ -2,10 +2,10 @@


namespace Discord namespace Discord
{ {
internal interface ICachedChannel : IChannel, ICachedEntity<ulong>
internal interface ISocketChannel : IChannel
{ {
void Update(Model model, UpdateSource source); void Update(Model model, UpdateSource source);


ICachedChannel Clone();
ISocketChannel Clone();
} }
} }

+ 7
- 0
src/Discord.Net/Entities/WebSocket/Channels/ISocketGuildChannel.cs View File

@@ -0,0 +1,7 @@
namespace Discord
{
internal interface ISocketGuildChannel : ISocketChannel, IGuildChannel
{
new SocketGuild Guild { get; }
}
}

+ 16
- 0
src/Discord.Net/Entities/WebSocket/Channels/ISocketMessageChannel.cs View File

@@ -0,0 +1,16 @@
using System.Collections.Generic;
using MessageModel = Discord.API.Message;

namespace Discord
{
internal interface ISocketMessageChannel : ISocketChannel, IMessageChannel
{
IReadOnlyCollection<ISocketUser> Users { get; }

SocketMessage AddMessage(ISocketUser author, MessageModel model);
SocketMessage GetMessage(ulong id);
SocketMessage RemoveMessage(ulong id);

ISocketUser GetUser(ulong id, bool skipCheck = false);
}
}

+ 9
- 0
src/Discord.Net/Entities/WebSocket/Channels/ISocketPrivateChannel.cs View File

@@ -0,0 +1,9 @@
using System.Collections.Generic;

namespace Discord
{
internal interface ISocketPrivateChannel : ISocketChannel, IPrivateChannel
{
new IReadOnlyCollection<ISocketUser> Recipients { get; }
}
}

src/Discord.Net/Entities/WebSocket/MessageCache.cs → src/Discord.Net/Entities/WebSocket/Channels/MessageCache.cs View File

@@ -10,51 +10,51 @@ namespace Discord
{ {
internal class MessageCache : MessageManager internal class MessageCache : MessageManager
{ {
private readonly ConcurrentDictionary<ulong, CachedMessage> _messages;
private readonly ConcurrentDictionary<ulong, SocketMessage> _messages;
private readonly ConcurrentQueue<ulong> _orderedMessages; private readonly ConcurrentQueue<ulong> _orderedMessages;
private readonly int _size; private readonly int _size;


public override IReadOnlyCollection<CachedMessage> Messages => _messages.ToReadOnlyCollection();
public override IReadOnlyCollection<SocketMessage> Messages => _messages.ToReadOnlyCollection();


public MessageCache(DiscordSocketClient discord, ICachedMessageChannel channel)
public MessageCache(DiscordSocketClient discord, ISocketMessageChannel channel)
: base(discord, channel) : base(discord, channel)
{ {
_size = discord.MessageCacheSize; _size = discord.MessageCacheSize;
_messages = new ConcurrentDictionary<ulong, CachedMessage>(1, (int)(_size * 1.05));
_messages = new ConcurrentDictionary<ulong, SocketMessage>(1, (int)(_size * 1.05));
_orderedMessages = new ConcurrentQueue<ulong>(); _orderedMessages = new ConcurrentQueue<ulong>();
} }


public override void Add(CachedMessage message)
public override void Add(SocketMessage message)
{ {
if (_messages.TryAdd(message.Id, message)) if (_messages.TryAdd(message.Id, message))
{ {
_orderedMessages.Enqueue(message.Id); _orderedMessages.Enqueue(message.Id);


ulong msgId; ulong msgId;
CachedMessage msg;
SocketMessage msg;
while (_orderedMessages.Count > _size && _orderedMessages.TryDequeue(out msgId)) while (_orderedMessages.Count > _size && _orderedMessages.TryDequeue(out msgId))
_messages.TryRemove(msgId, out msg); _messages.TryRemove(msgId, out msg);
} }
} }


public override CachedMessage Remove(ulong id)
public override SocketMessage Remove(ulong id)
{ {
CachedMessage msg;
SocketMessage msg;
_messages.TryRemove(id, out msg); _messages.TryRemove(id, out msg);
return msg; return msg;
} }


public override CachedMessage Get(ulong id)
public override SocketMessage Get(ulong id)
{ {
CachedMessage result;
SocketMessage result;
if (_messages.TryGetValue(id, out result)) if (_messages.TryGetValue(id, out result))
return result; return result;
return null; return null;
} }
public override IImmutableList<CachedMessage> GetMany(ulong? fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch)
public override IImmutableList<SocketMessage> GetMany(ulong? fromMessageId, Direction dir, int limit = DiscordRestConfig.MaxMessagesPerBatch)
{ {
if (limit < 0) throw new ArgumentOutOfRangeException(nameof(limit)); if (limit < 0) throw new ArgumentOutOfRangeException(nameof(limit));
if (limit == 0) return ImmutableArray<CachedMessage>.Empty;
if (limit == 0) return ImmutableArray<SocketMessage>.Empty;


IEnumerable<ulong> cachedMessageIds; IEnumerable<ulong> cachedMessageIds;
if (fromMessageId == null) if (fromMessageId == null)
@@ -68,7 +68,7 @@ namespace Discord
.Take(limit) .Take(limit)
.Select(x => .Select(x =>
{ {
CachedMessage msg;
SocketMessage msg;
if (_messages.TryGetValue(x, out msg)) if (_messages.TryGetValue(x, out msg))
return msg; return msg;
return null; return null;
@@ -77,7 +77,7 @@ namespace Discord
.ToImmutableArray(); .ToImmutableArray();
} }


public override async Task<CachedMessage> DownloadAsync(ulong id)
public override async Task<SocketMessage> DownloadAsync(ulong id)
{ {
var msg = Get(id); var msg = Get(id);
if (msg != null) if (msg != null)

src/Discord.Net/Entities/WebSocket/MessageManager.cs → src/Discord.Net/Entities/WebSocket/Channels/MessageManager.cs View File

@@ -10,36 +10,36 @@ namespace Discord
internal class MessageManager internal class MessageManager
{ {
private readonly DiscordSocketClient _discord; private readonly DiscordSocketClient _discord;
private readonly ICachedMessageChannel _channel;
private readonly ISocketMessageChannel _channel;


public virtual IReadOnlyCollection<CachedMessage> Messages
=> ImmutableArray.Create<CachedMessage>();
public virtual IReadOnlyCollection<SocketMessage> Messages
=> ImmutableArray.Create<SocketMessage>();


public MessageManager(DiscordSocketClient discord, ICachedMessageChannel channel)
public MessageManager(DiscordSocketClient discord, ISocketMessageChannel channel)
{ {
_discord = discord; _discord = discord;
_channel = channel; _channel = channel;
} }


public virtual void Add(CachedMessage message) { }
public virtual CachedMessage Remove(ulong id) => null;
public virtual CachedMessage Get(ulong id) => null;
public virtual void Add(SocketMessage message) { }
public virtual SocketMessage Remove(ulong id) => null;
public virtual SocketMessage Get(ulong id) => null;


public virtual IImmutableList<CachedMessage> GetMany(ulong? fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch)
=> ImmutableArray.Create<CachedMessage>();
public virtual IImmutableList<SocketMessage> GetMany(ulong? fromMessageId, Direction dir, int limit = DiscordRestConfig.MaxMessagesPerBatch)
=> ImmutableArray.Create<SocketMessage>();


public virtual async Task<CachedMessage> DownloadAsync(ulong id)
public virtual async Task<SocketMessage> DownloadAsync(ulong id)
{ {
var model = await _discord.ApiClient.GetChannelMessageAsync(_channel.Id, id).ConfigureAwait(false); var model = await _discord.ApiClient.GetChannelMessageAsync(_channel.Id, id).ConfigureAwait(false);
if (model != null) if (model != null)
return new CachedMessage(_channel, new User(model.Author.Value), model);
return new SocketMessage(_channel, new User(model.Author.Value), model);
return null; return null;
} }
public async Task<IReadOnlyCollection<CachedMessage>> DownloadAsync(ulong? fromId, Direction dir, int limit)
public async Task<IReadOnlyCollection<SocketMessage>> DownloadAsync(ulong? fromId, Direction dir, int limit)
{ {
//TODO: Test heavily, especially the ordering of messages //TODO: Test heavily, especially the ordering of messages
if (limit < 0) throw new ArgumentOutOfRangeException(nameof(limit)); if (limit < 0) throw new ArgumentOutOfRangeException(nameof(limit));
if (limit == 0) return ImmutableArray<CachedMessage>.Empty;
if (limit == 0) return ImmutableArray<SocketMessage>.Empty;


var cachedMessages = GetMany(fromId, dir, limit); var cachedMessages = GetMany(fromId, dir, limit);
if (cachedMessages.Count == limit) if (cachedMessages.Count == limit)
@@ -48,20 +48,21 @@ namespace Discord
return cachedMessages.Skip(cachedMessages.Count - limit).ToImmutableArray(); return cachedMessages.Skip(cachedMessages.Count - limit).ToImmutableArray();
else else
{ {
Optional<ulong> relativeId;
if (cachedMessages.Count == 0)
relativeId = fromId ?? new Optional<ulong>();
else
relativeId = dir == Direction.Before ? cachedMessages[0].Id : cachedMessages[cachedMessages.Count - 1].Id;
var args = new GetChannelMessagesParams var args = new GetChannelMessagesParams
{ {
Limit = limit - cachedMessages.Count, Limit = limit - cachedMessages.Count,
RelativeDirection = dir,
RelativeMessageId = relativeId
RelativeDirection = dir
}; };
if (cachedMessages.Count == 0)
{
if (fromId != null)
args.RelativeMessageId = fromId.Value;
}
else
args.RelativeMessageId = dir == Direction.Before ? cachedMessages[0].Id : cachedMessages[cachedMessages.Count - 1].Id;
var downloadedMessages = await _discord.ApiClient.GetChannelMessagesAsync(_channel.Id, args).ConfigureAwait(false); var downloadedMessages = await _discord.ApiClient.GetChannelMessagesAsync(_channel.Id, args).ConfigureAwait(false);


var guild = (_channel as ICachedGuildChannel)?.Guild;
var guild = (_channel as ISocketGuildChannel)?.Guild;
return cachedMessages.Concat(downloadedMessages.Select(x => return cachedMessages.Concat(downloadedMessages.Select(x =>
{ {
IUser user = _channel.GetUser(x.Author.Value.Id, true); IUser user = _channel.GetUser(x.Author.Value.Id, true);
@@ -73,7 +74,7 @@ namespace Discord
else else
user = newUser; user = newUser;
} }
return new CachedMessage(_channel, user, x);
return new SocketMessage(_channel, user, x);
})).ToImmutableArray(); })).ToImmutableArray();
} }
} }

src/Discord.Net/Entities/WebSocket/CachedDMChannel.cs → src/Discord.Net/Entities/WebSocket/Channels/SocketDMChannel.cs View File

@@ -6,16 +6,18 @@ using Model = Discord.API.Channel;


namespace Discord namespace Discord
{ {
internal class CachedDMChannel : DMChannel, IDMChannel, ICachedChannel, ICachedMessageChannel, ICachedPrivateChannel
internal class SocketDMChannel : DMChannel, IDMChannel, ISocketChannel, ISocketMessageChannel, ISocketPrivateChannel
{ {
internal override bool IsAttached => true;

private readonly MessageManager _messages; private readonly MessageManager _messages;


public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient; public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient;
public new CachedDMUser Recipient => base.Recipient as CachedDMUser;
public IReadOnlyCollection<ICachedUser> Members => ImmutableArray.Create<ICachedUser>(Discord.CurrentUser, Recipient);
IReadOnlyCollection<ICachedUser> ICachedPrivateChannel.Recipients => ImmutableArray.Create(Recipient);
public new SocketDMUser Recipient => base.Recipient as SocketDMUser;
public IReadOnlyCollection<ISocketUser> Users => ImmutableArray.Create<ISocketUser>(Discord.CurrentUser, Recipient);
IReadOnlyCollection<ISocketUser> ISocketPrivateChannel.Recipients => ImmutableArray.Create(Recipient);


public CachedDMChannel(DiscordSocketClient discord, CachedDMUser recipient, Model model)
public SocketDMChannel(DiscordSocketClient discord, SocketDMUser recipient, Model model)
: base(discord, recipient, model) : base(discord, recipient, model)
{ {
if (Discord.MessageCacheSize > 0) if (Discord.MessageCacheSize > 0)
@@ -25,8 +27,8 @@ namespace Discord
} }


public override Task<IUser> GetUserAsync(ulong id) => Task.FromResult<IUser>(GetUser(id)); public override Task<IUser> GetUserAsync(ulong id) => Task.FromResult<IUser>(GetUser(id));
public override Task<IReadOnlyCollection<IUser>> GetUsersAsync() => Task.FromResult<IReadOnlyCollection<IUser>>(Members);
public ICachedUser GetUser(ulong id)
public override Task<IReadOnlyCollection<IUser>> GetUsersAsync() => Task.FromResult<IReadOnlyCollection<IUser>>(Users);
public ISocketUser GetUser(ulong id)
{ {
var currentUser = Discord.CurrentUser; var currentUser = Discord.CurrentUser;
if (id == Recipient.Id) if (id == Recipient.Id)
@@ -49,25 +51,25 @@ namespace Discord
{ {
return await _messages.DownloadAsync(fromMessageId, dir, limit).ConfigureAwait(false); return await _messages.DownloadAsync(fromMessageId, dir, limit).ConfigureAwait(false);
} }
public CachedMessage AddMessage(ICachedUser author, MessageModel model)
public SocketMessage AddMessage(ISocketUser author, MessageModel model)
{ {
var msg = new CachedMessage(this, author, model);
var msg = new SocketMessage(this, author, model);
_messages.Add(msg); _messages.Add(msg);
return msg; return msg;
} }
public CachedMessage GetMessage(ulong id)
public SocketMessage GetMessage(ulong id)
{ {
return _messages.Get(id); return _messages.Get(id);
} }
public CachedMessage RemoveMessage(ulong id)
public SocketMessage RemoveMessage(ulong id)
{ {
return _messages.Remove(id); return _messages.Remove(id);
} }


public CachedDMChannel Clone() => MemberwiseClone() as CachedDMChannel;
public SocketDMChannel Clone() => MemberwiseClone() as SocketDMChannel;


IMessage IMessageChannel.GetCachedMessage(ulong id) => GetMessage(id); IMessage IMessageChannel.GetCachedMessage(ulong id) => GetMessage(id);
ICachedUser ICachedMessageChannel.GetUser(ulong id, bool skipCheck) => GetUser(id);
ICachedChannel ICachedChannel.Clone() => Clone();
ISocketUser ISocketMessageChannel.GetUser(ulong id, bool skipCheck) => GetUser(id);
ISocketChannel ISocketChannel.Clone() => Clone();
} }
} }

src/Discord.Net/Entities/WebSocket/CachedGroupChannel.cs → src/Discord.Net/Entities/WebSocket/Channels/SocketGroupChannel.cs View File

@@ -11,17 +11,19 @@ using VoiceStateModel = Discord.API.VoiceState;


namespace Discord namespace Discord
{ {
internal class CachedGroupChannel : GroupChannel, IGroupChannel, ICachedChannel, ICachedMessageChannel, ICachedPrivateChannel
internal class SocketGroupChannel : GroupChannel, IGroupChannel, ISocketChannel, ISocketMessageChannel, ISocketPrivateChannel
{ {
internal override bool IsAttached => true;

private readonly MessageManager _messages; private readonly MessageManager _messages;
private ConcurrentDictionary<ulong, VoiceState> _voiceStates; private ConcurrentDictionary<ulong, VoiceState> _voiceStates;


public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient; public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient;
public IReadOnlyCollection<ICachedUser> Members
=> _users.Select(x => x.Value as ICachedUser).Concat(ImmutableArray.Create(Discord.CurrentUser)).ToReadOnlyCollection(() => _users.Count + 1);
public new IReadOnlyCollection<ICachedUser> Recipients => _users.Select(x => x.Value as ICachedUser).ToReadOnlyCollection(_users);
public IReadOnlyCollection<ISocketUser> Users
=> _users.Select(x => x.Value as ISocketUser).Concat(ImmutableArray.Create(Discord.CurrentUser)).ToReadOnlyCollection(() => _users.Count + 1);
public new IReadOnlyCollection<ISocketUser> Recipients => _users.Select(x => x.Value as ISocketUser).ToReadOnlyCollection(_users);


public CachedGroupChannel(DiscordSocketClient discord, Model model)
public SocketGroupChannel(DiscordSocketClient discord, Model model)
: base(discord, model) : base(discord, model)
{ {
if (Discord.MessageCacheSize > 0) if (Discord.MessageCacheSize > 0)
@@ -43,46 +45,46 @@ namespace Discord
for (int i = 0; i < models.Length; i++) for (int i = 0; i < models.Length; i++)
{ {
var globalUser = Discord.GetOrAddUser(models[i], dataStore); var globalUser = Discord.GetOrAddUser(models[i], dataStore);
users[models[i].Id] = new CachedGroupUser(this, globalUser);
users[models[i].Id] = new SocketGroupUser(this, globalUser);
} }
_users = users; _users = users;
} }
internal override void UpdateUsers(UserModel[] models, UpdateSource source) internal override void UpdateUsers(UserModel[] models, UpdateSource source)
=> UpdateUsers(models, source, Discord.DataStore); => UpdateUsers(models, source, Discord.DataStore);


public CachedGroupUser AddUser(UserModel model, DataStore dataStore)
public SocketGroupUser AddUser(UserModel model, DataStore dataStore)
{ {
GroupUser user; GroupUser user;
if (_users.TryGetValue(model.Id, out user)) if (_users.TryGetValue(model.Id, out user))
return user as CachedGroupUser;
return user as SocketGroupUser;
else else
{ {
var globalUser = Discord.GetOrAddUser(model, dataStore); var globalUser = Discord.GetOrAddUser(model, dataStore);
var privateUser = new CachedGroupUser(this, globalUser);
var privateUser = new SocketGroupUser(this, globalUser);
_users[privateUser.Id] = privateUser; _users[privateUser.Id] = privateUser;
return privateUser; return privateUser;
} }
} }
public ICachedUser GetUser(ulong id)
public ISocketUser GetUser(ulong id)
{ {
GroupUser user; GroupUser user;
if (_users.TryGetValue(id, out user)) if (_users.TryGetValue(id, out user))
return user as CachedGroupUser;
return user as SocketGroupUser;
if (id == Discord.CurrentUser.Id) if (id == Discord.CurrentUser.Id)
return Discord.CurrentUser; return Discord.CurrentUser;
return null; return null;
} }
public CachedGroupUser RemoveUser(ulong id)
public SocketGroupUser RemoveUser(ulong id)
{ {
GroupUser user; GroupUser user;
if (_users.TryRemove(id, out user)) if (_users.TryRemove(id, out user))
return user as CachedGroupUser;
return user as SocketGroupUser;
return null; return null;
} }


public VoiceState AddOrUpdateVoiceState(VoiceStateModel model, DataStore dataStore, ConcurrentDictionary<ulong, VoiceState> voiceStates = null) public VoiceState AddOrUpdateVoiceState(VoiceStateModel model, DataStore dataStore, ConcurrentDictionary<ulong, VoiceState> voiceStates = null)
{ {
var voiceChannel = dataStore.GetChannel(model.ChannelId.Value) as CachedVoiceChannel;
var voiceChannel = dataStore.GetChannel(model.ChannelId.Value) as SocketVoiceChannel;
var voiceState = new VoiceState(voiceChannel, model); var voiceState = new VoiceState(voiceChannel, model);
(voiceStates ?? _voiceStates)[model.UserId] = voiceState; (voiceStates ?? _voiceStates)[model.UserId] = voiceState;
return voiceState; return voiceState;
@@ -114,25 +116,25 @@ namespace Discord
{ {
return await _messages.DownloadAsync(fromMessageId, dir, limit).ConfigureAwait(false); return await _messages.DownloadAsync(fromMessageId, dir, limit).ConfigureAwait(false);
} }
public CachedMessage AddMessage(ICachedUser author, MessageModel model)
public SocketMessage AddMessage(ISocketUser author, MessageModel model)
{ {
var msg = new CachedMessage(this, author, model);
var msg = new SocketMessage(this, author, model);
_messages.Add(msg); _messages.Add(msg);
return msg; return msg;
} }
public CachedMessage GetMessage(ulong id)
public SocketMessage GetMessage(ulong id)
{ {
return _messages.Get(id); return _messages.Get(id);
} }
public CachedMessage RemoveMessage(ulong id)
public SocketMessage RemoveMessage(ulong id)
{ {
return _messages.Remove(id); return _messages.Remove(id);
} }


public CachedDMChannel Clone() => MemberwiseClone() as CachedDMChannel;
public SocketDMChannel Clone() => MemberwiseClone() as SocketDMChannel;


IMessage IMessageChannel.GetCachedMessage(ulong id) => GetMessage(id); IMessage IMessageChannel.GetCachedMessage(ulong id) => GetMessage(id);
ICachedUser ICachedMessageChannel.GetUser(ulong id, bool skipCheck) => GetUser(id);
ICachedChannel ICachedChannel.Clone() => Clone();
ISocketUser ISocketMessageChannel.GetUser(ulong id, bool skipCheck) => GetUser(id);
ISocketChannel ISocketChannel.Clone() => Clone();
} }
} }

src/Discord.Net/Entities/WebSocket/CachedTextChannel.cs → src/Discord.Net/Entities/WebSocket/Channels/SocketTextChannel.cs View File

@@ -7,17 +7,19 @@ using Model = Discord.API.Channel;


namespace Discord namespace Discord
{ {
internal class CachedTextChannel : TextChannel, ICachedGuildChannel, ICachedMessageChannel
internal class SocketTextChannel : TextChannel, ISocketGuildChannel, ISocketMessageChannel
{ {
internal override bool IsAttached => true;

private readonly MessageManager _messages; private readonly MessageManager _messages;


public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient; public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient;
public new CachedGuild Guild => base.Guild as CachedGuild;
public new SocketGuild Guild => base.Guild as SocketGuild;


public IReadOnlyCollection<CachedGuildUser> Members
public IReadOnlyCollection<SocketGuildUser> Members
=> Guild.Members.Where(x => Permissions.GetValue(Permissions.ResolveChannel(x, this, x.GuildPermissions.RawValue), ChannelPermission.ReadMessages)).ToImmutableArray(); => Guild.Members.Where(x => Permissions.GetValue(Permissions.ResolveChannel(x, this, x.GuildPermissions.RawValue), ChannelPermission.ReadMessages)).ToImmutableArray();


public CachedTextChannel(CachedGuild guild, Model model)
public SocketTextChannel(SocketGuild guild, Model model)
: base(guild, model) : base(guild, model)
{ {
if (Discord.MessageCacheSize > 0) if (Discord.MessageCacheSize > 0)
@@ -28,7 +30,7 @@ namespace Discord


public override Task<IGuildUser> GetUserAsync(ulong id) => Task.FromResult<IGuildUser>(GetUser(id)); public override Task<IGuildUser> GetUserAsync(ulong id) => Task.FromResult<IGuildUser>(GetUser(id));
public override Task<IReadOnlyCollection<IGuildUser>> GetUsersAsync() => Task.FromResult<IReadOnlyCollection<IGuildUser>>(Members); public override Task<IReadOnlyCollection<IGuildUser>> GetUsersAsync() => Task.FromResult<IReadOnlyCollection<IGuildUser>>(Members);
public CachedGuildUser GetUser(ulong id, bool skipCheck = false)
public SocketGuildUser GetUser(ulong id, bool skipCheck = false)
{ {
var user = Guild.GetUser(id); var user = Guild.GetUser(id);
if (skipCheck) return user; if (skipCheck) return user;
@@ -46,36 +48,36 @@ namespace Discord
{ {
return await _messages.DownloadAsync(id).ConfigureAwait(false); return await _messages.DownloadAsync(id).ConfigureAwait(false);
} }
public override async Task<IReadOnlyCollection<IMessage>> GetMessagesAsync(int limit = DiscordConfig.MaxMessagesPerBatch)
public override async Task<IReadOnlyCollection<IMessage>> GetMessagesAsync(int limit = DiscordRestConfig.MaxMessagesPerBatch)
{ {
return await _messages.DownloadAsync(null, Direction.Before, limit).ConfigureAwait(false); return await _messages.DownloadAsync(null, Direction.Before, limit).ConfigureAwait(false);
} }
public override async Task<IReadOnlyCollection<IMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch)
public override async Task<IReadOnlyCollection<IMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = DiscordRestConfig.MaxMessagesPerBatch)
{ {
return await _messages.DownloadAsync(fromMessageId, dir, limit).ConfigureAwait(false); return await _messages.DownloadAsync(fromMessageId, dir, limit).ConfigureAwait(false);
} }


public CachedMessage AddMessage(ICachedUser author, MessageModel model)
public SocketMessage AddMessage(ISocketUser author, MessageModel model)
{ {
var msg = new CachedMessage(this, author, model);
var msg = new SocketMessage(this, author, model);
_messages.Add(msg); _messages.Add(msg);
return msg; return msg;
} }
public CachedMessage GetMessage(ulong id)
public SocketMessage GetMessage(ulong id)
{ {
return _messages.Get(id); return _messages.Get(id);
} }
public CachedMessage RemoveMessage(ulong id)
public SocketMessage RemoveMessage(ulong id)
{ {
return _messages.Remove(id); return _messages.Remove(id);
} }


public CachedTextChannel Clone() => MemberwiseClone() as CachedTextChannel;
public SocketTextChannel Clone() => MemberwiseClone() as SocketTextChannel;


IReadOnlyCollection<ICachedUser> ICachedMessageChannel.Members => Members;
IReadOnlyCollection<ISocketUser> ISocketMessageChannel.Users => Members;


IMessage IMessageChannel.GetCachedMessage(ulong id) => GetMessage(id); IMessage IMessageChannel.GetCachedMessage(ulong id) => GetMessage(id);
ICachedUser ICachedMessageChannel.GetUser(ulong id, bool skipCheck) => GetUser(id, skipCheck);
ICachedChannel ICachedChannel.Clone() => Clone();
ISocketUser ISocketMessageChannel.GetUser(ulong id, bool skipCheck) => GetUser(id, skipCheck);
ISocketChannel ISocketChannel.Clone() => Clone();
} }
} }

src/Discord.Net/Entities/WebSocket/CachedVoiceChannel.cs → src/Discord.Net/Entities/WebSocket/Channels/SocketVoiceChannel.cs View File

@@ -8,15 +8,17 @@ using Model = Discord.API.Channel;


namespace Discord namespace Discord
{ {
internal class CachedVoiceChannel : VoiceChannel, ICachedGuildChannel
internal class SocketVoiceChannel : VoiceChannel, ISocketGuildChannel
{ {
internal override bool IsAttached => true;

public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient; public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient;
public new CachedGuild Guild => base.Guild as CachedGuild;
public new SocketGuild Guild => base.Guild as SocketGuild;


public IReadOnlyCollection<IGuildUser> Members public IReadOnlyCollection<IGuildUser> Members
=> Guild.VoiceStates.Where(x => x.Value.VoiceChannel.Id == Id).Select(x => Guild.GetUser(x.Key)).ToImmutableArray(); => Guild.VoiceStates.Where(x => x.Value.VoiceChannel.Id == Id).Select(x => Guild.GetUser(x.Key)).ToImmutableArray();


public CachedVoiceChannel(CachedGuild guild, Model model)
public SocketVoiceChannel(SocketGuild guild, Model model)
: base(guild, model) : base(guild, model)
{ {
} }
@@ -46,8 +48,8 @@ namespace Discord
//TODO: Block and return //TODO: Block and return
} }


public CachedVoiceChannel Clone() => MemberwiseClone() as CachedVoiceChannel;
public SocketVoiceChannel Clone() => MemberwiseClone() as SocketVoiceChannel;


ICachedChannel ICachedChannel.Clone() => Clone();
ISocketChannel ISocketChannel.Clone() => Clone();
} }
} }

src/Discord.Net/Entities/WebSocket/CachedGuild.cs → src/Discord.Net/Entities/WebSocket/Guilds/SocketGuild.cs View File

@@ -19,12 +19,14 @@ using VoiceStateModel = Discord.API.VoiceState;


namespace Discord namespace Discord
{ {
internal class CachedGuild : Guild, ICachedEntity<ulong>, IGuild, IUserGuild
internal class SocketGuild : Guild, IGuild, IUserGuild
{ {
internal override bool IsAttached => true;

private readonly SemaphoreSlim _audioLock; private readonly SemaphoreSlim _audioLock;
private TaskCompletionSource<bool> _syncPromise, _downloaderPromise; private TaskCompletionSource<bool> _syncPromise, _downloaderPromise;
private ConcurrentHashSet<ulong> _channels; private ConcurrentHashSet<ulong> _channels;
private ConcurrentDictionary<ulong, CachedGuildUser> _members;
private ConcurrentDictionary<ulong, SocketGuildUser> _members;
private ConcurrentDictionary<ulong, VoiceState> _voiceStates; private ConcurrentDictionary<ulong, VoiceState> _voiceStates;
internal bool _available; internal bool _available;


@@ -39,20 +41,20 @@ namespace Discord
public Task DownloaderPromise => _downloaderPromise.Task; public Task DownloaderPromise => _downloaderPromise.Task;


public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient; public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient;
public CachedGuildUser CurrentUser => GetUser(Discord.CurrentUser.Id);
public IReadOnlyCollection<ICachedGuildChannel> Channels
public SocketGuildUser CurrentUser => GetUser(Discord.CurrentUser.Id);
public IReadOnlyCollection<ISocketGuildChannel> Channels
{ {
get get
{ {
var channels = _channels; var channels = _channels;
var store = Discord.DataStore; var store = Discord.DataStore;
return channels.Select(x => store.GetChannel(x) as ICachedGuildChannel).Where(x => x != null).ToReadOnlyCollection(channels);
return channels.Select(x => store.GetChannel(x) as ISocketGuildChannel).Where(x => x != null).ToReadOnlyCollection(channels);
} }
} }
public IReadOnlyCollection<CachedGuildUser> Members => _members.ToReadOnlyCollection();
public IReadOnlyCollection<SocketGuildUser> Members => _members.ToReadOnlyCollection();
public IEnumerable<KeyValuePair<ulong, VoiceState>> VoiceStates => _voiceStates; public IEnumerable<KeyValuePair<ulong, VoiceState>> VoiceStates => _voiceStates;
public CachedGuild(DiscordSocketClient discord, ExtendedModel model, DataStore dataStore) : base(discord, model)
public SocketGuild(DiscordSocketClient discord, ExtendedModel model, DataStore dataStore) : base(discord, model)
{ {
_audioLock = new SemaphoreSlim(1, 1); _audioLock = new SemaphoreSlim(1, 1);
_syncPromise = new TaskCompletionSource<bool>(); _syncPromise = new TaskCompletionSource<bool>();
@@ -70,7 +72,7 @@ namespace Discord
if (_channels == null) if (_channels == null)
_channels = new ConcurrentHashSet<ulong>(); _channels = new ConcurrentHashSet<ulong>();
if (_members == null) if (_members == null)
_members = new ConcurrentDictionary<ulong, CachedGuildUser>();
_members = new ConcurrentDictionary<ulong, SocketGuildUser>();
if (_roles == null) if (_roles == null)
_roles = new ConcurrentDictionary<ulong, Role>(); _roles = new ConcurrentDictionary<ulong, Role>();
if (Emojis == null) if (Emojis == null)
@@ -91,7 +93,7 @@ namespace Discord
} }
_channels = channels; _channels = channels;
var members = new ConcurrentDictionary<ulong, CachedGuildUser>(1, (int)(model.Presences.Length * 1.05));
var members = new ConcurrentDictionary<ulong, SocketGuildUser>(1, (int)(model.Presences.Length * 1.05));
{ {
DownloadedMemberCount = 0; DownloadedMemberCount = 0;
for (int i = 0; i < model.Members.Length; i++) for (int i = 0; i < model.Members.Length; i++)
@@ -119,7 +121,7 @@ namespace Discord
{ {
if (source == UpdateSource.Rest && IsAttached) return; if (source == UpdateSource.Rest && IsAttached) return;


var members = new ConcurrentDictionary<ulong, CachedGuildUser>(1, (int)(model.Presences.Length * 1.05));
var members = new ConcurrentDictionary<ulong, SocketGuildUser>(1, (int)(model.Presences.Length * 1.05));
{ {
DownloadedMemberCount = 0; DownloadedMemberCount = 0;
for (int i = 0; i < model.Members.Length; i++) for (int i = 0; i < model.Members.Length; i++)
@@ -152,14 +154,14 @@ namespace Discord
(channels ?? _channels).TryAdd(model.Id); (channels ?? _channels).TryAdd(model.Id);
dataStore.AddChannel(channel); dataStore.AddChannel(channel);
} }
public ICachedGuildChannel GetChannel(ulong id)
public ISocketGuildChannel GetChannel(ulong id)
{ {
return Discord.DataStore.GetChannel(id) as ICachedGuildChannel;
return Discord.DataStore.GetChannel(id) as ISocketGuildChannel;
} }
public ICachedGuildChannel RemoveChannel(ulong id)
public ISocketGuildChannel RemoveChannel(ulong id)
{ {
_channels.TryRemove(id); _channels.TryRemove(id);
return Discord.DataStore.RemoveChannel(id) as ICachedGuildChannel;
return Discord.DataStore.RemoveChannel(id) as ISocketGuildChannel;
} }
public Role AddRole(RoleModel model, ConcurrentDictionary<ulong, Role> roles = null) public Role AddRole(RoleModel model, ConcurrentDictionary<ulong, Role> roles = null)
@@ -181,48 +183,48 @@ namespace Discord
=> Task.FromResult<IGuildUser>(CurrentUser); => Task.FromResult<IGuildUser>(CurrentUser);
public override Task<IReadOnlyCollection<IGuildUser>> GetUsersAsync() public override Task<IReadOnlyCollection<IGuildUser>> GetUsersAsync()
=> Task.FromResult<IReadOnlyCollection<IGuildUser>>(Members); => Task.FromResult<IReadOnlyCollection<IGuildUser>>(Members);
public CachedGuildUser AddUser(MemberModel model, DataStore dataStore, ConcurrentDictionary<ulong, CachedGuildUser> members = null)
public SocketGuildUser AddUser(MemberModel model, DataStore dataStore, ConcurrentDictionary<ulong, SocketGuildUser> members = null)
{ {
members = members ?? _members; members = members ?? _members;


CachedGuildUser member;
SocketGuildUser member;
if (members.TryGetValue(model.User.Id, out member)) if (members.TryGetValue(model.User.Id, out member))
member.Update(model, UpdateSource.WebSocket); member.Update(model, UpdateSource.WebSocket);
else else
{ {
var user = Discord.GetOrAddUser(model.User, dataStore); var user = Discord.GetOrAddUser(model.User, dataStore);
member = new CachedGuildUser(this, user, model);
member = new SocketGuildUser(this, user, model);
members[user.Id] = member; members[user.Id] = member;
DownloadedMemberCount++; DownloadedMemberCount++;
} }
return member; return member;
} }
public CachedGuildUser AddOrUpdateUser(PresenceModel model, DataStore dataStore, ConcurrentDictionary<ulong, CachedGuildUser> members = null)
public SocketGuildUser AddOrUpdateUser(PresenceModel model, DataStore dataStore, ConcurrentDictionary<ulong, SocketGuildUser> members = null)
{ {
members = members ?? _members; members = members ?? _members;


CachedGuildUser member;
SocketGuildUser member;
if (members.TryGetValue(model.User.Id, out member)) if (members.TryGetValue(model.User.Id, out member))
member.Update(model, UpdateSource.WebSocket); member.Update(model, UpdateSource.WebSocket);
else else
{ {
var user = Discord.GetOrAddUser(model.User, dataStore); var user = Discord.GetOrAddUser(model.User, dataStore);
member = new CachedGuildUser(this, user, model);
member = new SocketGuildUser(this, user, model);
members[user.Id] = member; members[user.Id] = member;
DownloadedMemberCount++; DownloadedMemberCount++;
} }
return member; return member;
} }
public CachedGuildUser GetUser(ulong id)
public SocketGuildUser GetUser(ulong id)
{ {
CachedGuildUser member;
SocketGuildUser member;
if (_members.TryGetValue(id, out member)) if (_members.TryGetValue(id, out member))
return member; return member;
return null; return null;
} }
public CachedGuildUser RemoveUser(ulong id)
public SocketGuildUser RemoveUser(ulong id)
{ {
CachedGuildUser member;
SocketGuildUser member;
if (_members.TryRemove(id, out member)) if (_members.TryRemove(id, out member))
return member; return member;
return null; return null;
@@ -238,7 +240,7 @@ namespace Discord


public VoiceState AddOrUpdateVoiceState(VoiceStateModel model, DataStore dataStore, ConcurrentDictionary<ulong, VoiceState> voiceStates = null) public VoiceState AddOrUpdateVoiceState(VoiceStateModel model, DataStore dataStore, ConcurrentDictionary<ulong, VoiceState> voiceStates = null)
{ {
var voiceChannel = dataStore.GetChannel(model.ChannelId.Value) as CachedVoiceChannel;
var voiceChannel = dataStore.GetChannel(model.ChannelId.Value) as SocketVoiceChannel;
var voiceState = new VoiceState(voiceChannel, model); var voiceState = new VoiceState(voiceChannel, model);
(voiceStates ?? _voiceStates)[model.UserId] = voiceState; (voiceStates ?? _voiceStates)[model.UserId] = voiceState;
return voiceState; return voiceState;
@@ -307,16 +309,16 @@ namespace Discord
await audioClient.ConnectAsync(url, CurrentUser.Id, voiceState.VoiceSessionId, token).ConfigureAwait(false); await audioClient.ConnectAsync(url, CurrentUser.Id, voiceState.VoiceSessionId, token).ConfigureAwait(false);
} }


public CachedGuild Clone() => MemberwiseClone() as CachedGuild;
public SocketGuild Clone() => MemberwiseClone() as SocketGuild;


new internal ICachedGuildChannel ToChannel(ChannelModel model)
new internal ISocketGuildChannel ToChannel(ChannelModel model)
{ {
switch (model.Type) switch (model.Type)
{ {
case ChannelType.Text: case ChannelType.Text:
return new CachedTextChannel(this, model);
return new SocketTextChannel(this, model);
case ChannelType.Voice: case ChannelType.Voice:
return new CachedVoiceChannel(this, model);
return new SocketVoiceChannel(this, model);
default: default:
throw new InvalidOperationException($"Unexpected channel type: {model.Type}"); throw new InvalidOperationException($"Unexpected channel type: {model.Type}");
} }

+ 0
- 7
src/Discord.Net/Entities/WebSocket/ICachedEntity.cs View File

@@ -1,7 +0,0 @@
namespace Discord
{
internal interface ICachedEntity<T> : IEntity<T>
{
DiscordSocketClient Discord { get; }
}
}

+ 0
- 7
src/Discord.Net/Entities/WebSocket/ICachedGuildChannel.cs View File

@@ -1,7 +0,0 @@
namespace Discord
{
internal interface ICachedGuildChannel : ICachedChannel, IGuildChannel
{
new CachedGuild Guild { get; }
}
}

+ 0
- 16
src/Discord.Net/Entities/WebSocket/ICachedMessageChannel.cs View File

@@ -1,16 +0,0 @@
using System.Collections.Generic;
using MessageModel = Discord.API.Message;

namespace Discord
{
internal interface ICachedMessageChannel : ICachedChannel, IMessageChannel
{
IReadOnlyCollection<ICachedUser> Members { get; }

CachedMessage AddMessage(ICachedUser author, MessageModel model);
CachedMessage GetMessage(ulong id);
CachedMessage RemoveMessage(ulong id);

ICachedUser GetUser(ulong id, bool skipCheck = false);
}
}

+ 0
- 9
src/Discord.Net/Entities/WebSocket/ICachedPrivateChannel.cs View File

@@ -1,9 +0,0 @@
using System.Collections.Generic;

namespace Discord
{
internal interface ICachedPrivateChannel : ICachedChannel, IPrivateChannel
{
new IReadOnlyCollection<ICachedUser> Recipients { get; }
}
}

+ 0
- 9
src/Discord.Net/Entities/WebSocket/ICachedUser.cs View File

@@ -1,9 +0,0 @@
namespace Discord
{
internal interface ICachedUser : IUser, ICachedEntity<ulong>
{
CachedGlobalUser User { get; }

ICachedUser Clone();
}
}

+ 19
- 0
src/Discord.Net/Entities/WebSocket/Messages/SocketMessage.cs View File

@@ -0,0 +1,19 @@
using Model = Discord.API.Message;

namespace Discord
{
internal class SocketMessage : Message
{
internal override bool IsAttached => true;

public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient;
public new ISocketMessageChannel Channel => base.Channel as ISocketMessageChannel;

public SocketMessage(ISocketMessageChannel channel, IUser author, Model model)
: base(channel, author, model)
{
}

public SocketMessage Clone() => MemberwiseClone() as SocketMessage;
}
}

+ 9
- 0
src/Discord.Net/Entities/WebSocket/Users/ISocketUser.cs View File

@@ -0,0 +1,9 @@
namespace Discord
{
internal interface ISocketUser : IUser, IEntity<ulong>
{
SocketGlobalUser User { get; }

ISocketUser Clone();
}
}

src/Discord.Net/Entities/WebSocket/Presence.cs → src/Discord.Net/Entities/WebSocket/Users/Presence.cs View File


src/Discord.Net/Entities/WebSocket/CachedDMUser.cs → src/Discord.Net/Entities/WebSocket/Users/SocketDMUser.cs View File

@@ -5,9 +5,12 @@ using PresenceModel = Discord.API.Presence;
namespace Discord namespace Discord
{ {
[DebuggerDisplay("{DebuggerDisplay,nq}")] [DebuggerDisplay("{DebuggerDisplay,nq}")]
internal class CachedDMUser : ICachedUser
internal class SocketDMUser : ISocketUser
{ {
public CachedGlobalUser User { get; }
internal bool IsAttached => true;
bool IEntity<ulong>.IsAttached => IsAttached;

public SocketGlobalUser User { get; }


public DiscordSocketClient Discord => User.Discord; public DiscordSocketClient Discord => User.Discord;


@@ -20,12 +23,11 @@ namespace Discord
public DateTimeOffset CreatedAt => User.CreatedAt; public DateTimeOffset CreatedAt => User.CreatedAt;
public string Discriminator => User.Discriminator; public string Discriminator => User.Discriminator;
public ushort DiscriminatorValue => User.DiscriminatorValue; public ushort DiscriminatorValue => User.DiscriminatorValue;
public bool IsAttached => User.IsAttached;
public bool IsBot => User.IsBot; public bool IsBot => User.IsBot;
public string Mention => MentionUtils.Mention(this); public string Mention => MentionUtils.Mention(this);
public string Username => User.Username; public string Username => User.Username;


public CachedDMUser(CachedGlobalUser user)
public SocketDMUser(SocketGlobalUser user)
{ {
User = user; User = user;
} }
@@ -35,8 +37,8 @@ namespace Discord
User.Update(model, source); User.Update(model, source);
} }


public CachedDMUser Clone() => MemberwiseClone() as CachedDMUser;
ICachedUser ICachedUser.Clone() => Clone();
public SocketDMUser Clone() => MemberwiseClone() as SocketDMUser;
ISocketUser ISocketUser.Clone() => Clone();


public override string ToString() => $"{Username}#{Discriminator}"; public override string ToString() => $"{Username}#{Discriminator}";
private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id})"; private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id})";

src/Discord.Net/Entities/WebSocket/CachedGlobalUser.cs → src/Discord.Net/Entities/WebSocket/Users/SocketGlobalUser.cs View File

@@ -4,16 +4,18 @@ using PresenceModel = Discord.API.Presence;


namespace Discord namespace Discord
{ {
internal class CachedGlobalUser : User, ICachedUser
internal class SocketGlobalUser : User, ISocketUser
{ {
internal override bool IsAttached => true;

private ushort _references; private ushort _references;


public Presence Presence { get; private set; } public Presence Presence { get; private set; }


public new DiscordSocketClient Discord { get { throw new NotSupportedException(); } } public new DiscordSocketClient Discord { get { throw new NotSupportedException(); } }
CachedGlobalUser ICachedUser.User => this;
SocketGlobalUser ISocketUser.User => this;


public CachedGlobalUser(Model model)
public SocketGlobalUser(Model model)
: base(model) : base(model)
{ {
} }
@@ -51,7 +53,7 @@ namespace Discord
//} //}
} }


public CachedGlobalUser Clone() => MemberwiseClone() as CachedGlobalUser;
ICachedUser ICachedUser.Clone() => Clone();
public SocketGlobalUser Clone() => MemberwiseClone() as SocketGlobalUser;
ISocketUser ISocketUser.Clone() => Clone();
} }
} }

src/Discord.Net/Entities/WebSocket/CachedGroupUser.cs → src/Discord.Net/Entities/WebSocket/Users/SocketGroupUser.cs View File

@@ -3,11 +3,13 @@
namespace Discord namespace Discord
{ {
[DebuggerDisplay("{DebuggerDisplay,nq}")] [DebuggerDisplay("{DebuggerDisplay,nq}")]
internal class CachedGroupUser : GroupUser, ICachedUser
internal class SocketGroupUser : GroupUser, ISocketUser
{ {
internal override bool IsAttached => true;

public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient; public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient;
public new CachedGroupChannel Channel => base.Channel as CachedGroupChannel;
public new CachedGlobalUser User => base.User as CachedGlobalUser;
public new SocketGroupChannel Channel => base.Channel as SocketGroupChannel;
public new SocketGlobalUser User => base.User as SocketGlobalUser;
public Presence Presence => User.Presence; //{ get; private set; } public Presence Presence => User.Presence; //{ get; private set; }


public override Game Game => Presence.Game; public override Game Game => Presence.Game;
@@ -17,15 +19,15 @@ namespace Discord
public bool IsSelfDeafened => VoiceState?.IsSelfDeafened ?? false; public bool IsSelfDeafened => VoiceState?.IsSelfDeafened ?? false;
public bool IsSelfMuted => VoiceState?.IsSelfMuted ?? false; public bool IsSelfMuted => VoiceState?.IsSelfMuted ?? false;
public bool IsSuppressed => VoiceState?.IsSuppressed ?? false; public bool IsSuppressed => VoiceState?.IsSuppressed ?? false;
public CachedVoiceChannel VoiceChannel => VoiceState?.VoiceChannel;
public SocketVoiceChannel VoiceChannel => VoiceState?.VoiceChannel;


public CachedGroupUser(CachedGroupChannel channel, CachedGlobalUser user)
public SocketGroupUser(SocketGroupChannel channel, SocketGlobalUser user)
: base(channel, user) : base(channel, user)
{ {
} }


public CachedGroupUser Clone() => MemberwiseClone() as CachedGroupUser;
ICachedUser ICachedUser.Clone() => Clone();
public SocketGroupUser Clone() => MemberwiseClone() as SocketGroupUser;
ISocketUser ISocketUser.Clone() => Clone();


public override string ToString() => $"{Username}#{Discriminator}"; public override string ToString() => $"{Username}#{Discriminator}";
private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id})"; private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id})";

src/Discord.Net/Entities/WebSocket/CachedGuildUser.cs → src/Discord.Net/Entities/WebSocket/Users/SocketGuildUser.cs View File

@@ -3,11 +3,13 @@ using PresenceModel = Discord.API.Presence;


namespace Discord namespace Discord
{ {
internal class CachedGuildUser : GuildUser, ICachedUser
internal class SocketGuildUser : GuildUser, ISocketUser
{ {
internal override bool IsAttached => true;

public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient; public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient;
public new CachedGuild Guild => base.Guild as CachedGuild;
public new CachedGlobalUser User => base.User as CachedGlobalUser;
public new SocketGuild Guild => base.Guild as SocketGuild;
public new SocketGlobalUser User => base.User as SocketGlobalUser;
public Presence Presence => User.Presence; //{ get; private set; } public Presence Presence => User.Presence; //{ get; private set; }


public override Game Game => Presence.Game; public override Game Game => Presence.Game;
@@ -17,14 +19,14 @@ namespace Discord
public bool IsSelfDeafened => VoiceState?.IsSelfDeafened ?? false; public bool IsSelfDeafened => VoiceState?.IsSelfDeafened ?? false;
public bool IsSelfMuted => VoiceState?.IsSelfMuted ?? false; public bool IsSelfMuted => VoiceState?.IsSelfMuted ?? false;
public bool IsSuppressed => VoiceState?.IsSuppressed ?? false; public bool IsSuppressed => VoiceState?.IsSuppressed ?? false;
public CachedVoiceChannel VoiceChannel => VoiceState?.VoiceChannel;
public SocketVoiceChannel VoiceChannel => VoiceState?.VoiceChannel;


public CachedGuildUser(CachedGuild guild, CachedGlobalUser user, Model model)
public SocketGuildUser(SocketGuild guild, SocketGlobalUser user, Model model)
: base(guild, user, model) : base(guild, user, model)
{ {
//Presence = new Presence(null, UserStatus.Offline); //Presence = new Presence(null, UserStatus.Offline);
} }
public CachedGuildUser(CachedGuild guild, CachedGlobalUser user, PresenceModel model)
public SocketGuildUser(SocketGuild guild, SocketGlobalUser user, PresenceModel model)
: base(guild, user, model) : base(guild, user, model)
{ {
} }
@@ -39,7 +41,7 @@ namespace Discord
User.Update(model, source); User.Update(model, source);
} }


public CachedGuildUser Clone() => MemberwiseClone() as CachedGuildUser;
ICachedUser ICachedUser.Clone() => Clone();
public SocketGuildUser Clone() => MemberwiseClone() as SocketGuildUser;
ISocketUser ISocketUser.Clone() => Clone();
} }
} }

+ 21
- 0
src/Discord.Net/Entities/WebSocket/Users/SocketSelfUser.cs View File

@@ -0,0 +1,21 @@
using System;
using Model = Discord.API.User;

namespace Discord
{
internal class SocketSelfUser : SelfUser, ISocketUser
{
internal override bool IsAttached => true;

public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient;
SocketGlobalUser ISocketUser.User { get { throw new NotSupportedException(); } }

public SocketSelfUser(DiscordSocketClient discord, Model model)
: base(discord, model)
{
}

public SocketSelfUser Clone() => MemberwiseClone() as SocketSelfUser;
ISocketUser ISocketUser.Clone() => Clone();
}
}

src/Discord.Net/Entities/WebSocket/VoiceState.cs → src/Discord.Net/Entities/WebSocket/Users/VoiceState.cs View File

@@ -19,7 +19,7 @@ namespace Discord


private readonly Flags _voiceStates; private readonly Flags _voiceStates;
public CachedVoiceChannel VoiceChannel { get; }
public SocketVoiceChannel VoiceChannel { get; }
public string VoiceSessionId { get; } public string VoiceSessionId { get; }


public bool IsMuted => (_voiceStates & Flags.Muted) != 0; public bool IsMuted => (_voiceStates & Flags.Muted) != 0;
@@ -28,9 +28,9 @@ namespace Discord
public bool IsSelfMuted => (_voiceStates & Flags.SelfMuted) != 0; public bool IsSelfMuted => (_voiceStates & Flags.SelfMuted) != 0;
public bool IsSelfDeafened => (_voiceStates & Flags.SelfDeafened) != 0; public bool IsSelfDeafened => (_voiceStates & Flags.SelfDeafened) != 0;


public VoiceState(CachedVoiceChannel voiceChannel, Model model)
public VoiceState(SocketVoiceChannel voiceChannel, Model model)
: this(voiceChannel, model.SessionId, model.SelfMute, model.SelfDeaf, model.Suppress) { } : this(voiceChannel, model.SessionId, model.SelfMute, model.SelfDeaf, model.Suppress) { }
public VoiceState(CachedVoiceChannel voiceChannel, string sessionId, bool isSelfMuted, bool isSelfDeafened, bool isSuppressed)
public VoiceState(SocketVoiceChannel voiceChannel, string sessionId, bool isSelfMuted, bool isSelfDeafened, bool isSuppressed)
{ {
VoiceChannel = voiceChannel; VoiceChannel = voiceChannel;
VoiceSessionId = sessionId; VoiceSessionId = sessionId;

+ 1
- 1
src/Discord.Net/Extensions/DiscordClientExtensions.cs View File

@@ -5,7 +5,7 @@ namespace Discord.Extensions
{ {
public static class DiscordClientExtensions public static class DiscordClientExtensions
{ {
public static async Task<IVoiceRegion> GetOptimalVoiceRegionAsync(this DiscordClient discord)
public static async Task<IVoiceRegion> GetOptimalVoiceRegionAsync(this DiscordRestClient discord)
{ {
var regions = await discord.GetVoiceRegionsAsync().ConfigureAwait(false); var regions = await discord.GetVoiceRegionsAsync().ConfigureAwait(false);
return regions.FirstOrDefault(x => x.IsOptimal); return regions.FirstOrDefault(x => x.IsOptimal);


+ 2
- 2
src/Discord.Net/Extensions/GuildUserExtensions.cs View File

@@ -9,11 +9,11 @@ namespace Discord.Extensions
public static Task AddRolesAsync(this IGuildUser user, params IRole[] roles) public static Task AddRolesAsync(this IGuildUser user, params IRole[] roles)
=> AddRolesAsync(user, (IEnumerable<IRole>)roles); => AddRolesAsync(user, (IEnumerable<IRole>)roles);
public static Task AddRolesAsync(this IGuildUser user, IEnumerable<IRole> roles) public static Task AddRolesAsync(this IGuildUser user, IEnumerable<IRole> roles)
=> user.ModifyAsync(x => x.Roles = Optional.Create(user.Roles.Concat(roles)));
=> user.ModifyAsync(x => x.Roles = user.Roles.Concat(roles));


public static Task RemoveRolesAsync(this IGuildUser user, params IRole[] roles) public static Task RemoveRolesAsync(this IGuildUser user, params IRole[] roles)
=> RemoveRolesAsync(user, (IEnumerable<IRole>)roles); => RemoveRolesAsync(user, (IEnumerable<IRole>)roles);
public static Task RemoveRolesAsync(this IGuildUser user, IEnumerable<IRole> roles) public static Task RemoveRolesAsync(this IGuildUser user, IEnumerable<IRole> roles)
=> user.ModifyAsync(x => x.Roles = Optional.Create(user.Roles.Except(roles)));
=> user.ModifyAsync(x => x.Roles = user.Roles.Except(roles));
} }
} }

+ 0
- 4
src/Discord.Net/IDiscordClient.cs View File

@@ -11,14 +11,10 @@ namespace Discord
//TODO: Docstrings should explain when REST requests are sent and how many //TODO: Docstrings should explain when REST requests are sent and how many
public interface IDiscordClient : IDisposable public interface IDiscordClient : IDisposable
{ {
LoginState LoginState { get; }
ConnectionState ConnectionState { get; } ConnectionState ConnectionState { get; }


DiscordApiClient ApiClient { get; } DiscordApiClient ApiClient { get; }
ILogManager LogManager { get; } ILogManager LogManager { get; }
Task LoginAsync(TokenType tokenType, string token, bool validateToken = true);
Task LogoutAsync();


Task ConnectAsync(); Task ConnectAsync();
Task DisconnectAsync(); Task DisconnectAsync();


Loading…
Cancel
Save