737c423d9c
Retire the three-card overview for a search + medium + genre browser over all releases. Adds q/genre filter params to the api/release paged read path, mirroring the existing api/track/page TrackFilter pattern.
88 lines
3.8 KiB
C#
88 lines
3.8 KiB
C#
using Microsoft.AspNetCore.Mvc;
|
|
|
|
namespace DeepDrftPublic.Controllers;
|
|
|
|
/// <summary>
|
|
/// Proxies the public release read surface (Phase 9) to DeepDrftAPI so the browser never
|
|
/// makes a cross-origin request. Mirrors <see cref="TrackProxyController"/>: the WASM client
|
|
/// issues relative <c>api/release/*</c> 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.
|
|
/// </summary>
|
|
[ApiController]
|
|
[Route("api/release")]
|
|
public class ReleaseProxyController : ControllerBase
|
|
{
|
|
private readonly HttpClient _upstream;
|
|
private readonly ILogger<ReleaseProxyController> _logger;
|
|
|
|
public ReleaseProxyController(IHttpClientFactory httpClientFactory, ILogger<ReleaseProxyController> logger)
|
|
{
|
|
_upstream = httpClientFactory.CreateClient("DeepDrft.API");
|
|
_logger = logger;
|
|
}
|
|
|
|
/// <summary>Proxies the paged release list, forwarding the optional medium, search (q), genre, and sort params.</summary>
|
|
[HttpGet]
|
|
public async Task<ActionResult> GetReleases(
|
|
[FromQuery] string? medium = null,
|
|
[FromQuery] string? q = null,
|
|
[FromQuery] string? genre = 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(q))
|
|
query += $"&q={Uri.EscapeDataString(q)}";
|
|
if (!string.IsNullOrWhiteSpace(genre))
|
|
query += $"&genre={Uri.EscapeDataString(genre)}";
|
|
if (!string.IsNullOrWhiteSpace(sortColumn))
|
|
query += $"&sortColumn={Uri.EscapeDataString(sortColumn)}";
|
|
|
|
return await RelayJson(query, "release list");
|
|
}
|
|
|
|
/// <summary>Proxies the Mix waveform datum. A 404 (no datum stored) passes through verbatim.</summary>
|
|
[HttpGet("{id:long}/mix/waveform")]
|
|
public async Task<ActionResult> GetMixWaveform(long id, CancellationToken ct = default)
|
|
=> await RelayJson($"api/release/{id}/mix/waveform", $"release {id} mix waveform", ct);
|
|
|
|
/// <summary>Proxies a single release. A 404 (no such release) passes through verbatim.</summary>
|
|
[HttpGet("{id:long}")]
|
|
public async Task<ActionResult> 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<ActionResult> 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");
|
|
}
|
|
}
|
|
}
|