Files
QMAX/server/QMax.Api/Controllers/AppUpdatesController.cs
T
2026-07-03 22:39:48 +03:00

80 lines
2.5 KiB
C#

using System.Security.Cryptography;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using QMax.Api.Configuration;
using QMax.Api.Contracts;
namespace QMax.Api.Controllers;
[ApiController]
[Route("api/app-updates")]
public sealed class AppUpdatesController(IOptions<QMaxOptions> options) : ControllerBase
{
private readonly QMaxOptions _options = options.Value;
[AllowAnonymous]
[HttpGet("android/latest")]
public async Task<ActionResult<AppUpdateManifestDto>> Latest(CancellationToken cancellationToken)
{
var manifestPath = Path.Combine(_options.ReleasesPath, "android", "latest.json");
if (System.IO.File.Exists(manifestPath))
{
return PhysicalFile(manifestPath, "application/json");
}
var androidReleases = new DirectoryInfo(Path.Combine(_options.ReleasesPath, "android"));
if (!androidReleases.Exists)
{
return NotFound();
}
var apk = androidReleases
.GetFiles("*.apk")
.OrderByDescending(x => x.LastWriteTimeUtc)
.FirstOrDefault();
if (apk is null)
{
return NotFound();
}
var manifest = new AppUpdateManifestDto(
"qmax",
"QMAX",
"0.1.0",
1,
"stable",
"android",
"apk",
$"/api/app-updates/android/download/{Uri.EscapeDataString(apk.Name)}",
apk.Length,
await Sha256Async(apk.FullName, cancellationToken),
"QMAX local release",
apk.LastWriteTimeUtc);
return manifest;
}
[AllowAnonymous]
[HttpGet("android/download/{fileName}")]
public IActionResult Download(string fileName)
{
var safeName = Path.GetFileName(fileName);
var path = Path.Combine(_options.ReleasesPath, "android", safeName);
if (!System.IO.File.Exists(path) || !safeName.EndsWith(".apk", StringComparison.OrdinalIgnoreCase))
{
return NotFound();
}
return PhysicalFile(path, "application/vnd.android.package-archive", safeName, enableRangeProcessing: true);
}
private static async Task<string> Sha256Async(string path, CancellationToken cancellationToken)
{
await using var stream = System.IO.File.OpenRead(path);
var hash = await SHA256.HashDataAsync(stream, cancellationToken);
return Convert.ToHexString(hash).ToLowerInvariant();
}
}