From 152df2b3a148ae06974de8b909e46c2fae923c91 Mon Sep 17 00:00:00 2001 From: RogueException Date: Thu, 5 Nov 2015 22:39:37 -0400 Subject: [PATCH] Initial commit of Modules extension --- src/Discord.Net.Modules/IModule.cs | 7 + src/Discord.Net.Modules/ModuleManager.cs | 213 +++++++++++++++++++++++ src/Discord.Net.Modules/ModuleService.cs | 34 ++++ src/Discord.Net.Modules/ModuleType.cs | 17 ++ 4 files changed, 271 insertions(+) create mode 100644 src/Discord.Net.Modules/IModule.cs create mode 100644 src/Discord.Net.Modules/ModuleManager.cs create mode 100644 src/Discord.Net.Modules/ModuleService.cs create mode 100644 src/Discord.Net.Modules/ModuleType.cs diff --git a/src/Discord.Net.Modules/IModule.cs b/src/Discord.Net.Modules/IModule.cs new file mode 100644 index 000000000..f45e48379 --- /dev/null +++ b/src/Discord.Net.Modules/IModule.cs @@ -0,0 +1,7 @@ +namespace Discord +{ + public interface IModule + { + void Install(ModuleManager manager); + } +} diff --git a/src/Discord.Net.Modules/ModuleManager.cs b/src/Discord.Net.Modules/ModuleManager.cs new file mode 100644 index 000000000..b2395d77d --- /dev/null +++ b/src/Discord.Net.Modules/ModuleManager.cs @@ -0,0 +1,213 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; + +namespace Discord +{ + public class ModuleManager + { + public event EventHandler ServerEnabled; + public event EventHandler ServerDisbled; + public event EventHandler ChannelEnabled; + public event EventHandler ChannelDisbled; + + public event EventHandler LeftServer; + public event EventHandler ServerUpdated; + public event EventHandler ServerUnavailable; + public event EventHandler ServerAvailable; + + public event EventHandler UserBanned; + public event EventHandler UserUnbanned; + + public event EventHandler ChannelCreated; + public event EventHandler ChannelDestroyed; + public event EventHandler ChannelUpdated; + + public event EventHandler RoleCreated; + public event EventHandler RoleUpdated; + public event EventHandler RoleDeleted; + + public event EventHandler UserJoined; + public event EventHandler UserLeft; + public event EventHandler UserUpdated; + public event EventHandler UserPresenceUpdated; + public event EventHandler UserVoiceStateUpdated; + public event EventHandler UserIsTypingUpdated; + public event EventHandler UserIsSpeakingUpdated; + + public event EventHandler MessageReceived; + public event EventHandler MessageSent; + public event EventHandler MessageDeleted; + public event EventHandler MessageUpdated; + public event EventHandler MessageReadRemotely; + + private readonly bool _allowServerWhitelist, _allowChannelWhitelist, _allowPrivate; + private readonly ConcurrentDictionary _enabledServers; + private readonly ConcurrentDictionary _enabledChannels; + private readonly ConcurrentDictionary _indirectServers; + + public IEnumerable EnabledServers => _enabledServers.Select(x => x.Value); + public IEnumerable EnabledChannels => _enabledChannels.Select(x => x.Value); + + internal ModuleManager(DiscordClient client, FilterType type) + { + _allowServerWhitelist = type.HasFlag(FilterType.Server); + _allowChannelWhitelist = type.HasFlag(FilterType.Channel); + _allowPrivate = type.HasFlag(FilterType.AllowPrivate); + + _enabledServers = new ConcurrentDictionary(); + _enabledChannels = new ConcurrentDictionary(); + _indirectServers = new ConcurrentDictionary(); + + if (_allowServerWhitelist) //Server-only events + { + client.LeftServer += (s, e) => { if (LeftServer != null && HasIndirectServer(e.Server)) DisableServer(e.Server); LeftServer(s, e); }; + client.ServerUpdated += (s, e) => { if (ServerUpdated != null && HasIndirectServer(e.Server)) ServerUpdated(s, e); }; + client.ServerUnavailable += (s, e) => { if (ServerUnavailable != null && HasIndirectServer(e.Server)) ServerUnavailable(s, e); }; + client.ServerAvailable += (s, e) => { if (ServerAvailable != null && HasIndirectServer(e.Server)) ServerAvailable(s, e); }; + + client.UserBanned += (s, e) => { if (UserBanned != null && HasIndirectServer(e.Server)) UserBanned(s, e); }; + client.UserUnbanned += (s, e) => { if (UserUnbanned != null && HasIndirectServer(e.Server)) UserUnbanned(s, e); }; + + client.ChannelCreated += (s, e) => { if (ChannelCreated != null && HasServer(e.Server)) ChannelCreated(s, e); }; + client.ChannelDestroyed += (s, e) => { if (ChannelDestroyed != null && HasChannel(e.Channel)) ChannelDestroyed(s, e); }; + client.ChannelUpdated += (s, e) => { if (ChannelUpdated != null && HasChannel(e.Channel)) ChannelUpdated(s, e); }; + + client.RoleCreated += (s, e) => { if (RoleCreated != null && HasIndirectServer(e.Server)) RoleCreated(s, e); }; + client.RoleUpdated += (s, e) => { if (RoleUpdated != null && HasIndirectServer(e.Server)) RoleUpdated(s, e); }; + client.RoleDeleted += (s, e) => { if (RoleDeleted != null && HasIndirectServer(e.Server)) RoleDeleted(s, e); }; + + client.UserJoined += (s, e) => { if (UserJoined != null && HasIndirectServer(e.Server)) UserJoined(s, e); }; + client.UserLeft += (s, e) => { if (UserLeft != null && HasIndirectServer(e.Server)) UserLeft(s, e); }; + client.UserUpdated += (s, e) => { if (UserUpdated != null && HasIndirectServer(e.Server)) UserUpdated(s, e); }; + client.UserPresenceUpdated += (s, e) => { if (UserPresenceUpdated != null && HasIndirectServer(e.Server)) UserPresenceUpdated(s, e); }; + client.UserVoiceStateUpdated += (s, e) => { if (UserVoiceStateUpdated != null && HasServer(e.Server)) UserVoiceStateUpdated(s, e); }; + client.UserIsTypingUpdated += (s, e) => { if (UserIsSpeakingUpdated != null && HasChannel(e.Channel)) UserIsTypingUpdated(s, e); }; + client.UserIsSpeakingUpdated += (s, e) => { if (UserIsSpeakingUpdated != null && HasServer(e.Server)) UserIsSpeakingUpdated(s, e); }; + + client.MessageReceived += (s, e) => { if (MessageReceived != null && HasChannel(e.Channel)) MessageReceived(s, e); }; + client.MessageSent += (s, e) => { if (MessageSent != null && HasChannel(e.Channel)) MessageSent(s, e); }; + client.MessageDeleted += (s, e) => { if (MessageDeleted != null && HasChannel(e.Channel)) MessageDeleted(s, e); }; + client.MessageUpdated += (s, e) => { if (MessageUpdated != null && HasChannel(e.Channel)) MessageUpdated(s, e); }; + client.MessageReadRemotely += (s, e) => { if (MessageReadRemotely != null && HasChannel(e.Channel)) MessageReadRemotely(s, e); }; + client.MessageReceived += (s, e) => { if (MessageReceived != null && HasChannel(e.Channel)) MessageReceived(s, e); }; + } + } + + public bool EnableServer(Server server) + { + if (server == null) throw new ArgumentNullException(nameof(server)); + if (!_allowServerWhitelist) throw new InvalidOperationException("This module is not configured to use a server whitelist."); + + if (_enabledServers.TryAdd(server.Id, server)) + { + if (ServerEnabled != null) + ServerEnabled(this, new ServerEventArgs(server)); + return true; + } + return false; + } + public bool DisableServer(Server server) + { + if (server == null) throw new ArgumentNullException(nameof(server)); + if (!_allowServerWhitelist) throw new InvalidOperationException("This module is not configured to use a server whitelist."); + + if (_enabledServers.TryRemove(server.Id, out server)) + { + if (ServerDisbled != null) + ServerDisbled(this, new ServerEventArgs(server)); + return true; + } + return false; + } + public void DisableAllServers() + { + if (!_allowServerWhitelist) throw new InvalidOperationException("This module is not configured to use a server whitelist."); + + _enabledServers.Clear(); + } + + public void EnableChannel(Channel channel) + { + if (channel == null) throw new ArgumentNullException(nameof(channel)); + if (!_allowChannelWhitelist) throw new InvalidOperationException("This module is not configured to use a channel whitelist."); + + lock (this) + { + _enabledChannels[channel.Id] = channel; + var server = channel.Server; + if (server != null) + { + int value = 0; + _indirectServers.TryGetValue(server.Id, out value); + value++; + _indirectServers[server.Id] = value; + } + } + } + public bool DisableChannel(Channel channel) + { + if (channel == null) throw new ArgumentNullException(nameof(channel)); + if (!_allowChannelWhitelist) throw new InvalidOperationException("This module is not configured to use a channel whitelist."); + + lock (this) + { + Channel ignored; + if (_enabledChannels.TryRemove(channel.Id, out ignored)) + { + var server = channel.Server; + if (server != null) + { + int value = 0; + _indirectServers.TryGetValue(server.Id, out value); + value--; + if (value <= 0) + _indirectServers.TryRemove(server.Id, out value); + else + _indirectServers[server.Id] = value; + } + return true; + } + return false; + } + } + public void DisableAllChannels() + { + if (!_allowChannelWhitelist) throw new InvalidOperationException("This module is not configured to use a channel whitelist."); + + lock (this) + { + _enabledChannels.Clear(); + _indirectServers.Clear(); + } + } + + public void DisableAll() + { + if (_allowServerWhitelist) + DisableAllServers(); + if (_allowChannelWhitelist) + DisableAllChannels(); + } + + private bool HasServer(Server server) => + _allowServerWhitelist && _enabledServers.ContainsKey(server.Id); + private bool HasIndirectServer(Server server) => + (_allowServerWhitelist && _enabledServers.ContainsKey(server.Id)) || + (_allowChannelWhitelist && _indirectServers.ContainsKey(server.Id)); + private bool HasChannel(Channel channel) + { + if (channel.IsPrivate) return _allowPrivate; + + if (_allowChannelWhitelist && _enabledChannels.ContainsKey(channel.Id)) return true; + if (_allowServerWhitelist) + { + var server = channel.Server; + if (server == null) return false; + if (_enabledServers.ContainsKey(server.Id)) return true; + } + return false; + } + } +} diff --git a/src/Discord.Net.Modules/ModuleService.cs b/src/Discord.Net.Modules/ModuleService.cs new file mode 100644 index 000000000..d99907c0e --- /dev/null +++ b/src/Discord.Net.Modules/ModuleService.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; + +namespace Discord +{ + public class ModuleService : IService + { + private DiscordClient _client; + + //ModuleServiceConfig Config { get; } + public IEnumerable Modules => _modules.Keys; + private readonly Dictionary _modules; + + public ModuleService(/*ModuleServiceConfig config*/) + { + //Config = config; + _modules = new Dictionary(); + } + + void IService.Install(DiscordClient client) + { + _client = client; + } + + public void Install(IModule module, FilterType type) + { + if (_modules.ContainsKey(module)) throw new InvalidOperationException("This module has already been added."); + + var manager = new ModuleManager(_client, type); + _modules.Add(module, manager); + module.Install(manager); + } + } +} diff --git a/src/Discord.Net.Modules/ModuleType.cs b/src/Discord.Net.Modules/ModuleType.cs new file mode 100644 index 000000000..514beb3d1 --- /dev/null +++ b/src/Discord.Net.Modules/ModuleType.cs @@ -0,0 +1,17 @@ +using System; + +namespace Discord +{ + [Flags] + public enum FilterType + { + /// Disables the event filter. + Disabled = 0x0, + /// Uses the server whitelist to filter events. + Server = 0x1, + /// Uses the channel whitelist to filter events. + Channel = 0x2, + /// Enables this module in all private messages. + AllowPrivate = 0x4 + } +}