public static async Task Main(string[] args) { var worker = false; var baseUrl = string.Empty; int processId = 0; for (var i = 0; i < args.Length; i++) { if (args[i].Equals("--worker", StringComparison.OrdinalIgnoreCase)) { worker = true; } if (args[i].Equals("--baseurl", StringComparison.OrdinalIgnoreCase) && i + 1 < args.Length) { baseUrl = args[i + 1]; } if (args[i].Equals("--process-id", StringComparison.OrdinalIgnoreCase) && i + 1 < args.Length) { if (!int.TryParse(args[i + 1], out processId)) { processId = 0; } } } if (worker && !string.IsNullOrWhiteSpace(baseUrl)) { await WorkerBootstrapper.Start(baseUrl, processId); return; } var hasDebugEnabled = ApplicationDataHelper.HasDebugEnabled(Constants.AppName); #if RELEASE SetupReleaseLogging(hasDebugEnabled); #else SetupDebugLogging(); #endif Log.Information("Imager starting"); Log.Information($"OS: {OperatingSystem.OsDescription}"); try { CreateHostBuilder(args).Build().Run(); } catch (Exception e) { Log.Fatal(e, "Host terminated unexpectedly"); throw; } finally { Log.CloseAndFlush(); } }
private async Task ElectronBootstrap(string appPath) { if (!HybridSupport.IsElectronActive) { return; } var browserWindow = await Electron.WindowManager.CreateWindowAsync( new BrowserWindowOptions { Width = 1280, Height = 720, Center = true, BackgroundColor = "#1A2933", Frame = false, WebPreferences = new WebPreferences { NodeIntegration = true, }, Show = false, Icon = Path.Combine(appPath, "ClientApp", "build", "icon.ico") }); browserWindow.RemoveMenu(); await browserWindow.WebContents.Session.ClearCacheAsync(); browserWindow.OnClosed += () => Electron.App.Quit(); browserWindow.OnReadyToShow += () => browserWindow.Show(); browserWindow.OnMaximize += () => Electron.IpcMain.Send(browserWindow, "window-maximized"); browserWindow.OnUnmaximize += () => Electron.IpcMain.Send(browserWindow, "window-unmaximized"); if (ApplicationDataHelper.HasDebugEnabled(Constants.AppName)) { browserWindow.WebContents.OpenDevTools(); } Electron.IpcMain.On("minimize-window", _ => browserWindow.Minimize()); Electron.IpcMain.On("maximize-window", _ => browserWindow.Maximize()); Electron.IpcMain.On("unmaximize-window", _ => browserWindow.Unmaximize()); Electron.IpcMain.On("close-window", _ => browserWindow.Close()); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddSignalR(o => { o.EnableDetailedErrors = ApplicationDataHelper.HasDebugEnabled(Constants.AppName); o.MaximumReceiveMessageSize = 1024 * 1024; }); services.AddControllersWithViews().AddJsonOptions(options => { options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); }); // In production, the React files will be served from this directory services.AddSpaStaticFiles(configuration => { configuration.RootPath = "ClientApp/build"; }); services.AddHostedService <QueuedHostedService>(); services.AddSingleton <IBackgroundTaskQueue>(new BackgroundTaskQueue(100)); services.AddHostedService <BackgroundTaskService>(); services.AddSingleton <IActiveBackgroundTaskList>(new ActiveBackgroundTaskList()); services.AddSingleton(new AppState { AppPath = AppContext.BaseDirectory, ExecutingFile = WorkerHelper.GetExecutingFile(), IsLicenseAgreed = ApplicationDataHelper.IsLicenseAgreed(Constants.AppName), IsAdministrator = OperatingSystem.IsAdministrator(), IsElectronActive = HybridSupport.IsElectronActive, UseFake = Debugger.IsAttached, IsWindows = OperatingSystem.IsWindows(), IsMacOs = OperatingSystem.IsMacOs(), IsLinux = OperatingSystem.IsLinux() }); services.AddSingleton <PhysicalDriveManagerFactory>(); services.AddSingleton <WorkerService>(); }
public static async Task Start(string baseUrl, int processId) { var hasDebugEnabled = ApplicationDataHelper.HasDebugEnabled(Constants.AppName); #if RELEASE SetupReleaseLogging(hasDebugEnabled); #else SetupDebugLogging(); #endif var serviceCollection = new ServiceCollection(); ConfigureServices(serviceCollection); var serviceProvider = serviceCollection.BuildServiceProvider(); var loggerFactory = serviceProvider.GetService <ILoggerFactory>(); var logger = serviceProvider.GetService <ILogger <Program> >(); if (processId > 0) { KillOtherWorkers(logger, processId); } logger.LogDebug($"Connecting to base url '{baseUrl}'"); var progressHubConnection = new HubConnectionBuilder() .WithUrl($"{baseUrl}/hubs/progress") .WithAutomaticReconnect() .ConfigureLogging(logging => { if (!hasDebugEnabled) { return; } logging.AddSerilog(); }) .Build(); var errorHubConnection = new HubConnectionBuilder() .WithUrl($"{baseUrl}/hubs/error") .WithAutomaticReconnect() .ConfigureLogging(logging => { if (!hasDebugEnabled) { return; } logging.AddSerilog(); }) .Build(); var workerHubConnection = new HubConnectionBuilder() .WithUrl($"{baseUrl}/hubs/worker") .WithAutomaticReconnect() .ConfigureLogging(logging => { if (!hasDebugEnabled) { return; } logging.AddSerilog(); }) .Build(); var resultHubConnection = new HubConnectionBuilder() .WithUrl($"{baseUrl}/hubs/result") .WithAutomaticReconnect() .ConfigureLogging(logging => { if (!hasDebugEnabled) { return; } logging.AddSerilog(); }) .Build(); await progressHubConnection.StartAsync(); await errorHubConnection.StartAsync(); await workerHubConnection.StartAsync(); await resultHubConnection.StartAsync(); logger.LogDebug($"ProgressHubConnection = {progressHubConnection.State}"); logger.LogDebug($"ErrorHubConnection = {errorHubConnection.State}"); logger.LogDebug($"WorkerHubConnection = {workerHubConnection.State}"); logger.LogDebug($"ResultHubConnection = {resultHubConnection.State}"); var physicalDriveManagerFactory = new PhysicalDriveManagerFactory(loggerFactory); var backgroundTaskQueue = new BackgroundTaskQueue(100); var activeBackgroundTaskList = new ActiveBackgroundTaskList(); var queuedHostedService = new QueuedHostedService(backgroundTaskQueue, activeBackgroundTaskList, loggerFactory.CreateLogger <QueuedHostedService>()); var backgroundTaskHandler = new BackgroundTaskHandler( loggerFactory.CreateLogger <BackgroundTaskHandler>(), loggerFactory, progressHubConnection, errorHubConnection, resultHubConnection, physicalDriveManagerFactory.Create(), activeBackgroundTaskList, backgroundTaskQueue); await queuedHostedService.StartAsync(CancellationToken.None); workerHubConnection.On <BackgroundTask>(Constants.HubMethodNames.RunBackgroundTask, async(task) => { logger.LogDebug($"Start handle background task type '{task.Type}' with payload '{task.Payload}'"); try { await backgroundTaskHandler.Handle(task); logger.LogDebug($"End handle background task type '{task.Type}' with payload '{task.Payload}'"); } catch (Exception e) { logger.LogError(e, $"Failed to handle background task '{task.Type}' with payload '{task.Payload}'"); } }); workerHubConnection.On(Constants.HubMethodNames.CancelBackgroundTask, () => { logger.LogDebug("Cancel background task"); try { activeBackgroundTaskList.CancelAll(); } catch (Exception e) { logger.LogError(e, "Failed to cancel background task"); } }); var workerProcessId = Process.GetCurrentProcess().Id; logger.LogDebug($"Worker process id '{workerProcessId}'"); await workerHubConnection.WorkerProcess(workerProcessId); logger.LogDebug("Worker is ready"); var pingFailed = 0; var maxPingFailed = 3; while (true) { await Task.Delay(5000); try { await workerHubConnection.WorkerPing(); pingFailed = 0; } catch (Exception) { pingFailed++; } if (pingFailed <= maxPingFailed) { continue; } logger.LogInformation($"Stopping worker after ping failed {maxPingFailed} times"); return; } }