made reminders a bit cooler

This commit is contained in:
Deukhoofd 2018-08-13 19:26:11 +02:00
parent 7a9c6cec16
commit d69b90bbd1
No known key found for this signature in database
GPG Key ID: B4C087AC81641654
4 changed files with 103 additions and 76 deletions

View File

@ -11,15 +11,15 @@ namespace DeukBot4.Database
public static ConnectionMultiplexer Redis = ConnectionMultiplexer.Connect("127.0.0.1"); public static ConnectionMultiplexer Redis = ConnectionMultiplexer.Connect("127.0.0.1");
public void AddReminder(TimeSpan time, string message, ulong channel, ulong author, ulong recipient) public async Task AddReminder(TimeSpan time, string message, ulong channel, ulong author, ulong recipient)
{ {
try try
{ {
var db = Redis.GetDatabase(); var db = Redis.GetDatabase();
var id = Guid.NewGuid().ToString(); var id = Guid.NewGuid().ToString();
var expectedTime = DateTime.UtcNow.Add(time); var expectedTime = DateTime.UtcNow.Add(time);
db.SortedSetAdd("deukbot_reminders", (RedisValue)id, expectedTime.ToBinary()); db.SortedSetAddAsync("deukbot_reminders", (RedisValue)id, expectedTime.ToBinary());
db.HashSet((RedisKey) id, new[] db.HashSetAsync((RedisKey) id, new[]
{ {
new HashEntry("channel", channel), new HashEntry("channel", channel),
new HashEntry("message", message), new HashEntry("message", message),
@ -62,7 +62,7 @@ namespace DeukBot4.Database
db.KeyDelete(val); db.KeyDelete(val);
} }
db.SortedSetRemoveRangeByScore("deukbot_reminders", Double.MinValue, desiredTopScore); db.SortedSetRemoveRangeByScoreAsync("deukbot_reminders", Double.MinValue, desiredTopScore);
await Task.Delay(checkTime); await Task.Delay(checkTime);
await CheckReminders(); await CheckReminders();

View File

@ -1,11 +1,5 @@
using System; using System;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Web;
using DeukBot4.APIHandlers;
using DeukBot4.Database;
using DeukBot4.Utilities;
using Discord; using Discord;
using Discord.WebSocket; using Discord.WebSocket;
@ -24,7 +18,7 @@ namespace DeukBot4.MessageHandlers
#pragma warning disable 4014 #pragma warning disable 4014
CommandHandler.CommandHandler.HandleMessage(message); CommandHandler.CommandHandler.HandleMessage(message);
HandlePrivateMessage(message); HandlePrivateMessage(message);
HandleReminder(message); ReminderHandler.HandleReminder(message);
ImageBackupHandler.Backup(message); ImageBackupHandler.Backup(message);
JokeHandlers.DeltaHandler(message); JokeHandlers.DeltaHandler(message);
JokeHandlers.DadJokeHandler(message); JokeHandlers.DadJokeHandler(message);
@ -66,70 +60,5 @@ namespace DeukBot4.MessageHandlers
} }
} }
private static Regex ReminderMatcher =
new Regex(
@".*(remind\s*((?<recipient>me)|<@!*(?<recipient>\d*)>)\s*to)(?<action>.*)(in\s*)(?<timeNum>\d)\s*(?<timeId>\w*)",
RegexOptions.IgnoreCase);
private static async Task HandleReminder(SocketMessage message)
{
var match = ReminderMatcher.Match(message.Content);
if (!match.Success)
{
return;
}
var recipient = match.Groups["recipient"].Captures[0].Value;
var action = match.Groups["action"].Value.Trim();
if (string.IsNullOrWhiteSpace(action))
return;
var timeNumber = double.Parse(match.Groups["timeNum"].Value);
var timeIdentifier = match.Groups["timeId"].Value.Trim();
TimeSpan timespan;
if (timeIdentifier.ToLowerInvariant().StartsWith("minu"))
{
timespan = TimeSpan.FromMinutes(timeNumber);
}
else if (timeIdentifier.ToLowerInvariant().StartsWith("hour"))
{
timespan = TimeSpan.FromHours(timeNumber);
}
else if (timeIdentifier.ToLowerInvariant().StartsWith("day"))
{
timespan = TimeSpan.FromDays(timeNumber);
}
else if (timeIdentifier.ToLowerInvariant().StartsWith("month"))
{
var dest = DateTime.UtcNow.AddMonths((int) (timeNumber));
dest = dest.AddDays(timeNumber % 1 * 30);
timespan = dest - DateTime.UtcNow;
}
else if (timeIdentifier.ToLowerInvariant().StartsWith("year"))
{
var dest = DateTime.UtcNow.AddYears((int) (timeNumber));
dest = dest.AddDays(timeNumber % 1 * 365);
timespan = dest - DateTime.UtcNow;
}
else
{
Logger.Main.LogError("Unknown timespan identifier: " + timeIdentifier);
return;
}
if (timespan.TotalMinutes < 5)
{
message.Channel.SendMessageAsync("A reminder should be at least 5 minutes in the future");
return;
}
if (!ulong.TryParse(recipient, out var recip))
{
recip = message.Author.Id;
}
ReminderHandler.Main.AddReminder(timespan, action, message.Channel.Id, message.Author.Id, recip);
message.Channel.SendMessageAsync(
message.Author.Id == recip
? $"Reminder set! I will remind you in {timespan.ToPrettyFormat()} to {action}"
: $"Reminder set! I will remind <@!{recip}> in {timespan.ToPrettyFormat()} to {action}");
}
} }
} }

