sozsoft-platform/api/src/Sozsoft.Platform.HttpApi.Host/Controllers/SetupController.cs
2026-06-04 13:11:31 +03:00

167 lines
5.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Diagnostics;
using System.IO;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
namespace Sozsoft.Platform.Controllers;
/// <summary>
/// DB hazır olduğunda bile /setup sayfasından migration çalıştırmaya olanak tanır.
/// </summary>
[Route("api/setup")]
[Authorize(Roles = "admin")]
public class SetupController : ControllerBase
{
private readonly IConfiguration _configuration;
private readonly IHostEnvironment _env;
public SetupController(
IConfiguration configuration,
IHostEnvironment env)
{
_configuration = configuration;
_env = env;
}
[HttpGet("application-status")]
[AllowAnonymous]
public IActionResult Status()
{
return Ok(new { dbExists = SetupAppRunner.DatabaseIsReady(_configuration) });
}
[HttpPost("migrate")]
public async Task Migrate(CancellationToken ct)
{
Response.ContentType = "text/event-stream; charset=utf-8";
Response.Headers["Cache-Control"] = "no-cache, no-store";
Response.Headers["X-Accel-Buffering"] = "no";
await Response.Body.FlushAsync(ct);
async Task Send(string level, string message)
{
try
{
var payload = JsonSerializer.Serialize(new { level, message });
await Response.WriteAsync($"data: {payload}\n\n", ct);
await Response.Body.FlushAsync(ct);
}
catch { }
}
var migratorPath = _configuration["Setup:MigratorPath"]
?? Path.GetFullPath(Path.Combine(_env.ContentRootPath, "..", "Sozsoft.Platform.DbMigrator"));
await Send("info", "Database migration and seeding are being initiated...");
await Send("info", $"Migrator path: {migratorPath}");
var extraArgs = _configuration["Setup:MigratorArgs"] ?? "--Seed=true";
string fileName;
string arguments;
string workingDirectory;
if (migratorPath.EndsWith(".dll", StringComparison.OrdinalIgnoreCase) && System.IO.File.Exists(migratorPath))
{
fileName = "dotnet";
arguments = $"\"{migratorPath}\" {extraArgs}";
workingDirectory = Path.GetDirectoryName(migratorPath)!;
}
else if (Directory.Exists(migratorPath))
{
var dllFiles = Directory.GetFiles(migratorPath, "*.DbMigrator.dll", SearchOption.TopDirectoryOnly);
if (dllFiles.Length == 0)
dllFiles = Directory.GetFiles(migratorPath, "*Migrator*.dll", SearchOption.TopDirectoryOnly);
if (dllFiles.Length > 0)
{
fileName = "dotnet";
arguments = $"\"{dllFiles[0]}\" {extraArgs}";
workingDirectory = migratorPath;
}
else
{
fileName = "dotnet";
arguments = $"run --project \"{migratorPath}\" -- {extraArgs}";
workingDirectory = migratorPath;
}
}
else
{
await Send("error", $"Migrator path not found or invalid: {migratorPath}");
await Send("done", "Failed.");
return;
}
await Send("info", $"Running: {fileName} {arguments}");
Process? process = null;
try
{
process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = fileName,
Arguments = arguments,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true,
WorkingDirectory = workingDirectory,
}
};
process.Start();
async Task ReadStream(StreamReader reader, string level)
{
try
{
while (await reader.ReadLineAsync(ct) is { } line)
{
await Send(level, line);
}
}
catch (OperationCanceledException) { }
}
await Task.WhenAll(
ReadStream(process.StandardOutput, "info"),
ReadStream(process.StandardError, "warn"));
await process.WaitForExitAsync(ct);
if (process.ExitCode == 0)
{
await Send("success", "Migration and seed completed successfully.");
await Send("done", "Completed.");
}
else
{
await Send("error", $"Migration failed. Exit code: {process.ExitCode}");
await Send("done", "Failed.");
}
}
catch (OperationCanceledException)
{
await Send("warn", "Migration request was canceled.");
}
catch (Exception ex)
{
await Send("error", $"Migration failed: {ex.Message}");
await Send("done", "Failed.");
}
finally
{
process?.Dispose();
}
}
}