forked from amkovkov/GranuSightSoftware2
201 lines
8.5 KiB
C#
201 lines
8.5 KiB
C#
using System.CommandLine;
|
|
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.Hosting;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
|
using Avalonia;
|
|
using Avalonia.OpenGL.Egl;
|
|
|
|
using GSS2.Core.Logging;
|
|
using GSS2.Core;
|
|
using GSS2.Core.Analysis.AmineContent.Database.Calibration;
|
|
using GSS2.Core.Analysis.AmineContent.Database.Results;
|
|
|
|
namespace GSS2.Commands;
|
|
|
|
public static class UI
|
|
{
|
|
public enum RenderingModes
|
|
{
|
|
X11,
|
|
DRM
|
|
}
|
|
|
|
public static readonly RootCommand RootCommand;
|
|
public static readonly Command Command;
|
|
public static readonly Option<bool> Fullscreen;
|
|
public static readonly Option<RenderingModes> RenderingMode;
|
|
public static readonly Option<bool> HideConsole;
|
|
|
|
static UI()
|
|
{
|
|
// Создаём команды, опции, аргументы и пр.
|
|
RootCommand = new("Запустить графическое приложение");
|
|
Command = new("ui")
|
|
{
|
|
Description = "Запустить графическое приложение"
|
|
};
|
|
Fullscreen = new("--fullscreen", ["-f"])
|
|
{
|
|
Description = "Запустить приложение в полноэкранном режиме",
|
|
};
|
|
RenderingMode = new("--mode", ["--rendering-mode", "-m"])
|
|
{
|
|
Description = "Режим рендеринга",
|
|
DefaultValueFactory = (_) => RenderingModes.X11
|
|
};
|
|
HideConsole = new("--hide-console", ["--no-console", "-c"])
|
|
{
|
|
Description = "Отключить вывод в консоль",
|
|
DefaultValueFactory = (result) => result.GetValue(RenderingMode) == RenderingModes.DRM
|
|
};
|
|
|
|
// Изменяем описания стандартных опций
|
|
Helper.TranslateDefaultOptionDescriptions(RootCommand);
|
|
|
|
// Наполняем команды
|
|
RootCommand.Add(Fullscreen);
|
|
RootCommand.Add(RenderingMode);
|
|
RootCommand.Add(HideConsole);
|
|
RootCommand.SetAction(CommandAction);
|
|
|
|
Command.Add(Fullscreen);
|
|
Command.Add(RenderingMode);
|
|
Command.Add(HideConsole);
|
|
Command.SetAction(CommandAction);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Получить команду как корневую
|
|
/// </summary>
|
|
public static RootCommand GetCommand() => RootCommand;
|
|
|
|
/// <summary>
|
|
/// Зарегистрировать команду как подкоманду
|
|
/// </summary>
|
|
/// <param name="command">Команда в которой необходимо зарегистрировать подкоманду</param>
|
|
public static void RegisterCommand(Command command) => command.Add(Command);
|
|
|
|
private static void CommandAction(ParseResult result)
|
|
{
|
|
/// Получаем значения аргументов командной строки
|
|
var fullscreen = result.GetValue(Fullscreen);
|
|
var renderingMode = result.GetValue(RenderingMode);
|
|
var hideConsole = result.GetValue(HideConsole);
|
|
|
|
// Если выбран режим рендеринга DRM, то приложение будет рисоваться вместе с консолью,
|
|
// поэтому если не перехватить консоль, то вывод в неё будет рисоваться вместе с интерфейсом
|
|
if (hideConsole)
|
|
SilenceConsole();
|
|
|
|
// Собираем хост
|
|
var host = BuildHost();
|
|
|
|
// Запускаем хост асинхронно без блокировки потока
|
|
_ = host.RunAsync();
|
|
|
|
// Собираем графическое приложение
|
|
var ui = BuildApplication(host, fullscreen);
|
|
switch (renderingMode)
|
|
{
|
|
case RenderingModes.X11:
|
|
// Если мы запускаемся под X11,
|
|
// то очевидно у нас есть полноценный рабочий стол,
|
|
// поэтому запускаем графический интерфейс в классическом режиме с главным окном
|
|
ui.StartWithClassicDesktopLifetime(Program.Args);
|
|
break;
|
|
case RenderingModes.DRM:
|
|
// Если мы запускаемся в DRM (Direct Rendering Mode),
|
|
// то у нас нет рабочего стола и окон,
|
|
// потому что отрисовка (вроде как) идёт напрямую в кадровый буфер,
|
|
// поэтому запускаем графический интерфейс в DRM.
|
|
// Если работает X11, или любая другая графическая система,
|
|
// то запустить приложение в DRM не получится,
|
|
// потому что DRI (Direct Rendering Interface) занят этой графической системой
|
|
// TODO: Подумать над тем, чтобы брать DRI и scale для DRM рендеринга из переменных среды
|
|
// TODO: Подумать над тем, чтобы при запуске в DRM убивать приложения, которые занимают DRI
|
|
ui.StartLinuxDrm(Program.Args, "/dev/dri/card1", 1.0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
private static void SilenceConsole()
|
|
{
|
|
var start = new ThreadStart(() =>
|
|
{
|
|
Console.CursorVisible = false;
|
|
while (true)
|
|
Console.ReadKey(true);
|
|
});
|
|
var thread = new Thread(start)
|
|
{
|
|
IsBackground = true
|
|
};
|
|
thread.Start();
|
|
}
|
|
|
|
private static IHost BuildHost()
|
|
{
|
|
// Создаём хост
|
|
var builder = Host.CreateApplicationBuilder();
|
|
|
|
// Добавляем конфигурацию из appsettings.json
|
|
builder.Configuration.AddAppSettingsJson();
|
|
|
|
// Конфигурируем логгер
|
|
builder.Logging.ConfigureLogging();
|
|
builder.Services.AddSingleton<LibCameraLogSink>();
|
|
|
|
// Добавляем сервисы баз данных
|
|
builder.Services.AddAmineContentCalibrationContext(builder.Configuration);
|
|
builder.Services.AddAmineContentResultsContext(builder.Configuration);
|
|
|
|
// Добавляем сервисы аппаратной части и прочее
|
|
builder.Services.AddLightsService("Hardware:Lights");
|
|
builder.Services.AddTemperatureHumidityService("Hardware:TemperatureHumidity");
|
|
builder.Services.AddIlluminatorService("Hardware:Illuminator");
|
|
builder.Services.AddCameraService("Hardware:Camera", true);
|
|
builder.Services.AddComputeResourcesService();
|
|
builder.Services.AddImageStorageService(new DirectoryInfo("images"));
|
|
|
|
// Добавляем элементы интерфейса как сервисы
|
|
builder.Services.AddViewsAndModels();
|
|
|
|
// Собираем хост
|
|
var host = builder.Build();
|
|
|
|
// Поскольку LibCameraLogSink, который перенаправляет логи из libcamera в хост,
|
|
// не будет создан ни одним из других сервисов, его необходимо создать превентивно
|
|
host.Services.GetRequiredService<LibCameraLogSink>();
|
|
|
|
// Применяем миграции баз данных если их схема данных изменялась
|
|
using (var scope = host.Services.CreateScope())
|
|
{
|
|
var context = scope.ServiceProvider.GetRequiredService<AmineContentCalibrationContext>();
|
|
context.Database.Migrate();
|
|
}
|
|
using (var scope = host.Services.CreateScope())
|
|
{
|
|
var context = scope.ServiceProvider.GetRequiredService<AmineContentResultsContext>();
|
|
context.Database.Migrate();
|
|
}
|
|
|
|
return host;
|
|
}
|
|
|
|
private static AppBuilder BuildApplication(IHost host, bool fullscreen) =>
|
|
AppBuilder.Configure(() => new Application(host.Services, fullscreen))
|
|
.UsePlatformDetect()
|
|
.UseSkia()
|
|
.LogToTrace()
|
|
.With(new X11PlatformOptions
|
|
{
|
|
RenderingMode = [X11RenderingMode.Egl]
|
|
})
|
|
.With(new EglDisplayOptions
|
|
{
|
|
SupportsContextSharing = true
|
|
});
|
|
}
|