Ratelimiting done, untested
This commit is contained in:
		| @@ -5,9 +5,10 @@ using NadekoBot.Attributes; | ||||
| using NadekoBot.Extensions; | ||||
| using System; | ||||
| using System.Collections.Concurrent; | ||||
| using System.Threading; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| //todo rewrite to accept msg/sec (for example 1/5 - 1 message every 5 seconds) | ||||
| //todo rewrite | ||||
| namespace NadekoBot.Modules.Administration | ||||
| { | ||||
|     public partial class Administration | ||||
| @@ -15,58 +16,101 @@ namespace NadekoBot.Modules.Administration | ||||
|         [Group] | ||||
|         public class RatelimitCommand | ||||
|         { | ||||
|             public static ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, DateTime>> RatelimitingChannels = new ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, DateTime>>(); | ||||
|             public static ConcurrentDictionary<ulong, Ratelimiter> RatelimitingChannels = new ConcurrentDictionary<ulong, Ratelimiter>(); | ||||
|  | ||||
|             private static readonly TimeSpan ratelimitTime = new TimeSpan(0, 0, 0, 5); | ||||
|             private DiscordSocketClient _client { get; } | ||||
|  | ||||
|             public class Ratelimiter | ||||
|             { | ||||
|                 public class RatelimitedUser | ||||
|                 { | ||||
|                     public ulong UserId { get; set; } | ||||
|                     public int MessageCount { get; set; } = 0; | ||||
|                 } | ||||
|  | ||||
|                 public ulong ChannelId { get; set; } | ||||
|  | ||||
|                 public int MaxMessages { get; set; } | ||||
|                 public int PerSeconds { get; set; } | ||||
|  | ||||
|                 public CancellationTokenSource cancelSource { get; set; } | ||||
|                 public CancellationToken cancelToken { get; set; } | ||||
|  | ||||
|                 public ConcurrentDictionary<ulong, RatelimitedUser> Users { get; set; } | ||||
|  | ||||
|                 public bool CheckUserRatelimit(ulong id) | ||||
|                 { | ||||
|                     RatelimitedUser usr = Users.GetOrAdd(id, (key) => new RatelimitedUser() { UserId = id }); | ||||
|                     if (usr.MessageCount == MaxMessages) | ||||
|                     { | ||||
|                         return true; | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         usr.MessageCount++; | ||||
|                         var t = Task.Run(async () => { | ||||
|                             try | ||||
|                             { | ||||
|                                 await Task.Delay(PerSeconds * 1000, cancelToken); | ||||
|                             } | ||||
|                             catch (OperationCanceledException) { } | ||||
|                             usr.MessageCount--; | ||||
|                         }); | ||||
|                         return false; | ||||
|                     } | ||||
|  | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             public RatelimitCommand() | ||||
|             { | ||||
|  | ||||
|                 this._client = NadekoBot.Client; | ||||
|  | ||||
|                _client.MessageReceived += async (umsg) => | ||||
|                _client.MessageReceived += (umsg) => | ||||
|                 { | ||||
|                     var usrMsg = umsg as IUserMessage; | ||||
|                     var channel = usrMsg.Channel as ITextChannel; | ||||
|  | ||||
|                     if (channel == null || await usrMsg.IsAuthor()) | ||||
|                         return; | ||||
|                     ConcurrentDictionary<ulong, DateTime> userTimePair; | ||||
|                     if (!RatelimitingChannels.TryGetValue(channel.Id, out userTimePair)) return; | ||||
|                     DateTime lastMessageTime; | ||||
|                     if (userTimePair.TryGetValue(usrMsg.Author.Id, out lastMessageTime)) | ||||
|                     var t = Task.Run(async () => | ||||
|                     { | ||||
|                         if (DateTime.Now - lastMessageTime < ratelimitTime) | ||||
|                         { | ||||
|                             try | ||||
|                             { | ||||
|                                 await usrMsg.DeleteAsync().ConfigureAwait(false); | ||||
|                             } | ||||
|                             catch { } | ||||
|                         var usrMsg = umsg as IUserMessage; | ||||
|                         var channel = usrMsg.Channel as ITextChannel; | ||||
|  | ||||
|                         if (channel == null || await usrMsg.IsAuthor()) | ||||
|                             return; | ||||
|                         } | ||||
|                     } | ||||
|                     userTimePair.AddOrUpdate(usrMsg.Author.Id, id => DateTime.Now, (id, dt) => DateTime.Now); | ||||
|                         Ratelimiter limiter; | ||||
|                         if (!RatelimitingChannels.TryGetValue(channel.Id, out limiter)) | ||||
|                             return; | ||||
|  | ||||
|                         if (limiter.CheckUserRatelimit(usrMsg.Author.Id)) | ||||
|                             await usrMsg.DeleteAsync(); | ||||
|                     }); | ||||
|                     return Task.CompletedTask; | ||||
|                 }; | ||||
|             } | ||||
|  | ||||
|             [LocalizedCommand, LocalizedDescription, LocalizedSummary] | ||||
|             [RequireContext(ContextType.Guild)] | ||||
|             public async Task Slowmode(IUserMessage umsg) | ||||
|             public async Task Slowmode(IUserMessage umsg, int msg = 1, int perSec = 5) | ||||
|             { | ||||
|                 var channel = (ITextChannel)umsg.Channel; | ||||
|  | ||||
|                 ConcurrentDictionary<ulong, DateTime> throwaway; | ||||
|                 Ratelimiter throwaway; | ||||
|                 if (RatelimitingChannels.TryRemove(channel.Id, out throwaway)) | ||||
|                 { | ||||
|                     await channel.SendMessageAsync("Slow mode disabled.").ConfigureAwait(false); | ||||
|                     await channel.SendMessageAsync("`Slow mode disabled.`").ConfigureAwait(false); | ||||
|                     return; | ||||
|                 } | ||||
|                 if (RatelimitingChannels.TryAdd(channel.Id, new ConcurrentDictionary<ulong, DateTime>())) | ||||
|  | ||||
|                 if (msg < 1 || perSec < 1) | ||||
|                 { | ||||
|                     await channel.SendMessageAsync("Slow mode initiated. " + | ||||
|                                                 "Users can't send more than 1 message every 5 seconds.") | ||||
|                     await channel.SendMessageAsync("`Invalid parameters.`"); | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
|                 if (RatelimitingChannels.TryAdd(channel.Id,throwaway = new Ratelimiter() { | ||||
|                     ChannelId = channel.Id | ||||
|                 })) | ||||
|                 { | ||||
|                     await channel.SendMessageAsync("`Slow mode initiated.` " + | ||||
|                                                 $"Users can't send more than {throwaway.MaxMessages} message(s) every {throwaway.PerSeconds} second(s).") | ||||
|                                                 .ConfigureAwait(false); | ||||
|                 } | ||||
|             } | ||||
|   | ||||
| @@ -7,7 +7,6 @@ using System.Text; | ||||
| using System.Threading; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| // todo rewrite | ||||
| namespace NadekoBot.Modules.Games.Trivia | ||||
| { | ||||
|     public class TriviaGame | ||||
|   | ||||
| @@ -417,7 +417,7 @@ namespace NadekoBot.Modules.Music | ||||
|             musicPlayer.RemoveSongAt(num - 1); | ||||
|             await channel.SendMessageAsync($"🎵**Track {song.PrettyName} at position `#{num}` has been removed.**").ConfigureAwait(false); | ||||
|         } | ||||
|         //todo fix | ||||
|  | ||||
|         [LocalizedCommand, LocalizedDescription, LocalizedSummary] | ||||
|         [RequireContext(ContextType.Guild)] | ||||
|         public async Task Remove(IUserMessage umsg, string all) | ||||
|   | ||||
| @@ -117,7 +117,6 @@ namespace NadekoBot.Modules.Searches | ||||
|                     { | ||||
|                         var res = await http.GetStringAsync("http://anilist.co/api/manga/search/" + Uri.EscapeUriString(query) + $"?access_token={anilistToken}").ConfigureAwait(false); | ||||
|                         var smallObj = JArray.Parse(res)[0]; | ||||
|                         //todo check if successfull | ||||
|                         var aniData = await http.GetStringAsync("http://anilist.co/api/manga/" + smallObj["id"] + $"?access_token={anilistToken}").ConfigureAwait(false); | ||||
|  | ||||
|                         return await Task.Run(() => JsonConvert.DeserializeObject<MangaResult>(aniData)).ConfigureAwait(false); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user