Cleanup, .clparew can now be ran everyone, modules load appropriate guild configs, IEnumerable<GuildConfig> replaces with NadekoBot.AllGuildConfigs

This commit is contained in:
Master Kwoth 2017-10-13 02:21:39 +02:00
parent db6fa9af1a
commit e32446335e
40 changed files with 336 additions and 180 deletions

View File

@ -0,0 +1,49 @@
using System;
namespace NadekoBot.Core.Common.Caching
{
/// <summary>
/// A caching object which loads its value with a factory method when it expires.
/// </summary>
/// <typeparam name="T">Type of the value which is cached.</typeparam>
public class FactoryCache<T> : IFactoryCache
{
public DateTime LastUpdate { get; set; } = DateTime.MinValue;
private readonly object _locker = new object();
private TimeSpan _expireAfter;
private readonly Func<T> _factory;
private T Value;
/// <summary>
/// Creates a new factory cache object.
/// </summary>
/// <param name="factory">Method which loads the value when it expires or if it's not loaded the first time.</param>
/// <param name="expireAfter">Time after which the value will be reloaded.</param>
/// <param name="loadImmediately">Should the value be loaded right away. If set to false, value will load when it's first retrieved.</param>
public FactoryCache(Func<T> factory, TimeSpan expireAfter,
bool loadImmediately = false)
{
_expireAfter = expireAfter;
_factory = factory;
if (loadImmediately)
{
Value = _factory();
LastUpdate = DateTime.UtcNow;
}
}
public T GetValue()
{
lock (_locker)
{
if (DateTime.UtcNow - LastUpdate > _expireAfter)
{
LastUpdate = DateTime.UtcNow;
return Value = _factory();
}
return Value;
}
}
}
}

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NadekoBot.Core.Common.Caching
{
public interface IFactoryCache
{
}
}

View File

@ -0,0 +1,48 @@
using Discord.Commands;
using Microsoft.EntityFrameworkCore;
using NadekoBot.Common.Attributes;
using NadekoBot.Extensions;
using NadekoBot.Modules;
using NadekoBot.Services;
using System;
using System.Threading.Tasks;
#if DEBUG
namespace NadekoBot.Modules.Administration
{
public partial class Administration
{
[Group]
[OwnerOnly]
public class DangerousCommands : NadekoSubmodule
{
private readonly DbService _db;
public DangerousCommands(DbService db)
{
_db = db;
}
[NadekoCommand, Usage, Description, Aliases]
[OwnerOnly]
public async Task ExecSql([Remainder]string sql)
{
try
{
int res;
using (var uow = _db.UnitOfWork)
{
res = uow._context.Database.ExecuteSqlCommand(sql);
}
await Context.Channel.SendConfirmAsync(res.ToString());
}
catch (Exception ex)
{
await Context.Channel.SendErrorAsync(ex.ToString());
}
}
}
}
}
#endif

View File

