Skip to content

Commit

Permalink
Rework direct content download a bit
Browse files Browse the repository at this point in the history
  • Loading branch information
compujuckel committed Feb 10, 2024
1 parent c721a8f commit 5696f30
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 129 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@ public class CMContentEntry
public string? Url { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.Always)]
public string? File { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public bool? Direct { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public bool Direct => File != null;
}
53 changes: 28 additions & 25 deletions AssettoServer/Network/Http/ContentManagerController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using AssettoServer.Server.CMContentProviders;
using AssettoServer.Server.Configuration;
using AssettoServer.Utils;
using Microsoft.AspNetCore.Mvc;
Expand All @@ -13,46 +12,47 @@ namespace AssettoServer.Network.Http;
[ApiController]
public class ContentManagerController : ControllerBase
{
private readonly ICMContentProvider _contentProvider;
private readonly ACServerConfiguration _configuration;

public ContentManagerController(ICMContentProvider contentProvider, ACServerConfiguration configuration)
public ContentManagerController(ACServerConfiguration configuration)
{
_contentProvider = contentProvider;
_configuration = configuration;
}

[HttpGet("/content/car/{carId}")]
[HttpHead("/content/car/{carId}")]
public IActionResult GetCarZip(string carId, string password = "")
public IActionResult GetCarZip(string carId, string? password = null)
{
if (!ValidatePassword(password)) return Unauthorized();
if (_contentProvider.TryGetZipPath("cars",carId, out var car))
return CreateFileDownload(car);

return NotFound();
if (_configuration.ContentConfiguration?.Cars == null
|| !_configuration.ContentConfiguration.Cars.TryGetValue(carId, out var car)
|| car.File == null) return NotFound();

return CreateFileDownload(car.File);
}

[HttpGet("/content/skin/{carId}/{skinId}")]
[HttpHead("/content/skin/{carId}/{skinId}")]
public IActionResult GetSkinZip(string carId, string skinId, string password = "")
public IActionResult GetSkinZip(string carId, string skinId, string? password = null)
{
if (!ValidatePassword(password)) return Unauthorized();
if (_contentProvider.TryGetZipPath("skins",$"{carId}/{skinId}", out var skin))
return CreateFileDownload(skin);

return NotFound();
if (_configuration.ContentConfiguration?.Cars == null
|| !_configuration.ContentConfiguration.Cars.TryGetValue(carId, out var car)
|| car.Skins == null
|| !car.Skins.TryGetValue(skinId, out var skin)
|| skin.File == null) return NotFound();

return CreateFileDownload(skin.File);
}

[HttpGet("/content/track/{trackId}")]
[HttpHead("/content/track/{trackId}")]
public IActionResult GetTrackZip(string trackId, string password = "")
[HttpGet("/content/track")]
[HttpHead("/content/track")]
public IActionResult GetTrackZip(string? password = null)
{
if (!ValidatePassword(password)) return Unauthorized();
if (_contentProvider.TryGetZipPath("tracks",trackId, out var track))
return CreateFileDownload(track);

return NotFound();
if (_configuration.ContentConfiguration?.Track?.File == null) return NotFound();

return CreateFileDownload(_configuration.ContentConfiguration.Track.File);
}

private FileStreamResult CreateFileDownload(string path)
Expand All @@ -66,11 +66,14 @@ private FileStreamResult CreateFileDownload(string path)
return File(fileStream, "application/zip", fileName);
}

private bool ValidatePassword(string input)
private bool ValidatePassword(string? input)
{
if (_configuration.Server.Password == null) return true;
if (_configuration.WrapperParams?.DownloadPasswordOnly != true) return true;
if (_configuration.Server.Password == null
|| _configuration.WrapperParams is { DownloadPasswordOnly: false }) return true;

return Convert.FromHexString(input).SequenceEqual(SHA1.HashData(Encoding.UTF8.GetBytes($"tanidolizedhoatzin{_configuration.Server.Password}")));
return input != null ?
Convert.FromHexString(input)
.SequenceEqual(SHA1.HashData(Encoding.UTF8.GetBytes($"tanidolizedhoatzin{_configuration.Server.Password}")))
: false;
}
}
1 change: 0 additions & 1 deletion AssettoServer/Server/ACServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,6 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
_entryCarManager.Initialize();
_checksumManager.Initialize();
_sessionManager.Initialize();
_cmContentProvider.Initialize();
await _trackParamsProvider.InitializeAsync();
await _geoParamsManager.InitializeAsync();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,113 +1,20 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Threading.Tasks;
using AssettoServer.Server.Configuration;
using AssettoServer.Shared.Network.Http.Responses;

