Esempio n. 1
0
        internal async Task <CachedClanWar?> TryAddCachedClanWar(string tag, DateTime serverExpiration, DateTime localExpiration, CancellationToken?cancellationToken = default)
        {
            try
            {
                using var scope = Services.CreateScope();

                CacheContext dbContext = scope.ServiceProvider.GetRequiredService <CacheContext>();

                CachedClanWar?clanWar = await dbContext.ClanWars.FirstOrDefaultAsync(cw => cw.Tag == tag, cancellationToken.GetValueOrDefault()).ConfigureAwait(false);

                if (clanWar != null)
                {
                    return(clanWar);
                }

                clanWar = new CachedClanWar(tag)
                {
                    LocalExpiration  = localExpiration,
                    ServerExpiration = serverExpiration
                };

                dbContext.ClanWars.Add(clanWar);

                await dbContext.SaveChangesAsync(cancellationToken.GetValueOrDefault()).ConfigureAwait(false);

                return(clanWar);
            }
            catch (Exception)
            {
                return(null); //this is a race condition that is hard to handle
            }
        }
Esempio n. 2
0
        public async Task <CachedPlayer> UpdateAsync(string tag, bool download = true)
        {
            string formattedTag = Clash.FormatTag(tag);

            using var scope = Services.CreateScope();

            CacheContext cacheContext = scope.ServiceProvider.GetRequiredService <CacheContext>();

            CachedPlayer cachedPlayer = await cacheContext.Players
                                        .FirstOrDefaultAsync(v => v.Tag == formattedTag)
                                        .ConfigureAwait(false);

            if (cachedPlayer != null && cachedPlayer.Download == download)
            {
                return(cachedPlayer);
            }

            if (cachedPlayer == null)
            {
                cachedPlayer = new CachedPlayer(formattedTag);
                cacheContext.Players.Add(cachedPlayer);
            }

            cachedPlayer.Download = download;

            await cacheContext.SaveChangesAsync().ConfigureAwait(false);

            return(cachedPlayer);
        }
Esempio n. 3
0
        public async Task AddOrUpdateAsync(IEnumerable <string> tags, bool downloadWars = true, bool downloadCwl = true, bool downloadMembers = false)
        {
            List <string> formattedTags = new List <string>();

            foreach (string tag in tags)
            {
                formattedTags.Add(Clash.FormatTag(tag));
            }

            using var scope = Services.CreateScope();

            CacheContext dbContext = scope.ServiceProvider.GetRequiredService <CacheContext>();

            List <CachedClan> cachedClans = await dbContext.Clans
                                            .Where(c => formattedTags.Contains(c.Tag))
                                            .ToListAsync()
                                            .ConfigureAwait(false);

            foreach (string formattedTag in formattedTags)
            {
                CachedClan cachedClan = cachedClans.FirstOrDefault(c => c.Tag == formattedTag) ??
                                        await PrepareNewCachedClanAsync(formattedTag, downloadWars, downloadCwl, downloadMembers, dbContext).ConfigureAwait(false);

                cachedClan.Tag = formattedTag;
                cachedClan.DownloadCurrentWar = downloadWars;
                cachedClan.DownloadCwl        = downloadCwl;
                cachedClan.DownloadMembers    = downloadMembers;
            }

            await dbContext.SaveChangesAsync().ConfigureAwait(false);
        }
Esempio n. 4
0
        private async Task MonitorMembersAsync(CachedClan cached)
        {
            if (_stopRequestedTokenSource.IsCancellationRequested || cached.Data == null)
            {
                return;
            }

            List <Task> tasks = new List <Task>();

            using var scope = Services.CreateScope();

            CacheContext dbContext = scope.ServiceProvider.GetRequiredService <CacheContext>();

            List <CachedPlayer> players = await dbContext.Players.Where(p => cached.Data.Members.Select(m => m.Tag).Contains(p.Tag)).ToListAsync();

            foreach (Model.ClanMember member in cached.Data.Members.Where(m => !players.Any(p => p.Tag == m.Tag)))
            {
                CachedPlayer player = new CachedPlayer(member.Tag);

                dbContext.Players.Add(player);

                players.Add(player);
            }

            foreach (Model.ClanMember?member in cached.Data.Members)
            {
                tasks.Add(MonitorMemberAsync(players.Single(p => p.Tag == member.Tag)));
            }

            await Task.WhenAll(tasks);

            await dbContext.SaveChangesAsync(_stopRequestedTokenSource.Token);
        }