@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Discord; using Discord;
@ -7,7 +6,6 @@ using Discord.Commands;
using Discord.WebSocket; using Discord.WebSocket;
using NadekoBot.Common.Collections; using NadekoBot.Common.Collections;
using NadekoBot.Services; using NadekoBot.Services;
using NadekoBot.Services.Database.Models;
using NLog; using NLog;
namespace NadekoBot.Modules.Administration.Services namespace NadekoBot.Modules.Administration.Services
@ -16,12 +14,14 @@ namespace NadekoBot.Modules.Administration.Services
{ {
public readonly ConcurrentHashSet<ulong> DeleteMessagesOnCommand; public readonly ConcurrentHashSet<ulong> DeleteMessagesOnCommand;
private readonly Logger _log; private readonly Logger _log;
private readonly NadekoBot _bot;
public AdministrationService(IEnumerable<GuildConfig> gcs, CommandHandler cmdHandler) public AdministrationService(NadekoBot bot, CommandHandler cmdHandler)
{ {
_log = LogManager.GetCurrentClassLogger(); _log = LogManager.GetCurrentClassLogger();
_bot = bot;
DeleteMessagesOnCommand = new ConcurrentHashSet<ulong>(gcs.Where(g => g.DeleteMessageOnCommand).Select(g => g.GuildId)); DeleteMessagesOnCommand = new ConcurrentHashSet<ulong>(bot.AllGuildConfigs.Where(g => g.DeleteMessageOnCommand).Select(g => g.GuildId));
cmdHandler.CommandExecuted += DelMsgOnCmd_Handler; cmdHandler.CommandExecuted += DelMsgOnCmd_Handler;
} }

View File

@ -1,11 +1,9 @@
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Discord.WebSocket; using Discord.WebSocket;
using NadekoBot.Services; using NadekoBot.Services;
using NadekoBot.Services.Database.Models;
using NLog; using NLog;
namespace NadekoBot.Modules.Administration.Services namespace NadekoBot.Modules.Administration.Services
@ -18,13 +16,13 @@ namespace NadekoBot.Modules.Administration.Services
//guildid/roleid //guildid/roleid
public ConcurrentDictionary<ulong, ulong> AutoAssignedRoles { get; } public ConcurrentDictionary<ulong, ulong> AutoAssignedRoles { get; }
public AutoAssignRoleService(DiscordSocketClient client, IEnumerable<GuildConfig> gcs) public AutoAssignRoleService(DiscordSocketClient client, NadekoBot bot)
{ {
_log = LogManager.GetCurrentClassLogger(); _log = LogManager.GetCurrentClassLogger();
_client = client; _client = client;
AutoAssignedRoles = new ConcurrentDictionary<ulong, ulong>( AutoAssignedRoles = new ConcurrentDictionary<ulong, ulong>(
gcs.Where(x => x.AutoAssignRoleId != 0) bot.AllGuildConfigs.Where(x => x.AutoAssignRoleId != 0)
.ToDictionary(k => k.GuildId, v => v.AutoAssignRoleId)); .ToDictionary(k => k.GuildId, v => v.AutoAssignRoleId));
_client.UserJoined += (user) => _client.UserJoined += (user) =>

View File

@ -19,14 +19,14 @@ namespace NadekoBot.Modules.Administration.Services
private readonly DbService _db; private readonly DbService _db;
private readonly DiscordSocketClient _client; private readonly DiscordSocketClient _client;
public GameVoiceChannelService(DiscordSocketClient client, DbService db, IEnumerable<GuildConfig> gcs) public GameVoiceChannelService(DiscordSocketClient client, DbService db, NadekoBot bot)
{ {
_log = LogManager.GetCurrentClassLogger(); _log = LogManager.GetCurrentClassLogger();
_db = db; _db = db;
_client = client; _client = client;
GameVoiceChannels = new ConcurrentHashSet<ulong>( GameVoiceChannels = new ConcurrentHashSet<ulong>(
gcs.Where(gc => gc.GameVoiceChannel != null) bot.AllGuildConfigs.Where(gc => gc.GameVoiceChannel != null)
.Select(gc => gc.GameVoiceChannel.Value)); .Select(gc => gc.GameVoiceChannel.Value));
_client.UserVoiceStateUpdated += Client_UserVoiceStateUpdated; _client.UserVoiceStateUpdated += Client_UserVoiceStateUpdated;

View File

@ -16,9 +16,9 @@ namespace NadekoBot.Modules.Administration.Services
private ConcurrentDictionary<ulong, TimeZoneInfo> _timezones; private ConcurrentDictionary<ulong, TimeZoneInfo> _timezones;
private readonly DbService _db; private readonly DbService _db;
public GuildTimezoneService(DiscordSocketClient client, IEnumerable<GuildConfig> gcs, DbService db) public GuildTimezoneService(DiscordSocketClient client, NadekoBot bot, DbService db)
{ {
_timezones = gcs _timezones = bot.AllGuildConfigs
.Select(x => .Select(x =>
{ {
TimeZoneInfo tz; TimeZoneInfo tz;
@ -33,10 +33,10 @@ namespace NadekoBot.Modules.Administration.Services
{ {
tz = null; tz = null;
} }
return (x.GuildId, tz); return (x.GuildId, Timezone: tz);
}) })
.Where(x => x.Item2 != null) .Where(x => x.Timezone != null)
.ToDictionary(x => x.Item1, x => x.Item2) .ToDictionary(x => x.GuildId, x => x.Timezone)
.ToConcurrent(); .ToConcurrent();
var curUser = client.CurrentUser; var curUser = client.CurrentUser;

View File

@ -50,7 +50,7 @@ namespace NadekoBot.Modules.Administration.Services
private readonly GuildTimezoneService _tz; private readonly GuildTimezoneService _tz;
public LogCommandService(DiscordSocketClient client, NadekoStrings strings, public LogCommandService(DiscordSocketClient client, NadekoStrings strings,
IEnumerable<GuildConfig> gcs, DbService db, MuteService mute, ProtectionService prot, GuildTimezoneService tz) NadekoBot bot, DbService db, MuteService mute, ProtectionService prot, GuildTimezoneService tz)
{ {
_client = client; _client = client;
_log = LogManager.GetCurrentClassLogger(); _log = LogManager.GetCurrentClassLogger();
@ -60,7 +60,7 @@ namespace NadekoBot.Modules.Administration.Services
_prot = prot; _prot = prot;
_tz = tz; _tz = tz;
GuildLogSettings = gcs GuildLogSettings = bot.AllGuildConfigs
.ToDictionary(g => g.GuildId, g => g.LogSetting) .ToDictionary(g => g.GuildId, g => g.LogSetting)
.ToConcurrent(); .ToConcurrent();

View File

@ -38,22 +38,25 @@ namespace NadekoBot.Modules.Administration.Services
private readonly DiscordSocketClient _client; private readonly DiscordSocketClient _client;
private readonly DbService _db; private readonly DbService _db;
public MuteService(DiscordSocketClient client, IEnumerable<GuildConfig> gcs, DbService db) public MuteService(DiscordSocketClient client, NadekoBot bot, DbService db)
{ {
_client = client; _client = client;
_db = db; _db = db;
GuildMuteRoles = gcs GuildMuteRoles = bot
.Where(c => !string.IsNullOrWhiteSpace(c.MuteRoleName)) .AllGuildConfigs
.ToDictionary(c => c.GuildId, c => c.MuteRoleName) .Where(c => !string.IsNullOrWhiteSpace(c.MuteRoleName))
.ToConcurrent(); .ToDictionary(c => c.GuildId, c => c.MuteRoleName)
.ToConcurrent();
MutedUsers = new ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>>(gcs.ToDictionary( MutedUsers = new ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>>(bot
k => k.GuildId, .AllGuildConfigs
v => new ConcurrentHashSet<ulong>(v.MutedUsers.Select(m => m.UserId)) .ToDictionary(
k => k.GuildId,
v => new ConcurrentHashSet<ulong>(v.MutedUsers.Select(m => m.UserId))
)); ));
foreach (var conf in gcs) foreach (var conf in bot.AllGuildConfigs)
{ {
foreach (var x in conf.UnmuteTimers) foreach (var x in conf.UnmuteTimers)
{ {

View File

@ -1,6 +1,5 @@
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Discord; using Discord;
@ -26,13 +25,13 @@ namespace NadekoBot.Modules.Administration.Services
private readonly DiscordSocketClient _client; private readonly DiscordSocketClient _client;
private readonly MuteService _mute; private readonly MuteService _mute;
public ProtectionService(DiscordSocketClient client, IEnumerable<GuildConfig> gcs, MuteService mute) public ProtectionService(DiscordSocketClient client, NadekoBot bot, MuteService mute)
{ {
_log = LogManager.GetCurrentClassLogger(); _log = LogManager.GetCurrentClassLogger();
_client = client; _client = client;
_mute = mute; _mute = mute;
foreach (var gc in gcs) foreach (var gc in bot.AllGuildConfigs)
{ {
var raid = gc.AntiRaidSetting; var raid = gc.AntiRaidSetting;
var spam = gc.AntiSpamSetting; var spam = gc.AntiSpamSetting;

View File

@ -23,17 +23,17 @@ namespace NadekoBot.Modules.Administration.Services
private readonly Logger _log; private readonly Logger _log;
private readonly DiscordSocketClient _client; private readonly DiscordSocketClient _client;
public SlowmodeService(DiscordSocketClient client, IEnumerable<GuildConfig> gcs) public SlowmodeService(DiscordSocketClient client, NadekoBot bot)
{ {
_log = LogManager.GetCurrentClassLogger(); _log = LogManager.GetCurrentClassLogger();
_client = client; _client = client;
IgnoredRoles = new ConcurrentDictionary<ulong, HashSet<ulong>>( IgnoredRoles = new ConcurrentDictionary<ulong, HashSet<ulong>>(
gcs.ToDictionary(x => x.GuildId, bot.AllGuildConfigs.ToDictionary(x => x.GuildId,
x => new HashSet<ulong>(x.SlowmodeIgnoredRoles.Select(y => y.RoleId)))); x => new HashSet<ulong>(x.SlowmodeIgnoredRoles.Select(y => y.RoleId))));
IgnoredUsers = new ConcurrentDictionary<ulong, HashSet<ulong>>( IgnoredUsers = new ConcurrentDictionary<ulong, HashSet<ulong>>(
gcs.ToDictionary(x => x.GuildId, bot.AllGuildConfigs.ToDictionary(x => x.GuildId,
x => new HashSet<ulong>(x.SlowmodeIgnoredUsers.Select(y => y.UserId)))); x => new HashSet<ulong>(x.SlowmodeIgnoredUsers.Select(y => y.UserId))));
} }

View File

@ -42,7 +42,7 @@ namespace NadekoBot.Modules.Administration.Services
_creds = creds; _creds = creds;
_bc = bc; _bc = bc;
var _ = Task.Run(async () => Task.Run(async () =>
{ {
await bot.Ready.Task.ConfigureAwait(false); await bot.Ready.Task.ConfigureAwait(false);
@ -57,14 +57,12 @@ namespace NadekoBot.Modules.Administration.Services
} }
}); });
var ___ = Task.Run(async () => Task.Run(async () =>
{ {
await bot.Ready.Task.ConfigureAwait(false); await bot.Ready.Task.ConfigureAwait(false);
await Task.Delay(5000); await Task.Delay(5000);
_client.Guilds.SelectMany(g => g.Users);
if(client.ShardId == 0) if(client.ShardId == 0)
LoadOwnerChannels(); LoadOwnerChannels();
}); });

View File

@ -19,7 +19,7 @@ namespace NadekoBot.Modules.Administration.Services
public ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, IRole>> VcRoles { get; } public ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, IRole>> VcRoles { get; }
public VcRoleService(DiscordSocketClient client, IEnumerable<GuildConfig> gcs, DbService db) public VcRoleService(DiscordSocketClient client, NadekoBot bot, DbService db)
{ {
_log = LogManager.GetCurrentClassLogger(); _log = LogManager.GetCurrentClassLogger();
_db = db; _db = db;
@ -28,7 +28,7 @@ namespace NadekoBot.Modules.Administration.Services
_client.UserVoiceStateUpdated += ClientOnUserVoiceStateUpdated; _client.UserVoiceStateUpdated += ClientOnUserVoiceStateUpdated;
VcRoles = new ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, IRole>>(); VcRoles = new ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, IRole>>();
var missingRoles = new List<VcRoleInfo>(); var missingRoles = new List<VcRoleInfo>();
foreach (var gconf in gcs) foreach (var gconf in bot.AllGuildConfigs)
{ {
var g = _client.GetGuild(gconf.GuildId); var g = _client.GetGuild(gconf.GuildId);
if (g == null) if (g == null)

View File

@ -28,7 +28,7 @@ namespace NadekoBot.Modules.Administration.Services
private readonly DbService _db; private readonly DbService _db;
private readonly Logger _log; private readonly Logger _log;
public VplusTService(DiscordSocketClient client, IEnumerable<GuildConfig> gcs, NadekoStrings strings, public VplusTService(DiscordSocketClient client, NadekoBot bot, NadekoStrings strings,
DbService db) DbService db)
{ {
_client = client; _client = client;
@ -36,7 +36,7 @@ namespace NadekoBot.Modules.Administration.Services
_db = db; _db = db;
_log = LogManager.GetCurrentClassLogger(); _log = LogManager.GetCurrentClassLogger();
VoicePlusTextCache = new ConcurrentHashSet<ulong>(gcs.Where(g => g.VoicePlusTextEnabled).Select(g => g.GuildId)); VoicePlusTextCache = new ConcurrentHashSet<ulong>(bot.AllGuildConfigs.Where(g => g.VoicePlusTextEnabled).Select(g => g.GuildId));
_client.UserVoiceStateUpdated += UserUpdatedEventHandler; _client.UserVoiceStateUpdated += UserUpdatedEventHandler;
} }

View File

@ -16,10 +16,10 @@ namespace NadekoBot.Modules.Permissions.Services
public ConcurrentDictionary<ulong, ConcurrentHashSet<CommandCooldown>> CommandCooldowns { get; } public ConcurrentDictionary<ulong, ConcurrentHashSet<CommandCooldown>> CommandCooldowns { get; }
public ConcurrentDictionary<ulong, ConcurrentHashSet<ActiveCooldown>> ActiveCooldowns { get; } = new ConcurrentDictionary<ulong, ConcurrentHashSet<ActiveCooldown>>(); public ConcurrentDictionary<ulong, ConcurrentHashSet<ActiveCooldown>> ActiveCooldowns { get; } = new ConcurrentDictionary<ulong, ConcurrentHashSet<ActiveCooldown>>();
public CmdCdService(IEnumerable<GuildConfig> gcs) public CmdCdService(NadekoBot bot)
{ {
CommandCooldowns = new ConcurrentDictionary<ulong, ConcurrentHashSet<CommandCooldown>>( CommandCooldowns = new ConcurrentDictionary<ulong, ConcurrentHashSet<CommandCooldown>>(
gcs.ToDictionary(k => k.GuildId, bot.AllGuildConfigs.ToDictionary(k => k.GuildId,
v => new ConcurrentHashSet<CommandCooldown>(v.CommandCooldowns))); v => new ConcurrentHashSet<CommandCooldown>(v.CommandCooldowns)));
} }

View File

@ -43,21 +43,21 @@ namespace NadekoBot.Modules.Permissions.Services
return words; return words;
} }
public FilterService(DiscordSocketClient _client, IEnumerable<GuildConfig> gcs) public FilterService(DiscordSocketClient _client, NadekoBot bot)
{ {
_log = LogManager.GetCurrentClassLogger(); _log = LogManager.GetCurrentClassLogger();
InviteFilteringServers = new ConcurrentHashSet<ulong>(gcs.Where(gc => gc.FilterInvites).Select(gc => gc.GuildId)); InviteFilteringServers = new ConcurrentHashSet<ulong>(bot.AllGuildConfigs.Where(gc => gc.FilterInvites).Select(gc => gc.GuildId));
InviteFilteringChannels = new ConcurrentHashSet<ulong>(gcs.SelectMany(gc => gc.FilterInvitesChannelIds.Select(fci => fci.ChannelId))); InviteFilteringChannels = new ConcurrentHashSet<ulong>(bot.AllGuildConfigs.SelectMany(gc => gc.FilterInvitesChannelIds.Select(fci => fci.ChannelId)));
var dict = gcs.ToDictionary(gc => gc.GuildId, gc => new ConcurrentHashSet<string>(gc.FilteredWords.Select(fw => fw.Word))); var dict = bot.AllGuildConfigs.ToDictionary(gc => gc.GuildId, gc => new ConcurrentHashSet<string>(gc.FilteredWords.Select(fw => fw.Word)));
ServerFilteredWords = new ConcurrentDictionary<ulong, ConcurrentHashSet<string>>(dict); ServerFilteredWords = new ConcurrentDictionary<ulong, ConcurrentHashSet<string>>(dict);
var serverFiltering = gcs.Where(gc => gc.FilterWords); var serverFiltering = bot.AllGuildConfigs.Where(gc => gc.FilterWords);
WordFilteringServers = new ConcurrentHashSet<ulong>(serverFiltering.Select(gc => gc.GuildId)); WordFilteringServers = new ConcurrentHashSet<ulong>(serverFiltering.Select(gc => gc.GuildId));
WordFilteringChannels = new ConcurrentHashSet<ulong>(gcs.SelectMany(gc => gc.FilterWordsChannelIds.Select(fwci => fwci.ChannelId))); WordFilteringChannels = new ConcurrentHashSet<ulong>(bot.AllGuildConfigs.SelectMany(gc => gc.FilterWordsChannelIds.Select(fwci => fwci.ChannelId)));
_client.MessageUpdated += (oldData, newMsg, channel) => _client.MessageUpdated += (oldData, newMsg, channel) =>
{ {

View File

@ -51,7 +51,9 @@ namespace NadekoBot.Services
public ConcurrentHashSet<ulong> UsersOnShortCooldown { get; } = new ConcurrentHashSet<ulong>(); public ConcurrentHashSet<ulong> UsersOnShortCooldown { get; } = new ConcurrentHashSet<ulong>();
private readonly Timer _clearUsersOnShortCooldown; private readonly Timer _clearUsersOnShortCooldown;
public CommandHandler(DiscordSocketClient client, DbService db, IBotConfigProvider bc, IEnumerable<GuildConfig> gcs, CommandService commandService, IBotCredentials credentials, NadekoBot bot) public CommandHandler(DiscordSocketClient client, DbService db,
IBotConfigProvider bc, CommandService commandService,
IBotCredentials credentials, NadekoBot bot)
{ {
_client = client; _client = client;
_commandService = commandService; _commandService = commandService;
@ -67,7 +69,7 @@ namespace NadekoBot.Services
}, null, GlobalCommandsCooldown, GlobalCommandsCooldown); }, null, GlobalCommandsCooldown, GlobalCommandsCooldown);
DefaultPrefix = bc.BotConfig.DefaultPrefix; DefaultPrefix = bc.BotConfig.DefaultPrefix;
_prefixes = gcs _prefixes = bot.AllGuildConfigs
.Where(x => x.Prefix != null) .Where(x => x.Prefix != null)
.ToDictionary(x => x.GuildId, x => x.Prefix) .ToDictionary(x => x.GuildId, x => x.Prefix)
.ToConcurrent(); .ToConcurrent();

View File

@ -29,8 +29,6 @@ namespace NadekoBot.Services.Database
public DbSet<Quote> Quotes { get; set; } public DbSet<Quote> Quotes { get; set; }
public DbSet<Donator> Donators { get; set; } public DbSet<Donator> Donators { get; set; }
public DbSet<GuildConfig> GuildConfigs { get; set; } public DbSet<GuildConfig> GuildConfigs { get; set; }
public DbSet<ClashWar> ClashOfClans { get; set; }
public DbSet<ClashCaller> ClashCallers { get; set; }
public DbSet<Reminder> Reminders { get; set; } public DbSet<Reminder> Reminders { get; set; }
public DbSet<SelfAssignedRole> SelfAssignableRoles { get; set; } public DbSet<SelfAssignedRole> SelfAssignableRoles { get; set; }
public DbSet<BotConfig> BotConfig { get; set; } public DbSet<BotConfig> BotConfig { get; set; }

View File

@ -21,13 +21,15 @@ namespace NadekoBot.Services
private readonly DiscordSocketClient _client; private readonly DiscordSocketClient _client;
private readonly Logger _log; private readonly Logger _log;
public GreetSettingsService(DiscordSocketClient client, IEnumerable<GuildConfig> guildConfigs, DbService db) public GreetSettingsService(DiscordSocketClient client, NadekoBot bot, DbService db)
{ {
_db = db; _db = db;
_client = client; _client = client;
_log = LogManager.GetCurrentClassLogger(); _log = LogManager.GetCurrentClassLogger();
GuildConfigsCache = new ConcurrentDictionary<ulong, GreetSettings>(guildConfigs.ToDictionary(g => g.GuildId, GreetSettings.Create)); GuildConfigsCache = new ConcurrentDictionary<ulong, GreetSettings>(
bot.AllGuildConfigs
.ToDictionary(g => g.GuildId, GreetSettings.Create));
_client.UserJoined += UserJoined; _client.UserJoined += UserJoined;
_client.UserLeft += UserLeft; _client.UserLeft += UserLeft;
@ -180,10 +182,8 @@ namespace NadekoBot.Services
public GreetSettings GetOrAddSettingsForGuild(ulong guildId) public GreetSettings GetOrAddSettingsForGuild(ulong guildId)
{ {
GreetSettings settings; if(GuildConfigsCache.TryGetValue(guildId, out var settings) &&
GuildConfigsCache.TryGetValue(guildId, out settings); settings != null)
if (settings != null)
return settings; return settings;
using (var uow = _db.UnitOfWork) using (var uow = _db.UnitOfWork)

View File

@ -28,11 +28,11 @@ namespace NadekoBot.Services.Impl
} }
private Localization() { } private Localization() { }
public Localization(IBotConfigProvider bcp, IEnumerable<GuildConfig> gcs, DbService db) public Localization(IBotConfigProvider bcp, NadekoBot bot, DbService db)
{ {
_log = LogManager.GetCurrentClassLogger(); _log = LogManager.GetCurrentClassLogger();
var cultureInfoNames = gcs.ToDictionary(x => x.GuildId, x => x.Locale); var cultureInfoNames = bot.AllGuildConfigs.ToDictionary(x => x.GuildId, x => x.Locale);
var defaultCulture = bcp.BotConfig.Locale; var defaultCulture = bcp.BotConfig.Locale;
_db = db; _db = db;
@ -123,8 +123,7 @@ namespace NadekoBot.Services.Impl
{ {
if (guildId == null) if (guildId == null)
return DefaultCultureInfo; return DefaultCultureInfo;
CultureInfo info = null; GuildCultureInfos.TryGetValue(guildId.Value, out CultureInfo info);
GuildCultureInfos.TryGetValue(guildId.Value, out info);
return info ?? DefaultCultureInfo; return info ?? DefaultCultureInfo;
} }

View File

@ -42,7 +42,6 @@ namespace NadekoBot.Services.Impl
private readonly Timer _carbonitexTimer; private readonly Timer _carbonitexTimer;
private readonly Timer _dataTimer; private readonly Timer _dataTimer;
private readonly ShardsCoordinator _sc;
private readonly ConnectionMultiplexer _redis; private readonly ConnectionMultiplexer _redis;
public StatsService(DiscordSocketClient client, CommandHandler cmdHandler, public StatsService(DiscordSocketClient client, CommandHandler cmdHandler,
@ -51,7 +50,6 @@ namespace NadekoBot.Services.Impl
{ {
_client = client; _client = client;
_creds = creds; _creds = creds;
_sc = nadeko.ShardCoord;
_redis = cache.Redis; _redis = cache.Redis;
_started = DateTime.UtcNow; _started = DateTime.UtcNow;
@ -134,7 +132,7 @@ namespace NadekoBot.Services.Impl
return Task.CompletedTask; return Task.CompletedTask;
}; };
if (_sc != null) if (_client.ShardId == 0)
{ {
_carbonitexTimer = new Timer(async (state) => _carbonitexTimer = new Timer(async (state) =>
{ {

View File

@ -48,8 +48,6 @@ namespace NadekoBot
public INServiceProvider Services { get; private set; } public INServiceProvider Services { get; private set; }
public ShardsCoordinator ShardCoord { get; private set; }
private readonly BotConfig _botConfig; private readonly BotConfig _botConfig;
public IDataCache Cache { get; private set; } public IDataCache Cache { get; private set; }
@ -143,9 +141,6 @@ namespace NadekoBot
.AddManual(Client) .AddManual(Client)
.AddManual(CommandService) .AddManual(CommandService)
.AddManual(botConfigProvider) .AddManual(botConfigProvider)
//todo this needs to reload whenever a new service is supposed to be loaded
//except at startup for obvious reasons
.AddManual<IEnumerable<GuildConfig>>(AllGuildConfigs) //todo wrap this
.AddManual<NadekoBot>(this) .AddManual<NadekoBot>(this)
.AddManual<IUnitOfWork>(uow) .AddManual<IUnitOfWork>(uow)
.AddManual<IDataCache>(Cache); .AddManual<IDataCache>(Cache);
@ -255,9 +250,6 @@ namespace NadekoBot
public async Task RunAsync(params string[] args) public async Task RunAsync(params string[] args)
{ {
if (Client.ShardId == 0)
_log.Info("Starting NadekoBot v" + StatsService.BotVersion);
var sw = Stopwatch.StartNew(); var sw = Stopwatch.StartNew();
await LoginAsync(Credentials.Token).ConfigureAwait(false); await LoginAsync(Credentials.Token).ConfigureAwait(false);
@ -450,7 +442,12 @@ namespace NadekoBot
{ {
if (_packageModules.ContainsKey(name)) if (_packageModules.ContainsKey(name))
return false; return false;
var startingGuildIdList = Client.Guilds.Select(x => (long)x.Id).ToList();
using (var uow = _db.UnitOfWork)
{
AllGuildConfigs = uow.GuildConfigs.GetAllGuildConfigs(startingGuildIdList).ToImmutableArray();
}
var package = Assembly.LoadFile(Path.Combine(AppContext.BaseDirectory, var package = Assembly.LoadFile(Path.Combine(AppContext.BaseDirectory,
"modules", "modules",
$"NadekoBot.Modules.{name}", $"NadekoBot.Modules.{name}",

View File

@ -54,6 +54,16 @@ namespace NadekoBot.Services
return this; return this;
} }
public INServiceProvider UpdateManual<T>(T obj)
{
lock (_locker)
{
_services.Remove(typeof(T));
_services.TryAdd(typeof(T), obj);
}
return this;
}
public IEnumerable<Type> LoadFrom(Assembly assembly) public IEnumerable<Type> LoadFrom(Assembly assembly)
{ {
List<Type> addedTypes = new List<Type>(); List<Type> addedTypes = new List<Type>();

View File

@ -27,7 +27,11 @@ namespace NadekoBot.Services
LogSetup.SetupLogger(); LogSetup.SetupLogger();
_log = LogManager.GetCurrentClassLogger(); _log = LogManager.GetCurrentClassLogger();
_creds = new BotCredentials(); _creds = new BotCredentials();
_log.Info("Starting NadekoBot v" + StatsService.BotVersion);
_key = _creds.RedisKey(); _key = _creds.RedisKey();
_redis = ConnectionMultiplexer.Connect("127.0.0.1");
//setup initial shard statuses //setup initial shard statuses
_defaultShardState = new ShardComMessage() _defaultShardState = new ShardComMessage()

View File

@ -0,0 +1,12 @@
using NadekoBot.Services;
using System;
using System.Collections.Concurrent;
namespace NadekoBot.Modules.Gambling.Services
{
public class WaifuService : INService
{
public ConcurrentDictionary<ulong, DateTime> DivorceCooldowns { get; } = new ConcurrentDictionary<ulong, DateTime>();
public ConcurrentDictionary<ulong, DateTime> AffinityCooldowns { get; } = new ConcurrentDictionary<ulong, DateTime>();
}
}

View File

@ -4,13 +4,17 @@ using NadekoBot.Extensions;
using NadekoBot.Services; using NadekoBot.Services;
using NadekoBot.Services.Database.Models; using NadekoBot.Services.Database.Models;
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using NadekoBot.Common; using NadekoBot.Common;
using NadekoBot.Common.Attributes; using NadekoBot.Common.Attributes;
using NadekoBot.Modules.Gambling.Services;
//todo add .deletewaifus
//todo add .deletecurrency
//todo add .deleteplaylists
//todo add .deletexp
namespace NadekoBot.Modules.Gambling namespace NadekoBot.Modules.Gambling
{ {
public partial class Gambling public partial class Gambling
@ -44,13 +48,10 @@ namespace NadekoBot.Modules.Gambling
Depraved, Depraved,
Harlot Harlot
} }
//todo unclaimed waifus should lose 3% of their value a day
[Group]
public class WaifuClaimCommands : NadekoSubmodule
{
private static ConcurrentDictionary<ulong, DateTime> _divorceCooldowns { get; } = new ConcurrentDictionary<ulong, DateTime>();
private static ConcurrentDictionary<ulong, DateTime> _affinityCooldowns { get; } = new ConcurrentDictionary<ulong, DateTime>();
[Group]
public class WaifuClaimCommands : NadekoSubmodule<WaifuService>
{
enum WaifuClaimResult enum WaifuClaimResult
{ {
Success, Success,
@ -219,7 +220,7 @@ namespace NadekoBot.Modules.Gambling
var now = DateTime.UtcNow; var now = DateTime.UtcNow;
if (w?.Claimer == null || w.Claimer.UserId != Context.User.Id) if (w?.Claimer == null || w.Claimer.UserId != Context.User.Id)
result = DivorceResult.NotYourWife; result = DivorceResult.NotYourWife;
else if (_divorceCooldowns.AddOrUpdate(Context.User.Id, else if (_service.DivorceCooldowns.AddOrUpdate(Context.User.Id,
now, now,
(key, old) => ((difference = now.Subtract(old)) > _divorceLimit) ? now : old) != now) (key, old) => ((difference = now.Subtract(old)) > _divorceLimit) ? now : old) != now)
{ {
@ -303,7 +304,7 @@ namespace NadekoBot.Modules.Gambling
if (w?.Affinity?.UserId == u?.Id) if (w?.Affinity?.UserId == u?.Id)
{ {
} }
else if (_affinityCooldowns.AddOrUpdate(Context.User.Id, else if (_service.AffinityCooldowns.AddOrUpdate(Context.User.Id,
now, now,
(key, old) => ((difference = now.Subtract(old)) > _affinityLimit) ? now : old) != now) (key, old) => ((difference = now.Subtract(old)) > _affinityLimit) ? now : old) != now)
{ {

View File

@ -28,8 +28,9 @@ namespace NadekoBot.Modules.Games.Services
public ConcurrentDictionary<ulong, Lazy<IChatterBotSession>> ChatterBotGuilds { get; } public ConcurrentDictionary<ulong, Lazy<IChatterBotSession>> ChatterBotGuilds { get; }
public ChatterBotService(DiscordSocketClient client, PermissionService perms, IEnumerable<GuildConfig> gcs, public ChatterBotService(DiscordSocketClient client, PermissionService perms,
CommandHandler cmd, NadekoStrings strings, IBotCredentials creds) NadekoBot bot, CommandHandler cmd, NadekoStrings strings,
IBotCredentials creds)
{ {
_client = client; _client = client;
_log = LogManager.GetCurrentClassLogger(); _log = LogManager.GetCurrentClassLogger();
@ -39,7 +40,8 @@ namespace NadekoBot.Modules.Games.Services
_creds = creds; _creds = creds;
ChatterBotGuilds = new ConcurrentDictionary<ulong, Lazy<IChatterBotSession>>( ChatterBotGuilds = new ConcurrentDictionary<ulong, Lazy<IChatterBotSession>>(
gcs.Where(gc => gc.CleverbotEnabled) bot.AllGuildConfigs
.Where(gc => gc.CleverbotEnabled)
.ToDictionary(gc => gc.GuildId, gc => new Lazy<IChatterBotSession>(() => CreateSession(), true))); .ToDictionary(gc => gc.GuildId, gc => new Lazy<IChatterBotSession>(() => CreateSession(), true)));
} }

View File

@ -55,7 +55,7 @@ namespace NadekoBot.Modules.Games.Services
public ConcurrentDictionary<ulong, TypingGame> RunningContests { get; } = new ConcurrentDictionary<ulong, TypingGame>(); public ConcurrentDictionary<ulong, TypingGame> RunningContests { get; } = new ConcurrentDictionary<ulong, TypingGame>();
public ConcurrentDictionary<ulong, Nunchi> NunchiGames { get; } = new ConcurrentDictionary<ulong, Common.Nunchi.Nunchi>(); public ConcurrentDictionary<ulong, Nunchi> NunchiGames { get; } = new ConcurrentDictionary<ulong, Common.Nunchi.Nunchi>();
public GamesService(CommandHandler cmd, IBotConfigProvider bc, IEnumerable<GuildConfig> gcs, public GamesService(CommandHandler cmd, IBotConfigProvider bc, NadekoBot bot,
NadekoStrings strings, IImagesService images, CommandHandler cmdHandler) NadekoStrings strings, IImagesService images, CommandHandler cmdHandler)
{ {
_bc = bc; _bc = bc;
@ -77,7 +77,8 @@ namespace NadekoBot.Modules.Games.Services
//plantpick //plantpick
_cmd.OnMessageNoTrigger += PotentialFlowerGeneration; _cmd.OnMessageNoTrigger += PotentialFlowerGeneration;
GenerationChannels = new ConcurrentHashSet<ulong>(gcs GenerationChannels = new ConcurrentHashSet<ulong>(bot
.AllGuildConfigs
.SelectMany(c => c.GenerateCurrencyChannelIds.Select(obj => obj.ChannelId))); .SelectMany(c => c.GenerateCurrencyChannelIds.Select(obj => obj.ChannelId)));
try try

View File

@ -36,7 +36,7 @@ namespace NadekoBot.Modules.Music.Services
public MusicService(DiscordSocketClient client, IGoogleApiService google, public MusicService(DiscordSocketClient client, IGoogleApiService google,
NadekoStrings strings, ILocalization localization, DbService db, NadekoStrings strings, ILocalization localization, DbService db,
SoundCloudApiService sc, IBotCredentials creds, IEnumerable<GuildConfig> gcs) SoundCloudApiService sc, IBotCredentials creds, NadekoBot bot)
{ {
_client = client; _client = client;
_google = google; _google = google;
@ -51,7 +51,9 @@ namespace NadekoBot.Modules.Music.Services
try { Directory.Delete(MusicDataPath, true); } catch { } try { Directory.Delete(MusicDataPath, true); } catch { }
_defaultVolumes = new ConcurrentDictionary<ulong, float>(gcs.ToDictionary(x => x.GuildId, x => x.DefaultMusicVolume)); _defaultVolumes = new ConcurrentDictionary<ulong, float>(
bot.AllGuildConfigs
.ToDictionary(x => x.GuildId, x => x.DefaultMusicVolume));
Directory.CreateDirectory(MusicDataPath); Directory.CreateDirectory(MusicDataPath);
} }

View File

@ -24,11 +24,13 @@ namespace NadekoBot.Modules.Searches.Services
private readonly ConcurrentDictionary<string, DateTime> _lastPosts = private readonly ConcurrentDictionary<string, DateTime> _lastPosts =
new ConcurrentDictionary<string, DateTime>(); new ConcurrentDictionary<string, DateTime>();
public FeedsService(IEnumerable<GuildConfig> gcs, DbService db, DiscordSocketClient client) public FeedsService(NadekoBot bot, DbService db, DiscordSocketClient client)
{ {
_db = db; _db = db;
_subs = gcs.SelectMany(x => x.FeedSubs) _subs = bot
.AllGuildConfigs
.SelectMany(x => x.FeedSubs)
.GroupBy(x => x.Url) .GroupBy(x => x.Url)
.ToDictionary(x => x.Key, x => x.ToHashSet()) .ToDictionary(x => x.Key, x => x.ToHashSet())
.ToConcurrent(); .ToConcurrent();
@ -54,8 +56,7 @@ namespace NadekoBot.Modules.Searches.Services
if (kvp.Value.Count == 0) if (kvp.Value.Count == 0)
continue; continue;
DateTime lastTime; if (!_lastPosts.TryGetValue(kvp.Key, out DateTime lastTime))
if (!_lastPosts.TryGetValue(kvp.Key, out lastTime))
lastTime = _lastPosts.AddOrUpdate(kvp.Key, DateTime.UtcNow, (k, old) => DateTime.UtcNow); lastTime = _lastPosts.AddOrUpdate(kvp.Key, DateTime.UtcNow, (k, old) => DateTime.UtcNow);
var rssUrl = kvp.Key; var rssUrl = kvp.Key;

View File

@ -49,7 +49,8 @@ namespace NadekoBot.Modules.Searches.Services
private readonly ConcurrentDictionary<ulong, HashSet<string>> _blacklistedTags = new ConcurrentDictionary<ulong, HashSet<string>>(); private readonly ConcurrentDictionary<ulong, HashSet<string>> _blacklistedTags = new ConcurrentDictionary<ulong, HashSet<string>>();
public SearchesService(DiscordSocketClient client, IGoogleApiService google, DbService db, IEnumerable<GuildConfig> gcs) public SearchesService(DiscordSocketClient client, IGoogleApiService google,
DbService db, NadekoBot bot)
{ {
Http = new HttpClient(); Http = new HttpClient();
Http.AddFakeHeaders(); Http.AddFakeHeaders();
@ -59,7 +60,7 @@ namespace NadekoBot.Modules.Searches.Services
_log = LogManager.GetCurrentClassLogger(); _log = LogManager.GetCurrentClassLogger();
_blacklistedTags = new ConcurrentDictionary<ulong, HashSet<string>>( _blacklistedTags = new ConcurrentDictionary<ulong, HashSet<string>>(
gcs.ToDictionary( bot.AllGuildConfigs.ToDictionary(
x => x.GuildId, x => x.GuildId,
x => new HashSet<string>(x.NsfwBlacklistedTags.Select(y => y.Tag)))); x => new HashSet<string>(x.NsfwBlacklistedTags.Select(y => y.Tag))));

View File

@ -26,21 +26,19 @@ namespace NadekoBot.Modules.Utility
_db = db; _db = db;
_currency = currency; _currency = currency;
} }
[NadekoCommand, Usage, Description, Aliases] [NadekoCommand, Usage, Description, Aliases]
[OwnerOnly]
[RequireContext(ContextType.DM)] [RequireContext(ContextType.DM)]
public async Task PatreonRewardsReload() public async Task PatreonRewardsReload()
{ {
if (string.IsNullOrWhiteSpace(_creds.PatreonAccessToken)) if (string.IsNullOrWhiteSpace(_creds.PatreonAccessToken))
return; return;
await _service.RefreshPledges(true).ConfigureAwait(false); await _service.RefreshPledges().ConfigureAwait(false);
await Context.Channel.SendConfirmAsync("👌").ConfigureAwait(false); await Context.Channel.SendConfirmAsync("👌").ConfigureAwait(false);
} }
[NadekoCommand, Usage, Description, Aliases] [NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.DM)]
public async Task ClaimPatreonRewards() public async Task ClaimPatreonRewards()
{ {
if (string.IsNullOrWhiteSpace(_creds.PatreonAccessToken)) if (string.IsNullOrWhiteSpace(_creds.PatreonAccessToken))

View File

@ -17,11 +17,11 @@ namespace NadekoBot.Modules.Utility.Services
public ConcurrentDictionary<ulong, ConcurrentDictionary<string, string>> AliasMaps { get; } = new ConcurrentDictionary<ulong, ConcurrentDictionary<string, string>>(); public ConcurrentDictionary<ulong, ConcurrentDictionary<string, string>> AliasMaps { get; } = new ConcurrentDictionary<ulong, ConcurrentDictionary<string, string>>();
//commandmap //commandmap
public CommandMapService(IEnumerable<GuildConfig> gcs) public CommandMapService(NadekoBot bot)
{ {
_log = LogManager.GetCurrentClassLogger(); _log = LogManager.GetCurrentClassLogger();
AliasMaps = new ConcurrentDictionary<ulong, ConcurrentDictionary<string, string>>( AliasMaps = new ConcurrentDictionary<ulong, ConcurrentDictionary<string, string>>(
gcs.ToDictionary( bot.AllGuildConfigs.ToDictionary(
x => x.GuildId, x => x.GuildId,
x => new ConcurrentDictionary<string, string>(x.CommandAliases x => new ConcurrentDictionary<string, string>(x.CommandAliases
.Distinct(new CommandAliasEqualityComparer()) .Distinct(new CommandAliasEqualityComparer())

View File

@ -13,6 +13,7 @@ using NLog;
namespace NadekoBot.Modules.Utility.Services namespace NadekoBot.Modules.Utility.Services
{ {
//todo rewrite
public class ConverterService : INService, IUnloadableService public class ConverterService : INService, IUnloadableService
{ {
public List<ConvertUnit> Units { get; } = new List<ConvertUnit>(); public List<ConvertUnit> Units { get; } = new List<ConvertUnit>();

View File

@ -16,24 +16,25 @@ namespace NadekoBot.Modules.Utility.Services
public ConcurrentDictionary<ulong, ConcurrentQueue<RepeatRunner>> Repeaters { get; set; } public ConcurrentDictionary<ulong, ConcurrentQueue<RepeatRunner>> Repeaters { get; set; }
public bool RepeaterReady { get; private set; } public bool RepeaterReady { get; private set; }
public MessageRepeaterService(NadekoBot bot, DiscordSocketClient client, IEnumerable<GuildConfig> gcs) public MessageRepeaterService(NadekoBot bot, DiscordSocketClient client)
{ {
var _ = Task.Run(async () => var _ = Task.Run(async () =>
{ {
await bot.Ready.Task.ConfigureAwait(false); await bot.Ready.Task.ConfigureAwait(false);
Repeaters = new ConcurrentDictionary<ulong, ConcurrentQueue<RepeatRunner>>(gcs Repeaters = new ConcurrentDictionary<ulong, ConcurrentQueue<RepeatRunner>>(
.Select(gc => bot.AllGuildConfigs
{ .Select(gc =>
var guild = client.GetGuild(gc.GuildId); {
if (guild == null) var guild = client.GetGuild(gc.GuildId);
return (0, null); if (guild == null)
return (gc.GuildId, new ConcurrentQueue<RepeatRunner>(gc.GuildRepeaters return (0, null);
.Select(gr => new RepeatRunner(client, guild, gr)) return (gc.GuildId, new ConcurrentQueue<RepeatRunner>(gc.GuildRepeaters
.Where(x => x.Guild != null))); .Select(gr => new RepeatRunner(client, guild, gr))
}) .Where(x => x.Guild != null)));
.Where(x => x.Item2 != null) })
.ToDictionary(x => x.GuildId, x => x.Item2)); .Where(x => x.Item2 != null)
.ToDictionary(x => x.GuildId, x => x.Item2));
RepeaterReady = true; RepeaterReady = true;
}); });
} }

View File

@ -1,7 +1,5 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq; using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Threading; using System.Threading;
@ -12,6 +10,8 @@ using NadekoBot.Services;
using NadekoBot.Services.Database.Models; using NadekoBot.Services.Database.Models;
using Newtonsoft.Json; using Newtonsoft.Json;
using NLog; using NLog;
using NadekoBot.Extensions;
using NadekoBot.Core.Common.Caching;
namespace NadekoBot.Modules.Utility.Services namespace NadekoBot.Modules.Utility.Services
{ {
@ -19,8 +19,8 @@ namespace NadekoBot.Modules.Utility.Services
{ {
private readonly SemaphoreSlim getPledgesLocker = new SemaphoreSlim(1, 1); private readonly SemaphoreSlim getPledgesLocker = new SemaphoreSlim(1, 1);
public ImmutableArray<PatreonUserAndReward> Pledges { get; private set; } private readonly FactoryCache<PatreonUserAndReward[]> _pledges;
public DateTime LastUpdate { get; private set; } = DateTime.UtcNow; public PatreonUserAndReward[] Pledges => _pledges.GetValue();
public readonly Timer Updater; public readonly Timer Updater;
private readonly SemaphoreSlim claimLockJustInCase = new SemaphoreSlim(1, 1); private readonly SemaphoreSlim claimLockJustInCase = new SemaphoreSlim(1, 1);
@ -30,79 +30,95 @@ namespace NadekoBot.Modules.Utility.Services
private readonly IBotCredentials _creds; private readonly IBotCredentials _creds;
private readonly DbService _db; private readonly DbService _db;
private readonly CurrencyService _currency; private readonly CurrencyService _currency;
private readonly IDataCache _cache;
private readonly string _key;
private readonly string cacheFileName = "./patreon-rewards.json"; public DateTime LastUpdate { get; private set; } = DateTime.UtcNow;
public PatreonRewardsService(IBotCredentials creds, DbService db, public PatreonRewardsService(IBotCredentials creds, DbService db,
CurrencyService currency, CurrencyService currency,
DiscordSocketClient client) DiscordSocketClient client, IDataCache cache)
{ {
_log = LogManager.GetCurrentClassLogger(); _log = LogManager.GetCurrentClassLogger();
_creds = creds; _creds = creds;
_db = db; _db = db;
_currency = currency; _currency = currency;
if (string.IsNullOrWhiteSpace(creds.PatreonAccessToken)) _cache = cache;
return; _key = _creds.RedisKey() + "_patreon_rewards";
Updater = new Timer(async (load) => await RefreshPledges((bool)load),
client.ShardId == 0, client.ShardId == 0 ? TimeSpan.Zero : TimeSpan.FromMinutes(2), Interval); _pledges = new FactoryCache<PatreonUserAndReward[]>(() =>
{
var r = _cache.Redis.GetDatabase();
var data = r.StringGet(_key);
if (data.IsNullOrEmpty)
return null;
else
{
_log.Info(data);
return JsonConvert.DeserializeObject<PatreonUserAndReward[]>(data);
}
}, TimeSpan.FromSeconds(20));
if(client.ShardId == 0)
Updater = new Timer(async _ => await RefreshPledges(),
null, TimeSpan.Zero, Interval);
} }
public async Task RefreshPledges(bool shouldLoad) public async Task RefreshPledges()
{ {
if (shouldLoad) if (string.IsNullOrWhiteSpace(_creds.PatreonAccessToken))
return;
LastUpdate = DateTime.UtcNow;
await getPledgesLocker.WaitAsync().ConfigureAwait(false);
try
{ {
LastUpdate = DateTime.UtcNow; var rewards = new List<PatreonPledge>();
await getPledgesLocker.WaitAsync().ConfigureAwait(false); var users = new List<PatreonUser>();
try using (var http = new HttpClient())
{ {
var rewards = new List<PatreonPledge>(); http.DefaultRequestHeaders.Clear();
var users = new List<PatreonUser>(); http.DefaultRequestHeaders.Add("Authorization", "Bearer " + _creds.PatreonAccessToken);
using (var http = new HttpClient()) var data = new PatreonData()
{ {
http.DefaultRequestHeaders.Clear(); Links = new PatreonDataLinks()
http.DefaultRequestHeaders.Add("Authorization", "Bearer " + _creds.PatreonAccessToken);
var data = new PatreonData()
{ {
Links = new PatreonDataLinks() next = $"https://api.patreon.com/oauth2/api/campaigns/{_creds.PatreonCampaignId}/pledges"
{ }
next = $"https://api.patreon.com/oauth2/api/campaigns/{_creds.PatreonCampaignId}/pledges" };
} do
};
do
{
var res = await http.GetStringAsync(data.Links.next)
.ConfigureAwait(false);
data = JsonConvert.DeserializeObject<PatreonData>(res);
var pledgers = data.Data.Where(x => x["type"].ToString() == "pledge");
rewards.AddRange(pledgers.Select(x => JsonConvert.DeserializeObject<PatreonPledge>(x.ToString()))
.Where(x => x.attributes.declined_since == null));
users.AddRange(data.Included
.Where(x => x["type"].ToString() == "user")
.Select(x => JsonConvert.DeserializeObject<PatreonUser>(x.ToString())));
} while (!string.IsNullOrWhiteSpace(data.Links.next));
}
Pledges = rewards.Join(users, (r) => r.relationships?.patron?.data?.id, (u) => u.id, (x, y) => new PatreonUserAndReward()
{ {
User = y, var res = await http.GetStringAsync(data.Links.next)
Reward = x, .ConfigureAwait(false);
}).ToImmutableArray(); data = JsonConvert.DeserializeObject<PatreonData>(res);
File.WriteAllText("./patreon_rewards.json", JsonConvert.SerializeObject(Pledges)); var pledgers = data.Data.Where(x => x["type"].ToString() == "pledge");
rewards.AddRange(pledgers.Select(x => JsonConvert.DeserializeObject<PatreonPledge>(x.ToString()))
.Where(x => x.attributes.declined_since == null));
users.AddRange(data.Included
.Where(x => x["type"].ToString() == "user")
.Select(x => JsonConvert.DeserializeObject<PatreonUser>(x.ToString())));
} while (!string.IsNullOrWhiteSpace(data.Links.next));
} }
catch (Exception ex) var db = _cache.Redis.GetDatabase();
var toSet = JsonConvert.SerializeObject(rewards.Join(users, (r) => r.relationships?.patron?.data?.id, (u) => u.id, (x, y) => new PatreonUserAndReward()
{ {
_log.Warn(ex); User = y,
} Reward = x,
finally }).ToArray());
{
getPledgesLocker.Release(); _log.Info(toSet);
}
db.StringSet(_key, toSet);
} }
else catch (Exception ex)
{ {
if(File.Exists(cacheFileName)) _log.Warn(ex);
Pledges = JsonConvert.DeserializeObject<PatreonUserAndReward[]>(File.ReadAllText("./patreon_rewards.json"))
.ToImmutableArray();
} }
finally
{
getPledgesLocker.Release();
}
} }
public async Task<int> ClaimReward(ulong userId) public async Task<int> ClaimReward(ulong userId)
@ -111,7 +127,7 @@ namespace NadekoBot.Modules.Utility.Services
var now = DateTime.UtcNow; var now = DateTime.UtcNow;
try try
{ {
var data = Pledges.FirstOrDefault(x => x.User.attributes?.social_connections?.discord?.user_id == userId.ToString()); var data = Pledges?.FirstOrDefault(x => x.User.attributes?.social_connections?.discord?.user_id == userId.ToString());
if (data == null) if (data == null)
return 0; return 0;
@ -175,7 +191,7 @@ namespace NadekoBot.Modules.Utility.Services
public Task Unload() public Task Unload()
{ {
Updater.Change(Timeout.Infinite, Timeout.Infinite); Updater?.Change(Timeout.Infinite, Timeout.Infinite);
return Task.CompletedTask; return Task.CompletedTask;
} }
} }

View File

@ -24,13 +24,14 @@ namespace NadekoBot.Modules.Utility.Services
private readonly ConcurrentDictionary<ulong, StreamRoleSettings> guildSettings; private readonly ConcurrentDictionary<ulong, StreamRoleSettings> guildSettings;
private readonly Logger _log; private readonly Logger _log;
public StreamRoleService(DiscordSocketClient client, DbService db, IEnumerable<GuildConfig> gcs) public StreamRoleService(DiscordSocketClient client, DbService db, NadekoBot bot)
{ {
this._log = LogManager.GetCurrentClassLogger(); this._log = LogManager.GetCurrentClassLogger();
this._db = db; this._db = db;
this._client = client; this._client = client;
guildSettings = gcs.ToDictionary(x => x.GuildId, x => x.StreamRole) guildSettings = bot.AllGuildConfigs
.ToDictionary(x => x.GuildId, x => x.StreamRole)
.Where(x => x.Value != null && x.Value.Enabled) .Where(x => x.Value != null && x.Value.Enabled)
.ToConcurrent(); .ToConcurrent();

View File

@ -18,7 +18,7 @@ namespace NadekoBot.Modules.Utility.Services
private readonly CommandHandler _ch; private readonly CommandHandler _ch;
private readonly HelpService _hs; private readonly HelpService _hs;
public VerboseErrorsService(IEnumerable<GuildConfig> gcs, DbService db, CommandHandler ch, HelpService hs) public VerboseErrorsService(NadekoBot bot, DbService db, CommandHandler ch, HelpService hs)
{ {
_db = db; _db = db;
_ch = ch; _ch = ch;
@ -26,7 +26,10 @@ namespace NadekoBot.Modules.Utility.Services
_ch.CommandErrored += LogVerboseError; _ch.CommandErrored += LogVerboseError;
guildsEnabled = new ConcurrentHashSet<ulong>(gcs.Where(x => x.VerboseErrors).Select(x => x.GuildId)); guildsEnabled = new ConcurrentHashSet<ulong>(bot
.AllGuildConfigs
.Where(x => x.VerboseErrors)
.Select(x => x.GuildId));
} }
public Task Unload() public Task Unload()

View File

@ -68,7 +68,7 @@ namespace NadekoBot.Modules.Xp.Services
private Font _timeFont; private Font _timeFont;
public XpService(CommandHandler cmd, IBotConfigProvider bc, public XpService(CommandHandler cmd, IBotConfigProvider bc,
IEnumerable<GuildConfig> allGuildConfigs, IImagesService images, NadekoBot bot, IImagesService images,
DbService db, NadekoStrings strings, IDataCache cache) DbService db, NadekoStrings strings, IDataCache cache)
{ {
_db = db; _db = db;
@ -80,7 +80,7 @@ namespace NadekoBot.Modules.Xp.Services
_cache = cache; _cache = cache;
//load settings //load settings
allGuildConfigs = allGuildConfigs.Where(x => x.XpSettings != null); var allGuildConfigs = bot.AllGuildConfigs.Where(x => x.XpSettings != null);
_excludedChannels = allGuildConfigs _excludedChannels = allGuildConfigs
.ToDictionary( .ToDictionary(
x => x.GuildId, x => x.GuildId,
@ -685,7 +685,6 @@ namespace NadekoBot.Modules.Xp.Services
} }
//club image //club image
if (!string.IsNullOrWhiteSpace(stats.User.Club?.ImageUrl)) if (!string.IsNullOrWhiteSpace(stats.User.Club?.ImageUrl))
{ {
var imgUrl = stats.User.Club.ImageUrl; var imgUrl = stats.User.Club.ImageUrl;
@ -694,6 +693,7 @@ namespace NadekoBot.Modules.Xp.Services
var (succ, data) = await _cache.TryGetImageDataAsync(imgUrl); var (succ, data) = await _cache.TryGetImageDataAsync(imgUrl);
if (!succ) if (!succ)
{ {
//todo make sure it's a picture
using (var temp = await http.GetStreamAsync(imgUrl)) using (var temp = await http.GetStreamAsync(imgUrl))
using (var tempDraw = Image.Load(temp).Resize(45, 45)) using (var tempDraw = Image.Load(temp).Resize(45, 45))
{ {

View File

@ -1836,7 +1836,7 @@
}, },
"antispam": { "antispam": {
"Cmd": "antispam", "Cmd": "antispam",
"Desc": "Stops people from repeating same message X times in a row. You can specify to either mute, kick or ban the offenders. Max message count is 10.", "Desc": "Stops people from repeating same message X times in a row. You can specify to either mute, kick or ban the offenders. If you're using mute, you can add a number of seconds at the end to use a timed mute. Max message count is 10.",
"Usage": [ "Usage": [
"{0}antispam 3 Mute", "{0}antispam 3 Mute",
"{0}antispam 4 Kick", "{0}antispam 4 Kick",