diff --git a/src/Discord.Net.Rest/BaseDiscordClient.cs b/src/Discord.Net.Rest/BaseDiscordClient.cs index 87f974dc2..47a946f20 100644 --- a/src/Discord.Net.Rest/BaseDiscordClient.cs +++ b/src/Discord.Net.Rest/BaseDiscordClient.cs @@ -85,7 +85,8 @@ namespace Discord.Rest await _loggedInEvent.InvokeAsync().ConfigureAwait(false); } - internal virtual Task OnLoginAsync(TokenType tokenType, string token) { return Task.Delay(0); } + internal virtual Task OnLoginAsync(TokenType tokenType, string token) + => Task.Delay(0); /// public async Task LogoutAsync() @@ -110,7 +111,8 @@ namespace Discord.Rest await _loggedOutEvent.InvokeAsync().ConfigureAwait(false); } - internal virtual Task OnLogoutAsync() { return Task.Delay(0); } + internal virtual Task OnLogoutAsync() + => Task.Delay(0); internal virtual void Dispose(bool disposing) { @@ -127,7 +129,8 @@ namespace Discord.Rest ConnectionState IDiscordClient.ConnectionState => ConnectionState.Disconnected; ISelfUser IDiscordClient.CurrentUser => CurrentUser; - Task IDiscordClient.GetApplicationInfoAsync(RequestOptions options) { throw new NotSupportedException(); } + Task IDiscordClient.GetApplicationInfoAsync(RequestOptions options) + => throw new NotSupportedException(); Task IDiscordClient.GetChannelAsync(ulong id, CacheMode mode, RequestOptions options) => Task.FromResult(null); @@ -148,7 +151,8 @@ namespace Discord.Rest => Task.FromResult(null); Task> IDiscordClient.GetGuildsAsync(CacheMode mode, RequestOptions options) => Task.FromResult>(ImmutableArray.Create()); - Task IDiscordClient.CreateGuildAsync(string name, IVoiceRegion region, Stream jpegIcon, RequestOptions options) { throw new NotSupportedException(); } + Task IDiscordClient.CreateGuildAsync(string name, IVoiceRegion region, Stream jpegIcon, RequestOptions options) + => throw new NotSupportedException(); Task IDiscordClient.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) => Task.FromResult(null); diff --git a/src/Discord.Net.WebSocket/BaseSocketClient.Events.cs b/src/Discord.Net.WebSocket/BaseSocketClient.Events.cs new file mode 100644 index 000000000..e881a7855 --- /dev/null +++ b/src/Discord.Net.WebSocket/BaseSocketClient.Events.cs @@ -0,0 +1,193 @@ +using System; +using System.Threading.Tasks; + +namespace Discord.WebSocket +{ + public partial class BaseSocketClient + { + //Channels + /// Fired when a channel is created. + public event Func ChannelCreated + { + add { _channelCreatedEvent.Add(value); } + remove { _channelCreatedEvent.Remove(value); } + } + internal readonly AsyncEvent> _channelCreatedEvent = new AsyncEvent>(); + /// Fired when a channel is destroyed. + public event Func ChannelDestroyed { + add { _channelDestroyedEvent.Add(value); } + remove { _channelDestroyedEvent.Remove(value); } + } + internal readonly AsyncEvent> _channelDestroyedEvent = new AsyncEvent>(); + /// Fired when a channel is updated. + public event Func ChannelUpdated { + add { _channelUpdatedEvent.Add(value); } + remove { _channelUpdatedEvent.Remove(value); } + } + internal readonly AsyncEvent> _channelUpdatedEvent = new AsyncEvent>(); + + //Messages + /// Fired when a message is received. + public event Func MessageReceived { + add { _messageReceivedEvent.Add(value); } + remove { _messageReceivedEvent.Remove(value); } + } + internal readonly AsyncEvent> _messageReceivedEvent = new AsyncEvent>(); + /// Fired when a message is deleted. + public event Func, ISocketMessageChannel, Task> MessageDeleted { + add { _messageDeletedEvent.Add(value); } + remove { _messageDeletedEvent.Remove(value); } + } + internal readonly AsyncEvent, ISocketMessageChannel, Task>> _messageDeletedEvent = new AsyncEvent, ISocketMessageChannel, Task>>(); + /// Fired when a message is updated. + public event Func, SocketMessage, ISocketMessageChannel, Task> MessageUpdated { + add { _messageUpdatedEvent.Add(value); } + remove { _messageUpdatedEvent.Remove(value); } + } + internal readonly AsyncEvent, SocketMessage, ISocketMessageChannel, Task>> _messageUpdatedEvent = new AsyncEvent, SocketMessage, ISocketMessageChannel, Task>>(); + /// Fired when a reaction is added to a message. + public event Func, ISocketMessageChannel, SocketReaction, Task> ReactionAdded { + add { _reactionAddedEvent.Add(value); } + remove { _reactionAddedEvent.Remove(value); } + } + internal readonly AsyncEvent, ISocketMessageChannel, SocketReaction, Task>> _reactionAddedEvent = new AsyncEvent, ISocketMessageChannel, SocketReaction, Task>>(); + /// Fired when a reaction is removed from a message. + public event Func, ISocketMessageChannel, SocketReaction, Task> ReactionRemoved { + add { _reactionRemovedEvent.Add(value); } + remove { _reactionRemovedEvent.Remove(value); } + } + internal readonly AsyncEvent, ISocketMessageChannel, SocketReaction, Task>> _reactionRemovedEvent = new AsyncEvent, ISocketMessageChannel, SocketReaction, Task>>(); + /// Fired when all reactions to a message are cleared. + public event Func, ISocketMessageChannel, Task> ReactionsCleared { + add { _reactionsClearedEvent.Add(value); } + remove { _reactionsClearedEvent.Remove(value); } + } + internal readonly AsyncEvent, ISocketMessageChannel, Task>> _reactionsClearedEvent = new AsyncEvent, ISocketMessageChannel, Task>>(); + + //Roles + /// Fired when a role is created. + public event Func RoleCreated { + add { _roleCreatedEvent.Add(value); } + remove { _roleCreatedEvent.Remove(value); } + } + internal readonly AsyncEvent> _roleCreatedEvent = new AsyncEvent>(); + /// Fired when a role is deleted. + public event Func RoleDeleted { + add { _roleDeletedEvent.Add(value); } + remove { _roleDeletedEvent.Remove(value); } + } + internal readonly AsyncEvent> _roleDeletedEvent = new AsyncEvent>(); + /// Fired when a role is updated. + public event Func RoleUpdated { + add { _roleUpdatedEvent.Add(value); } + remove { _roleUpdatedEvent.Remove(value); } + } + internal readonly AsyncEvent> _roleUpdatedEvent = new AsyncEvent>(); + + //Guilds + /// Fired when the connected account joins a guild. + public event Func JoinedGuild { + add { _joinedGuildEvent.Add(value); } + remove { _joinedGuildEvent.Remove(value); } + } + internal readonly AsyncEvent> _joinedGuildEvent = new AsyncEvent>(); + /// Fired when the connected account leaves a guild. + public event Func LeftGuild { + add { _leftGuildEvent.Add(value); } + remove { _leftGuildEvent.Remove(value); } + } + internal readonly AsyncEvent> _leftGuildEvent = new AsyncEvent>(); + /// Fired when a guild becomes available. + public event Func GuildAvailable { + add { _guildAvailableEvent.Add(value); } + remove { _guildAvailableEvent.Remove(value); } + } + internal readonly AsyncEvent> _guildAvailableEvent = new AsyncEvent>(); + /// Fired when a guild becomes unavailable. + public event Func GuildUnavailable { + add { _guildUnavailableEvent.Add(value); } + remove { _guildUnavailableEvent.Remove(value); } + } + internal readonly AsyncEvent> _guildUnavailableEvent = new AsyncEvent>(); + /// Fired when offline guild members are downloaded. + public event Func GuildMembersDownloaded { + add { _guildMembersDownloadedEvent.Add(value); } + remove { _guildMembersDownloadedEvent.Remove(value); } + } + internal readonly AsyncEvent> _guildMembersDownloadedEvent = new AsyncEvent>(); + /// Fired when a guild is updated. + public event Func GuildUpdated { + add { _guildUpdatedEvent.Add(value); } + remove { _guildUpdatedEvent.Remove(value); } + } + internal readonly AsyncEvent> _guildUpdatedEvent = new AsyncEvent>(); + + //Users + /// Fired when a user joins a guild. + public event Func UserJoined { + add { _userJoinedEvent.Add(value); } + remove { _userJoinedEvent.Remove(value); } + } + internal readonly AsyncEvent> _userJoinedEvent = new AsyncEvent>(); + /// Fired when a user leaves a guild. + public event Func UserLeft { + add { _userLeftEvent.Add(value); } + remove { _userLeftEvent.Remove(value); } + } + internal readonly AsyncEvent> _userLeftEvent = new AsyncEvent>(); + /// Fired when a user is banned from a guild. + public event Func UserBanned { + add { _userBannedEvent.Add(value); } + remove { _userBannedEvent.Remove(value); } + } + internal readonly AsyncEvent> _userBannedEvent = new AsyncEvent>(); + /// Fired when a user is unbanned from a guild. + public event Func UserUnbanned { + add { _userUnbannedEvent.Add(value); } + remove { _userUnbannedEvent.Remove(value); } + } + internal readonly AsyncEvent> _userUnbannedEvent = new AsyncEvent>(); + /// Fired when a user is updated. + public event Func UserUpdated { + add { _userUpdatedEvent.Add(value); } + remove { _userUpdatedEvent.Remove(value); } + } + internal readonly AsyncEvent> _userUpdatedEvent = new AsyncEvent>(); + /// Fired when a guild member is updated, or a member presence is updated. + public event Func GuildMemberUpdated { + add { _guildMemberUpdatedEvent.Add(value); } + remove { _guildMemberUpdatedEvent.Remove(value); } + } + internal readonly AsyncEvent> _guildMemberUpdatedEvent = new AsyncEvent>(); + /// Fired when a user joins, leaves, or moves voice channels. + public event Func UserVoiceStateUpdated { + add { _userVoiceStateUpdatedEvent.Add(value); } + remove { _userVoiceStateUpdatedEvent.Remove(value); } + } + internal readonly AsyncEvent> _userVoiceStateUpdatedEvent = new AsyncEvent>(); + /// Fired when the connected account is updated. + public event Func CurrentUserUpdated { + add { _selfUpdatedEvent.Add(value); } + remove { _selfUpdatedEvent.Remove(value); } + } + internal readonly AsyncEvent> _selfUpdatedEvent = new AsyncEvent>(); + /// Fired when a user starts typing. + public event Func UserIsTyping { + add { _userIsTypingEvent.Add(value); } + remove { _userIsTypingEvent.Remove(value); } + } + internal readonly AsyncEvent> _userIsTypingEvent = new AsyncEvent>(); + /// Fired when a user joins a group channel. + public event Func RecipientAdded { + add { _recipientAddedEvent.Add(value); } + remove { _recipientAddedEvent.Remove(value); } + } + internal readonly AsyncEvent> _recipientAddedEvent = new AsyncEvent>(); + /// Fired when a user is removed from a group channel. + public event Func RecipientRemoved { + add { _recipientRemovedEvent.Add(value); } + remove { _recipientRemovedEvent.Remove(value); } + } + internal readonly AsyncEvent> _recipientRemovedEvent = new AsyncEvent>(); + } +} diff --git a/src/Discord.Net.WebSocket/BaseSocketClient.cs b/src/Discord.Net.WebSocket/BaseSocketClient.cs new file mode 100644 index 000000000..d248285cd --- /dev/null +++ b/src/Discord.Net.WebSocket/BaseSocketClient.cs @@ -0,0 +1,93 @@ +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using Discord.API; +using Discord.Rest; + +namespace Discord.WebSocket +{ + public abstract partial class BaseSocketClient : BaseDiscordClient, IDiscordClient + { + protected readonly DiscordSocketConfig _baseconfig; + + /// Gets the estimated round-trip latency, in milliseconds, to the gateway server. + public abstract int Latency { get; protected set; } + public abstract UserStatus Status { get; protected set; } + public abstract Game? Game { get; protected set; } + + internal new DiscordSocketApiClient ApiClient => base.ApiClient as DiscordSocketApiClient; + + public new SocketSelfUser CurrentUser { get => base.CurrentUser as SocketSelfUser; protected set => base.CurrentUser = value; } + public abstract IReadOnlyCollection Guilds { get; } + public abstract IReadOnlyCollection PrivateChannels { get; } + public abstract IReadOnlyCollection VoiceRegions { get; } + + internal BaseSocketClient(DiscordSocketConfig config, DiscordRestApiClient client) + : base(config, client) => _baseconfig = config; + private static DiscordSocketApiClient CreateApiClient(DiscordSocketConfig config) + => new DiscordSocketApiClient(config.RestClientProvider, config.WebSocketProvider, DiscordRestConfig.UserAgent); + + /// + public abstract Task GetApplicationInfoAsync(RequestOptions options = null); + /// + public abstract SocketUser GetUser(ulong id); + /// + public abstract SocketUser GetUser(string username, string discriminator); + /// + public abstract SocketChannel GetChannel(ulong id); + /// + public abstract SocketGuild GetGuild(ulong id); + /// + public abstract RestVoiceRegion GetVoiceRegion(string id); + /// + public abstract Task StartAsync(); + /// + public abstract Task StopAsync(); + public abstract Task SetStatusAsync(UserStatus status); + public abstract Task SetGameAsync(string name, string streamUrl = null, StreamType streamType = StreamType.NotStreaming); + public abstract Task DownloadUsersAsync(IEnumerable guilds); + + /// + public Task CreateGuildAsync(string name, IVoiceRegion region, Stream jpegIcon = null, RequestOptions options = null) + => ClientHelper.CreateGuildAsync(this, name, region, jpegIcon, options ?? RequestOptions.Default); + /// + public Task> GetConnectionsAsync(RequestOptions options = null) + => ClientHelper.GetConnectionsAsync(this, options ?? RequestOptions.Default); + /// + public Task GetInviteAsync(string inviteId, RequestOptions options = null) + => ClientHelper.GetInviteAsync(this, inviteId, options ?? RequestOptions.Default); + + // IDiscordClient + async Task IDiscordClient.GetApplicationInfoAsync(RequestOptions options) + => await GetApplicationInfoAsync(options).ConfigureAwait(false); + + Task IDiscordClient.GetChannelAsync(ulong id, CacheMode mode, RequestOptions options) + => Task.FromResult(GetChannel(id)); + Task> IDiscordClient.GetPrivateChannelsAsync(CacheMode mode, RequestOptions options) + => Task.FromResult>(PrivateChannels); + + async Task> IDiscordClient.GetConnectionsAsync(RequestOptions options) + => await GetConnectionsAsync(options).ConfigureAwait(false); + + async Task IDiscordClient.GetInviteAsync(string inviteId, RequestOptions options) + => await GetInviteAsync(inviteId, options).ConfigureAwait(false); + + Task IDiscordClient.GetGuildAsync(ulong id, CacheMode mode, RequestOptions options) + => Task.FromResult(GetGuild(id)); + Task> IDiscordClient.GetGuildsAsync(CacheMode mode, RequestOptions options) + => Task.FromResult>(Guilds); + + async Task IDiscordClient.CreateGuildAsync(string name, IVoiceRegion region, Stream jpegIcon, RequestOptions options) + => await CreateGuildAsync(name, region, jpegIcon, options).ConfigureAwait(false); + + Task IDiscordClient.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) + => Task.FromResult(GetUser(id)); + Task IDiscordClient.GetUserAsync(string username, string discriminator, RequestOptions options) + => Task.FromResult(GetUser(username, discriminator)); + + Task IDiscordClient.GetVoiceRegionAsync(string id, RequestOptions options) + => Task.FromResult(GetVoiceRegion(id)); + Task> IDiscordClient.GetVoiceRegionsAsync(RequestOptions options) + => Task.FromResult>(VoiceRegions); + } +} diff --git a/src/Discord.Net.WebSocket/DiscordShardedClient.Events.cs b/src/Discord.Net.WebSocket/DiscordShardedClient.Events.cs index c52675e70..c9e679669 100644 --- a/src/Discord.Net.WebSocket/DiscordShardedClient.Events.cs +++ b/src/Discord.Net.WebSocket/DiscordShardedClient.Events.cs @@ -3,197 +3,36 @@ using System.Threading.Tasks; namespace Discord.WebSocket { - //TODO: Add event docstrings public partial class DiscordShardedClient { - //Channels - public event Func ChannelCreated + //General + /// Fired when a shard is connected to the Discord gateway. + public event Func ShardConnected { - add { _channelCreatedEvent.Add(value); } - remove { _channelCreatedEvent.Remove(value); } + add { _shardConnectedEvent.Add(value); } + remove { _shardConnectedEvent.Remove(value); } } - private readonly AsyncEvent> _channelCreatedEvent = new AsyncEvent>(); - public event Func ChannelDestroyed + private readonly AsyncEvent> _shardConnectedEvent = new AsyncEvent>(); + /// Fired when a shard is disconnected from the Discord gateway. + public event Func ShardDisconnected { - add { _channelDestroyedEvent.Add(value); } - remove { _channelDestroyedEvent.Remove(value); } + add { _shardDisconnectedEvent.Add(value); } + remove { _shardDisconnectedEvent.Remove(value); } } - private readonly AsyncEvent> _channelDestroyedEvent = new AsyncEvent>(); - public event Func ChannelUpdated + private readonly AsyncEvent> _shardDisconnectedEvent = new AsyncEvent>(); + /// Fired when a guild data for a shard has finished downloading. + public event Func ShardReady { - add { _channelUpdatedEvent.Add(value); } - remove { _channelUpdatedEvent.Remove(value); } + add { _shardReadyEvent.Add(value); } + remove { _shardReadyEvent.Remove(value); } } - private readonly AsyncEvent> _channelUpdatedEvent = new AsyncEvent>(); - - //Messages - public event Func MessageReceived - { - add { _messageReceivedEvent.Add(value); } - remove { _messageReceivedEvent.Remove(value); } - } - private readonly AsyncEvent> _messageReceivedEvent = new AsyncEvent>(); - public event Func, ISocketMessageChannel, Task> MessageDeleted - { - add { _messageDeletedEvent.Add(value); } - remove { _messageDeletedEvent.Remove(value); } - } - private readonly AsyncEvent, ISocketMessageChannel, Task>> _messageDeletedEvent = new AsyncEvent, ISocketMessageChannel, Task>>(); - public event Func, SocketMessage, ISocketMessageChannel, Task> MessageUpdated - { - add { _messageUpdatedEvent.Add(value); } - remove { _messageUpdatedEvent.Remove(value); } - } - private readonly AsyncEvent, SocketMessage, ISocketMessageChannel, Task>> _messageUpdatedEvent = new AsyncEvent, SocketMessage, ISocketMessageChannel, Task>>(); - public event Func, ISocketMessageChannel, SocketReaction, Task> ReactionAdded - { - add { _reactionAddedEvent.Add(value); } - remove { _reactionAddedEvent.Remove(value); } - } - private readonly AsyncEvent, ISocketMessageChannel, SocketReaction, Task>> _reactionAddedEvent = new AsyncEvent, ISocketMessageChannel, SocketReaction, Task>>(); - public event Func, ISocketMessageChannel, SocketReaction, Task> ReactionRemoved - { - add { _reactionRemovedEvent.Add(value); } - remove { _reactionRemovedEvent.Remove(value); } - } - private readonly AsyncEvent, ISocketMessageChannel, SocketReaction, Task>> _reactionRemovedEvent = new AsyncEvent, ISocketMessageChannel, SocketReaction, Task>>(); - public event Func, ISocketMessageChannel, Task> ReactionsCleared - { - add { _reactionsClearedEvent.Add(value); } - remove { _reactionsClearedEvent.Remove(value); } - } - private readonly AsyncEvent, ISocketMessageChannel, Task>> _reactionsClearedEvent = new AsyncEvent, ISocketMessageChannel, Task>>(); - - //Roles - public event Func RoleCreated - { - add { _roleCreatedEvent.Add(value); } - remove { _roleCreatedEvent.Remove(value); } - } - private readonly AsyncEvent> _roleCreatedEvent = new AsyncEvent>(); - public event Func RoleDeleted - { - add { _roleDeletedEvent.Add(value); } - remove { _roleDeletedEvent.Remove(value); } - } - private readonly AsyncEvent> _roleDeletedEvent = new AsyncEvent>(); - public event Func RoleUpdated - { - add { _roleUpdatedEvent.Add(value); } - remove { _roleUpdatedEvent.Remove(value); } - } - private readonly AsyncEvent> _roleUpdatedEvent = new AsyncEvent>(); - - //Guilds - public event Func JoinedGuild - { - add { _joinedGuildEvent.Add(value); } - remove { _joinedGuildEvent.Remove(value); } - } - private AsyncEvent> _joinedGuildEvent = new AsyncEvent>(); - public event Func LeftGuild - { - add { _leftGuildEvent.Add(value); } - remove { _leftGuildEvent.Remove(value); } - } - private AsyncEvent> _leftGuildEvent = new AsyncEvent>(); - public event Func GuildAvailable - { - add { _guildAvailableEvent.Add(value); } - remove { _guildAvailableEvent.Remove(value); } - } - private AsyncEvent> _guildAvailableEvent = new AsyncEvent>(); - public event Func GuildUnavailable - { - add { _guildUnavailableEvent.Add(value); } - remove { _guildUnavailableEvent.Remove(value); } - } - private AsyncEvent> _guildUnavailableEvent = new AsyncEvent>(); - public event Func GuildMembersDownloaded - { - add { _guildMembersDownloadedEvent.Add(value); } - remove { _guildMembersDownloadedEvent.Remove(value); } - } - private AsyncEvent> _guildMembersDownloadedEvent = new AsyncEvent>(); - public event Func GuildUpdated - { - add { _guildUpdatedEvent.Add(value); } - remove { _guildUpdatedEvent.Remove(value); } - } - private AsyncEvent> _guildUpdatedEvent = new AsyncEvent>(); - - //Users - public event Func UserJoined - { - add { _userJoinedEvent.Add(value); } - remove { _userJoinedEvent.Remove(value); } - } - private readonly AsyncEvent> _userJoinedEvent = new AsyncEvent>(); - public event Func UserLeft - { - add { _userLeftEvent.Add(value); } - remove { _userLeftEvent.Remove(value); } - } - private readonly AsyncEvent> _userLeftEvent = new AsyncEvent>(); - public event Func UserBanned - { - add { _userBannedEvent.Add(value); } - remove { _userBannedEvent.Remove(value); } - } - private readonly AsyncEvent> _userBannedEvent = new AsyncEvent>(); - public event Func UserUnbanned - { - add { _userUnbannedEvent.Add(value); } - remove { _userUnbannedEvent.Remove(value); } - } - private readonly AsyncEvent> _userUnbannedEvent = new AsyncEvent>(); - public event Func UserUpdated - { - add { _userUpdatedEvent.Add(value); } - remove { _userUpdatedEvent.Remove(value); } - } - private readonly AsyncEvent> _userUpdatedEvent = new AsyncEvent>(); - public event Func GuildMemberUpdated - { - add { _guildMemberUpdatedEvent.Add(value); } - remove { _guildMemberUpdatedEvent.Remove(value); } - } - private readonly AsyncEvent> _guildMemberUpdatedEvent = new AsyncEvent>(); - public event Func, SocketUser, SocketPresence, SocketPresence, Task> UserPresenceUpdated - { - add { _userPresenceUpdatedEvent.Add(value); } - remove { _userPresenceUpdatedEvent.Remove(value); } - } - private readonly AsyncEvent, SocketUser, SocketPresence, SocketPresence, Task>> _userPresenceUpdatedEvent = new AsyncEvent, SocketUser, SocketPresence, SocketPresence, Task>>(); - public event Func UserVoiceStateUpdated - { - add { _userVoiceStateUpdatedEvent.Add(value); } - remove { _userVoiceStateUpdatedEvent.Remove(value); } - } - private readonly AsyncEvent> _userVoiceStateUpdatedEvent = new AsyncEvent>(); - public event Func CurrentUserUpdated - { - add { _selfUpdatedEvent.Add(value); } - remove { _selfUpdatedEvent.Remove(value); } - } - private readonly AsyncEvent> _selfUpdatedEvent = new AsyncEvent>(); - public event Func UserIsTyping - { - add { _userIsTypingEvent.Add(value); } - remove { _userIsTypingEvent.Remove(value); } - } - private readonly AsyncEvent> _userIsTypingEvent = new AsyncEvent>(); - public event Func RecipientAdded - { - add { _recipientAddedEvent.Add(value); } - remove { _recipientAddedEvent.Remove(value); } - } - private readonly AsyncEvent> _recipientAddedEvent = new AsyncEvent>(); - public event Func RecipientRemoved + private readonly AsyncEvent> _shardReadyEvent = new AsyncEvent>(); + /// Fired when a shard receives a heartbeat from the Discord gateway. + public event Func ShardLatencyUpdated { - add { _recipientRemovedEvent.Add(value); } - remove { _recipientRemovedEvent.Remove(value); } + add { _shardLatencyUpdatedEvent.Add(value); } + remove { _shardLatencyUpdatedEvent.Remove(value); } } - private readonly AsyncEvent> _recipientRemovedEvent = new AsyncEvent>(); + private readonly AsyncEvent> _shardLatencyUpdatedEvent = new AsyncEvent>(); } -} +} \ No newline at end of file diff --git a/src/Discord.Net.WebSocket/DiscordShardedClient.cs b/src/Discord.Net.WebSocket/DiscordShardedClient.cs index ab2cb9266..6c2a0f3b9 100644 --- a/src/Discord.Net.WebSocket/DiscordShardedClient.cs +++ b/src/Discord.Net.WebSocket/DiscordShardedClient.cs @@ -9,7 +9,7 @@ using System.Threading; namespace Discord.WebSocket { - public partial class DiscordShardedClient : BaseDiscordClient, IDiscordClient + public partial class DiscordShardedClient : BaseSocketClient, IDiscordClient { private readonly DiscordSocketConfig _baseConfig; private readonly SemaphoreSlim _connectionGroupLock; @@ -20,16 +20,15 @@ namespace Discord.WebSocket private bool _automaticShards; /// Gets the estimated round-trip latency, in milliseconds, to the gateway server. - public int Latency => GetLatency(); - public UserStatus Status => _shards[0].Status; - public Game? Game => _shards[0].Game; + public override int Latency { get => GetLatency(); protected set { } } + public override UserStatus Status { get => _shards[0].Status; protected set { } } + public override Game? Game { get => _shards[0].Game; protected set { } } internal new DiscordSocketApiClient ApiClient => base.ApiClient as DiscordSocketApiClient; - public new SocketSelfUser CurrentUser { get { return base.CurrentUser as SocketSelfUser; } private set { base.CurrentUser = value; } } - public IReadOnlyCollection Guilds => GetGuilds().ToReadOnlyCollection(() => GetGuildCount()); - public IReadOnlyCollection PrivateChannels => GetPrivateChannels().ToReadOnlyCollection(() => GetPrivateChannelCount()); + public override IReadOnlyCollection Guilds => GetGuilds().ToReadOnlyCollection(() => GetGuildCount()); + public override IReadOnlyCollection PrivateChannels => GetPrivateChannels().ToReadOnlyCollection(() => GetPrivateChannelCount()); public IReadOnlyCollection Shards => _shards; - public IReadOnlyCollection VoiceRegions => _shards[0].VoiceRegions; + public override IReadOnlyCollection VoiceRegions => _shards[0].VoiceRegions; /// Creates a new REST/WebSocket discord client. public DiscordShardedClient() : this(null, new DiscordSocketConfig()) { } @@ -115,15 +114,11 @@ namespace Discord.WebSocket } /// - public async Task StartAsync() - { - await Task.WhenAll(_shards.Select(x => x.StartAsync())).ConfigureAwait(false); - } + public override async Task StartAsync() + => await Task.WhenAll(_shards.Select(x => x.StartAsync())).ConfigureAwait(false); /// - public async Task StopAsync() - { - await Task.WhenAll(_shards.Select(x => x.StopAsync())).ConfigureAwait(false); - } + public override async Task StopAsync() + => await Task.WhenAll(_shards.Select(x => x.StopAsync())).ConfigureAwait(false); public DiscordSocketClient GetShard(int id) { @@ -141,17 +136,15 @@ namespace Discord.WebSocket => GetShardFor(guild.Id); /// - public async Task GetApplicationInfoAsync() - => await _shards[0].GetApplicationInfoAsync().ConfigureAwait(false); + public override async Task GetApplicationInfoAsync(RequestOptions options = null) + => await _shards[0].GetApplicationInfoAsync(options).ConfigureAwait(false); /// - public SocketGuild GetGuild(ulong id) => GetShardFor(id).GetGuild(id); - /// - public Task CreateGuildAsync(string name, IVoiceRegion region, Stream jpegIcon = null) - => ClientHelper.CreateGuildAsync(this, name, region, jpegIcon, new RequestOptions()); + public override SocketGuild GetGuild(ulong id) + => GetShardFor(id).GetGuild(id); /// - public SocketChannel GetChannel(ulong id) + public override SocketChannel GetChannel(ulong id) { for (int i = 0; i < _shards.Length; i++) { @@ -175,11 +168,7 @@ namespace Discord.WebSocket for (int i = 0; i < _shards.Length; i++) result += _shards[i].PrivateChannels.Count; return result; - } - - /// - public Task> GetConnectionsAsync() - => ClientHelper.GetConnectionsAsync(this, new RequestOptions()); + } private IEnumerable GetGuilds() { @@ -195,14 +184,10 @@ namespace Discord.WebSocket for (int i = 0; i < _shards.Length; i++) result += _shards[i].Guilds.Count; return result; - } + } /// - public Task GetInviteAsync(string inviteId) - => ClientHelper.GetInviteAsync(this, inviteId, new RequestOptions()); - - /// - public SocketUser GetUser(ulong id) + public override SocketUser GetUser(ulong id) { for (int i = 0; i < _shards.Length; i++) { @@ -213,7 +198,7 @@ namespace Discord.WebSocket return null; } /// - public SocketUser GetUser(string username, string discriminator) + public override SocketUser GetUser(string username, string discriminator) { for (int i = 0; i < _shards.Length; i++) { @@ -225,11 +210,11 @@ namespace Discord.WebSocket } /// - public RestVoiceRegion GetVoiceRegion(string id) + public override RestVoiceRegion GetVoiceRegion(string id) => _shards[0].GetVoiceRegion(id); /// Downloads the users list for the provided guilds, if they don't have a complete list. - public async Task DownloadUsersAsync(IEnumerable guilds) + public override async Task DownloadUsersAsync(IEnumerable guilds) { for (int i = 0; i < _shards.Length; i++) { @@ -248,12 +233,12 @@ namespace Discord.WebSocket return (int)Math.Round(total / (double)_shards.Length); } - public async Task SetStatusAsync(UserStatus status) + public override async Task SetStatusAsync(UserStatus status) { for (int i = 0; i < _shards.Length; i++) await _shards[i].SetStatusAsync(status).ConfigureAwait(false); } - public async Task SetGameAsync(string name, string streamUrl = null, StreamType streamType = StreamType.NotStreaming) + public override async Task SetGameAsync(string name, string streamUrl = null, StreamType streamType = StreamType.NotStreaming) { for (int i = 0; i < _shards.Length; i++) await _shards[i].SetGameAsync(name, streamUrl, streamType).ConfigureAwait(false); @@ -281,6 +266,11 @@ namespace Discord.WebSocket }; } + client.Connected += () => _shardConnectedEvent.InvokeAsync(client); + client.Disconnected += (exception) => _shardDisconnectedEvent.InvokeAsync(exception, client); + client.Ready += () => _shardReadyEvent.InvokeAsync(client); + client.LatencyUpdated += (oldLatency, newLatency) => _shardLatencyUpdatedEvent.InvokeAsync(oldLatency, newLatency, client); + client.ChannelCreated += (channel) => _channelCreatedEvent.InvokeAsync(channel); client.ChannelDestroyed += (channel) => _channelDestroyedEvent.InvokeAsync(channel); client.ChannelUpdated += (oldChannel, newChannel) => _channelUpdatedEvent.InvokeAsync(oldChannel, newChannel); diff --git a/src/Discord.Net.WebSocket/DiscordSocketClient.Events.cs b/src/Discord.Net.WebSocket/DiscordSocketClient.Events.cs index fb155e535..1222b270e 100644 --- a/src/Discord.Net.WebSocket/DiscordSocketClient.Events.cs +++ b/src/Discord.Net.WebSocket/DiscordSocketClient.Events.cs @@ -2,218 +2,37 @@ using System.Threading.Tasks; namespace Discord.WebSocket -{ - //TODO: Add event docstrings +{ public partial class DiscordSocketClient { //General + /// Fired when connected to the Discord gateway. public event Func Connected { add { _connectedEvent.Add(value); } remove { _connectedEvent.Remove(value); } } private readonly AsyncEvent> _connectedEvent = new AsyncEvent>(); + /// Fired when disconnected to the Discord gateway. public event Func Disconnected { add { _disconnectedEvent.Add(value); } remove { _disconnectedEvent.Remove(value); } } private readonly AsyncEvent> _disconnectedEvent = new AsyncEvent>(); + /// Fired when guild data has finished downloading. public event Func Ready { add { _readyEvent.Add(value); } remove { _readyEvent.Remove(value); } } private readonly AsyncEvent> _readyEvent = new AsyncEvent>(); + /// Fired when a heartbeat is received from the Discord gateway. public event Func LatencyUpdated { add { _latencyUpdatedEvent.Add(value); } remove { _latencyUpdatedEvent.Remove(value); } } private readonly AsyncEvent> _latencyUpdatedEvent = new AsyncEvent>(); - - //Channels - public event Func ChannelCreated - { - add { _channelCreatedEvent.Add(value); } - remove { _channelCreatedEvent.Remove(value); } - } - private readonly AsyncEvent> _channelCreatedEvent = new AsyncEvent>(); - public event Func ChannelDestroyed - { - add { _channelDestroyedEvent.Add(value); } - remove { _channelDestroyedEvent.Remove(value); } - } - private readonly AsyncEvent> _channelDestroyedEvent = new AsyncEvent>(); - public event Func ChannelUpdated - { - add { _channelUpdatedEvent.Add(value); } - remove { _channelUpdatedEvent.Remove(value); } - } - private readonly AsyncEvent> _channelUpdatedEvent = new AsyncEvent>(); - - //Messages - public event Func MessageReceived - { - add { _messageReceivedEvent.Add(value); } - remove { _messageReceivedEvent.Remove(value); } - } - private readonly AsyncEvent> _messageReceivedEvent = new AsyncEvent>(); - public event Func, ISocketMessageChannel, Task> MessageDeleted - { - add { _messageDeletedEvent.Add(value); } - remove { _messageDeletedEvent.Remove(value); } - } - private readonly AsyncEvent, ISocketMessageChannel, Task>> _messageDeletedEvent = new AsyncEvent, ISocketMessageChannel, Task>>(); - public event Func, SocketMessage, ISocketMessageChannel, Task> MessageUpdated - { - add { _messageUpdatedEvent.Add(value); } - remove { _messageUpdatedEvent.Remove(value); } - } - private readonly AsyncEvent, SocketMessage, ISocketMessageChannel, Task>> _messageUpdatedEvent = new AsyncEvent, SocketMessage, ISocketMessageChannel, Task>>(); - public event Func, ISocketMessageChannel, SocketReaction, Task> ReactionAdded - { - add { _reactionAddedEvent.Add(value); } - remove { _reactionAddedEvent.Remove(value); } - } - private readonly AsyncEvent, ISocketMessageChannel, SocketReaction, Task>> _reactionAddedEvent = new AsyncEvent, ISocketMessageChannel, SocketReaction, Task>>(); - public event Func, ISocketMessageChannel, SocketReaction, Task> ReactionRemoved - { - add { _reactionRemovedEvent.Add(value); } - remove { _reactionRemovedEvent.Remove(value); } - } - private readonly AsyncEvent, ISocketMessageChannel, SocketReaction, Task>> _reactionRemovedEvent = new AsyncEvent, ISocketMessageChannel, SocketReaction, Task>>(); - public event Func, ISocketMessageChannel, Task> ReactionsCleared - { - add { _reactionsClearedEvent.Add(value); } - remove { _reactionsClearedEvent.Remove(value); } - } - private readonly AsyncEvent, ISocketMessageChannel, Task>> _reactionsClearedEvent = new AsyncEvent, ISocketMessageChannel, Task>>(); - - //Roles - public event Func RoleCreated - { - add { _roleCreatedEvent.Add(value); } - remove { _roleCreatedEvent.Remove(value); } - } - private readonly AsyncEvent> _roleCreatedEvent = new AsyncEvent>(); - public event Func RoleDeleted - { - add { _roleDeletedEvent.Add(value); } - remove { _roleDeletedEvent.Remove(value); } - } - private readonly AsyncEvent> _roleDeletedEvent = new AsyncEvent>(); - public event Func RoleUpdated - { - add { _roleUpdatedEvent.Add(value); } - remove { _roleUpdatedEvent.Remove(value); } - } - private readonly AsyncEvent> _roleUpdatedEvent = new AsyncEvent>(); - - //Guilds - public event Func JoinedGuild - { - add { _joinedGuildEvent.Add(value); } - remove { _joinedGuildEvent.Remove(value); } - } - private readonly AsyncEvent> _joinedGuildEvent = new AsyncEvent>(); - public event Func LeftGuild - { - add { _leftGuildEvent.Add(value); } - remove { _leftGuildEvent.Remove(value); } - } - private readonly AsyncEvent> _leftGuildEvent = new AsyncEvent>(); - public event Func GuildAvailable - { - add { _guildAvailableEvent.Add(value); } - remove { _guildAvailableEvent.Remove(value); } - } - private readonly AsyncEvent> _guildAvailableEvent = new AsyncEvent>(); - public event Func GuildUnavailable - { - add { _guildUnavailableEvent.Add(value); } - remove { _guildUnavailableEvent.Remove(value); } - } - private readonly AsyncEvent> _guildUnavailableEvent = new AsyncEvent>(); - public event Func GuildMembersDownloaded - { - add { _guildMembersDownloadedEvent.Add(value); } - remove { _guildMembersDownloadedEvent.Remove(value); } - } - private readonly AsyncEvent> _guildMembersDownloadedEvent = new AsyncEvent>(); - public event Func GuildUpdated - { - add { _guildUpdatedEvent.Add(value); } - remove { _guildUpdatedEvent.Remove(value); } - } - private readonly AsyncEvent> _guildUpdatedEvent = new AsyncEvent>(); - - //Users - public event Func UserJoined - { - add { _userJoinedEvent.Add(value); } - remove { _userJoinedEvent.Remove(value); } - } - private readonly AsyncEvent> _userJoinedEvent = new AsyncEvent>(); - public event Func UserLeft - { - add { _userLeftEvent.Add(value); } - remove { _userLeftEvent.Remove(value); } - } - private readonly AsyncEvent> _userLeftEvent = new AsyncEvent>(); - public event Func UserBanned - { - add { _userBannedEvent.Add(value); } - remove { _userBannedEvent.Remove(value); } - } - private readonly AsyncEvent> _userBannedEvent = new AsyncEvent>(); - public event Func UserUnbanned - { - add { _userUnbannedEvent.Add(value); } - remove { _userUnbannedEvent.Remove(value); } - } - private readonly AsyncEvent> _userUnbannedEvent = new AsyncEvent>(); - public event Func UserUpdated - { - add { _userUpdatedEvent.Add(value); } - remove { _userUpdatedEvent.Remove(value); } - } - private readonly AsyncEvent> _userUpdatedEvent = new AsyncEvent>(); - public event Func GuildMemberUpdated - { - add { _guildMemberUpdatedEvent.Add(value); } - remove { _guildMemberUpdatedEvent.Remove(value); } - } - private readonly AsyncEvent> _guildMemberUpdatedEvent = new AsyncEvent>(); - public event Func UserVoiceStateUpdated - { - add { _userVoiceStateUpdatedEvent.Add(value); } - remove { _userVoiceStateUpdatedEvent.Remove(value); } - } - private readonly AsyncEvent> _userVoiceStateUpdatedEvent = new AsyncEvent>(); - public event Func CurrentUserUpdated - { - add { _selfUpdatedEvent.Add(value); } - remove { _selfUpdatedEvent.Remove(value); } - } - private readonly AsyncEvent> _selfUpdatedEvent = new AsyncEvent>(); - public event Func UserIsTyping - { - add { _userIsTypingEvent.Add(value); } - remove { _userIsTypingEvent.Remove(value); } - } - private readonly AsyncEvent> _userIsTypingEvent = new AsyncEvent>(); - public event Func RecipientAdded - { - add { _recipientAddedEvent.Add(value); } - remove { _recipientAddedEvent.Remove(value); } - } - private readonly AsyncEvent> _recipientAddedEvent = new AsyncEvent>(); - public event Func RecipientRemoved - { - add { _recipientRemovedEvent.Add(value); } - remove { _recipientRemovedEvent.Remove(value); } - } - private readonly AsyncEvent> _recipientRemovedEvent = new AsyncEvent>(); } } diff --git a/src/Discord.Net.WebSocket/DiscordSocketClient.cs b/src/Discord.Net.WebSocket/DiscordSocketClient.cs index 5256e0efd..09b10aac9 100644 --- a/src/Discord.Net.WebSocket/DiscordSocketClient.cs +++ b/src/Discord.Net.WebSocket/DiscordSocketClient.cs @@ -19,7 +19,7 @@ using GameModel = Discord.API.Game; namespace Discord.WebSocket { - public partial class DiscordSocketClient : BaseDiscordClient, IDiscordClient + public partial class DiscordSocketClient : BaseSocketClient, IDiscordClient { private readonly ConcurrentQueue _largeGuilds; private readonly JsonSerializer _serializer; @@ -44,10 +44,10 @@ namespace Discord.WebSocket public int ShardId { get; } /// Gets the current connection state of this client. public ConnectionState ConnectionState => _connection.State; - /// Gets the estimated round-trip latency, in milliseconds, to the gateway server. - public int Latency { get; private set; } - internal UserStatus Status { get; private set; } = UserStatus.Online; - internal Game? Game { get; private set; } + /// + public override int Latency { get; protected set; } + public override UserStatus Status { get; protected set; } = UserStatus.Online; + public override Game? Game { get; protected set; } //From DiscordSocketConfig internal int TotalShards { get; private set; } @@ -60,14 +60,13 @@ namespace Discord.WebSocket internal int? HandlerTimeout { get; private set; } internal new DiscordSocketApiClient ApiClient => base.ApiClient as DiscordSocketApiClient; - public new SocketSelfUser CurrentUser { get => base.CurrentUser as SocketSelfUser; private set => base.CurrentUser = value; } - public IReadOnlyCollection Guilds => State.Guilds; - public IReadOnlyCollection PrivateChannels => State.PrivateChannels; + public override IReadOnlyCollection Guilds => State.Guilds; + public override IReadOnlyCollection PrivateChannels => State.PrivateChannels; public IReadOnlyCollection DMChannels => State.PrivateChannels.Select(x => x as SocketDMChannel).Where(x => x != null).ToImmutableArray(); public IReadOnlyCollection GroupChannels => State.PrivateChannels.Select(x => x as SocketGroupChannel).Where(x => x != null).ToImmutableArray(); - public IReadOnlyCollection VoiceRegions => _voiceRegions.ToReadOnlyCollection(); + public override IReadOnlyCollection VoiceRegions => _voiceRegions.ToReadOnlyCollection(); /// Creates a new REST/WebSocket discord client. public DiscordSocketClient() : this(new DiscordSocketConfig()) { } @@ -155,9 +154,9 @@ namespace Discord.WebSocket _voiceRegions = ImmutableDictionary.Create(); } - public async Task StartAsync() + public override async Task StartAsync() => await _connection.StartAsync().ConfigureAwait(false); - public async Task StopAsync() + public override async Task StopAsync() => await _connection.StopAsync().ConfigureAwait(false); private async Task OnConnectingAsync() @@ -231,44 +230,23 @@ namespace Discord.WebSocket } /// - public async Task GetApplicationInfoAsync() - { - return _applicationInfo ?? (_applicationInfo = await ClientHelper.GetApplicationInfoAsync(this, new RequestOptions())); - } - - /// - public SocketGuild GetGuild(ulong id) - { - return State.GetGuild(id); - } - /// - public Task CreateGuildAsync(string name, IVoiceRegion region, Stream jpegIcon = null) - => ClientHelper.CreateGuildAsync(this, name, region, jpegIcon, new RequestOptions()); - - /// - public SocketChannel GetChannel(ulong id) - { - return State.GetChannel(id); - } + public override async Task GetApplicationInfoAsync(RequestOptions options = null) + => _applicationInfo ?? (_applicationInfo = await ClientHelper.GetApplicationInfoAsync(this, options ?? RequestOptions.Default).ConfigureAwait(false)); /// - public Task> GetConnectionsAsync() - => ClientHelper.GetConnectionsAsync(this, new RequestOptions()); + public override SocketGuild GetGuild(ulong id) + => State.GetGuild(id); /// - public Task GetInviteAsync(string inviteId) - => ClientHelper.GetInviteAsync(this, inviteId, new RequestOptions()); - + public override SocketChannel GetChannel(ulong id) + => State.GetChannel(id); + /// - public SocketUser GetUser(ulong id) - { - return State.GetUser(id); - } + public override SocketUser GetUser(ulong id) + => State.GetUser(id); /// - public SocketUser GetUser(string username, string discriminator) - { - return State.Users.FirstOrDefault(x => x.Discriminator == discriminator && x.Username == username); - } + public override SocketUser GetUser(string username, string discriminator) + => State.Users.FirstOrDefault(x => x.Discriminator == discriminator && x.Username == username); internal SocketGlobalUser GetOrCreateUser(ClientState state, Discord.API.User model) { return state.GetOrAddUser(model.Id, x => @@ -288,13 +266,11 @@ namespace Discord.WebSocket return user; }); } - internal void RemoveUser(ulong id) - { - State.RemoveUser(id); - } + internal void RemoveUser(ulong id) + => State.RemoveUser(id); /// - public RestVoiceRegion GetVoiceRegion(string id) + public override RestVoiceRegion GetVoiceRegion(string id) { if (_voiceRegions.TryGetValue(id, out RestVoiceRegion region)) return region; @@ -302,7 +278,7 @@ namespace Discord.WebSocket } /// Downloads the users list for the provided guilds, if they don't have a complete list. - public async Task DownloadUsersAsync(IEnumerable guilds) + public override async Task DownloadUsersAsync(IEnumerable guilds) { if (ConnectionState == ConnectionState.Connected) { @@ -340,7 +316,7 @@ namespace Discord.WebSocket } } - public async Task SetStatusAsync(UserStatus status) + public override async Task SetStatusAsync(UserStatus status) { Status = status; if (status == UserStatus.AFK) @@ -349,7 +325,7 @@ namespace Discord.WebSocket _statusSince = null; await SendStatusAsync().ConfigureAwait(false); } - public async Task SetGameAsync(string name, string streamUrl = null, StreamType streamType = StreamType.NotStreaming) + public override async Task SetGameAsync(string name, string streamUrl = null, StreamType streamType = StreamType.NotStreaming) { if (name != null) Game = new Game(name, streamUrl, streamType);