Typereaders finished, cleanup
This commit is contained in:
@ -0,0 +1,12 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling.Common
|
||||
{
|
||||
public abstract class CurrencyEvent
|
||||
{
|
||||
public abstract Task Stop();
|
||||
public abstract Task Start(IUserMessage msg, ICommandContext channel);
|
||||
}
|
||||
}
|
@ -0,0 +1,144 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Common.Collections;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling.Common
|
||||
{
|
||||
public class ReactionEvent : CurrencyEvent
|
||||
{
|
||||
private readonly ConcurrentHashSet<ulong> _reactionAwardedUsers = new ConcurrentHashSet<ulong>();
|
||||
private readonly BotConfig _bc;
|
||||
private readonly Logger _log;
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly CurrencyService _cs;
|
||||
private readonly SocketSelfUser _botUser;
|
||||
|
||||
private IUserMessage StartingMessage { get; set; }
|
||||
|
||||
private CancellationTokenSource Source { get; }
|
||||
private CancellationToken CancelToken { get; }
|
||||
|
||||
private readonly ConcurrentQueue<ulong> _toGiveTo = new ConcurrentQueue<ulong>();
|
||||
private readonly int _amount;
|
||||
|
||||
public ReactionEvent(BotConfig bc, DiscordSocketClient client, CurrencyService cs, int amount)
|
||||
{
|
||||
_bc = bc;
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
_client = client;
|
||||
_cs = cs;
|
||||
_botUser = client.CurrentUser;
|
||||
_amount = amount;
|
||||
Source = new CancellationTokenSource();
|
||||
CancelToken = Source.Token;
|
||||
|
||||
var _ = Task.Run(async () =>
|
||||
{
|
||||
var users = new List<ulong>();
|
||||
while (!CancelToken.IsCancellationRequested)
|
||||
{
|
||||
await Task.Delay(1000).ConfigureAwait(false);
|
||||
while (_toGiveTo.TryDequeue(out var usrId))
|
||||
{
|
||||
users.Add(usrId);
|
||||
}
|
||||
|
||||
if (users.Count > 0)
|
||||
{
|
||||
await _cs.AddToManyAsync("Reaction Event", _amount, users.ToArray()).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
users.Clear();
|
||||
}
|
||||
}, CancelToken);
|
||||
}
|
||||
|
||||
public override async Task Stop()
|
||||
{
|
||||
if (StartingMessage != null)
|
||||
await StartingMessage.DeleteAsync().ConfigureAwait(false);
|
||||
|
||||
if (!Source.IsCancellationRequested)
|
||||
Source.Cancel();
|
||||
|
||||
_client.MessageDeleted -= MessageDeletedEventHandler;
|
||||
}
|
||||
|
||||
private Task MessageDeletedEventHandler(Cacheable<IMessage, ulong> msg, ISocketMessageChannel channel)
|
||||
{
|
||||
if (StartingMessage?.Id == msg.Id)
|
||||
{
|
||||
_log.Warn("Stopping flower reaction event because message is deleted.");
|
||||
var __ = Task.Run(Stop);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override async Task Start(IUserMessage umsg, ICommandContext context)
|
||||
{
|
||||
StartingMessage = umsg;
|
||||
_client.MessageDeleted += MessageDeletedEventHandler;
|
||||
|
||||
IEmote iemote;
|
||||
if (Emote.TryParse(_bc.CurrencySign, out var emote))
|
||||
{
|
||||
iemote = emote;
|
||||
}
|
||||
else
|
||||
iemote = new Emoji(_bc.CurrencySign);
|
||||
try { await StartingMessage.AddReactionAsync(iemote).ConfigureAwait(false); }
|
||||
catch
|
||||
{
|
||||
try { await StartingMessage.AddReactionAsync(iemote).ConfigureAwait(false); }
|
||||
catch
|
||||
{
|
||||
try { await StartingMessage.DeleteAsync().ConfigureAwait(false); }
|
||||
catch { return; }
|
||||
}
|
||||
}
|
||||
using (StartingMessage.OnReaction(_client, (r) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (r.UserId == _botUser.Id)
|
||||
return;
|
||||
|
||||
if (r.Emote.Name == iemote.Name && r.User.IsSpecified && ((DateTime.UtcNow - r.User.Value.CreatedAt).TotalDays > 5) && _reactionAwardedUsers.Add(r.User.Value.Id))
|
||||
{
|
||||
_toGiveTo.Enqueue(r.UserId);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}))
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromHours(24), CancelToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
|
||||
}
|
||||
if (CancelToken.IsCancellationRequested)
|
||||
return;
|
||||
|
||||
_log.Warn("Stopping flower reaction event because it expired.");
|
||||
await Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Common;
|
||||
using NadekoBot.Common.Collections;
|
||||
using NadekoBot.Services;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling.Common.CurrencyEvents
|
||||
{
|
||||
public class SneakyEvent : CurrencyEvent
|
||||
{
|
||||
public event Action OnEnded;
|
||||
public string Code { get; private set; } = string.Empty;
|
||||
private readonly ConcurrentHashSet<ulong> _sneakyGameAwardedUsers = new ConcurrentHashSet<ulong>();
|
||||
|
||||
private readonly char[] _sneakyGameStatusChars = Enumerable.Range(48, 10)
|
||||
.Concat(Enumerable.Range(65, 26))
|
||||
.Concat(Enumerable.Range(97, 26))
|
||||
.Select(x => (char)x)
|
||||
.ToArray();
|
||||
|
||||
private readonly CurrencyService _cs;
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly IBotConfigProvider _bc;
|
||||
private readonly int _length;
|
||||
|
||||
public SneakyEvent(CurrencyService cs, DiscordSocketClient client,
|
||||
IBotConfigProvider bc, int len)
|
||||
{
|
||||
_cs = cs;
|
||||
_client = client;
|
||||
_bc = bc;
|
||||
_length = len;
|
||||
}
|
||||
|
||||
public override async Task Start(IUserMessage msg, ICommandContext channel)
|
||||
{
|
||||
GenerateCode();
|
||||
|
||||
//start the event
|
||||
_client.MessageReceived += SneakyGameMessageReceivedEventHandler;
|
||||
await _client.SetGameAsync($"type {Code} for " + _bc.BotConfig.CurrencyPluralName)
|
||||
.ConfigureAwait(false);
|
||||
await Task.Delay(_length * 1000).ConfigureAwait(false);
|
||||
await Stop().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private void GenerateCode()
|
||||
{
|
||||
var rng = new NadekoRandom();
|
||||
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
Code += _sneakyGameStatusChars[rng.Next(0, _sneakyGameStatusChars.Length)];
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task Stop()
|
||||
{
|
||||
try
|
||||
{
|
||||
_client.MessageReceived -= SneakyGameMessageReceivedEventHandler;
|
||||
Code = string.Empty;
|
||||
_sneakyGameAwardedUsers.Clear();
|
||||
await _client.SetGameAsync(null).ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
finally
|
||||
{
|
||||
|
||||
OnEnded?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
private Task SneakyGameMessageReceivedEventHandler(SocketMessage arg)
|
||||
{
|
||||
if (arg.Content == Code &&
|
||||
_sneakyGameAwardedUsers.Add(arg.Author.Id))
|
||||
{
|
||||
var _ = Task.Run(async () =>
|
||||
{
|
||||
await _cs.AddAsync(arg.Author, "Sneaky Game Event", 100, false)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
try { await arg.DeleteAsync(new RequestOptions() { RetryMode = RetryMode.AlwaysFail }).ConfigureAwait(false); }
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
@ -2,42 +2,26 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.WebSocket;
|
||||
using System.Threading;
|
||||
using NadekoBot.Common;
|
||||
using NadekoBot.Common.Attributes;
|
||||
using NadekoBot.Common.Collections;
|
||||
using NLog;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Modules.Gambling.Common;
|
||||
using NadekoBot.Modules.Gambling.Services;
|
||||
using NadekoBot.Modules.Gambling.Common.CurrencyEvents;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling
|
||||
{
|
||||
//todo mess, needs unload thing too - refactor
|
||||
public partial class Gambling
|
||||
{
|
||||
[Group]
|
||||
public class CurrencyEventsCommands : NadekoSubmodule
|
||||
public class CurrencyEventsCommands : NadekoSubmodule<CurrencyEventsService>
|
||||
{
|
||||
public enum CurrencyEvent
|
||||
{
|
||||
Reaction,
|
||||
SneakyGameStatus
|
||||
}
|
||||
//flower reaction event
|
||||
private static readonly ConcurrentHashSet<ulong> _sneakyGameAwardedUsers = new ConcurrentHashSet<ulong>();
|
||||
|
||||
private static readonly char[] _sneakyGameStatusChars = Enumerable.Range(48, 10)
|
||||
.Concat(Enumerable.Range(65, 26))
|
||||
.Concat(Enumerable.Range(97, 26))
|
||||
.Select(x => (char)x)
|
||||
.ToArray();
|
||||
|
||||
private string _secretCode = string.Empty;
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly IBotConfigProvider _bc;
|
||||
private readonly CurrencyService _cs;
|
||||
@ -65,68 +49,27 @@ namespace NadekoBot.Modules.Gambling
|
||||
}
|
||||
}
|
||||
|
||||
public async Task SneakyGameStatusEvent(ICommandContext context, int? arg)
|
||||
private async Task SneakyGameStatusEvent(ICommandContext context, int num)
|
||||
{
|
||||
int num;
|
||||
if (arg == null || arg < 5)
|
||||
if (num < 10 || num > 600)
|
||||
num = 60;
|
||||
else
|
||||
num = arg.Value;
|
||||
|
||||
if (_secretCode != string.Empty)
|
||||
var ev = new SneakyEvent(_cs, _client, _bc, num);
|
||||
if (!await _service.StartSneakyEvent(ev, context.Message, context))
|
||||
return;
|
||||
var rng = new NadekoRandom();
|
||||
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
_secretCode += _sneakyGameStatusChars[rng.Next(0, _sneakyGameStatusChars.Length)];
|
||||
}
|
||||
|
||||
await _client.SetGameAsync($"type {_secretCode} for " + _bc.BotConfig.CurrencyPluralName)
|
||||
.ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
var title = GetText("sneakygamestatus_title");
|
||||
var desc = GetText("sneakygamestatus_desc", Format.Bold(100.ToString()) + _bc.BotConfig.CurrencySign, Format.Bold(num.ToString()));
|
||||
await context.Channel.SendConfirmAsync(title, desc).ConfigureAwait(false);
|
||||
var desc = GetText("sneakygamestatus_desc",
|
||||
Format.Bold(100.ToString()) + _bc.BotConfig.CurrencySign,
|
||||
Format.Bold(num.ToString()));
|
||||
await context.Channel.SendConfirmAsync(title, desc)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
|
||||
_client.MessageReceived += SneakyGameMessageReceivedEventHandler;
|
||||
await Task.Delay(num * 1000);
|
||||
_client.MessageReceived -= SneakyGameMessageReceivedEventHandler;
|
||||
|
||||
var cnt = _sneakyGameAwardedUsers.Count;
|
||||
_sneakyGameAwardedUsers.Clear();
|
||||
_secretCode = string.Empty;
|
||||
|
||||
await _client.SetGameAsync(GetText("sneakygamestatus_end", cnt))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private Task SneakyGameMessageReceivedEventHandler(SocketMessage arg)
|
||||
{
|
||||
if (arg.Content == _secretCode &&
|
||||
_sneakyGameAwardedUsers.Add(arg.Author.Id))
|
||||
{
|
||||
var _ = Task.Run(async () =>
|
||||
{
|
||||
await _cs.AddAsync(arg.Author, "Sneaky Game Event", 100, false)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
try { await arg.DeleteAsync(new RequestOptions() { RetryMode = RetryMode.AlwaysFail }).ConfigureAwait(false); }
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task ReactionEvent(ICommandContext context, int amount)
|
||||
@ -137,144 +80,11 @@ namespace NadekoBot.Modules.Gambling
|
||||
var title = GetText("reaction_title");
|
||||
var desc = GetText("reaction_desc", _bc.BotConfig.CurrencySign, Format.Bold(amount.ToString()) + _bc.BotConfig.CurrencySign);
|
||||
var footer = GetText("reaction_footer", 24);
|
||||
var re = new ReactionEvent(_bc.BotConfig, _client, _cs, amount);
|
||||
var msg = await context.Channel.SendConfirmAsync(title,
|
||||
desc, footer: footer)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
await new ReactionEvent(_bc.BotConfig, _client, _cs, amount).Start(msg, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class CurrencyEvent
|
||||
{
|
||||
public abstract Task Start(IUserMessage msg, ICommandContext channel);
|
||||
}
|
||||
|
||||
public class ReactionEvent : CurrencyEvent
|
||||
{
|
||||
private readonly ConcurrentHashSet<ulong> _reactionAwardedUsers = new ConcurrentHashSet<ulong>();
|
||||
private readonly BotConfig _bc;
|
||||
private readonly Logger _log;
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly CurrencyService _cs;
|
||||
private readonly SocketSelfUser _botUser;
|
||||
|
||||
private IUserMessage StartingMessage { get; set; }
|
||||
|
||||
private CancellationTokenSource Source { get; }
|
||||
private CancellationToken CancelToken { get; }
|
||||
|
||||
private readonly ConcurrentQueue<ulong> _toGiveTo = new ConcurrentQueue<ulong>();
|
||||
private readonly int _amount;
|
||||
|
||||
public ReactionEvent(BotConfig bc, DiscordSocketClient client, CurrencyService cs, int amount)
|
||||
{
|
||||
_bc = bc;
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
_client = client;
|
||||
_cs = cs;
|
||||
_botUser = client.CurrentUser;
|
||||
_amount = amount;
|
||||
Source = new CancellationTokenSource();
|
||||
CancelToken = Source.Token;
|
||||
|
||||
var _ = Task.Run(async () =>
|
||||
{
|
||||
|
||||
var users = new List<ulong>();
|
||||
while (!CancelToken.IsCancellationRequested)
|
||||
{
|
||||
await Task.Delay(1000).ConfigureAwait(false);
|
||||
while (_toGiveTo.TryDequeue(out var usrId))
|
||||
{
|
||||
users.Add(usrId);
|
||||
}
|
||||
|
||||
if (users.Count > 0)
|
||||
{
|
||||
await _cs.AddToManyAsync("Reaction Event", _amount, users.ToArray()).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
users.Clear();
|
||||
}
|
||||
}, CancelToken);
|
||||
}
|
||||
|
||||
private async Task End()
|
||||
{
|
||||
if(StartingMessage != null)
|
||||
await StartingMessage.DeleteAsync().ConfigureAwait(false);
|
||||
|
||||
if(!Source.IsCancellationRequested)
|
||||
Source.Cancel();
|
||||
|
||||
_client.MessageDeleted -= MessageDeletedEventHandler;
|
||||
}
|
||||
|
||||
private Task MessageDeletedEventHandler(Cacheable<IMessage, ulong> msg, ISocketMessageChannel channel) {
|
||||
if (StartingMessage?.Id == msg.Id)
|
||||
{
|
||||
_log.Warn("Stopping flower reaction event because message is deleted.");
|
||||
var __ = Task.Run(End);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override async Task Start(IUserMessage umsg, ICommandContext context)
|
||||
{
|
||||
StartingMessage = umsg;
|
||||
_client.MessageDeleted += MessageDeletedEventHandler;
|
||||
|
||||
IEmote iemote;
|
||||
if (Emote.TryParse(_bc.CurrencySign, out var emote))
|
||||
{
|
||||
iemote = emote;
|
||||
}
|
||||
else
|
||||
iemote = new Emoji(_bc.CurrencySign);
|
||||
try { await StartingMessage.AddReactionAsync(iemote).ConfigureAwait(false); }
|
||||
catch
|
||||
{
|
||||
try { await StartingMessage.AddReactionAsync(iemote).ConfigureAwait(false); }
|
||||
catch
|
||||
{
|
||||
try { await StartingMessage.DeleteAsync().ConfigureAwait(false); }
|
||||
catch { return; }
|
||||
}
|
||||
}
|
||||
using (StartingMessage.OnReaction(_client, (r) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (r.UserId == _botUser.Id)
|
||||
return;
|
||||
|
||||
if (r.Emote.Name == iemote.Name && r.User.IsSpecified && ((DateTime.UtcNow - r.User.Value.CreatedAt).TotalDays > 5) && _reactionAwardedUsers.Add(r.User.Value.Id))
|
||||
{
|
||||
_toGiveTo.Enqueue(r.UserId);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}))
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromHours(24), CancelToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
|
||||
}
|
||||
if (CancelToken.IsCancellationRequested)
|
||||
return;
|
||||
|
||||
_log.Warn("Stopping flower reaction event because it expired.");
|
||||
await End();
|
||||
await re.Start(msg, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
66
NadekoBot.Modules.Gambling/Services/CurrencyEventsService.cs
Normal file
66
NadekoBot.Modules.Gambling/Services/CurrencyEventsService.cs
Normal file
@ -0,0 +1,66 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Modules.Gambling.Common;
|
||||
using NadekoBot.Modules.Gambling.Common.CurrencyEvents;
|
||||
using NadekoBot.Services;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling.Services
|
||||
{
|
||||
public class CurrencyEventsService : INService, IUnloadableService
|
||||
{
|
||||
public ConcurrentDictionary<ulong, List<ReactionEvent>> ReactionEvents { get; }
|
||||
|
||||
public SneakyEvent SneakyEvent { get; private set; } = null;
|
||||
private SemaphoreSlim _sneakyLock = new SemaphoreSlim(1, 1);
|
||||
|
||||
public CurrencyEventsService()
|
||||
{
|
||||
ReactionEvents = new ConcurrentDictionary<ulong, List<ReactionEvent>>();
|
||||
}
|
||||
|
||||
public async Task<bool> StartSneakyEvent(SneakyEvent ev, IUserMessage msg, ICommandContext ctx)
|
||||
{
|
||||
await _sneakyLock.WaitAsync().ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
if (SneakyEvent != null)
|
||||
return false;
|
||||
|
||||
SneakyEvent = ev;
|
||||
ev.OnEnded += () => SneakyEvent = null;
|
||||
var _ = SneakyEvent.Start(msg, ctx).ConfigureAwait(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_sneakyLock.Release();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task Unload()
|
||||
{
|
||||
foreach (var kvp in ReactionEvents)
|
||||
{
|
||||
foreach (var ev in kvp.Value)
|
||||
{
|
||||
try { await ev.Stop().ConfigureAwait(false); } catch { }
|
||||
}
|
||||
}
|
||||
ReactionEvents.Clear();
|
||||
|
||||
await _sneakyLock.WaitAsync().ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
await SneakyEvent.Stop().ConfigureAwait(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_sneakyLock.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user