Esempio n. 5
0
        public async Task DeleteAsync(string tag)
        {
            string formattedTag = Clash.FormatTag(tag);

            using var scope = Services.CreateScope();

            CacheContext dbContext = scope.ServiceProvider.GetRequiredService <CacheContext>();

            while (!UpdatingVillage.TryAdd(formattedTag, new byte()))
            {
                await Task.Delay(500);
            }

            try
            {
                CachedPlayer cachedPlayer = await dbContext.Players.FirstOrDefaultAsync(c => c.Tag == formattedTag);

                if (cachedPlayer != null)
                {
                    dbContext.Players.Remove(cachedPlayer);
                }

                await dbContext.SaveChangesAsync();
            }
            finally
            {
                UpdatingVillage.TryRemove(formattedTag, out _);
            }
        }
Esempio n. 6
0
        public async Task AddAsync(string tag, bool downloadWars = true, bool downloadCwl = true, bool downloadMembers = false)
        {
            string formattedTag = Clash.FormatTag(tag);

            using var scope = Services.CreateScope();

            CacheContext dbContext = scope.ServiceProvider.GetRequiredService <CacheContext>();

            CachedClan cachedClan = await dbContext.Clans.Where(c => c.Tag == formattedTag).FirstOrDefaultAsync().ConfigureAwait(false);

            cachedClan ??= await PrepareNewCachedClanAsync(formattedTag, downloadWars, downloadCwl, downloadMembers, dbContext).ConfigureAwait(false);

            await dbContext.SaveChangesAsync().ConfigureAwait(false);

            return;
        }
Esempio n. 7
0
        private async Task DeleteUnmonitoredPlayersNotInAClan()
        {
            using var scope = Services.CreateScope();

            CacheContext dbContext = scope.ServiceProvider.GetRequiredService <CacheContext>();

            // delete any player who is not being monitored so stale items dont get stuck in cache
            List <CachedPlayer> cachedPlayers = await dbContext.Players
                                                .Where(p =>
                                                       p.ClanTag == null &&
                                                       p.Download == false &&
                                                       p.ServerExpiration < DateTime.UtcNow.AddMinutes(-10))
                                                .ToListAsync(_stopRequestedTokenSource.Token);

            dbContext.RemoveRange(cachedPlayers);

            await dbContext.SaveChangesAsync(_stopRequestedTokenSource.Token);
        }
Esempio n. 8
0
        public async Task DeleteAsync(string tag)
        {
            string formattedTag = Clash.FormatTag(tag);

            using var scope = Services.CreateScope();

            CacheContext dbContext = scope.ServiceProvider.GetRequiredService <CacheContext>();

            while (!_clanMonitor.UpdatingClan.TryAdd(formattedTag, new byte()))
            {
                await Task.Delay(500);
            }

            while (!UpdatingClanWar.TryAdd(formattedTag, new byte()))
            {
                await Task.Delay(500);
            }

            try
            {
                CachedClan cachedClan = await dbContext.Clans.FirstOrDefaultAsync(c => c.Tag == formattedTag);

                CachedClanWarLog cachedClanWarLog = await dbContext.WarLogs.FirstOrDefaultAsync(c => c.Tag == formattedTag);

                if (cachedClan != null)
                {
                    dbContext.Clans.Remove(cachedClan);
                }

                if (cachedClanWarLog != null)
                {
                    dbContext.WarLogs.Remove(cachedClanWarLog);
                }

                await dbContext.SaveChangesAsync();
            }
            finally
            {
                _clanMonitor.UpdatingClan.TryRemove(formattedTag, out _);
                UpdatingClanWar.TryRemove(formattedTag, out _);
            }
        }
