158 lines
No EOL
4.4 KiB
C#
158 lines
No EOL
4.4 KiB
C#
using System;
|
|
using System.Linq;
|
|
using System.Net.Http;
|
|
using System.Threading.Tasks;
|
|
using LANCommander.SDK.Abstractions;
|
|
using LANCommander.SDK.Exceptions;
|
|
using LANCommander.SDK.Extensions;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace LANCommander.SDK.Services;
|
|
|
|
public class ConnectionClient(
|
|
ILogger<ConnectionClient> logger,
|
|
ISettingsProvider settingsProvider,
|
|
IServerAddressProvider serverAddressProvider,
|
|
RpcClient rpc,
|
|
ITokenProvider tokenProvider) : IConnectionClient
|
|
{
|
|
public event EventHandler OnConnect;
|
|
public event EventHandler OnDisconnect;
|
|
public event EventHandler OnServerAddressChanged;
|
|
public event EventHandler OnOfflineModeEnabled;
|
|
|
|
public bool IsConnected()
|
|
=> rpc.IsConnected;
|
|
|
|
public bool IsConfigured()
|
|
{
|
|
return HasServerAddress() && !String.IsNullOrEmpty(tokenProvider.GetToken()?.AccessToken);
|
|
}
|
|
|
|
public bool IsOfflineMode()
|
|
{
|
|
return settingsProvider.CurrentValue.Authentication.OfflineModeEnabled;
|
|
}
|
|
|
|
public bool HasServerAddress()
|
|
{
|
|
return GetServerAddress() != null;
|
|
}
|
|
|
|
public Uri GetServerAddress() => serverAddressProvider.GetServerAddress();
|
|
|
|
public async Task UpdateServerAddressAsync(Uri address) => await UpdateServerAddressAsync(address?.ToString() ?? String.Empty);
|
|
|
|
public async Task UpdateServerAddressAsync(string address)
|
|
{
|
|
if (String.IsNullOrWhiteSpace(address))
|
|
throw new InvalidAddressException("Server address cannot be blank");
|
|
|
|
var urisToTry = address.SuggestValidUris();
|
|
|
|
if (Uri.TryCreate(address, UriKind.RelativeOrAbsolute, out var baseUri))
|
|
{
|
|
var hasPort = address.Replace(Uri.SchemeDelimiter, "").Contains(':');
|
|
|
|
if (hasPort)
|
|
urisToTry = urisToTry.Take(baseUri.IsAbsoluteUri ? 1 : 2);
|
|
}
|
|
|
|
foreach (var uri in urisToTry)
|
|
{
|
|
logger?.LogInformation("Attempting to discover server at {ServerAddress}", uri.ToString());
|
|
|
|
try
|
|
{
|
|
if (await PingAsync(uri))
|
|
{
|
|
serverAddressProvider.SetServerAddress(uri);
|
|
|
|
logger?.LogInformation("Successfully discovered server at {ServerAddress}", uri.ToString());
|
|
|
|
OnServerAddressChanged?.Invoke(this, EventArgs.Empty);
|
|
|
|
await ConnectAsync();
|
|
|
|
return;
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
logger?.LogError("Failed to discover server at {ServerAddress}", uri.ToString());
|
|
}
|
|
}
|
|
|
|
throw new InvalidAddressException("Could not find a server at that address");
|
|
}
|
|
|
|
public async Task<bool> ConnectAsync()
|
|
{
|
|
if (IsConfigured())
|
|
{
|
|
if (!IsConnected())
|
|
await rpc.ConnectAsync(GetServerAddress());
|
|
|
|
settingsProvider.Update(s => s.Authentication.OfflineModeEnabled = false);
|
|
|
|
OnConnect?.Invoke(this, EventArgs.Empty);
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public async Task<bool> DisconnectAsync()
|
|
{
|
|
try
|
|
{
|
|
OnDisconnect?.Invoke(this, EventArgs.Empty);
|
|
|
|
return await rpc.DisconnectAsync();
|
|
}
|
|
catch
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public async Task EnableOfflineModeAsync()
|
|
{
|
|
await DisconnectAsync();
|
|
|
|
settingsProvider.Update(s => s.Authentication.OfflineModeEnabled = true);
|
|
|
|
OnOfflineModeEnabled?.Invoke(this, EventArgs.Empty);
|
|
}
|
|
|
|
public async Task<bool> PingAsync(Uri serverAddress = null)
|
|
{
|
|
try
|
|
{
|
|
var pingId = Guid.NewGuid().ToString();
|
|
|
|
var pingHttpClient = new HttpClient();
|
|
|
|
pingHttpClient.BaseAddress = serverAddress ?? GetServerAddress();
|
|
pingHttpClient.Timeout = TimeSpan.FromSeconds(1);
|
|
|
|
var httpRequest = new HttpRequestMessage();
|
|
|
|
httpRequest.Headers.Add("X-Ping", pingId);
|
|
httpRequest.Method = HttpMethod.Head;
|
|
|
|
var response = await pingHttpClient.SendAsync(httpRequest);
|
|
|
|
return response.IsSuccessStatusCode
|
|
&&
|
|
response.Headers.Contains("X-Pong")
|
|
&&
|
|
response.Headers.GetValues("X-Pong").First() == pingId.FastReverse();
|
|
}
|
|
catch
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
} |