| @@ -60,15 +60,18 @@ namespace Discord.Collections | |||||
| _dictionary = new ConcurrentDictionary<string, TValue>(); | _dictionary = new ConcurrentDictionary<string, TValue>(); | ||||
| } | } | ||||
| protected TValue Get(string key) | |||||
| public TValue this[string key] | |||||
| { | { | ||||
| if (key == null) | |||||
| return null; | |||||
| get | |||||
| { | |||||
| if (key == null) | |||||
| return null; | |||||
| TValue result; | |||||
| if (!_dictionary.TryGetValue(key, out result)) | |||||
| return null; | |||||
| return result; | |||||
| TValue result; | |||||
| if (!_dictionary.TryGetValue(key, out result)) | |||||
| return null; | |||||
| return result; | |||||
| } | |||||
| } | } | ||||
| protected TValue GetOrAdd(string key, Func<TValue> createFunc) | protected TValue GetOrAdd(string key, Func<TValue> createFunc) | ||||
| { | { | ||||
| @@ -88,7 +91,7 @@ namespace Discord.Collections | |||||
| } | } | ||||
| return result; | return result; | ||||
| } | } | ||||
| protected TValue TryRemove(string key) | |||||
| public TValue TryRemove(string key) | |||||
| { | { | ||||
| if (_dictionary.ContainsKey(key)) | if (_dictionary.ContainsKey(key)) | ||||
| { | { | ||||
| @@ -104,7 +107,7 @@ namespace Discord.Collections | |||||
| } | } | ||||
| return null; | return null; | ||||
| } | } | ||||
| protected TValue Remap(string oldKey, string newKey) | |||||
| public TValue Remap(string oldKey, string newKey) | |||||
| { | { | ||||
| if (_dictionary.ContainsKey(oldKey)) | if (_dictionary.ContainsKey(oldKey)) | ||||
| { | { | ||||
| @@ -2,13 +2,13 @@ | |||||
| namespace Discord.Collections | namespace Discord.Collections | ||||
| { | { | ||||
| public sealed class Channels : AsyncCollection<Channel> | |||||
| { | |||||
| internal Channels(DiscordClient client, object writerLock) | |||||
| internal sealed class Channels : AsyncCollection<Channel> | |||||
| { | |||||
| public Channels(DiscordClient client, object writerLock) | |||||
| : base(client, writerLock) { } | : base(client, writerLock) { } | ||||
| internal Channel GetOrAdd(string id, string serverId, string recipientId = null) => GetOrAdd(id, () => new Channel(_client, id, serverId, recipientId)); | |||||
| internal new Channel TryRemove(string id) => base.TryRemove(id); | |||||
| public Channel GetOrAdd(string id, string serverId, string recipientId = null) | |||||
| => GetOrAdd(id, () => new Channel(_client, id, serverId, recipientId)); | |||||
| protected override void OnCreated(Channel item) | protected override void OnCreated(Channel item) | ||||
| { | { | ||||
| @@ -43,14 +43,5 @@ namespace Discord.Collections | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| internal Channel this[string id] | |||||
| { | |||||
| get | |||||
| { | |||||
| if (id == null) throw new ArgumentNullException(nameof(id)); | |||||
| return Get(id); | |||||
| } | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,16 +1,18 @@ | |||||
| using System; | |||||
| namespace Discord.Collections | |||||
| namespace Discord.Collections | |||||
| { | { | ||||
| public sealed class Members : AsyncCollection<Member> | |||||
| internal sealed class Members : AsyncCollection<Member> | |||||
| { | { | ||||
| internal Members(DiscordClient client, object writerLock) | |||||
| public Members(DiscordClient client, object writerLock) | |||||
| : base(client, writerLock) { } | : base(client, writerLock) { } | ||||
| private string GetKey(string userId, string serverId) | |||||
| => serverId + '_' + userId; | |||||
| private string GetKey(string userId, string serverId) => serverId + '_' + userId; | |||||
| internal Member GetOrAdd(string userId, string serverId) => GetOrAdd(GetKey(userId, serverId), () => new Member(_client, userId, serverId)); | |||||
| internal Member TryRemove(string userId, string serverId) => base.TryRemove(GetKey(userId, serverId)); | |||||
| public Member this[string userId, string serverId] | |||||
| => this[GetKey(userId, serverId)]; | |||||
| public Member GetOrAdd(string userId, string serverId) | |||||
| => GetOrAdd(GetKey(userId, serverId), () => new Member(_client, userId, serverId)); | |||||
| public Member TryRemove(string userId, string serverId) | |||||
| => TryRemove(GetKey(userId, serverId)); | |||||
| protected override void OnCreated(Member item) | protected override void OnCreated(Member item) | ||||
| { | { | ||||
| @@ -36,15 +38,5 @@ namespace Discord.Collections | |||||
| user.RemoveRef(); | user.RemoveRef(); | ||||
| } | } | ||||
| } | } | ||||
| internal Member this[string userId, string serverId] | |||||
| { | |||||
| get | |||||
| { | |||||
| if (serverId == null) throw new ArgumentNullException(nameof(serverId)); | |||||
| if (userId == null) throw new ArgumentNullException(nameof(userId)); | |||||
| return Get(GetKey(userId, serverId)); | |||||
| } | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,15 +1,12 @@ | |||||
| using System; | |||||
| namespace Discord.Collections | |||||
| namespace Discord.Collections | |||||
| { | { | ||||
| public sealed class Messages : AsyncCollection<Message> | |||||
| internal sealed class Messages : AsyncCollection<Message> | |||||
| { | { | ||||
| internal Messages(DiscordClient client, object writerLock) | |||||
| public Messages(DiscordClient client, object writerLock) | |||||
| : base(client, writerLock) { } | : base(client, writerLock) { } | ||||
| internal Message GetOrAdd(string id, string channelId, string userId) => GetOrAdd(id, () => new Message(_client, id, channelId, userId)); | |||||
| internal new Message TryRemove(string id) => base.TryRemove(id); | |||||
| internal new Message Remap(string oldKey, string newKey) => base.Remap(oldKey, newKey); | |||||
| public Message GetOrAdd(string id, string channelId, string userId) | |||||
| => GetOrAdd(id, () => new Message(_client, id, channelId, userId)); | |||||
| protected override void OnCreated(Message item) | protected override void OnCreated(Message item) | ||||
| { | { | ||||
| @@ -25,14 +22,5 @@ namespace Discord.Collections | |||||
| if (user != null) | if (user != null) | ||||
| user.RemoveRef(); | user.RemoveRef(); | ||||
| } | } | ||||
| internal Message this[string id] | |||||
| { | |||||
| get | |||||
| { | |||||
| if (id == null) throw new ArgumentNullException(nameof(id)); | |||||
| return Get(id); | |||||
| } | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,14 +1,12 @@ | |||||
| using System; | |||||
| namespace Discord.Collections | |||||
| namespace Discord.Collections | |||||
| { | { | ||||
| public sealed class Roles : AsyncCollection<Role> | |||||
| internal sealed class Roles : AsyncCollection<Role> | |||||
| { | { | ||||
| internal Roles(DiscordClient client, object writerLock) | |||||
| public Roles(DiscordClient client, object writerLock) | |||||
| : base(client, writerLock) { } | : base(client, writerLock) { } | ||||
| internal Role GetOrAdd(string id, string serverId) => GetOrAdd(id, () => new Role(_client, id, serverId)); | |||||
| internal new Role TryRemove(string id) => base.TryRemove(id); | |||||
| public Role GetOrAdd(string id, string serverId) | |||||
| => GetOrAdd(id, () => new Role(_client, id, serverId)); | |||||
| protected override void OnCreated(Role item) | protected override void OnCreated(Role item) | ||||
| { | { | ||||
| @@ -20,14 +18,5 @@ namespace Discord.Collections | |||||
| if (server != null) | if (server != null) | ||||
| item.Server.RemoveRole(item.Id); | item.Server.RemoveRole(item.Id); | ||||
| } | } | ||||
| internal Role this[string id] | |||||
| { | |||||
| get | |||||
| { | |||||
| if (id == null) throw new ArgumentNullException(nameof(id)); | |||||
| return Get(id); | |||||
| } | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -4,13 +4,13 @@ using System.Linq; | |||||
| namespace Discord.Collections | namespace Discord.Collections | ||||
| { | { | ||||
| public sealed class Servers : AsyncCollection<Server> | |||||
| internal sealed class Servers : AsyncCollection<Server> | |||||
| { | { | ||||
| internal Servers(DiscordClient client, object writerLock) | |||||
| public Servers(DiscordClient client, object writerLock) | |||||
| : base(client, writerLock) { } | : base(client, writerLock) { } | ||||
| internal Server GetOrAdd(string id) => base.GetOrAdd(id, () => new Server(_client, id)); | |||||
| internal new Server TryRemove(string id) => base.TryRemove(id); | |||||
| public Server GetOrAdd(string id) | |||||
| => base.GetOrAdd(id, () => new Server(_client, id)); | |||||
| protected override void OnRemoved(Server item) | protected override void OnRemoved(Server item) | ||||
| { | { | ||||
| @@ -26,7 +26,5 @@ namespace Discord.Collections | |||||
| foreach (var roleId in item.RoleIds) | foreach (var roleId in item.RoleIds) | ||||
| roles.TryRemove(roleId); | roles.TryRemove(roleId); | ||||
| } | } | ||||
| internal Server this[string id] => Get(id); | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,25 +1,10 @@ | |||||
| using System; | |||||
| namespace Discord.Collections | |||||
| namespace Discord.Collections | |||||
| { | { | ||||
| public sealed class Users : AsyncCollection<User> | |||||
| internal sealed class Users : AsyncCollection<User> | |||||
| { | { | ||||
| internal Users(DiscordClient client, object writerLock) | |||||
| public Users(DiscordClient client, object writerLock) | |||||
| : base(client, writerLock) { } | : base(client, writerLock) { } | ||||
| internal User GetOrAdd(string id) => GetOrAdd(id, () => new User(_client, id)); | |||||
| internal new User TryRemove(string id) => base.TryRemove(id); | |||||
| protected override void OnCreated(User item) { } | |||||
| protected override void OnRemoved(User item) { } | |||||
| internal User this[string id] | |||||
| { | |||||
| get | |||||
| { | |||||
| if (id == null) throw new ArgumentNullException(nameof(id)); | |||||
| return Get(id); | |||||
| } | |||||
| } | |||||
| public User GetOrAdd(string id) => GetOrAdd(id, () => new User(_client, id)); | |||||
| } | } | ||||
| } | } | ||||
| @@ -20,8 +20,7 @@ namespace Discord | |||||
| public partial class DiscordClient | public partial class DiscordClient | ||||
| { | { | ||||
| /// <summary> Returns a collection of all channels this client is a member of. </summary> | |||||
| public Channels Channels => _channels; | |||||
| internal Channels Channels => _channels; | |||||
| private readonly Channels _channels; | private readonly Channels _channels; | ||||
| public event EventHandler<ChannelEventArgs> ChannelCreated; | public event EventHandler<ChannelEventArgs> ChannelCreated; | ||||
| @@ -7,6 +7,19 @@ namespace Discord | |||||
| { | { | ||||
| public partial class DiscordClient | public partial class DiscordClient | ||||
| { | { | ||||
| /// <summary> Gets more info about the provided invite code. </summary> | |||||
| /// <remarks> Supported formats: inviteCode, xkcdCode, https://discord.gg/inviteCode, https://discord.gg/xkcdCode </remarks> | |||||
| public async Task<Invite> GetInvite(string inviteIdOrXkcd) | |||||
| { | |||||
| CheckReady(); | |||||
| if (inviteIdOrXkcd == null) throw new ArgumentNullException(nameof(inviteIdOrXkcd)); | |||||
| var response = await _api.GetInvite(inviteIdOrXkcd).ConfigureAwait(false); | |||||
| var invite = new Invite(this, response.Code, response.XkcdPass, response.Guild.Id); | |||||
| invite.Update(response); | |||||
| return invite; | |||||
| } | |||||
| /// <summary> Creates a new invite to the default channel of the provided server. </summary> | /// <summary> Creates a new invite to the default channel of the provided server. </summary> | ||||
| /// <param name="maxAge"> Time (in seconds) until the invite expires. Set to 0 to never expire. </param> | /// <param name="maxAge"> Time (in seconds) until the invite expires. Set to 0 to never expire. </param> | ||||
| /// <param name="tempMembership"> If true, a user accepting this invite will be kicked from the server after closing their client. </param> | /// <param name="tempMembership"> If true, a user accepting this invite will be kicked from the server after closing their client. </param> | ||||
| @@ -53,20 +66,7 @@ namespace Discord | |||||
| } | } | ||||
| catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } | catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } | ||||
| } | } | ||||
| /// <summary> Gets more info about the provided invite code. </summary> | |||||
| /// <remarks> Supported formats: inviteCode, xkcdCode, https://discord.gg/inviteCode, https://discord.gg/xkcdCode </remarks> | |||||
| public async Task<Invite> GetInvite(string inviteIdOrXkcd) | |||||
| { | |||||
| CheckReady(); | |||||
| if (inviteIdOrXkcd == null) throw new ArgumentNullException(nameof(inviteIdOrXkcd)); | |||||
| var response = await _api.GetInvite(inviteIdOrXkcd).ConfigureAwait(false); | |||||
| var invite = new Invite(this, response.Code, response.XkcdPass, response.Guild.Id); | |||||
| invite.Update(response); | |||||
| return invite; | |||||
| } | |||||
| /// <summary> Accepts the provided invite. </summary> | /// <summary> Accepts the provided invite. </summary> | ||||
| public Task AcceptInvite(Invite invite) | public Task AcceptInvite(Invite invite) | ||||
| { | { | ||||
| @@ -55,9 +55,8 @@ namespace Discord | |||||
| if (UserIsSpeaking != null) | if (UserIsSpeaking != null) | ||||
| RaiseEvent(nameof(UserIsSpeaking), () => UserIsSpeaking(this, new MemberIsSpeakingEventArgs(member, isSpeaking))); | RaiseEvent(nameof(UserIsSpeaking), () => UserIsSpeaking(this, new MemberIsSpeakingEventArgs(member, isSpeaking))); | ||||
| } | } | ||||
| /// <summary> Returns a collection of all user-server pairs this client can currently see. </summary> | |||||
| public Members Members => _members; | |||||
| internal Members Members => _members; | |||||
| private readonly Members _members; | private readonly Members _members; | ||||
| /// <summary> Returns the user with the specified id, along with their server-specific data, or null if none was found. </summary> | /// <summary> Returns the user with the specified id, along with their server-specific data, or null if none was found. </summary> | ||||
| @@ -13,10 +13,6 @@ namespace Discord | |||||
| { | { | ||||
| public const int MaxMessageSize = 2000; | public const int MaxMessageSize = 2000; | ||||
| /// <summary> Returns a collection of all messages this client has seen since logging in and currently has in cache. </summary> | |||||
| public Messages Messages => _messages; | |||||
| private readonly Messages _messages; | |||||
| public event EventHandler<MessageEventArgs> MessageCreated; | public event EventHandler<MessageEventArgs> MessageCreated; | ||||
| private void RaiseMessageCreated(Message msg) | private void RaiseMessageCreated(Message msg) | ||||
| { | { | ||||
| @@ -47,6 +43,9 @@ namespace Discord | |||||
| if (MessageSent != null) | if (MessageSent != null) | ||||
| RaiseEvent(nameof(MessageSent), () => MessageSent(this, new MessageEventArgs(msg))); | RaiseEvent(nameof(MessageSent), () => MessageSent(this, new MessageEventArgs(msg))); | ||||
| } | } | ||||
| internal Messages Messages => _messages; | |||||
| private readonly Messages _messages; | |||||
| /// <summary> Returns the message with the specified id, or null if none was found. </summary> | /// <summary> Returns the message with the specified id, or null if none was found. </summary> | ||||
| public Message GetMessage(string id) => _messages[id]; | public Message GetMessage(string id) => _messages[id]; | ||||
| @@ -27,8 +27,7 @@ namespace Discord | |||||
| RaiseEvent(nameof(RoleUpdated), () => RoleUpdated(this, new RoleEventArgs(role))); | RaiseEvent(nameof(RoleUpdated), () => RoleUpdated(this, new RoleEventArgs(role))); | ||||
| } | } | ||||
| /// <summary> Returns a collection of all role-server pairs this client can currently see. </summary> | |||||
| public Roles Roles => _roles; | |||||
| internal Roles Roles => _roles; | |||||
| private readonly Roles _roles; | private readonly Roles _roles; | ||||
| /// <summary> Returns the role with the specified id, or null if none was found. </summary> | /// <summary> Returns the role with the specified id, or null if none was found. </summary> | ||||
| @@ -1,3 +1,4 @@ | |||||
| using Discord.Collections; | |||||
| using Discord.Net; | using Discord.Net; | ||||
| using System; | using System; | ||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| @@ -48,8 +49,14 @@ namespace Discord | |||||
| RaiseEvent(nameof(ServerAvailable), () => ServerAvailable(this, new ServerEventArgs(server))); | RaiseEvent(nameof(ServerAvailable), () => ServerAvailable(this, new ServerEventArgs(server))); | ||||
| } | } | ||||
| /// <summary> Returns a collection of all servers this client is a member of. </summary> | |||||
| public IEnumerable<Server> AllServers => _servers; | |||||
| internal Servers Servers => _servers; | |||||
| private readonly Servers _servers; | |||||
| /// <summary> Returns the server with the specified id, or null if none was found. </summary> | /// <summary> Returns the server with the specified id, or null if none was found. </summary> | ||||
| public Server GetServer(string id) => _servers[id]; | public Server GetServer(string id) => _servers[id]; | ||||
| /// <summary> Returns all servers with the specified name. </summary> | /// <summary> Returns all servers with the specified name. </summary> | ||||
| /// <remarks> Search is case-insensitive. </remarks> | /// <remarks> Search is case-insensitive. </remarks> | ||||
| public IEnumerable<Server> FindServers(string name) | public IEnumerable<Server> FindServers(string name) | ||||
| @@ -55,8 +55,9 @@ namespace Discord | |||||
| } | } | ||||
| /// <summary> Returns a collection of all users this client can currently see. </summary> | /// <summary> Returns a collection of all users this client can currently see. </summary> | ||||
| public Users Users => _users; | |||||
| internal Users Users => _users; | |||||
| private readonly Users _users; | private readonly Users _users; | ||||
| /// <summary> Returns the current logged-in user. </summary> | /// <summary> Returns the current logged-in user. </summary> | ||||
| public User CurrentUser => _currentUser; | public User CurrentUser => _currentUser; | ||||
| private User _currentUser; | private User _currentUser; | ||||
| @@ -76,11 +76,6 @@ namespace Discord | |||||
| public new DiscordClientConfig Config => _config as DiscordClientConfig; | public new DiscordClientConfig Config => _config as DiscordClientConfig; | ||||
| /// <summary> Returns a collection of all servers this client is a member of. </summary> | |||||
| public Servers Servers => _servers; | |||||
| private readonly Servers _servers; | |||||
| /// <summary> Initializes a new instance of the DiscordClient class. </summary> | /// <summary> Initializes a new instance of the DiscordClient class. </summary> | ||||
| public DiscordClient(DiscordClientConfig config = null) | public DiscordClient(DiscordClientConfig config = null) | ||||
| : base(config ?? new DiscordClientConfig()) | : base(config ?? new DiscordClientConfig()) | ||||
| @@ -98,8 +93,8 @@ namespace Discord | |||||
| _messages = new Messages(this, cacheLock); | _messages = new Messages(this, cacheLock); | ||||
| _roles = new Roles(this, cacheLock); | _roles = new Roles(this, cacheLock); | ||||
| _servers = new Servers(this, cacheLock); | _servers = new Servers(this, cacheLock); | ||||
| _status = UserStatus.Online; | |||||
| _users = new Users(this, cacheLock); | _users = new Users(this, cacheLock); | ||||
| _status = UserStatus.Online; | |||||
| this.Connected += async (s, e) => | this.Connected += async (s, e) => | ||||
| { | { | ||||
| @@ -33,9 +33,9 @@ namespace Discord.Net.Tests | |||||
| //Cleanup existing servers | //Cleanup existing servers | ||||
| WaitMany( | WaitMany( | ||||
| _hostClient.Servers.Select(x => _hostClient.LeaveServer(x)), | |||||
| _targetBot.Servers.Select(x => _targetBot.LeaveServer(x)), | |||||
| _observerBot.Servers.Select(x => _observerBot.LeaveServer(x))); | |||||
| _hostClient.AllServers.Select(x => _hostClient.LeaveServer(x)), | |||||
| _targetBot.AllServers.Select(x => _targetBot.LeaveServer(x)), | |||||
| _observerBot.AllServers.Select(x => _observerBot.LeaveServer(x))); | |||||
| //Create new server and invite the other bots to it | //Create new server and invite the other bots to it | ||||
| _testServer = _hostClient.CreateServer("Discord.Net Testing", Regions.US_East).Result; | _testServer = _hostClient.CreateServer("Discord.Net Testing", Regions.US_East).Result; | ||||
| @@ -110,9 +110,9 @@ namespace Discord.Net.Tests | |||||
| public static void Cleanup() | public static void Cleanup() | ||||
| { | { | ||||
| WaitMany( | WaitMany( | ||||
| _hostClient.State == DiscordClientState.Connected ? _hostClient.Servers.Select(x => _hostClient.LeaveServer(x)) : null, | |||||
| _targetBot.State == DiscordClientState.Connected ? _targetBot.Servers.Select(x => _targetBot.LeaveServer(x)) : null, | |||||
| _observerBot.State == DiscordClientState.Connected ? _observerBot.Servers.Select(x => _observerBot.LeaveServer(x)) : null); | |||||
| _hostClient.State == DiscordClientState.Connected ? _hostClient.AllServers.Select(x => _hostClient.LeaveServer(x)) : null, | |||||
| _targetBot.State == DiscordClientState.Connected ? _targetBot.AllServers.Select(x => _targetBot.LeaveServer(x)) : null, | |||||
| _observerBot.State == DiscordClientState.Connected ? _observerBot.AllServers.Select(x => _observerBot.LeaveServer(x)) : null); | |||||
| WaitAll( | WaitAll( | ||||
| _hostClient.Disconnect(), | _hostClient.Disconnect(), | ||||