Esempio n. 9
0
        internal async Task InsertNewWarAsync(CachedWar fetched)
        {
            if (fetched.Data == null)
            {
                throw new ArgumentException("Data should not be null.");
            }

            if (UpdatingWar.TryAdd(fetched, new byte()) == false)
            {
                return;
            }

            try
            {
                using var scope = Services.CreateScope();

                CacheContext dbContext = scope.ServiceProvider.GetRequiredService <CacheContext>();

                CachedWar?exists = await dbContext.Wars
                                   .Where(w =>
                                          w.PreparationStartTime == fetched.Data.PreparationStartTime &&
                                          w.ClanTag == fetched.Data.Clans.First().Value.Tag)
                                   .FirstOrDefaultAsync(_stopRequestedTokenSource.Token);

                if (exists != null)
                {
                    return;
                }

                dbContext.Wars.Add(fetched);

                await dbContext.SaveChangesAsync(_stopRequestedTokenSource.Token);

                OnClanWarAdded(fetched.Data);
            }
            finally
            {
                UpdatingWar.TryRemove(fetched, out var _);
            }
        }
Esempio n. 10
0
        public async Task RunAsync(CancellationToken cancellationToken)
        {
            try
            {
                if (_isRunning)
                {
                    return;
                }

                _isRunning = true;

                _stopRequestedTokenSource = new CancellationTokenSource();

                _playersClientBase.OnLog(this, new LogEventArgs(nameof(RunAsync), LogLevel.Information));

                while (cancellationToken.IsCancellationRequested == false && _stopRequestedTokenSource.IsCancellationRequested == false)
                {
                    using var scope = Services.CreateScope();

                    using CacheContext dbContext = scope.ServiceProvider.GetRequiredService <CacheContext>();

                    List <CachedPlayer> cachedPlayers = await dbContext.Players
                                                        .Where(v =>
                                                               v.Download &&
                                                               v.ServerExpiration < DateTime.UtcNow.AddSeconds(-3) &&
                                                               v.LocalExpiration < DateTime.UtcNow)
                                                        .OrderBy(v => v.ServerExpiration)
                                                        .Take(Configuration.ConcurrentPlayerDownloads)
                                                        .ToListAsync(_stopRequestedTokenSource.Token)
                                                        .ConfigureAwait(false);

                    List <Task> tasks = new();

                    for (int i = 0; i < cachedPlayers.Count; i++)
                    {
                        tasks.Add(UpdatePlayerAsync(cachedPlayers[i]));
                    }

                    await Task.WhenAll(tasks).ConfigureAwait(false);

                    await dbContext.SaveChangesAsync(_stopRequestedTokenSource.Token).ConfigureAwait(false);

                    await Task.Delay(Configuration.DelayBetweenTasks, _stopRequestedTokenSource.Token).ConfigureAwait(false);
                }

                _isRunning = false;
            }
            catch (Exception e)
            {
                _isRunning = false;

                if (_stopRequestedTokenSource.IsCancellationRequested)
                {
                    return;
                }

                _playersClientBase.OnLog(this, new ExceptionEventArgs(nameof(RunAsync), e));

                if (cancellationToken.IsCancellationRequested == false)
                {
                    _ = RunAsync(cancellationToken);
                }
            }
        }
