Skip to content

Commit

Permalink
Merge pull request #1 from DubyaDude/feature/cloudflare
Browse files Browse the repository at this point in the history
Feature/cloudflare
  • Loading branch information
DubyaDude authored Aug 18, 2024
2 parents 35d85df + 67af2d1 commit 742303b
Show file tree
Hide file tree
Showing 5 changed files with 186 additions and 14 deletions.
6 changes: 4 additions & 2 deletions VRCX-API/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ public static void Main(string[] args)

CommonConfig.Config.Load();

builder.Services.AddSingleton<CloudflareService>();
builder.Services.AddSingleton<GithubCacheService>();
builder.Services.AddSingleton<GithubPeriodicService>();
builder.Services.AddHostedService(provider => provider.GetRequiredService<GithubPeriodicService>());
builder.Services.AddSingleton<CachePeriodicService>();
builder.Services.AddHostedService(provider => provider.GetRequiredService<CloudflareService>());
builder.Services.AddHostedService(provider => provider.GetRequiredService<CachePeriodicService>());

builder.Services.AddControllers()
.AddJsonOptions(options =>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
namespace VRCX_API.Services
{
public class GithubPeriodicService : BackgroundService
public class CachePeriodicService : BackgroundService
{
private readonly ILogger<GithubPeriodicService> _logger;
private readonly ILogger<CachePeriodicService> _logger;
private readonly GithubCacheService _githubCacheService;
private readonly CloudflareService _cloudflareService;
private DateTime _lastRefresh = DateTime.MinValue;

public GithubPeriodicService(ILogger<GithubPeriodicService> logger, GithubCacheService githubCacheService)
public CachePeriodicService(ILogger<CachePeriodicService> logger, GithubCacheService githubCacheService, CloudflareService cloudflareService)
{
_logger = logger;
_githubCacheService = githubCacheService;
_cloudflareService = cloudflareService;
}

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))
Expand All @@ -24,8 +28,15 @@ 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();
}

TriggerGC();
}
}
catch (Exception ex)
Expand All @@ -34,5 +45,11 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
}
}
}

private static void TriggerGC()
{
GC.Collect(2, GCCollectionMode.Aggressive);
GC.WaitForFullGCComplete();
}
}
}
56 changes: 56 additions & 0 deletions VRCX-API/Services/CloudflareService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using CloudFlare.Client;
using CloudFlare.Client.Api.Authentication;
using VRCX_API.Configs;

namespace VRCX_API.Services
{
public class CloudflareService : IHostedService
{
private const string _zoneName = "vrcx.app";
private readonly ILogger<CloudflareService> _logger;
private readonly CloudFlareClient _client;
private string _zoneId = string.Empty;

public CloudflareService(ILogger<CloudflareService> 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 == _zoneName);

if (string.IsNullOrWhiteSpace(vrcxZone?.Id))
{
throw new Exception($"Failed to get zone id for {_zoneName}");
}

_zoneId = vrcxZone.Id;
}

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 {_zoneName}");
}
}

public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
}
110 changes: 103 additions & 7 deletions VRCX-API/Services/GithubCacheService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,21 @@ public GithubCacheService(ILogger<GithubCacheService> logger)
_jsonSerializerOptions.Converters.Add(new IgnoreEmptyStringNullableEnumConverter());
}

public async Task RefreshAsync()
public async Task<bool> 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 hasChanged;
}

private async Task RefreshReleases()
private async Task<bool> RefreshReleases()
{
bool hasChanged = false;

List<GitHub.Models.Release> stableReleases = [];
List<GitHub.Models.Release> nighltyReleases = [];

Expand All @@ -74,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);

Expand All @@ -83,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<bool> RefreshAdvisories()
{
bool hasChanged = false;

var advisories = await GetAllAsync<GitHub.Models.RepositoryAdvisory>($"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<List<T>> GetAllAsync<T>(string path)
Expand Down Expand Up @@ -131,5 +147,85 @@ private async Task<List<T>> GetAllAsync<T>(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;
}
}
}
3 changes: 2 additions & 1 deletion VRCX-API/VRCX-API.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
Expand All @@ -8,6 +8,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="CloudFlare.Client" Version="6.3.0" />
<PackageReference Include="GitHub.Octokit.SDK" Version="0.0.25" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Serilog" Version="4.0.1" />
Expand Down

0 comments on commit 742303b

Please sign in to comment.