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)
|
||||
{
|
||||
DateTime dt = DateTime.UtcNow;
|
||||
Console.WriteLine("Connecting to public server '{0}' using API {1}.", Domain, Version);
|
||||
PublicServer s;
|
||||
try
|
||||
{
|
||||
IEnumerable<PublicServer> isl = InternalServers.Where(a => (a.Domain == Domain && a.ApiVersion == Version));
|
||||
if (isl.Any()) return isl.First();
|
||||
s = new(Domain, Version, Secure)
|
||||
{
|
||||
ServerType = ServerType.Public
|
||||
};
|
||||
s = await PublicServer.GetServer(Domain, Version, Secure);
|
||||
}
|
||||
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;
|
||||
}
|
||||
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";
|
||||
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 description { get; set; }
|
||||
public long owner { get; set; }
|
||||
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("alternate_servers")]
|
||||
public ServerData[] AlternateServers { get; set; } = default!;
|
||||
}
|
||||
|
||||
[JsonSerializable(typeof(ServerInfo))]
|
||||
|
@ -13,7 +13,7 @@
|
||||
<RepositoryUrl>https://github.com/JacobTech-com/Luski.net</RepositoryUrl>
|
||||
<IncludeSymbols>True</IncludeSymbols>
|
||||
<FileVersion>1.0.0</FileVersion>
|
||||
<Version>2.0.0-alpha12</Version>
|
||||
<Version>2.0.0-alpha23</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Text.Json.Serialization.Metadata;
|
||||
using System.Threading;
|
||||
@ -29,14 +30,63 @@ public partial class PublicServer : Server
|
||||
public List<Role> roles { get; } = new();
|
||||
|
||||
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)
|
||||
{ }
|
||||
|
||||
internal static async Task<PublicServer> GetServer(string Domain, string API_Version, bool Secure = true)
|
||||
{
|
||||
ServerInfo si = GetFromServer("socketserver", ServerInfoContext.Default.ServerInfo, CancellationToken.None).Result;
|
||||
Name = si.name;
|
||||
Description = si.description;
|
||||
wssurl = si.wssv4;
|
||||
DateTime dt = DateTime.UtcNow;
|
||||
Console.WriteLine("Connecting to public server '{0}' using API {1}.", Domain, API_Version);
|
||||
PublicServer s = new(Domain, API_Version, Secure);
|
||||
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()
|
||||
@ -295,6 +345,6 @@ public partial class PublicServer : Server
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public string Description { get; }
|
||||
public string Name { get; private set; }
|
||||
public string Description { get; private set; }
|
||||
}
|
@ -12,12 +12,11 @@ public class ServerEncryption
|
||||
{
|
||||
internal bool Generating, Generated;
|
||||
internal string ServerPublicKey = "", MyPublicKey = "", myPrivateKey = "", OfflinePrivateKey = "", OfflinePublicKey = "";
|
||||
|
||||
internal byte[] Hash = default!;
|
||||
internal ServerEncryption(string Domain, string API_Version, ServerStorage Storage, bool Secure)
|
||||
internal ServerEncryption(ServerStorage 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)
|
||||
|
@ -14,7 +14,7 @@ namespace Luski.net;
|
||||
public partial class Server
|
||||
{
|
||||
public ServerType ServerType { get; internal set; } = ServerType.Public;
|
||||
public string Domain { get; } = default!;
|
||||
public string Domain { get; set; } = default!;
|
||||
public string ApiVersion { get; } = "v1";
|
||||
internal WebSocket? ServerOut;
|
||||
internal string? Token = null, Error = null, gen = null;
|
||||
|
@ -4,6 +4,7 @@ using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization.Metadata;
|
||||
using JacobTechEncryption;
|
||||
using JacobTechEncryption.Enums;
|
||||
using Luski.net.Enums;
|
||||
@ -73,6 +74,20 @@ public class ServerStorage
|
||||
|
||||
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)
|
||||
{
|
||||
try
|
||||
@ -218,6 +233,11 @@ public class ServerStorage
|
||||
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)
|
||||
{
|
||||
return Encoding.UTF8.GetString(Encryption.AES.Decrypt(GetResourceBytes(Directory, Resource), Key));
|
||||
@ -283,6 +303,23 @@ public class ServerStorage
|
||||
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)
|
||||
{
|
||||
File.WriteAllBytes(Location + Directories[(byte)Directory] + "/" + Resource, data);
|
||||
|
@ -25,7 +25,7 @@ public partial class Server
|
||||
this.ApiVersion = API_Version;
|
||||
this.Secure = Secure;
|
||||
Storage = new(Domain);
|
||||
EncryptionHandler = new(Domain, API_Version, Storage, this.Secure);
|
||||
EncryptionHandler = new(Storage);
|
||||
}
|
||||
|
||||
internal bool Secure = true;
|
||||
|
@ -33,7 +33,6 @@ public class MainSocketUserBase : IncomingHTTP, IUser
|
||||
public Task<PublicKeyInfo[]> GetUserKeys(CancellationToken CancellationToken)
|
||||
{
|
||||
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) }});
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user