Compare commits

...

2 Commits

Author SHA1 Message Date
defnotken
49177e639e conflicts 2025-10-15 14:15:30 -05:00
azyges
79483205f1 cdn download support on shards + clean up 2025-10-16 01:15:31 +09:00
4 changed files with 105 additions and 18 deletions

View File

@@ -34,12 +34,14 @@ public class ServerFilesController : ControllerBase
private readonly LightlessMetrics _metricsClient; private readonly LightlessMetrics _metricsClient;
private readonly MainServerShardRegistrationService _shardRegistrationService; private readonly MainServerShardRegistrationService _shardRegistrationService;
private readonly CDNDownloadUrlService _cdnDownloadUrlService; private readonly CDNDownloadUrlService _cdnDownloadUrlService;
private readonly CDNDownloadsService _cdnDownloadsService;
public ServerFilesController(ILogger<ServerFilesController> logger, CachedFileProvider cachedFileProvider, public ServerFilesController(ILogger<ServerFilesController> logger, CachedFileProvider cachedFileProvider,
IConfigurationService<StaticFilesServerConfiguration> configuration, IConfigurationService<StaticFilesServerConfiguration> configuration,
IHubContext<LightlessHub> hubContext, IHubContext<LightlessHub> hubContext,
IDbContextFactory<LightlessDbContext> lightlessDbContext, LightlessMetrics metricsClient, IDbContextFactory<LightlessDbContext> lightlessDbContext, LightlessMetrics metricsClient,
MainServerShardRegistrationService shardRegistrationService, CDNDownloadUrlService cdnDownloadUrlService) : base(logger) MainServerShardRegistrationService shardRegistrationService, CDNDownloadUrlService cdnDownloadUrlService,
CDNDownloadsService cdnDownloadsService) : base(logger)
{ {
_basePath = configuration.GetValueOrDefault(nameof(StaticFilesServerConfiguration.UseColdStorage), false) _basePath = configuration.GetValueOrDefault(nameof(StaticFilesServerConfiguration.UseColdStorage), false)
? configuration.GetValue<string>(nameof(StaticFilesServerConfiguration.ColdStorageDirectory)) ? configuration.GetValue<string>(nameof(StaticFilesServerConfiguration.ColdStorageDirectory))
@@ -51,6 +53,7 @@ public class ServerFilesController : ControllerBase
_metricsClient = metricsClient; _metricsClient = metricsClient;
_shardRegistrationService = shardRegistrationService; _shardRegistrationService = shardRegistrationService;
_cdnDownloadUrlService = cdnDownloadUrlService; _cdnDownloadUrlService = cdnDownloadUrlService;
_cdnDownloadsService = cdnDownloadsService;
} }
[HttpPost(LightlessFiles.ServerFiles_DeleteAll)] [HttpPost(LightlessFiles.ServerFiles_DeleteAll)]
@@ -145,24 +148,16 @@ public class ServerFilesController : ControllerBase
[AllowAnonymous] [AllowAnonymous]
public async Task<IActionResult> DownloadFileDirect(string hash, [FromQuery] long expires, [FromQuery] string signature) public async Task<IActionResult> DownloadFileDirect(string hash, [FromQuery] long expires, [FromQuery] string signature)
{ {
if (!_cdnDownloadUrlService.DirectDownloadsEnabled) var result = await _cdnDownloadsService.GetDownloadAsync(hash, expires, signature).ConfigureAwait(false);
{
return NotFound();
}
hash = hash.ToUpperInvariant(); return result.Status switch
if (!_cdnDownloadUrlService.TryValidateSignature(hash, expires, signature))
{ {
return Unauthorized(); CDNDownloadsService.ResultStatus.Disabled => NotFound(),
} CDNDownloadsService.ResultStatus.Unauthorized => Unauthorized(),
CDNDownloadsService.ResultStatus.NotFound => NotFound(),
var fileInfo = await _cachedFileProvider.DownloadAndGetLocalFileInfo(hash).ConfigureAwait(false); CDNDownloadsService.ResultStatus.Success => PhysicalFile(result.File!.FullName, "application/octet-stream"),
if (fileInfo == null) _ => NotFound()
{ };
return NotFound();
}
return PhysicalFile(fileInfo.FullName, "application/octet-stream");
} }
[HttpPost(LightlessFiles.ServerFiles_FilesSend)] [HttpPost(LightlessFiles.ServerFiles_FilesSend)]

View File

