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 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);
}
}

View File

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

View File

@ -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)

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 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);