private void Migrate2() { // load new images var urls = JsonConvert.DeserializeObject <ImageUrls>( File.ReadAllText(Path.Combine(_basePath, "images.json"))); if (urls.Version >= 2) { return; } _log.Info("Migrating images v1 to images v2."); urls.Version = 2; var prefix = $"{_creds.RedisKey()}_localimg_"; _db.KeyDelete(new[] { prefix + "heads", prefix + "tails", prefix + "dice", prefix + "slot_background", prefix + "slotnumbers", prefix + "slotemojis", prefix + "wife_matrix", prefix + "rategirl_dot", prefix + "xp_card", prefix + "rip", prefix + "rip_overlay" } .Select(x => (RedisKey)x).ToArray()); File.WriteAllText(Path.Combine(_basePath, "images.json"), JsonConvert.SerializeObject(urls, Formatting.Indented)); }
public async Task <bool> AllKeysExist() { try { var prefix = $"{_creds.RedisKey()}_localimg_"; var results = await Task.WhenAll(_db.KeyExistsAsync(prefix + "heads"), _db.KeyExistsAsync(prefix + "tails"), _db.KeyExistsAsync(prefix + "dice"), _db.KeyExistsAsync(prefix + "slot_background"), _db.KeyExistsAsync(prefix + "slotnumbers"), _db.KeyExistsAsync(prefix + "slotemojis"), _db.KeyExistsAsync(prefix + "wife_matrix"), _db.KeyExistsAsync(prefix + "rategirl_dot"), _db.KeyExistsAsync(prefix + "xp_card"), _db.KeyExistsAsync(prefix + "rip"), _db.KeyExistsAsync(prefix + "rip_overlay")); return(results.All(x => x)); } catch (Exception ex) { _log.Warn(ex); return(false); } }
public SelfService(DiscordSocketClient client, NadekoBot bot, CommandHandler cmdHandler, DbService db, IBotConfigProvider bc, ILocalization localization, NadekoStrings strings, IBotCredentials creds, IDataCache cache) { _redis = cache.Redis; _bot = bot; _cmdHandler = cmdHandler; _db = db; _log = LogManager.GetCurrentClassLogger(); _localization = localization; _strings = strings; _client = client; _creds = creds; _bc = bc; _cache = cache; _imgs = cache.LocalImages; var sub = _redis.GetSubscriber(); sub.Subscribe(_creds.RedisKey() + "_reload_images", delegate { _imgs.Reload(); }, CommandFlags.FireAndForget); sub.Subscribe(_creds.RedisKey() + "_reload_bot_config", delegate { _bc.Reload(); }, CommandFlags.FireAndForget); Task.Run(async() => { await bot.Ready.Task.ConfigureAwait(false); _autoCommands = bc.BotConfig .StartupCommands .Where(x => x.Interval >= 5) .GroupBy(x => x.GuildId) .ToDictionary( x => x.Key, y => y.ToDictionary(x => x.Id, x => TimerFromStartupCommand((StartupCommand)x)) .ToConcurrent()) .ToConcurrent(); foreach (var cmd in bc.BotConfig.StartupCommands.Where(x => x.Interval <= 0)) { try { await ExecuteCommand(cmd); } catch { } } }); Task.Run(async() => { await bot.Ready.Task.ConfigureAwait(false); await Task.Delay(5000).ConfigureAwait(false); if (client.ShardId == 0) { await LoadOwnerChannels().ConfigureAwait(false); } }); }
public SelfService(DiscordSocketClient client, CommandHandler cmdHandler, DbService db, IBotStrings strings, IBotCredentials creds, IDataCache cache, IHttpClientFactory factory, BotConfigService bss) { _redis = cache.Redis; _cmdHandler = cmdHandler; _db = db; _strings = strings; _client = client; _creds = creds; _cache = cache; _imgs = cache.LocalImages; _httpFactory = factory; _bss = bss; var sub = _redis.GetSubscriber(); if (_client.ShardId == 0) { sub.Subscribe(_creds.RedisKey() + "_reload_images", delegate { _imgs.Reload(); }, CommandFlags.FireAndForget); } sub.Subscribe(_creds.RedisKey() + "_leave_guild", async(ch, v) => { try { var guildStr = v.ToString()?.Trim().ToUpperInvariant(); if (string.IsNullOrWhiteSpace(guildStr)) { return; } var server = _client.Guilds.FirstOrDefault(g => g.Id.ToString() == guildStr) ?? _client.Guilds.FirstOrDefault(g => g.Name.Trim().ToUpperInvariant() == guildStr); if (server == null) { return; } if (server.OwnerId != _client.CurrentUser.Id) { await server.LeaveAsync().ConfigureAwait(false); Log.Information($"Left server {server.Name} [{server.Id}]"); } else { await server.DeleteAsync().ConfigureAwait(false); Log.Information($"Deleted server {server.Name} [{server.Id}]"); } } catch { } }, CommandFlags.FireAndForget); }
public SelfService(DiscordSocketClient client, NadekoBot bot, CommandHandler cmdHandler, DbService db, IBotConfigProvider bc, ILocalization localization, NadekoStrings strings, IBotCredentials creds, IDataCache cache) { _redis = cache.Redis; _bot = bot; _cmdHandler = cmdHandler; _db = db; _log = LogManager.GetCurrentClassLogger(); _localization = localization; _strings = strings; _client = client; _creds = creds; _bc = bc; _cache = cache; _imgs = cache.LocalImages; var sub = _redis.GetSubscriber(); sub.Subscribe(_creds.RedisKey() + "_reload_images", delegate { _imgs.Reload(); }, CommandFlags.FireAndForget); sub.Subscribe(_creds.RedisKey() + "_reload_bot_config", delegate { _bc.Reload(); }, CommandFlags.FireAndForget); Task.Run(async() => { await bot.Ready.Task.ConfigureAwait(false); foreach (var cmd in bc.BotConfig.StartupCommands) { var prefix = _cmdHandler.GetPrefix(cmd.GuildId); //if someone already has .die as their startup command, ignore it if (cmd.CommandText.StartsWith(prefix + "die")) { continue; } await cmdHandler.ExecuteExternal(cmd.GuildId, cmd.ChannelId, cmd.CommandText); await Task.Delay(400).ConfigureAwait(false); } }); Task.Run(async() => { await bot.Ready.Task.ConfigureAwait(false); await Task.Delay(5000).ConfigureAwait(false); if (client.ShardId == 0) { await LoadOwnerChannels().ConfigureAwait(false); } }); }
public PatreonRewardsService(IBotCredentials creds, DbService db, CurrencyService currency, DiscordSocketClient client, IDataCache cache) { _log = LogManager.GetCurrentClassLogger(); _creds = creds; _db = db; _currency = currency; _cache = cache; _key = _creds.RedisKey() + "_patreon_rewards"; _pledges = new FactoryCache <PatreonUserAndReward[]>(() => { var r = _cache.Redis.GetDatabase(); var data = r.StringGet(_key); if (data.IsNullOrEmpty) { return(null); } else { return(JsonConvert.DeserializeObject <PatreonUserAndReward[]>(data)); } }, TimeSpan.FromSeconds(20)); if (client.ShardId == 0) { Updater = new Timer(async _ => await RefreshPledges(), null, TimeSpan.Zero, Interval); } }
public RedisCache(IBotCredentials creds) { Redis = ConnectionMultiplexer.Connect("127.0.0.1"); Redis.PreserveAsyncOrder = false; _db = Redis.GetDatabase(); _redisKey = creds.RedisKey(); }
public RedisCache(IBotCredentials creds) { _log = LogManager.GetCurrentClassLogger(); Redis = ConnectionMultiplexer.Connect("127.0.0.1"); Redis.PreserveAsyncOrder = false; LocalImages = new RedisImagesCache(Redis, creds); LocalData = new RedisLocalDataCache(Redis, creds); _redisKey = creds.RedisKey(); }
public RedisCache(IBotCredentials creds) { Redis = ConnectionMultiplexer.Connect("127.0.0.1"); Redis.PreserveAsyncOrder = false; LocalImages = new RedisImagesCache(Redis, creds); LocalData = new RedisLocalDataCache(Redis, creds); _db = Redis.GetDatabase(); _redisKey = creds.RedisKey(); }
public async Task ShardStats(int page = 1) { if (--page < 0) { return; } var db = _cache.Redis.GetDatabase(); var statuses = db.ListRange(_creds.RedisKey() + "_shardstats") .Select(x => JsonConvert.DeserializeObject <ShardComMessage>(x)); var status = string.Join(", ", statuses .GroupBy(x => x.ConnectionState) .Select(x => $"{x.Count()} {x.Key}") .ToArray()); var allShardStrings = statuses .Select(x => { var timeDiff = DateTime.UtcNow - x.Time; if (timeDiff > TimeSpan.FromSeconds(20)) { return($"Shard #{Format.Bold(x.ShardId.ToString())} **UNRESPONSIVE** for {timeDiff.ToString(@"hh\:mm\:ss")}"); } return(GetText("shard_stats_txt", x.ShardId.ToString(), Format.Bold(x.ConnectionState.ToString()), Format.Bold(x.Guilds.ToString()), timeDiff.ToString(@"hh\:mm\:ss"))); }) .ToArray(); await Context.Channel.SendPaginatedConfirmAsync(_client, page, (curPage) => { var str = string.Join("\n", allShardStrings.Skip(25 * curPage).Take(25)); if (string.IsNullOrWhiteSpace(str)) { str = GetText("no_shards_on_page"); } return(new EmbedBuilder() .WithAuthor(a => a.WithName(GetText("shard_stats"))) .WithTitle(status) .WithOkColor() .WithDescription(str)); }, allShardStrings.Length, 25); }
private bool SetUserRewarded(ulong userId) { var r = _cache.Redis.GetDatabase(); var key = $"{_creds.RedisKey()}_user_xp_gain_{userId}"; return(r.StringSet(key, true, TimeSpan.FromMinutes(_bc.BotConfig.XpMinutesTimeout), StackExchange.Redis.When.NotExists)); }
public RedisCache(IBotCredentials creds, int shardId) { var conf = ConfigurationOptions.Parse(creds.RedisOptions); Redis = ConnectionMultiplexer.Connect(conf); _redisEndpoint = Redis.GetEndPoints().First(); Redis.PreserveAsyncOrder = false; LocalImages = new RedisImagesCache(Redis, creds); LocalData = new RedisLocalDataCache(Redis, creds, shardId); _redisKey = creds.RedisKey(); }
public RedisCache(IBotCredentials creds, int shardId) { _log = LogManager.GetCurrentClassLogger(); var conf = ConfigurationOptions.Parse("127.0.0.1"); conf.SyncTimeout = 3000; Redis = ConnectionMultiplexer.Connect(conf); Redis.PreserveAsyncOrder = false; LocalImages = new RedisImagesCache(Redis, creds); LocalData = new RedisLocalDataCache(Redis, creds, shardId); _redisKey = creds.RedisKey(); }
public void ReloadBotConfig() { var sub = _cache.Redis.GetSubscriber(); sub.Publish(_creds.RedisKey() + "_reload_bot_config", "", CommandFlags.FireAndForget); }
public RedisCache(IBotCredentials creds, int shardId) { _log = LogManager.GetCurrentClassLogger(); ConfigurationOptions conf; if (!string.IsNullOrWhiteSpace(creds.RedisOptions)) { conf = ConfigurationOptions.Parse(creds.RedisOptions); } else { conf = ConfigurationOptions.Parse("127.0.0.1,syncTimeout=3000"); } Redis = ConnectionMultiplexer.Connect(conf); Redis.PreserveAsyncOrder = false; LocalImages = new RedisImagesCache(Redis, creds); LocalData = new RedisLocalDataCache(Redis, creds, shardId); _redisKey = creds.RedisKey(); }
private T Get <T>(string key) where T : class { return(JsonConvert.DeserializeObject <T>(_db.StringGet($"{_creds.RedisKey()}_localdata_{key}"))); }
public XpService(DiscordSocketClient client, CommandHandler cmd, IBotConfigProvider bc, NadekoBot bot, DbService db, NadekoStrings strings, IDataCache cache, FontProvider fonts, IBotCredentials creds, ICurrencyService cs, IHttpClientFactory http) { _db = db; _cmd = cmd; _bc = bc; _images = cache.LocalImages; _log = LogManager.GetCurrentClassLogger(); _strings = strings; _cache = cache; _fonts = fonts; _creds = creds; _cs = cs; _httpFactory = http; _client = client; InternalReloadXpTemplate(); if (client.ShardId == 0) { var sub = _cache.Redis.GetSubscriber(); sub.Subscribe(_creds.RedisKey() + "_reload_xp_template", (ch, val) => InternalReloadXpTemplate()); } //load settings var allGuildConfigs = bot.AllGuildConfigs .Where(x => x.XpSettings != null) .ToList(); _excludedChannels = allGuildConfigs .ToDictionary( x => x.GuildId, x => new ConcurrentHashSet <ulong>(x.XpSettings .ExclusionList .Where(ex => ex.ItemType == ExcludedItemType.Channel) .Select(ex => ex.ItemId) .Distinct())) .ToConcurrent(); _excludedRoles = allGuildConfigs .ToDictionary( x => x.GuildId, x => new ConcurrentHashSet <ulong>(x.XpSettings .ExclusionList .Where(ex => ex.ItemType == ExcludedItemType.Role) .Select(ex => ex.ItemId) .Distinct())) .ToConcurrent(); _excludedServers = new ConcurrentHashSet <ulong>( allGuildConfigs.Where(x => x.XpSettings.ServerExcluded) .Select(x => x.GuildId)); _cmd.OnMessageNoTrigger += _cmd_OnMessageNoTrigger; #if !GLOBAL_NADEKO _client.UserVoiceStateUpdated += _client_OnUserVoiceStateUpdated; // Scan guilds on startup. _client.GuildAvailable += _client_OnGuildAvailable; foreach (var guild in _client.Guilds) { _client_OnGuildAvailable(guild); } #endif updateXpTask = Task.Run(UpdateLoop); }
public SelfService(DiscordSocketClient client, NadekoBot bot, CommandHandler cmdHandler, DbService db, IBotConfigProvider bc, ILocalization localization, NadekoStrings strings, IBotCredentials creds, IDataCache cache) { _redis = cache.Redis; _bot = bot; _cmdHandler = cmdHandler; _db = db; _log = LogManager.GetCurrentClassLogger(); _localization = localization; _strings = strings; _client = client; _creds = creds; _bc = bc; _cache = cache; _imgs = cache.LocalImages; if (_client.ShardId == 0) { _updateTimer = new Timer(async _ => { try { var ch = ownerChannels?.Values.FirstOrDefault(); if (ch == null) // no owner channels { return; } var cfo = _bc.BotConfig.CheckForUpdates; if (cfo == UpdateCheckType.None) { return; } string data; if ((cfo == UpdateCheckType.Commit && (data = await GetNewCommit()) != null) || (cfo == UpdateCheckType.Release && (data = await GetNewRelease()) != null)) { await ch.SendConfirmAsync("New Bot Update", data).ConfigureAwait(false); } } catch (Exception ex) { _log.Warn(ex); } }, null, TimeSpan.FromHours(8), TimeSpan.FromHours(8)); } var sub = _redis.GetSubscriber(); sub.Subscribe(_creds.RedisKey() + "_reload_images", delegate { _imgs.Reload(); }, CommandFlags.FireAndForget); sub.Subscribe(_creds.RedisKey() + "_reload_bot_config", delegate { _bc.Reload(); }, CommandFlags.FireAndForget); Task.Run(async() => { await bot.Ready.Task.ConfigureAwait(false); _autoCommands = bc.BotConfig .StartupCommands .Where(x => x.Interval >= 5) .GroupBy(x => x.GuildId) .ToDictionary( x => x.Key, y => y.ToDictionary(x => x.Id, x => TimerFromStartupCommand((StartupCommand)x)) .ToConcurrent()) .ToConcurrent(); foreach (var cmd in bc.BotConfig.StartupCommands.Where(x => x.Interval <= 0)) { try { await ExecuteCommand(cmd); } catch { } } }); Task.Run(async() => { await bot.Ready.Task.ConfigureAwait(false); await Task.Delay(5000).ConfigureAwait(false); if (client.ShardId == 0) { await LoadOwnerChannels().ConfigureAwait(false); } }); }
private byte[] Get(string key) { return(_db.StringGet($"{_creds.RedisKey()}_localimg_{key}")); }
public string GetText(string localeName, string key) { var value = _redis.GetDatabase().HashGet($"{_creds.RedisKey()}:responses:{localeName}", key); return(value); }
public StreamNotificationService(DbService db, DiscordSocketClient client, IBotStrings strings, IDataCache cache, IBotCredentials creds, IHttpClientFactory httpFactory, NadekoBot bot) { _db = db; _client = client; _strings = strings; _multi = cache.Redis; _creds = creds; _streamTracker = new NotifChecker(httpFactory, cache.Redis, creds.RedisKey(), client.ShardId == 0); using (var uow = db.GetDbContext()) { var ids = client.GetGuildIds(); var guildConfigs = uow._context.Set <GuildConfig>() .AsQueryable() .Include(x => x.FollowedStreams) .Where(x => ids.Contains(x.GuildId)) .ToList(); _offlineNotificationServers = new ConcurrentHashSet <ulong>(guildConfigs .Where(gc => gc.NotifyStreamOffline) .Select(x => x.GuildId) .ToList()); var followedStreams = guildConfigs .SelectMany(x => x.FollowedStreams) .ToList(); _shardTrackedStreams = followedStreams .GroupBy(x => new { Type = x.Type, Name = x.Username.ToLower() }) .ToList() .ToDictionary( x => new StreamDataKey(x.Key.Type, x.Key.Name.ToLower()), x => x.GroupBy(y => y.GuildId) .ToDictionary(y => y.Key, y => y.AsEnumerable().ToHashSet())); // shard 0 will keep track of when there are no more guilds which track a stream if (client.ShardId == 0) { var allFollowedStreams = uow._context.Set <FollowedStream>() .AsQueryable() .ToList(); foreach (var fs in allFollowedStreams) { _streamTracker.CacheAddData(fs.CreateKey(), null, replace: false); } _trackCounter = allFollowedStreams .GroupBy(x => new { Type = x.Type, Name = x.Username.ToLower() }) .ToDictionary( x => new StreamDataKey(x.Key.Type, x.Key.Name), x => x.Select(fs => fs.GuildId).ToHashSet()); } } var sub = _multi.GetSubscriber(); sub.Subscribe($"{_creds.RedisKey()}_streams_offline", HandleStreamsOffline); sub.Subscribe($"{_creds.RedisKey()}_streams_online", HandleStreamsOnline); if (client.ShardId == 0) { // only shard 0 will run the tracker, // and then publish updates with redis to other shards _streamTracker.OnStreamsOffline += OnStreamsOffline; _streamTracker.OnStreamsOnline += OnStreamsOnline; _ = _streamTracker.RunAsync(); _notifCleanupTimer = new Timer(_ => { try { var errorLimit = TimeSpan.FromHours(12); var failingStreams = _streamTracker.GetFailingStreams(errorLimit, true) .ToList(); if (!failingStreams.Any()) { return; } var deleteGroups = failingStreams.GroupBy(x => x.Type) .ToDictionary(x => x.Key, x => x.Select(x => x.Name).ToList()); using (var uow = _db.GetDbContext()) { foreach (var kvp in deleteGroups) { Log.Information($"Deleting {kvp.Value.Count} {kvp.Key} streams because " + $"they've been erroring for more than {errorLimit}: {string.Join(", ", kvp.Value)}"); var toDelete = uow._context.Set <FollowedStream>() .AsQueryable() .Where(x => x.Type == kvp.Key && kvp.Value.Contains(x.Username)) .ToList(); uow._context.RemoveRange(toDelete); uow.SaveChanges(); foreach (var loginToDelete in kvp.Value) { _streamTracker.UntrackStreamByKey(new StreamDataKey(kvp.Key, loginToDelete)); } } } } catch (Exception ex) { Log.Error("Error cleaning up FollowedStreams"); Log.Error(ex.ToString()); } }, null, TimeSpan.FromMinutes(30), TimeSpan.FromMinutes(30)); sub.Subscribe($"{_creds.RedisKey()}_follow_stream", HandleFollowStream); sub.Subscribe($"{_creds.RedisKey()}_unfollow_stream", HandleUnfollowStream); } bot.JoinedGuild += ClientOnJoinedGuild; client.LeftGuild += ClientOnLeftGuild; }
public StreamNotificationService(DbService db, DiscordSocketClient client, NadekoStrings strings, IDataCache cache, IBotCredentials creds, IHttpClientFactory httpFactory, NadekoBot bot) { _db = db; _client = client; _strings = strings; _multi = cache.Redis; _creds = creds; _streamTracker = new NotifChecker(httpFactory, cache.Redis, creds.RedisKey(), client.ShardId == 0); using (var uow = db.GetDbContext()) { var ids = client.GetGuildIds(); var guildConfigs = uow._context.Set <GuildConfig>() .AsQueryable() .Include(x => x.FollowedStreams) .Where(x => ids.Contains(x.GuildId)) .ToList(); _offlineNotificationServers = new ConcurrentHashSet <ulong>(guildConfigs .Where(gc => gc.NotifyStreamOffline) .Select(x => x.GuildId) .ToList()); var followedStreams = guildConfigs .SelectMany(x => x.FollowedStreams) .ToList(); _shardTrackedStreams = followedStreams .GroupBy(x => new { Type = x.Type, Name = x.Username.ToLower() }) .ToList() .ToDictionary( x => new StreamDataKey(x.Key.Type, x.Key.Name.ToLower()), x => x.GroupBy(y => y.GuildId) .ToDictionary(y => y.Key, y => y.AsEnumerable().ToHashSet())); // shard 0 will keep track of when there are no more guilds which track a stream if (client.ShardId == 0) { var allFollowedStreams = uow._context.Set <FollowedStream>() .AsQueryable() .ToList(); foreach (var fs in allFollowedStreams) { _streamTracker.CacheAddData(fs.CreateKey(), null, replace: false); } _trackCounter = allFollowedStreams .GroupBy(x => new { Type = x.Type, Name = x.Username.ToLower() }) .ToDictionary( x => new StreamDataKey(x.Key.Type, x.Key.Name), x => x.Select(fs => fs.GuildId).ToHashSet()); } } var sub = _multi.GetSubscriber(); sub.Subscribe($"{_creds.RedisKey()}_streams_offline", HandleStreamsOffline); sub.Subscribe($"{_creds.RedisKey()}_streams_online", HandleStreamsOnline); if (client.ShardId == 0) { // only shard 0 will run the tracker, // and then publish updates with redis to other shards _streamTracker.OnStreamsOffline += OnStreamsOffline; _streamTracker.OnStreamsOnline += OnStreamsOnline; _ = _streamTracker.RunAsync(); sub.Subscribe($"{_creds.RedisKey()}_follow_stream", HandleFollowStream); sub.Subscribe($"{_creds.RedisKey()}_unfollow_stream", HandleUnfollowStream); } bot.JoinedGuild += ClientOnJoinedGuild; client.LeftGuild += ClientOnLeftGuild; }
//private readonly Timer _updateTimer; public SelfService(DiscordSocketClient client, NadekoBot bot, CommandHandler cmdHandler, DbService db, IBotConfigProvider bc, ILocalization localization, NadekoStrings strings, IBotCredentials creds, IDataCache cache, IHttpClientFactory factory) { _redis = cache.Redis; _bot = bot; _cmdHandler = cmdHandler; _db = db; _log = LogManager.GetCurrentClassLogger(); _localization = localization; _strings = strings; _client = client; _creds = creds; _bc = bc; _cache = cache; _imgs = cache.LocalImages; _httpFactory = factory; var sub = _redis.GetSubscriber(); if (_client.ShardId == 0) { sub.Subscribe(_creds.RedisKey() + "_reload_images", delegate { _imgs.Reload(); }, CommandFlags.FireAndForget); //_updateTimer = new Timer(async _ => //{ // try // { // var ch = ownerChannels?.Values.FirstOrDefault(); // if (ch == null) // no owner channels // return; // var cfo = _bc.BotConfig.CheckForUpdates; // if (cfo == UpdateCheckType.None) // return; // string data; // if ((cfo == UpdateCheckType.Commit && (data = await GetNewCommit().ConfigureAwait(false)) != null) // || (cfo == UpdateCheckType.Release && (data = await GetNewRelease().ConfigureAwait(false)) != null)) // { // await ch.SendConfirmAsync("New Bot Update", data).ConfigureAwait(false); // } // } // catch (Exception ex) // { // _log.Warn(ex); // } //}, null, TimeSpan.FromHours(8), TimeSpan.FromHours(8)); } sub.Subscribe(_creds.RedisKey() + "_reload_bot_config", delegate { _bc.Reload(); }, CommandFlags.FireAndForget); sub.Subscribe(_creds.RedisKey() + "_leave_guild", async(ch, v) => { try { var guildStr = v.ToString()?.Trim().ToUpperInvariant(); if (string.IsNullOrWhiteSpace(guildStr)) { return; } var server = _client.Guilds.FirstOrDefault(g => g.Id.ToString() == guildStr) ?? _client.Guilds.FirstOrDefault(g => g.Name.Trim().ToUpperInvariant() == guildStr); if (server == null) { return; } if (server.OwnerId != _client.CurrentUser.Id) { await server.LeaveAsync().ConfigureAwait(false); _log.Info($"Left server {server.Name} [{server.Id}]"); } else { await server.DeleteAsync().ConfigureAwait(false); _log.Info($"Deleted server {server.Name} [{server.Id}]"); } } catch { } }, CommandFlags.FireAndForget); Task.Run(async() => { await bot.Ready.Task.ConfigureAwait(false); _autoCommands = bc.BotConfig .StartupCommands .Where(x => x.Interval >= 5) .GroupBy(x => x.GuildId) .ToDictionary( x => x.Key, y => y.ToDictionary(x => x.Id, x => TimerFromStartupCommand((StartupCommand)x)) .ToConcurrent()) .ToConcurrent(); foreach (var cmd in bc.BotConfig.StartupCommands.Where(x => x.Interval <= 0)) { try { await ExecuteCommand(cmd).ConfigureAwait(false); } catch { } } }); Task.Run(async() => { await bot.Ready.Task.ConfigureAwait(false); await Task.Delay(5000).ConfigureAwait(false); if (client.ShardId == 0) { await LoadOwnerChannels().ConfigureAwait(false); } }); }
public void ReloadXpTemplate() { var sub = _cache.Redis.GetSubscriber(); sub.Publish(_creds.RedisKey() + "_reload_xp_template", ""); }
public XpService(DiscordSocketClient client, CommandHandler cmd, IBotConfigProvider bc, NadekoBot bot, DbService db, NadekoStrings strings, IDataCache cache, FontProvider fonts, IBotCredentials creds, ICurrencyService cs, IHttpClientFactory http) { _db = db; _cmd = cmd; _bc = bc; _images = cache.LocalImages; _log = LogManager.GetCurrentClassLogger(); _strings = strings; _cache = cache; _fonts = fonts; _creds = creds; _cs = cs; _httpFactory = http; InternalReloadXpTemplate(); if (client.ShardId == 0) { var sub = _cache.Redis.GetSubscriber(); sub.Subscribe(_creds.RedisKey() + "_reload_xp_template", (ch, val) => InternalReloadXpTemplate()); } //load settings var allGuildConfigs = bot.AllGuildConfigs.Where(x => x.XpSettings != null); _excludedChannels = allGuildConfigs .ToDictionary( x => x.GuildId, x => new ConcurrentHashSet <ulong>(x.XpSettings .ExclusionList .Where(ex => ex.ItemType == ExcludedItemType.Channel) .Select(ex => ex.ItemId) .Distinct())) .ToConcurrent(); _excludedRoles = allGuildConfigs .ToDictionary( x => x.GuildId, x => new ConcurrentHashSet <ulong>(x.XpSettings .ExclusionList .Where(ex => ex.ItemType == ExcludedItemType.Role) .Select(ex => ex.ItemId) .Distinct())) .ToConcurrent(); _excludedServers = new ConcurrentHashSet <ulong>( allGuildConfigs.Where(x => x.XpSettings.ServerExcluded) .Select(x => x.GuildId)); _cmd.OnMessageNoTrigger += _cmd_OnMessageNoTrigger; updateXpTask = Task.Run(async() => { while (true) { await Task.Delay(TimeSpan.FromSeconds(5)); try { var toNotify = new List <(IMessageChannel MessageChannel, IUser User, int Level, XpNotificationType NotifyType, NotifOf NotifOf)>(); var roleRewards = new Dictionary <ulong, List <XpRoleReward> >(); var curRewards = new Dictionary <ulong, List <XpCurrencyReward> >(); var toAddTo = new List <UserCacheItem>(); while (_addMessageXp.TryDequeue(out var usr)) { toAddTo.Add(usr); } var group = toAddTo.GroupBy(x => (GuildId: x.Guild.Id, x.User)); if (toAddTo.Count == 0) { continue; } using (var uow = _db.UnitOfWork) { foreach (var item in group) { var xp = item.Select(x => bc.BotConfig.XpPerMessage).Sum(); //1. Mass query discord users and userxpstats and get them from local dict //2. (better but much harder) Move everything to the database, and get old and new xp // amounts for every user (in order to give rewards) var usr = uow.Xp.GetOrCreateUser(item.Key.GuildId, item.Key.User.Id); var du = uow.DiscordUsers.GetOrCreate(item.Key.User); var globalXp = du.TotalXp; var oldGlobalLevelData = new LevelStats(globalXp); var newGlobalLevelData = new LevelStats(globalXp + xp); var oldGuildLevelData = new LevelStats(usr.Xp + usr.AwardedXp); usr.Xp += xp; du.TotalXp += xp; if (du.Club != null) { du.Club.Xp += xp; } var newGuildLevelData = new LevelStats(usr.Xp + usr.AwardedXp); if (oldGlobalLevelData.Level < newGlobalLevelData.Level) { du.LastLevelUp = DateTime.UtcNow; var first = item.First(); if (du.NotifyOnLevelUp != XpNotificationType.None) { toNotify.Add((first.Channel, first.User, newGlobalLevelData.Level, du.NotifyOnLevelUp, NotifOf.Global)); } } if (oldGuildLevelData.Level < newGuildLevelData.Level) { usr.LastLevelUp = DateTime.UtcNow; //send level up notification var first = item.First(); if (usr.NotifyOnLevelUp != XpNotificationType.None) { toNotify.Add((first.Channel, first.User, newGuildLevelData.Level, usr.NotifyOnLevelUp, NotifOf.Server)); } //give role if (!roleRewards.TryGetValue(usr.GuildId, out var rrews)) { rrews = uow.GuildConfigs.XpSettingsFor(usr.GuildId).RoleRewards.ToList(); roleRewards.Add(usr.GuildId, rrews); } if (!curRewards.TryGetValue(usr.GuildId, out var crews)) { crews = uow.GuildConfigs.XpSettingsFor(usr.GuildId).CurrencyRewards.ToList(); curRewards.Add(usr.GuildId, crews); } var rrew = rrews.FirstOrDefault(x => x.Level == newGuildLevelData.Level); if (rrew != null) { var role = first.User.Guild.GetRole(rrew.RoleId); if (role != null) { var __ = first.User.AddRoleAsync(role); } } //get currency reward for this level var crew = crews.FirstOrDefault(x => x.Level == newGuildLevelData.Level); if (crew != null) { //give the user the reward if it exists await _cs.AddAsync(item.Key.User.Id, "Level-up Reward", crew.Amount); } } } uow.Complete(); } await Task.WhenAll(toNotify.Select(async x => { if (x.NotifOf == NotifOf.Server) { if (x.NotifyType == XpNotificationType.Dm) { var chan = await x.User.GetOrCreateDMChannelAsync(); if (chan != null) { await chan.SendConfirmAsync(_strings.GetText("level_up_dm", (x.MessageChannel as ITextChannel)?.GuildId, "xp", x.User.Mention, Format.Bold(x.Level.ToString()), Format.Bold((x.MessageChannel as ITextChannel)?.Guild.ToString() ?? "-"))); } } else // channel { await x.MessageChannel.SendConfirmAsync(_strings.GetText("level_up_channel", (x.MessageChannel as ITextChannel)?.GuildId, "xp", x.User.Mention, Format.Bold(x.Level.ToString()))); } } else { IMessageChannel chan; if (x.NotifyType == XpNotificationType.Dm) { chan = await x.User.GetOrCreateDMChannelAsync(); } else // channel { chan = x.MessageChannel; } await chan.SendConfirmAsync(_strings.GetText("level_up_global", (x.MessageChannel as ITextChannel)?.GuildId, "xp", x.User.Mention, Format.Bold(x.Level.ToString()))); } })); } catch (Exception ex) { _log.Warn(ex); } } }); }
public Task LeaveGuild(string guildStr) { var sub = _cache.Redis.GetSubscriber(); return(sub.PublishAsync(_creds.RedisKey() + "_leave_guild", guildStr)); }