using System.Runtime.CompilerServices; using Explorer.Hosting; using Explorer.Hosting.Ipc; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Serilog; using Serilog.Extensions.Logging; namespace Explorer.Host; internal static class HostEntry { public static async Task RunAsync(string[] args, Action boot) { using var loggerFactory = new SerilogLoggerFactory(Log.Logger, dispose: false); var deferred = new DeferredServiceProvider(); var pipe = new WorkbenchPipeServer( deferred, new WorkbenchIpcOptions(), loggerFactory.CreateLogger()); await pipe.StartAsync(CancellationToken.None).ConfigureAwait(false); await pipe.Listening.WaitAsync(TimeSpan.FromSeconds(5)).ConfigureAwait(false); boot("Pipe listening"); Log.Information("Named pipe {Pipe} is listening; loading the rest of the host", new WorkbenchIpcOptions().PipeName); using var stopping = new CancellationTokenSource(); pipe.ShutdownRequested = () => stopping.Cancel(); using var tray = new HostTray(pipe.RequestShutdown); tray.Start(); try { return await RunCoreAsync(args, deferred, boot, stopping.Token).ConfigureAwait(false); } finally { try { await pipe.StopAsync(CancellationToken.None).ConfigureAwait(false); } catch (Exception ex) { Log.Debug(ex, "Pipe server stop"); } } } [MethodImpl(MethodImplOptions.NoInlining)] private static async Task RunCoreAsync( string[] args, DeferredServiceProvider deferred, Action boot, CancellationToken shutdown) { if (shutdown.IsCancellationRequested) { return 0; } var builder = Microsoft.Extensions.Hosting.Host.CreateApplicationBuilder(args); builder.Services.Configure(options => options.ServicesStartConcurrently = true); builder.Services.AddExplorerHostProcess(); using var host = builder.Build(); using var stop = shutdown.Register(() => host.Services.GetRequiredService().StopApplication()); if (shutdown.IsCancellationRequested) { return 0; } await host.StartAsync().ConfigureAwait(false); deferred.Complete(host.Services); boot("Core ready"); Log.Information("Host core is ready"); try { await host.WaitForShutdownAsync().ConfigureAwait(false); } finally { await host.StopAsync().ConfigureAwait(false); } return 0; } }