View File

@ -0,0 +1,97 @@
using System;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using DeukBot4.Utilities;
using Discord.WebSocket;
namespace DeukBot4.MessageHandlers
{
public static class ReminderHandler
{
private static Regex ReminderMatcher =
new Regex(
@".*(remind\s*((?<recipient>me)|<@!*(?<recipient2>\d*)>)\s*to)(?<action>.*)(in\s+)(?<time>.*)",
RegexOptions.IgnoreCase);
public static async Task HandleReminder(SocketMessage message)
{
var match = ReminderMatcher.Match(message.Content);
if (!match.Success)
{
return;
}
var recipient = match.Groups["recipient"].Captures[0].Value;
var action = match.Groups["action"].Value.Trim();
if (string.IsNullOrWhiteSpace(action))
return;
var time = match.Groups["time"].Value;
var timespan = ParseTime(time);
if (!timespan.HasValue)
return;
if (timespan.Value.TotalMinutes < 5)
{
message.Channel.SendMessageAsync("A reminder should be at least 5 minutes in the future");
return;
}
if (!ulong.TryParse(recipient, out var recip))
{
recip = message.Author.Id;
}
Database.ReminderHandler.Main.AddReminder(timespan.Value, action, message.Channel.Id, message.Author.Id, recip);
message.Channel.SendMessageAsync(
message.Author.Id == recip
? $"Reminder set! I will remind you in {timespan.Value.ToPrettyFormat()} to {action}"
: $"Reminder set! I will remind <@!{recip}> in {timespan.Value.ToPrettyFormat()} to {action}");
}
private static Regex TimespanMatcher =
new Regex(@"(?<timeNumber>\d+.?\d*)\s*(?<timeId>minutes*|hours*|days*|weeks*|months*|years*)\W*(and )*",
RegexOptions.IgnoreCase);
private static TimeSpan? ParseTime(string message)
{
var matches = TimespanMatcher.Matches(message);
if (matches.Count == 0)
return null;
var timespan = new TimeSpan();
foreach (Match match in matches)
{
if (!match.Success)
continue;
var timeId = match.Groups["timeId"].Value.ToLowerInvariant();
var timeAmount = double.Parse(match.Groups["timeNumber"].Value);
if (timeId.StartsWith("minute"))
timespan += TimeSpan.FromMinutes(timeAmount);
else if (timeId.StartsWith("hour"))
timespan += TimeSpan.FromHours(timeAmount);
else if (timeId.StartsWith("day"))
timespan += TimeSpan.FromDays(timeAmount);
else if (timeId.StartsWith("week"))
timespan += TimeSpan.FromDays(timeAmount * 7);
else if (timeId.StartsWith("month"))
{
var target = DateTime.UtcNow.AddMonths((int) timeAmount);
target = target.AddDays(timeAmount % 1 * 30);
timespan += (target - DateTime.UtcNow);
}
else if (timeId.StartsWith("month"))
{
var target = DateTime.UtcNow.AddMonths((int) timeAmount);
target = target.AddDays(timeAmount % 1 * 30);
timespan += (target - DateTime.UtcNow);
}
else if (timeId.StartsWith("year"))
{
var target = DateTime.UtcNow.AddYears((int) timeAmount);
target = target.AddDays(timeAmount % 1 * 365);
timespan += (target - DateTime.UtcNow);
}
}
return timespan;
}
}
}

View File

@ -8,6 +8,7 @@ using Discord;
using Discord.Commands.Builders; using Discord.Commands.Builders;
using Discord.WebSocket; using Discord.WebSocket;
using StackExchange.Redis; using StackExchange.Redis;
using ReminderHandler = DeukBot4.Database.ReminderHandler;
namespace DeukBot4 namespace DeukBot4
{ {