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 } }
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); }
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); }
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); }
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 _); } }
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; }
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); }
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 _); } }
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 _); } }
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); } } }
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); } } }
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); } } }
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); } } }
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); } } }
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); } } }