| @@ -155,7 +155,7 @@ namespace Discord.API | |||||
| } | } | ||||
| private async Task LogoutInternalAsync() | private async Task LogoutInternalAsync() | ||||
| { | { | ||||
| //TODO: An exception here will lock the client into the unusable LoggingOut state. How should we handle? (Add same solution to both DiscordClients too) | |||||
| //An exception here will lock the client into the unusable LoggingOut state, but that's probably fine since our client is in an undefined state too. | |||||
| if (LoginState == LoginState.LoggedOut) return; | if (LoginState == LoginState.LoggedOut) return; | ||||
| LoginState = LoginState.LoggingOut; | LoginState = LoginState.LoggingOut; | ||||
| @@ -41,8 +41,7 @@ namespace Discord | |||||
| _connectionLock = new SemaphoreSlim(1, 1); | _connectionLock = new SemaphoreSlim(1, 1); | ||||
| _requestQueue = new RequestQueue(); | _requestQueue = new RequestQueue(); | ||||
| //TODO: Is there any better way to do this WebSocketProvider access? | |||||
| ApiClient = new API.DiscordApiClient(config.RestClientProvider, (config as DiscordSocketConfig)?.WebSocketProvider, requestQueue: _requestQueue); | ApiClient = new API.DiscordApiClient(config.RestClientProvider, (config as DiscordSocketConfig)?.WebSocketProvider, requestQueue: _requestQueue); | ||||
| ApiClient.SentRequest += async (method, endpoint, millis) => await _log.VerboseAsync("Rest", $"{method} {endpoint}: {millis} ms").ConfigureAwait(false); | ApiClient.SentRequest += async (method, endpoint, millis) => await _log.VerboseAsync("Rest", $"{method} {endpoint}: {millis} ms").ConfigureAwait(false); | ||||
| } | } | ||||
| @@ -3,8 +3,6 @@ using System.Reflection; | |||||
| namespace Discord | namespace Discord | ||||
| { | { | ||||
| //TODO: Add socket config items in their own class | |||||
| public class DiscordConfig | public class DiscordConfig | ||||
| { | { | ||||
| public static string Version { get; } = typeof(DiscordConfig).GetTypeInfo().Assembly?.GetName().Version.ToString(3) ?? "Unknown"; | public static string Version { get; } = typeof(DiscordConfig).GetTypeInfo().Assembly?.GetName().Version.ToString(3) ?? "Unknown"; | ||||
| @@ -361,8 +361,7 @@ namespace Discord | |||||
| case "READY": | case "READY": | ||||
| { | { | ||||
| await _gatewayLogger.DebugAsync("Received Dispatch (READY)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Received Dispatch (READY)").ConfigureAwait(false); | ||||
| //TODO: Make downloading large guilds optional | |||||
| var data = (payload as JToken).ToObject<ReadyEvent>(_serializer); | var data = (payload as JToken).ToObject<ReadyEvent>(_serializer); | ||||
| var dataStore = _dataStoreProvider(ShardId, _totalShards, data.Guilds.Length, data.PrivateChannels.Length); | var dataStore = _dataStoreProvider(ShardId, _totalShards, data.Guilds.Length, data.PrivateChannels.Length); | ||||
| @@ -741,7 +740,7 @@ namespace Discord | |||||
| var channel = DataStore.GetChannel(data.ChannelId) as ICachedMessageChannel; | var channel = DataStore.GetChannel(data.ChannelId) as ICachedMessageChannel; | ||||
| if (channel != null) | if (channel != null) | ||||
| { | { | ||||
| var author = channel.GetUser(data.Author.Value.Id); | |||||
| var author = channel.GetUser(data.Author.Value.Id, true); | |||||
| if (author != null) | if (author != null) | ||||
| { | { | ||||
| @@ -780,7 +779,7 @@ namespace Discord | |||||
| else if (data.Author.IsSpecified) | else if (data.Author.IsSpecified) | ||||
| { | { | ||||
| //Edited message isnt in cache, create a detached one | //Edited message isnt in cache, create a detached one | ||||
| var author = channel.GetUser(data.Author.Value.Id); | |||||
| var author = channel.GetUser(data.Author.Value.Id, true); | |||||
| if (author != null) | if (author != null) | ||||
| after = new Message(channel, author, data); | after = new Message(channel, author, data); | ||||
| } | } | ||||
| @@ -879,7 +878,7 @@ namespace Discord | |||||
| var channel = DataStore.GetChannel(data.ChannelId) as ICachedMessageChannel; | var channel = DataStore.GetChannel(data.ChannelId) as ICachedMessageChannel; | ||||
| if (channel != null) | if (channel != null) | ||||
| { | { | ||||
| var user = channel.GetUser(data.UserId); | |||||
| var user = channel.GetUser(data.UserId, true); | |||||
| if (user != null) | if (user != null) | ||||
| await UserIsTyping.RaiseAsync(channel, user).ConfigureAwait(false); | await UserIsTyping.RaiseAsync(channel, user).ConfigureAwait(false); | ||||
| } | } | ||||
| @@ -130,7 +130,6 @@ namespace Discord | |||||
| } | } | ||||
| public async Task ModifyChannelsAsync(IEnumerable<ModifyGuildChannelsParams> args) | public async Task ModifyChannelsAsync(IEnumerable<ModifyGuildChannelsParams> args) | ||||
| { | { | ||||
| //TODO: Update channels | |||||
| await Discord.ApiClient.ModifyGuildChannelsAsync(Id, args).ConfigureAwait(false); | await Discord.ApiClient.ModifyGuildChannelsAsync(Id, args).ConfigureAwait(false); | ||||
| } | } | ||||
| public async Task ModifyRolesAsync(IEnumerable<ModifyGuildRolesParams> args) | public async Task ModifyRolesAsync(IEnumerable<ModifyGuildRolesParams> args) | ||||
| @@ -131,7 +131,7 @@ namespace Discord | |||||
| if (perms != null) | if (perms != null) | ||||
| resolvedPermissions = (resolvedPermissions & ~perms.Value.DenyValue) | perms.Value.AllowValue; | resolvedPermissions = (resolvedPermissions & ~perms.Value.DenyValue) | perms.Value.AllowValue; | ||||
| //TODO: C# Typeswitch candidate | |||||
| //TODO: C#7 Typeswitch candidate | |||||
| var textChannel = channel as ITextChannel; | var textChannel = channel as ITextChannel; | ||||
| var voiceChannel = channel as IVoiceChannel; | var voiceChannel = channel as IVoiceChannel; | ||||
| if (textChannel != null && !GetValue(resolvedPermissions, ChannelPermission.ReadMessages)) | if (textChannel != null && !GetValue(resolvedPermissions, ChannelPermission.ReadMessages)) | ||||
| @@ -4,7 +4,7 @@ namespace Discord | |||||
| { | { | ||||
| internal abstract class SnowflakeEntity : Entity<ulong>, ISnowflakeEntity | internal abstract class SnowflakeEntity : Entity<ulong>, ISnowflakeEntity | ||||
| { | { | ||||
| //TODO: Candidate for Extension Property. Lets us remove this class. | |||||
| //TODO: C#7 Candidate for Extension Property. Lets us remove this class. | |||||
| public DateTime CreatedAt => DateTimeUtils.FromSnowflake(Id); | public DateTime CreatedAt => DateTimeUtils.FromSnowflake(Id); | ||||
| public SnowflakeEntity(ulong id) | public SnowflakeEntity(ulong id) | ||||
| @@ -12,8 +12,7 @@ namespace Discord | |||||
| bool IsBot { get; } | bool IsBot { get; } | ||||
| /// <summary> Gets the username for this user. </summary> | /// <summary> Gets the username for this user. </summary> | ||||
| string Username { get; } | string Username { get; } | ||||
| //TODO: CreateDMChannel is a candidate to move to IGuildUser, and User made a common class, depending on next friends list update | |||||
| /// <summary> Returns a private message channel to this user, creating one if it does not already exist. </summary> | /// <summary> Returns a private message channel to this user, creating one if it does not already exist. </summary> | ||||
| Task<IDMChannel> CreateDMChannelAsync(); | Task<IDMChannel> CreateDMChannelAsync(); | ||||
| } | } | ||||
| @@ -66,6 +66,7 @@ namespace Discord | |||||
| public CachedDMChannel Clone() => MemberwiseClone() as CachedDMChannel; | public CachedDMChannel Clone() => MemberwiseClone() as CachedDMChannel; | ||||
| IMessage IMessageChannel.GetCachedMessage(ulong id) => GetMessage(id); | IMessage IMessageChannel.GetCachedMessage(ulong id) => GetMessage(id); | ||||
| ICachedUser ICachedMessageChannel.GetUser(ulong id, bool skipCheck) => GetUser(id); | |||||
| ICachedChannel ICachedChannel.Clone() => Clone(); | ICachedChannel ICachedChannel.Clone() => Clone(); | ||||
| } | } | ||||
| } | } | ||||
| @@ -27,12 +27,15 @@ namespace Discord | |||||
| public override Task<IReadOnlyCollection<IGuildUser>> GetUsersAsync() => Task.FromResult<IReadOnlyCollection<IGuildUser>>(Members); | public override Task<IReadOnlyCollection<IGuildUser>> GetUsersAsync() => Task.FromResult<IReadOnlyCollection<IGuildUser>>(Members); | ||||
| public override Task<IReadOnlyCollection<IGuildUser>> GetUsersAsync(int limit, int offset) | public override Task<IReadOnlyCollection<IGuildUser>> GetUsersAsync(int limit, int offset) | ||||
| => Task.FromResult<IReadOnlyCollection<IGuildUser>>(Members.Skip(offset).Take(limit).ToImmutableArray()); | => Task.FromResult<IReadOnlyCollection<IGuildUser>>(Members.Skip(offset).Take(limit).ToImmutableArray()); | ||||
| public CachedGuildUser GetUser(ulong id) | |||||
| public CachedGuildUser GetUser(ulong id, bool skipCheck = false) | |||||
| { | { | ||||
| //TODO: It's slow to do a perms check here... Maybe only do it on external calls? | |||||
| var user = Guild.GetUser(id); | var user = Guild.GetUser(id); | ||||
| if (user != null && Permissions.GetValue(Permissions.ResolveChannel(user, this, user.GuildPermissions.RawValue), ChannelPermission.ReadMessages)) | |||||
| return user; | |||||
| if (user != null && !skipCheck) | |||||
| { | |||||
| ulong perms = Permissions.ResolveChannel(user, this, user.GuildPermissions.RawValue); | |||||
| if (Permissions.GetValue(perms, ChannelPermission.ReadMessages)) | |||||
| return user; | |||||
| } | |||||
| return null; | return null; | ||||
| } | } | ||||
| @@ -69,7 +72,7 @@ namespace Discord | |||||
| IReadOnlyCollection<ICachedUser> ICachedMessageChannel.Members => Members; | IReadOnlyCollection<ICachedUser> ICachedMessageChannel.Members => Members; | ||||
| IMessage IMessageChannel.GetCachedMessage(ulong id) => GetMessage(id); | IMessage IMessageChannel.GetCachedMessage(ulong id) => GetMessage(id); | ||||
| ICachedUser ICachedMessageChannel.GetUser(ulong id) => GetUser(id); | |||||
| ICachedUser ICachedMessageChannel.GetUser(ulong id, bool skipCheck) => GetUser(id, skipCheck); | |||||
| ICachedChannel ICachedChannel.Clone() => Clone(); | ICachedChannel ICachedChannel.Clone() => Clone(); | ||||
| } | } | ||||
| } | } | ||||
| @@ -11,6 +11,6 @@ namespace Discord | |||||
| CachedMessage GetMessage(ulong id); | CachedMessage GetMessage(ulong id); | ||||
| CachedMessage RemoveMessage(ulong id); | CachedMessage RemoveMessage(ulong id); | ||||
| ICachedUser GetUser(ulong id); | |||||
| ICachedUser GetUser(ulong id, bool skipCheck = false); | |||||
| } | } | ||||
| } | } | ||||
| @@ -120,7 +120,7 @@ namespace Discord | |||||
| var guild = (_channel as ICachedGuildChannel).Guild; | var guild = (_channel as ICachedGuildChannel).Guild; | ||||
| return cachedMessages.Concat(downloadedMessages.Select(x => | return cachedMessages.Concat(downloadedMessages.Select(x => | ||||
| { | { | ||||
| IUser user = _channel.GetUser(x.Author.Value.Id); | |||||
| IUser user = _channel.GetUser(x.Author.Value.Id, true); | |||||
| if (user == null) | if (user == null) | ||||
| { | { | ||||
| var newUser = new User(_channel.Discord, x.Author.Value); | var newUser = new User(_channel.Discord, x.Author.Value); | ||||
| @@ -92,7 +92,7 @@ namespace Discord.Net.Rest | |||||
| { | { | ||||
| foreach (var p in multipartParams) | foreach (var p in multipartParams) | ||||
| { | { | ||||
| //TODO: C# Typeswitch candidate | |||||
| //TODO: C#7 Typeswitch candidate | |||||
| var stringValue = p.Value as string; | var stringValue = p.Value as string; | ||||
| if (stringValue != null) { content.Add(new StringContent(stringValue), p.Key); continue; } | if (stringValue != null) { content.Add(new StringContent(stringValue), p.Key); continue; } | ||||
| var byteArrayValue = p.Value as byte[]; | var byteArrayValue = p.Value as byte[]; | ||||
| @@ -124,8 +124,7 @@ namespace Discord.Net.WebSockets | |||||
| _sendLock.Release(); | _sendLock.Release(); | ||||
| } | } | ||||
| } | } | ||||
| //TODO: Check this code | |||||
| private async Task RunAsync(CancellationToken cancelToken) | private async Task RunAsync(CancellationToken cancelToken) | ||||
| { | { | ||||
| var buffer = new ArraySegment<byte>(new byte[ReceiveChunkSize]); | var buffer = new ArraySegment<byte>(new byte[ReceiveChunkSize]); | ||||