diff --git a/src/Discord.Net/DiscordClient.cs b/src/Discord.Net/DiscordClient.cs index 61644efab..c74faf03a 100644 --- a/src/Discord.Net/DiscordClient.cs +++ b/src/Discord.Net/DiscordClient.cs @@ -11,36 +11,52 @@ using System.Threading.Tasks; namespace Discord { + /// Provides a connection to the DiscordApp service. public partial class DiscordClient { - public const int ReconnectDelay = 1000; //Time in milliseconds to wait after an unexpected disconnect before retrying - public const int FailedReconnectDelay = 10000; //Time in milliseconds to wait after a failed reconnect attempt - private DiscordWebSocket _webSocket; - private bool _isReady; + private ManualResetEventSlim _isStopping; + /// Returns the User object for the current logged in user. + public User User { get; private set; } public string UserId { get; private set; } - public User User => _users[UserId]; + /// Returns a collection of all users the client can see across all servers. + /// This collection does not guarantee any ordering. public IEnumerable Users => _users; private AsyncCache _users; + /// Returns a collection of all servers the client is a member of. + /// This collection does not guarantee any ordering. public IEnumerable Servers => _servers; private AsyncCache _servers; + /// Returns a collection of all channels the client can see across all servers. + /// This collection does not guarantee any ordering. public IEnumerable Channels => _channels; private AsyncCache _channels; + /// Returns a collection of all messages the client has in cache. + /// This collection does not guarantee any ordering. public IEnumerable Messages => _messages; private AsyncCache _messages; + /// Returns a collection of all roles the client can see across all servers. + /// This collection does not guarantee any ordering. public IEnumerable Roles => _roles; private AsyncCache _roles; - private ManualResetEventSlim _isStopping; - + /// Returns true if the user has successfully logged in and the websocket connection has been established. public bool IsConnected => _isReady; + private bool _isReady; + /// 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; } = 10000; + + + /// Initializes a new instance of the DiscordClient class. public DiscordClient() { _isStopping = new ManualResetEventSlim(false); @@ -50,7 +66,7 @@ namespace Discord (server, model) => { server.Name = model.Name; - if (!server.Channels.Any()) //Assume a default channel exists with the same id as the server. Not sure if this is safe? + if (!server.Channels.Any()) //A default channel always exists with the same id as the server. { var defaultChannel = new ChannelReference() { Id = server.DefaultChannelId, GuildId = server.Id }; _channels.Update(defaultChannel.Id, defaultChannel.GuildId, defaultChannel); @@ -173,8 +189,9 @@ namespace Discord await _webSocket.ConnectAsync(Endpoints.WebSocket_Hub, true); break; } - catch (Exception) + catch (Exception ex) { + RaiseOnDebugMessage($"Reconnect Failed: {ex.Message}"); //Net is down? We can keep trying to reconnect until the user runs Disconnect() await Task.Delay(FailedReconnectDelay); } @@ -194,7 +211,7 @@ namespace Discord _users.Clear(); UserId = data.User.Id; - _users.Update(data.User.Id, data.User); + User = _users.Update(data.User.Id, data.User); foreach (var server in data.Guilds) _servers.Update(server.Id, server); foreach (var channel in data.PrivateChannels) @@ -416,101 +433,131 @@ namespace Discord }; _webSocket.OnDebugMessage += (s, e) => RaiseOnDebugMessage(e.Message); } + - //Collections + /// Returns the user with the specified id, or null if none was found. public User GetUser(string id) => _users[id]; - public User FindUser(string name) - { - return _users - .Where(x => string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase)) - .FirstOrDefault(); - } - public User FindUser(string name, string discriminator) + /// Returns the user with the specified name and discriminator, or null if none was found. + /// Name formats supported: Name and @Name. Search is case-insensitive. + public User GetUser(string name, string discriminator) { if (name.StartsWith("@")) name = name.Substring(1); return _users - .Where(x => + .Where(x => string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase) && x.Discriminator == discriminator - ) + ) .FirstOrDefault(); } - public Membership FindMember(string serverId, string name) - => FindMember(GetServer(serverId), name); - public Membership FindMember(Server server, string name) + /// Returns all users with the specified name. + /// Name formats supported: Name and @Name. Search is case-insensitive. + /*public IEnumerable FindUsers(string name) { - if (server == null) - return null; - - if (name.StartsWith("<@") && name.EndsWith(">")) + if (name.StartsWith("@")) { - var user = GetUser(name.Substring(2, name.Length - 3)); - if (user == null) - return null; - return server.GetMembership(user.Id); - } + string name2 = name.Substring(1); + return _users.Where(x => + string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase) || string.Equals(x.Name, name2, StringComparison.OrdinalIgnoreCase)); + } + else + { + return _users.Where(x => + string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase)); + } + }*/ + /// Returns all users in with the specified server and name, along with their server-specific data. + /// Name formats supported: Name and @Name. Search is case-insensitive. + public IEnumerable FindUsers(string serverId, string name) + => FindUsers(GetServer(serverId), name); + /// Returns all users in with the specified server and name, along with their server-specific data. + /// Name formats supported: Name and @Name. Search is case-insensitive. + public IEnumerable FindUsers(Server server, string name) + { + if (server == null) + return new Membership[0]; if (name.StartsWith("@")) - name = name.Substring(1); - - return server.Members - .Where(x => string.Equals(x.User.Name, name, StringComparison.OrdinalIgnoreCase)) - .FirstOrDefault(); + { + string name2 = name.Substring(1); + return server.Members.Where(x => + { + var user = x.User; + return string.Equals(user.Name, name, StringComparison.OrdinalIgnoreCase) || string.Equals(user.Name, name2, StringComparison.OrdinalIgnoreCase); + }); + } + else + { + return server.Members.Where(x => + string.Equals(x.User.Name, name, StringComparison.OrdinalIgnoreCase)); + } } + /// Returns the server with the specified id, or null if none was found. public Server GetServer(string id) => _servers[id]; - public Server FindServer(string name) + /// Returns all servers with the specified name. + /// Search is case-insensitive. + public IEnumerable FindServers(string name) { - return _servers - .Where(x => string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase)) - .FirstOrDefault(); + return _servers.Where(x => + string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase)); } + /// Returns the channel with the specified id, or null if none was found. public Channel GetChannel(string id) => _channels[id]; - public Channel FindChannel(string name) + /// Returns all channels with the specified server and name. + /// Name formats supported: Name and #Name. Search is case-insensitive. + public IEnumerable FindChannels(Server server, string name) + => FindChannels(server.Id, name); + /// Returns all channels with the specified server and name. + /// Name formats supported: Name and #Name. Search is case-insensitive. + public IEnumerable FindChannels(string serverId, string name) { - if (name.StartsWith("<#") && name.EndsWith(">")) - return GetChannel(name.Substring(2, name.Length - 3)); - if (name.StartsWith("#")) - name = name.Substring(1); - return _channels - .Where(x => string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase)) - .FirstOrDefault(); - } - public Channel FindChannel(Server server, string name) - => FindChannel(server.Id, name); - public Channel FindChannel(string serverId, string name) - { - if (name.StartsWith("<#") && name.EndsWith(">")) - return GetChannel(name.Substring(2, name.Length - 3)); - - if (name.StartsWith("#")) - name = name.Substring(1); - return _channels - .Where(x => - string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase) && - x.ServerId == serverId - ) - .FirstOrDefault(); + { + string name2 = name.Substring(1); + return _channels.Where(x => x.ServerId == serverId && + string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase) || string.Equals(x.Name, name2, StringComparison.OrdinalIgnoreCase)); + } + else + { + return _channels.Where(x => x.ServerId == serverId && + string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase)); + } } + /// Returns the role with the specified id, or null if none was found. public Role GetRole(string id) => _roles[id]; - public Role FindRole(Server server, string name) - => FindRole(server.Id, name); - public Role FindRole(string serverId, string name) + /// Returns all roles with the specified server and name. + /// Name formats supported: Name and @Name. Search is case-insensitive. + public IEnumerable FindRoles(Server server, string name) + => FindRoles(server.Id, name); + /// Returns all roles with the specified server and name. + /// Name formats supported: Name and @Name. Search is case-insensitive. + public IEnumerable FindRoles(string serverId, string name) { - return _roles - .Where(x => string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase)) - .FirstOrDefault(); + if (name.StartsWith("@")) + { + string name2 = name.Substring(1); + return _roles.Where(x => x.ServerId == serverId && + string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase) || string.Equals(x.Name, name2, StringComparison.OrdinalIgnoreCase)); + } + else + { + return _roles.Where(x => x.ServerId == serverId && + string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase)); + } } + /// Returns the message with the specified id, or null if none was found. public Message GetMessage(string id) => _messages[id]; - public Task DownloadMessages(Channel channel, int count) + + /// Downloads last count messages from the server, starting at beforeMessageId if it's provided. + public Task DownloadMessages(Channel channel, int count, string beforeMessageId = null) => DownloadMessages(channel.Id, count); - public async Task DownloadMessages(string channelId, int count) + /// Downloads last count messages from the server, starting at beforeMessageId if it's provided. + public async Task DownloadMessages(string channelId, int count, string beforeMessageId = null) { Channel channel = GetChannel(channelId); if (channel != null && channel.Type == ChannelTypes.Text)