Esempio n. 11
0
        public async Task RunAsync(CancellationToken cancellationToken)
        {
            try
            {
                if (_isRunning)
                {
                    return;
                }

                _isRunning = true;

                _stopRequestedTokenSource = new CancellationTokenSource();

                _clansClient.OnLog(this, new LogEventArgs(nameof(RunAsync), LogLevel.Information));

                while (_stopRequestedTokenSource.IsCancellationRequested == false && cancellationToken.IsCancellationRequested == false)
                {
                    if (_clansClient.DownloadWarLog == false)
                    {
                        await Task.Delay(Configuration.DelayBetweenTasks, _stopRequestedTokenSource.Token).ConfigureAwait(false);

                        continue;
                    }

                    using var scope = Services.CreateScope();

                    CacheContext dbContext = scope.ServiceProvider.GetRequiredService <CacheContext>();

                    //var clanWarLogsWithLogStatus = await dbContext.ClanWarLogWithLogStatus
                    //    .Where(w =>
                    //        w.IsWarLogPublic &&
                    //        w.DownloadCurrentWar &&
                    //        w.ServerExpiration < DateTime.UtcNow.AddSeconds(-3) &&
                    //        w.LocalExpiration < DateTime.UtcNow)
                    //    .OrderBy(w => w.ServerExpiration)
                    //    .Take(1000)
                    //    .Select(l => l.Tag)
                    //    .ToListAsync()
                    //    .ConfigureAwait(false);

                    List <CachedClanWarLog> cachedLogs = await(
                        from l in dbContext.WarLogs
                        join c in dbContext.Clans on l.Tag equals c.Tag
                        where c.IsWarLogPublic == true && c.DownloadCurrentWar && l.ServerExpiration < DateTime.UtcNow.AddSeconds(-3) && l.LocalExpiration < DateTime.UtcNow
                        orderby l.ServerExpiration
                        select l)
                                                         .Take(Configuration.ConcurrentWarLogDownloads)
                                                         .ToListAsync()
                                                         .ConfigureAwait(false);

                    List <Task> tasks = new();

                    foreach (CachedClanWarLog cachedLog in cachedLogs)
                    {
                        tasks.Add(MonitorLogAsync(cachedLog));
                    }

                    await Task.WhenAll(tasks).ConfigureAwait(false);

                    await dbContext.SaveChangesAsync(_stopRequestedTokenSource.Token).ConfigureAwait(false);

                    //for (int i = 0; i < clanWarLogsWithLogStatus.Count; i++)
                    //    await MonitorLogAsync(clanWarLogsWithLogStatus[i]);

                    await Task.Delay(Configuration.DelayBetweenTasks, _stopRequestedTokenSource.Token).ConfigureAwait(false);
                }

                _isRunning = false;
            }
            catch (Exception e)
            {
                _isRunning = false;

                if (_stopRequestedTokenSource.IsCancellationRequested)
                {
                    return;
                }

                _clansClient.OnLog(this, new ExceptionEventArgs(nameof(RunAsync), e));

                if (cancellationToken.IsCancellationRequested == false)
                {
                    _ = RunAsync(cancellationToken);
                }
            }
        }
Esempio n. 12
0
        public async Task RunAsync(CancellationToken cancellationToken)
        {
            try
            {
                if (_isRunning)
                {
                    return;
                }

                _isRunning = true;

                _stopRequestedTokenSource = new CancellationTokenSource();

                _clansClient.OnLog(this, new LogEventArgs(nameof(RunAsync), LogLevel.Information));

                while (_stopRequestedTokenSource.IsCancellationRequested == false && cancellationToken.IsCancellationRequested == false)
                {
                    if (_clansClient.DownloadCurrentWars == false)
                    {
                        await Task.Delay(Configuration.DelayBetweenTasks, _stopRequestedTokenSource.Token).ConfigureAwait(false);

                        continue;
                    }

                    using var scope = Services.CreateScope();

                    CacheContext dbContext = scope.ServiceProvider.GetRequiredService <CacheContext>();

                    //List<string> clanWarWithLogStatus = await dbContext.ClanWarWithLogStatus
                    //    .Where(w =>
                    //        w.IsWarLogPublic == true &&
                    //        w.DownloadCurrentWar &&
                    //        w.ServerExpiration < DateTime.UtcNow.AddSeconds(-3) &&
                    //        w.LocalExpiration < DateTime.UtcNow)
                    //    .OrderBy(w => w.ServerExpiration)
                    //    .Take(100)
                    //    .Select(l => l.Tag )
                    //    .ToListAsync()
                    //    .ConfigureAwait(false);

                    List <CachedClanWar> cachedClanWars = await(
                        from cw in dbContext.ClanWars
                        join c in dbContext.Clans on cw.Tag equals c.Tag
                        into cw_c_join
                        from c2 in cw_c_join.DefaultIfEmpty()
                        where
                        c2.IsWarLogPublic == true &&
                        c2.DownloadCurrentWar == true &&
                        cw.ServerExpiration < DateTime.UtcNow.AddSeconds(-3) &&
                        cw.LocalExpiration < DateTime.UtcNow
                        orderby cw.ServerExpiration
                        select cw)
                                                          .Take(Configuration.ConcurrentClanWarDownloads)
                                                          .ToListAsync();

                    List <Task> tasks = new();

                    foreach (CachedClanWar cachedClanWar in cachedClanWars)
                    {
                        tasks.Add(MonitorClanWarAsync(cachedClanWar));
                    }

                    await Task.WhenAll(tasks).ConfigureAwait(false);

                    await dbContext.SaveChangesAsync(_stopRequestedTokenSource.Token).ConfigureAwait(false);

                    await Task.Delay(Configuration.DelayBetweenTasks, _stopRequestedTokenSource.Token).ConfigureAwait(false);
                }

                _isRunning = false;
            }
            catch (Exception e)
            {
                _isRunning = false;

                if (_stopRequestedTokenSource.IsCancellationRequested)
                {
                    return;
                }

                _clansClient.OnLog(this, new ExceptionEventArgs(nameof(RunAsync), e));

                if (cancellationToken.IsCancellationRequested == false)
                {
                    _ = RunAsync(cancellationToken);
                }
            }
        }
