From 356015229deb54d2d84a9a25c7576308c32bee75 Mon Sep 17 00:00:00 2001 From: DubyaDude Date: Sat, 17 Aug 2024 20:43:42 -0400 Subject: [PATCH 1/2] Work on cloudflare service --- VRCX-API/Program.cs | 6 ++- ...odicService.cs => CachePeriodicService.cs} | 15 ++++-- VRCX-API/Services/CloudflareService.cs | 54 +++++++++++++++++++ VRCX-API/Services/GithubCacheService.cs | 5 +- VRCX-API/VRCX-API.csproj | 3 +- 5 files changed, 75 insertions(+), 8 deletions(-) rename VRCX-API/Services/{GithubPeriodicService.cs => CachePeriodicService.cs} (63%) create mode 100644 VRCX-API/Services/CloudflareService.cs diff --git a/VRCX-API/Program.cs b/VRCX-API/Program.cs index 5e7aeb6..06ab194 100644 --- a/VRCX-API/Program.cs +++ b/VRCX-API/Program.cs @@ -22,9 +22,11 @@ public static void Main(string[] args) CommonConfig.Config.Load(); + builder.Services.AddSingleton(); builder.Services.AddSingleton(); - builder.Services.AddSingleton(); - builder.Services.AddHostedService(provider => provider.GetRequiredService()); + builder.Services.AddSingleton(); + builder.Services.AddHostedService(provider => provider.GetRequiredService()); + builder.Services.AddHostedService(provider => provider.GetRequiredService()); builder.Services.AddControllers() .AddJsonOptions(options => diff --git a/VRCX-API/Services/GithubPeriodicService.cs b/VRCX-API/Services/CachePeriodicService.cs similarity index 63% rename from VRCX-API/Services/GithubPeriodicService.cs rename to VRCX-API/Services/CachePeriodicService.cs index 0a5ce18..7619a99 100644 --- a/VRCX-API/Services/GithubPeriodicService.cs +++ b/VRCX-API/Services/CachePeriodicService.cs @@ -1,15 +1,17 @@ namespace VRCX_API.Services { - public class GithubPeriodicService : BackgroundService + public class CachePeriodicService : BackgroundService { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly GithubCacheService _githubCacheService; + private readonly CloudflareService _cloudflareService; private DateTime _lastRefresh = DateTime.MinValue; - public GithubPeriodicService(ILogger logger, GithubCacheService githubCacheService) + public CachePeriodicService(ILogger logger, GithubCacheService githubCacheService, CloudflareService cloudflareService) { _logger = logger; _githubCacheService = githubCacheService; + _cloudflareService = cloudflareService; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) @@ -24,8 +26,13 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) { if (DateTime.Now - _lastRefresh > TimeSpan.FromSeconds(120)) { - await _githubCacheService.RefreshAsync(); + var hasChanged = await _githubCacheService.RefreshAsync(); _lastRefresh = DateTime.Now; + + if(hasChanged) + { + await _cloudflareService.PurgeCache(); + } } } catch (Exception ex) diff --git a/VRCX-API/Services/CloudflareService.cs b/VRCX-API/Services/CloudflareService.cs new file mode 100644 index 0000000..e009ea8 --- /dev/null +++ b/VRCX-API/Services/CloudflareService.cs @@ -0,0 +1,54 @@ +using CloudFlare.Client; +using CloudFlare.Client.Api.Authentication; +using VRCX_API.Configs; + +namespace VRCX_API.Services +{ + public class CloudflareService : IHostedService + { + private readonly ILogger _logger; + private readonly CloudFlareClient _client; + private string _zoneId = string.Empty; + + public CloudflareService(ILogger logger) + { + _logger = logger; + + var authentication = new ApiTokenAuthentication(CommonConfig.Config.Instance.CloudflareAPIKey); + _client = new CloudFlareClient(authentication); + } + + public async Task StartAsync(CancellationToken cancellationToken) + { + var zones = await _client.Zones.GetAsync(); + + if (!zones.Success) + { + throw new Exception("Failed to get zones from Cloudflare"); + } + + var vrcxZone = zones.Result.FirstOrDefault(x => x.Name == "vrcx.app"); + + if (string.IsNullOrWhiteSpace(vrcxZone?.Id)) + { + throw new Exception("Failed to get zone id for vrcx.app"); + } + + _zoneId = vrcxZone.Id; + } + + public async Task PurgeCache() + { + var result = await _client.Zones.PurgeAllFilesAsync(_zoneId, true); + if (!result.Success) + { + throw new Exception("Failed to purge cache for vrcx.app"); + } + } + + public Task StopAsync(CancellationToken cancellationToken) + { + return Task.CompletedTask; + } + } +} diff --git a/VRCX-API/Services/GithubCacheService.cs b/VRCX-API/Services/GithubCacheService.cs index be2a6c5..8b764ec 100644 --- a/VRCX-API/Services/GithubCacheService.cs +++ b/VRCX-API/Services/GithubCacheService.cs @@ -42,13 +42,16 @@ public GithubCacheService(ILogger logger) _jsonSerializerOptions.Converters.Add(new IgnoreEmptyStringNullableEnumConverter()); } - public async Task RefreshAsync() + public async Task RefreshAsync() { await RefreshReleases(); await RefreshAdvisories(); GC.Collect(2, GCCollectionMode.Aggressive); GC.WaitForFullGCComplete(); + + // @TODO Impliment a way to see if latest releases changed. + return true; } private async Task RefreshReleases() diff --git a/VRCX-API/VRCX-API.csproj b/VRCX-API/VRCX-API.csproj index 868451b..9f364b2 100644 --- a/VRCX-API/VRCX-API.csproj +++ b/VRCX-API/VRCX-API.csproj @@ -1,4 +1,4 @@ - + net8.0 @@ -8,6 +8,7 @@ + From 67af2d1b6da037516ade72365e1856b76b8e7847 Mon Sep 17 00:00:00 2001 From: DubyaDude Date: Sun, 18 Aug 2024 08:37:31 -0400 Subject: [PATCH 2/2] Created diff checking --- VRCX-API/Services/CachePeriodicService.cs | 10 ++ VRCX-API/Services/CloudflareService.cs | 8 +- VRCX-API/Services/GithubCacheService.cs | 107 ++++++++++++++++++++-- 3 files changed, 115 insertions(+), 10 deletions(-) diff --git a/VRCX-API/Services/CachePeriodicService.cs b/VRCX-API/Services/CachePeriodicService.cs index 7619a99..c22dd54 100644 --- a/VRCX-API/Services/CachePeriodicService.cs +++ b/VRCX-API/Services/CachePeriodicService.cs @@ -18,6 +18,8 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) { await _githubCacheService.RefreshAsync(); _lastRefresh = DateTime.Now; + await _cloudflareService.PurgeCache(); + TriggerGC(); using PeriodicTimer timer = new PeriodicTimer(TimeSpan.FromSeconds(60)); while (!stoppingToken.IsCancellationRequested && await timer.WaitForNextTickAsync(stoppingToken)) @@ -33,6 +35,8 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) { await _cloudflareService.PurgeCache(); } + + TriggerGC(); } } catch (Exception ex) @@ -41,5 +45,11 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) } } } + + private static void TriggerGC() + { + GC.Collect(2, GCCollectionMode.Aggressive); + GC.WaitForFullGCComplete(); + } } } diff --git a/VRCX-API/Services/CloudflareService.cs b/VRCX-API/Services/CloudflareService.cs index e009ea8..14eebc5 100644 --- a/VRCX-API/Services/CloudflareService.cs +++ b/VRCX-API/Services/CloudflareService.cs @@ -6,6 +6,7 @@ namespace VRCX_API.Services { public class CloudflareService : IHostedService { + private const string _zoneName = "vrcx.app"; private readonly ILogger _logger; private readonly CloudFlareClient _client; private string _zoneId = string.Empty; @@ -27,11 +28,11 @@ public async Task StartAsync(CancellationToken cancellationToken) throw new Exception("Failed to get zones from Cloudflare"); } - var vrcxZone = zones.Result.FirstOrDefault(x => x.Name == "vrcx.app"); + var vrcxZone = zones.Result.FirstOrDefault(x => x.Name == _zoneName); if (string.IsNullOrWhiteSpace(vrcxZone?.Id)) { - throw new Exception("Failed to get zone id for vrcx.app"); + throw new Exception($"Failed to get zone id for {_zoneName}"); } _zoneId = vrcxZone.Id; @@ -39,10 +40,11 @@ public async Task StartAsync(CancellationToken cancellationToken) public async Task PurgeCache() { + _logger.LogInformation("Purging cache for {zoneName}", _zoneName); var result = await _client.Zones.PurgeAllFilesAsync(_zoneId, true); if (!result.Success) { - throw new Exception("Failed to purge cache for vrcx.app"); + throw new Exception($"Failed to purge cache for {_zoneName}"); } } diff --git a/VRCX-API/Services/GithubCacheService.cs b/VRCX-API/Services/GithubCacheService.cs index 8b764ec..faa23ca 100644 --- a/VRCX-API/Services/GithubCacheService.cs +++ b/VRCX-API/Services/GithubCacheService.cs @@ -44,18 +44,19 @@ public GithubCacheService(ILogger logger) public async Task RefreshAsync() { - await RefreshReleases(); - await RefreshAdvisories(); + bool hasChanged = false; - GC.Collect(2, GCCollectionMode.Aggressive); - GC.WaitForFullGCComplete(); + hasChanged |= await RefreshReleases(); + hasChanged |= await RefreshAdvisories(); // @TODO Impliment a way to see if latest releases changed. - return true; + return hasChanged; } - private async Task RefreshReleases() + private async Task RefreshReleases() { + bool hasChanged = false; + List stableReleases = []; List nighltyReleases = []; @@ -77,6 +78,8 @@ private async Task RefreshReleases() stableReleases[i].Prerelease = false; } + hasChanged |= !AreEqual(stableReleases.FirstOrDefault(), _stableReleases.FirstOrDefault()); + _stableReleases = stableReleases; _logger.LogInformation("Stabe Releases: {count}; Latest: {latestName}", _stableReleases.Count, _stableReleases.FirstOrDefault()?.Name); @@ -86,16 +89,26 @@ private async Task RefreshReleases() nighltyReleases[i].Prerelease = false; } + hasChanged |= !AreEqual(nighltyReleases.FirstOrDefault(), _nighltyReleases.FirstOrDefault()); + _nighltyReleases = nighltyReleases; _logger.LogInformation("Nightly Releases: {count}; Latest: {latestName}", _nighltyReleases.Count, _nighltyReleases.FirstOrDefault()?.Name); + + return hasChanged; } - private async Task RefreshAdvisories() + private async Task RefreshAdvisories() { + bool hasChanged = false; + var advisories = await GetAllAsync($"https://api.github.com/repos/{MainRepo.Owner}/{MainRepo.Repo}/security-advisories"); + hasChanged |= !AreEqual(advisories.FirstOrDefault(), _advisories.FirstOrDefault()); + _advisories = advisories; _logger.LogInformation("Advisories: {count}; Latest: {latestName}", _advisories.Count, _advisories.FirstOrDefault()?.CveId); + + return hasChanged; } private async Task> GetAllAsync(string path) @@ -134,5 +147,85 @@ private async Task> GetAllAsync(string path) return result; } + + private static bool AreEqual(GitHub.Models.Release? a, GitHub.Models.Release? b) + { + if (a == null && b == null) + { + return false; + } + + if (a == null || b == null) + { + return false; + } + + if (a.Id != b.Id && + a.Name != b.Name && + a.Body != b.Body && + a.PublishedAt != b.PublishedAt && + a.TagName != b.TagName && + a.Assets?.Count != b.Assets?.Count) + { + return false; + } + + if (a.Assets?.Count > 0 && b.Assets?.Count > 0) + { + for (int i = 0; i < a.Assets.Count; i++) + { + if (a.Assets[i].Id != b.Assets[i].Id && + a.Assets[i].Name != b.Assets[i].Name && + a.Assets[i].UpdatedAt != b.Assets[i].UpdatedAt && + a.Assets[i].State != b.Assets[i].State && + a.Assets[i].BrowserDownloadUrl != b.Assets[i].BrowserDownloadUrl) + { + return false; + } + } + } + + return true; + } + + private static bool AreEqual(GitHub.Models.RepositoryAdvisory? a, GitHub.Models.RepositoryAdvisory? b) + { + if (a == null && b == null) + { + return false; + } + + if (a == null || b == null) + { + return false; + } + + if (a.CveId != b.CveId && + a.PublishedAt != b.PublishedAt && + a.Severity != b.Severity && + a.Summary != b.Summary && + a.Description != b.Description && + a.UpdatedAt != b.UpdatedAt && + a.State != b.State && + a.Vulnerabilities?.Count != b.Vulnerabilities?.Count) + { + return false; + } + + if (a.Vulnerabilities?.Count > 0 && b.Vulnerabilities?.Count > 0) + { + for (int i = 0; i < a.Vulnerabilities.Count; i++) + { + if (a.Vulnerabilities[i].PatchedVersions != b.Vulnerabilities[i].PatchedVersions && + a.Vulnerabilities[i].Package != b.Vulnerabilities[i].Package && + a.Vulnerabilities[i].VulnerableVersionRange != b.Vulnerabilities[i].VulnerableVersionRange) + { + return false; + } + } + } + + return true; + } } }