@@ -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]); | ||||