Esempio n. 13
0
        public async Task RunAsync(CancellationToken cancellationToken)
        {
            try
            {
                if (_isRunning)
                {
                    return;
                }

                _isRunning = true;

                _stopRequestedTokenSource = new CancellationTokenSource();

                _clansClient.OnLog(this, new LogEventArgs(nameof(RunAsync), LogLevel.Information));

                while (_stopRequestedTokenSource.IsCancellationRequested == false && cancellationToken.IsCancellationRequested == false)
                {
                    using var scope = Services.CreateScope();

                    CacheContext dbContext = scope.ServiceProvider.GetRequiredService <CacheContext>();

                    List <CachedClan> cachedClans = await dbContext.Clans
                                                    .Where(w =>
                                                           w.ServerExpiration < DateTime.UtcNow.AddSeconds(-3) &&
                                                           w.LocalExpiration < DateTime.UtcNow)
                                                    .OrderBy(w => w.ServerExpiration)
                                                    .Take(Configuration.ConcurrentClanDownloads)
                                                    .ToListAsync(_stopRequestedTokenSource.Token)
                                                    .ConfigureAwait(false);

                    List <Task> tasks = new();

                    foreach (CachedClan cachedClan in cachedClans)
                    {
                        tasks.Add(MonitorClanAsync(cachedClan));
                    }

                    await Task.WhenAll(tasks).ConfigureAwait(false);

                    await dbContext.SaveChangesAsync(_stopRequestedTokenSource.Token).ConfigureAwait(false);

                    if (_deletedUnmonitoredPlayers < DateTime.UtcNow.AddMinutes(-10))
                    {
                        _deletedUnmonitoredPlayers = DateTime.UtcNow;

                        tasks = new List <Task>
                        {
                            DeleteUnmonitoredPlayersNotInAClan(),

                            DeletePlayersInClansNotMonitored()
                        };

                        await Task.WhenAll(tasks);
                    }

                    await Task.Delay(Configuration.DelayBetweenTasks, _stopRequestedTokenSource.Token).ConfigureAwait(false);
                }

                _isRunning = false;
            }
            catch (Exception e)
            {
                _isRunning = false;

                if (_stopRequestedTokenSource.IsCancellationRequested)
                {
                    return;
                }

                _clansClient.OnLog(this, new ExceptionEventArgs(nameof(RunAsync), e));

                if (cancellationToken.IsCancellationRequested == false)
                {
                    _ = RunAsync(cancellationToken);
                }
            }
        }
Esempio n. 14
0
        public async Task RunAsync(CancellationToken cancellationToken)
        {
            try
            {
                if (_isRunning)
                {
                    return;
                }

                _isRunning = true;

                _stopRequestedTokenSource = new CancellationTokenSource();

                _clansClient.OnLog(this, new LogEventArgs(nameof(RunAsync), LogLevel.Information));

                while (_stopRequestedTokenSource.IsCancellationRequested == false && cancellationToken.IsCancellationRequested == false)
                {
                    if (_clansClient.DownloadCurrentWars == false && _clansClient.DownloadCwl == false)
                    {
                        await Task.Delay(Configuration.DelayBetweenTasks, _stopRequestedTokenSource.Token).ConfigureAwait(false);

                        continue;
                    }

                    using var scope = Services.CreateScope();

                    CacheContext dbContext = scope.ServiceProvider.GetRequiredService <CacheContext>();

                    var wars = await dbContext.Wars
                               .Where(w =>
                                      w.IsFinal == false &&
                                      w.ServerExpiration < DateTime.UtcNow.AddSeconds(-3) &&
                                      w.LocalExpiration < DateTime.UtcNow //&&
                                                                          //w.State < WarState.WarEnded && //todo is there an index on state?
                                                                          //w.EndTime.AddDays(8) > DateTime.UtcNow //todo does this require a new column and a new index?
                                                                          //todo w.StartTime < DateTime.UtcNow.AddHours(-1))  //todo preparation start time < now
                                      )
                               .OrderBy(w => w.ServerExpiration)
                               .ToListAsync()
                               .ConfigureAwait(false);

                    for (int i = 0; i < wars.Count; i++)
                    {
                        await MonitorWarAsync(wars[i]).ConfigureAwait(false);
                    }

                    await dbContext.SaveChangesAsync(_stopRequestedTokenSource.Token).ConfigureAwait(false);

                    await Task.Delay(Configuration.DelayBetweenTasks, _stopRequestedTokenSource.Token).ConfigureAwait(false);
                }

                _isRunning = false;
            }
            catch (Exception e)
            {
                _isRunning = false;

                if (_stopRequestedTokenSource.IsCancellationRequested)
                {
                    return;
                }

                _clansClient.OnLog(this, new ExceptionEventArgs(nameof(RunAsync), e));

                if (cancellationToken.IsCancellationRequested == false)
                {
                    _ = RunAsync(cancellationToken);
                }
            }
        }
