Alternate servers.
On load, the client can find alternate servers to connect to.
This commit is contained in:
parent
9f641e7429
commit
0349745944
@ -15,24 +15,19 @@ public class API
|
|||||||
|
|
||||||
public async Task<PublicServer> GetPublicServer(string Domain, string Version = "v1", bool Secure = true)
|
public async Task<PublicServer> GetPublicServer(string Domain, string Version = "v1", bool Secure = true)
|
||||||
{
|
{
|
||||||
DateTime dt = DateTime.UtcNow;
|
|
||||||
Console.WriteLine("Connecting to public server '{0}' using API {1}.", Domain, Version);
|
|
||||||
PublicServer s;
|
PublicServer s;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
IEnumerable<PublicServer> isl = InternalServers.Where(a => (a.Domain == Domain && a.ApiVersion == Version));
|
IEnumerable<PublicServer> isl = InternalServers.Where(a => (a.Domain == Domain && a.ApiVersion == Version));
|
||||||
if (isl.Any()) return isl.First();
|
if (isl.Any()) return isl.First();
|
||||||
s = new(Domain, Version, Secure)
|
s = await PublicServer.GetServer(Domain, Version, Secure);
|
||||||
{
|
|
||||||
ServerType = ServerType.Public
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Failed to connect to public server '{0}' using API {1}.", Domain, Version);
|
Console.WriteLine("Failed to connect to public server '{0}' using API {1}. No alternate server was found.", Domain, Version);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
Console.WriteLine("Connected to public server '{0}' using API {1} in {4}.\nServer Name: {2}\nServer Description: {3}", Domain, Version, s.Name, s.Description, DateTime.UtcNow.Subtract(dt).ToString("g"));
|
|
||||||
string? f = s.Storage.GetStorageDirectory(StorageDirectory.StorageInfo) + "token";
|
string? f = s.Storage.GetStorageDirectory(StorageDirectory.StorageInfo) + "token";
|
||||||
if (File.Exists(f))
|
if (File.Exists(f))
|
||||||
{
|
{
|
||||||
|
21
Luski.net/JsonTypes/LocalServerInfo.cs
Normal file
21
Luski.net/JsonTypes/LocalServerInfo.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
using System;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Luski.net.JsonTypes;
|
||||||
|
|
||||||
|
public class LocalServerInfo
|
||||||
|
{
|
||||||
|
[JsonInclude]
|
||||||
|
[JsonPropertyName("alternate_servers")]
|
||||||
|
public ServerData[] AlternateServers { get; set; } = Array.Empty<ServerData>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonSerializable(typeof(LocalServerInfo))]
|
||||||
|
[JsonSourceGenerationOptions(
|
||||||
|
GenerationMode = JsonSourceGenerationMode.Default,
|
||||||
|
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
|
||||||
|
WriteIndented = false)]
|
||||||
|
internal partial class LocalServerInfoContext : JsonSerializerContext
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
23
Luski.net/JsonTypes/ServerData.cs
Normal file
23
Luski.net/JsonTypes/ServerData.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Luski.net.JsonTypes;
|
||||||
|
|
||||||
|
public class ServerData
|
||||||
|
{
|
||||||
|
[JsonInclude]
|
||||||
|
[JsonPropertyName("address")]
|
||||||
|
public string DomainAndPort = default!;
|
||||||
|
[JsonInclude]
|
||||||
|
[JsonPropertyName("secure")]
|
||||||
|
public bool Secure;
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonSerializable(typeof(ServerData))]
|
||||||
|
[JsonSourceGenerationOptions(
|
||||||
|
GenerationMode = JsonSourceGenerationMode.Default,
|
||||||
|
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
|
||||||
|
WriteIndented = false)]
|
||||||
|
internal partial class ServerDataContext : JsonSerializerContext
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
@ -9,6 +9,10 @@ public class ServerInfo : IncomingHTTP
|
|||||||
public string wssv4 { get; set; }
|
public string wssv4 { get; set; }
|
||||||
public string description { get; set; }
|
public string description { get; set; }
|
||||||
public long owner { get; set; }
|
public long owner { get; set; }
|
||||||
|
|
||||||
|
[JsonInclude]
|
||||||
|
[JsonPropertyName("alternate_servers")]
|
||||||
|
public ServerData[] AlternateServers { get; set; } = default!;
|
||||||
}
|
}
|
||||||
|
|
||||||
[JsonSerializable(typeof(ServerInfo))]
|
[JsonSerializable(typeof(ServerInfo))]
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
<RepositoryUrl>https://github.com/JacobTech-com/Luski.net</RepositoryUrl>
|
<RepositoryUrl>https://github.com/JacobTech-com/Luski.net</RepositoryUrl>
|
||||||
<IncludeSymbols>True</IncludeSymbols>
|
<IncludeSymbols>True</IncludeSymbols>
|
||||||
<FileVersion>1.0.0</FileVersion>
|
<FileVersion>1.0.0</FileVersion>
|
||||||
<Version>2.0.0-alpha12</Version>
|
<Version>2.0.0-alpha23</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json.Serialization.Metadata;
|
using System.Text.Json.Serialization.Metadata;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@ -30,13 +31,62 @@ public partial class PublicServer : Server
|
|||||||
|
|
||||||
public SocketAppUser User { get; private set; } = null!;
|
public SocketAppUser User { get; private set; } = null!;
|
||||||
|
|
||||||
internal PublicServer(string Domain, string API_Version, bool Secure = true):
|
private PublicServer(string Domain, string API_Version, bool Secure = true) :
|
||||||
base(Domain, API_Version, Secure)
|
base(Domain, API_Version, Secure)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
internal static async Task<PublicServer> GetServer(string Domain, string API_Version, bool Secure = true)
|
||||||
{
|
{
|
||||||
ServerInfo si = GetFromServer("socketserver", ServerInfoContext.Default.ServerInfo, CancellationToken.None).Result;
|
DateTime dt = DateTime.UtcNow;
|
||||||
Name = si.name;
|
Console.WriteLine("Connecting to public server '{0}' using API {1}.", Domain, API_Version);
|
||||||
Description = si.description;
|
PublicServer s = new(Domain, API_Version, Secure);
|
||||||
wssurl = si.wssv4;
|
ServerInfo? si = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
si = await s.GetFromServer("socketserver", ServerInfoContext.Default.ServerInfo, CancellationToken.None);
|
||||||
|
s.EncryptionHandler.ServerPublicKey = await (await new HttpClient()
|
||||||
|
.GetAsync($"{(s.Secure ? "https" : "http")}://{s.Domain}/{s.ApiVersion}/Keys/PublicKey"))
|
||||||
|
.Content
|
||||||
|
.ReadAsStringAsync();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
LocalServerInfo ServerListing = s.Storage.GetJson(StorageDirectory.ServerInfo, "Servers.json", true,
|
||||||
|
LocalServerInfoContext.Default.LocalServerInfo);
|
||||||
|
if (ServerListing.AlternateServers.Length > 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Failed to connect to public server '{0}' using API {1}. Attempting to connect to alternate servers.", Domain, API_Version);
|
||||||
|
foreach (ServerData Server in ServerListing.AlternateServers)
|
||||||
|
{
|
||||||
|
s.Secure = Server.Secure;
|
||||||
|
s.Domain = Server.DomainAndPort;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
si = await s.GetFromServer("socketserver", ServerInfoContext.Default.ServerInfo, CancellationToken.None);
|
||||||
|
s.EncryptionHandler.ServerPublicKey = await (await new HttpClient()
|
||||||
|
.GetAsync($"{(s.Secure ? "https" : "http")}://{s.Domain}/{s.ApiVersion}/Keys/PublicKey"))
|
||||||
|
.Content
|
||||||
|
.ReadAsStringAsync();
|
||||||
|
Console.WriteLine("Public server '{0}' connection restored by alternate server '{1}' using API {2}.", Domain, s.Domain, API_Version);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (si is null) throw;
|
||||||
|
}
|
||||||
|
s.Name = si.name;
|
||||||
|
s.Description = si.description;
|
||||||
|
s.wssurl = si.wssv4;
|
||||||
|
s.ServerType = ServerType.Public;
|
||||||
|
Console.WriteLine("Connected to public server '{0}' using API {1} in {4}.\nServer Name: {2}\nServer Description: {3}", Domain, API_Version, s.Name, s.Description, DateTime.UtcNow.Subtract(dt).ToString("g"));
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<TCategory> GetCategory<TCategory>(long id, CancellationToken CancellationToken) where TCategory : SocketCategory, new()
|
public async Task<TCategory> GetCategory<TCategory>(long id, CancellationToken CancellationToken) where TCategory : SocketCategory, new()
|
||||||
@ -295,6 +345,6 @@ public partial class PublicServer : Server
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Name { get; }
|
public string Name { get; private set; }
|
||||||
public string Description { get; }
|
public string Description { get; private set; }
|
||||||
}
|
}
|
@ -12,12 +12,11 @@ public class ServerEncryption
|
|||||||
{
|
{
|
||||||
internal bool Generating, Generated;
|
internal bool Generating, Generated;
|
||||||
internal string ServerPublicKey = "", MyPublicKey = "", myPrivateKey = "", OfflinePrivateKey = "", OfflinePublicKey = "";
|
internal string ServerPublicKey = "", MyPublicKey = "", myPrivateKey = "", OfflinePrivateKey = "", OfflinePublicKey = "";
|
||||||
|
|
||||||
internal byte[] Hash = default!;
|
internal byte[] Hash = default!;
|
||||||
internal ServerEncryption(string Domain, string API_Version, ServerStorage Storage, bool Secure)
|
internal ServerEncryption(ServerStorage Storage)
|
||||||
{
|
{
|
||||||
this.Storage = Storage;
|
this.Storage = Storage;
|
||||||
ServerPublicKey = new HttpClient().GetAsync($"{(Secure ? "https" : "http" )}://{Domain}/{API_Version}/Keys/PublicKey").Result.Content
|
|
||||||
.ReadAsStringAsync().Result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetChannelKey(long Channel)
|
public string GetChannelKey(long Channel)
|
||||||
|
@ -14,7 +14,7 @@ namespace Luski.net;
|
|||||||
public partial class Server
|
public partial class Server
|
||||||
{
|
{
|
||||||
public ServerType ServerType { get; internal set; } = ServerType.Public;
|
public ServerType ServerType { get; internal set; } = ServerType.Public;
|
||||||
public string Domain { get; } = default!;
|
public string Domain { get; set; } = default!;
|
||||||
public string ApiVersion { get; } = "v1";
|
public string ApiVersion { get; } = "v1";
|
||||||
internal WebSocket? ServerOut;
|
internal WebSocket? ServerOut;
|
||||||
internal string? Token = null, Error = null, gen = null;
|
internal string? Token = null, Error = null, gen = null;
|
||||||
|
@ -4,6 +4,7 @@ using System.Linq;
|
|||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization.Metadata;
|
||||||
using JacobTechEncryption;
|
using JacobTechEncryption;
|
||||||
using JacobTechEncryption.Enums;
|
using JacobTechEncryption.Enums;
|
||||||
using Luski.net.Enums;
|
using Luski.net.Enums;
|
||||||
@ -73,6 +74,20 @@ public class ServerStorage
|
|||||||
|
|
||||||
internal ServerStorageInfo RawInfo { get; }
|
internal ServerStorageInfo RawInfo { get; }
|
||||||
|
|
||||||
|
public TResult GetJson<TResult>(StorageDirectory Directory, string Resource, bool CreateOnMissing, JsonTypeInfo<TResult> JsonInfo) where TResult : new()
|
||||||
|
{
|
||||||
|
string FilePath = GetResourceDirectory(Directory, Resource);
|
||||||
|
if (!File.Exists(FilePath))
|
||||||
|
{
|
||||||
|
TResult res = new();
|
||||||
|
File.WriteAllText(FilePath, JsonSerializer.Serialize(res, JsonInfo));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
Stream s = GetResourceStream(FilePath);
|
||||||
|
return JsonSerializer.Deserialize(s, JsonInfo)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public byte[] UpdateStorage(byte[] OldPassword)
|
public byte[] UpdateStorage(byte[] OldPassword)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -218,6 +233,11 @@ public class ServerStorage
|
|||||||
return Location + Directories[(byte)Directory] + "/";
|
return Location + Directories[(byte)Directory] + "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string GetResourceDirectory(StorageDirectory Directory, string Resourse)
|
||||||
|
{
|
||||||
|
return Location + Directories[(byte)Directory] + "/" + Resourse;
|
||||||
|
}
|
||||||
|
|
||||||
public string GetResourceKey(StorageDirectory Directory, string Resource, string Key)
|
public string GetResourceKey(StorageDirectory Directory, string Resource, string Key)
|
||||||
{
|
{
|
||||||
return Encoding.UTF8.GetString(Encryption.AES.Decrypt(GetResourceBytes(Directory, Resource), Key));
|
return Encoding.UTF8.GetString(Encryption.AES.Decrypt(GetResourceBytes(Directory, Resource), Key));
|
||||||
@ -283,6 +303,23 @@ public class ServerStorage
|
|||||||
return ms;
|
return ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Stream GetResourceStream(string dir)
|
||||||
|
{
|
||||||
|
byte[] buffer = new byte[16 * 1024];
|
||||||
|
MemoryStream ms = new();
|
||||||
|
using (FileStream r = File.OpenRead(dir))
|
||||||
|
{
|
||||||
|
int readBytes;
|
||||||
|
while ((readBytes = r.Read(buffer, 0, buffer.Length)) > 0)
|
||||||
|
{
|
||||||
|
ms.Write(buffer, 0, readBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ms.Position = 0;
|
||||||
|
return ms;
|
||||||
|
}
|
||||||
|
|
||||||
public void SetResourceBytes(StorageDirectory Directory, string Resource, byte[] data)
|
public void SetResourceBytes(StorageDirectory Directory, string Resource, byte[] data)
|
||||||
{
|
{
|
||||||
File.WriteAllBytes(Location + Directories[(byte)Directory] + "/" + Resource, data);
|
File.WriteAllBytes(Location + Directories[(byte)Directory] + "/" + Resource, data);
|
||||||
|
@ -25,7 +25,7 @@ public partial class Server
|
|||||||
this.ApiVersion = API_Version;
|
this.ApiVersion = API_Version;
|
||||||
this.Secure = Secure;
|
this.Secure = Secure;
|
||||||
Storage = new(Domain);
|
Storage = new(Domain);
|
||||||
EncryptionHandler = new(Domain, API_Version, Storage, this.Secure);
|
EncryptionHandler = new(Storage);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool Secure = true;
|
internal bool Secure = true;
|
||||||
|
@ -33,7 +33,6 @@ public class MainSocketUserBase : IncomingHTTP, IUser
|
|||||||
public Task<PublicKeyInfo[]> GetUserKeys(CancellationToken CancellationToken)
|
public Task<PublicKeyInfo[]> GetUserKeys(CancellationToken CancellationToken)
|
||||||
{
|
{
|
||||||
string data = Server.GetFromServer($"Keys/GetUserKey/{Id}", CancellationToken).Content.ReadAsStringAsync().Result;
|
string data = Server.GetFromServer($"Keys/GetUserKey/{Id}", CancellationToken).Content.ReadAsStringAsync().Result;
|
||||||
//return Task.FromResult(new long[] {long.Parse(data)});
|
|
||||||
return Task.FromResult(new[] { new PublicKeyInfo() { Id = long.Parse(data) }});
|
return Task.FromResult(new[] { new PublicKeyInfo() { Id = long.Parse(data) }});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user