diff --git a/Moonlight/Features/Servers/Actions/ServerActions.cs b/Moonlight/Features/Servers/Actions/ServerActions.cs index 441d770e..6f65e3c9 100644 --- a/Moonlight/Features/Servers/Actions/ServerActions.cs +++ b/Moonlight/Features/Servers/Actions/ServerActions.cs @@ -105,7 +105,7 @@ public class ServerActions : ServiceActions serverRepo.Add(server); await serverService.Sync(server); - await serverService.SendPowerAction(server, PowerAction.Install); + await serverService.Console.SendAction(server, PowerAction.Install); } public override Task Update(IServiceProvider provider, Service service) diff --git a/Moonlight/Features/Servers/Api/Requests/EnterCommand.cs b/Moonlight/Features/Servers/Api/Requests/SendCommand.cs similarity index 78% rename from Moonlight/Features/Servers/Api/Requests/EnterCommand.cs rename to Moonlight/Features/Servers/Api/Requests/SendCommand.cs index 5f7392f5..0101aab3 100644 --- a/Moonlight/Features/Servers/Api/Requests/EnterCommand.cs +++ b/Moonlight/Features/Servers/Api/Requests/SendCommand.cs @@ -1,6 +1,6 @@ namespace Moonlight.Features.Servers.Api.Requests; -public class EnterCommand +public class SendCommand { public string Command { get; set; } } \ No newline at end of file diff --git a/Moonlight/Features/Servers/BackgroundServices/InitBackgroundService.cs b/Moonlight/Features/Servers/BackgroundServices/InitBackgroundService.cs new file mode 100644 index 00000000..c9551f0f --- /dev/null +++ b/Moonlight/Features/Servers/BackgroundServices/InitBackgroundService.cs @@ -0,0 +1,44 @@ +using MoonCore.Abstractions; +using MoonCore.Attributes; +using MoonCore.Helpers; +using Moonlight.Features.Servers.Entities; +using Moonlight.Features.Servers.Services; +using BackgroundService = MoonCore.Abstractions.BackgroundService; + +namespace Moonlight.Features.Servers.BackgroundServices; + +[BackgroundService] +public class InitBackgroundService : BackgroundService +{ + private readonly IServiceProvider ServiceProvider; + + public InitBackgroundService(IServiceProvider serviceProvider) + { + ServiceProvider = serviceProvider; + } + + public override async Task Run() + { + Logger.Info("Booting all nodes"); + + using var scope = ServiceProvider.CreateScope(); + + var nodeRepo = scope.ServiceProvider.GetRequiredService>(); + var nodeService = scope.ServiceProvider.GetRequiredService(); + + foreach (var node in nodeRepo.Get().ToArray()) + { + try + { + await nodeService.Boot(node); + } + catch (Exception e) + { + Logger.Warn($"An error occured while booting node '{node.Name}'"); + Logger.Warn(e); + } + } + + Logger.Info("Booted all nodes"); + } +} \ No newline at end of file diff --git a/Moonlight/Features/Servers/Extensions/NodeExtensions.cs b/Moonlight/Features/Servers/Extensions/NodeExtensions.cs new file mode 100644 index 00000000..ee4c7ae1 --- /dev/null +++ b/Moonlight/Features/Servers/Extensions/NodeExtensions.cs @@ -0,0 +1,16 @@ +using MoonCore.Helpers; +using Moonlight.Features.Servers.Entities; +using Moonlight.Features.Servers.Exceptions; + +namespace Moonlight.Features.Servers.Extensions; + +public static class NodeExtensions +{ + public static HttpApiClient CreateHttpClient(this ServerNode node) + { + var protocol = node.UseSsl ? "https" : "http"; + var remoteUrl = $"{protocol}://{node.Fqdn}:{node.HttpPort}/"; + + return new HttpApiClient(remoteUrl, node.Token); + } +} \ No newline at end of file diff --git a/Moonlight/Features/Servers/Extensions/ServerExtensions.cs b/Moonlight/Features/Servers/Extensions/ServerExtensions.cs index 451d6a75..aeb06f6a 100644 --- a/Moonlight/Features/Servers/Extensions/ServerExtensions.cs +++ b/Moonlight/Features/Servers/Extensions/ServerExtensions.cs @@ -1,4 +1,8 @@ +using Microsoft.EntityFrameworkCore; +using MoonCore.Abstractions; +using MoonCore.Helpers; using Moonlight.Features.Servers.Entities; +using Moonlight.Features.Servers.Exceptions; using Moonlight.Features.Servers.Models.Abstractions; namespace Moonlight.Features.Servers.Extensions; @@ -71,4 +75,17 @@ public static class ServerExtensions return installConfiguration; } + + public static HttpApiClient CreateHttpClient(this Server server, IServiceProvider serviceProvider) + { + using var scope = serviceProvider.CreateScope(); + var serverRepo = scope.ServiceProvider.GetRequiredService>(); + + var serverWithNode = serverRepo + .Get() + .Include(x => x.Node) + .First(x => x.Id == server.Id); + + return serverWithNode.Node.CreateHttpClient(); + } } \ No newline at end of file diff --git a/Moonlight/Features/Servers/Services/NodeService.cs b/Moonlight/Features/Servers/Services/NodeService.cs index 94ed3ac9..a2dbacd9 100644 --- a/Moonlight/Features/Servers/Services/NodeService.cs +++ b/Moonlight/Features/Servers/Services/NodeService.cs @@ -1,4 +1,6 @@ using MoonCore.Attributes; +using Moonlight.Features.Servers.Entities; +using Moonlight.Features.Servers.Extensions; using Moonlight.Features.Servers.Helpers; using Moonlight.Features.Servers.Models.Abstractions; @@ -8,4 +10,17 @@ namespace Moonlight.Features.Servers.Services; public class NodeService { public readonly MetaCache Meta = new(); + + private readonly IServiceProvider ServiceProvider; + + public NodeService(IServiceProvider serviceProvider) + { + ServiceProvider = serviceProvider; + } + + public async Task Boot(ServerNode node) + { + using var httpClient = node.CreateHttpClient(); + await httpClient.Post("system/boot"); + } } \ No newline at end of file diff --git a/Moonlight/Features/Servers/Services/ServerConsoleService.cs b/Moonlight/Features/Servers/Services/ServerConsoleService.cs new file mode 100644 index 00000000..863a5ff2 --- /dev/null +++ b/Moonlight/Features/Servers/Services/ServerConsoleService.cs @@ -0,0 +1,40 @@ +using MoonCore.Attributes; +using Moonlight.Features.Servers.Api.Requests; +using Moonlight.Features.Servers.Entities; +using Moonlight.Features.Servers.Extensions; +using Moonlight.Features.Servers.Models.Enums; + +namespace Moonlight.Features.Servers.Services; + +[Singleton] +public class ServerConsoleService +{ + private readonly IServiceProvider ServiceProvider; + + public ServerConsoleService(IServiceProvider serviceProvider) + { + ServiceProvider = serviceProvider; + } + + public async Task SendAction(Server server, PowerAction powerAction) + { + using var httpClient = server.CreateHttpClient(ServiceProvider); + await httpClient.Post($"servers/{server.Id}/power/{powerAction.ToString().ToLower()}"); + } + + public async Task Subscribe(Server server) + { + using var httpClient = server.CreateHttpClient(ServiceProvider); + await httpClient.Post($"servers/{server.Id}/subscribe"); + } + + public async Task SendCommand(Server server, string command) + { + using var httpClient = server.CreateHttpClient(ServiceProvider); + + await httpClient.Post($"servers/{server.Id}/command", new SendCommand() + { + Command = command + }); + } +} \ No newline at end of file diff --git a/Moonlight/Features/Servers/Services/ServerService.cs b/Moonlight/Features/Servers/Services/ServerService.cs index 4db32130..99ed5b88 100644 --- a/Moonlight/Features/Servers/Services/ServerService.cs +++ b/Moonlight/Features/Servers/Services/ServerService.cs @@ -1,13 +1,8 @@ -using Microsoft.EntityFrameworkCore; -using MoonCore.Abstractions; using MoonCore.Attributes; -using MoonCore.Helpers; -using Moonlight.Features.Servers.Api.Requests; using Moonlight.Features.Servers.Entities; -using Moonlight.Features.Servers.Exceptions; +using Moonlight.Features.Servers.Extensions; using Moonlight.Features.Servers.Helpers; using Moonlight.Features.Servers.Models.Abstractions; -using Moonlight.Features.Servers.Models.Enums; namespace Moonlight.Features.Servers.Services; @@ -15,6 +10,7 @@ namespace Moonlight.Features.Servers.Services; public class ServerService { public readonly MetaCache Meta = new(); + public ServerConsoleService Console => ServiceProvider.GetRequiredService(); private readonly IServiceProvider ServiceProvider; @@ -25,7 +21,7 @@ public class ServerService public async Task Sync(Server server) { - using var httpClient = CreateHttpClient(server); + using var httpClient = server.CreateHttpClient(ServiceProvider); await httpClient.Post($"servers/{server.Id}/sync"); } @@ -33,42 +29,4 @@ public class ServerService { } - - public async Task SendPowerAction(Server server, PowerAction powerAction) - { - using var httpClient = CreateHttpClient(server); - await httpClient.Post($"servers/{server.Id}/power/{powerAction.ToString().ToLower()}"); - } - - public async Task SubscribeToConsole(Server server) - { - using var httpClient = CreateHttpClient(server); - await httpClient.Post($"servers/{server.Id}/subscribe"); - } - - public async Task SendCommand(Server server, string command) - { - using var httpClient = CreateHttpClient(server); - - await httpClient.Post($"servers/{server.Id}/command", new EnterCommand() - { - Command = command - }); - } - - private HttpApiClient CreateHttpClient(Server server) - { - using var scope = ServiceProvider.CreateScope(); - var serverRepo = scope.ServiceProvider.GetRequiredService>(); - - var serverWithNode = serverRepo - .Get() - .Include(x => x.Node) - .First(x => x.Id == server.Id); - - var protocol = serverWithNode.Node.UseSsl ? "https" : "http"; - var remoteUrl = $"{protocol}://{serverWithNode.Node.Fqdn}:{serverWithNode.Node.HttpPort}/"; - - return new HttpApiClient(remoteUrl, serverWithNode.Node.Token); - } } \ No newline at end of file diff --git a/Moonlight/Features/Servers/UI/Layouts/UserLayout.razor b/Moonlight/Features/Servers/UI/Layouts/UserLayout.razor index 379eac53..ec660333 100644 --- a/Moonlight/Features/Servers/UI/Layouts/UserLayout.razor +++ b/Moonlight/Features/Servers/UI/Layouts/UserLayout.razor @@ -245,7 +245,7 @@ }; // Send console subscription and add auto resubscribe for it - await ServerService.SubscribeToConsole(Server); + await ServerService.Console.Subscribe(Server); // We need this to revalidate to the daemon that we are still interested // in the console logs. By default the expiration time is 15 minutes from last @@ -255,7 +255,7 @@ while (!BackgroundCancel.IsCancellationRequested) { await Task.Delay(TimeSpan.FromMinutes(10)); - await ServerService.SubscribeToConsole(Server); + await ServerService.Console.Subscribe(Server); } }); @@ -276,11 +276,11 @@ await InstallTerminal.WriteLine(message); } - private async Task Start() => await ServerService.SendPowerAction(Server, PowerAction.Start); + private async Task Start() => await ServerService.Console.SendAction(Server, PowerAction.Start); - private async Task Stop() => await ServerService.SendPowerAction(Server, PowerAction.Stop); + private async Task Stop() => await ServerService.Console.SendAction(Server, PowerAction.Stop); - private async Task Kill() => await ServerService.SendPowerAction(Server, PowerAction.Kill); + private async Task Kill() => await ServerService.Console.SendAction(Server, PowerAction.Kill); public void Dispose() { diff --git a/Moonlight/Features/Servers/UI/UserViews/Console.razor b/Moonlight/Features/Servers/UI/UserViews/Console.razor index e42a4f5b..8b2aab6b 100644 --- a/Moonlight/Features/Servers/UI/UserViews/Console.razor +++ b/Moonlight/Features/Servers/UI/UserViews/Console.razor @@ -51,7 +51,7 @@ private async Task SendCommand() { - await ServerService.SendCommand(Server, CommandInput); + await ServerService.Console.SendCommand(Server, CommandInput); CommandInput = ""; await InvokeAsync(StateHasChanged); diff --git a/Moonlight/Features/Servers/UI/UserViews/Reset.razor b/Moonlight/Features/Servers/UI/UserViews/Reset.razor index ccddd2ed..2e10d0a7 100644 --- a/Moonlight/Features/Servers/UI/UserViews/Reset.razor +++ b/Moonlight/Features/Servers/UI/UserViews/Reset.razor @@ -38,7 +38,7 @@ private async Task ResetServer() { - await ServerService.SendPowerAction(Server, PowerAction.Install); + await ServerService.Console.SendAction(Server, PowerAction.Install); } private async Task OnStateChanged()