NadekoBot/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs

257 lines
10 KiB
C#
Raw Normal View History

2016-08-28 12:19:50 +00:00
using Discord;
using Discord.Commands;
using Discord.Net;
using Microsoft.EntityFrameworkCore;
2016-08-28 20:59:12 +00:00
using NadekoBot.Attributes;
2016-12-11 16:18:25 +00:00
using NadekoBot.Extensions;
2016-08-28 20:59:12 +00:00
using NadekoBot.Services;
using NadekoBot.Services.Database;
2016-08-28 20:59:12 +00:00
using NadekoBot.Services.Database.Models;
2016-10-05 05:01:19 +00:00
using NLog;
2016-08-28 12:19:50 +00:00
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
2016-12-29 13:56:15 +00:00
using System.Diagnostics;
2016-08-28 20:59:12 +00:00
using System.Linq;
using System.Text;
2016-08-29 12:34:46 +00:00
using System.Threading;
2016-08-28 12:19:50 +00:00
using System.Threading.Tasks;
2017-01-11 13:08:50 +00:00
namespace NadekoBot.Modules.Utility
2016-08-28 12:19:50 +00:00
{
2017-01-11 13:08:50 +00:00
public partial class Utility
2016-08-28 12:19:50 +00:00
{
2016-08-28 20:59:12 +00:00
[Group]
2016-12-17 00:16:14 +00:00
public class RepeatCommands : ModuleBase
2016-08-28 20:59:12 +00:00
{
//guildid/RepeatRunners
public static ConcurrentDictionary<ulong, ConcurrentQueue<RepeatRunner>> repeaters { get; }
2016-08-29 12:34:46 +00:00
public class RepeatRunner
{
2016-10-05 05:01:19 +00:00
private Logger _log { get; }
2016-08-29 12:34:46 +00:00
private CancellationTokenSource source { get; set; }
private CancellationToken token { get; set; }
public Repeater Repeater { get; }
public ITextChannel Channel { get; }
public RepeatRunner(Repeater repeater, ITextChannel channel = null)
2016-08-29 12:34:46 +00:00
{
2016-10-05 05:01:19 +00:00
_log = LogManager.GetCurrentClassLogger();
2016-08-29 12:34:46 +00:00
this.Repeater = repeater;
2017-01-28 23:38:09 +00:00
this.Channel = channel ?? NadekoBot.Client.GetGuild(repeater.GuildId)?.GetTextChannel(repeater.ChannelId);
2016-08-29 12:34:46 +00:00
if (Channel == null)
return;
Task.Run(Run);
}
private async Task Run()
{
source = new CancellationTokenSource();
token = source.Token;
IUserMessage oldMsg = null;
2016-08-29 12:34:46 +00:00
try
{
while (!token.IsCancellationRequested)
{
var toSend = "🔄 " + Repeater.Message;
2016-08-29 12:34:46 +00:00
await Task.Delay(Repeater.Interval, token).ConfigureAwait(false);
//var lastMsgInChannel = (await Channel.GetMessagesAsync(2)).FirstOrDefault();
// if (lastMsgInChannel.Id == oldMsg?.Id) //don't send if it's the same message in the channel
// continue;
if (oldMsg != null)
try { await oldMsg.DeleteAsync(); } catch { }
try
{
oldMsg = await Channel.SendMessageAsync(toSend).ConfigureAwait(false);
}
2017-01-28 23:38:09 +00:00
catch (HttpException ex) when (ex.HttpCode == System.Net.HttpStatusCode.Forbidden)
{
_log.Warn("Missing permissions. Repeater stopped. ChannelId : {0}", Channel?.Id);
return;
}
2017-01-28 23:38:09 +00:00
catch (HttpException ex) when (ex.HttpCode == System.Net.HttpStatusCode.NotFound)
{
_log.Warn("Channel not found. Repeater stopped. ChannelId : {0}", Channel?.Id);
return;
}
catch (Exception ex)
{
_log.Warn(ex);
}
2016-08-29 12:34:46 +00:00
}
}
catch (OperationCanceledException) { }
}
public void Reset()
{
source.Cancel();
2017-02-14 13:30:21 +00:00
var _ = Task.Run(Run);
2016-08-29 12:34:46 +00:00
}
public void Stop()
{
source.Cancel();
}
public override string ToString()
{
return $"{this.Channel.Mention} | {(int)this.Repeater.Interval.TotalHours}:{this.Repeater.Interval:mm} | {this.Repeater.Message.TrimTo(33)}";
}
2016-08-29 12:34:46 +00:00
}
2016-05-23 20:50:16 +00:00
2016-12-08 17:35:34 +00:00
static RepeatCommands()
2016-08-28 12:19:50 +00:00
{
2016-12-29 13:56:15 +00:00
var _log = LogManager.GetCurrentClassLogger();
var sw = Stopwatch.StartNew();
repeaters = new ConcurrentDictionary<ulong, ConcurrentQueue<RepeatRunner>>(NadekoBot.AllGuildConfigs
.ToDictionary(gc => gc.GuildId,
gc => new ConcurrentQueue<RepeatRunner>(gc.GuildRepeaters.Select(gr => new RepeatRunner(gr))
.Where(gr => gr.Channel != null))));
2016-12-29 13:56:15 +00:00
sw.Stop();
_log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s");
2016-08-28 12:19:50 +00:00
}
[NadekoCommand, Usage, Description, Aliases]
2016-08-28 20:59:12 +00:00
[RequireContext(ContextType.Guild)]
2016-12-16 18:43:57 +00:00
[RequireUserPermission(GuildPermission.ManageMessages)]
public async Task RepeatInvoke(int index)
2016-08-28 12:19:50 +00:00
{
index -= 1;
ConcurrentQueue<RepeatRunner> rep;
if (!repeaters.TryGetValue(Context.Guild.Id, out rep))
2016-08-28 12:19:50 +00:00
{
2016-12-16 21:44:26 +00:00
await Context.Channel.SendErrorAsync(" **No repeating message found on this server.**").ConfigureAwait(false);
2016-08-28 20:59:12 +00:00
return;
2016-08-28 12:19:50 +00:00
}
var repList = rep.ToList();
if (index >= repList.Count)
{
await Context.Channel.SendErrorAsync("Index out of range.").ConfigureAwait(false);
return;
}
var repeater = repList[index].Repeater;
2017-02-09 20:11:33 +00:00
repList[index].Reset();
await Context.Channel.SendMessageAsync("🔄 " + repeater.Message).ConfigureAwait(false);
2016-08-28 12:19:50 +00:00
}
2016-05-23 20:50:16 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-08-28 20:59:12 +00:00
[RequireContext(ContextType.Guild)]
2016-12-16 18:43:57 +00:00
[RequireUserPermission(GuildPermission.ManageMessages)]
[Priority(0)]
public async Task RepeatRemove(int index)
2016-08-28 20:59:12 +00:00
{
if (index < 1)
return;
index -= 1;
ConcurrentQueue<RepeatRunner> rep;
if (!repeaters.TryGetValue(Context.Guild.Id, out rep))
return;
var repeaterList = rep.ToList();
if (index >= repeaterList.Count)
2016-08-28 12:19:50 +00:00
{
await Context.Channel.SendErrorAsync("Index out of range.").ConfigureAwait(false);
return;
}
var repeater = repeaterList[index];
repeater.Stop();
repeaterList.RemoveAt(index);
using (var uow = DbHandler.UnitOfWork())
{
var guildConfig = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(gc => gc.GuildRepeaters));
guildConfig.GuildRepeaters.RemoveWhere(r => r.Id == repeater.Repeater.Id);
await uow.CompleteAsync().ConfigureAwait(false);
2016-08-28 20:59:12 +00:00
}
if (repeaters.TryUpdate(Context.Guild.Id, new ConcurrentQueue<RepeatRunner>(repeaterList), rep))
await Context.Channel.SendConfirmAsync("Message Repeater",$"#{index+1} stopped.\n\n{repeater.ToString()}").ConfigureAwait(false);
}
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
2016-12-16 18:43:57 +00:00
[RequireUserPermission(GuildPermission.ManageMessages)]
[Priority(1)]
public async Task Repeat(int minutes, [Remainder] string message)
{
if (minutes < 1 || minutes > 10080)
return;
if (string.IsNullOrWhiteSpace(message))
return;
var toAdd = new GuildRepeater()
2016-08-28 12:19:50 +00:00
{
ChannelId = Context.Channel.Id,
GuildId = Context.Guild.Id,
Interval = TimeSpan.FromMinutes(minutes),
Message = message
};
using (var uow = DbHandler.UnitOfWork())
{
var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.GuildRepeaters));
2017-01-10 22:12:52 +00:00
if (gc.GuildRepeaters.Count >= 5)
return;
gc.GuildRepeaters.Add(toAdd);
await uow.CompleteAsync().ConfigureAwait(false);
}
var rep = new RepeatRunner(toAdd, (ITextChannel)Context.Channel);
repeaters.AddOrUpdate(Context.Guild.Id, new ConcurrentQueue<RepeatRunner>(new[] { rep }), (key, old) =>
2016-08-28 20:59:12 +00:00
{
old.Enqueue(rep);
2016-08-29 12:34:46 +00:00
return old;
2016-08-28 12:19:50 +00:00
});
2016-12-16 21:44:26 +00:00
await Context.Channel.SendConfirmAsync($"🔁 Repeating **\"{rep.Repeater.Message}\"** every `{rep.Repeater.Interval.Days} day(s), {rep.Repeater.Interval.Hours} hour(s) and {rep.Repeater.Interval.Minutes} minute(s)`.").ConfigureAwait(false);
}
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
[RequireUserPermission(GuildPermission.ManageMessages)]
public async Task RepeatList()
{
ConcurrentQueue<RepeatRunner> repRunners;
if (!repeaters.TryGetValue(Context.Guild.Id, out repRunners))
{
await Context.Channel.SendConfirmAsync("No repeaters running on this server.").ConfigureAwait(false);
return;
}
var replist = repRunners.ToList();
var sb = new StringBuilder();
for (int i = 0; i < replist.Count; i++)
{
var rep = replist[i];
sb.AppendLine($"`{i + 1}.` {rep.ToString()}");
}
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
.WithTitle("List Of Repeaters")
.WithDescription(sb.ToString()))
.ConfigureAwait(false);
}
2016-08-28 20:59:12 +00:00
}
2016-08-28 12:19:50 +00:00
}
}