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 Options; private readonly ILogger Logger; private readonly IHttpClientFactory ClientFactory; public RemoteService( IOptions options, IHttpClientFactory clientFactory, ILogger logger ) { Options = options; ClientFactory = clientFactory; Logger = logger; } public async Task 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( 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? Errors { get; } public RemoteException( string type, string title, int status, string? detail = null, Dictionary? errors = null) : base(detail ?? title) { Type = type; Title = title; Status = status; Detail = detail; Errors = errors; } }