using Microsoft.AspNetCore.Mvc;
namespace DeepDrftPublic.Controllers;
///
/// Proxies the public release read surface (Phase 9) to DeepDrftAPI so the browser never
/// makes a cross-origin request. Mirrors : the WASM client
/// issues relative api/release/* requests against this host, which forwards them
/// upstream. SSR prerender calls DeepDrftAPI directly via the same named client — no proxy
/// hop on the server side. All forwarded routes are unauthenticated reads.
///
[ApiController]
[Route("api/release")]
public class ReleaseProxyController : ControllerBase
{
private readonly HttpClient _upstream;
private readonly ILogger _logger;
public ReleaseProxyController(IHttpClientFactory httpClientFactory, ILogger logger)
{
_upstream = httpClientFactory.CreateClient("DeepDrft.API");
_logger = logger;
}
/// Proxies the paged release list, forwarding the optional medium filter and sort params.
[HttpGet]
public async Task GetReleases(
[FromQuery] string? medium = null,
[FromQuery] int page = 1,
[FromQuery] int pageSize = 20,
[FromQuery] string? sortColumn = null,
[FromQuery] bool sortDescending = false,
CancellationToken ct = default)
{
var query = $"api/release?page={page}&pageSize={pageSize}&sortDescending={sortDescending}";
if (!string.IsNullOrWhiteSpace(medium))
query += $"&medium={Uri.EscapeDataString(medium)}";
if (!string.IsNullOrWhiteSpace(sortColumn))
query += $"&sortColumn={Uri.EscapeDataString(sortColumn)}";
return await RelayJson(query, "release list");
}
/// Proxies the Mix waveform datum. A 404 (no datum stored) passes through verbatim.
[HttpGet("{id:long}/mix/waveform")]
public async Task GetMixWaveform(long id, CancellationToken ct = default)
=> await RelayJson($"api/release/{id}/mix/waveform", $"release {id} mix waveform", ct);
/// Proxies a single release. A 404 (no such release) passes through verbatim.
[HttpGet("{id:long}")]
public async Task GetReleaseById(long id, CancellationToken ct = default)
=> await RelayJson($"api/release/{id}", $"release {id}", ct);
// Small JSON payloads, buffered and relayed. Non-success statuses (notably 404) pass through
// so the client renders them as valid states rather than collapsing to a 502.
private async Task RelayJson(string upstreamPath, string description, CancellationToken ct = default)
{
HttpResponseMessage upstream;
try
{
upstream = await _upstream.GetAsync(upstreamPath, HttpCompletionOption.ResponseHeadersRead, ct);
}
catch (Exception ex)
{
_logger.LogError(ex, "Upstream call to DeepDrftAPI {Description} failed", description);
return StatusCode(502, "Upstream unavailable");
}
using (upstream)
{
if (!upstream.IsSuccessStatusCode)
{
_logger.LogWarning("DeepDrftAPI {Description} returned {Status}", description, (int)upstream.StatusCode);
return StatusCode((int)upstream.StatusCode);
}
var json = await upstream.Content.ReadAsStringAsync(ct);
return Content(json, "application/json");
}
}
}