Added node server sync and delete sync. Cleaned up codebase and extracted calls to apis to services

This commit is contained in:
2025-03-02 19:24:24 +01:00
parent ef7f866ded
commit 30390dab71
25 changed files with 751 additions and 282 deletions

View File

@@ -14,27 +14,6 @@ namespace MoonlightServers.ApiServer.Services;
[Singleton]
public class NodeService
{
public async Task<HttpApiClient> CreateApiClient(Node node)
{
var url = "";
if (node.UseSsl)
url += "https://";
else
url += "http://";
url += $"{node.Fqdn}:{node.HttpPort}/";
var httpClient = new HttpClient()
{
BaseAddress = new Uri(url)
};
httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {node.Token}");
return new HttpApiClient(httpClient);
}
public string CreateAccessToken(Node node, Action<Dictionary<string, object>> parameters, TimeSpan duration)
{
var claims = new Dictionary<string, object>();
@@ -63,7 +42,7 @@ public class NodeService
public async Task<SystemStatusResponse> GetSystemStatus(Node node)
{
using var apiClient = await CreateApiClient(node);
using var apiClient = CreateApiClient(node);
return await apiClient.GetJson<SystemStatusResponse>("api/system/status");
}
@@ -71,21 +50,66 @@ public class NodeService
public async Task<StatisticsApplicationResponse> GetApplicationStatistics(Node node)
{
using var apiClient = await CreateApiClient(node);
using var apiClient = CreateApiClient(node);
return await apiClient.GetJson<StatisticsApplicationResponse>("api/statistics/application");
}
public async Task<StatisticsHostResponse> GetHostStatistics(Node node)
{
using var apiClient = await CreateApiClient(node);
using var apiClient = CreateApiClient(node);
return await apiClient.GetJson<StatisticsHostResponse>("api/statistics/host");
}
public async Task<StatisticsDockerResponse> GetDockerStatistics(Node node)
{
using var apiClient = await CreateApiClient(node);
using var apiClient = CreateApiClient(node);
return await apiClient.GetJson<StatisticsDockerResponse>("api/statistics/docker");
}
#endregion
#region Helpers
private string GenerateJwt(Node node)
{
var jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
var securityTokenDescriptor = new SecurityTokenDescriptor()
{
//Expires = DateTime.UtcNow.AddYears(1),
Expires = DateTime.UtcNow.AddMinutes(1),
NotBefore = DateTime.UtcNow.AddSeconds(-1),
IssuedAt = DateTime.UtcNow,
SigningCredentials = new SigningCredentials(
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(
node.Token
)),
SecurityAlgorithms.HmacSha256
)
};
var securityToken = jwtSecurityTokenHandler.CreateJwtSecurityToken(securityTokenDescriptor);
return jwtSecurityTokenHandler.WriteToken(securityToken);
}
public HttpApiClient CreateApiClient(Node node)
{
var url = "";
url += node.UseSsl ? "https://" : "http://";
url += $"{node.Fqdn}:{node.HttpPort}/";
var httpClient = new HttpClient()
{
BaseAddress = new Uri(url)
};
var jwt = GenerateJwt(node);
httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {jwt}");
return new HttpApiClient(httpClient);
}
#endregion
}

View File

@@ -0,0 +1,165 @@
using System.Text.Json;
using Microsoft.EntityFrameworkCore;
using MoonCore.Attributes;
using MoonCore.Exceptions;
using MoonCore.Extended.Abstractions;
using MoonCore.Helpers;
using Moonlight.ApiServer.Database.Entities;
using MoonlightServers.ApiServer.Database.Entities;
using MoonlightServers.DaemonShared.DaemonSide.Http.Responses.Servers;
namespace MoonlightServers.ApiServer.Services;
[Scoped]
public class ServerService
{
private readonly NodeService NodeService;
private readonly DatabaseRepository<Server> ServerRepository;
public ServerService(NodeService nodeService, DatabaseRepository<Server> serverRepository)
{
NodeService = nodeService;
ServerRepository = serverRepository;
}
#region Power Actions
public async Task Start(Server server)
{
try
{
using var apiClient = await GetApiClient(server);
await apiClient.Post($"api/servers/{server.Id}/start");
}
catch (HttpRequestException e)
{
throw new HttpApiException("Unable to access the node the server is running on", 502);
}
}
public async Task Stop(Server server)
{
try
{
using var apiClient = await GetApiClient(server);
await apiClient.Post($"api/servers/{server.Id}/stop");
}
catch (HttpRequestException e)
{
throw new HttpApiException("Unable to access the node the server is running on", 502);
}
}
public async Task Kill(Server server)
{
try
{
using var apiClient = await GetApiClient(server);
await apiClient.Post($"api/servers/{server.Id}/kill");
}
catch (HttpRequestException e)
{
throw new HttpApiException("Unable to access the node the server is running on", 502);
}
}
#endregion
public async Task Install(Server server)
{
try
{
using var apiClient = await GetApiClient(server);
await apiClient.Post($"api/servers/{server.Id}/install");
}
catch (HttpRequestException e)
{
throw new HttpApiException("Unable to access the node the server is running on", 502);
}
}
public async Task Sync(Server server)
{
try
{
using var apiClient = await GetApiClient(server);
await apiClient.Post($"api/servers/{server.Id}/sync");
}
catch (HttpRequestException e)
{
throw new HttpApiException("Unable to access the node the server is running on", 502);
}
}
public async Task SyncDelete(Server server)
{
try
{
using var apiClient = await GetApiClient(server);
await apiClient.Delete($"api/servers/{server.Id}");
}
catch (HttpRequestException e)
{
throw new HttpApiException("Unable to access the node the server is running on", 502);
}
}
public async Task<ServerStatusResponse> GetStatus(Server server)
{
try
{
using var apiClient = await GetApiClient(server);
return await apiClient.GetJson<ServerStatusResponse>($"api/servers/{server.Id}/status");
}
catch (HttpRequestException e)
{
throw new HttpApiException("Unable to access the node the server is running on", 502);
}
}
public async Task<ServerLogsResponse> GetLogs(Server server)
{
try
{
using var apiClient = await GetApiClient(server);
return await apiClient.GetJson<ServerLogsResponse>($"api/servers/{server.Id}/logs");
}
catch (HttpRequestException e)
{
throw new HttpApiException("Unable to access the node the server is running on", 502);
}
}
#region Helpers
public bool IsAllowedToAccess(User user, Server server)
{
if (server.OwnerId == user.Id)
return true;
var permissions = JsonSerializer.Deserialize<string[]>(
user.PermissionsJson
) ?? [];
return PermissionHelper.HasPermission(permissions, "admin.servers.get");
}
private async Task<HttpApiClient> GetApiClient(Server server)
{
var serverWithNode = server;
// ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
// It can be null when its not included when loading via ef !!!
if (server.Node == null)
{
serverWithNode = await ServerRepository
.Get()
.Include(x => x.Node)
.FirstAsync(x => x.Id == server.Id);
}
return NodeService.CreateApiClient(serverWithNode.Node);
}
#endregion
}