w4c-workflows-api/Controllers/BinaryController.cs
2026-09-12 01:02:46 +03:00

64 lines
2.2 KiB
C#

using Microsoft.AspNetCore.Mvc;
using w4c_workflows.Filters;
using w4c_workflows.Models.Nodes;
using w4c_workflows.Services.Nodes.Binary;
namespace w4c_workflows.Controllers;
/// <summary>
/// Streams binary payloads referenced by run items. Items carry only an opaque,
/// content-addressed <c>assetId</c>; the bytes live in <see cref="IBinaryStore"/>.
/// The node catalog's HTTP/binary nodes write assets here, and the run panel's
/// item preview reads them back (inline preview with <c>?download=false</c>, or
/// a named download with <c>?download=true</c>).
/// </summary>
[ApiController]
[Route("api/binary")]
public class BinaryController : ControllerBase
{
private readonly IBinaryStore _store;
public BinaryController(IBinaryStore store)
{
_store = store;
}
/// <summary>Streams one stored asset. 404 when the id is unknown/malformed.</summary>
[HttpGet("{assetId}")]
[RequireScope("read")]
public async Task<IActionResult> Get(string assetId, [FromQuery] bool download = false, CancellationToken ct = default)
{
var meta = await _store.DescribeAsync(assetId, ct);
var stream = await _store.OpenAsync(assetId, ct);
if (stream == null)
return NotFound(new { error = "Asset not found." });
var contentType = meta?.MimeType ?? "application/octet-stream";
var fileName = SafeFileName(meta?.FileName) ?? "asset";
return download
? File(stream, contentType, fileName)
: File(stream, contentType);
}
/// <summary>Asset metadata only — used to label binary chips without downloading.</summary>
[HttpGet("{assetId}/meta")]
[RequireScope("read")]
public async Task<IActionResult> Meta(string assetId, CancellationToken ct)
{
var meta = await _store.DescribeAsync(assetId, ct);
if (meta == null)
return NotFound(new { error = "Asset not found." });
return Ok(meta);
}
private static string? SafeFileName(string? name)
{
if (string.IsNullOrWhiteSpace(name))
return null;
var trimmed = name.Replace('\\', '/');
var slash = trimmed.LastIndexOf('/');
return slash >= 0 ? trimmed[(slash + 1)..] : trimmed;
}
}