CustomReactions almost done

This commit is contained in:
Master Kwoth 2017-05-25 04:24:43 +02:00
parent 9e3dc6d5a1
commit 351ebabd64
14 changed files with 211 additions and 123 deletions

View File

@ -1,18 +0,0 @@
using Discord.Commands;
namespace NadekoBot.DataStructures
{
public struct ExecuteCommandResult
{
public readonly CommandInfo CommandInfo;
public readonly PermissionCache PermissionCache;
public readonly IResult Result;
public ExecuteCommandResult(CommandInfo commandInfo, PermissionCache cache, IResult result)
{
this.CommandInfo = commandInfo;
this.PermissionCache = cache;
this.Result = result;
}
}
}

View File

@ -0,0 +1,22 @@
using Discord;
using Discord.WebSocket;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NadekoBot.DataStructures.ModuleBehaviors
{
/// <summary>
/// Implemented by modules which can execute something and prevent further commands from being executed.
/// </summary>
public interface IBlockingExecutor
{
/// <summary>
/// Try to execute some logic within some module's service.
/// </summary>
/// <returns>Whether it should block other command executions after it.</returns>
Task<bool> TryExecute(DiscordShardedClient client, IGuild guild, IUserMessage msg);
}
}

View File

@ -3,26 +3,31 @@ using System.Threading.Tasks;
using Discord.Commands;
using NadekoBot.Services;
using NadekoBot.Attributes;
using System.Collections.Concurrent;
using NadekoBot.Services.Database.Models;
using Discord;
using NadekoBot.Extensions;
using NLog;
using System.Diagnostics;
using Discord.WebSocket;
using System;
using NadekoBot.DataStructures;
using NadekoBot.Services.CustomReactions;
namespace NadekoBot.Modules.CustomReactions
{
public static class CustomReactionExtensions
{
}
[NadekoModule("CustomReactions", ".")]
public class CustomReactions : NadekoTopLevelModule
{
private readonly IBotCredentials _creds;
private readonly DbHandler _db;
private readonly CustomReactionsService _crs;
private readonly DiscordShardedClient _client;
public CustomReactions(IBotCredentials creds, DbHandler db, CustomReactionsService crs,
DiscordShardedClient client)
{
_creds = creds;
_db = db;
_crs = crs;
_client = client;
}
[NadekoCommand, Usage, Description, Aliases]
public async Task AddCustReact(string key, [Remainder] string message)
{
@ -32,7 +37,7 @@ namespace NadekoBot.Modules.CustomReactions
key = key.ToLowerInvariant();
if ((channel == null && !NadekoBot.Credentials.IsOwner(Context.User)) || (channel != null && !((IGuildUser)Context.User).GuildPermissions.Administrator))
if ((channel == null && !_creds.IsOwner(Context.User)) || (channel != null && !((IGuildUser)Context.User).GuildPermissions.Administrator))
{
await ReplyErrorLocalized("insuff_perms").ConfigureAwait(false);
return;
@ -55,12 +60,12 @@ namespace NadekoBot.Modules.CustomReactions
if (channel == null)
{
Array.Resize(ref _globalReactions, _globalReactions.Length + 1);
_globalReactions[_globalReactions.Length - 1] = cr;
Array.Resize(ref _crs.GlobalReactions, _crs.GlobalReactions.Length + 1);
_crs.GlobalReactions[_crs.GlobalReactions.Length - 1] = cr;
}
else
{
GuildReactions.AddOrUpdate(Context.Guild.Id,
_crs.GuildReactions.AddOrUpdate(Context.Guild.Id,
new CustomReaction[] { cr },
(k, old) =>
{
@ -86,9 +91,9 @@ namespace NadekoBot.Modules.CustomReactions
return;
CustomReaction[] customReactions;
if (Context.Guild == null)
customReactions = GlobalReactions.Where(cr => cr != null).ToArray();
customReactions = _crs.GlobalReactions.Where(cr => cr != null).ToArray();
else
customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, Array.Empty<CustomReaction>()).Where(cr => cr != null).ToArray();
customReactions = _crs.GuildReactions.GetOrAdd(Context.Guild.Id, Array.Empty<CustomReaction>()).Where(cr => cr != null).ToArray();
if (customReactions == null || !customReactions.Any())
{
@ -97,7 +102,7 @@ namespace NadekoBot.Modules.CustomReactions
}
var lastPage = customReactions.Length / 20;
await Context.Channel.SendPaginatedConfirmAsync(page, curPage =>
await Context.Channel.SendPaginatedConfirmAsync(_client, page, curPage =>
new EmbedBuilder().WithOkColor()
.WithTitle(GetText("name"))
.WithDescription(string.Join("\n", customReactions.OrderBy(cr => cr.Trigger)
@ -130,9 +135,9 @@ namespace NadekoBot.Modules.CustomReactions
{
CustomReaction[] customReactions;
if (Context.Guild == null)
customReactions = GlobalReactions.Where(cr => cr != null).ToArray();
customReactions = _crs.GlobalReactions.Where(cr => cr != null).ToArray();
else
customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new CustomReaction[]{ }).Where(cr => cr != null).ToArray();
customReactions = _crs.GuildReactions.GetOrAdd(Context.Guild.Id, new CustomReaction[]{ }).Where(cr => cr != null).ToArray();
if (customReactions == null || !customReactions.Any())
{
@ -160,9 +165,9 @@ namespace NadekoBot.Modules.CustomReactions
return;
CustomReaction[] customReactions;
if (Context.Guild == null)
customReactions = GlobalReactions.Where(cr => cr != null).ToArray();
customReactions = _crs.GlobalReactions.Where(cr => cr != null).ToArray();
else
customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new CustomReaction[]{ }).Where(cr => cr != null).ToArray();
customReactions = _crs.GuildReactions.GetOrAdd(Context.Guild.Id, new CustomReaction[]{ }).Where(cr => cr != null).ToArray();
if (customReactions == null || !customReactions.Any())
{
@ -176,7 +181,7 @@ namespace NadekoBot.Modules.CustomReactions
.ToList();
var lastPage = ordered.Count / 20;
await Context.Channel.SendPaginatedConfirmAsync(page, (curPage) =>
await Context.Channel.SendPaginatedConfirmAsync(_client, page, (curPage) =>
new EmbedBuilder().WithOkColor()
.WithTitle(GetText("name"))
.WithDescription(string.Join("\r\n", ordered
@ -192,9 +197,9 @@ namespace NadekoBot.Modules.CustomReactions
{
CustomReaction[] customReactions;
if (Context.Guild == null)
customReactions = GlobalReactions;
customReactions = _crs.GlobalReactions;
else
customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new CustomReaction[]{ });
customReactions = _crs.GuildReactions.GetOrAdd(Context.Guild.Id, new CustomReaction[]{ });
var found = customReactions.FirstOrDefault(cr => cr?.Id == id);
@ -216,7 +221,7 @@ namespace NadekoBot.Modules.CustomReactions
[NadekoCommand, Usage, Description, Aliases]
public async Task DelCustReact(int id)
{
if ((Context.Guild == null && !NadekoBot.Credentials.IsOwner(Context.User)) || (Context.Guild != null && !((IGuildUser)Context.User).GuildPermissions.Administrator))
if ((Context.Guild == null && !_creds.IsOwner(Context.User)) || (Context.Guild != null && !((IGuildUser)Context.User).GuildPermissions.Administrator))
{
await ReplyErrorLocalized("insuff_perms").ConfigureAwait(false);
return;
@ -235,13 +240,13 @@ namespace NadekoBot.Modules.CustomReactions
{
uow.CustomReactions.Remove(toDelete);
//todo i can dramatically improve performance of this, if Ids are ordered.
_globalReactions = GlobalReactions.Where(cr => cr?.Id != toDelete.Id).ToArray();
_crs.GlobalReactions = _crs.GlobalReactions.Where(cr => cr?.Id != toDelete.Id).ToArray();
success = true;
}
else if ((toDelete.GuildId != null && toDelete.GuildId != 0) && Context.Guild.Id == toDelete.GuildId)
{
uow.CustomReactions.Remove(toDelete);
GuildReactions.AddOrUpdate(Context.Guild.Id, new CustomReaction[] { }, (key, old) =>
_crs.GuildReactions.AddOrUpdate(Context.Guild.Id, new CustomReaction[] { }, (key, old) =>
{
return old.Where(cr => cr?.Id != toDelete.Id).ToArray();
});
@ -269,7 +274,7 @@ namespace NadekoBot.Modules.CustomReactions
[NadekoCommand, Usage, Description, Aliases]
public async Task CrDm(int id)
{
if ((Context.Guild == null && !NadekoBot.Credentials.IsOwner(Context.User)) ||
if ((Context.Guild == null && !_creds.IsOwner(Context.User)) ||
(Context.Guild != null && !((IGuildUser)Context.User).GuildPermissions.Administrator))
{
await ReplyErrorLocalized("insuff_perms").ConfigureAwait(false);
@ -279,10 +284,10 @@ namespace NadekoBot.Modules.CustomReactions
CustomReaction[] reactions = new CustomReaction[0];
if (Context.Guild == null)
reactions = GlobalReactions;
reactions = _crs.GlobalReactions;
else
{
GuildReactions.TryGetValue(Context.Guild.Id, out reactions);
_crs.GuildReactions.TryGetValue(Context.Guild.Id, out reactions);
}
if (reactions.Any())
{
@ -320,7 +325,7 @@ namespace NadekoBot.Modules.CustomReactions
[NadekoCommand, Usage, Description, Aliases]
public async Task CrAd(int id)
{
if ((Context.Guild == null && !NadekoBot.Credentials.IsOwner(Context.User)) ||
if ((Context.Guild == null && !_creds.IsOwner(Context.User)) ||
(Context.Guild != null && !((IGuildUser)Context.User).GuildPermissions.Administrator))
{
await ReplyErrorLocalized("insuff_perms").ConfigureAwait(false);
@ -330,10 +335,10 @@ namespace NadekoBot.Modules.CustomReactions
CustomReaction[] reactions = new CustomReaction[0];
if (Context.Guild == null)
reactions = GlobalReactions;
reactions = _crs.GlobalReactions;
else
{
GuildReactions.TryGetValue(Context.Guild.Id, out reactions);
_crs.GuildReactions.TryGetValue(Context.Guild.Id, out reactions);
}
if (reactions.Any())
{
@ -374,13 +379,13 @@ namespace NadekoBot.Modules.CustomReactions
{
if (string.IsNullOrWhiteSpace(trigger))
{
ClearStats();
_crs.ClearStats();
await ReplyConfirmLocalized("all_stats_cleared").ConfigureAwait(false);
}
else
{
uint throwaway;
if (ReactionStats.TryRemove(trigger, out throwaway))
if (_crs.ReactionStats.TryRemove(trigger, out throwaway))
{
await ReplyErrorLocalized("stats_cleared", Format.Bold(trigger)).ConfigureAwait(false);
}
@ -396,11 +401,11 @@ namespace NadekoBot.Modules.CustomReactions
{
if (page < 1)
return;
var ordered = ReactionStats.OrderByDescending(x => x.Value).ToArray();
var ordered = _crs.ReactionStats.OrderByDescending(x => x.Value).ToArray();
if (!ordered.Any())
return;
var lastPage = ordered.Length / 9;
await Context.Channel.SendPaginatedConfirmAsync(page,
await Context.Channel.SendPaginatedConfirmAsync(_client, page,
(curPage) => ordered.Skip((curPage - 1) * 9)
.Take(9)
.Aggregate(new EmbedBuilder().WithOkColor().WithTitle(GetText("stats")),

View File

@ -38,14 +38,14 @@ namespace NadekoBot.Modules.Gambling
{
using (var heads = _images.Heads.ToStream())
{
await Context.Channel.SendFileAsync(heads, "heads.jpg", Context.User.Mention + " " + GetText("flipped", Format.Bold(GetText("heads"))) + ".").ConfigureAwait(false);
await Context.Channel.SendFileAsync(heads, "heads.jpg", Context.User.Mention + " " + GetText("flipped", Format.Bold(GetText("heads")))).ConfigureAwait(false);
}
}
else
{
using (var tails = _images.Tails.ToStream())
{
await Context.Channel.SendFileAsync(tails, "tails.jpg", Context.User.Mention + " " + GetText("flipped", Format.Bold(GetText("tails"))) + ".").ConfigureAwait(false);
await Context.Channel.SendFileAsync(tails, "tails.jpg", Context.User.Mention + " " + GetText("flipped", Format.Bold(GetText("tails")))).ConfigureAwait(false);
}
}
return;

View File

@ -20,6 +20,7 @@ using NadekoBot.Modules.Utility;
using NadekoBot.Services.Searches;
using NadekoBot.Services.ClashOfClans;
using NadekoBot.Services.Music;
using NadekoBot.Services.CustomReactions;
namespace NadekoBot
{
@ -99,6 +100,7 @@ namespace NadekoBot
var searchesService = new SearchesService();
var clashService = new ClashOfClansService(Client, db, localization, strings);
var musicService = new MusicService(google, strings, localization, db, soundcloud, credentials);
var crService = new CustomReactionsService(db, Client);
//initialize Services
Services = new NServiceProvider.ServiceProviderBuilder() //todo all Adds should be interfaces
@ -111,16 +113,17 @@ namespace NadekoBot
.Add<CommandService>(commandService)
.Add<NadekoStrings>(strings)
.Add<DiscordShardedClient>(Client)
.Add<GreetSettingsService>(greetSettingsService)
.Add<BotConfig>(BotConfig)
.Add<CurrencyHandler>(currencyHandler)
.Add(musicService)
.Add<CommandHandler>(commandHandler)
.Add<DbHandler>(db)
//modules
.Add<UtilityService>(utilityService)
.Add<SearchesService>(searchesService)
.Add<ClashOfClansService>(clashService)
.Add<MusicService>(musicService)
.Add<GreetSettingsService>(greetSettingsService)
.Add<CustomReactionsService>(crService)
.Build();
commandHandler.AddServices(Services);

View File

@ -29,28 +29,21 @@
<ItemGroup>
<Compile Remove="data\**\*;credentials.json;credentials_example.json" />
<Compile Remove="Modules\Administration\**" />
<Compile Remove="Modules\CustomReactions\**" />
<Compile Remove="Modules\Games\**" />
<Compile Remove="Modules\NSFW\**" />
<Compile Remove="Modules\Permissions\**" />
<Compile Remove="Modules\Searches\**" />
<Compile Remove="Services\CustomReactions\**" />
<EmbeddedResource Remove="Modules\Administration\**" />
<EmbeddedResource Remove="Modules\CustomReactions\**" />
<EmbeddedResource Remove="Modules\Games\**" />
<EmbeddedResource Remove="Modules\NSFW\**" />
<EmbeddedResource Remove="Modules\Permissions\**" />
<EmbeddedResource Remove="Modules\Searches\**" />
<EmbeddedResource Remove="Services\CustomReactions\**" />
<None Remove="Modules\Administration\**" />
<None Remove="Modules\CustomReactions\**" />
<None Remove="Modules\Games\**" />
<None Remove="Modules\NSFW\**" />
<None Remove="Modules\Permissions\**" />
<None Remove="Modules\Searches\**" />
<None Remove="Services\CustomReactions\**" />
<Compile Remove="Modules\Gambling\Commands\Lucky7Commands.cs" />
<Compile Remove="Modules\Gambling\Commands\WaifuClaimCommands.cs" />
<None Update="libsodium.dll;opus.dll;libsodium.so;libopus.so">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>

View File

@ -1,5 +1,6 @@
using Discord;
using Discord.WebSocket;
using NadekoBot.DataStructures.ModuleBehaviors;
using NadekoBot.Extensions;
using NadekoBot.Services.Database.Models;
using System;

View File

@ -11,6 +11,7 @@ using System.Collections.Concurrent;
using System.Threading;
using NadekoBot.DataStructures;
using System.Collections.Immutable;
using NadekoBot.DataStructures.ModuleBehaviors;
namespace NadekoBot.Services
{
@ -201,7 +202,7 @@ namespace NadekoBot.Services
private const float _oneThousandth = 1.0f / 1000;
private Task LogSuccessfulExecution(IUserMessage usrMsg, ExecuteCommandResult exec, ITextChannel channel, params int[] execPoints)
private Task LogSuccessfulExecution(IUserMessage usrMsg, bool exec, ITextChannel channel, params int[] execPoints)
{
_log.Info("Command Executed after " + string.Join("/", execPoints.Select(x => x * _oneThousandth)) + "s\n\t" +
"User: {0}\n\t" +
@ -216,7 +217,7 @@ namespace NadekoBot.Services
return Task.CompletedTask;
}
private void LogErroredExecution(IUserMessage usrMsg, ExecuteCommandResult exec, ITextChannel channel, params int[] execPoints)
private void LogErroredExecution(IUserMessage usrMsg, bool exec, ITextChannel channel, params int[] execPoints)
{
_log.Warn("Command Errored after " + string.Join("/", execPoints.Select(x => x * _oneThousandth)) + "s\n\t" +
"User: {0}\n\t" +
@ -228,7 +229,8 @@ namespace NadekoBot.Services
(channel == null ? "PRIVATE" : channel.Guild.Name + " [" + channel.Guild.Id + "]"), // {1}
(channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2}
usrMsg.Content,// {3}
exec.Result.ErrorReason // {4}
exec
//exec.Result.ErrorReason // {4}
);
}
////todo invite filtering
@ -323,6 +325,17 @@ namespace NadekoBot.Services
{
var execTime = Environment.TickCount;
foreach (var svc in _services)
{
if (svc is IBlockingExecutor _executor &&
await _executor.TryExecute(_client, guild, usrMsg))
{
_log.Info("User [{0}] executed [{1}] in [{2}]", usrMsg.Author, usrMsg.Content, svc.GetType().Name);
return;
}
}
////todo word and invite filtering
//if (guild != null && guild.OwnerId != usrMsg.Author.Id)
//{
@ -423,22 +436,23 @@ namespace NadekoBot.Services
var exec = await Task.Run(() => ExecuteCommandAsync(new CommandContext(_client, usrMsg), NadekoBot.Prefix.Length, _services, MultiMatchHandling.Best)).ConfigureAwait(false);
execTime = Environment.TickCount - execTime;
if (exec.Result.IsSuccess)
{
await CommandExecuted(usrMsg, exec.CommandInfo).ConfigureAwait(false);
await LogSuccessfulExecution(usrMsg, exec, channel, exec2, exec3, execTime).ConfigureAwait(false);
return;
}
else if (!exec.Result.IsSuccess && exec.Result.Error != CommandError.UnknownCommand)
{
LogErroredExecution(usrMsg, exec, channel, exec2, exec3, execTime);
if (guild != null && exec.CommandInfo != null && exec.Result.Error == CommandError.Exception)
{
if (exec.PermissionCache != null && exec.PermissionCache.Verbose)
try { await usrMsg.Channel.SendMessageAsync("⚠️ " + exec.Result.ErrorReason).ConfigureAwait(false); } catch { }
}
return;
}
////todo permissions
//if (exec.Result.IsSuccess)
//{
// await CommandExecuted(usrMsg, exec.CommandInfo).ConfigureAwait(false);
// await LogSuccessfulExecution(usrMsg, exec, channel, exec2, exec3, execTime).ConfigureAwait(false);
// return;
//}
//else if (!exec.Result.IsSuccess && exec.Result.Error != CommandError.UnknownCommand)
//{
// LogErroredExecution(usrMsg, exec, channel, exec2, exec3, execTime);
// if (guild != null && exec.CommandInfo != null && exec.Result.Error == CommandError.Exception)
// {
// if (exec.PermissionCache != null && exec.PermissionCache.Verbose)
// try { await usrMsg.Channel.SendMessageAsync("⚠️ " + exec.Result.ErrorReason).ConfigureAwait(false); } catch { }
// }
// return;
//}
}
if (usrMsg.Channel is IPrivateChannel)
@ -455,15 +469,15 @@ namespace NadekoBot.Services
}
}
public Task<ExecuteCommandResult> ExecuteCommandAsync(CommandContext context, int argPos, IServiceProvider serviceProvider, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
public Task<bool> ExecuteCommandAsync(CommandContext context, int argPos, IServiceProvider serviceProvider, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
=> ExecuteCommand(context, context.Message.Content.Substring(argPos), serviceProvider, multiMatchHandling);
public async Task<ExecuteCommandResult> ExecuteCommand(CommandContext context, string input, IServiceProvider serviceProvider, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
public async Task<bool> ExecuteCommand(CommandContext context, string input, IServiceProvider serviceProvider, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
{
var searchResult = _commandService.Search(context, input);
if (!searchResult.IsSuccess)
return new ExecuteCommandResult(null, null, searchResult);
return false;
var commands = searchResult.Commands;
for (int i = commands.Count - 1; i >= 0; i--)
@ -472,7 +486,7 @@ namespace NadekoBot.Services
if (!preconditionResult.IsSuccess)
{
if (commands.Count == 1)
return new ExecuteCommandResult(null, null, preconditionResult);
return false;
else
continue;
}
@ -496,7 +510,7 @@ namespace NadekoBot.Services
if (!parseResult.IsSuccess)
{
if (commands.Count == 1)
return new ExecuteCommandResult(null, null, parseResult);
return false;
else
continue;
}
@ -549,16 +563,19 @@ namespace NadekoBot.Services
// Bot will ignore commands which are ran more often than what specified by
// GlobalCommandsCooldown constant (miliseconds)
if (!UsersOnShortCooldown.Add(context.Message.Author.Id))
return new ExecuteCommandResult(cmd, null, SearchResult.FromError(CommandError.Exception, "You are on a global cooldown."));
return false;
//return SearchResult.FromError(CommandError.Exception, "You are on a global cooldown.");
////todo cmdcds
//if (CmdCdsCommands.HasCooldown(cmd, context.Guild, context.User))
// return new ExecuteCommandResult(cmd, null, SearchResult.FromError(CommandError.Exception, "That command is on a cooldown for you."));
return new ExecuteCommandResult(cmd, null, await commands[i].ExecuteAsync(context, parseResult, serviceProvider));
await commands[i].ExecuteAsync(context, parseResult, serviceProvider);
return true;
}
return new ExecuteCommandResult(null, null, SearchResult.FromError(CommandError.UnknownCommand, "This input does not match any overload."));
return false;
//return new ExecuteCommandResult(null, null, SearchResult.FromError(CommandError.UnknownCommand, "This input does not match any overload."));
}
}
}

View File

@ -1,34 +1,39 @@
using Discord;
using Discord.WebSocket;
using NadekoBot.DataStructures.ModuleBehaviors;
using NadekoBot.Services.Database.Models;
using NLog;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Linq;
using System;
using System.Threading.Tasks;
namespace NadekoBot.Services
namespace NadekoBot.Services.CustomReactions
{
public class CustomReactions
public class CustomReactionsService : IBlockingExecutor
{
private CustomReaction[] _globalReactions = new CustomReaction[] { };
public CustomReaction[] GlobalReactions => _globalReactions;
public CustomReaction[] GlobalReactions = new CustomReaction[] { };
public ConcurrentDictionary<ulong, CustomReaction[]> GuildReactions { get; } = new ConcurrentDictionary<ulong, CustomReaction[]>();
public ConcurrentDictionary<string, uint> ReactionStats { get; } = new ConcurrentDictionary<string, uint>();
private readonly Logger _log;
private readonly DbHandler _db;
private readonly DiscordShardedClient _client;
public CustomReactions(DbHandler db)
public CustomReactionsService(DbHandler db, DiscordShardedClient client)
{
_log = LogManager.GetCurrentClassLogger();
_db = db;
_client = client;
var sw = Stopwatch.StartNew();
using (var uow = _db.UnitOfWork)
{
var items = uow.CustomReactions.GetAll();
GuildReactions = new ConcurrentDictionary<ulong, CustomReaction[]>(items.Where(g => g.GuildId != null && g.GuildId != 0).GroupBy(k => k.GuildId.Value).ToDictionary(g => g.Key, g => g.ToArray()));
_globalReactions = items.Where(g => g.GuildId == null || g.GuildId == 0).ToArray();
GlobalReactions = items.Where(g => g.GuildId == null || g.GuildId == 0).ToArray();
}
sw.Stop();
_log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s");
@ -54,7 +59,7 @@ namespace NadekoBot.Services
return false;
var hasTarget = cr.Response.ToLowerInvariant().Contains("%target%");
var trigger = cr.TriggerWithContext(umsg).Trim().ToLowerInvariant();
var trigger = cr.TriggerWithContext(umsg, _client).Trim().ToLowerInvariant();
return ((hasTarget && content.StartsWith(trigger + " ")) || content == trigger);
}).ToArray();
@ -75,7 +80,7 @@ namespace NadekoBot.Services
if (cr == null)
return false;
var hasTarget = cr.Response.ToLowerInvariant().Contains("%target%");
var trigger = cr.TriggerWithContext(umsg).Trim().ToLowerInvariant();
var trigger = cr.TriggerWithContext(umsg, _client).Trim().ToLowerInvariant();
return ((hasTarget && content.StartsWith(trigger + " ")) || content == trigger);
}).ToArray();
if (grs.Length == 0)
@ -84,5 +89,46 @@ namespace NadekoBot.Services
return greaction;
}
public async Task<bool> TryExecute(DiscordShardedClient client, IGuild guild, IUserMessage msg)
{
//todo custom reactions
// maybe this message is a custom reaction
// todo log custom reaction executions. return struct with info
var cr = await Task.Run(() => TryGetCustomReaction(msg)).ConfigureAwait(false);
if (cr != null) //if it was, don't execute the command
{
try
{
//if (guild != null)
//{
// PermissionCache pc = Permissions.GetCache(guild.Id);
// if (!pc.Permissions.CheckPermissions(usrMsg, cr.Trigger, "ActualCustomReactions",
// out int index))
// {
// //todo print in guild actually
// var returnMsg =
// $"Permission number #{index + 1} **{pc.Permissions[index].GetCommand(guild)}** is preventing this action.";
// _log.Info(returnMsg);
// return;
// }
//}
await cr.Send(msg, _client, this).ConfigureAwait(false);
if (cr.AutoDeleteTrigger)
{
try { await msg.DeleteAsync().ConfigureAwait(false); } catch { }
}
return true;
}
catch (Exception ex)
{
_log.Warn("Sending CREmbed failed");
_log.Warn(ex);
}
}
return false;
}
}
}

View File

@ -1,4 +1,5 @@
using Discord;
using Discord.WebSocket;
using NadekoBot.DataStructures;
using NadekoBot.Extensions;
using NadekoBot.Services;
@ -8,7 +9,7 @@ using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace NadekoBot.Modules.CustomReactions
namespace NadekoBot.Services.CustomReactions
{
public static class Extensions
{
@ -17,11 +18,11 @@ namespace NadekoBot.Modules.CustomReactions
{"%target%", (ctx, trigger) => { return ctx.Content.Substring(trigger.Length).Trim().SanitizeMentions(); } }
};
public static Dictionary<string, Func<IUserMessage, string>> placeholders = new Dictionary<string, Func<IUserMessage, string>>()
public static Dictionary<string, Func<IUserMessage, DiscordShardedClient, string>> placeholders = new Dictionary<string, Func<IUserMessage, DiscordShardedClient, string>>()
{
{"%mention%", (ctx) => { return $"<@{NadekoBot.Client.CurrentUser.Id}>"; } },
{"%user%", (ctx) => { return ctx.Author.Mention; } },
{"%rnduser%", (ctx) => {
{"%mention%", (ctx, client) => { return $"<@{client.CurrentUser.Id}>"; } },
{"%user%", (ctx, client) => { return ctx.Author.Mention; } },
{"%rnduser%", (ctx, client) => {
//var ch = ctx.Channel as ITextChannel;
//if(ch == null)
// return "";
@ -69,20 +70,20 @@ namespace NadekoBot.Modules.CustomReactions
} }
};
private static string ResolveTriggerString(this string str, IUserMessage ctx)
private static string ResolveTriggerString(this string str, IUserMessage ctx, DiscordShardedClient client)
{
foreach (var ph in placeholders)
{
str = str.ToLowerInvariant().Replace(ph.Key, ph.Value(ctx));
str = str.ToLowerInvariant().Replace(ph.Key, ph.Value(ctx, client));
}
return str;
}
private static string ResolveResponseString(this string str, IUserMessage ctx, string resolvedTrigger)
private static string ResolveResponseString(this string str, IUserMessage ctx, DiscordShardedClient client, string resolvedTrigger)
{
foreach (var ph in placeholders)
{
str = str.Replace(ph.Key.ToLowerInvariant(), ph.Value(ctx));
str = str.Replace(ph.Key.ToLowerInvariant(), ph.Value(ctx, client));
}
foreach (var ph in responsePlaceholders)
@ -97,24 +98,23 @@ namespace NadekoBot.Modules.CustomReactions
return str;
}
public static string TriggerWithContext(this CustomReaction cr, IUserMessage ctx)
=> cr.Trigger.ResolveTriggerString(ctx);
public static string TriggerWithContext(this CustomReaction cr, IUserMessage ctx, DiscordShardedClient client)
=> cr.Trigger.ResolveTriggerString(ctx, client);
public static string ResponseWithContext(this CustomReaction cr, IUserMessage ctx)
=> cr.Response.ResolveResponseString(ctx, cr.Trigger.ResolveTriggerString(ctx));
public static string ResponseWithContext(this CustomReaction cr, IUserMessage ctx, DiscordShardedClient client)
=> cr.Response.ResolveResponseString(ctx, client, cr.Trigger.ResolveTriggerString(ctx, client));
public static async Task<IUserMessage> Send(this CustomReaction cr, IUserMessage context)
public static async Task<IUserMessage> Send(this CustomReaction cr, IUserMessage context, DiscordShardedClient client, CustomReactionsService crs)
{
var channel = cr.DmResponse ? await context.Author.CreateDMChannelAsync() : context.Channel;
CustomReactions.ReactionStats.AddOrUpdate(cr.Trigger, 1, (k, old) => ++old);
crs.ReactionStats.AddOrUpdate(cr.Trigger, 1, (k, old) => ++old);
CREmbed crembed;
if (CREmbed.TryParse(cr.Response, out crembed))
if (CREmbed.TryParse(cr.Response, out CREmbed crembed))
{
return await channel.EmbedAsync(crembed.ToEmbed(), crembed.PlainText ?? "");
}
return await channel.SendMessageAsync(cr.ResponseWithContext(context).SanitizeMentions());
return await channel.SendMessageAsync(cr.ResponseWithContext(context, client).SanitizeMentions());
}
}
}

View File

@ -5,7 +5,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NadekoBot.DataStructures
namespace NadekoBot.Services.Permissions
{
public class OldPermissionCache
{

View File

@ -3,8 +3,9 @@ using System.Collections;
using System.Collections.Generic;
using System.Linq;
using NadekoBot.Services.Database.Models;
using NadekoBot.DataStructures;
namespace NadekoBot.DataStructures
namespace NadekoBot.Services.Permissions
{
public class PermissionsCollection<T> : IndexedCollection<T> where T : IIndexed
{

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NadekoBot.Services.Permissions
{
public class PermissionsService
{
}
}

View File

@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
@ -8,7 +9,7 @@ using System.Threading.Tasks;
namespace NadekoBot.Services
{
public interface INServiceProvider : IServiceProvider
public interface INServiceProvider : IServiceProvider, IEnumerable<object>
{
T GetService<T>();
}
@ -49,5 +50,9 @@ namespace NadekoBot.Services
_services.TryGetValue(serviceType, out var toReturn);
return toReturn;
}
IEnumerator IEnumerable.GetEnumerator() => _services.Values.GetEnumerator();
public IEnumerator<object> GetEnumerator() => _services.Values.GetEnumerator();
}
}