namespace AssettoServer.Server.CMContentProviders;

public class DefaultCMContentProvider : ICMContentProvider
{
private readonly ACServerConfiguration _configuration;
private readonly CMContentConfiguration? _contentConfiguration;

private readonly Dictionary<string, string> _carIndex = [];
private readonly Dictionary<string, string> _skinIndex = [];
private readonly Dictionary<string, string> _trackIndex = [];

public DefaultCMContentProvider(ACServerConfiguration configuration)
{
_configuration = configuration;
_contentConfiguration = configuration.ContentConfiguration;

if (_contentConfiguration?.Track != null)
_contentConfiguration.Track.Direct = _contentConfiguration?.Track?.File != null ? true : null;

if (_contentConfiguration?.Cars == null) return;
foreach (var (_, car) in _contentConfiguration.Cars)
{
car.Direct = car.File != null ? true : null;

if (car.Skins == null) continue;
foreach (var (_, skin) in car.Skins)
{
skin.Direct = skin.File != null ? true : null;
}
}
}

public ValueTask<CMContentConfiguration?> GetContentAsync(ulong guid)
{
return ValueTask.FromResult(_contentConfiguration);
}

public void Initialize()
{
if (_contentConfiguration == null) return;

if (_contentConfiguration.Track != null)
{
var trackEntry = _configuration.Server.Track.Split('/').Last();
PrepareTrackDownload(trackEntry, _contentConfiguration.Track);
}

if (_contentConfiguration.Cars == null) return;
foreach (var car in _contentConfiguration.Cars)
{
PrepareCarDownload(car.Key, car.Value);
}
}

private void PrepareCarDownload(string carId, CMContentEntryCar car)
{
if (car.Direct != true) return;

var zipPath = car.File;

if (Path.Exists(zipPath))
_carIndex.Add(carId, zipPath);

if (car.Skins == null) return;
foreach (var (skinId, skin) in car.Skins)
PrepareSkinDownload(carId, skinId, skin);
}

private void PrepareSkinDownload(string parentId, string skinId, CMContentEntry skin)
{
if (skin.Direct != true) return;

var zipPath = skin.File;

if (Path.Exists(zipPath))
_skinIndex.Add($"{parentId}/{skinId}", zipPath);
}

private void PrepareTrackDownload(string trackId, CMContentEntryVersionized track)
{
if (track.Direct != true) return;

var zipPath = track.File;

if (Path.Exists(zipPath))
_trackIndex.Add(trackId, zipPath);
}

public bool TryGetZipPath(string type, string entry, [NotNullWhen(true)] out string? path)
{
switch (type)
{
case "cars":
return _carIndex.TryGetValue(entry, out path);
case "skins":
return _skinIndex.TryGetValue(entry, out path);
case "tracks":
return _trackIndex.TryGetValue(entry, out path);
}

path = default;
return false;
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
using System.Threading.Tasks;
using AssettoServer.Shared.Network.Http.Responses;

namespace AssettoServer.Server.CMContentProviders;

public interface ICMContentProvider
{
public ValueTask<CMContentConfiguration?> GetContentAsync(ulong guid);

public void Initialize();

public bool TryGetZipPath(string type, string entry, [NotNullWhen(true)] out string? path);
}
2 changes: 1 addition & 1 deletion AssettoServer/Server/Configuration/CMWrapperParams.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ public class CMWrapperParams
public long DownloadSpeedLimit { get; init; } = 0;

[JsonPropertyName("downloadPasswordOnly")]
public bool? DownloadPasswordOnly { get; set; }
public bool DownloadPasswordOnly { get; set; }
}

0 comments on commit 5696f30

Please sign in to comment.