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
7 changed files with 106 additions and 34 deletions

View File

@@ -7,9 +7,7 @@ using LightlessSyncShared.Services;
using LightlessSyncShared.Utils.Configuration;
using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore;
using StackExchange.Redis;
using StackExchange.Redis.Extensions.Core.Abstractions;
using static LightlessSyncServer.Hubs.LightlessHub;
namespace LightlessSyncServer.Services;
@@ -54,13 +52,6 @@ public sealed class SystemInfoService : BackgroundService
_lightlessMetrics.SetGaugeTo(MetricsAPI.GaugeAvailableIOWorkerThreads, ioThreads);
var onlineUsers = (_redis.SearchKeysAsync("UID:*").GetAwaiter().GetResult()).Count();
var allLightfinderKeys = _redis.SearchKeysAsync("broadcast:*").GetAwaiter().GetResult().Where(c => !c.Contains("owner", StringComparison.Ordinal)).ToHashSet(StringComparer.Ordinal);
var allLightfinderItems = _redis.GetAllAsync<BroadcastRedisEntry>(allLightfinderKeys).GetAwaiter().GetResult();
var countLightFinderUsers = allLightfinderItems.Count;
var countLightFinderSyncshells = allLightfinderItems.Count(static l => !string.IsNullOrEmpty(l.Value.GID));
SystemInfoDto = new SystemInfoDto()
{
OnlineUsers = onlineUsers,
@@ -75,12 +66,10 @@ public sealed class SystemInfoService : BackgroundService
using var db = await _dbContextFactory.CreateDbContextAsync(ct).ConfigureAwait(false);
_lightlessMetrics.SetGaugeTo(MetricsAPI.GaugeAuthorizedConnections, onlineUsers);
_lightlessMetrics.SetGaugeTo(MetricsAPI.GaugeLightFinderConnections, countLightFinderUsers);
_lightlessMetrics.SetGaugeTo(MetricsAPI.GaugePairs, db.ClientPairs.AsNoTracking().Count());
_lightlessMetrics.SetGaugeTo(MetricsAPI.GaugePairsPaused, db.Permissions.AsNoTracking().Count(p => p.IsPaused));
_lightlessMetrics.SetGaugeTo(MetricsAPI.GaugePairsPaused, db.Permissions.AsNoTracking().Where(p => p.IsPaused).Count());
_lightlessMetrics.SetGaugeTo(MetricsAPI.GaugeGroups, db.Groups.AsNoTracking().Count());
_lightlessMetrics.SetGaugeTo(MetricsAPI.GaugeGroupPairs, db.GroupPairs.AsNoTracking().Count());
_lightlessMetrics.SetGaugeTo(MetricsAPI.GaugeLightFinderGroups, countLightFinderSyncshells);
_lightlessMetrics.SetGaugeTo(MetricsAPI.GaugeUsersRegistered, db.Users.AsNoTracking().Count());
}

View File

@@ -295,8 +295,6 @@ public class Startup
}, new List<string>
{
MetricsAPI.GaugeAuthorizedConnections,
MetricsAPI.GaugeLightFinderConnections,
MetricsAPI.GaugeLightFinderGroups,
MetricsAPI.GaugeConnections,
MetricsAPI.GaugePairs,
MetricsAPI.GaugePairsPaused,

View File

@@ -9,8 +9,6 @@ public class MetricsAPI
public const string GaugeAvailableIOWorkerThreads = "lightless_available_threadpool_io";
public const string GaugeUsersRegistered = "lightless_users_registered";
public const string CounterUsersRegisteredDeleted = "lightless_users_registered_deleted";
public const string GaugeLightFinderConnections = "lightless_lightfinder_connections";
public const string GaugeLightFinderGroups = "lightless_lightfinder_groups";
public const string GaugePairs = "lightless_pairs";
public const string GaugePairsPaused = "lightless_pairs_paused";
public const string GaugeFilesTotal = "lightless_files";

View File

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