Luski.Net/Luski.net/PublicServer.cs

350 lines
15 KiB
C#
Raw Normal View History

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;
using System.Threading.Tasks;
using JacobTechEncryption;
using JacobTechEncryption.Enums;
using Luski.net.Enums;
using Luski.net.Enums.Main;
using Luski.net.Interfaces;
using Luski.net.JsonTypes;
using Luski.net.JsonTypes.BaseTypes;
using Luski.net.JsonTypes.HTTP;
using Luski.net.JsonTypes.Public;
using Luski.net.Structures;
using Luski.net.Structures.Public;
using Channel = Luski.net.JsonTypes.Public.Channel;
using Role = Luski.net.Structures.Public.Role;
using SocketUser = Luski.net.Structures.Public.SocketUser;
namespace Luski.net;
public partial class PublicServer : Server
{
public List<SocketChannel> chans { get; } = new();
public List<SocketCategory> cats { get; } = new();
public List<Role> roles { get; } = new();
public SocketAppUser User { get; private set; } = null!;
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)
{
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()
{
Category request;
if (cats.Count > 0 && cats.Any(s => s.ID == id))
{
return (cats.Where(s => s is TCategory && s.ID == id).First() as TCategory)!;
}
while (true)
{
if (CanRequest)
{
request = await GetFromServer($"SocketCategory", PublicCategoryContext.Default.Category, CancellationToken, new KeyValuePair<string, string?>("id", id.ToString()));
break;
}
}
if (request is null) throw new Exception("Something was wrong with the server responce");
if (request.Error is null)
{
if (cats.Count > 0 && cats.Any(s => s.ID == request.ID))
{
foreach (SocketCategory? p in cats.Where(s => s.ID == request.ID))
{
cats.Remove(p);
}
}
LocalKeyInfo deckey = EncryptionHandler.GetKey(request.DescriptionEncryptionKey);
string dec = deckey.EncryptionType switch
{
EncryptionType.RSA => Encryption.RSA.Decrypt(Convert.FromBase64String(request.Description), deckey.Key, request.DescriptionEncoderType),
EncryptionType.AES => Encryption.Generic.Encoders[(short)request.DescriptionEncoderType].GetString(
Encryption.AES.Decrypt(Convert.FromBase64String(request.Description), deckey.Key)),
_ => Encryption.Generic.Encoders[(short)request.DescriptionEncoderType].GetString(Convert.FromBase64String(request.Description))
};
LocalKeyInfo nkey = EncryptionHandler.GetKey(request.TitleEncryptionKey);
string n = nkey.EncryptionType switch
{
EncryptionType.RSA => Encryption.RSA.Decrypt(Convert.FromBase64String(request.Name), nkey.Key, request.TitleEncoderType),
EncryptionType.AES => Encryption.Generic.Encoders[(short)request.TitleEncoderType].GetString(
Encryption.AES.Decrypt(Convert.FromBase64String(request.Name), nkey.Key)),
_ => Encryption.Generic.Encoders[(short)request.TitleEncoderType].GetString(Convert.FromBase64String(request.Name))
};
TCategory bob = new()
{
ID = request.ID,
ParentID = request.Parent,
Description = dec,
DescriptionEncoderType = request.DescriptionEncoderType,
DescriptionEncryptionKey = request.DescriptionEncryptionKey,
Channels = request.Channels,
Categories = request.InnerCategories,
Name = n,
RoleOverides = request.RoleOverides,
UserOverides = request.UserOverides,
TitleEncoderType = request.TitleEncoderType,
TitleEncryptionKey = request.TitleEncryptionKey,
Server = this,
Color = new(request.Color)
};
cats.Add(bob);
return bob;
}
throw request.Error switch
{
ErrorCode.InvalidToken => new Exception("Your current token is no longer valid"),
ErrorCode.Forbidden => new Exception("The server rejected your request"),
ErrorCode.ServerError => new Exception("Error from server: " + request.ErrorMessage),
ErrorCode.InvalidURL or ErrorCode.MissingHeader => new Exception(request.ErrorMessage),
_ => new Exception($"Unknown data: '{request.ErrorMessage}'"),
};
}
public async Task<Role> GetRole(long id)
{
Role[] r = roles.Where(s => s.ID == id).ToArray();
if (r.Length > 0) return r[0];
JsonTypes.Public.Role s = await GetFromServer("SocketRole?id=" + id.ToString(), RoleContext.Default.Role, CancellationToken.None);
Role role = new()
{
Server = this,
ID = s.id,
Color = new(s.color),
Description = s.description,
DisplayName = s.display_name,
MembersListID = s.members_list,
Name = s.name,
Index = s.index,
ServerPermissions = s.server_permissions
};
roles.Add(role);
return role;
}
public async Task<TChannel> GetChannel<TChannel>(long id, CancellationToken CancellationToken) where TChannel : SocketChannel, new()
{
Channel request;
if (chans.Count > 0 && chans.Any(s => s.ID == id))
{
return (chans.Where(s => s is TChannel && s.ID == id).First() as TChannel)!;
}
while (true)
{
if (CanRequest)
{
request = await GetFromServer($"SocketChannel", PublicChannelContext.Default.Channel, CancellationToken, new KeyValuePair<string, string?>("id", id.ToString()));
break;
}
}
if (request is null) throw new Exception("Something was wrong with the server responce");
if (request.Error is null)
{
if (chans.Count > 0 && chans.Any(s => s.ID == request.ID))
{
foreach (SocketChannel? p in chans.Where(s => s.ID == request.ID))
{
chans.Remove(p);
}
}
LocalKeyInfo deckey = EncryptionHandler.GetKey(request.DescriptionEncryptionKey);
string dec = deckey.EncryptionType switch
{
EncryptionType.RSA => Encryption.RSA.Decrypt(Convert.FromBase64String(request.Description), deckey.Key, request.DescriptionEncoderType),
EncryptionType.AES => Encryption.Generic.Encoders[(short)request.DescriptionEncoderType].GetString(
Encryption.AES.Decrypt(Convert.FromBase64String(request.Description), deckey.Key)),
_ => Encryption.Generic.Encoders[(short)request.DescriptionEncoderType].GetString(Convert.FromBase64String(request.Description))
};
LocalKeyInfo nkey = EncryptionHandler.GetKey(request.TitleEncryptionKey);
string n = nkey.EncryptionType switch
{
EncryptionType.RSA => Encryption.RSA.Decrypt(Convert.FromBase64String(request.Name), nkey.Key, request.TitleEncoderType),
EncryptionType.AES => Encryption.Generic.Encoders[(short)request.TitleEncoderType].GetString(
Encryption.AES.Decrypt(Convert.FromBase64String(request.Name), nkey.Key)),
_ => Encryption.Generic.Encoders[(short)request.TitleEncoderType].GetString(Convert.FromBase64String(request.Name))
};
TChannel bob = new()
{
ID = request.ID,
CategoryID = request.Parent,
Description = dec,
DescriptionEncoderType = request.DescriptionEncoderType,
DescriptionEncryptionKey = request.DescriptionEncryptionKey,
EncoderTypes = request.EncoderTypes,
EncryptionKeys = request.EncryptionKeys,
Epoch = request.Epoch,
Name = n,
RoleOverides = request.RoleOverides,
UserOverides = request.UserOverides,
Type = request.Type,
TitleEncoderType = request.TitleEncoderType,
TitleEncryptionKey = request.TitleEncryptionKey,
PictureType = request.PictureType,
Server = this,
Color = new(request.Color)
};
chans.Add(bob);
return bob;
}
throw request.Error switch
{
ErrorCode.InvalidToken => new Exception("Your current token is no longer valid"),
ErrorCode.Forbidden => new Exception("The server rejected your request"),
ErrorCode.ServerError => new Exception("Error from server: " + request.ErrorMessage),
ErrorCode.InvalidURL or ErrorCode.MissingHeader => new Exception(request.ErrorMessage),
_ => new Exception($"Unknown data: '{request.ErrorMessage}'"),
};
}
public async Task<Tuser> GetUser<Tuser>(long UserId, CancellationToken CancellationToken) where Tuser : SocketUser, new()
{
JsonTypes.Public.SocketUser user;
if (poeople.Count > 0 && poeople.Any(s => s.Id == UserId))
{
Tuser temp = poeople.Where(s => s is Tuser && s.Id == UserId).Cast<Tuser>().FirstOrDefault()!;
return temp;
}
while (true)
{
if (CanRequest)
{
user = await GetFromServer("socketuser",
PublicSocketUserContext.Default.SocketUser,
CancellationToken,
new KeyValuePair<string, string?>("id", UserId.ToString()));
break;
}
}
if (user is null) throw new Exception("Server did not return a user");
if (poeople.Count > 0 && poeople.Any(s => s.Id == UserId))
{
foreach (IUser? p in poeople.Where(s => s.Id == UserId))
{
poeople.Remove(p);
}
}
if (user is null || user.Error is not null)
{
string error = "User was null";
if (user is not null && user.Error is not null) error = $"{user.Error}: {user.ErrorMessage}";
throw new Exception($"Something went wrong getting your user information\n{error}");
}
Tuser u = new();
if (u is SocketUser)
{
u = new()
{
Server = this,
Id = user.ID,
DisplayName = user.DisplayName,
PictureType = user.PictureType,
RoleIds = user.RoleIds,
Status = user.Status
};
}
else
{
u = (new SocketAppUser()
{
Server = this,
Id = user.ID,
DisplayName = user.DisplayName,
SelectedChannel = user.SelectedChannel,
PictureType = user.PictureType,
RoleIds = user.RoleIds,
Status = user.Status,
Username = user.Username
} as Tuser)!;
}
poeople.Add(u);
return u;
}
/// <summary>
/// Sends the server a request to update the <paramref name="Status"/> of you account
/// </summary>
/// <param name="Status">The <see cref="UserStatus"/> you want to set your status to</param>
/// <exception cref="Exception"></exception>
public async Task<Task> UpdateStatus(UserStatus Status, CancellationToken CancellationToken)
{
IncomingHTTP? data = await SendServer("SocketUserProfile/Status", new Status() { UserStatus = Status }, StatusContext.Default.Status, IncomingHTTPContext.Default.IncomingHTTP, CancellationToken);
if (data.Error is not null && ((int)data.StatusCode < 200 || (int)data.StatusCode > 299))
{
if (data?.ErrorMessage is not null) throw new Exception(data.ErrorMessage);
if (data?.Error is not null) throw new Exception(((int)data.Error).ToString());
else throw new Exception("Something went worng");
}
User.Status = Status;
return Task.CompletedTask;
}
public string Name { get; private set; }
public string Description { get; private set; }
}