You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

ModuleManager.cs 12 kB

10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. using Discord.Commands;
  2. using Nito.AsyncEx;
  3. using System;
  4. using System.Collections.Concurrent;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. namespace Discord.Modules
  8. {
  9. public class ModuleManager
  10. {
  11. public event EventHandler<ServerEventArgs> ServerEnabled = delegate { };
  12. public event EventHandler<ServerEventArgs> ServerDisabled = delegate { };
  13. public event EventHandler<ChannelEventArgs> ChannelEnabled = delegate { };
  14. public event EventHandler<ChannelEventArgs> ChannelDisabled = delegate { };
  15. public event EventHandler<ServerEventArgs> LeftServer = delegate { };
  16. public event EventHandler<ServerUpdatedEventArgs> ServerUpdated = delegate { };
  17. public event EventHandler<ServerEventArgs> ServerUnavailable = delegate { };
  18. public event EventHandler<ServerEventArgs> ServerAvailable = delegate { };
  19. public event EventHandler<ChannelEventArgs> ChannelCreated = delegate { };
  20. public event EventHandler<ChannelEventArgs> ChannelDestroyed = delegate { };
  21. public event EventHandler<ChannelUpdatedEventArgs> ChannelUpdated = delegate { };
  22. public event EventHandler<RoleEventArgs> RoleCreated = delegate { };
  23. public event EventHandler<RoleUpdatedEventArgs> RoleUpdated = delegate { };
  24. public event EventHandler<RoleEventArgs> RoleDeleted = delegate { };
  25. public event EventHandler<UserEventArgs> UserBanned = delegate { };
  26. public event EventHandler<UserEventArgs> UserJoined = delegate { };
  27. public event EventHandler<UserEventArgs> UserLeft = delegate { };
  28. public event EventHandler<UserUpdatedEventArgs> UserUpdated = delegate { };
  29. //public event EventHandler<UserEventArgs> UserPresenceUpdated = delegate { };
  30. //public event EventHandler<UserEventArgs> UserVoiceStateUpdated = delegate { };
  31. public event EventHandler<UserEventArgs> UserUnbanned = delegate { };
  32. public event EventHandler<ChannelUserEventArgs> UserIsTyping = delegate { };
  33. public event EventHandler<MessageEventArgs> MessageReceived = delegate { };
  34. public event EventHandler<MessageEventArgs> MessageSent = delegate { };
  35. public event EventHandler<MessageEventArgs> MessageDeleted = delegate { };
  36. public event EventHandler<MessageUpdatedEventArgs> MessageUpdated = delegate { };
  37. public event EventHandler<MessageEventArgs> MessageReadRemotely = delegate { };
  38. private readonly bool _useServerWhitelist, _useChannelWhitelist, _allowAll, _allowPrivate;
  39. private readonly ConcurrentDictionary<ulong, Server> _enabledServers;
  40. private readonly ConcurrentDictionary<ulong, Channel> _enabledChannels;
  41. private readonly ConcurrentDictionary<ulong, int> _indirectServers;
  42. private readonly AsyncLock _lock;
  43. public DiscordClient Client { get; }
  44. public IModule Instance { get; }
  45. public string Name { get; }
  46. public string Id { get; }
  47. public ModuleFilter FilterType { get; }
  48. public IEnumerable<Server> EnabledServers => _enabledServers.Select(x => x.Value);
  49. public IEnumerable<Channel> EnabledChannels => _enabledChannels.Select(x => x.Value);
  50. internal ModuleManager(DiscordClient client, IModule instance, string name, ModuleFilter filterType)
  51. {
  52. Client = client;
  53. Instance = instance;
  54. Name = name;
  55. FilterType = filterType;
  56. Id = name.ToLowerInvariant();
  57. _lock = new AsyncLock();
  58. _allowAll = filterType == ModuleFilter.None;
  59. _useServerWhitelist = filterType.HasFlag(ModuleFilter.ServerWhitelist);
  60. _useChannelWhitelist = filterType.HasFlag(ModuleFilter.ChannelWhitelist);
  61. _allowPrivate = filterType.HasFlag(ModuleFilter.AlwaysAllowPrivate);
  62. _enabledServers = new ConcurrentDictionary<ulong, Server>();
  63. _enabledChannels = new ConcurrentDictionary<ulong, Channel>();
  64. _indirectServers = new ConcurrentDictionary<ulong, int>();
  65. if (_allowAll || _useServerWhitelist) //Server-only events
  66. {
  67. client.ChannelCreated += (s, e) => { if (e.Server != null && HasServer(e.Server)) ChannelCreated(s, e); };
  68. //TODO: This *is* a channel update if the before/after voice channel is whitelisted
  69. //client.UserVoiceStateUpdated += (s, e) => { if (HasServer(e.Server)) UserVoiceStateUpdated(s, e); };
  70. }
  71. client.ChannelDestroyed += (s, e) => { if (HasChannel(e.Channel)) ChannelDestroyed(s, e); };
  72. client.ChannelUpdated += (s, e) => { if (HasChannel(e.After)) ChannelUpdated(s, e); };
  73. client.MessageReceived += (s, e) => { if (HasChannel(e.Channel)) MessageReceived(s, e); };
  74. client.MessageSent += (s, e) => { if (HasChannel(e.Channel)) MessageSent(s, e); };
  75. client.MessageDeleted += (s, e) => { if (HasChannel(e.Channel)) MessageDeleted(s, e); };
  76. client.MessageUpdated += (s, e) => { if (HasChannel(e.Channel)) MessageUpdated(s, e); };
  77. client.MessageAcknowledged += (s, e) => { if (HasChannel(e.Channel)) MessageReadRemotely(s, e); };
  78. client.RoleCreated += (s, e) => { if (HasIndirectServer(e.Server)) RoleCreated(s, e); };
  79. client.RoleUpdated += (s, e) => { if (HasIndirectServer(e.Server)) RoleUpdated(s, e); };
  80. client.RoleDeleted += (s, e) => { if (HasIndirectServer(e.Server)) RoleDeleted(s, e); };
  81. client.LeftServer += (s, e) => { if (HasIndirectServer(e.Server)) { DisableServer(e.Server); LeftServer(s, e); } };
  82. client.ServerUpdated += (s, e) => { if (HasIndirectServer(e.After)) ServerUpdated(s, e); };
  83. client.ServerUnavailable += (s, e) => { if (HasIndirectServer(e.Server)) ServerUnavailable(s, e); };
  84. client.ServerAvailable += (s, e) => { if (HasIndirectServer(e.Server)) ServerAvailable(s, e); };
  85. client.UserJoined += (s, e) => { if (HasIndirectServer(e.Server)) UserJoined(s, e); };
  86. client.UserLeft += (s, e) => { if (HasIndirectServer(e.Server)) UserLeft(s, e); };
  87. client.UserUpdated += (s, e) => { if (HasIndirectServer(e.Server)) UserUpdated(s, e); };
  88. client.UserIsTyping += (s, e) => { if (HasChannel(e.Channel)) UserIsTyping(s, e); };
  89. //TODO: We aren't getting events from UserPresence if AllowPrivate is enabled, but the server we know that user through isn't on the whitelist
  90. //client.UserPresenceUpdated += (s, e) => { if (HasIndirectServer(e.Server)) UserPresenceUpdated(s, e); };
  91. client.UserBanned += (s, e) => { if (HasIndirectServer(e.Server)) UserBanned(s, e); };
  92. client.UserUnbanned += (s, e) => { if (HasIndirectServer(e.Server)) UserUnbanned(s, e); };
  93. }
  94. public void CreateCommands(string prefix, Action<CommandGroupBuilder> config)
  95. {
  96. var commandService = Client.Commands(true);
  97. commandService.CreateGroup(prefix, x =>
  98. {
  99. x.Category(Name);
  100. x.AddCheck(new ModuleChecker(this));
  101. config(x);
  102. });
  103. }
  104. public bool EnableServer(Server server)
  105. {
  106. if (server == null) throw new ArgumentNullException(nameof(server));
  107. if (!_useServerWhitelist) throw new InvalidOperationException("This module is not configured to use a server whitelist.");
  108. using (_lock.Lock())
  109. return EnableServerInternal(server);
  110. }
  111. public void EnableServers(IEnumerable<Server> servers)
  112. {
  113. if (servers == null) throw new ArgumentNullException(nameof(servers));
  114. if (servers.Contains(null)) throw new ArgumentException("Collection cannot contain null.", nameof(servers));
  115. if (!_useServerWhitelist) throw new InvalidOperationException("This module is not configured to use a server whitelist.");
  116. using (_lock.Lock())
  117. {
  118. foreach (var server in servers)
  119. EnableServerInternal(server);
  120. }
  121. }
  122. private bool EnableServerInternal(Server server)
  123. {
  124. if (_enabledServers.TryAdd(server.Id, server))
  125. {
  126. if (ServerEnabled != null)
  127. ServerEnabled(this, new ServerEventArgs(server));
  128. return true;
  129. }
  130. return false;
  131. }
  132. public bool DisableServer(Server server)
  133. {
  134. if (server == null) throw new ArgumentNullException(nameof(server));
  135. if (!_useServerWhitelist) return false;
  136. using (_lock.Lock())
  137. {
  138. if (_enabledServers.TryRemove(server.Id, out server))
  139. {
  140. if (ServerDisabled != null)
  141. ServerDisabled(this, new ServerEventArgs(server));
  142. return true;
  143. }
  144. return false;
  145. }
  146. }
  147. public void DisableAllServers()
  148. {
  149. if (!_useServerWhitelist) throw new InvalidOperationException("This module is not configured to use a server whitelist.");
  150. if (!_useServerWhitelist) return;
  151. using (_lock.Lock())
  152. {
  153. if (ServerDisabled != null)
  154. {
  155. foreach (var server in _enabledServers)
  156. ServerDisabled(this, new ServerEventArgs(server.Value));
  157. }
  158. _enabledServers.Clear();
  159. }
  160. }
  161. public bool EnableChannel(Channel channel)
  162. {
  163. if (channel == null) throw new ArgumentNullException(nameof(channel));
  164. if (!_useChannelWhitelist) throw new InvalidOperationException("This module is not configured to use a channel whitelist.");
  165. using (_lock.Lock())
  166. return EnableChannelInternal(channel);
  167. }
  168. public void EnableChannels(IEnumerable<Channel> channels)
  169. {
  170. if (channels == null) throw new ArgumentNullException(nameof(channels));
  171. if (channels.Contains(null)) throw new ArgumentException("Collection cannot contain null.", nameof(channels));
  172. if (!_useChannelWhitelist) throw new InvalidOperationException("This module is not configured to use a channel whitelist.");
  173. using (_lock.Lock())
  174. {
  175. foreach (var channel in channels)
  176. EnableChannelInternal(channel);
  177. }
  178. }
  179. private bool EnableChannelInternal(Channel channel)
  180. {
  181. if (_enabledChannels.TryAdd(channel.Id, channel))
  182. {
  183. var server = channel.Server;
  184. if (server != null)
  185. {
  186. int value = 0;
  187. _indirectServers.TryGetValue(server.Id, out value);
  188. value++;
  189. _indirectServers[server.Id] = value;
  190. }
  191. if (ChannelEnabled != null)
  192. ChannelEnabled(this, new ChannelEventArgs(channel));
  193. return true;
  194. }
  195. return false;
  196. }
  197. public bool DisableChannel(Channel channel)
  198. {
  199. if (channel == null) throw new ArgumentNullException(nameof(channel));
  200. if (!_useChannelWhitelist) return false;
  201. using (_lock.Lock())
  202. {
  203. Channel ignored;
  204. if (_enabledChannels.TryRemove(channel.Id, out ignored))
  205. {
  206. var server = channel.Server;
  207. if (server != null)
  208. {
  209. int value = 0;
  210. _indirectServers.TryGetValue(server.Id, out value);
  211. value--;
  212. if (value <= 0)
  213. _indirectServers.TryRemove(server.Id, out value);
  214. else
  215. _indirectServers[server.Id] = value;
  216. }
  217. if (ChannelDisabled != null)
  218. ChannelDisabled(this, new ChannelEventArgs(channel));
  219. return true;
  220. }
  221. return false;
  222. }
  223. }
  224. public void DisableAllChannels()
  225. {
  226. if (!_useChannelWhitelist) return;
  227. using (_lock.Lock())
  228. {
  229. if (ChannelDisabled != null)
  230. {
  231. foreach (var channel in _enabledChannels)
  232. ChannelDisabled(this, new ChannelEventArgs(channel.Value));
  233. }
  234. _enabledChannels.Clear();
  235. _indirectServers.Clear();
  236. }
  237. }
  238. public void DisableAll()
  239. {
  240. if (_useServerWhitelist)
  241. DisableAllServers();
  242. if (_useChannelWhitelist)
  243. DisableAllChannels();
  244. }
  245. internal bool HasServer(Server server) =>
  246. _allowAll ||
  247. _useServerWhitelist && _enabledServers.ContainsKey(server.Id);
  248. internal bool HasIndirectServer(Server server) =>
  249. _allowAll ||
  250. (_useServerWhitelist && _enabledServers.ContainsKey(server.Id)) ||
  251. (_useChannelWhitelist && _indirectServers.ContainsKey(server.Id));
  252. internal bool HasChannel(Channel channel)
  253. {
  254. if (_allowAll) return true;
  255. if (channel.IsPrivate) return _allowPrivate;
  256. if (_useChannelWhitelist && _enabledChannels.ContainsKey(channel.Id)) return true;
  257. if (_useServerWhitelist)
  258. {
  259. var server = channel.Server;
  260. if (server == null) return false;
  261. if (_enabledServers.ContainsKey(server.Id)) return true;
  262. }
  263. return false;
  264. }
  265. }
  266. }