mirror of
https://github.com/JogmansonReal/Radicade.git
synced 2026-10-26 07:29:00 -07:00
82 lines
3.0 KiB
C#
82 lines
3.0 KiB
C#
using System.Text.Json;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using RadicadeServer.API.Studio;
|
|
|
|
namespace RadicadeServer.CDN
|
|
{
|
|
/// <summary>
|
|
/// Step one of the client's two-step bundle download. The client asks
|
|
/// <c>/rooms/unity_assets/{assetId}/{target}/{version}</c> and is handed a file name, then
|
|
/// ranges over that file at <c>/data/{Filename}</c> (and, for a subroom's bundle, under the
|
|
/// CDN's own <c>/unity/{Filename}</c> alias).
|
|
///
|
|
/// The id arrives in two shapes and both have to be answered. A Studio manifest id is 40
|
|
/// alphanumerics and its baked bundles are named in the manifest's own metadata. A legacy
|
|
/// bundle is stored under its file name (or that name minus <c>.assetbundle</c>), and that
|
|
/// name is what the subroom's <c>UnityAssetId</c> carries - every imported room, the built-in
|
|
/// rooms and every room bound from the admin panel. Answering only the 40-character shape
|
|
/// leaves every legacy bundle unresolvable, and the client reports one 400 as
|
|
/// "Error downloading room assets" for the whole room.
|
|
/// </summary>
|
|
[Route("rooms/")]
|
|
public class UnityAssetsCDN : Controller
|
|
{
|
|
[HttpGet("unity_assets/{assetId}/{target}/{version}")]
|
|
public async Task<IActionResult> GetUnityAsset(string assetId, int target, int version)
|
|
{
|
|
return await ServeMetadataAsync(assetId, target, version);
|
|
}
|
|
|
|
[HttpGet("unity_assets/{assetId}")]
|
|
public async Task<IActionResult> GetUnityAsset(string assetId)
|
|
{
|
|
return await ServeMetadataAsync(assetId, 0, 1);
|
|
}
|
|
|
|
private async Task<IActionResult> ServeMetadataAsync(string assetId, int target, int version)
|
|
{
|
|
if (!CdnStorageNames.IsServable(assetId) || target < 0 || target > byte.MaxValue || version < 0)
|
|
return BadRequest();
|
|
|
|
string? filename = null;
|
|
string? rejectedDependencies = null;
|
|
|
|
if (StudioUnityAssetRegistry.IsValidAssetId(assetId))
|
|
{
|
|
var asset = await StudioUnityAssetRegistry.ReadAsync(assetId, HttpContext.RequestAborted);
|
|
var baked = asset?.BakedUnityAssets.FirstOrDefault(x => x.Target == target && x.Version == version);
|
|
|
|
if (baked != null)
|
|
{
|
|
filename = baked.Filename;
|
|
rejectedDependencies = baked.RejectedDependenciesFilename;
|
|
}
|
|
else if (asset != null)
|
|
{
|
|
// The manifest exists, so the file on disk under this id is that JSON
|
|
// manifest and not a bundle. A target/version it does not name is a 404:
|
|
// handing the manifest over as the bundle would have the client parse
|
|
// metadata as an asset bundle.
|
|
return NotFound();
|
|
}
|
|
}
|
|
|
|
// Reached for every legacy id, and for a 40-character id with no manifest behind it:
|
|
// the bundle is the file stored under the name the subroom points at, with or without
|
|
// the .assetbundle suffix an import appends.
|
|
filename ??= CdnStorageNames.Resolve(assetId);
|
|
if (filename == null) return NotFound();
|
|
|
|
var body = JsonSerializer.Serialize(new
|
|
{
|
|
UnityAssetId = assetId,
|
|
Target = target,
|
|
Version = version,
|
|
Filename = filename,
|
|
RejectedDependenciesFilename = rejectedDependencies
|
|
});
|
|
return Content(body, "application/json");
|
|
}
|
|
}
|
|
}
|