94 lines
4.9 KiB
C#
94 lines
4.9 KiB
C#
using System.Net;
|
|
using adas_core.Authentication.Attributes;
|
|
using adas_core.Domain.Enums;
|
|
using adas_core.module.ProxyDevices.Services;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
|
namespace adas_core.Controllers;
|
|
|
|
[Route("proxy-devices")]
|
|
[ApiController]
|
|
public class ProxyDeviceController(IProxyDeviceService proxyDeviceService) : ControllerBase
|
|
{
|
|
/// <summary>
|
|
/// Retrieves a media stream for the specified device by delegating the request to the proxy device service.
|
|
/// When the proxy call is not successful, the upstream status code is returned as-is; otherwise the response
|
|
/// stream is forwarded with the original content type, falling back to "multipart/x-mixed-replace" when no
|
|
/// content type is provided, and the response content length is set when known.
|
|
/// </summary>
|
|
/// <param name="deviceId">The unique identifier of the device whose stream should be retrieved.</param>
|
|
/// <returns>A <see cref="FileStreamResult"/> containing the proxied device stream, or a <see cref="StatusCodeResult"/> reflecting the upstream HTTP status when the proxy call fails.</returns>
|
|
[HttpGet("{deviceId}")]
|
|
[AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
|
|
public async Task<IActionResult> GetStreamById(string deviceId)
|
|
{
|
|
var response = await proxyDeviceService.Process(deviceId);
|
|
if (!response.IsSuccessStatusCode) return new StatusCodeResult((int)response.StatusCode);
|
|
var stream = await response.Content.ReadAsStreamAsync();
|
|
if (response.Content.Headers.ContentLength > 0) Response.ContentLength = response.Content.Headers.ContentLength;
|
|
return new FileStreamResult(stream,
|
|
response.Content.Headers.ContentType?.ToString() ?? "multipart/x-mixed-replace"); // Set MIME type as needed
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves the content associated with the specified device by proxying the request through the device service.
|
|
/// Forwards the upstream content length and content type headers to the response when available, and returns the resulting content as a stream.
|
|
/// </summary>
|
|
/// <param name="deviceId">The unique identifier of the device whose content is being requested.</param>
|
|
/// <returns>An <see cref="IActionResult"/> containing the proxied content stream for the specified device.</returns>
|
|
[HttpGet("{deviceId}/content")]
|
|
[AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
|
|
public async Task<IActionResult> GetContentById(string deviceId)
|
|
{
|
|
var response = await proxyDeviceService.Process(deviceId);
|
|
var content = await response.Content.ReadAsStreamAsync();
|
|
if (response.Content.Headers.ContentLength > 0) Response.ContentLength = response.Content.Headers.ContentLength;
|
|
if (response.Content.Headers.ContentType != null)
|
|
Response.ContentType = response.Content.Headers.ContentType?.ToString() ?? "";
|
|
return Ok(content);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Streams MJPEG video from the specified device by proxying the request through an external service and writing the response body to the client.
|
|
/// Forwards the upstream status code when the proxy call is not successful, defaults the response content type to <c>multipart/x-mixed-replace</c> when none is provided, and returns 404 (or the original status code) if the upstream request fails.
|
|
/// </summary>
|
|
/// <param name="deviceId">The identifier of the device whose MJPEG stream should be retrieved and forwarded to the caller.</param>
|
|
[HttpGet("{deviceId}/mjpeg-stream")]
|
|
[AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
|
|
public async Task GetAsMpegStreamById(string deviceId)
|
|
{
|
|
try
|
|
{
|
|
|
|
using var cts = CancellationTokenSource.CreateLinkedTokenSource(HttpContext.RequestAborted);
|
|
//cts.CancelAfter(TimeSpan.FromMinutes(5));
|
|
|
|
var response = await proxyDeviceService.Stream(deviceId);
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
{
|
|
Response.StatusCode = (int)response.StatusCode;
|
|
return;
|
|
}
|
|
|
|
if (response.Content.Headers.ContentType != null)
|
|
Response.ContentType = response.Content.Headers.ContentType?.ToString() ??
|
|
"multipart/x-mixed-replace;boundary=my-boundary";
|
|
await using var stream = await response.Content.ReadAsStreamAsync(cts.Token);
|
|
// Buffer for reading the stream
|
|
var buffer = new byte[4096];
|
|
int bytesRead;
|
|
|
|
|
|
while (!cts.Token.IsCancellationRequested && (bytesRead = await stream.ReadAsync(buffer, cts.Token)) > 0)
|
|
{
|
|
await Response.Body.WriteAsync(buffer.AsMemory(0, bytesRead), cts.Token);
|
|
await Response.Body.FlushAsync(cts.Token);
|
|
}
|
|
}
|
|
catch (HttpRequestException e)
|
|
{
|
|
Response.StatusCode = (int)(e.StatusCode ?? HttpStatusCode.NotFound);
|
|
}
|
|
}
|
|
} |