public ProtectionService(DiscordSocketClient client, NadekoBot bot, MuteService mute, DbService db, UserPunishService punishService) { _client = client; _mute = mute; _db = db; _punishService = punishService; var ids = client.GetGuildIds(); using (var uow = db.GetDbContext()) { var configs = uow._context.Set <GuildConfig>() .AsQueryable() .Include(x => x.AntiRaidSetting) .Include(x => x.AntiSpamSetting) .ThenInclude(x => x.IgnoredChannels) .Include(x => x.AntiAltSetting) .Where(x => ids.Contains(x.GuildId)) .ToList(); foreach (var gc in configs) { Initialize(gc); } } _client.MessageReceived += HandleAntiSpam; _client.UserJoined += HandleUserJoined; bot.JoinedGuild += _bot_JoinedGuild; _client.LeftGuild += _client_LeftGuild; _ = Task.Run(RunQueue); }
public FilterService(DiscordSocketClient client, NadekoBot bot, DbService db) { _log = LogManager.GetCurrentClassLogger(); _db = db; using (var uow = db.GetDbContext()) { var ids = client.GetGuildIds(); var configs = uow._context.Set <GuildConfig>() .AsQueryable() .Include(x => x.FilteredWords) .Include(x => x.FilterLinksChannelIds) .Include(x => x.FilterWordsChannelIds) .Include(x => x.FilterInvitesChannelIds) .Where(gc => ids.Contains(gc.GuildId)) .ToList(); InviteFilteringServers = new ConcurrentHashSet <ulong>(configs.Where(gc => gc.FilterInvites).Select(gc => gc.GuildId)); InviteFilteringChannels = new ConcurrentHashSet <ulong>(configs.SelectMany(gc => gc.FilterInvitesChannelIds.Select(fci => fci.ChannelId))); LinkFilteringServers = new ConcurrentHashSet <ulong>(configs.Where(gc => gc.FilterLinks).Select(gc => gc.GuildId)); LinkFilteringChannels = new ConcurrentHashSet <ulong>(configs.SelectMany(gc => gc.FilterLinksChannelIds.Select(fci => fci.ChannelId))); var dict = configs.ToDictionary(gc => gc.GuildId, gc => new ConcurrentHashSet <string>(gc.FilteredWords.Select(fw => fw.Word))); ServerFilteredWords = new ConcurrentDictionary <ulong, ConcurrentHashSet <string> >(dict); var serverFiltering = configs.Where(gc => gc.FilterWords); WordFilteringServers = new ConcurrentHashSet <ulong>(serverFiltering.Select(gc => gc.GuildId)); WordFilteringChannels = new ConcurrentHashSet <ulong>(configs.SelectMany(gc => gc.FilterWordsChannelIds.Select(fwci => fwci.ChannelId))); } client.MessageUpdated += (oldData, newMsg, channel) => { var _ = Task.Run(() => { var guild = (channel as ITextChannel)?.Guild; var usrMsg = newMsg as IUserMessage; if (guild == null || usrMsg == null) { return(Task.CompletedTask); } return(RunBehavior(null, guild, usrMsg)); }); return(Task.CompletedTask); }; }
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; }
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; }