using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Net.Http; using System.Text.Json; using System.Text.Json.Serialization; using System.Text.Json.Serialization.Metadata; using System.Threading; using System.Threading.Tasks; using Luski.net.Enums; using Luski.Shared.PublicServers.V1.Enums; using Luski.Shared.PublicServers.V1.ServerToClient.HTTP; namespace Luski.net; public class API { [JsonIgnore] public MainServer MainServer { get; internal set; } public bool IsAnyServerLoggedin { get; internal set; } public const string DefaultVersion = "v1"; internal List Versions = new() { DefaultVersion }; public IReadOnlyList SupportedVersions => Versions.AsReadOnly(); internal List InternalServers { get; } = new(); public IReadOnlyList LoadedServers => InternalServers.AsReadOnly(); internal List InternalFailedServers { get; } = new(); public IReadOnlyList FailedServers => InternalFailedServers.AsReadOnly(); private static HttpResponseMessage GetFromServer(string Domain, string ApiVersion, bool Secure, string Path, CancellationToken CancellationToken, params KeyValuePair[] Headers) { using HttpClient web = new(); web.Timeout = TimeSpan.FromSeconds(10); if (Headers is not null && Headers.Length > 0) foreach (KeyValuePair header in Headers) web.DefaultRequestHeaders.Add(header.Key, header.Value); return web.GetAsync($"{(Secure ? "https" : "http" )}://{Domain}/{ApiVersion}/{Path}", cancellationToken: CancellationToken).Result; } private static Task GetFromServer(string Domain, string ApiVersion, bool Secure, string Path, JsonTypeInfo Type, CancellationToken CancellationToken, params KeyValuePair[] Headers) where Tresult : STC, new() { HttpResponseMessage ServerResponce = GetFromServer(Domain, ApiVersion, Secure, Path, CancellationToken, Headers); Tresult temp = new(); string raw = ServerResponce.Content.ReadAsStringAsync(CancellationToken).Result; try { temp = JsonSerializer.Deserialize(raw, Type)!; } catch (Exception e) { Console.WriteLine("JSON parse failed for the following data as type {0}\n{1}", temp.GetType(), raw); } if (temp is null) return Task.FromResult(new Tresult() { StatusCode = ServerResponce.StatusCode, Error = ErrorCode.ServerError, ErrorMessage = $"Server responded with empty data" }); return Task.FromResult(temp); } public Task GetServerInfo(string Domain, string Version = DefaultVersion, bool Secure = true) { ServerInfoSTC? si = GetFromServer(Domain, Version, Secure, "socketserver", ServerInfoSTCContext.Default.ServerInfoSTC, CancellationToken.None).Result; if (si is null) throw new Exception("Bad Response"); return Task.FromResult(si); } public Task TryGetServerInfo([NotNullWhen(true)]out ServerInfoSTC? si, string Domain, string Version = DefaultVersion, bool Secure = true) { try { si = GetServerInfo(Domain, Version, Secure).Result; return Task.FromResult(true); } catch (Exception e) { si = null; return Task.FromResult(false); } } public Task TryGetPublicServer(out PublicServer Server, string Domain, string Version = DefaultVersion, bool Secure = true, bool GenerateEncryption = true, bool LogConsole = false) { try { Task result = GetPublicServer(Domain, Version, Secure, GenerateEncryption, LogConsole); Task.WaitAll(result); Server = result.Result; return Task.FromResult(true); } catch (Exception e) { if (!e.Message.Contains("Connection refused")) Console.WriteLine(e); Server = null!; return Task.FromResult(false); } } public async Task GetPublicServer(string Domain, string Version = DefaultVersion, bool Secure = true, bool GenerateEncryption = true, bool LogConsole = false) { PublicServer s; try { IEnumerable isl = InternalServers.Where(a => (a.Domain == Domain && a.ApiVersion == Version)); if (isl.Any()) return isl.First(); s = await PublicServer.GetServer(InternalFailedServers, Domain, Version, Secure, GenerateEncryption, LogConsole); } catch (Exception e) { Console.WriteLine("Failed to connect to public server '{0}' using API {1}. No alternate server was found.", Domain, Version); throw; } string? f = s.Storage.GetStorageDirectory(StorageDirectory.StorageInfo) + "token"; if (File.Exists(f)) { f = File.ReadAllText(f); } else f = null; try { if (f is not null) { bool b = await s.LoginViaToken(f); if (b) { IsAnyServerLoggedin = true; } else { s.Token = null; s.Error = null; } } } catch { } InternalServers.Add(s); return s; } public MainServer GetMainServer(string Domain, string Version = DefaultVersion) { DateTime dt = DateTime.UtcNow; Console.WriteLine("Conecting to main server '{0}' using API {1}.", Domain, Version); MainServer = new(Domain, Version) { ServerType = ServerType.Main }; Console.WriteLine("Connected to main server '{0}' using API {1} in {2}.", Domain, Version, DateTime.UtcNow.Subtract(dt).ToString("g")); return MainServer; } }