using System.Reflection; using NetMQ; using Phantom.Common.Messages.Web; using Phantom.Common.Messages.Web.ToController; using Phantom.Utils.Actor; using Phantom.Utils.Cryptography; using Phantom.Utils.IO; using Phantom.Utils.Logging; using Phantom.Utils.Rpc; using Phantom.Utils.Rpc.Sockets; using Phantom.Utils.Runtime; using Phantom.Utils.Tasks; using Phantom.Web; using Phantom.Web.Services; using Phantom.Web.Services.Rpc; var shutdownCancellationTokenSource = new CancellationTokenSource(); var shutdownCancellationToken = shutdownCancellationTokenSource.Token; PosixSignals.RegisterCancellation(shutdownCancellationTokenSource, static () => { PhantomLogger.Root.InformationHeading("Stopping Phantom Panel web..."); }); static void CreateFolderOrStop(string path, UnixFileMode chmod) { if (!Directory.Exists(path)) { try { Directories.Create(path, chmod); } catch (Exception e) { PhantomLogger.Root.Fatal(e, "Error creating folder: {FolderName}", path); throw StopProcedureException.Instance; } } } try { var fullVersion = AssemblyAttributes.GetFullVersion(Assembly.GetExecutingAssembly()); PhantomLogger.Root.InformationHeading("Initializing Phantom Panel web..."); PhantomLogger.Root.Information("Web version: {Version}", fullVersion); var (controllerHost, controllerPort, webKeyToken, webKeyFilePath, webServerHost, webServerPort, webBasePath) = Variables.LoadOrStop(); var webKey = await WebKey.Load(webKeyToken, webKeyFilePath); if (webKey == null) { return 1; } string dataProtectionKeysPath = Path.GetFullPath("./keys"); CreateFolderOrStop(dataProtectionKeysPath, Chmod.URWX); var (controllerCertificate, webToken) = webKey.Value; var administratorToken = TokenGenerator.Create(60); var applicationProperties = new ApplicationProperties(fullVersion, TokenGenerator.GetBytesOrThrow(administratorToken)); var rpcConfiguration = new RpcConfiguration("Web", controllerHost, controllerPort, controllerCertificate); var rpcSocket = RpcClientSocket.Connect(rpcConfiguration, WebMessageRegistries.Definitions, new RegisterWebMessage(webToken)); var webConfiguration = new WebLauncher.Configuration(PhantomLogger.Create("Web"), webServerHost, webServerPort, webBasePath, dataProtectionKeysPath, shutdownCancellationToken); var taskManager = new TaskManager(PhantomLogger.Create<TaskManager>("Web")); var webApplication = WebLauncher.CreateApplication(webConfiguration, taskManager, applicationProperties, rpcSocket.Connection); using var actorSystem = ActorSystemFactory.Create("Web"); ControllerMessageHandlerFactory messageHandlerFactory; await using (var scope = webApplication.Services.CreateAsyncScope()) { messageHandlerFactory = scope.ServiceProvider.GetRequiredService<ControllerMessageHandlerFactory>(); } var rpcDisconnectSemaphore = new SemaphoreSlim(0, 1); var rpcTask = RpcClientRuntime.Launch(rpcSocket, messageHandlerFactory.Create(actorSystem), rpcDisconnectSemaphore, shutdownCancellationToken); try { PhantomLogger.Root.Information("Registering with the controller..."); if (await messageHandlerFactory.RegisterSuccessWaiter) { PhantomLogger.Root.Information("Successfully registered with the controller."); } else { PhantomLogger.Root.Fatal("Failed to register with the controller."); return 1; } PhantomLogger.Root.InformationHeading("Launching Phantom Panel web..."); PhantomLogger.Root.Information("Your administrator token is: {AdministratorToken}", administratorToken); PhantomLogger.Root.Information("For administrator setup, visit: {HttpUrl}{SetupPath}", webConfiguration.HttpUrl, webConfiguration.BasePath + "setup"); await WebLauncher.Launch(webConfiguration, webApplication); } finally { shutdownCancellationTokenSource.Cancel(); await taskManager.Stop(); rpcDisconnectSemaphore.Release(); await rpcTask; rpcDisconnectSemaphore.Dispose(); NetMQConfig.Cleanup(); } return 0; } catch (OperationCanceledException) { return 0; } catch (StopProcedureException) { return 1; } catch (Exception e) { PhantomLogger.Root.Fatal(e, "Caught exception in entry point."); return 1; } finally { shutdownCancellationTokenSource.Dispose(); PhantomLogger.Root.Information("Bye!"); PhantomLogger.Dispose(); }