Initial QMAX production app
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user