@@ -0,0 +1,34 @@
using LightlessSync.API.Routes;
using LightlessSyncStaticFilesServer.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace LightlessSyncStaticFilesServer.Controllers;
[Route(LightlessFiles.ServerFiles)]
public class ShardServerFilesController : ControllerBase
{
private readonly CDNDownloadsService _cdnDownloadsService;
public ShardServerFilesController(ILogger<ShardServerFilesController> logger,
CDNDownloadsService cdnDownloadsService) : base(logger)
{
_cdnDownloadsService = cdnDownloadsService;
}
[HttpGet(LightlessFiles.ServerFiles_DirectDownload + "/{hash}")]
[AllowAnonymous]
public async Task<IActionResult> DownloadFileDirect(string hash, [FromQuery] long expires, [FromQuery] string signature)
{
var result = await _cdnDownloadsService.GetDownloadAsync(hash, expires, signature).ConfigureAwait(false);
return result.Status switch
{
CDNDownloadsService.ResultStatus.Disabled => NotFound(),
CDNDownloadsService.ResultStatus.Unauthorized => Unauthorized(),
CDNDownloadsService.ResultStatus.NotFound => NotFound(),
CDNDownloadsService.ResultStatus.Success => PhysicalFile(result.File!.FullName, "application/octet-stream"),
_ => NotFound()
};
}
}

View File

@@ -0,0 +1,56 @@
using System.IO;
using System.Threading.Tasks;
namespace LightlessSyncStaticFilesServer.Services;
public class CDNDownloadsService
{
public enum ResultStatus
{
Disabled,
Unauthorized,
NotFound,
Success
}
public readonly record struct Result(ResultStatus Status, FileInfo? File);
private readonly CDNDownloadUrlService _cdnDownloadUrlService;
private readonly CachedFileProvider _cachedFileProvider;
public CDNDownloadsService(CDNDownloadUrlService cdnDownloadUrlService, CachedFileProvider cachedFileProvider)
{
_cdnDownloadUrlService = cdnDownloadUrlService;
_cachedFileProvider = cachedFileProvider;
}
public bool DownloadsEnabled => _cdnDownloadUrlService.DirectDownloadsEnabled;
public async Task<Result> GetDownloadAsync(string hash, long expiresUnixSeconds, string signature)
{
if (!_cdnDownloadUrlService.DirectDownloadsEnabled)
{
return new Result(ResultStatus.Disabled, null);
}
if (string.IsNullOrEmpty(signature) || string.IsNullOrEmpty(hash))
{
return new Result(ResultStatus.Unauthorized, null);
}
hash = hash.ToUpperInvariant();
if (!_cdnDownloadUrlService.TryValidateSignature(hash, expiresUnixSeconds, signature))
{
return new Result(ResultStatus.Unauthorized, null);
}
var fileInfo = await _cachedFileProvider.DownloadAndGetLocalFileInfo(hash).ConfigureAwait(false);
if (fileInfo == null)
{
return new Result(ResultStatus.NotFound, null);
}
return new Result(ResultStatus.Success, fileInfo);
}
}

View File

@@ -88,6 +88,7 @@ public class Startup
services.AddSingleton<ServerTokenGenerator>(); services.AddSingleton<ServerTokenGenerator>();
services.AddSingleton<RequestQueueService>(); services.AddSingleton<RequestQueueService>();
services.AddSingleton<CDNDownloadUrlService>(); services.AddSingleton<CDNDownloadUrlService>();
services.AddSingleton<CDNDownloadsService>();
services.AddHostedService(p => p.GetService<RequestQueueService>()); services.AddHostedService(p => p.GetService<RequestQueueService>());
services.AddHostedService(m => m.GetService<FileStatisticsService>()); services.AddHostedService(m => m.GetService<FileStatisticsService>());
services.AddSingleton<IConfigurationService<LightlessConfigurationBase>, LightlessConfigurationServiceClient<LightlessConfigurationBase>>(); services.AddSingleton<IConfigurationService<LightlessConfigurationBase>, LightlessConfigurationServiceClient<LightlessConfigurationBase>>();
@@ -205,7 +206,8 @@ public class Startup
} }
else if (_isDistributionNode) else if (_isDistributionNode)
{ {
a.FeatureProviders.Add(new AllowedControllersFeatureProvider(typeof(CacheController), typeof(RequestController), typeof(DistributionController), typeof(SpeedTestController))); a.FeatureProviders.Add(new AllowedControllersFeatureProvider(typeof(CacheController), typeof(RequestController),
typeof(DistributionController), typeof(ShardServerFilesController), typeof(SpeedTestController)));
} }
else else
{ {