diff --git a/src/Discord.Net.Commands/CommandService.cs b/src/Discord.Net.Commands/CommandService.cs index 46c5aaa39..cd09c47b6 100644 --- a/src/Discord.Net.Commands/CommandService.cs +++ b/src/Discord.Net.Commands/CommandService.cs @@ -2,7 +2,6 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; -using System.Globalization; using System.Linq; using System.Reflection; using System.Threading; @@ -27,94 +26,56 @@ namespace Discord.Commands _map = new CommandMap(); _typeReaders = new ConcurrentDictionary { - [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(), + [typeof(byte)] = new SimpleTypeReader(), + [typeof(sbyte)] = new SimpleTypeReader(), + [typeof(ushort)] = new SimpleTypeReader(), + [typeof(short)] = new SimpleTypeReader(), + [typeof(uint)] = new SimpleTypeReader(), + [typeof(int)] = new SimpleTypeReader(), + [typeof(ulong)] = new SimpleTypeReader(), + [typeof(long)] = new SimpleTypeReader(), + [typeof(float)] = new SimpleTypeReader(), + [typeof(double)] = new SimpleTypeReader(), + [typeof(decimal)] = new SimpleTypeReader(), + [typeof(DateTime)] = new SimpleTypeReader(), + [typeof(DateTimeOffset)] = new SimpleTypeReader(), + + //TODO: Do we want to support any other interfaces? + + //[typeof(IMentionable)] = new GeneralTypeReader(), + //[typeof(ISnowflakeEntity)] = new GeneralTypeReader(), + //[typeof(IEntity)] = new GeneralTypeReader(), [typeof(IMessage)] = new MessageTypeReader(), + //[typeof(IAttachment)] = new xxx(), + //[typeof(IEmbed)] = new xxx(), + [typeof(IChannel)] = new ChannelTypeReader(), + [typeof(IDMChannel)] = new ChannelTypeReader(), + [typeof(IGroupChannel)] = new ChannelTypeReader(), [typeof(IGuildChannel)] = new ChannelTypeReader(), + [typeof(IMessageChannel)] = new ChannelTypeReader(), + [typeof(IPrivateChannel)] = new ChannelTypeReader(), [typeof(ITextChannel)] = new ChannelTypeReader(), [typeof(IVoiceChannel)] = new ChannelTypeReader(), + + //[typeof(IGuild)] = new GuildTypeReader(), + //[typeof(IUserGuild)] = new GuildTypeReader(), + //[typeof(IGuildIntegration)] = new xxx(), + [typeof(IRole)] = new RoleTypeReader(), + + //[typeof(IInvite)] = new InviteTypeReader(), + //[typeof(IInviteMetadata)] = new InviteTypeReader(), + [typeof(IUser)] = new UserTypeReader(), - [typeof(IGuildUser)] = new UserTypeReader() + [typeof(IGroupUser)] = new UserTypeReader(), + [typeof(IGuildUser)] = new UserTypeReader(), + //[typeof(ISelfUser)] = new UserTypeReader(), + //[typeof(IPresence)] = new UserTypeReader(), + //[typeof(IVoiceState)] = new UserTypeReader(), + //[typeof(IConnection)] = new xxx(), }; } diff --git a/src/Discord.Net.Commands/Map/CommandMap.cs b/src/Discord.Net.Commands/Map/CommandMap.cs index 0f719d56d..5cf667903 100644 --- a/src/Discord.Net.Commands/Map/CommandMap.cs +++ b/src/Discord.Net.Commands/Map/CommandMap.cs @@ -1,6 +1,5 @@ using System.Collections.Concurrent; using System.Collections.Generic; -using System.Collections.Immutable; using System.Linq; namespace Discord.Commands diff --git a/src/Discord.Net.Commands/PrimitiveParsers.cs b/src/Discord.Net.Commands/PrimitiveParsers.cs new file mode 100644 index 000000000..ac705764e --- /dev/null +++ b/src/Discord.Net.Commands/PrimitiveParsers.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; + +namespace Discord.Commands +{ + internal delegate bool TryParseDelegate(string str, out T value); + + internal static class PrimitiveParsers + { + private static readonly IReadOnlyDictionary _parsers; + + static PrimitiveParsers() + { + var parserBuilder = ImmutableDictionary.CreateBuilder(); + parserBuilder[typeof(string)] = (TryParseDelegate)delegate(string str, out string value) { value = str; return true; }; + parserBuilder[typeof(sbyte)] = (TryParseDelegate)sbyte.TryParse; + parserBuilder[typeof(byte)] = (TryParseDelegate)byte.TryParse; + parserBuilder[typeof(short)] = (TryParseDelegate)short.TryParse; + parserBuilder[typeof(ushort)] = (TryParseDelegate)ushort.TryParse; + parserBuilder[typeof(int)] = (TryParseDelegate)int.TryParse; + parserBuilder[typeof(uint)] = (TryParseDelegate)uint.TryParse; + parserBuilder[typeof(long)] = (TryParseDelegate)long.TryParse; + parserBuilder[typeof(ulong)] = (TryParseDelegate)ulong.TryParse; + parserBuilder[typeof(float)] = (TryParseDelegate)float.TryParse; + parserBuilder[typeof(double)] = (TryParseDelegate)double.TryParse; + parserBuilder[typeof(decimal)] = (TryParseDelegate)decimal.TryParse; + parserBuilder[typeof(DateTime)] = (TryParseDelegate)DateTime.TryParse; + parserBuilder[typeof(DateTimeOffset)] = (TryParseDelegate)DateTimeOffset.TryParse; + _parsers = parserBuilder.ToImmutable(); + } + + public static TryParseDelegate Get() => (TryParseDelegate)_parsers[typeof(T)]; + public static Delegate Get(Type type) => _parsers[type]; + } +} diff --git a/src/Discord.Net.Commands/Readers/EnumTypeReader.cs b/src/Discord.Net.Commands/Readers/EnumTypeReader.cs index ca2b2159c..8e5313118 100644 --- a/src/Discord.Net.Commands/Readers/EnumTypeReader.cs +++ b/src/Discord.Net.Commands/Readers/EnumTypeReader.cs @@ -7,31 +7,13 @@ using System.Threading.Tasks; namespace Discord.Commands { - delegate bool TryParseDelegate(string str, out T value); - internal static class EnumTypeReader - { - private static readonly IReadOnlyDictionary _parsers; - - static EnumTypeReader() - { - var parserBuilder = ImmutableDictionary.CreateBuilder(); - parserBuilder[typeof(sbyte)] = (TryParseDelegate)sbyte.TryParse; - parserBuilder[typeof(byte)] = (TryParseDelegate)byte.TryParse; - parserBuilder[typeof(short)] = (TryParseDelegate)short.TryParse; - parserBuilder[typeof(ushort)] = (TryParseDelegate)ushort.TryParse; - parserBuilder[typeof(int)] = (TryParseDelegate)int.TryParse; - parserBuilder[typeof(uint)] = (TryParseDelegate)uint.TryParse; - parserBuilder[typeof(long)] = (TryParseDelegate)long.TryParse; - parserBuilder[typeof(ulong)] = (TryParseDelegate)ulong.TryParse; - _parsers = parserBuilder.ToImmutable(); - } - + { public static TypeReader GetReader(Type type) { Type baseType = Enum.GetUnderlyingType(type); 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) }); } } diff --git a/src/Discord.Net.Commands/Readers/GenericTypeReader.cs b/src/Discord.Net.Commands/Readers/GenericTypeReader.cs deleted file mode 100644 index 97bc7d94c..000000000 --- a/src/Discord.Net.Commands/Readers/GenericTypeReader.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Threading.Tasks; - -namespace Discord.Commands -{ - internal class GenericTypeReader : TypeReader - { - private readonly Func> _action; - - public GenericTypeReader(Func> action) - { - _action = action; - } - - public override Task Read(IMessage context, string input) => _action(context, input); - } -} diff --git a/src/Discord.Net.Commands/Readers/SimpleTypeReader.cs b/src/Discord.Net.Commands/Readers/SimpleTypeReader.cs new file mode 100644 index 000000000..a3822084b --- /dev/null +++ b/src/Discord.Net.Commands/Readers/SimpleTypeReader.cs @@ -0,0 +1,23 @@ +using System.Threading.Tasks; + +namespace Discord.Commands +{ + internal class SimpleTypeReader : TypeReader + { + private readonly TryParseDelegate _tryParse; + + public SimpleTypeReader() + { + _tryParse = PrimitiveParsers.Get(); + } + + public override Task 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}")); + } + } +} diff --git a/src/Discord.Net.Commands/ReflectionUtils.cs b/src/Discord.Net.Commands/ReflectionUtils.cs index 7245965e9..4de883731 100644 --- a/src/Discord.Net.Commands/ReflectionUtils.cs +++ b/src/Discord.Net.Commands/ReflectionUtils.cs @@ -8,7 +8,7 @@ namespace Discord.Commands { 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) throw new InvalidOperationException($"No constructor found for \"{typeInfo.FullName}\""); else if (constructors.Length > 1) diff --git a/src/Discord.Net/API/CDN.cs b/src/Discord.Net/API/CDN.cs index 3973344db..19c6e5b3c 100644 --- a/src/Discord.Net/API/CDN.cs +++ b/src/Discord.Net/API/CDN.cs @@ -3,14 +3,14 @@ internal static class CDN { 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) - => 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) - => 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) - => 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) - => iconId != null ? $"{DiscordConfig.CDNUrl}channel-icons/{channelId}/{iconId}.jpg" : null; + => iconId != null ? $"{DiscordRestConfig.CDNUrl}channel-icons/{channelId}/{iconId}.jpg" : null; } } diff --git a/src/Discord.Net/API/DiscordAPIClient.cs b/src/Discord.Net/API/DiscordAPIClient.cs index ff8e30782..81ca94d89 100644 --- a/src/Discord.Net/API/DiscordAPIClient.cs +++ b/src/Discord.Net/API/DiscordAPIClient.cs @@ -55,9 +55,9 @@ namespace Discord.API _requestQueue = requestQueue ?? new RequestQueue(); - _restClient = restClientProvider(DiscordConfig.ClientAPIUrl); + _restClient = restClientProvider(DiscordRestConfig.ClientAPIUrl); _restClient.SetHeader("accept", "*/*"); - _restClient.SetHeader("user-agent", DiscordConfig.UserAgent); + _restClient.SetHeader("user-agent", DiscordRestConfig.UserAgent); if (webSocketProvider != null) { _gatewayClient = webSocketProvider(); @@ -211,7 +211,7 @@ namespace Discord.API if (_gatewayUrl == null) { 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); @@ -461,8 +461,8 @@ namespace Discord.API { Preconditions.NotEqual(guildId, 0, nameof(guildId)); 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("POST", $"guilds/{guildId}/channels", args, options: options).ConfigureAwait(false); } @@ -476,8 +476,8 @@ namespace Discord.API { Preconditions.NotEqual(channelId, 0, nameof(channelId)); 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("PATCH", $"channels/{channelId}", args, options: options).ConfigureAwait(false); } @@ -485,8 +485,8 @@ namespace Discord.API { Preconditions.NotEqual(channelId, 0, nameof(channelId)); 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("PATCH", $"channels/{channelId}", args, options: options).ConfigureAwait(false); } @@ -494,10 +494,10 @@ namespace Discord.API { Preconditions.NotEqual(channelId, 0, nameof(channelId)); 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("PATCH", $"channels/{channelId}", args, options: options).ConfigureAwait(false); } @@ -606,11 +606,11 @@ namespace Discord.API { Preconditions.NotEqual(guildId, 0, nameof(guildId)); 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("PATCH", $"guilds/{guildId}", args, options: options).ConfigureAwait(false); } @@ -643,7 +643,7 @@ namespace Discord.API Preconditions.NotEqual(guildId, 0, nameof(guildId)); Preconditions.NotEqual(userId, 0, nameof(userId)); 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); } @@ -701,8 +701,8 @@ namespace Discord.API Preconditions.NotEqual(guildId, 0, nameof(guildId)); Preconditions.NotEqual(integrationId, 0, nameof(integrationId)); 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("PATCH", $"guilds/{guildId}/integrations/{integrationId}", args, options: options).ConfigureAwait(false); } @@ -749,8 +749,8 @@ namespace Discord.API { Preconditions.NotEqual(channelId, 0, nameof(channelId)); 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("POST", $"channels/{channelId}/invites", args, options: options).ConfigureAwait(false); } @@ -783,21 +783,21 @@ namespace Discord.API { Preconditions.NotEqual(guildId, 0, nameof(guildId)); 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 result; - if (args.Limit.IsSpecified) - result = new List((limit + DiscordConfig.MaxUsersPerBatch - 1) / DiscordConfig.MaxUsersPerBatch); + if (args._limit.IsSpecified) + result = new List((limit + DiscordRestConfig.MaxUsersPerBatch - 1) / DiscordRestConfig.MaxUsersPerBatch); else result = new List(); 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}"; var models = await SendAsync("GET", endpoint, options: options).ConfigureAwait(false); @@ -806,11 +806,11 @@ namespace Discord.API result.Add(models); - limit -= DiscordConfig.MaxUsersPerBatch; + limit -= DiscordRestConfig.MaxUsersPerBatch; afterUserId = models[models.Length - 1].User.Id; //Was this an incomplete (the last) batch? - if (models.Length != DiscordConfig.MaxUsersPerBatch) break; + if (models.Length != DiscordRestConfig.MaxUsersPerBatch) break; } if (result.Count > 1) @@ -861,9 +861,9 @@ namespace Discord.API Preconditions.NotEqual(guildId, 0, nameof(guildId)); Preconditions.NotEqual(roleId, 0, nameof(roleId)); 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("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)); 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; switch (args.RelativeDirection) @@ -920,14 +920,14 @@ namespace Discord.API 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][]; int i = 0; for (; i < runs; i++) { - int runCount = i == (runs - 1) ? lastRunCount : DiscordConfig.MaxMessagesPerBatch; + int runCount = i == (runs - 1) ? lastRunCount : DiscordRestConfig.MaxMessagesPerBatch; string endpoint; if (relativeId != null) endpoint = $"channels/{channelId}/messages?limit={runCount}&{relativeDir}={relativeId}"; @@ -966,7 +966,7 @@ namespace Discord.API } //Was this an incomplete (the last) batch? - if (models.Length != DiscordConfig.MaxMessagesPerBatch) { i++; break; } + if (models.Length != DiscordRestConfig.MaxMessagesPerBatch) { i++; break; } } if (i > 1) @@ -1010,9 +1010,9 @@ namespace Discord.API { Preconditions.NotEqual(channelId, 0, nameof(channelId)); 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) return await SendAsync("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.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) @@ -1084,8 +1084,8 @@ namespace Discord.API Preconditions.NotEqual(channelId, 0, nameof(channelId)); 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)); switch (messageIds.Length) @@ -1118,11 +1118,11 @@ namespace Discord.API Preconditions.NotEqual(channelId, 0, nameof(channelId)); Preconditions.NotEqual(messageId, 0, nameof(messageId)); 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) @@ -1195,7 +1195,7 @@ namespace Discord.API public async Task ModifySelfAsync(ModifyCurrentUserParams args, RequestOptions options = null) { Preconditions.NotNull(args, nameof(args)); - Preconditions.NotNullOrEmpty(args.Username, nameof(args.Username)); + Preconditions.NotNullOrEmpty(args._username, nameof(args.Username)); return await SendAsync("PATCH", "users/@me", args, options: options).ConfigureAwait(false); } @@ -1209,7 +1209,7 @@ namespace Discord.API public async Task CreateDMChannelAsync(CreateDMChannelParams args, RequestOptions options = null) { Preconditions.NotNull(args, nameof(args)); - Preconditions.GreaterThan(args.RecipientId, 0, nameof(args.Recipient)); + Preconditions.GreaterThan(args._recipientId, 0, nameof(args.Recipient)); return await SendAsync("POST", $"users/@me/channels", args, options: options).ConfigureAwait(false); } diff --git a/src/Discord.Net/API/Gateway/IdentifyParams.cs b/src/Discord.Net/API/Gateway/IdentifyParams.cs index 8338e6e14..0a056e225 100644 --- a/src/Discord.Net/API/Gateway/IdentifyParams.cs +++ b/src/Discord.Net/API/Gateway/IdentifyParams.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; namespace Discord.API.Gateway { + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public class IdentifyParams { [JsonProperty("token")] diff --git a/src/Discord.Net/API/Gateway/RequestMembersParams.cs b/src/Discord.Net/API/Gateway/RequestMembersParams.cs index a0819c556..81e83f5c1 100644 --- a/src/Discord.Net/API/Gateway/RequestMembersParams.cs +++ b/src/Discord.Net/API/Gateway/RequestMembersParams.cs @@ -4,6 +4,7 @@ using System.Linq; namespace Discord.API.Gateway { + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public class RequestMembersParams { [JsonProperty("query")] @@ -12,8 +13,8 @@ namespace Discord.API.Gateway public int Limit { get; set; } [JsonProperty("guild_id")] - public IEnumerable GuildIds { get; set; } - [JsonIgnore] - public IEnumerable Guilds { set { GuildIds = value.Select(x => x.Id); } } + private ulong[] _guildIds; + public IEnumerable GuildIds { set { _guildIds = value.ToArray(); } } + public IEnumerable Guilds { set { _guildIds = value.Select(x => x.Id).ToArray(); } } } } diff --git a/src/Discord.Net/API/Gateway/ResumeParams.cs b/src/Discord.Net/API/Gateway/ResumeParams.cs index bf9dfbac1..898ac8edb 100644 --- a/src/Discord.Net/API/Gateway/ResumeParams.cs +++ b/src/Discord.Net/API/Gateway/ResumeParams.cs @@ -2,6 +2,7 @@ namespace Discord.API.Gateway { + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public class ResumeParams { [JsonProperty("token")] diff --git a/src/Discord.Net/API/Gateway/StatusUpdateParams.cs b/src/Discord.Net/API/Gateway/StatusUpdateParams.cs index 29a525674..b1dca0f98 100644 --- a/src/Discord.Net/API/Gateway/StatusUpdateParams.cs +++ b/src/Discord.Net/API/Gateway/StatusUpdateParams.cs @@ -2,6 +2,7 @@ namespace Discord.API.Gateway { + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public class StatusUpdateParams { [JsonProperty("idle_since"), Int53] diff --git a/src/Discord.Net/API/Gateway/UpdateStatusParams.cs b/src/Discord.Net/API/Gateway/UpdateStatusParams.cs index 99e5ed7b8..10f95de2b 100644 --- a/src/Discord.Net/API/Gateway/UpdateStatusParams.cs +++ b/src/Discord.Net/API/Gateway/UpdateStatusParams.cs @@ -2,6 +2,7 @@ namespace Discord.API.Gateway { + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public class UpdateStatusParams { [JsonProperty("idle_since")] diff --git a/src/Discord.Net/API/Gateway/VoiceStateUpdateParams.cs b/src/Discord.Net/API/Gateway/VoiceStateUpdateParams.cs index 6eb285cea..36fe46c6f 100644 --- a/src/Discord.Net/API/Gateway/VoiceStateUpdateParams.cs +++ b/src/Discord.Net/API/Gateway/VoiceStateUpdateParams.cs @@ -2,6 +2,7 @@ namespace Discord.API.Gateway { + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public class VoiceStateUpdateParams { [JsonProperty("self_mute")] @@ -10,12 +11,11 @@ namespace Discord.API.Gateway public bool SelfDeaf { get; set; } [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")] public ulong? ChannelId { get; set; } - [JsonIgnore] public IChannel Channel { set { ChannelId = value?.Id; } } } } diff --git a/src/Discord.Net/API/Rest/ApplicationInfo.cs b/src/Discord.Net/API/Rest/ApplicationInfo.cs deleted file mode 100644 index ce9f833af..000000000 --- a/src/Discord.Net/API/Rest/ApplicationInfo.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Discord.API.Rest -{ - public class ApplicationInfo - { - } -} diff --git a/src/Discord.Net/API/Rest/CreateChannelInviteParams.cs b/src/Discord.Net/API/Rest/CreateChannelInviteParams.cs index e579a98d8..c8e4490d8 100644 --- a/src/Discord.Net/API/Rest/CreateChannelInviteParams.cs +++ b/src/Discord.Net/API/Rest/CreateChannelInviteParams.cs @@ -2,15 +2,23 @@ namespace Discord.API.Rest { + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public class CreateChannelInviteParams { [JsonProperty("max_age")] - public Optional MaxAge { get; set; } + internal Optional _maxAge { get; set; } + public int MaxAge { set { _maxAge = value; } } + [JsonProperty("max_uses")] - public Optional MaxUses { get; set; } + internal Optional _maxUses { get; set; } + public int MaxUses { set { _maxUses = value; } } + [JsonProperty("temporary")] - public Optional Temporary { get; set; } + internal Optional _temporary { get; set; } + public bool Temporary { set { _temporary = value; } } + [JsonProperty("xkcdpass")] - public Optional XkcdPass { get; set; } + internal Optional _xkcdPass { get; set; } + public bool XkcdPass { set { _xkcdPass = value; } } } } diff --git a/src/Discord.Net/API/Rest/CreateDMChannelParams.cs b/src/Discord.Net/API/Rest/CreateDMChannelParams.cs index 779fd5dc9..b28ff2342 100644 --- a/src/Discord.Net/API/Rest/CreateDMChannelParams.cs +++ b/src/Discord.Net/API/Rest/CreateDMChannelParams.cs @@ -2,11 +2,12 @@ namespace Discord.API.Rest { + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public class CreateDMChannelParams { [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; } } } } diff --git a/src/Discord.Net/API/Rest/CreateGuildBanParams.cs b/src/Discord.Net/API/Rest/CreateGuildBanParams.cs index 16e2c9846..ba20ca96c 100644 --- a/src/Discord.Net/API/Rest/CreateGuildBanParams.cs +++ b/src/Discord.Net/API/Rest/CreateGuildBanParams.cs @@ -2,9 +2,11 @@ namespace Discord.API.Rest { + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public class CreateGuildBanParams { [JsonProperty("delete-message-days")] - public Optional PruneDays { get; set; } + internal Optional _deleteMessageDays { get; set; } + public int DeleteMessageDays { set { _deleteMessageDays = value; } } } } diff --git a/src/Discord.Net/API/Rest/CreateGuildChannelParams.cs b/src/Discord.Net/API/Rest/CreateGuildChannelParams.cs index 11a1487ec..28cbfea67 100644 --- a/src/Discord.Net/API/Rest/CreateGuildChannelParams.cs +++ b/src/Discord.Net/API/Rest/CreateGuildChannelParams.cs @@ -2,14 +2,19 @@ namespace Discord.API.Rest { + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public class CreateGuildChannelParams { [JsonProperty("name")] - public string Name { get; set; } + internal string _name { get; set; } + public string Name { set { _name = value; } } + [JsonProperty("type")] - public ChannelType Type { get; set; } + internal ChannelType _type { get; set; } + public ChannelType Type { set { _type = value; } } [JsonProperty("bitrate")] - public Optional Bitrate { get; set; } + internal Optional _bitrate { get; set; } + public int Bitrate { set { _bitrate = value; } } } } diff --git a/src/Discord.Net/API/Rest/CreateGuildIntegrationParams.cs b/src/Discord.Net/API/Rest/CreateGuildIntegrationParams.cs index 8107548ac..913f65269 100644 --- a/src/Discord.Net/API/Rest/CreateGuildIntegrationParams.cs +++ b/src/Discord.Net/API/Rest/CreateGuildIntegrationParams.cs @@ -2,11 +2,13 @@ namespace Discord.API.Rest { + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public class CreateGuildIntegrationParams { [JsonProperty("id")] - public ulong Id { get; set; } + public ulong Id { internal get; set; } + [JsonProperty("type")] - public string Type { get; set; } + public string Type { internal get; set; } } } diff --git a/src/Discord.Net/API/Rest/CreateGuildParams.cs b/src/Discord.Net/API/Rest/CreateGuildParams.cs index 75892a0e2..ad38d5bfa 100644 --- a/src/Discord.Net/API/Rest/CreateGuildParams.cs +++ b/src/Discord.Net/API/Rest/CreateGuildParams.cs @@ -3,20 +3,17 @@ using System.IO; namespace Discord.API.Rest { + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public class CreateGuildParams { [JsonProperty("name")] - public string Name { get; set; } + public string Name { internal get; set; } + [JsonProperty("region")] - public string Region { get; set; } + public string Region { internal get; set; } [JsonProperty("icon")] - private Optional _icon { get; set; } - [JsonIgnore] - public Optional Icon - { - get { return _icon.IsSpecified ? _icon.Value.Stream : null; } - set { _icon = value.IsSpecified ? new Image(value.Value) : Optional.Create(); } - } + internal Optional _icon { get; set; } + public Stream Icon { set { _icon = value != null ? new Image(value) : (Image?)null; } } } } diff --git a/src/Discord.Net/API/Rest/CreateMessageParams.cs b/src/Discord.Net/API/Rest/CreateMessageParams.cs index 457bbe841..59b56dda1 100644 --- a/src/Discord.Net/API/Rest/CreateMessageParams.cs +++ b/src/Discord.Net/API/Rest/CreateMessageParams.cs @@ -2,14 +2,19 @@ namespace Discord.API.Rest { + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public class CreateMessageParams { [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 Nonce { get; set; } - [JsonProperty("tts", DefaultValueHandling = DefaultValueHandling.Ignore)] - public Optional IsTTS { get; set; } + [JsonProperty("nonce")] + internal Optional _nonce { get; set; } + public string Nonce { set { _nonce = value; } } + + [JsonProperty("tts")] + internal Optional _tts { get; set; } + public bool IsTTS { set { _tts = value; } } } } diff --git a/src/Discord.Net/API/Rest/DeleteMessagesParams.cs b/src/Discord.Net/API/Rest/DeleteMessagesParams.cs index 1ea2fca2a..10b8112f1 100644 --- a/src/Discord.Net/API/Rest/DeleteMessagesParams.cs +++ b/src/Discord.Net/API/Rest/DeleteMessagesParams.cs @@ -4,11 +4,12 @@ using System.Linq; namespace Discord.API.Rest { + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public class DeleteMessagesParams { [JsonProperty("messages")] - public IEnumerable MessageIds { get; set; } - [JsonIgnore] - public IEnumerable Messages { set { MessageIds = value.Select(x => x.Id); } } + internal ulong[] _messages { get; set; } + public IEnumerable MessageIds { set { _messages = value.ToArray(); } } + public IEnumerable Messages { set { _messages = value.Select(x => x.Id).ToArray(); } } } } diff --git a/src/Discord.Net/API/Rest/GetChannelMessagesParams.cs b/src/Discord.Net/API/Rest/GetChannelMessagesParams.cs index 18107807e..8843c9e73 100644 --- a/src/Discord.Net/API/Rest/GetChannelMessagesParams.cs +++ b/src/Discord.Net/API/Rest/GetChannelMessagesParams.cs @@ -2,10 +2,12 @@ { 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 RelativeMessageId { get; set; } - public Optional RelativeMessage { set { RelativeMessageId = value.IsSpecified ? value.Value.Id : Optional.Create(); } } + public Direction RelativeDirection { internal get; set; } = Direction.Before; + + internal Optional _relativeMessageId { get; set; } + public ulong RelativeMessageId { set { _relativeMessageId = value; } } + public IMessage RelativeMessage { set { _relativeMessageId = value.Id; } } } } diff --git a/src/Discord.Net/API/Rest/GetGuildMembersParams.cs b/src/Discord.Net/API/Rest/GetGuildMembersParams.cs index 3df756d29..d8e952911 100644 --- a/src/Discord.Net/API/Rest/GetGuildMembersParams.cs +++ b/src/Discord.Net/API/Rest/GetGuildMembersParams.cs @@ -2,7 +2,10 @@ { public class GetGuildMembersParams { - public Optional Limit { get; set; } - public Optional AfterUserId { get; set; } + internal Optional _limit { get; set; } + public int Limit { set { _limit = value; } } + + internal Optional _afterUserId { get; set; } + public ulong AfterUserId { set { _afterUserId = value; } } } } diff --git a/src/Discord.Net/API/Rest/GuildPruneParams.cs b/src/Discord.Net/API/Rest/GuildPruneParams.cs index 12a7a11da..373955185 100644 --- a/src/Discord.Net/API/Rest/GuildPruneParams.cs +++ b/src/Discord.Net/API/Rest/GuildPruneParams.cs @@ -2,9 +2,10 @@ namespace Discord.API.Rest { + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public class GuildPruneParams { [JsonProperty("days")] - public int Days = 30; + public int Days { internal get; set; } } } diff --git a/src/Discord.Net/API/Rest/ModifyChannelPermissionsParams.cs b/src/Discord.Net/API/Rest/ModifyChannelPermissionsParams.cs index 31a41086a..fd34e0230 100644 --- a/src/Discord.Net/API/Rest/ModifyChannelPermissionsParams.cs +++ b/src/Discord.Net/API/Rest/ModifyChannelPermissionsParams.cs @@ -2,11 +2,13 @@ namespace Discord.API.Rest { + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public class ModifyChannelPermissionsParams { [JsonProperty("allow")] - public Optional Allow { get; set; } + public ulong Allow { internal get; set; } + [JsonProperty("deny")] - public Optional Deny { get; set; } + public ulong Deny { internal get; set; } } } diff --git a/src/Discord.Net/API/Rest/ModifyCurrentUserNickParams.cs b/src/Discord.Net/API/Rest/ModifyCurrentUserNickParams.cs index 38cd54991..71c417469 100644 --- a/src/Discord.Net/API/Rest/ModifyCurrentUserNickParams.cs +++ b/src/Discord.Net/API/Rest/ModifyCurrentUserNickParams.cs @@ -2,9 +2,10 @@ namespace Discord.API.Rest { + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public class ModifyCurrentUserNickParams { [JsonProperty("nick")] - public string Nickname { get; set; } + public string Nickname { internal get; set; } } } diff --git a/src/Discord.Net/API/Rest/ModifyCurrentUserParams.cs b/src/Discord.Net/API/Rest/ModifyCurrentUserParams.cs index 03fe3550c..fb5dca64d 100644 --- a/src/Discord.Net/API/Rest/ModifyCurrentUserParams.cs +++ b/src/Discord.Net/API/Rest/ModifyCurrentUserParams.cs @@ -3,24 +3,15 @@ using System.IO; namespace Discord.API.Rest { + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public class ModifyCurrentUserParams { [JsonProperty("username")] - public Optional Username { get; set; } + internal Optional _username { get; set; } + public string Username { set { _username = value; } } [JsonProperty("avatar")] - private Optional _avatar { get; set; } - [JsonIgnore] - public Optional Avatar - { - get { return _avatar.IsSpecified ? _avatar.Value.Stream : null; } - set { _avatar = value.IsSpecified ? new Image(value.Value) : Optional.Create(); } - } - [JsonIgnore] - internal Optional AvatarHash - { - get { return _avatar.IsSpecified ? _avatar.Value.Hash : null; } - set { _avatar = value.IsSpecified ? new Image(value.Value) : Optional.Create(); } - } + internal Optional _avatar { get; set; } + public Stream Avatar { set { _avatar = new Image(value); } } } } diff --git a/src/Discord.Net/API/Rest/ModifyGuildChannelParams.cs b/src/Discord.Net/API/Rest/ModifyGuildChannelParams.cs index 374f87377..79b6ecf73 100644 --- a/src/Discord.Net/API/Rest/ModifyGuildChannelParams.cs +++ b/src/Discord.Net/API/Rest/ModifyGuildChannelParams.cs @@ -2,11 +2,15 @@ namespace Discord.API.Rest { + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public class ModifyGuildChannelParams { [JsonProperty("name")] - public Optional Name { get; set; } + internal Optional _name { get; set; } + public string Name { set { _name = value; } } + [JsonProperty("position")] - public Optional Position { get; set; } + internal Optional _position { get; set; } + public int Position { set { _position = value; } } } } diff --git a/src/Discord.Net/API/Rest/ModifyGuildChannelsParams.cs b/src/Discord.Net/API/Rest/ModifyGuildChannelsParams.cs index 23d498f25..835c6bc7e 100644 --- a/src/Discord.Net/API/Rest/ModifyGuildChannelsParams.cs +++ b/src/Discord.Net/API/Rest/ModifyGuildChannelsParams.cs @@ -2,11 +2,13 @@ namespace Discord.API.Rest { + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public class ModifyGuildChannelsParams { [JsonProperty("id")] - public ulong Id { get; set; } + public ulong Id { internal get; set; } + [JsonProperty("position")] - public Optional Position { get; set; } + public int Position { internal get; set; } } } diff --git a/src/Discord.Net/API/Rest/ModifyGuildEmbedParams.cs b/src/Discord.Net/API/Rest/ModifyGuildEmbedParams.cs index f8e8de1f1..0174e9313 100644 --- a/src/Discord.Net/API/Rest/ModifyGuildEmbedParams.cs +++ b/src/Discord.Net/API/Rest/ModifyGuildEmbedParams.cs @@ -2,14 +2,16 @@ namespace Discord.API.Rest { + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public class ModifyGuildEmbedParams { [JsonProperty("enabled")] - public Optional Enabled { get; set; } + internal Optional _enabled { get; set; } + public bool Enabled { set { _enabled = value; } } [JsonProperty("channel")] - public Optional ChannelId { get; set; } - [JsonIgnore] - public Optional Channel { set { ChannelId = value.IsSpecified ? value.Value.Id : Optional.Create(); } } + internal Optional _channelId { get; set; } + public ulong? ChannelId { set { _channelId = value; } } + public IVoiceChannel Channel { set { _channelId = value != null ? value.Id : (ulong?)null; } } } } diff --git a/src/Discord.Net/API/Rest/ModifyGuildIntegrationParams.cs b/src/Discord.Net/API/Rest/ModifyGuildIntegrationParams.cs index c58971c73..8602a013f 100644 --- a/src/Discord.Net/API/Rest/ModifyGuildIntegrationParams.cs +++ b/src/Discord.Net/API/Rest/ModifyGuildIntegrationParams.cs @@ -2,13 +2,19 @@ namespace Discord.API.Rest { + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public class ModifyGuildIntegrationParams { [JsonProperty("expire_behavior")] - public Optional ExpireBehavior { get; set; } + internal Optional _expireBehavior { get; set; } + public int ExpireBehavior { set { _expireBehavior = value; } } + [JsonProperty("expire_grace_period")] - public Optional ExpireGracePeriod { get; set; } + internal Optional _expireGracePeriod { get; set; } + public int ExpireGracePeriod { set { _expireGracePeriod = value; } } + [JsonProperty("enable_emoticons")] - public Optional EnableEmoticons { get; set; } + internal Optional _enableEmoticons { get; set; } + public bool EnableEmoticons { set { _enableEmoticons = value; } } } } diff --git a/src/Discord.Net/API/Rest/ModifyGuildMemberParams.cs b/src/Discord.Net/API/Rest/ModifyGuildMemberParams.cs index 8a4077e90..03b5ce28e 100644 --- a/src/Discord.Net/API/Rest/ModifyGuildMemberParams.cs +++ b/src/Discord.Net/API/Rest/ModifyGuildMemberParams.cs @@ -4,23 +4,29 @@ using System.Linq; namespace Discord.API.Rest { + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public class ModifyGuildMemberParams { [JsonProperty("mute")] - public Optional Mute { get; set; } + internal Optional _mute { get; set; } + public bool Mute { set { _mute = value; } } + [JsonProperty("deaf")] - public Optional Deaf { get; set; } + internal Optional _deaf { get; set; } + public bool Deaf { set { _deaf = value; } } + [JsonProperty("nick")] - public Optional Nickname { get; set; } + internal Optional _nickname { get; set; } + public string Nickname { set { _nickname = value; } } [JsonProperty("roles")] - public Optional> RoleIds { get; set; } - [JsonIgnore] - public Optional> Roles { set { RoleIds = value.IsSpecified ? Optional.Create(value.Value.Select(x => x.Id)) : Optional.Create>(); } } + internal Optional _roleIds { get; set; } + public IEnumerable RoleIds { set { _roleIds = value.ToArray(); } } + public IEnumerable Roles { set { _roleIds = value.Select(x => x.Id).ToArray(); } } [JsonProperty("channel_id")] - public Optional VoiceChannelId { get; set; } - [JsonIgnore] - public Optional VoiceChannel { set { VoiceChannelId = value.IsSpecified ? value.Value.Id : Optional.Create(); } } + internal Optional _channelId { get; set; } + public ulong VoiceChannelId { set { _channelId = value; } } + public IVoiceChannel VoiceChannel { set { _channelId = value.Id; } } } } diff --git a/src/Discord.Net/API/Rest/ModifyGuildParams.cs b/src/Discord.Net/API/Rest/ModifyGuildParams.cs index f111ceaea..5c4400c8b 100644 --- a/src/Discord.Net/API/Rest/ModifyGuildParams.cs +++ b/src/Discord.Net/API/Rest/ModifyGuildParams.cs @@ -3,60 +3,49 @@ using System.IO; namespace Discord.API.Rest { + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public class ModifyGuildParams { [JsonProperty("username")] - public Optional Username { get; set; } + internal Optional _username { get; set; } + public string Username { set { _username = value; } } [JsonProperty("name")] - public Optional Name { get; set; } + internal Optional _name { get; set; } + public string Name { set { _name = value; } } + [JsonProperty("region")] - public Optional Region { get; set; } + internal Optional _region { get; set; } + public IVoiceRegion Region { set { _region = Optional.Create(value); } } + [JsonProperty("verification_level")] - public Optional VerificationLevel { get; set; } + internal Optional _verificationLevel { get; set; } + public VerificationLevel VerificationLevel { set { _verificationLevel = value; } } + [JsonProperty("default_message_notifications")] - public Optional DefaultMessageNotifications { get; set; } + internal Optional _defaultMessageNotifications { get; set; } + public DefaultMessageNotifications DefaultMessageNotifications { set { _defaultMessageNotifications = value; } } + [JsonProperty("afk_timeout")] - public Optional AFKTimeout { get; set; } + internal Optional _afkTimeout { get; set; } + public int AFKTimeout { set { _afkTimeout = value; } } [JsonProperty("icon")] - private Optional _icon { get; set; } - [JsonIgnore] - public Optional Icon - { - get { return _icon.IsSpecified ? _icon.Value.Stream : null; } - set { _icon = value.IsSpecified ? new Image(value.Value) : Optional.Create(); } - } - [JsonIgnore] - internal Optional IconHash - { - get { return _icon.IsSpecified ? _icon.Value.Hash : null; } - set { _icon = value.IsSpecified ? new Image(value.Value) : Optional.Create(); } - } + internal Optional _icon { get; set; } + public Stream Icon { set { _icon = value != null ? new Image(value) : (Image?)null; } } [JsonProperty("splash")] - private Optional _splash { get; set; } - [JsonIgnore] - public Optional Splash - { - get { return _splash.IsSpecified ? _splash.Value.Stream : null; } - set { _splash = value.IsSpecified ? new Image(value.Value) : Optional.Create(); } - } - [JsonIgnore] - internal Optional SplashHash - { - get { return _splash.IsSpecified ? _splash.Value.Hash : null; } - set { _splash = value.IsSpecified ? new Image(value.Value) : Optional.Create(); } - } + internal Optional _splash { get; set; } + public Stream Splash { set { _splash = value != null ? new Image(value) : (Image?)null; } } [JsonProperty("afk_channel_id")] - public Optional AFKChannelId { get; set; } - [JsonIgnore] - public Optional AFKChannel { set { OwnerId = value.IsSpecified ? value.Value.Id : Optional.Create(); } } + internal Optional _afkChannelId { get; set; } + public ulong? AFKChannelId { set { _afkChannelId = value; } } + public IVoiceChannel AFKChannel { set { _afkChannelId = value?.Id; } } [JsonProperty("owner_id")] - public Optional OwnerId { get; set; } - [JsonIgnore] - public Optional Owner { set { OwnerId = value.IsSpecified ? value.Value.Id : Optional.Create(); } } + internal Optional _ownerId { get; set; } + public ulong OwnerId { set { _ownerId = value; } } + public IGuildUser Owner { set { _ownerId = value.Id; } } } } diff --git a/src/Discord.Net/API/Rest/ModifyGuildRoleParams.cs b/src/Discord.Net/API/Rest/ModifyGuildRoleParams.cs index d3b6979ec..71b609dfe 100644 --- a/src/Discord.Net/API/Rest/ModifyGuildRoleParams.cs +++ b/src/Discord.Net/API/Rest/ModifyGuildRoleParams.cs @@ -2,17 +2,27 @@ namespace Discord.API.Rest { + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public class ModifyGuildRoleParams { [JsonProperty("name")] - public Optional Name { get; set; } + internal Optional _name { get; set; } + public string Name { set { _name = value; } } + [JsonProperty("permissions")] - public Optional Permissions { get; set; } + internal Optional _permissions { get; set; } + public ulong Permissions { set { _permissions = value; } } + [JsonProperty("position")] - public Optional Position { get; set; } + internal Optional _position { get; set; } + public int Position { set { _position = value; } } + [JsonProperty("color")] - public Optional Color { get; set; } + internal Optional _color { get; set; } + public uint Color { set { _color = value; } } + [JsonProperty("hoist")] - public Optional Hoist { get; set; } + internal Optional _hoist { get; set; } + public bool Hoist { set { _hoist = value; } } } } diff --git a/src/Discord.Net/API/Rest/ModifyGuildRolesParams.cs b/src/Discord.Net/API/Rest/ModifyGuildRolesParams.cs index 7002079d5..4e599bf41 100644 --- a/src/Discord.Net/API/Rest/ModifyGuildRolesParams.cs +++ b/src/Discord.Net/API/Rest/ModifyGuildRolesParams.cs @@ -2,9 +2,10 @@ namespace Discord.API.Rest { + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public class ModifyGuildRolesParams : ModifyGuildRoleParams { [JsonProperty("id")] - public ulong Id { get; set; } + public ulong Id { internal get; set; } } } diff --git a/src/Discord.Net/API/Rest/ModifyMessageParams.cs b/src/Discord.Net/API/Rest/ModifyMessageParams.cs index 140bd93e3..79102d2cc 100644 --- a/src/Discord.Net/API/Rest/ModifyMessageParams.cs +++ b/src/Discord.Net/API/Rest/ModifyMessageParams.cs @@ -2,9 +2,11 @@ namespace Discord.API.Rest { + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public class ModifyMessageParams { [JsonProperty("content")] - public Optional Content { get; set; } = ""; + internal Optional _content { get; set; } + public string Content { set { _content = value; } } } } diff --git a/src/Discord.Net/API/Rest/ModifyPresenceParams.cs b/src/Discord.Net/API/Rest/ModifyPresenceParams.cs index 6c6579e4d..67f1c479d 100644 --- a/src/Discord.Net/API/Rest/ModifyPresenceParams.cs +++ b/src/Discord.Net/API/Rest/ModifyPresenceParams.cs @@ -2,7 +2,10 @@ { public class ModifyPresenceParams { - public Optional Status { get; set; } - public Optional Game { get; set; } + internal Optional _status { get; set; } + public UserStatus Status { set { _status = value; } } + + internal Optional _game { get; set; } + public Discord.Game Game { set { _game = value; } } } } diff --git a/src/Discord.Net/API/Rest/ModifyTextChannelParams.cs b/src/Discord.Net/API/Rest/ModifyTextChannelParams.cs index 28cfb3ee5..3a9a1df03 100644 --- a/src/Discord.Net/API/Rest/ModifyTextChannelParams.cs +++ b/src/Discord.Net/API/Rest/ModifyTextChannelParams.cs @@ -2,9 +2,11 @@ namespace Discord.API.Rest { + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public class ModifyTextChannelParams : ModifyGuildChannelParams { [JsonProperty("topic")] - public Optional Topic { get; set; } + internal Optional _topic { get; set; } + public string Topic { set { _topic = value; } } } } diff --git a/src/Discord.Net/API/Rest/ModifyVoiceChannelParams.cs b/src/Discord.Net/API/Rest/ModifyVoiceChannelParams.cs index 8d449c607..4537cab6f 100644 --- a/src/Discord.Net/API/Rest/ModifyVoiceChannelParams.cs +++ b/src/Discord.Net/API/Rest/ModifyVoiceChannelParams.cs @@ -2,11 +2,15 @@ namespace Discord.API.Rest { + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public class ModifyVoiceChannelParams : ModifyGuildChannelParams { [JsonProperty("bitrate")] - public Optional Bitrate { get; set; } + internal Optional _bitrate { get; set; } + public int Bitrate { set { _bitrate = value; } } + [JsonProperty("user_limit")] - public Optional UserLimit { get; set; } + internal Optional _userLimit { get; set; } + public int UserLimit { set { _userLimit = value; } } } } diff --git a/src/Discord.Net/API/Rest/UploadFileParams.cs b/src/Discord.Net/API/Rest/UploadFileParams.cs index c949a6990..100f44227 100644 --- a/src/Discord.Net/API/Rest/UploadFileParams.cs +++ b/src/Discord.Net/API/Rest/UploadFileParams.cs @@ -6,28 +6,35 @@ namespace Discord.API.Rest { public class UploadFileParams { - public Stream File { get; set; } - public string Filename { get; set; } = "unknown.dat"; + public Stream File { internal get; set; } - public Optional Content { get; set; } - public Optional Nonce { get; set; } - public Optional IsTTS { get; set; } + internal Optional _filename { get; set; } + public string Filename { set { _filename = value; } } + + internal Optional _content { get; set; } + public string Content { set { _content = value; } } + + internal Optional _nonce { get; set; } + public string Nonce { set { _nonce = value; } } + + internal Optional _isTTS { get; set; } + public bool IsTTS { set { _isTTS = value; } } public UploadFileParams(Stream file) { File = file; } - public IReadOnlyDictionary ToDictionary() + internal IReadOnlyDictionary ToDictionary() { var d = new Dictionary(); - 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; } } diff --git a/src/Discord.Net/Audio/AudioClient.cs b/src/Discord.Net/Audio/AudioClient.cs index 4b178b807..e4a3a1e51 100644 --- a/src/Discord.Net/Audio/AudioClient.cs +++ b/src/Discord.Net/Audio/AudioClient.cs @@ -49,7 +49,7 @@ namespace Discord.Audio private uint _ssrc; private byte[] _secretKey; - public CachedGuild Guild { get; } + public SocketGuild Guild { get; } public DiscordVoiceAPIClient ApiClient { get; private set; } public ConnectionState ConnectionState { get; private set; } public int Latency { get; private set; } @@ -57,7 +57,7 @@ namespace Discord.Audio private DiscordSocketClient Discord => Guild.Discord; /// Creates a new REST/WebSocket discord client. - public AudioClient(CachedGuild guild, int id) + public AudioClient(SocketGuild guild, int id) { Guild = guild; diff --git a/src/Discord.Net/Data/DataStore.cs b/src/Discord.Net/Data/DataStore.cs index af8598aa8..d7cfe0913 100644 --- a/src/Discord.Net/Data/DataStore.cs +++ b/src/Discord.Net/Data/DataStore.cs @@ -13,76 +13,76 @@ namespace Discord private const double AverageUsersPerGuild = 47.78; //Source: Googie2149 private const double CollectionMultiplier = 1.05; //Add 5% buffer to handle growth - private readonly ConcurrentDictionary _channels; - private readonly ConcurrentDictionary _dmChannels; - private readonly ConcurrentDictionary _guilds; - private readonly ConcurrentDictionary _users; + private readonly ConcurrentDictionary _channels; + private readonly ConcurrentDictionary _dmChannels; + private readonly ConcurrentDictionary _guilds; + private readonly ConcurrentDictionary _users; private readonly ConcurrentHashSet _groupChannels; - internal IReadOnlyCollection Channels => _channels.ToReadOnlyCollection(); - internal IReadOnlyCollection DMChannels => _dmChannels.ToReadOnlyCollection(); - internal IReadOnlyCollection GroupChannels => _groupChannels.Select(x => GetChannel(x) as CachedGroupChannel).ToReadOnlyCollection(_groupChannels); - internal IReadOnlyCollection Guilds => _guilds.ToReadOnlyCollection(); - internal IReadOnlyCollection Users => _users.ToReadOnlyCollection(); + internal IReadOnlyCollection Channels => _channels.ToReadOnlyCollection(); + internal IReadOnlyCollection DMChannels => _dmChannels.ToReadOnlyCollection(); + internal IReadOnlyCollection GroupChannels => _groupChannels.Select(x => GetChannel(x) as SocketGroupChannel).ToReadOnlyCollection(_groupChannels); + internal IReadOnlyCollection Guilds => _guilds.ToReadOnlyCollection(); + internal IReadOnlyCollection Users => _users.ToReadOnlyCollection(); - internal IReadOnlyCollection PrivateChannels => - _dmChannels.Select(x => x.Value as ICachedPrivateChannel).Concat( - _groupChannels.Select(x => GetChannel(x) as ICachedPrivateChannel)) + internal IReadOnlyCollection PrivateChannels => + _dmChannels.Select(x => x.Value as ISocketPrivateChannel).Concat( + _groupChannels.Select(x => GetChannel(x) as ISocketPrivateChannel)) .ToReadOnlyCollection(() => _dmChannels.Count + _groupChannels.Count); public DataStore(int guildCount, int dmChannelCount) { double estimatedChannelCount = guildCount * AverageChannelsPerGuild + dmChannelCount; double estimatedUsersCount = guildCount * AverageUsersPerGuild; - _channels = new ConcurrentDictionary(CollectionConcurrencyLevel, (int)(estimatedChannelCount * CollectionMultiplier)); - _dmChannels = new ConcurrentDictionary(CollectionConcurrencyLevel, (int)(dmChannelCount * CollectionMultiplier)); - _guilds = new ConcurrentDictionary(CollectionConcurrencyLevel, (int)(guildCount * CollectionMultiplier)); - _users = new ConcurrentDictionary(CollectionConcurrencyLevel, (int)(estimatedUsersCount * CollectionMultiplier)); + _channels = new ConcurrentDictionary(CollectionConcurrencyLevel, (int)(estimatedChannelCount * CollectionMultiplier)); + _dmChannels = new ConcurrentDictionary(CollectionConcurrencyLevel, (int)(dmChannelCount * CollectionMultiplier)); + _guilds = new ConcurrentDictionary(CollectionConcurrencyLevel, (int)(guildCount * CollectionMultiplier)); + _users = new ConcurrentDictionary(CollectionConcurrencyLevel, (int)(estimatedUsersCount * CollectionMultiplier)); _groupChannels = new ConcurrentHashSet(CollectionConcurrencyLevel, (int)(10 * CollectionMultiplier)); } - internal ICachedChannel GetChannel(ulong id) + internal ISocketChannel GetChannel(ulong id) { - ICachedChannel channel; + ISocketChannel channel; if (_channels.TryGetValue(id, out channel)) return channel; return null; } - internal CachedDMChannel GetDMChannel(ulong userId) + internal SocketDMChannel GetDMChannel(ulong userId) { - CachedDMChannel channel; + SocketDMChannel channel; if (_dmChannels.TryGetValue(userId, out channel)) return channel; return null; } - internal void AddChannel(ICachedChannel channel) + internal void AddChannel(ISocketChannel channel) { _channels[channel.Id] = channel; - var dmChannel = channel as CachedDMChannel; + var dmChannel = channel as SocketDMChannel; if (dmChannel != null) _dmChannels[dmChannel.Recipient.Id] = dmChannel; else { - var groupChannel = channel as CachedGroupChannel; + var groupChannel = channel as SocketGroupChannel; if (groupChannel != null) _groupChannels.TryAdd(groupChannel.Id); } } - internal ICachedChannel RemoveChannel(ulong id) + internal ISocketChannel RemoveChannel(ulong id) { - ICachedChannel channel; + ISocketChannel channel; if (_channels.TryRemove(id, out channel)) { - var dmChannel = channel as CachedDMChannel; + var dmChannel = channel as SocketDMChannel; if (dmChannel != null) { - CachedDMChannel ignored; + SocketDMChannel ignored; _dmChannels.TryRemove(dmChannel.Recipient.Id, out ignored); } else { - var groupChannel = channel as CachedGroupChannel; + var groupChannel = channel as SocketGroupChannel; if (groupChannel != null) _groupChannels.TryRemove(id); } @@ -91,39 +91,39 @@ namespace Discord return null; } - internal CachedGuild GetGuild(ulong id) + internal SocketGuild GetGuild(ulong id) { - CachedGuild guild; + SocketGuild guild; if (_guilds.TryGetValue(id, out guild)) return guild; return null; } - internal void AddGuild(CachedGuild guild) + internal void AddGuild(SocketGuild 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)) return guild; return null; } - internal CachedGlobalUser GetUser(ulong id) + internal SocketGlobalUser GetUser(ulong id) { - CachedGlobalUser user; + SocketGlobalUser user; if (_users.TryGetValue(id, out user)) return user; return null; } - internal CachedGlobalUser GetOrAddUser(ulong id, Func userFactory) + internal SocketGlobalUser GetOrAddUser(ulong id, Func 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)) return user; return null; diff --git a/src/Discord.Net/DiscordConfig.cs b/src/Discord.Net/DiscordConfig.cs index 5fcffd0a2..2f0f50018 100644 --- a/src/Discord.Net/DiscordConfig.cs +++ b/src/Discord.Net/DiscordConfig.cs @@ -1,33 +1,17 @@ -using Discord.Net.Rest; -using System.Reflection; +using System.Reflection; namespace Discord { 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().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().InformationalVersion ?? "Unknown"; public static readonly string ClientAPIUrl = $"https://discordapp.com/api/v{APIVersion}/"; public const string CDNUrl = "https://cdn.discordapp.com/"; 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; - /// Gets or sets the minimum log level severity that will be sent to the LogMessage event. public LogSeverity LogLevel { get; set; } = LogSeverity.Info; - - /// Gets or sets the provider used to generate new REST connections. - public RestClientProvider RestClientProvider { get; set; } = url => new DefaultRestClient(url); } } diff --git a/src/Discord.Net/DiscordClient.cs b/src/Discord.Net/DiscordRestClient.cs similarity index 96% rename from src/Discord.Net/DiscordClient.cs rename to src/Discord.Net/DiscordRestClient.cs index 13ce1632c..253c624f1 100644 --- a/src/Discord.Net/DiscordClient.cs +++ b/src/Discord.Net/DiscordRestClient.cs @@ -10,11 +10,10 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Runtime.InteropServices; -using System.Collections.Concurrent; namespace Discord { - public class DiscordClient : IDiscordClient + public class DiscordRestClient : IDiscordClient { private readonly object _eventLock = new object(); @@ -38,9 +37,9 @@ namespace Discord public LoginState LoginState { get; private set; } /// Creates a new REST-only discord client. - public DiscordClient() : this(new DiscordConfig()) { } + public DiscordRestClient() : this(new DiscordRestConfig()) { } /// Creates a new REST-only discord client. - public DiscordClient(DiscordConfig config) + public DiscordRestClient(DiscordRestConfig config) { LogManager = new LogManager(config.LogLevel); LogManager.Message += async msg => await _logEvent.InvokeAsync(msg).ConfigureAwait(false); @@ -305,9 +304,10 @@ namespace Discord private async Task WriteInitialLog() { 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 - 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($"OS: {RuntimeInformation.OSDescription.Trim()} ({ToArchString(RuntimeInformation.OSArchitecture)})").ConfigureAwait(false); await _clientLogger.VerboseAsync($"Processors: {Environment.ProcessorCount}").ConfigureAwait(false); diff --git a/src/Discord.Net/DiscordRestConfig.cs b/src/Discord.Net/DiscordRestConfig.cs new file mode 100644 index 000000000..16252c854 --- /dev/null +++ b/src/Discord.Net/DiscordRestConfig.cs @@ -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; + + /// Gets or sets the provider used to generate new REST connections. + public RestClientProvider RestClientProvider { get; set; } = url => new DefaultRestClient(url); + } +} diff --git a/src/Discord.Net/DiscordSocketClient.cs b/src/Discord.Net/DiscordSocketClient.cs index a2ca7def3..12a988336 100644 --- a/src/Discord.Net/DiscordSocketClient.cs +++ b/src/Discord.Net/DiscordSocketClient.cs @@ -16,7 +16,7 @@ using System.Threading.Tasks; namespace Discord { - public partial class DiscordSocketClient : DiscordClient, IDiscordClient + public partial class DiscordSocketClient : DiscordRestClient, IDiscordClient { private readonly ConcurrentQueue _largeGuilds; private readonly ILogger _gatewayLogger; @@ -44,19 +44,16 @@ namespace Discord /// Gets the estimated round-trip latency, in milliseconds, to the gateway server. public int Latency { get; private set; } - //From DiscordConfig + //From DiscordSocketConfig 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 LargeThreshold { get; private set; } internal AudioMode AudioMode { get; private set; } internal DataStore DataStore { get; private set; } internal WebSocketProvider WebSocketProvider { get; private set; } - internal CachedSelfUser CurrentUser => _currentUser as CachedSelfUser; - internal IReadOnlyCollection Guilds => DataStore.Guilds; + internal SocketSelfUser CurrentUser => _currentUser as SocketSelfUser; + internal IReadOnlyCollection Guilds => DataStore.Guilds; internal IReadOnlyCollection VoiceRegions => _voiceRegions.ToReadOnlyCollection(); /// Creates a new REST/WebSocket discord client. @@ -67,9 +64,6 @@ namespace Discord { ShardId = config.ShardId; TotalShards = config.TotalShards; - ConnectionTimeout = config.ConnectionTimeout; - ReconnectDelay = config.ReconnectDelay; - FailedReconnectDelay = config.FailedReconnectDelay; MessageCacheSize = config.MessageCacheSize; LargeThreshold = config.LargeThreshold; AudioMode = config.AudioMode; @@ -340,15 +334,15 @@ namespace Discord { return Task.FromResult>(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); if (model.Large) _largeGuilds.Enqueue(model.Id); return guild; } - internal CachedGuild RemoveGuild(ulong id) + internal SocketGuild RemoveGuild(ulong id) { var guild = DataStore.RemoveGuild(id); foreach (var channel in guild.Channels) @@ -367,7 +361,7 @@ namespace Discord { return Task.FromResult>(DataStore.PrivateChannels); } - internal ICachedChannel AddPrivateChannel(API.Channel model, DataStore dataStore) + internal ISocketChannel AddPrivateChannel(API.Channel model, DataStore dataStore) { switch (model.Type) { @@ -375,13 +369,13 @@ namespace Discord { var recipients = model.Recipients.Value; 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); return channel; } case ChannelType.Group: { - var channel = new CachedGroupChannel(this, model); + var channel = new SocketGroupChannel(this, model); channel.UpdateUsers(model.Recipients.Value, UpdateSource.Creation, dataStore); dataStore.AddChannel(channel); return channel; @@ -390,9 +384,9 @@ namespace Discord 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) recipient.User.RemoveRef(this); return channel; @@ -413,13 +407,13 @@ namespace Discord { return Task.FromResult(_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(); return user; } - internal CachedGlobalUser RemoveUser(ulong id) + internal SocketGlobalUser RemoveUser(ulong id) { return DataStore.RemoveUser(id); } @@ -429,10 +423,10 @@ namespace Discord => DownloadUsersAsync(DataStore.Guilds.Where(x => !x.HasAllMembers)); /// Downloads the users list for the provided guilds, if they don't have a complete list. public Task DownloadUsersAsync(IEnumerable 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) - => DownloadUsersAsync(guilds.Select(x => x as CachedGuild).Where(x => x != null)); - private async Task DownloadUsersAsync(IEnumerable guilds) + => DownloadUsersAsync(guilds.Select(x => x as SocketGuild).Where(x => x != null)); + private async Task DownloadUsersAsync(IEnumerable guilds) { var cachedGuilds = guilds.ToArray(); if (cachedGuilds.Length == 0) return; @@ -559,7 +553,7 @@ namespace Discord var data = (payload as JToken).ToObject(_serializer); 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; for (int i = 0; i < data.Guilds.Length; i++) { @@ -625,7 +619,7 @@ namespace Discord } await _gatewayLogger.DebugAsync($"Received Dispatch ({type})").ConfigureAwait(false); - CachedGuild guild; + SocketGuild guild; if (data.Unavailable != false) { guild = AddGuild(data, DataStore); @@ -751,7 +745,7 @@ namespace Discord await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_CREATE)").ConfigureAwait(false); var data = (payload as JToken).ToObject(_serializer); - ICachedChannel channel = null; + ISocketChannel channel = null; if (data.GuildId.IsSpecified) { var guild = DataStore.GetGuild(data.GuildId.Value); @@ -789,7 +783,7 @@ namespace Discord var before = channel.Clone(); 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); return; @@ -808,7 +802,7 @@ namespace Discord { await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_DELETE)").ConfigureAwait(false); - ICachedChannel channel = null; + ISocketChannel channel = null; var data = (payload as JToken).ToObject(_serializer); if (data.GuildId.IsSpecified) { @@ -978,7 +972,7 @@ namespace Discord await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_RECIPIENT_ADD)").ConfigureAwait(false); var data = (payload as JToken).ToObject(_serializer); - var channel = DataStore.GetChannel(data.ChannelId) as CachedGroupChannel; + var channel = DataStore.GetChannel(data.ChannelId) as SocketGroupChannel; if (channel != null) { var user = channel.AddUser(data.User, DataStore); @@ -996,7 +990,7 @@ namespace Discord await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_RECIPIENT_REMOVE)").ConfigureAwait(false); var data = (payload as JToken).ToObject(_serializer); - var channel = DataStore.GetChannel(data.ChannelId) as CachedGroupChannel; + var channel = DataStore.GetChannel(data.ChannelId) as SocketGroupChannel; if (channel != null) { var user = channel.RemoveUser(data.User.Id); @@ -1166,10 +1160,10 @@ namespace Discord await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_CREATE)").ConfigureAwait(false); var data = (payload as JToken).ToObject(_serializer); - var channel = DataStore.GetChannel(data.ChannelId) as ICachedMessageChannel; + var channel = DataStore.GetChannel(data.ChannelId) as ISocketMessageChannel; 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); return; @@ -1200,17 +1194,17 @@ namespace Discord await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_UPDATE)").ConfigureAwait(false); var data = (payload as JToken).ToObject(_serializer); - var channel = DataStore.GetChannel(data.ChannelId) as ICachedMessageChannel; + var channel = DataStore.GetChannel(data.ChannelId) as ISocketMessageChannel; 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); return; } IMessage before = null, after = null; - CachedMessage cachedMsg = channel.GetMessage(data.Id); + SocketMessage cachedMsg = channel.GetMessage(data.Id); if (cachedMsg != null) { before = cachedMsg.Clone(); @@ -1239,10 +1233,10 @@ namespace Discord await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_DELETE)").ConfigureAwait(false); var data = (payload as JToken).ToObject(_serializer); - var channel = DataStore.GetChannel(data.ChannelId) as ICachedMessageChannel; + var channel = DataStore.GetChannel(data.ChannelId) as ISocketMessageChannel; 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); return; @@ -1266,10 +1260,10 @@ namespace Discord await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_DELETE_BULK)").ConfigureAwait(false); var data = (payload as JToken).ToObject(_serializer); - var channel = DataStore.GetChannel(data.ChannelId) as ICachedMessageChannel; + var channel = DataStore.GetChannel(data.ChannelId) as ISocketMessageChannel; 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); return; @@ -1341,10 +1335,10 @@ namespace Discord await _gatewayLogger.DebugAsync("Received Dispatch (TYPING_START)").ConfigureAwait(false); var data = (payload as JToken).ToObject(_serializer); - var channel = DataStore.GetChannel(data.ChannelId) as ICachedMessageChannel; + var channel = DataStore.GetChannel(data.ChannelId) as ISocketMessageChannel; 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); return; @@ -1385,7 +1379,7 @@ namespace Discord var data = (payload as JToken).ToObject(_serializer); if (data.GuildId.HasValue) { - ICachedUser user; + ISocketUser user; VoiceState before, after; if (data.GuildId != null) { @@ -1418,7 +1412,7 @@ namespace Discord } else { - var groupChannel = DataStore.GetChannel(data.ChannelId.Value) as CachedGroupChannel; + var groupChannel = DataStore.GetChannel(data.ChannelId.Value) as SocketGroupChannel; if (groupChannel != null) { if (data.ChannelId != null) diff --git a/src/Discord.Net/DiscordSocketConfig.cs b/src/Discord.Net/DiscordSocketConfig.cs index cd54fcd8d..8bdb3020a 100644 --- a/src/Discord.Net/DiscordSocketConfig.cs +++ b/src/Discord.Net/DiscordSocketConfig.cs @@ -3,20 +3,15 @@ using Discord.Net.WebSockets; namespace Discord { - public class DiscordSocketConfig : DiscordConfig + public class DiscordSocketConfig : DiscordRestConfig { + public const string GatewayEncoding = "json"; + /// Gets or sets the id for this shard. Must be less than TotalShards. public int ShardId { get; set; } = 0; /// Gets or sets the total number of shards for this application. public int TotalShards { get; set; } = 1; - /// Gets or sets the time (in milliseconds) to wait for the websocket to connect and initialize. - public int ConnectionTimeout { get; set; } = 30000; - /// Gets or sets the time (in milliseconds) to wait after an unexpected disconnect before reconnecting. - public int ReconnectDelay { get; set; } = 1000; - /// Gets or sets the time (in milliseconds) to wait after an reconnect fails before retrying. - public int FailedReconnectDelay { get; set; } = 15000; - /// Gets or sets the number of messages per channel that should be kept in cache. Setting this to zero disables the message cache entirely. public int MessageCacheSize { get; set; } = 0; /*/// diff --git a/src/Discord.Net/Entities/Application.cs b/src/Discord.Net/Entities/Application.cs index bee814fb4..677dd2aab 100644 --- a/src/Discord.Net/Entities/Application.cs +++ b/src/Discord.Net/Entities/Application.cs @@ -13,12 +13,12 @@ namespace Discord public string[] RPCOrigins { 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 string IconUrl => API.CDN.GetApplicationIconUrl(Id, _iconId); - public Application(DiscordClient discord, Model model) + public Application(DiscordRestClient discord, Model model) : base(model.Id) { Discord = discord; diff --git a/src/Discord.Net/Entities/Channels/DMChannel.cs b/src/Discord.Net/Entities/Channels/DMChannel.cs index 8f79ddccd..dee579432 100644 --- a/src/Discord.Net/Entities/Channels/DMChannel.cs +++ b/src/Discord.Net/Entities/Channels/DMChannel.cs @@ -13,13 +13,13 @@ namespace Discord [DebuggerDisplay(@"{DebuggerDisplay,nq}")] internal class DMChannel : SnowflakeEntity, IDMChannel { - public override DiscordClient Discord { get; } + public override DiscordRestClient Discord { get; } public IUser Recipient { get; private set; } public virtual IReadOnlyCollection CachedMessages => ImmutableArray.Create(); IReadOnlyCollection IPrivateChannel.Recipients => ImmutableArray.Create(Recipient); - public DMChannel(DiscordClient discord, IUser recipient, Model model) + public DMChannel(DiscordRestClient discord, IUser recipient, Model model) : base(model.Id) { Discord = discord; diff --git a/src/Discord.Net/Entities/Channels/GroupChannel.cs b/src/Discord.Net/Entities/Channels/GroupChannel.cs index 8169bfb9c..929d050cd 100644 --- a/src/Discord.Net/Entities/Channels/GroupChannel.cs +++ b/src/Discord.Net/Entities/Channels/GroupChannel.cs @@ -18,14 +18,14 @@ namespace Discord protected ConcurrentDictionary _users; private string _iconId; - public override DiscordClient Discord { get; } + public override DiscordRestClient Discord { get; } public string Name { get; private set; } public IReadOnlyCollection Recipients => _users.ToReadOnlyCollection(); public virtual IReadOnlyCollection CachedMessages => ImmutableArray.Create(); public string IconUrl => API.CDN.GetChannelIconUrl(Id, _iconId); - public GroupChannel(DiscordClient discord, Model model) + public GroupChannel(DiscordRestClient discord, Model model) : base(model.Id) { Discord = discord; diff --git a/src/Discord.Net/Entities/Channels/GuildChannel.cs b/src/Discord.Net/Entities/Channels/GuildChannel.cs index fac9b045a..31303bc10 100644 --- a/src/Discord.Net/Entities/Channels/GuildChannel.cs +++ b/src/Discord.Net/Entities/Channels/GuildChannel.cs @@ -19,7 +19,7 @@ namespace Discord public Guild Guild { get; private set; } - public override DiscordClient Discord => Guild.Discord; + public override DiscordRestClient Discord => Guild.Discord; public GuildChannel(Guild guild, Model model) : base(model.Id) @@ -56,8 +56,8 @@ namespace Discord var args = new ModifyGuildChannelParams(); 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); Update(model, UpdateSource.Rest); diff --git a/src/Discord.Net/Entities/Channels/IMessageChannel.cs b/src/Discord.Net/Entities/Channels/IMessageChannel.cs index a5a73b177..7aafb6ac1 100644 --- a/src/Discord.Net/Entities/Channels/IMessageChannel.cs +++ b/src/Discord.Net/Entities/Channels/IMessageChannel.cs @@ -20,12 +20,11 @@ namespace Discord /// Gets the message from this channel's cache with the given id, or null if not found. IMessage GetCachedMessage(ulong id); /// Gets the last N messages from this message channel. - Task> GetMessagesAsync(int limit = DiscordConfig.MaxMessagesPerBatch); + Task> GetMessagesAsync(int limit = DiscordRestConfig.MaxMessagesPerBatch); /// Gets a collection of messages in this channel. - Task> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch); + Task> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = DiscordRestConfig.MaxMessagesPerBatch); /// Bulk deletes multiple messages. - Task DeleteMessagesAsync(IEnumerable messages); - + Task DeleteMessagesAsync(IEnumerable messages); /// Broadcasts the "user is typing" message to all users in this channel, lasting 10 seconds. Task TriggerTypingAsync(); diff --git a/src/Discord.Net/Entities/Channels/IPrivateChannel.cs b/src/Discord.Net/Entities/Channels/IPrivateChannel.cs index 9fe7e2147..9a3289794 100644 --- a/src/Discord.Net/Entities/Channels/IPrivateChannel.cs +++ b/src/Discord.Net/Entities/Channels/IPrivateChannel.cs @@ -2,7 +2,7 @@ namespace Discord { - public interface IPrivateChannel + public interface IPrivateChannel : IChannel { IReadOnlyCollection Recipients { get; } } diff --git a/src/Discord.Net/Entities/Channels/TextChannel.cs b/src/Discord.Net/Entities/Channels/TextChannel.cs index a8c0d24ee..f301a7e18 100644 --- a/src/Discord.Net/Entities/Channels/TextChannel.cs +++ b/src/Discord.Net/Entities/Channels/TextChannel.cs @@ -37,8 +37,8 @@ namespace Discord var args = new ModifyTextChannelParams(); 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); Update(model, UpdateSource.Rest); diff --git a/src/Discord.Net/Entities/Channels/VoiceChannel.cs b/src/Discord.Net/Entities/Channels/VoiceChannel.cs index 20accdaf4..b0db27e4d 100644 --- a/src/Discord.Net/Entities/Channels/VoiceChannel.cs +++ b/src/Discord.Net/Entities/Channels/VoiceChannel.cs @@ -34,8 +34,8 @@ namespace Discord var args = new ModifyVoiceChannelParams(); 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); Update(model, UpdateSource.Rest); diff --git a/src/Discord.Net/Entities/Entity.cs b/src/Discord.Net/Entities/Entity.cs index 4ffd45d1f..8e8e7587f 100644 --- a/src/Discord.Net/Entities/Entity.cs +++ b/src/Discord.Net/Entities/Entity.cs @@ -4,9 +4,10 @@ { public T Id { get; } - public abstract DiscordClient Discord { get; } + public abstract DiscordRestClient Discord { get; } - public bool IsAttached => this is ICachedEntity; + internal virtual bool IsAttached => false; + bool IEntity.IsAttached => IsAttached; public Entity(T id) { diff --git a/src/Discord.Net/Entities/Guilds/Guild.cs b/src/Discord.Net/Entities/Guilds/Guild.cs index cc360813d..dc5b64592 100644 --- a/src/Discord.Net/Entities/Guilds/Guild.cs +++ b/src/Discord.Net/Entities/Guilds/Guild.cs @@ -27,7 +27,7 @@ namespace Discord public MfaLevel MfaLevel { 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? EmbedChannelId { get; private set; } public ulong OwnerId { get; private set; } @@ -42,7 +42,7 @@ namespace Discord public Role EveryoneRole => GetRole(Id); public IReadOnlyCollection Roles => _roles.ToReadOnlyCollection(); - public Guild(DiscordClient discord, Model model) + public Guild(DiscordRestClient discord, Model model) : base(model.Id) { Discord = discord; @@ -122,10 +122,10 @@ namespace Discord var args = new ModifyGuildParams(); 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); Update(model, UpdateSource.Rest); @@ -165,7 +165,7 @@ namespace Discord public Task AddBanAsync(IUser user, int pruneDays = 0) => AddBanAsync(user, pruneDays); 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); } public Task RemoveBanAsync(IUser user) => RemoveBanAsync(user.Id); diff --git a/src/Discord.Net/Entities/Guilds/GuildIntegration.cs b/src/Discord.Net/Entities/Guilds/GuildIntegration.cs index 0aba4d4e3..fa2ceddda 100644 --- a/src/Discord.Net/Entities/Guilds/GuildIntegration.cs +++ b/src/Discord.Net/Entities/Guilds/GuildIntegration.cs @@ -23,7 +23,7 @@ namespace Discord public User User { 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 GuildIntegration(Guild guild, Model model) diff --git a/src/Discord.Net/Entities/Guilds/UserGuild.cs b/src/Discord.Net/Entities/Guilds/UserGuild.cs index 9d76817e5..77c28192d 100644 --- a/src/Discord.Net/Entities/Guilds/UserGuild.cs +++ b/src/Discord.Net/Entities/Guilds/UserGuild.cs @@ -13,11 +13,11 @@ namespace Discord public bool IsOwner { 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 UserGuild(DiscordClient discord, Model model) + public UserGuild(DiscordRestClient discord, Model model) : base(model.Id) { Discord = discord; diff --git a/src/Discord.Net/Entities/Invites/Invite.cs b/src/Discord.Net/Entities/Invites/Invite.cs index 90e380582..3ed09410f 100644 --- a/src/Discord.Net/Entities/Invites/Invite.cs +++ b/src/Discord.Net/Entities/Invites/Invite.cs @@ -13,13 +13,13 @@ namespace Discord public ulong ChannelId { 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 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) { Discord = discord; diff --git a/src/Discord.Net/Entities/Invites/InviteMetadata.cs b/src/Discord.Net/Entities/Invites/InviteMetadata.cs index 6c334a79f..df7d965af 100644 --- a/src/Discord.Net/Entities/Invites/InviteMetadata.cs +++ b/src/Discord.Net/Entities/Invites/InviteMetadata.cs @@ -16,7 +16,7 @@ namespace Discord public DateTimeOffset CreatedAt => DateTimeUtils.FromTicks(_createdAtTicks); - public InviteMetadata(DiscordClient client, Model model) + public InviteMetadata(DiscordRestClient client, Model model) : base(client, model) { Update(model, UpdateSource.Creation); diff --git a/src/Discord.Net/Entities/Messages/Message.cs b/src/Discord.Net/Entities/Messages/Message.cs index 186ca7308..1dbf0c6a1 100644 --- a/src/Discord.Net/Entities/Messages/Message.cs +++ b/src/Discord.Net/Entities/Messages/Message.cs @@ -29,7 +29,7 @@ namespace Discord public IReadOnlyCollection MentionedRoles { get; private set; } public IReadOnlyCollection MentionedUsers { get; private set; } - public override DiscordClient Discord => (Channel as Entity).Discord; + public override DiscordRestClient Discord => (Channel as Entity).Discord; public DateTimeOffset? EditedTimestamp => DateTimeUtils.FromTicks(_editedTimestampTicks); public DateTimeOffset Timestamp => DateTimeUtils.FromTicks(_timestampTicks); diff --git a/src/Discord.Net/Entities/Roles/Role.cs b/src/Discord.Net/Entities/Roles/Role.cs index dd06cc507..43af085b3 100644 --- a/src/Discord.Net/Entities/Roles/Role.cs +++ b/src/Discord.Net/Entities/Roles/Role.cs @@ -23,7 +23,7 @@ namespace Discord public bool IsEveryone => Id == Guild.Id; public string Mention => MentionUtils.Mention(this); - public override DiscordClient Discord => Guild.Discord; + public override DiscordRestClient Discord => Guild.Discord; public Role(Guild guild, Model model) : base(model.Id) @@ -51,6 +51,7 @@ namespace Discord var args = new ModifyGuildRoleParams(); func(args); var response = await Discord.ApiClient.ModifyGuildRoleAsync(Guild.Id, Id, args).ConfigureAwait(false); + Update(response, UpdateSource.Rest); } public async Task DeleteAsync() diff --git a/src/Discord.Net/Entities/Users/GroupUser.cs b/src/Discord.Net/Entities/Users/GroupUser.cs index 98a8dade4..7a44e5d8e 100644 --- a/src/Discord.Net/Entities/Users/GroupUser.cs +++ b/src/Discord.Net/Entities/Users/GroupUser.cs @@ -6,6 +6,9 @@ namespace Discord { internal class GroupUser : IGroupUser { + internal virtual bool IsAttached => false; + bool IEntity.IsAttached => IsAttached; + public GroupChannel Channel { get; private set; } public User User { get; private set; } @@ -14,7 +17,6 @@ namespace Discord public DateTimeOffset CreatedAt => User.CreatedAt; public string Discriminator => User.Discriminator; public ushort DiscriminatorValue => User.DiscriminatorValue; - public bool IsAttached => User.IsAttached; public bool IsBot => User.IsBot; public string Username => User.Username; public string Mention => MentionUtils.Mention(this, false); @@ -22,7 +24,7 @@ namespace Discord public virtual UserStatus Status => UserStatus.Unknown; public virtual Game Game => null; - public DiscordClient Discord => Channel.Discord; + public DiscordRestClient Discord => Channel.Discord; public GroupUser(GroupChannel channel, User user) { diff --git a/src/Discord.Net/Entities/Users/GuildUser.cs b/src/Discord.Net/Entities/Users/GuildUser.cs index 1aa0ba9fc..caccb4336 100644 --- a/src/Discord.Net/Entities/Users/GuildUser.cs +++ b/src/Discord.Net/Entities/Users/GuildUser.cs @@ -13,6 +13,9 @@ namespace Discord [DebuggerDisplay("{DebuggerDisplay,nq}")] internal class GuildUser : IGuildUser, ISnowflakeEntity { + internal virtual bool IsAttached => false; + bool IEntity.IsAttached => IsAttached; + private long? _joinedAtTicks; public string Nickname { get; private set; } @@ -27,7 +30,6 @@ namespace Discord public DateTimeOffset CreatedAt => User.CreatedAt; public string Discriminator => User.Discriminator; public ushort DiscriminatorValue => User.DiscriminatorValue; - public bool IsAttached => User.IsAttached; public bool IsBot => User.IsBot; public string Mention => MentionUtils.Mention(this, Nickname != null); public string Username => User.Username; @@ -35,7 +37,7 @@ namespace Discord public virtual UserStatus Status => UserStatus.Unknown; public virtual Game Game => null; - public DiscordClient Discord => Guild.Discord; + public DiscordRestClient Discord => Guild.Discord; public DateTimeOffset? JoinedAt => DateTimeUtils.FromTicks(_joinedAtTicks); public GuildUser(Guild guild, User user) @@ -75,6 +77,15 @@ namespace Discord if (model.Nick.IsSpecified) 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) { var roles = ImmutableArray.CreateBuilder(roleIds.Length + 1); @@ -104,20 +115,17 @@ namespace Discord func(args); 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); - args.Nickname = new Optional(); //Remove + args._nickname = Optional.Create(); //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); - 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() diff --git a/src/Discord.Net/Entities/Users/SelfUser.cs b/src/Discord.Net/Entities/Users/SelfUser.cs index e4f67b5d6..0169ef6cd 100644 --- a/src/Discord.Net/Entities/Users/SelfUser.cs +++ b/src/Discord.Net/Entities/Users/SelfUser.cs @@ -18,9 +18,9 @@ namespace Discord public override UserStatus Status => _status; 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) { Discord = discord; @@ -53,10 +53,10 @@ namespace Discord var args = new ModifyCurrentUserParams(); 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); Update(model, UpdateSource.Rest); @@ -68,13 +68,13 @@ namespace Discord var args = new ModifyPresenceParams(); 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; if (status == UserStatus.Idle && _status != UserStatus.Idle) 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); diff --git a/src/Discord.Net/Entities/Users/User.cs b/src/Discord.Net/Entities/Users/User.cs index e6628fe3e..640084f7b 100644 --- a/src/Discord.Net/Entities/Users/User.cs +++ b/src/Discord.Net/Entities/Users/User.cs @@ -13,7 +13,7 @@ namespace Discord public string Username { 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 Discriminator => DiscriminatorValue.ToString("D4"); diff --git a/src/Discord.Net/Entities/WebSocket/CachedMessage.cs b/src/Discord.Net/Entities/WebSocket/CachedMessage.cs deleted file mode 100644 index 72edb107d..000000000 --- a/src/Discord.Net/Entities/WebSocket/CachedMessage.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Model = Discord.API.Message; - -namespace Discord -{ - internal class CachedMessage : Message, ICachedEntity - { - 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; - } -} diff --git a/src/Discord.Net/Entities/WebSocket/CachedSelfUser.cs b/src/Discord.Net/Entities/WebSocket/CachedSelfUser.cs deleted file mode 100644 index 5e9c2dbc2..000000000 --- a/src/Discord.Net/Entities/WebSocket/CachedSelfUser.cs +++ /dev/null @@ -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(); - } -} diff --git a/src/Discord.Net/Entities/WebSocket/ICachedChannel.cs b/src/Discord.Net/Entities/WebSocket/Channels/ISocketChannel.cs similarity index 55% rename from src/Discord.Net/Entities/WebSocket/ICachedChannel.cs rename to src/Discord.Net/Entities/WebSocket/Channels/ISocketChannel.cs index caebf7c10..91535e7c9 100644 --- a/src/Discord.Net/Entities/WebSocket/ICachedChannel.cs +++ b/src/Discord.Net/Entities/WebSocket/Channels/ISocketChannel.cs @@ -2,10 +2,10 @@ namespace Discord { - internal interface ICachedChannel : IChannel, ICachedEntity + internal interface ISocketChannel : IChannel { void Update(Model model, UpdateSource source); - ICachedChannel Clone(); + ISocketChannel Clone(); } } diff --git a/src/Discord.Net/Entities/WebSocket/Channels/ISocketGuildChannel.cs b/src/Discord.Net/Entities/WebSocket/Channels/ISocketGuildChannel.cs new file mode 100644 index 000000000..b9925582d --- /dev/null +++ b/src/Discord.Net/Entities/WebSocket/Channels/ISocketGuildChannel.cs @@ -0,0 +1,7 @@ +namespace Discord +{ + internal interface ISocketGuildChannel : ISocketChannel, IGuildChannel + { + new SocketGuild Guild { get; } + } +} diff --git a/src/Discord.Net/Entities/WebSocket/Channels/ISocketMessageChannel.cs b/src/Discord.Net/Entities/WebSocket/Channels/ISocketMessageChannel.cs new file mode 100644 index 000000000..e1a538719 --- /dev/null +++ b/src/Discord.Net/Entities/WebSocket/Channels/ISocketMessageChannel.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using MessageModel = Discord.API.Message; + +namespace Discord +{ + internal interface ISocketMessageChannel : ISocketChannel, IMessageChannel + { + IReadOnlyCollection Users { get; } + + SocketMessage AddMessage(ISocketUser author, MessageModel model); + SocketMessage GetMessage(ulong id); + SocketMessage RemoveMessage(ulong id); + + ISocketUser GetUser(ulong id, bool skipCheck = false); + } +} diff --git a/src/Discord.Net/Entities/WebSocket/Channels/ISocketPrivateChannel.cs b/src/Discord.Net/Entities/WebSocket/Channels/ISocketPrivateChannel.cs new file mode 100644 index 000000000..609aea3b6 --- /dev/null +++ b/src/Discord.Net/Entities/WebSocket/Channels/ISocketPrivateChannel.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace Discord +{ + internal interface ISocketPrivateChannel : ISocketChannel, IPrivateChannel + { + new IReadOnlyCollection Recipients { get; } + } +} diff --git a/src/Discord.Net/Entities/WebSocket/MessageCache.cs b/src/Discord.Net/Entities/WebSocket/Channels/MessageCache.cs similarity index 72% rename from src/Discord.Net/Entities/WebSocket/MessageCache.cs rename to src/Discord.Net/Entities/WebSocket/Channels/MessageCache.cs index 0eaee13c3..e97c76524 100644 --- a/src/Discord.Net/Entities/WebSocket/MessageCache.cs +++ b/src/Discord.Net/Entities/WebSocket/Channels/MessageCache.cs @@ -10,51 +10,51 @@ namespace Discord { internal class MessageCache : MessageManager { - private readonly ConcurrentDictionary _messages; + private readonly ConcurrentDictionary _messages; private readonly ConcurrentQueue _orderedMessages; private readonly int _size; - public override IReadOnlyCollection Messages => _messages.ToReadOnlyCollection(); + public override IReadOnlyCollection Messages => _messages.ToReadOnlyCollection(); - public MessageCache(DiscordSocketClient discord, ICachedMessageChannel channel) + public MessageCache(DiscordSocketClient discord, ISocketMessageChannel channel) : base(discord, channel) { _size = discord.MessageCacheSize; - _messages = new ConcurrentDictionary(1, (int)(_size * 1.05)); + _messages = new ConcurrentDictionary(1, (int)(_size * 1.05)); _orderedMessages = new ConcurrentQueue(); } - public override void Add(CachedMessage message) + public override void Add(SocketMessage message) { if (_messages.TryAdd(message.Id, message)) { _orderedMessages.Enqueue(message.Id); ulong msgId; - CachedMessage msg; + SocketMessage msg; while (_orderedMessages.Count > _size && _orderedMessages.TryDequeue(out msgId)) _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); return msg; } - public override CachedMessage Get(ulong id) + public override SocketMessage Get(ulong id) { - CachedMessage result; + SocketMessage result; if (_messages.TryGetValue(id, out result)) return result; return null; } - public override IImmutableList GetMany(ulong? fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch) + public override IImmutableList GetMany(ulong? fromMessageId, Direction dir, int limit = DiscordRestConfig.MaxMessagesPerBatch) { if (limit < 0) throw new ArgumentOutOfRangeException(nameof(limit)); - if (limit == 0) return ImmutableArray.Empty; + if (limit == 0) return ImmutableArray.Empty; IEnumerable cachedMessageIds; if (fromMessageId == null) @@ -68,7 +68,7 @@ namespace Discord .Take(limit) .Select(x => { - CachedMessage msg; + SocketMessage msg; if (_messages.TryGetValue(x, out msg)) return msg; return null; @@ -77,7 +77,7 @@ namespace Discord .ToImmutableArray(); } - public override async Task DownloadAsync(ulong id) + public override async Task DownloadAsync(ulong id) { var msg = Get(id); if (msg != null) diff --git a/src/Discord.Net/Entities/WebSocket/MessageManager.cs b/src/Discord.Net/Entities/WebSocket/Channels/MessageManager.cs similarity index 60% rename from src/Discord.Net/Entities/WebSocket/MessageManager.cs rename to src/Discord.Net/Entities/WebSocket/Channels/MessageManager.cs index ea9ec11c8..984e66f92 100644 --- a/src/Discord.Net/Entities/WebSocket/MessageManager.cs +++ b/src/Discord.Net/Entities/WebSocket/Channels/MessageManager.cs @@ -10,36 +10,36 @@ namespace Discord internal class MessageManager { private readonly DiscordSocketClient _discord; - private readonly ICachedMessageChannel _channel; + private readonly ISocketMessageChannel _channel; - public virtual IReadOnlyCollection Messages - => ImmutableArray.Create(); + public virtual IReadOnlyCollection Messages + => ImmutableArray.Create(); - public MessageManager(DiscordSocketClient discord, ICachedMessageChannel channel) + public MessageManager(DiscordSocketClient discord, ISocketMessageChannel channel) { _discord = discord; _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 GetMany(ulong? fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch) - => ImmutableArray.Create(); + public virtual IImmutableList GetMany(ulong? fromMessageId, Direction dir, int limit = DiscordRestConfig.MaxMessagesPerBatch) + => ImmutableArray.Create(); - public virtual async Task DownloadAsync(ulong id) + public virtual async Task DownloadAsync(ulong id) { var model = await _discord.ApiClient.GetChannelMessageAsync(_channel.Id, id).ConfigureAwait(false); 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; } - public async Task> DownloadAsync(ulong? fromId, Direction dir, int limit) + public async Task> DownloadAsync(ulong? fromId, Direction dir, int limit) { //TODO: Test heavily, especially the ordering of messages if (limit < 0) throw new ArgumentOutOfRangeException(nameof(limit)); - if (limit == 0) return ImmutableArray.Empty; + if (limit == 0) return ImmutableArray.Empty; var cachedMessages = GetMany(fromId, dir, limit); if (cachedMessages.Count == limit) @@ -48,20 +48,21 @@ namespace Discord return cachedMessages.Skip(cachedMessages.Count - limit).ToImmutableArray(); else { - Optional relativeId; - if (cachedMessages.Count == 0) - relativeId = fromId ?? new Optional(); - else - relativeId = dir == Direction.Before ? cachedMessages[0].Id : cachedMessages[cachedMessages.Count - 1].Id; var args = new GetChannelMessagesParams { 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 guild = (_channel as ICachedGuildChannel)?.Guild; + var guild = (_channel as ISocketGuildChannel)?.Guild; return cachedMessages.Concat(downloadedMessages.Select(x => { IUser user = _channel.GetUser(x.Author.Value.Id, true); @@ -73,7 +74,7 @@ namespace Discord else user = newUser; } - return new CachedMessage(_channel, user, x); + return new SocketMessage(_channel, user, x); })).ToImmutableArray(); } } diff --git a/src/Discord.Net/Entities/WebSocket/CachedDMChannel.cs b/src/Discord.Net/Entities/WebSocket/Channels/SocketDMChannel.cs similarity index 65% rename from src/Discord.Net/Entities/WebSocket/CachedDMChannel.cs rename to src/Discord.Net/Entities/WebSocket/Channels/SocketDMChannel.cs index 40d0f72c7..bfc0c1c1e 100644 --- a/src/Discord.Net/Entities/WebSocket/CachedDMChannel.cs +++ b/src/Discord.Net/Entities/WebSocket/Channels/SocketDMChannel.cs @@ -6,16 +6,18 @@ using Model = Discord.API.Channel; 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; public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient; - public new CachedDMUser Recipient => base.Recipient as CachedDMUser; - public IReadOnlyCollection Members => ImmutableArray.Create(Discord.CurrentUser, Recipient); - IReadOnlyCollection ICachedPrivateChannel.Recipients => ImmutableArray.Create(Recipient); + public new SocketDMUser Recipient => base.Recipient as SocketDMUser; + public IReadOnlyCollection Users => ImmutableArray.Create(Discord.CurrentUser, Recipient); + IReadOnlyCollection 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) { if (Discord.MessageCacheSize > 0) @@ -25,8 +27,8 @@ namespace Discord } public override Task GetUserAsync(ulong id) => Task.FromResult(GetUser(id)); - public override Task> GetUsersAsync() => Task.FromResult>(Members); - public ICachedUser GetUser(ulong id) + public override Task> GetUsersAsync() => Task.FromResult>(Users); + public ISocketUser GetUser(ulong id) { var currentUser = Discord.CurrentUser; if (id == Recipient.Id) @@ -49,25 +51,25 @@ namespace Discord { 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); return msg; } - public CachedMessage GetMessage(ulong id) + public SocketMessage GetMessage(ulong id) { return _messages.Get(id); } - public CachedMessage RemoveMessage(ulong id) + public SocketMessage RemoveMessage(ulong id) { return _messages.Remove(id); } - public CachedDMChannel Clone() => MemberwiseClone() as CachedDMChannel; + public SocketDMChannel Clone() => MemberwiseClone() as SocketDMChannel; 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(); } } diff --git a/src/Discord.Net/Entities/WebSocket/CachedGroupChannel.cs b/src/Discord.Net/Entities/WebSocket/Channels/SocketGroupChannel.cs similarity index 75% rename from src/Discord.Net/Entities/WebSocket/CachedGroupChannel.cs rename to src/Discord.Net/Entities/WebSocket/Channels/SocketGroupChannel.cs index 783bcd133..f0f15d0c4 100644 --- a/src/Discord.Net/Entities/WebSocket/CachedGroupChannel.cs +++ b/src/Discord.Net/Entities/WebSocket/Channels/SocketGroupChannel.cs @@ -11,17 +11,19 @@ using VoiceStateModel = Discord.API.VoiceState; 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 ConcurrentDictionary _voiceStates; public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient; - public IReadOnlyCollection Members - => _users.Select(x => x.Value as ICachedUser).Concat(ImmutableArray.Create(Discord.CurrentUser)).ToReadOnlyCollection(() => _users.Count + 1); - public new IReadOnlyCollection Recipients => _users.Select(x => x.Value as ICachedUser).ToReadOnlyCollection(_users); + public IReadOnlyCollection Users + => _users.Select(x => x.Value as ISocketUser).Concat(ImmutableArray.Create(Discord.CurrentUser)).ToReadOnlyCollection(() => _users.Count + 1); + public new IReadOnlyCollection 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) { if (Discord.MessageCacheSize > 0) @@ -43,46 +45,46 @@ namespace Discord for (int i = 0; i < models.Length; i++) { 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; } internal override void UpdateUsers(UserModel[] models, UpdateSource source) => UpdateUsers(models, source, Discord.DataStore); - public CachedGroupUser AddUser(UserModel model, DataStore dataStore) + public SocketGroupUser AddUser(UserModel model, DataStore dataStore) { GroupUser user; if (_users.TryGetValue(model.Id, out user)) - return user as CachedGroupUser; + return user as SocketGroupUser; else { var globalUser = Discord.GetOrAddUser(model, dataStore); - var privateUser = new CachedGroupUser(this, globalUser); + var privateUser = new SocketGroupUser(this, globalUser); _users[privateUser.Id] = privateUser; return privateUser; } } - public ICachedUser GetUser(ulong id) + public ISocketUser GetUser(ulong id) { GroupUser user; if (_users.TryGetValue(id, out user)) - return user as CachedGroupUser; + return user as SocketGroupUser; if (id == Discord.CurrentUser.Id) return Discord.CurrentUser; return null; } - public CachedGroupUser RemoveUser(ulong id) + public SocketGroupUser RemoveUser(ulong id) { GroupUser user; if (_users.TryRemove(id, out user)) - return user as CachedGroupUser; + return user as SocketGroupUser; return null; } public VoiceState AddOrUpdateVoiceState(VoiceStateModel model, DataStore dataStore, ConcurrentDictionary 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); (voiceStates ?? _voiceStates)[model.UserId] = voiceState; return voiceState; @@ -114,25 +116,25 @@ namespace Discord { 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); return msg; } - public CachedMessage GetMessage(ulong id) + public SocketMessage GetMessage(ulong id) { return _messages.Get(id); } - public CachedMessage RemoveMessage(ulong id) + public SocketMessage RemoveMessage(ulong id) { return _messages.Remove(id); } - public CachedDMChannel Clone() => MemberwiseClone() as CachedDMChannel; + public SocketDMChannel Clone() => MemberwiseClone() as SocketDMChannel; 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(); } } diff --git a/src/Discord.Net/Entities/WebSocket/CachedTextChannel.cs b/src/Discord.Net/Entities/WebSocket/Channels/SocketTextChannel.cs similarity index 69% rename from src/Discord.Net/Entities/WebSocket/CachedTextChannel.cs rename to src/Discord.Net/Entities/WebSocket/Channels/SocketTextChannel.cs index 48c51c761..0c7d08e43 100644 --- a/src/Discord.Net/Entities/WebSocket/CachedTextChannel.cs +++ b/src/Discord.Net/Entities/WebSocket/Channels/SocketTextChannel.cs @@ -7,17 +7,19 @@ using Model = Discord.API.Channel; namespace Discord { - internal class CachedTextChannel : TextChannel, ICachedGuildChannel, ICachedMessageChannel + internal class SocketTextChannel : TextChannel, ISocketGuildChannel, ISocketMessageChannel { + internal override bool IsAttached => true; + private readonly MessageManager _messages; 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 Members + public IReadOnlyCollection Members => 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) { if (Discord.MessageCacheSize > 0) @@ -28,7 +30,7 @@ namespace Discord public override Task GetUserAsync(ulong id) => Task.FromResult(GetUser(id)); public override Task> GetUsersAsync() => Task.FromResult>(Members); - public CachedGuildUser GetUser(ulong id, bool skipCheck = false) + public SocketGuildUser GetUser(ulong id, bool skipCheck = false) { var user = Guild.GetUser(id); if (skipCheck) return user; @@ -46,36 +48,36 @@ namespace Discord { return await _messages.DownloadAsync(id).ConfigureAwait(false); } - public override async Task> GetMessagesAsync(int limit = DiscordConfig.MaxMessagesPerBatch) + public override async Task> GetMessagesAsync(int limit = DiscordRestConfig.MaxMessagesPerBatch) { return await _messages.DownloadAsync(null, Direction.Before, limit).ConfigureAwait(false); } - public override async Task> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch) + public override async Task> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = DiscordRestConfig.MaxMessagesPerBatch) { 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); return msg; } - public CachedMessage GetMessage(ulong id) + public SocketMessage GetMessage(ulong id) { return _messages.Get(id); } - public CachedMessage RemoveMessage(ulong id) + public SocketMessage RemoveMessage(ulong id) { return _messages.Remove(id); } - public CachedTextChannel Clone() => MemberwiseClone() as CachedTextChannel; + public SocketTextChannel Clone() => MemberwiseClone() as SocketTextChannel; - IReadOnlyCollection ICachedMessageChannel.Members => Members; + IReadOnlyCollection ISocketMessageChannel.Users => Members; 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(); } } diff --git a/src/Discord.Net/Entities/WebSocket/CachedVoiceChannel.cs b/src/Discord.Net/Entities/WebSocket/Channels/SocketVoiceChannel.cs similarity index 81% rename from src/Discord.Net/Entities/WebSocket/CachedVoiceChannel.cs rename to src/Discord.Net/Entities/WebSocket/Channels/SocketVoiceChannel.cs index c0de8915d..f017c1396 100644 --- a/src/Discord.Net/Entities/WebSocket/CachedVoiceChannel.cs +++ b/src/Discord.Net/Entities/WebSocket/Channels/SocketVoiceChannel.cs @@ -8,15 +8,17 @@ using Model = Discord.API.Channel; 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 CachedGuild Guild => base.Guild as CachedGuild; + public new SocketGuild Guild => base.Guild as SocketGuild; public IReadOnlyCollection Members => 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) { } @@ -46,8 +48,8 @@ namespace Discord //TODO: Block and return } - public CachedVoiceChannel Clone() => MemberwiseClone() as CachedVoiceChannel; + public SocketVoiceChannel Clone() => MemberwiseClone() as SocketVoiceChannel; - ICachedChannel ICachedChannel.Clone() => Clone(); + ISocketChannel ISocketChannel.Clone() => Clone(); } } diff --git a/src/Discord.Net/Entities/WebSocket/CachedGuild.cs b/src/Discord.Net/Entities/WebSocket/Guilds/SocketGuild.cs similarity index 86% rename from src/Discord.Net/Entities/WebSocket/CachedGuild.cs rename to src/Discord.Net/Entities/WebSocket/Guilds/SocketGuild.cs index 61e8c635f..befbab3aa 100644 --- a/src/Discord.Net/Entities/WebSocket/CachedGuild.cs +++ b/src/Discord.Net/Entities/WebSocket/Guilds/SocketGuild.cs @@ -19,12 +19,14 @@ using VoiceStateModel = Discord.API.VoiceState; namespace Discord { - internal class CachedGuild : Guild, ICachedEntity, IGuild, IUserGuild + internal class SocketGuild : Guild, IGuild, IUserGuild { + internal override bool IsAttached => true; + private readonly SemaphoreSlim _audioLock; private TaskCompletionSource _syncPromise, _downloaderPromise; private ConcurrentHashSet _channels; - private ConcurrentDictionary _members; + private ConcurrentDictionary _members; private ConcurrentDictionary _voiceStates; internal bool _available; @@ -39,20 +41,20 @@ namespace Discord public Task DownloaderPromise => _downloaderPromise.Task; public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient; - public CachedGuildUser CurrentUser => GetUser(Discord.CurrentUser.Id); - public IReadOnlyCollection Channels + public SocketGuildUser CurrentUser => GetUser(Discord.CurrentUser.Id); + public IReadOnlyCollection Channels { get { var channels = _channels; 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 Members => _members.ToReadOnlyCollection(); + public IReadOnlyCollection Members => _members.ToReadOnlyCollection(); public IEnumerable> 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); _syncPromise = new TaskCompletionSource(); @@ -70,7 +72,7 @@ namespace Discord if (_channels == null) _channels = new ConcurrentHashSet(); if (_members == null) - _members = new ConcurrentDictionary(); + _members = new ConcurrentDictionary(); if (_roles == null) _roles = new ConcurrentDictionary(); if (Emojis == null) @@ -91,7 +93,7 @@ namespace Discord } _channels = channels; - var members = new ConcurrentDictionary(1, (int)(model.Presences.Length * 1.05)); + var members = new ConcurrentDictionary(1, (int)(model.Presences.Length * 1.05)); { DownloadedMemberCount = 0; for (int i = 0; i < model.Members.Length; i++) @@ -119,7 +121,7 @@ namespace Discord { if (source == UpdateSource.Rest && IsAttached) return; - var members = new ConcurrentDictionary(1, (int)(model.Presences.Length * 1.05)); + var members = new ConcurrentDictionary(1, (int)(model.Presences.Length * 1.05)); { DownloadedMemberCount = 0; for (int i = 0; i < model.Members.Length; i++) @@ -152,14 +154,14 @@ namespace Discord (channels ?? _channels).TryAdd(model.Id); 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); - return Discord.DataStore.RemoveChannel(id) as ICachedGuildChannel; + return Discord.DataStore.RemoveChannel(id) as ISocketGuildChannel; } public Role AddRole(RoleModel model, ConcurrentDictionary roles = null) @@ -181,48 +183,48 @@ namespace Discord => Task.FromResult(CurrentUser); public override Task> GetUsersAsync() => Task.FromResult>(Members); - public CachedGuildUser AddUser(MemberModel model, DataStore dataStore, ConcurrentDictionary members = null) + public SocketGuildUser AddUser(MemberModel model, DataStore dataStore, ConcurrentDictionary members = null) { members = members ?? _members; - CachedGuildUser member; + SocketGuildUser member; if (members.TryGetValue(model.User.Id, out member)) member.Update(model, UpdateSource.WebSocket); else { var user = Discord.GetOrAddUser(model.User, dataStore); - member = new CachedGuildUser(this, user, model); + member = new SocketGuildUser(this, user, model); members[user.Id] = member; DownloadedMemberCount++; } return member; } - public CachedGuildUser AddOrUpdateUser(PresenceModel model, DataStore dataStore, ConcurrentDictionary members = null) + public SocketGuildUser AddOrUpdateUser(PresenceModel model, DataStore dataStore, ConcurrentDictionary members = null) { members = members ?? _members; - CachedGuildUser member; + SocketGuildUser member; if (members.TryGetValue(model.User.Id, out member)) member.Update(model, UpdateSource.WebSocket); else { var user = Discord.GetOrAddUser(model.User, dataStore); - member = new CachedGuildUser(this, user, model); + member = new SocketGuildUser(this, user, model); members[user.Id] = member; DownloadedMemberCount++; } return member; } - public CachedGuildUser GetUser(ulong id) + public SocketGuildUser GetUser(ulong id) { - CachedGuildUser member; + SocketGuildUser member; if (_members.TryGetValue(id, out member)) return member; return null; } - public CachedGuildUser RemoveUser(ulong id) + public SocketGuildUser RemoveUser(ulong id) { - CachedGuildUser member; + SocketGuildUser member; if (_members.TryRemove(id, out member)) return member; return null; @@ -238,7 +240,7 @@ namespace Discord public VoiceState AddOrUpdateVoiceState(VoiceStateModel model, DataStore dataStore, ConcurrentDictionary 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); (voiceStates ?? _voiceStates)[model.UserId] = voiceState; return voiceState; @@ -307,16 +309,16 @@ namespace Discord 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) { case ChannelType.Text: - return new CachedTextChannel(this, model); + return new SocketTextChannel(this, model); case ChannelType.Voice: - return new CachedVoiceChannel(this, model); + return new SocketVoiceChannel(this, model); default: throw new InvalidOperationException($"Unexpected channel type: {model.Type}"); } diff --git a/src/Discord.Net/Entities/WebSocket/ICachedEntity.cs b/src/Discord.Net/Entities/WebSocket/ICachedEntity.cs deleted file mode 100644 index 48dc26f2e..000000000 --- a/src/Discord.Net/Entities/WebSocket/ICachedEntity.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Discord -{ - internal interface ICachedEntity : IEntity - { - DiscordSocketClient Discord { get; } - } -} diff --git a/src/Discord.Net/Entities/WebSocket/ICachedGuildChannel.cs b/src/Discord.Net/Entities/WebSocket/ICachedGuildChannel.cs deleted file mode 100644 index 290bff64e..000000000 --- a/src/Discord.Net/Entities/WebSocket/ICachedGuildChannel.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Discord -{ - internal interface ICachedGuildChannel : ICachedChannel, IGuildChannel - { - new CachedGuild Guild { get; } - } -} diff --git a/src/Discord.Net/Entities/WebSocket/ICachedMessageChannel.cs b/src/Discord.Net/Entities/WebSocket/ICachedMessageChannel.cs deleted file mode 100644 index 9704198b0..000000000 --- a/src/Discord.Net/Entities/WebSocket/ICachedMessageChannel.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Collections.Generic; -using MessageModel = Discord.API.Message; - -namespace Discord -{ - internal interface ICachedMessageChannel : ICachedChannel, IMessageChannel - { - IReadOnlyCollection Members { get; } - - CachedMessage AddMessage(ICachedUser author, MessageModel model); - CachedMessage GetMessage(ulong id); - CachedMessage RemoveMessage(ulong id); - - ICachedUser GetUser(ulong id, bool skipCheck = false); - } -} diff --git a/src/Discord.Net/Entities/WebSocket/ICachedPrivateChannel.cs b/src/Discord.Net/Entities/WebSocket/ICachedPrivateChannel.cs deleted file mode 100644 index af2d885be..000000000 --- a/src/Discord.Net/Entities/WebSocket/ICachedPrivateChannel.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Collections.Generic; - -namespace Discord -{ - internal interface ICachedPrivateChannel : ICachedChannel, IPrivateChannel - { - new IReadOnlyCollection Recipients { get; } - } -} diff --git a/src/Discord.Net/Entities/WebSocket/ICachedUser.cs b/src/Discord.Net/Entities/WebSocket/ICachedUser.cs deleted file mode 100644 index fbae8c5ff..000000000 --- a/src/Discord.Net/Entities/WebSocket/ICachedUser.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Discord -{ - internal interface ICachedUser : IUser, ICachedEntity - { - CachedGlobalUser User { get; } - - ICachedUser Clone(); - } -} diff --git a/src/Discord.Net/Entities/WebSocket/Messages/SocketMessage.cs b/src/Discord.Net/Entities/WebSocket/Messages/SocketMessage.cs new file mode 100644 index 000000000..71d73a525 --- /dev/null +++ b/src/Discord.Net/Entities/WebSocket/Messages/SocketMessage.cs @@ -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; + } +} diff --git a/src/Discord.Net/Entities/WebSocket/Users/ISocketUser.cs b/src/Discord.Net/Entities/WebSocket/Users/ISocketUser.cs new file mode 100644 index 000000000..4b0b7bfdf --- /dev/null +++ b/src/Discord.Net/Entities/WebSocket/Users/ISocketUser.cs @@ -0,0 +1,9 @@ +namespace Discord +{ + internal interface ISocketUser : IUser, IEntity + { + SocketGlobalUser User { get; } + + ISocketUser Clone(); + } +} diff --git a/src/Discord.Net/Entities/WebSocket/Presence.cs b/src/Discord.Net/Entities/WebSocket/Users/Presence.cs similarity index 100% rename from src/Discord.Net/Entities/WebSocket/Presence.cs rename to src/Discord.Net/Entities/WebSocket/Users/Presence.cs diff --git a/src/Discord.Net/Entities/WebSocket/CachedDMUser.cs b/src/Discord.Net/Entities/WebSocket/Users/SocketDMUser.cs similarity index 76% rename from src/Discord.Net/Entities/WebSocket/CachedDMUser.cs rename to src/Discord.Net/Entities/WebSocket/Users/SocketDMUser.cs index bb0a56198..e56dd53ee 100644 --- a/src/Discord.Net/Entities/WebSocket/CachedDMUser.cs +++ b/src/Discord.Net/Entities/WebSocket/Users/SocketDMUser.cs @@ -5,9 +5,12 @@ using PresenceModel = Discord.API.Presence; namespace Discord { [DebuggerDisplay("{DebuggerDisplay,nq}")] - internal class CachedDMUser : ICachedUser + internal class SocketDMUser : ISocketUser { - public CachedGlobalUser User { get; } + internal bool IsAttached => true; + bool IEntity.IsAttached => IsAttached; + + public SocketGlobalUser User { get; } public DiscordSocketClient Discord => User.Discord; @@ -20,12 +23,11 @@ namespace Discord public DateTimeOffset CreatedAt => User.CreatedAt; public string Discriminator => User.Discriminator; public ushort DiscriminatorValue => User.DiscriminatorValue; - public bool IsAttached => User.IsAttached; public bool IsBot => User.IsBot; public string Mention => MentionUtils.Mention(this); public string Username => User.Username; - public CachedDMUser(CachedGlobalUser user) + public SocketDMUser(SocketGlobalUser user) { User = user; } @@ -35,8 +37,8 @@ namespace Discord 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}"; private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id})"; diff --git a/src/Discord.Net/Entities/WebSocket/CachedGlobalUser.cs b/src/Discord.Net/Entities/WebSocket/Users/SocketGlobalUser.cs similarity index 79% rename from src/Discord.Net/Entities/WebSocket/CachedGlobalUser.cs rename to src/Discord.Net/Entities/WebSocket/Users/SocketGlobalUser.cs index 7f09bf6e7..96bbdd556 100644 --- a/src/Discord.Net/Entities/WebSocket/CachedGlobalUser.cs +++ b/src/Discord.Net/Entities/WebSocket/Users/SocketGlobalUser.cs @@ -4,16 +4,18 @@ using PresenceModel = Discord.API.Presence; namespace Discord { - internal class CachedGlobalUser : User, ICachedUser + internal class SocketGlobalUser : User, ISocketUser { + internal override bool IsAttached => true; + private ushort _references; public Presence Presence { get; private set; } 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) { } @@ -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(); } } diff --git a/src/Discord.Net/Entities/WebSocket/CachedGroupUser.cs b/src/Discord.Net/Entities/WebSocket/Users/SocketGroupUser.cs similarity index 62% rename from src/Discord.Net/Entities/WebSocket/CachedGroupUser.cs rename to src/Discord.Net/Entities/WebSocket/Users/SocketGroupUser.cs index 8735bbd11..0de43c9b9 100644 --- a/src/Discord.Net/Entities/WebSocket/CachedGroupUser.cs +++ b/src/Discord.Net/Entities/WebSocket/Users/SocketGroupUser.cs @@ -3,11 +3,13 @@ namespace Discord { [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 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 override Game Game => Presence.Game; @@ -17,15 +19,15 @@ namespace Discord public bool IsSelfDeafened => VoiceState?.IsSelfDeafened ?? false; public bool IsSelfMuted => VoiceState?.IsSelfMuted ?? 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) { } - 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}"; private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id})"; diff --git a/src/Discord.Net/Entities/WebSocket/CachedGuildUser.cs b/src/Discord.Net/Entities/WebSocket/Users/SocketGuildUser.cs similarity index 69% rename from src/Discord.Net/Entities/WebSocket/CachedGuildUser.cs rename to src/Discord.Net/Entities/WebSocket/Users/SocketGuildUser.cs index d165f43c2..a2fe29d46 100644 --- a/src/Discord.Net/Entities/WebSocket/CachedGuildUser.cs +++ b/src/Discord.Net/Entities/WebSocket/Users/SocketGuildUser.cs @@ -3,11 +3,13 @@ using PresenceModel = Discord.API.Presence; 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 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 override Game Game => Presence.Game; @@ -17,14 +19,14 @@ namespace Discord public bool IsSelfDeafened => VoiceState?.IsSelfDeafened ?? false; public bool IsSelfMuted => VoiceState?.IsSelfMuted ?? 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) { //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) { } @@ -39,7 +41,7 @@ namespace Discord User.Update(model, source); } - public CachedGuildUser Clone() => MemberwiseClone() as CachedGuildUser; - ICachedUser ICachedUser.Clone() => Clone(); + public SocketGuildUser Clone() => MemberwiseClone() as SocketGuildUser; + ISocketUser ISocketUser.Clone() => Clone(); } } diff --git a/src/Discord.Net/Entities/WebSocket/Users/SocketSelfUser.cs b/src/Discord.Net/Entities/WebSocket/Users/SocketSelfUser.cs new file mode 100644 index 000000000..a4a6aa733 --- /dev/null +++ b/src/Discord.Net/Entities/WebSocket/Users/SocketSelfUser.cs @@ -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(); + } +} diff --git a/src/Discord.Net/Entities/WebSocket/VoiceState.cs b/src/Discord.Net/Entities/WebSocket/Users/VoiceState.cs similarity index 89% rename from src/Discord.Net/Entities/WebSocket/VoiceState.cs rename to src/Discord.Net/Entities/WebSocket/Users/VoiceState.cs index 275108476..138c025a8 100644 --- a/src/Discord.Net/Entities/WebSocket/VoiceState.cs +++ b/src/Discord.Net/Entities/WebSocket/Users/VoiceState.cs @@ -19,7 +19,7 @@ namespace Discord private readonly Flags _voiceStates; - public CachedVoiceChannel VoiceChannel { get; } + public SocketVoiceChannel VoiceChannel { get; } public string VoiceSessionId { get; } public bool IsMuted => (_voiceStates & Flags.Muted) != 0; @@ -28,9 +28,9 @@ namespace Discord public bool IsSelfMuted => (_voiceStates & Flags.SelfMuted) != 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) { } - 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; VoiceSessionId = sessionId; diff --git a/src/Discord.Net/Extensions/DiscordClientExtensions.cs b/src/Discord.Net/Extensions/DiscordClientExtensions.cs index 53e09c0e0..dcde721d5 100644 --- a/src/Discord.Net/Extensions/DiscordClientExtensions.cs +++ b/src/Discord.Net/Extensions/DiscordClientExtensions.cs @@ -5,7 +5,7 @@ namespace Discord.Extensions { public static class DiscordClientExtensions { - public static async Task GetOptimalVoiceRegionAsync(this DiscordClient discord) + public static async Task GetOptimalVoiceRegionAsync(this DiscordRestClient discord) { var regions = await discord.GetVoiceRegionsAsync().ConfigureAwait(false); return regions.FirstOrDefault(x => x.IsOptimal); diff --git a/src/Discord.Net/Extensions/GuildUserExtensions.cs b/src/Discord.Net/Extensions/GuildUserExtensions.cs index 9575e66dc..357a4955f 100644 --- a/src/Discord.Net/Extensions/GuildUserExtensions.cs +++ b/src/Discord.Net/Extensions/GuildUserExtensions.cs @@ -9,11 +9,11 @@ namespace Discord.Extensions public static Task AddRolesAsync(this IGuildUser user, params IRole[] roles) => AddRolesAsync(user, (IEnumerable)roles); public static Task AddRolesAsync(this IGuildUser user, IEnumerable 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) => RemoveRolesAsync(user, (IEnumerable)roles); public static Task RemoveRolesAsync(this IGuildUser user, IEnumerable roles) - => user.ModifyAsync(x => x.Roles = Optional.Create(user.Roles.Except(roles))); + => user.ModifyAsync(x => x.Roles = user.Roles.Except(roles)); } } diff --git a/src/Discord.Net/IDiscordClient.cs b/src/Discord.Net/IDiscordClient.cs index 9cc5c79d2..87034d2c1 100644 --- a/src/Discord.Net/IDiscordClient.cs +++ b/src/Discord.Net/IDiscordClient.cs @@ -11,14 +11,10 @@ namespace Discord //TODO: Docstrings should explain when REST requests are sent and how many public interface IDiscordClient : IDisposable { - LoginState LoginState { get; } ConnectionState ConnectionState { get; } DiscordApiClient ApiClient { get; } ILogManager LogManager { get; } - - Task LoginAsync(TokenType tokenType, string token, bool validateToken = true); - Task LogoutAsync(); Task ConnectAsync(); Task DisconnectAsync();