diff --git a/LightlessSyncServer/LightlessSyncStaticFilesServer/Controllers/ShardServerFilesController.cs b/LightlessSyncServer/LightlessSyncStaticFilesServer/Controllers/ShardServerFilesController.cs index 819597e..3cfbf1a 100644 --- a/LightlessSyncServer/LightlessSyncStaticFilesServer/Controllers/ShardServerFilesController.cs +++ b/LightlessSyncServer/LightlessSyncStaticFilesServer/Controllers/ShardServerFilesController.cs @@ -20,13 +20,14 @@ public class ShardServerFilesController : ControllerBase [AllowAnonymous] public async Task DownloadFileDirect(string hash, [FromQuery] long expires, [FromQuery] string signature) { - var result = await _cdnDownloadsService.GetDownloadAsync(hash, expires, signature).ConfigureAwait(false); + var result = _cdnDownloadsService.GetDownloadWithCacheCheck(hash, expires, signature); return result.Status switch { CDNDownloadsService.ResultStatus.Disabled => NotFound(), CDNDownloadsService.ResultStatus.Unauthorized => Unauthorized(), CDNDownloadsService.ResultStatus.NotFound => NotFound(), + CDNDownloadsService.ResultStatus.Downloading => StatusCode(503), CDNDownloadsService.ResultStatus.Success => PhysicalFile(result.File!.FullName, "application/octet-stream"), _ => NotFound() }; diff --git a/LightlessSyncServer/LightlessSyncStaticFilesServer/Services/CDNDownloadsService.cs b/LightlessSyncServer/LightlessSyncStaticFilesServer/Services/CDNDownloadsService.cs index 3cbd661..c289176 100644 --- a/LightlessSyncServer/LightlessSyncStaticFilesServer/Services/CDNDownloadsService.cs +++ b/LightlessSyncServer/LightlessSyncStaticFilesServer/Services/CDNDownloadsService.cs @@ -10,7 +10,8 @@ public class CDNDownloadsService Disabled, Unauthorized, NotFound, - Success + Success, + Downloading } public readonly record struct Result(ResultStatus Status, FileInfo? File); @@ -53,4 +54,32 @@ public class CDNDownloadsService return new Result(ResultStatus.Success, fileInfo); } + + public Result GetDownloadWithCacheCheck(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 = _cachedFileProvider.TryGetLocalFileInfo(hash); + if (fileInfo == null) + { + return new Result(ResultStatus.Downloading, null); + } + + return new Result(ResultStatus.Success, fileInfo); + } } diff --git a/LightlessSyncServer/LightlessSyncStaticFilesServer/Services/CachedFileProvider.cs b/LightlessSyncServer/LightlessSyncStaticFilesServer/Services/CachedFileProvider.cs index fbc4ce6..ff3d37e 100644 --- a/LightlessSyncServer/LightlessSyncStaticFilesServer/Services/CachedFileProvider.cs +++ b/LightlessSyncServer/LightlessSyncStaticFilesServer/Services/CachedFileProvider.cs @@ -219,4 +219,27 @@ public sealed class CachedFileProvider : IDisposable { return hashes.Exists(_currentTransfers.Keys.Contains); } + + public FileInfo? TryGetLocalFileInfo(string hash) + { + var fi = FilePathUtil.GetFileInfoForHash(_hotStoragePath, hash); + if (fi != null) + { + return GetLocalFilePath(hash); + } + + _ = Task.Run(async () => + { + try + { + await DownloadFileWhenRequired(hash).ConfigureAwait(false); + } + catch (Exception ex) + { + _logger.LogWarning(ex, "Download failed for {hash}", hash); + } + }); + + return null; + } } \ No newline at end of file