Esempio n. 15
0
        public async Task RunAsync(CancellationToken cancellationToken)
        {
            try
            {
                if (_isRunning)
                {
                    return;
                }

                _isRunning = true;

                _stopRequestedTokenSource = new CancellationTokenSource();

                _clansClient.OnLog(this, new LogEventArgs(nameof(RunAsync), LogLevel.Information));

                int id = int.MinValue;

                while (_stopRequestedTokenSource.IsCancellationRequested == false && cancellationToken.IsCancellationRequested == false)
                {
                    if (_clansClient.DownloadCwl == false)
                    {
                        await Task.Delay(Configuration.DelayBetweenTasks, _stopRequestedTokenSource.Token).ConfigureAwait(false);

                        continue;
                    }

                    using var scope = Services.CreateScope();

                    CacheContext dbContext = scope.ServiceProvider.GetRequiredService <CacheContext>();

                    //var cachedWarLogs = await dbContext.ClanWarLeagueGroupWithStatus
                    //    .Where(w =>
                    //        w.DownloadCwl == true &&
                    //        w.ServerExpiration < DateTime.UtcNow.AddSeconds(-3) &&
                    //        w.LocalExpiration < DateTime.UtcNow)
                    //    .OrderBy(w => w.ServerExpiration)
                    //    .Take(10)
                    //    .ToListAsync()
                    //    .ConfigureAwait(false);

                    List <CachedClanWarLeagueGroup> cachedGroup = await(
                        from g in dbContext.Groups
                        join c in dbContext.Clans on g.Tag equals c.Tag
                        where c.DownloadCwl && g.ServerExpiration < DateTime.UtcNow.AddSeconds(-3) && g.LocalExpiration <DateTime.UtcNow && g.Id> id
                        orderby g.Id
                        select g)
                                                                  .Take(Configuration.ConcurrentCwlDownloads)
                                                                  .ToListAsync()
                                                                  .ConfigureAwait(false);

                    id = cachedGroup.Count == Configuration.ConcurrentClanDownloads
                        ? cachedGroup.Max(g => g.Id)
                        : int.MinValue;

                    List <Task> tasks = new();

                    foreach (CachedClanWarLeagueGroup group in cachedGroup)
                    {
                        tasks.Add(MonitorCwlAsync(group, dbContext));
                    }

                    await Task.WhenAll(tasks).ConfigureAwait(false);

                    await dbContext.SaveChangesAsync(_stopRequestedTokenSource.Token).ConfigureAwait(false);

                    await Task.Delay(Configuration.DelayBetweenTasks, _stopRequestedTokenSource.Token).ConfigureAwait(false);
                }

                _isRunning = false;
            }
            catch (Exception e)
            {
                _isRunning = false;

                if (_stopRequestedTokenSource.IsCancellationRequested)
                {
                    return;
                }

                _clansClient.OnLog(this, new ExceptionEventArgs(nameof(RunAsync), e));

                if (cancellationToken.IsCancellationRequested == false)
                {
                    _ = RunAsync(cancellationToken);
                }
            }
        }