Files
Servers/MoonlightServers.Daemon/Services/RemoteService.cs

117 lines
3.2 KiB
C#

using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using Microsoft.Extensions.Options;
using Microsoft.Net.Http.Headers;
using MoonlightServers.Daemon.Configuration;
using MoonlightServers.DaemonShared.Http;
namespace MoonlightServers.Daemon.Services;
public class RemoteService
{
private readonly IOptions<RemoteOptions> Options;
private readonly ILogger<RemoteService> Logger;
private readonly IHttpClientFactory ClientFactory;
public RemoteService(
IOptions<RemoteOptions> options,
IHttpClientFactory clientFactory,
ILogger<RemoteService> logger
)
{
Options = options;
ClientFactory = clientFactory;
Logger = logger;
}
public async Task<int> CheckReachabilityAsync()
{
try
{
var client = ClientFactory.CreateClient();
var request = CreateBaseRequest(HttpMethod.Get, "api/remote/servers/nodes/ping");
var response = await client.SendAsync(request);
return (int)response.StatusCode;
}
catch (Exception e)
{
Logger.LogTrace(e, "An error occured while checking if remote is reachable");
return 0;
}
}
private HttpRequestMessage CreateBaseRequest(
[StringSyntax(StringSyntaxAttribute.Uri)]
HttpMethod method,
string endpoint
)
{
var request = new HttpRequestMessage();
request.Headers.Add(HeaderNames.Authorization, $"{Options.Value.TokenId} {Options.Value.Token}");
request.RequestUri = new Uri(new Uri(Options.Value.EndpointUrl), endpoint);
request.Method = method;
return request;
}
private async Task EnsureSuccessAsync(HttpResponseMessage message)
{
if (message.IsSuccessStatusCode)
return;
try
{
var problemDetails = await message.Content.ReadFromJsonAsync<ProblemDetails>(
SerializationContext.Default.Options
);
if (problemDetails == null)
{
// If we cant handle problem details, we handle it natively
message.EnsureSuccessStatusCode();
return;
}
// Parse into exception
throw new RemoteException(
problemDetails.Type,
problemDetails.Title,
problemDetails.Status,
problemDetails.Detail,
problemDetails.Errors
);
}
catch (JsonException)
{
// If we cant handle problem details, we handle it natively
message.EnsureSuccessStatusCode();
}
}
}
public class RemoteException : Exception
{
public string Type { get; }
public string Title { get; }
public int Status { get; }
public string? Detail { get; }
public Dictionary<string, string[]>? Errors { get; }
public RemoteException(
string type,
string title,
int status,
string? detail = null,
Dictionary<string, string[]>? errors = null)
: base(detail ?? title)
{
Type = type;
Title = title;
Status = status;
Detail = detail;
Errors = errors;
}
}