Aliasing fixed, finishing up almost

This commit is contained in:
Master Kwoth 2017-05-30 01:53:16 +02:00
parent 6d27271d4a
commit bb897fc43d
14 changed files with 182 additions and 151 deletions

View File

@ -9,6 +9,6 @@ namespace NadekoBot.DataStructures.ModuleBehaviors
/// </summary>
public interface IEarlyBlocker
{
Task<bool> TryBlockEarly(DiscordShardedClient client, IGuild guild, IUserMessage msg);
Task<bool> TryBlockEarly(IGuild guild, IUserMessage msg);
}
}

View File

@ -0,0 +1,10 @@
using Discord;
using System.Threading.Tasks;
namespace NadekoBot.DataStructures.ModuleBehaviors
{
public interface IInputTransformer
{
Task<string> TransformInput(IGuild guild, IMessageChannel channel, IUser user, string input);
}
}

View File

@ -15,8 +15,7 @@ namespace NadekoBot.Modules
public readonly string Prefix;
public readonly string ModuleTypeName;
public readonly string LowerModuleTypeName;
//todo :thinking:
public NadekoStrings _strings { get; set; }
public ILocalization _localization { get; set; }

View File

@ -19,11 +19,11 @@ namespace NadekoBot.Modules.Utility
[Group]
public class CommandMapCommands : NadekoSubmodule
{
private readonly UtilityService _service;
private readonly CommandMapService _service;
private readonly DbService _db;
private readonly DiscordShardedClient _client;
public CommandMapCommands(UtilityService service, DbService db, DiscordShardedClient client)
public CommandMapCommands(CommandMapService service, DbService db, DiscordShardedClient client)
{
_service = service;
_db = db;

View File

@ -14,9 +14,9 @@ namespace NadekoBot.Modules.Utility
[Group]
public class CrossServerTextChannel : NadekoSubmodule
{
private readonly UtilityService _service;
private readonly CrossServerTextService _service;
public CrossServerTextChannel(UtilityService service)
public CrossServerTextChannel(CrossServerTextService service)
{
_service = service;
}

View File

@ -16,25 +16,23 @@ using System.Collections.Generic;
using Newtonsoft.Json;
using Discord.WebSocket;
using System.Diagnostics;
using NadekoBot.Modules;
using Color = Discord.Color;
using NadekoBot.Services;
namespace NadekoBot.Services.Utility
namespace NadekoBot.Modules.Utility
{
public partial class Utility : NadekoTopLevelModule
{
private static ConcurrentDictionary<ulong, Timer> _rotatingRoleColors = new ConcurrentDictionary<ulong, Timer>();
private readonly DiscordShardedClient _client;
private readonly IStatsService _stats;
private readonly UtilityService _service;
//private readonly MusicService _music;
private readonly IBotCredentials _creds;
public Utility(UtilityService service, DiscordShardedClient client, IStatsService stats, IBotCredentials creds)
public Utility(DiscordShardedClient client, IStatsService stats, IBotCredentials creds)
{
_client = client;
_stats = stats;
_service = service;
//_music = music;
_creds = creds;
}

View File

@ -105,10 +105,11 @@ namespace NadekoBot
//module services
//todo 90 - autodiscover, DI, and add instead of manual like this
#region utility
var utilityService = new UtilityService(AllGuildConfigs, Client);
var crossServerTextService = new CrossServerTextService(AllGuildConfigs, Client);
var remindService = new RemindService(Client, BotConfig, Db);
var repeaterService = new MessageRepeaterService(Client, AllGuildConfigs);
var converterService = new ConverterService(Db);
var commandMapService = new CommandMapService(AllGuildConfigs);
#endregion
#region Searches
@ -142,7 +143,7 @@ namespace NadekoBot
var permissionsService = new PermissionsService(Db, BotConfig);
var blacklistService = new BlacklistService(BotConfig);
var cmdcdsService = new CmdCdService(AllGuildConfigs);
var filterService = new FilterService(AllGuildConfigs);
var filterService = new FilterService(Client, AllGuildConfigs);
var globalPermsService = new GlobalPermissionService(BotConfig);
#endregion
@ -162,7 +163,8 @@ namespace NadekoBot
.Add<CommandHandler>(commandHandler)
.Add<DbService>(Db)
//modules
.Add<UtilityService>(utilityService)
.Add(crossServerTextService)
.Add(commandMapService)
.Add(remindService)
.Add(repeaterService)
.Add(converterService)

View File

@ -88,27 +88,6 @@ namespace NadekoBot.Services
public Task StartHandling()
{
_client.MessageReceived += MessageReceivedHandler;
_client.MessageUpdated += (oldmsg, newMsg, channel) =>
{
var ignore = Task.Run(() =>
{
try
{
var usrMsg = newMsg as SocketUserMessage;
var guild = (usrMsg?.Channel as ITextChannel)?.Guild;
////todo invite filtering
//if (guild != null && !await InviteFiltered(guild, usrMsg).ConfigureAwait(false))
// await WordFiltered(guild, usrMsg).ConfigureAwait(false);
}
catch (Exception ex)
{
_log.Warn(ex);
}
return Task.CompletedTask;
});
return Task.CompletedTask;
};
return Task.CompletedTask;
}
@ -182,18 +161,20 @@ namespace NadekoBot.Services
{
var execTime = Environment.TickCount;
//its nice to have early blockers and early blocking executors separate, but
//i could also have one interface with priorities, and just put early blockers on
//highest priority. :thinking:
foreach (var svc in _services)
{
if (svc is IEarlyBlocker blocker &&
await blocker.TryBlockEarly(_client, guild, usrMsg).ConfigureAwait(false))
await blocker.TryBlockEarly(guild, usrMsg).ConfigureAwait(false))
{
_log.Info("Blocked User: [{0}] Message: [{1}] Service: [{2}]", usrMsg.Author, usrMsg.Content, svc.GetType().Name);
return;
}
}
var exec2 = Environment.TickCount - execTime;
var exec2 = Environment.TickCount - execTime;
foreach (var svc in _services)
{
@ -208,44 +189,21 @@ namespace NadekoBot.Services
var exec3 = Environment.TickCount - execTime;
string messageContent = usrMsg.Content;
////todo alias mapping
// if (guild != null)
// {
// if (Modules.Utility.Utility.CommandMapCommands.AliasMaps.TryGetValue(guild.Id, out ConcurrentDictionary<string, string> maps))
// {
// var keys = maps.Keys
// .OrderByDescending(x => x.Length);
// var lowerMessageContent = messageContent.ToLowerInvariant();
// foreach (var k in keys)
// {
// string newMessageContent;
// if (lowerMessageContent.StartsWith(k + " "))
// newMessageContent = maps[k] + messageContent.Substring(k.Length, messageContent.Length - k.Length);
// else if (lowerMessageContent == k)
// newMessageContent = maps[k];
// else
// continue;
// _log.Info(@"--Mapping Command--
//GuildId: {0}
//Trigger: {1}
//Mapping: {2}", guild.Id, messageContent, newMessageContent);
// var oldMessageContent = messageContent;
// messageContent = newMessageContent;
// try { await usrMsg.Channel.SendConfirmAsync($"{oldMessageContent} => {newMessageContent}").ConfigureAwait(false); } catch { }
// break;
// }
// }
// }
foreach (var svc in _services)
{
string newContent;
if (svc is IInputTransformer exec &&
(newContent = await exec.TransformInput(guild, usrMsg.Channel, usrMsg.Author, messageContent).ConfigureAwait(false)) != messageContent.ToLowerInvariant())
{
messageContent = newContent;
break;
}
}
// execute the command and measure the time it took
if (messageContent.StartsWith(NadekoBot.Prefix))
{
var exec = await Task.Run(() => ExecuteCommandAsync(new CommandContext(_client, usrMsg), NadekoBot.Prefix.Length, _services, MultiMatchHandling.Best)).ConfigureAwait(false);
var exec = await Task.Run(() => ExecuteCommandAsync(new CommandContext(_client, usrMsg), messageContent, NadekoBot.Prefix.Length, _services, MultiMatchHandling.Best)).ConfigureAwait(false);
execTime = Environment.TickCount - execTime;
////todo commandHandler
@ -281,8 +239,8 @@ namespace NadekoBot.Services
}
public Task<bool> ExecuteCommandAsync(CommandContext context, int argPos, IServiceProvider serviceProvider, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
=> ExecuteCommand(context, context.Message.Content.Substring(argPos), serviceProvider, multiMatchHandling);
public Task<bool> ExecuteCommandAsync(CommandContext context, string input, int argPos, IServiceProvider serviceProvider, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
=> ExecuteCommand(context, input.Substring(argPos), serviceProvider, multiMatchHandling);
public async Task<bool> ExecuteCommand(CommandContext context, string input, IServiceProvider serviceProvider, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
@ -333,25 +291,6 @@ namespace NadekoBot.Services
var module = cmd.Module.GetTopLevelModule();
if (context.Guild != null)
{
////todo perms
//PermissionCache pc = Permissions.GetCache(context.Guild.Id);
//if (!resetCommand && !pc.Permissions.CheckPermissions(context.Message, cmd.Aliases.First(), module.Name, out int index))
//{
// var returnMsg = $"Permission number #{index + 1} **{pc.Permissions[index].GetCommand((SocketGuild)context.Guild)}** is preventing this action.";
// return new ExecuteCommandResult(cmd, pc, SearchResult.FromError(CommandError.Exception, returnMsg));
//}
//if (module.Name == typeof(Permissions).Name)
//{
// var guildUser = (IGuildUser)context.User;
// if (!guildUser.GetRoles().Any(r => r.Name.Trim().ToLowerInvariant() == pc.PermRole.Trim().ToLowerInvariant()) && guildUser.Id != guildUser.Guild.OwnerId)
// {
// return new ExecuteCommandResult(cmd, pc, SearchResult.FromError(CommandError.Exception, $"You need the **{pc.PermRole}** role in order to use permission commands."));
// }
//}
//////future
////int price;
////if (Permissions.CommandCostCommands.CommandCosts.TryGetValue(cmd.Aliases.First().Trim().ToLowerInvariant(), out price) && price > 0)
@ -364,14 +303,6 @@ namespace NadekoBot.Services
////}
}
////todo perms
//if (cmd.Name != "resetglobalperms" &&
// (GlobalPermissionCommands.BlockedCommands.Contains(cmd.Aliases.First().ToLowerInvariant()) ||
// GlobalPermissionCommands.BlockedModules.Contains(module.Name.ToLowerInvariant())))
//{
// return new ExecuteCommandResult(cmd, null, SearchResult.FromError(CommandError.Exception, $"Command or module is blocked globally by the bot owner."));
//}
// Bot will ignore commands which are ran more often than what specified by
// GlobalCommandsCooldown constant (miliseconds)
if (!UsersOnShortCooldown.Add(context.Message.Author.Id))

View File

@ -95,7 +95,7 @@ namespace NadekoBot.Services.Games
// "Games".ToLowerInvariant(),
// out int index))
//{
// //todo print in guild actually
// //todo 46 print in guild actually
// var returnMsg =
// $"Permission number #{index + 1} **{pc.Permissions[index].GetCommand(guild)}** is preventing this action.";
// _log.Info(returnMsg);

View File

@ -41,7 +41,7 @@ namespace NadekoBot.Services.Permissions
return words;
}
public FilterService(IEnumerable<GuildConfig> gcs)
public FilterService(DiscordShardedClient _client, IEnumerable<GuildConfig> gcs)
{
_log = LogManager.GetCurrentClassLogger();
@ -56,15 +56,22 @@ namespace NadekoBot.Services.Permissions
WordFilteringServers = new ConcurrentHashSet<ulong>(serverFiltering.Select(gc => gc.GuildId));
WordFilteringChannels = new ConcurrentHashSet<ulong>(gcs.SelectMany(gc => gc.FilterWordsChannelIds.Select(fwci => fwci.ChannelId)));
}
//todo ignore guild admin
public async Task<bool> TryBlockEarly(DiscordShardedClient client, IGuild guild, IUserMessage msg)
=> await FilterInvites(client, guild, msg) || await FilterWords(client, guild, msg);
public async Task<bool> FilterWords(DiscordShardedClient client, IGuild guild, IUserMessage usrMsg)
_client.MessageUpdated += (oldData, newMsg, channel)
=> FilterInvites((channel as ITextChannel)?.Guild, newMsg as IUserMessage);
}
public async Task<bool> TryBlockEarly(IGuild guild, IUserMessage msg)
=> !(msg.Author is IGuildUser gu) //it's never filtered outside of guilds, and never block administrators
? false
: gu.GuildPermissions.Administrator && (await FilterInvites(guild, msg) || await FilterWords(guild, msg));
public async Task<bool> FilterWords(IGuild guild, IUserMessage usrMsg)
{
if (guild is null)
return false;
if (usrMsg is null)
return false;
var filteredChannelWords = FilteredWordsForChannel(usrMsg.Channel.Id, guild.Id) ?? new ConcurrentHashSet<string>();
var filteredServerWords = FilteredWordsForServer(guild.Id) ?? new ConcurrentHashSet<string>();
@ -91,10 +98,12 @@ namespace NadekoBot.Services.Permissions
return false;
}
public async Task<bool> FilterInvites(DiscordShardedClient client, IGuild guild, IUserMessage usrMsg)
public async Task<bool> FilterInvites(IGuild guild, IUserMessage usrMsg)
{
if (guild is null)
return false;
if (usrMsg is null)
return false;
if ((InviteFilteringChannels.Contains(usrMsg.Channel.Id) ||
InviteFilteringServers.Contains(guild.Id)) &&

View File

@ -1,10 +1,15 @@
using NadekoBot.Services.Database.Models;
using NadekoBot.DataStructures.ModuleBehaviors;
using NadekoBot.Services.Database.Models;
using System.Collections.Concurrent;
using System.Linq;
using Discord;
using Discord.WebSocket;
using System;
using System.Threading.Tasks;
namespace NadekoBot.Services.Permissions
{
public class GlobalPermissionService
public class GlobalPermissionService : ILateBlocker
{
public readonly ConcurrentHashSet<string> BlockedModules;
public readonly ConcurrentHashSet<string> BlockedCommands;
@ -14,5 +19,20 @@ namespace NadekoBot.Services.Permissions
BlockedModules = new ConcurrentHashSet<string>(bc.BlockedModules.Select(x => x.Name));
BlockedCommands = new ConcurrentHashSet<string>(bc.BlockedCommands.Select(x => x.Name));
}
public async Task<bool> TryBlockLate(DiscordShardedClient client, IUserMessage msg, IGuild guild, IMessageChannel channel, IUser user, string moduleName, string commandName)
{
await Task.Yield();
commandName = commandName.ToLowerInvariant();
if (commandName != "resetglobalperms" &&
(BlockedCommands.Contains(commandName) ||
BlockedModules.Contains(moduleName.ToLowerInvariant())))
{
return true;
//return new ExecuteCommandResult(cmd, null, SearchResult.FromError(CommandError.Exception, $"Command or module is blocked globally by the bot owner."));
}
return false;
}
}
}

View File

@ -169,26 +169,27 @@ namespace NadekoBot.Services.Permissions
return false;
}
var resetCommand = commandName == "resetperms";
//todo perms
PermissionCache pc = GetCache(guild.Id);
if (!resetCommand && !pc.Permissions.CheckPermissions(msg, commandName, moduleName, out int index))
else
{
var returnMsg = $"Permission number #{index + 1} **{pc.Permissions[index].GetCommand((SocketGuild)guild)}** is preventing this action.";
return true;
//return new ExecuteCommandResult(cmd, pc, SearchResult.FromError(CommandError.Exception, returnMsg));
}
var resetCommand = commandName == "resetperms";
if (moduleName == "Permissions")
{
var roles = (user as SocketGuildUser)?.Roles ?? ((IGuildUser)user).RoleIds.Select(x => guild.GetRole(x)).Where(x => x != null);
if (!roles.Any(r => r.Name.Trim().ToLowerInvariant() == pc.PermRole.Trim().ToLowerInvariant()) && user.Id != ((IGuildUser)user).Guild.OwnerId)
PermissionCache pc = GetCache(guild.Id);
if (!resetCommand && !pc.Permissions.CheckPermissions(msg, commandName, moduleName, out int index))
{
var returnMsg = $"Permission number #{index + 1} **{pc.Permissions[index].GetCommand((SocketGuild)guild)}** is preventing this action.";
return true;
//return new ExecuteCommandResult(cmd, pc, SearchResult.FromError(CommandError.Exception, $"You need the **{pc.PermRole}** role in order to use permission commands."));
//return new ExecuteCommandResult(cmd, pc, SearchResult.FromError(CommandError.Exception, returnMsg));
}
if (moduleName == "Permissions")
{
var roles = (user as SocketGuildUser)?.Roles ?? ((IGuildUser)user).RoleIds.Select(x => guild.GetRole(x)).Where(x => x != null);
if (!roles.Any(r => r.Name.Trim().ToLowerInvariant() == pc.PermRole.Trim().ToLowerInvariant()) && user.Id != ((IGuildUser)user).Guild.OwnerId)
{
return true;
//return new ExecuteCommandResult(cmd, pc, SearchResult.FromError(CommandError.Exception, $"You need the **{pc.PermRole}** role in order to use permission commands."));
}
}
}

View File

@ -0,0 +1,79 @@
using NadekoBot.DataStructures.ModuleBehaviors;
using NadekoBot.Services.Database.Models;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Discord;
using NLog;
using NadekoBot.Extensions;
namespace NadekoBot.Services.Utility
{
public class CommandMapService : IInputTransformer
{
private readonly Logger _log;
public ConcurrentDictionary<ulong, ConcurrentDictionary<string, string>> AliasMaps { get; } = new ConcurrentDictionary<ulong, ConcurrentDictionary<string, string>>();
//commandmap
public CommandMapService(IEnumerable<GuildConfig> gcs)
{
_log = LogManager.GetCurrentClassLogger();
AliasMaps = new ConcurrentDictionary<ulong, ConcurrentDictionary<string, string>>(
gcs.ToDictionary(
x => x.GuildId,
x => new ConcurrentDictionary<string, string>(x.CommandAliases
.Distinct(new CommandAliasEqualityComparer())
.ToDictionary(ca => ca.Trigger, ca => ca.Mapping))));
}
public async Task<string> TransformInput(IGuild guild, IMessageChannel channel, IUser user, string input)
{
await Task.Yield();
if (guild == null || string.IsNullOrWhiteSpace(input))
return input;
//todo alias mapping
if (guild != null)
{
input = input.ToLowerInvariant();
if (AliasMaps.TryGetValue(guild.Id, out ConcurrentDictionary<string, string> maps))
{
var keys = maps.Keys
.OrderByDescending(x => x.Length);
foreach (var k in keys)
{
string newInput;
if (input.StartsWith(k + " "))
newInput = maps[k] + input.Substring(k.Length, input.Length - k.Length);
else if (input == k)
newInput = maps[k];
else
continue;
_log.Info(@"--Mapping Command--
GuildId: {0}
Trigger: {1}
Mapping: {2}", guild.Id, input, newInput);
try { await channel.SendConfirmAsync($"{input} => {newInput}").ConfigureAwait(false); } catch { }
return newInput;
}
}
}
return input;
}
}
public class CommandAliasEqualityComparer : IEqualityComparer<CommandAlias>
{
public bool Equals(CommandAlias x, CommandAlias y) => x.Trigger == y.Trigger;
public int GetHashCode(CommandAlias obj) => obj.Trigger.GetHashCode();
}
}

View File

@ -9,21 +9,14 @@ using System.Threading.Tasks;
namespace NadekoBot.Services.Utility
{
public class UtilityService
public class CrossServerTextService
{
public ConcurrentDictionary<ulong, ConcurrentDictionary<string, string>> AliasMaps { get; } = new ConcurrentDictionary<ulong, ConcurrentDictionary<string, string>>();
public readonly ConcurrentDictionary<int, ConcurrentHashSet<ITextChannel>> Subscribers =
new ConcurrentDictionary<int, ConcurrentHashSet<ITextChannel>>();
private DiscordShardedClient _client;
public UtilityService(IEnumerable<GuildConfig> guildConfigs, DiscordShardedClient client)
public CrossServerTextService(IEnumerable<GuildConfig> guildConfigs, DiscordShardedClient client)
{
//commandmap
AliasMaps = new ConcurrentDictionary<ulong, ConcurrentDictionary<string, string>>(
guildConfigs.ToDictionary(
x => x.GuildId,
x => new ConcurrentDictionary<string, string>(x.CommandAliases
.Distinct(new CommandAliasEqualityComparer())
.ToDictionary(ca => ca.Trigger, ca => ca.Mapping))));
//cross server
_client = client;
_client.MessageReceived += Client_MessageReceived;
}
@ -68,16 +61,5 @@ namespace NadekoBot.Services.Utility
private string GetMessage(ITextChannel channel, IGuildUser user, IUserMessage message) =>
$"**{channel.Guild.Name} | {channel.Name}** `{user.Username}`: " + message.Content.SanitizeMentions();
public readonly ConcurrentDictionary<int, ConcurrentHashSet<ITextChannel>> Subscribers =
new ConcurrentDictionary<int, ConcurrentHashSet<ITextChannel>>();
private DiscordShardedClient _client;
}
public class CommandAliasEqualityComparer : IEqualityComparer<CommandAlias>
{
public bool Equals(CommandAlias x, CommandAlias y) => x.Trigger == y.Trigger;
public int GetHashCode(CommandAlias obj) => obj.Trigger.GetHashCode();
}
}