Typereaders finished, cleanup
This commit is contained in:
parent
3d3871f903
commit
0bacb1f780
@ -3,26 +3,26 @@ using System.Net.Sockets;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using NadekoBot.Services;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
namespace NadekoBot.Common.ShardCom
|
namespace NadekoBot.Common.ShardCom
|
||||||
{
|
{
|
||||||
public class ShardComClient
|
public class ShardComClient
|
||||||
{
|
{
|
||||||
private int port;
|
private readonly IDataCache _cache;
|
||||||
|
|
||||||
public ShardComClient(int port)
|
public ShardComClient(IDataCache cache)
|
||||||
{
|
{
|
||||||
this.port = port;
|
_cache = cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Send(ShardComMessage data)
|
public async Task Send(ShardComMessage data)
|
||||||
{
|
{
|
||||||
|
var sub = _cache.Redis.GetSubscriber();
|
||||||
var msg = JsonConvert.SerializeObject(data);
|
var msg = JsonConvert.SerializeObject(data);
|
||||||
using (var client = new UdpClient())
|
|
||||||
{
|
await sub.PublishAsync("shardcoord_send", msg).ConfigureAwait(false);
|
||||||
var bytes = Encoding.UTF8.GetBytes(msg);
|
|
||||||
await client.SendAsync(bytes, bytes.Length, IPAddress.Loopback.ToString(), port).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,35 +4,26 @@ using System.Net.Sockets;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using NadekoBot.Services;
|
||||||
|
|
||||||
namespace NadekoBot.Common.ShardCom
|
namespace NadekoBot.Common.ShardCom
|
||||||
{
|
{
|
||||||
public class ShardComServer : IDisposable
|
public class ShardComServer
|
||||||
{
|
{
|
||||||
private readonly UdpClient _client;
|
private readonly IDataCache _cache;
|
||||||
|
|
||||||
public ShardComServer(int port)
|
public ShardComServer(IDataCache cache)
|
||||||
{
|
{
|
||||||
_client = new UdpClient(port);
|
_cache = cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
Task.Run(async () =>
|
var sub = _cache.Redis.GetSubscriber();
|
||||||
|
sub.SubscribeAsync("shardcoord_send", (ch, data) =>
|
||||||
{
|
{
|
||||||
var ip = new IPEndPoint(IPAddress.Any, 0);
|
var _ = OnDataReceived(JsonConvert.DeserializeObject<ShardComMessage>(data));
|
||||||
while (true)
|
}, StackExchange.Redis.CommandFlags.FireAndForget);
|
||||||
{
|
|
||||||
var recv = await _client.ReceiveAsync();
|
|
||||||
var data = Encoding.UTF8.GetString(recv.Buffer);
|
|
||||||
var _ = OnDataReceived(JsonConvert.DeserializeObject<ShardComMessage>(data));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_client.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public event Func<ShardComMessage, Task> OnDataReceived = delegate { return Task.CompletedTask; };
|
public event Func<ShardComMessage, Task> OnDataReceived = delegate { return Task.CompletedTask; };
|
||||||
|
@ -9,7 +9,7 @@ using Discord.WebSocket;
|
|||||||
|
|
||||||
namespace NadekoBot.Common.TypeReaders
|
namespace NadekoBot.Common.TypeReaders
|
||||||
{
|
{
|
||||||
public class CommandTypeReader : NadekoTypeReader
|
public class CommandTypeReader : NadekoTypeReader<CommandInfo>
|
||||||
{
|
{
|
||||||
public CommandTypeReader(DiscordSocketClient client, CommandService cmds) : base(client, cmds)
|
public CommandTypeReader(DiscordSocketClient client, CommandService cmds) : base(client, cmds)
|
||||||
{
|
{
|
||||||
@ -35,10 +35,14 @@ namespace NadekoBot.Common.TypeReaders
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CommandOrCrTypeReader : CommandTypeReader
|
public class CommandOrCrTypeReader : NadekoTypeReader<CommandOrCrInfo>
|
||||||
{
|
{
|
||||||
|
private readonly DiscordSocketClient _client;
|
||||||
|
private readonly CommandService _cmds;
|
||||||
public CommandOrCrTypeReader(DiscordSocketClient client, CommandService cmds) : base(client, cmds)
|
public CommandOrCrTypeReader(DiscordSocketClient client, CommandService cmds) : base(client, cmds)
|
||||||
{
|
{
|
||||||
|
_client = client;
|
||||||
|
_cmds = cmds;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<TypeReaderResult> Read(ICommandContext context, string input, IServiceProvider services)
|
public override async Task<TypeReaderResult> Read(ICommandContext context, string input, IServiceProvider services)
|
||||||
@ -63,7 +67,7 @@ namespace NadekoBot.Common.TypeReaders
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var cmd = await base.Read(context, input, services);
|
var cmd = await new CommandTypeReader(_client, _cmds).Read(context, input, services);
|
||||||
if (cmd.IsSuccess)
|
if (cmd.IsSuccess)
|
||||||
{
|
{
|
||||||
return TypeReaderResult.FromSuccess(new CommandOrCrInfo(((CommandInfo)cmd.Values.First().Value).Name));
|
return TypeReaderResult.FromSuccess(new CommandOrCrInfo(((CommandInfo)cmd.Values.First().Value).Name));
|
||||||
|
@ -7,7 +7,7 @@ using Discord.WebSocket;
|
|||||||
|
|
||||||
namespace NadekoBot.Common.TypeReaders
|
namespace NadekoBot.Common.TypeReaders
|
||||||
{
|
{
|
||||||
public class GuildDateTimeTypeReader : NadekoTypeReader
|
public class GuildDateTimeTypeReader : NadekoTypeReader<GuildDateTime>
|
||||||
{
|
{
|
||||||
public GuildDateTimeTypeReader(DiscordSocketClient client, CommandService cmds) : base(client, cmds)
|
public GuildDateTimeTypeReader(DiscordSocketClient client, CommandService cmds) : base(client, cmds)
|
||||||
{
|
{
|
||||||
|
@ -4,10 +4,11 @@ using System.Threading.Tasks;
|
|||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using Discord.WebSocket;
|
using Discord.WebSocket;
|
||||||
using NadekoBot.Core.Common.TypeReaders;
|
using NadekoBot.Core.Common.TypeReaders;
|
||||||
|
using Discord;
|
||||||
|
|
||||||
namespace NadekoBot.Common.TypeReaders
|
namespace NadekoBot.Common.TypeReaders
|
||||||
{
|
{
|
||||||
public class GuildTypeReader : NadekoTypeReader
|
public class GuildTypeReader : NadekoTypeReader<IGuild>
|
||||||
{
|
{
|
||||||
private readonly DiscordSocketClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ using Discord.WebSocket;
|
|||||||
|
|
||||||
namespace NadekoBot.Common.TypeReaders
|
namespace NadekoBot.Common.TypeReaders
|
||||||
{
|
{
|
||||||
public class ModuleTypeReader : NadekoTypeReader
|
public class ModuleTypeReader : NadekoTypeReader<ModuleInfo>
|
||||||
{
|
{
|
||||||
private readonly CommandService _cmds;
|
private readonly CommandService _cmds;
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ namespace NadekoBot.Common.TypeReaders
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ModuleOrCrTypeReader : NadekoTypeReader
|
public class ModuleOrCrTypeReader : NadekoTypeReader<ModuleOrCrInfo>
|
||||||
{
|
{
|
||||||
private readonly CommandService _cmds;
|
private readonly CommandService _cmds;
|
||||||
|
|
||||||
|
@ -3,7 +3,8 @@ using Discord.WebSocket;
|
|||||||
|
|
||||||
namespace NadekoBot.Core.Common.TypeReaders
|
namespace NadekoBot.Core.Common.TypeReaders
|
||||||
{
|
{
|
||||||
public abstract class NadekoTypeReader : TypeReader
|
public abstract class NadekoTypeReader<T> : TypeReader where
|
||||||
|
T : class
|
||||||
{
|
{
|
||||||
private readonly DiscordSocketClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly CommandService _cmds;
|
private readonly CommandService _cmds;
|
||||||
|
@ -10,7 +10,7 @@ namespace NadekoBot.Common.TypeReaders
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used instead of bool for more flexible keywords for true/false only in the permission module
|
/// Used instead of bool for more flexible keywords for true/false only in the permission module
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class PermissionActionTypeReader : NadekoTypeReader
|
public class PermissionActionTypeReader : NadekoTypeReader<PermissionAction>
|
||||||
{
|
{
|
||||||
public PermissionActionTypeReader(DiscordSocketClient client, CommandService cmds) : base(client, cmds)
|
public PermissionActionTypeReader(DiscordSocketClient client, CommandService cmds) : base(client, cmds)
|
||||||
{
|
{
|
||||||
|
@ -41,7 +41,7 @@ namespace NadekoBot.Modules.Administration.Services
|
|||||||
_rep = new ReplacementBuilder()
|
_rep = new ReplacementBuilder()
|
||||||
.WithClient(client)
|
.WithClient(client)
|
||||||
.WithStats(client)
|
.WithStats(client)
|
||||||
//todo type readers
|
//todo how to add music to replacement builder?
|
||||||
//.WithMusic(music)
|
//.WithMusic(music)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
|
@ -5,19 +5,20 @@ namespace NadekoBot.Services.Impl
|
|||||||
{
|
{
|
||||||
public class RedisCache : IDataCache
|
public class RedisCache : IDataCache
|
||||||
{
|
{
|
||||||
private ulong _botid;
|
|
||||||
|
|
||||||
public ConnectionMultiplexer Redis { get; }
|
public ConnectionMultiplexer Redis { get; }
|
||||||
private readonly IDatabase _db;
|
private readonly IDatabase _db;
|
||||||
|
|
||||||
public RedisCache(ulong botId)
|
public RedisCache()
|
||||||
{
|
{
|
||||||
_botid = botId;
|
|
||||||
Redis = ConnectionMultiplexer.Connect("127.0.0.1");
|
Redis = ConnectionMultiplexer.Connect("127.0.0.1");
|
||||||
Redis.PreserveAsyncOrder = false;
|
Redis.PreserveAsyncOrder = false;
|
||||||
_db = Redis.GetDatabase();
|
_db = Redis.GetDatabase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// things here so far don't need the bot id
|
||||||
|
// because it's a good thing if different bots
|
||||||
|
// which are hosted on the same PC
|
||||||
|
// can re-use the same image/anime data
|
||||||
public async Task<(bool Success, byte[] Data)> TryGetImageDataAsync(string key)
|
public async Task<(bool Success, byte[] Data)> TryGetImageDataAsync(string key)
|
||||||
{
|
{
|
||||||
byte[] x = await _db.StringGetAsync("image_" + key);
|
byte[] x = await _db.StringGetAsync("image_" + key);
|
||||||
|
@ -17,14 +17,11 @@ using NadekoBot.Extensions;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using NadekoBot.Common;
|
using NadekoBot.Common;
|
||||||
using NadekoBot.Common.ShardCom;
|
using NadekoBot.Common.ShardCom;
|
||||||
using NadekoBot.Common.TypeReaders;
|
|
||||||
using NadekoBot.Common.TypeReaders.Models;
|
|
||||||
using NadekoBot.Services.Database;
|
using NadekoBot.Services.Database;
|
||||||
using StackExchange.Redis;
|
using StackExchange.Redis;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using System.Runtime.Loader;
|
|
||||||
using NadekoBot.Core.Common.TypeReaders;
|
|
||||||
|
|
||||||
|
//todo Finish the script which autobuilds all projects if they're changed
|
||||||
namespace NadekoBot
|
namespace NadekoBot
|
||||||
{
|
{
|
||||||
public class NadekoBot
|
public class NadekoBot
|
||||||
@ -57,8 +54,9 @@ namespace NadekoBot
|
|||||||
private readonly ShardComClient _comClient;
|
private readonly ShardComClient _comClient;
|
||||||
|
|
||||||
private readonly BotConfig _botConfig;
|
private readonly BotConfig _botConfig;
|
||||||
|
public IDataCache Cache { get; private set; }
|
||||||
|
|
||||||
public NadekoBot(int shardId, int parentProcessId, int? port = null)
|
public NadekoBot(int shardId, int parentProcessId)
|
||||||
{
|
{
|
||||||
if (shardId < 0)
|
if (shardId < 0)
|
||||||
throw new ArgumentOutOfRangeException(nameof(shardId));
|
throw new ArgumentOutOfRangeException(nameof(shardId));
|
||||||
@ -67,6 +65,7 @@ namespace NadekoBot
|
|||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
TerribleElevatedPermissionCheck();
|
TerribleElevatedPermissionCheck();
|
||||||
|
|
||||||
|
Cache = new RedisCache();
|
||||||
Credentials = new BotCredentials();
|
Credentials = new BotCredentials();
|
||||||
_db = new DbService(Credentials);
|
_db = new DbService(Credentials);
|
||||||
Client = new DiscordSocketClient(new DiscordSocketConfig
|
Client = new DiscordSocketClient(new DiscordSocketConfig
|
||||||
@ -83,9 +82,8 @@ namespace NadekoBot
|
|||||||
CaseSensitiveCommands = false,
|
CaseSensitiveCommands = false,
|
||||||
DefaultRunMode = RunMode.Sync,
|
DefaultRunMode = RunMode.Sync,
|
||||||
});
|
});
|
||||||
|
|
||||||
port = port ?? Credentials.ShardRunPort;
|
_comClient = new ShardComClient(Cache);
|
||||||
_comClient = new ShardComClient(port.Value);
|
|
||||||
|
|
||||||
using (var uow = _db.UnitOfWork)
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
@ -94,7 +92,7 @@ namespace NadekoBot
|
|||||||
ErrorColor = new Color(Convert.ToUInt32(_botConfig.ErrorColor, 16));
|
ErrorColor = new Color(Convert.ToUInt32(_botConfig.ErrorColor, 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
SetupShard(parentProcessId, port.Value);
|
SetupShard(parentProcessId);
|
||||||
|
|
||||||
#if GLOBAL_NADEKO
|
#if GLOBAL_NADEKO
|
||||||
Client.Log += Client_Log;
|
Client.Log += Client_Log;
|
||||||
@ -144,7 +142,7 @@ namespace NadekoBot
|
|||||||
.AddManual<IEnumerable<GuildConfig>>(AllGuildConfigs) //todo wrap this
|
.AddManual<IEnumerable<GuildConfig>>(AllGuildConfigs) //todo wrap this
|
||||||
.AddManual<NadekoBot>(this)
|
.AddManual<NadekoBot>(this)
|
||||||
.AddManual<IUnitOfWork>(uow)
|
.AddManual<IUnitOfWork>(uow)
|
||||||
.AddManual<IDataCache>(new RedisCache(Client.CurrentUser.Id));
|
.AddManual<IDataCache>(Cache);
|
||||||
|
|
||||||
Services.LoadFrom(Assembly.GetAssembly(typeof(CommandHandler)));
|
Services.LoadFrom(Assembly.GetAssembly(typeof(CommandHandler)));
|
||||||
|
|
||||||
@ -156,7 +154,7 @@ namespace NadekoBot
|
|||||||
Services.Unload(typeof(IUnitOfWork)); // unload it after the startup
|
Services.Unload(typeof(IUnitOfWork)); // unload it after the startup
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<NadekoTypeReader> LoadTypeReaders(Assembly assembly)
|
private IEnumerable<object> LoadTypeReaders(Assembly assembly)
|
||||||
{
|
{
|
||||||
Type[] allTypes;
|
Type[] allTypes;
|
||||||
try
|
try
|
||||||
@ -166,18 +164,30 @@ namespace NadekoBot
|
|||||||
catch (ReflectionTypeLoadException ex)
|
catch (ReflectionTypeLoadException ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine(ex.LoaderExceptions[0]);
|
Console.WriteLine(ex.LoaderExceptions[0]);
|
||||||
return Enumerable.Empty<NadekoTypeReader>();
|
return Enumerable.Empty<object>();
|
||||||
}
|
}
|
||||||
var filteredTypes = allTypes
|
var filteredTypes = allTypes
|
||||||
.Where(x => x.IsSubclassOf(typeof(NadekoTypeReader))
|
.Where(x => x.IsSubclassOf(typeof(TypeReader))
|
||||||
|
&& x.BaseType.GetGenericArguments().Length > 0
|
||||||
&& !x.IsAbstract);
|
&& !x.IsAbstract);
|
||||||
|
|
||||||
var toReturn = new List<NadekoTypeReader>();
|
var toReturn = new List<object>();
|
||||||
foreach (var ft in filteredTypes)
|
foreach (var ft in filteredTypes)
|
||||||
{
|
{
|
||||||
//:yayyy:
|
//:yayyy:
|
||||||
var x = (NadekoTypeReader)Activator.CreateInstance(ft, Client, CommandService);
|
var x = (TypeReader)Activator.CreateInstance(ft, Client, CommandService);
|
||||||
CommandService.AddTypeReader(x.GetType(), x);
|
//@.@ XD XDDD
|
||||||
|
var baseType = ft.BaseType;
|
||||||
|
var typeArgs = baseType.GetGenericArguments();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
CommandService.AddTypeReader(typeArgs[0], x);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_log.Error(ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
toReturn.Add(x);
|
toReturn.Add(x);
|
||||||
_log.Info("Loaded {0} typereader.", x.GetType().Name);
|
_log.Info("Loaded {0} typereader.", x.GetType().Name);
|
||||||
}
|
}
|
||||||
@ -317,11 +327,11 @@ namespace NadekoBot
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetupShard(int parentProcessId, int port)
|
private void SetupShard(int parentProcessId)
|
||||||
{
|
{
|
||||||
if (Client.ShardId == 0)
|
if (Client.ShardId == 0)
|
||||||
{
|
{
|
||||||
ShardCoord = new ShardsCoordinator(port);
|
ShardCoord = new ShardsCoordinator(Cache);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
new Thread(new ThreadStart(() =>
|
new Thread(new ThreadStart(() =>
|
||||||
|
@ -19,19 +19,28 @@ namespace NadekoBot.Services
|
|||||||
|
|
||||||
private readonly Logger _log;
|
private readonly Logger _log;
|
||||||
private readonly ShardComServer _comServer;
|
private readonly ShardComServer _comServer;
|
||||||
private readonly int _port;
|
|
||||||
private readonly int _curProcessId;
|
private readonly int _curProcessId;
|
||||||
|
|
||||||
public ShardsCoordinator(int port)
|
public ShardsCoordinator(IDataCache cache)
|
||||||
{
|
{
|
||||||
LogSetup.SetupLogger();
|
LogSetup.SetupLogger();
|
||||||
_creds = new BotCredentials();
|
_creds = new BotCredentials();
|
||||||
_shardProcesses = new Process[_creds.TotalShards];
|
_shardProcesses = new Process[_creds.TotalShards];
|
||||||
Statuses = new ShardComMessage[_creds.TotalShards];
|
Statuses = new ShardComMessage[_creds.TotalShards];
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
|
||||||
_port = port;
|
|
||||||
|
|
||||||
_comServer = new ShardComServer(port);
|
for (int i = 0; i < Statuses.Length; i++)
|
||||||
|
{
|
||||||
|
Statuses[i] = new ShardComMessage();
|
||||||
|
var s = Statuses[i];
|
||||||
|
s.ConnectionState = Discord.ConnectionState.Disconnected;
|
||||||
|
s.Guilds = 0;
|
||||||
|
s.ShardId = i;
|
||||||
|
s.Time = DateTime.Now - TimeSpan.FromMinutes(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
_comServer = new ShardComServer(cache);
|
||||||
_comServer.Start();
|
_comServer.Start();
|
||||||
|
|
||||||
_comServer.OnDataReceived += _comServer_OnDataReceived;
|
_comServer.OnDataReceived += _comServer_OnDataReceived;
|
||||||
@ -54,8 +63,10 @@ namespace NadekoBot.Services
|
|||||||
var p = Process.Start(new ProcessStartInfo()
|
var p = Process.Start(new ProcessStartInfo()
|
||||||
{
|
{
|
||||||
FileName = _creds.ShardRunCommand,
|
FileName = _creds.ShardRunCommand,
|
||||||
Arguments = string.Format(_creds.ShardRunArguments, i, _curProcessId, _port)
|
Arguments = string.Format(_creds.ShardRunArguments, i, _curProcessId, "")
|
||||||
});
|
});
|
||||||
|
// last "" in format is for backwards compatibility
|
||||||
|
// because current startup commands have {2} in them probably
|
||||||
await Task.Delay(5000);
|
await Task.Delay(5000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,21 @@ namespace NadekoBot.Extensions
|
|||||||
{
|
{
|
||||||
public static class Extensions
|
public static class Extensions
|
||||||
{
|
{
|
||||||
|
//so ftw
|
||||||
|
public static bool IsSubclassOfRawGeneric(this Type toCheck, Type generic)
|
||||||
|
{
|
||||||
|
while (toCheck != null && toCheck != typeof(object))
|
||||||
|
{
|
||||||
|
var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
|
||||||
|
if (generic == cur)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
toCheck = toCheck.BaseType;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public static async Task<string> ReplaceAsync(this Regex regex, string input, Func<Match, Task<string>> replacementFn)
|
public static async Task<string> ReplaceAsync(this Regex regex, string input, Func<Match, Task<string>> replacementFn)
|
||||||
{
|
{
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
|
@ -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 Discord.Commands;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Discord.WebSocket;
|
using Discord.WebSocket;
|
||||||
using System.Threading;
|
|
||||||
using NadekoBot.Common;
|
|
||||||
using NadekoBot.Common.Attributes;
|
using NadekoBot.Common.Attributes;
|
||||||
using NadekoBot.Common.Collections;
|
using NadekoBot.Modules.Gambling.Common;
|
||||||
using NLog;
|
using NadekoBot.Modules.Gambling.Services;
|
||||||
using System.Collections.Concurrent;
|
using NadekoBot.Modules.Gambling.Common.CurrencyEvents;
|
||||||
using System.Collections.Generic;
|
|
||||||
using NadekoBot.Services.Database.Models;
|
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Gambling
|
namespace NadekoBot.Modules.Gambling
|
||||||
{
|
{
|
||||||
//todo mess, needs unload thing too - refactor
|
|
||||||
public partial class Gambling
|
public partial class Gambling
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class CurrencyEventsCommands : NadekoSubmodule
|
public class CurrencyEventsCommands : NadekoSubmodule<CurrencyEventsService>
|
||||||
{
|
{
|
||||||
public enum CurrencyEvent
|
public enum CurrencyEvent
|
||||||
{
|
{
|
||||||
Reaction,
|
Reaction,
|
||||||
SneakyGameStatus
|
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 DiscordSocketClient _client;
|
||||||
private readonly IBotConfigProvider _bc;
|
private readonly IBotConfigProvider _bc;
|
||||||
private readonly CurrencyService _cs;
|
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 (num < 10 || num > 600)
|
||||||
if (arg == null || arg < 5)
|
|
||||||
num = 60;
|
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;
|
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
|
try
|
||||||
{
|
{
|
||||||
var title = GetText("sneakygamestatus_title");
|
var title = GetText("sneakygamestatus_title");
|
||||||
var desc = GetText("sneakygamestatus_desc", Format.Bold(100.ToString()) + _bc.BotConfig.CurrencySign, Format.Bold(num.ToString()));
|
var desc = GetText("sneakygamestatus_desc",
|
||||||
await context.Channel.SendConfirmAsync(title, desc).ConfigureAwait(false);
|
Format.Bold(100.ToString()) + _bc.BotConfig.CurrencySign,
|
||||||
|
Format.Bold(num.ToString()));
|
||||||
|
await context.Channel.SendConfirmAsync(title, desc)
|
||||||
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
// ignored
|
// 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)
|
public async Task ReactionEvent(ICommandContext context, int amount)
|
||||||
@ -137,144 +80,11 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
var title = GetText("reaction_title");
|
var title = GetText("reaction_title");
|
||||||
var desc = GetText("reaction_desc", _bc.BotConfig.CurrencySign, Format.Bold(amount.ToString()) + _bc.BotConfig.CurrencySign);
|
var desc = GetText("reaction_desc", _bc.BotConfig.CurrencySign, Format.Bold(amount.ToString()) + _bc.BotConfig.CurrencySign);
|
||||||
var footer = GetText("reaction_footer", 24);
|
var footer = GetText("reaction_footer", 24);
|
||||||
|
var re = new ReactionEvent(_bc.BotConfig, _client, _cs, amount);
|
||||||
var msg = await context.Channel.SendConfirmAsync(title,
|
var msg = await context.Channel.SendConfirmAsync(title,
|
||||||
desc, footer: footer)
|
desc, footer: footer)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
await re.Start(msg, context);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -6,12 +6,9 @@ namespace NadekoBot
|
|||||||
{
|
{
|
||||||
public static Task Main(string[] args)
|
public static Task Main(string[] args)
|
||||||
{
|
{
|
||||||
if (args.Length == 3 && int.TryParse(args[0], out int shardId) && int.TryParse(args[1], out int parentProcessId))
|
if (args.Length == 2 && int.TryParse(args[0], out int shardId) && int.TryParse(args[1], out int parentProcessId))
|
||||||
{
|
{
|
||||||
int? port = null;
|
return new NadekoBot(shardId, parentProcessId).RunAndBlockAsync(args);
|
||||||
if (int.TryParse(args[2], out var outPort))
|
|
||||||
port = outPort;
|
|
||||||
return new NadekoBot(shardId, parentProcessId, outPort).RunAndBlockAsync(args);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return new NadekoBot(0, 0).RunAndBlockAsync(args);
|
return new NadekoBot(0, 0).RunAndBlockAsync(args);
|
||||||
|
Loading…
Reference in New Issue
Block a user