Ratelimiting done, untested

This commit is contained in:
Kwoth 2016-09-03 15:04:07 +02:00
parent 6d2c9970a7
commit 1c34b97e97
4 changed files with 75 additions and 33 deletions

View File

@ -5,9 +5,10 @@ using NadekoBot.Attributes;
using NadekoBot.Extensions; using NadekoBot.Extensions;
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks; 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 namespace NadekoBot.Modules.Administration
{ {
public partial class Administration public partial class Administration
@ -15,58 +16,101 @@ namespace NadekoBot.Modules.Administration
[Group] [Group]
public class RatelimitCommand 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; } 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() public RatelimitCommand()
{ {
this._client = NadekoBot.Client; this._client = NadekoBot.Client;
_client.MessageReceived += async (umsg) => _client.MessageReceived += (umsg) =>
{
var t = Task.Run(async () =>
{ {
var usrMsg = umsg as IUserMessage; var usrMsg = umsg as IUserMessage;
var channel = usrMsg.Channel as ITextChannel; var channel = usrMsg.Channel as ITextChannel;
if (channel == null || await usrMsg.IsAuthor()) if (channel == null || await usrMsg.IsAuthor())
return; return;
ConcurrentDictionary<ulong, DateTime> userTimePair; Ratelimiter limiter;
if (!RatelimitingChannels.TryGetValue(channel.Id, out userTimePair)) return; if (!RatelimitingChannels.TryGetValue(channel.Id, out limiter))
DateTime lastMessageTime;
if (userTimePair.TryGetValue(usrMsg.Author.Id, out lastMessageTime))
{
if (DateTime.Now - lastMessageTime < ratelimitTime)
{
try
{
await usrMsg.DeleteAsync().ConfigureAwait(false);
}
catch { }
return; return;
}
} if (limiter.CheckUserRatelimit(usrMsg.Author.Id))
userTimePair.AddOrUpdate(usrMsg.Author.Id, id => DateTime.Now, (id, dt) => DateTime.Now); await usrMsg.DeleteAsync();
});
return Task.CompletedTask;
}; };
} }
[LocalizedCommand, LocalizedDescription, LocalizedSummary] [LocalizedCommand, LocalizedDescription, LocalizedSummary]
[RequireContext(ContextType.Guild)] [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; var channel = (ITextChannel)umsg.Channel;
ConcurrentDictionary<ulong, DateTime> throwaway; Ratelimiter throwaway;
if (RatelimitingChannels.TryRemove(channel.Id, out 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; return;
} }
if (RatelimitingChannels.TryAdd(channel.Id, new ConcurrentDictionary<ulong, DateTime>()))
if (msg < 1 || perSec < 1)
{ {
await channel.SendMessageAsync("Slow mode initiated. " + await channel.SendMessageAsync("`Invalid parameters.`");
"Users can't send more than 1 message every 5 seconds.") 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); .ConfigureAwait(false);
} }
} }

View File

@ -7,7 +7,6 @@ using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
// todo rewrite
namespace NadekoBot.Modules.Games.Trivia namespace NadekoBot.Modules.Games.Trivia
{ {
public class TriviaGame public class TriviaGame

View File

@ -417,7 +417,7 @@ namespace NadekoBot.Modules.Music
musicPlayer.RemoveSongAt(num - 1); musicPlayer.RemoveSongAt(num - 1);
await channel.SendMessageAsync($"🎵**Track {song.PrettyName} at position `#{num}` has been removed.**").ConfigureAwait(false); await channel.SendMessageAsync($"🎵**Track {song.PrettyName} at position `#{num}` has been removed.**").ConfigureAwait(false);
} }
//todo fix
[LocalizedCommand, LocalizedDescription, LocalizedSummary] [LocalizedCommand, LocalizedDescription, LocalizedSummary]
[RequireContext(ContextType.Guild)] [RequireContext(ContextType.Guild)]
public async Task Remove(IUserMessage umsg, string all) public async Task Remove(IUserMessage umsg, string all)

View File

@ -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 res = await http.GetStringAsync("http://anilist.co/api/manga/search/" + Uri.EscapeUriString(query) + $"?access_token={anilistToken}").ConfigureAwait(false);
var smallObj = JArray.Parse(res)[0]; 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); 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); return await Task.Run(() => JsonConvert.DeserializeObject<MangaResult>(aniData)).ConfigureAwait(false);