RegexBot/Feature/AutoRespond/ConfigItem.cs

154 lines
5.1 KiB
C#
Raw Normal View History

2017-09-05 17:26:13 +00:00
using Discord.WebSocket;
using Newtonsoft.Json.Linq;
2017-08-10 03:16:08 +00:00
using Noikoio.RegexBot.ConfigItem;
using System;
using System.Collections.Generic;
2017-08-10 03:16:08 +00:00
using System.Text.RegularExpressions;
namespace Noikoio.RegexBot.Feature.AutoRespond
{
/// <summary>
/// Represents a single autoresponse definition.
/// </summary>
2017-09-05 17:18:07 +00:00
class ConfigItem
2017-08-10 03:16:08 +00:00
{
public enum ResponseType { None, Exec, Reply }
string _label;
IEnumerable<Regex> _regex;
2017-08-10 03:16:08 +00:00
ResponseType _rtype;
string _rbody;
2017-08-10 22:19:42 +00:00
private FilterList _filter;
private RateLimitCache _limit;
2017-08-10 03:16:08 +00:00
public string Label => _label;
public IEnumerable<Regex> Regex => _regex;
2017-08-10 03:16:08 +00:00
public (ResponseType, string) Response => (_rtype, _rbody);
2017-08-10 22:19:42 +00:00
public FilterList Filter => _filter;
public RateLimitCache RateLimit => _limit;
2017-08-10 03:16:08 +00:00
2017-09-05 17:18:07 +00:00
public ConfigItem(JProperty definition)
2017-08-10 03:16:08 +00:00
{
_label = definition.Name;
var data = (JObject)definition.Value;
2017-08-10 03:16:08 +00:00
// error postfix string
string errorpfx = $" in response definition for '{_label}'.";
// regex trigger
const string NoRegexError = "No regular expression patterns are defined";
var regexes = new List<Regex>();
2017-08-10 03:16:08 +00:00
const RegexOptions rxopts = RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Multiline;
var rxconf = data["regex"];
if (rxconf == null) throw new RuleImportException(NoRegexError + errorpfx);
if (rxconf.Type == JTokenType.Array)
2017-08-10 03:16:08 +00:00
{
foreach (var input in rxconf.Values<string>())
{
try
{
Regex r = new Regex(input, rxopts);
regexes.Add(r);
}
catch (ArgumentException)
{
throw new RuleImportException(
$"Failed to parse regular expression pattern '{input}'{errorpfx}");
}
}
2017-08-10 03:16:08 +00:00
}
else
2017-08-10 03:16:08 +00:00
{
string rxstr = rxconf.Value<string>();
try
{
Regex r = new Regex(rxstr, rxopts);
regexes.Add(r);
}
catch (Exception ex) when (ex is ArgumentException || ex is NullReferenceException)
{
throw new RuleImportException(
$"Failed to parse regular expression pattern '{rxstr}'{errorpfx}");
}
2017-08-10 03:16:08 +00:00
}
_regex = regexes.ToArray();
2017-08-10 03:16:08 +00:00
// response - defined in either "exec" or "reply", but not both
_rbody = null;
_rtype = ResponseType.None;
// exec response
string execstr = data["exec"]?.Value<string>();
2017-08-10 03:16:08 +00:00
if (!string.IsNullOrWhiteSpace(execstr))
{
_rbody = execstr;
_rtype = ResponseType.Exec;
}
// reply response
string replystr = data["reply"]?.Value<string>();
2017-08-10 03:16:08 +00:00
if (!string.IsNullOrWhiteSpace(replystr))
{
if (_rbody != null)
throw new RuleImportException("A value for both 'exec' and 'reply' is not allowed" + errorpfx);
_rbody = replystr;
_rtype = ResponseType.Reply;
}
if (_rbody == null)
throw new RuleImportException("A response value of either 'exec' or 'reply' was not defined" + errorpfx);
// ---
// whitelist/blacklist filtering
_filter = new FilterList(data);
2017-08-10 22:19:42 +00:00
// rate limiting
string rlstr = data["ratelimit"]?.Value<string>();
2017-08-10 22:19:42 +00:00
if (string.IsNullOrWhiteSpace(rlstr))
{
_limit = new RateLimitCache(RateLimitCache.DefaultTimeout);
}
else
{
if (ushort.TryParse(rlstr, out var rlval))
{
_limit = new RateLimitCache(rlval);
}
else
{
throw new RuleImportException("Rate limit value is invalid" + errorpfx);
}
}
2017-08-10 03:16:08 +00:00
}
2017-08-30 05:39:59 +00:00
2017-09-05 17:26:13 +00:00
/// <summary>
/// Checks given message to see if it matches this rule's constraints.
/// </summary>
/// <returns>If true, the rule's response(s) should be executed.</returns>
public bool Match(SocketMessage m)
{
// Filter check
if (Filter.IsFiltered(m)) return false;
// Match check
bool matchFound = false;
foreach (var item in Regex)
{
if (item.IsMatch(m.Content))
{
matchFound = true;
break;
}
}
if (!matchFound) return false;
2017-09-05 17:26:13 +00:00
// Rate limit check - currently per channel
if (!RateLimit.AllowUsage(m.Channel.Id)) return false;
return true;
}
2017-08-30 05:39:59 +00:00
public override string ToString() => $"Autoresponse definition '{Label}'";
2017-08-10 03:16:08 +00:00
}
}