From d8fbf281d01bb8cd869f6fe44c0b06a9170d1fc3 Mon Sep 17 00:00:00 2001
From: JacobTech <jacob@jacobtech.com>
Date: Sat, 8 Jul 2023 09:06:13 -0400
Subject: [PATCH] Server Separation.

I moved the two server types to their own classes to prevent API calls to a server, not of that type.
---
 Luski.net/API.cs                              |  14 +-
 Luski.net/Enums/ServerCacheMode.cs            |   8 +
 Luski.net/Interfaces/IServer.cs               |   1 -
 Luski.net/Interfaces/IUser.cs                 |   5 +-
 Luski.net/Luski.net.csproj                    |   2 +-
 ...erver.Account.cs => MainServer.Account.cs} |  22 +--
 Luski.net/MainServer.Events.cs                |  15 ++
 Luski.net/MainServer.Incoming.cs              | 116 ++++++++++++
 Luski.net/MainServer.cs                       | 171 ++++++++++++++++++
 Luski.net/PublicServer.cs                     |   6 +
 Luski.net/Server.Events.cs                    |  20 +-
 Luski.net/Server.Globals.cs                   |  11 +-
 Luski.net/Server.Incoming.cs                  | 125 +------------
 Luski.net/Server.cs                           | 157 +---------------
 .../Structures/Main/MainSocketAppUser.cs      |  48 ++---
 .../Structures/Main/MainSocketChannel.cs      |  10 +-
 .../Structures/Main/MainSocketDMChannel.cs    |   2 +-
 .../MainSocketMessage.cs}                     |  17 +-
 .../Structures/Main/MainSocketRemoteUser.cs   |   5 +-
 .../Structures/Main/MainSocketTextChannel.cs  |  16 +-
 .../MainSocketUserBase.cs}                    |  12 +-
 .../{ => Main}/SocketBulkMessage.cs           |   4 +-
 .../Structures/Public/MainSocketUserBase.cs   |  51 ++++++
 .../Structures/Public/PublicSocketAppUser.cs  |   3 +-
 24 files changed, 464 insertions(+), 377 deletions(-)
 create mode 100644 Luski.net/Enums/ServerCacheMode.cs
 rename Luski.net/{Server.Account.cs => MainServer.Account.cs} (89%)
 create mode 100644 Luski.net/MainServer.Events.cs
 create mode 100644 Luski.net/MainServer.Incoming.cs
 create mode 100644 Luski.net/MainServer.cs
 create mode 100644 Luski.net/PublicServer.cs
 rename Luski.net/Structures/{SocketMessage.cs => Main/MainSocketMessage.cs} (77%)
 rename Luski.net/Structures/{SocketUserBase.cs => Main/MainSocketUserBase.cs} (85%)
 rename Luski.net/Structures/{ => Main}/SocketBulkMessage.cs (83%)
 create mode 100644 Luski.net/Structures/Public/MainSocketUserBase.cs

diff --git a/Luski.net/API.cs b/Luski.net/API.cs
index a6c87f0..7b239f5 100644
--- a/Luski.net/API.cs
+++ b/Luski.net/API.cs
@@ -7,15 +7,15 @@ namespace Luski.net;
 
 public class API
 {
-    public Server<MainSocketAppUser> MainServer { get; internal set; }
-    internal List<Server<PublicSocketAppUser>> InternalServers { get; } = new();
-    public IReadOnlyList<Server<PublicSocketAppUser>> LoadedServers => InternalServers.AsReadOnly();
+    public MainServer MainServer { get; internal set; }
+    internal List<PublicServer> InternalServers { get; } = new();
+    public IReadOnlyList<PublicServer> LoadedServers => InternalServers.AsReadOnly();
     
-    public Server<PublicSocketAppUser> GetPublicServer(string Domain, string Version = "v1")
+    public PublicServer GetPublicServer(string Domain, string Version = "v1")
     {
-        IEnumerable<Server<PublicSocketAppUser>> 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();
-        Server<PublicSocketAppUser> s = new()
+        PublicServer s = new()
         {
             Domain = Domain,
             ApiVersion = Version,
@@ -24,7 +24,7 @@ public class API
         return s;
     }
     
-    public Server<MainSocketAppUser> GetMainServer(string Domain, string Version = "v1")
+    public MainServer GetMainServer(string Domain, string Version = "v1")
     {
         MainServer = new()
         {
diff --git a/Luski.net/Enums/ServerCacheMode.cs b/Luski.net/Enums/ServerCacheMode.cs
new file mode 100644
index 0000000..fa9b152
--- /dev/null
+++ b/Luski.net/Enums/ServerCacheMode.cs
@@ -0,0 +1,8 @@
+namespace Luski.net.Enums;
+
+public enum ServerCacheMode : byte
+{
+    None,
+    Encrypted,
+    Unencrypted
+}
\ No newline at end of file
diff --git a/Luski.net/Interfaces/IServer.cs b/Luski.net/Interfaces/IServer.cs
index 5214204..e20115c 100644
--- a/Luski.net/Interfaces/IServer.cs
+++ b/Luski.net/Interfaces/IServer.cs
@@ -33,6 +33,5 @@ public interface IServer
     public Task<Tresult> SendServer<Tresult>(string Path, string File, JsonTypeInfo<Tresult> ReturnjsonTypeInfo,
         CancellationToken CancellationToken, params KeyValuePair<string, string?>[] Headers)
         where Tresult : IncomingHTTP, new();
-    public Task<Tuser> GetUser<Tuser>(long UserID, CancellationToken CancellationToken) where Tuser : SocketUserBase, new();
 
 }
\ No newline at end of file
diff --git a/Luski.net/Interfaces/IUser.cs b/Luski.net/Interfaces/IUser.cs
index d06108f..26d8bc5 100755
--- a/Luski.net/Interfaces/IUser.cs
+++ b/Luski.net/Interfaces/IUser.cs
@@ -35,8 +35,5 @@ public interface IUser
     /// </summary>
     /// <returns></returns>
     Task<long> GetUserKey(CancellationToken CancellationToken);
-    /// <summary>
-    /// The server that the user comes from
-    /// </summary>
-    IServer Server { get; }
+
 }
diff --git a/Luski.net/Luski.net.csproj b/Luski.net/Luski.net.csproj
index a4622e6..7e53d0b 100755
--- a/Luski.net/Luski.net.csproj
+++ b/Luski.net/Luski.net.csproj
@@ -13,7 +13,7 @@
     <RepositoryUrl>https://github.com/JacobTech-com/Luski.net</RepositoryUrl>
     <IncludeSymbols>True</IncludeSymbols>
     <FileVersion>1.0.0</FileVersion>
-    <Version>1.1.3-alpha23</Version>
+    <Version>1.1.3-alpha24</Version>
   </PropertyGroup>
 
   <ItemGroup>
diff --git a/Luski.net/Server.Account.cs b/Luski.net/MainServer.Account.cs
similarity index 89%
rename from Luski.net/Server.Account.cs
rename to Luski.net/MainServer.Account.cs
index e450715..72d3bf7 100644
--- a/Luski.net/Server.Account.cs
+++ b/Luski.net/MainServer.Account.cs
@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.IO;
 using System.Linq;
 using System.Net.Http;
 using System.Security.Authentication;
@@ -14,23 +15,22 @@ using Luski.net.JsonTypes.WSS;
 using Luski.net.Structures.Main;
 using Luski.net.Structures.Public;
 using WebSocketSharp;
-using File = System.IO.File;
 
 namespace Luski.net;
 
-public partial class Server<TUser>
+public partial class MainServer
 {
-    public void Login(string Email, string Password, CancellationToken CancellationToken)
+    public void Login(string Email, string Password, System.Threading.CancellationToken CancellationToken)
     {
         Both(Email, Password, CancellationToken);
     }
 
-    public void CreateAccount(string Email, string Password, string Username, string PFP, CancellationToken CancellationToken)
+    public void CreateAccount(string Email, string Password, string Username, string PFP, System.Threading.CancellationToken CancellationToken)
     {
         Both(Email, Password, CancellationToken, Username, PFP);
     }
 
-    private void Both(string Email, string Password, CancellationToken CancellationToken, string? Username = null, string? pfp = null)
+    private void Both(string Email, string Password, System.Threading.CancellationToken CancellationToken, string? Username = null, string? pfp = null)
     {
         if (!ClientEncryption.Generating)
         {
@@ -95,15 +95,9 @@ public partial class Server<TUser>
             long id = long.Parse(Encoding.UTF8.GetString(Convert.FromBase64String(
                 Token.Split('.')[0]
             )));
-            TUser t = new();
-            User = t switch
-            {
-                MainSocketAppUser => (GetUser(id, MainSocketAppUserContext.Default.MainSocketAppUser,
-                        CancellationToken.None)
-                    .Result as TUser)!,
-                _ => (GetUser(id, PublicSocketAppUserContext.Default.PublicSocketAppUser, CancellationToken.None)
-                    .Result as TUser)!
-            };
+            User = GetUser(id, MainSocketAppUserContext.Default.MainSocketAppUser,
+                    CancellationToken)
+                .Result;
             if (User is null || User.Error is not null)
             {
                 string error = "User was null";
diff --git a/Luski.net/MainServer.Events.cs b/Luski.net/MainServer.Events.cs
new file mode 100644
index 0000000..011ebe1
--- /dev/null
+++ b/Luski.net/MainServer.Events.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Threading.Tasks;
+using Luski.net.Structures;
+using Luski.net.Structures.Main;
+
+namespace Luski.net;
+
+public partial class MainServer
+{
+    public event Func<MainSocketMessage, Task>? MessageReceived;
+    
+    public event Func<MainSocketRemoteUser, Task>? ReceivedFriendRequest;
+
+    public event Func<MainSocketRemoteUser, bool, Task>? FriendRequestResult;
+}
\ No newline at end of file
diff --git a/Luski.net/MainServer.Incoming.cs b/Luski.net/MainServer.Incoming.cs
new file mode 100644
index 0000000..7d769e6
--- /dev/null
+++ b/Luski.net/MainServer.Incoming.cs
@@ -0,0 +1,116 @@
+using System;
+using System.Text.Json;
+using System.Threading;
+using JacobTechEncryption;
+using Luski.net.Enums;
+using Luski.net.JsonTypes;
+using Luski.net.JsonTypes.BaseTypes;
+using Luski.net.JsonTypes.HTTP;
+using Luski.net.JsonTypes.WSS;
+using Luski.net.Structures;
+using Luski.net.Structures.Main;
+using WebSocketSharp;
+
+namespace Luski.net;
+
+public partial class MainServer
+{
+    private void DataFromServer(object? sender, MessageEventArgs e)
+    {
+        if (e.IsPing) return;
+        try
+        {
+            Console.WriteLine("From Server: {0}", e.Data);
+            IncomingWSS? data = JsonSerializer.Deserialize(e.Data, IncomingWSSContext.Default.IncomingWSS);
+            switch (data?.Type)
+            {
+                case DataType.Login:
+                    Console.WriteLine("Pre auth");
+                    WSSLogin n = JsonSerializer.Deserialize(e.Data, WSSLoginContext.Default.WSSLogin)!;
+                    Token = n.Token;
+                    Console.WriteLine("Token: {0}",Token);
+                    break;
+                case DataType.Error:
+                    if (Token is null)
+                    {
+                        Error = data.Error;
+                    }
+                    else
+                    {
+                        Exception(new Exception(data.Error));
+                    }
+                    break;
+                case DataType.Message_Create:
+                    if (MessageReceived is not null)
+                    {
+                        MainSocketMessage? m = JsonSerializer.Deserialize<MainSocketMessage>(e.Data);
+                        if (m is not null)
+                        {
+                            m.decrypt(ClientEncryption.File.Channels.GetKey(m.ChannelID), CancellationToken.None);
+                            _ = MessageReceived.Invoke(m);
+                        }
+                    }
+                    break;
+                case DataType.Status_Update:
+                    StatusUpdate? SU = JsonSerializer.Deserialize<StatusUpdate>(e.Data);
+                    if (SU is not null)
+                    {
+                        MainSocketRemoteUser after = GetUser(SU.id, MainSocketRemoteUserContext.Default.MainSocketRemoteUser, CancellationToken.None).Result;
+                        after.Status = SU.after;
+                        MainSocketRemoteUser before = after.Clone();
+                        before.Status = SU.before;
+                        StatusUpdate(before, after);
+                    }
+                    break;
+                case DataType.Friend_Request:
+                    if (ReceivedFriendRequest is not null)
+                    {
+                        FriendRequest? request =
+                            JsonSerializer.Deserialize(e.Data, FriendRequestContext.Default.FriendRequest);
+                        if (request is not null)
+                            _ = ReceivedFriendRequest.Invoke(GetUser(request.Id,
+                                MainSocketRemoteUserContext.Default.MainSocketRemoteUser,
+                                CancellationToken.None).Result);
+                    }
+                    break;
+                case DataType.Friend_Request_Result:
+                    FriendRequestResult? FRR = JsonSerializer.Deserialize<FriendRequestResult>(e.Data);
+                    if (FRR is not null && FRR.Channel is not null && FRR.Id is not null &&
+                        FRR.Result is not null)
+                    {
+                        MainSocketDMChannel chan = GetChannel((long)FRR.Channel,
+                            MainSocketDMChannelContext.Default.MainSocketDMChannel,
+                            CancellationToken.None).Result;
+                        chans.Add(chan);
+                        MainSocketRemoteUser from1 = GetUser((long)FRR.Id,
+                            MainSocketRemoteUserContext.Default.MainSocketRemoteUser,
+                            CancellationToken.None).Result;
+                        //from1.Channel = chan;
+                        if (FriendRequestResult is not null) _ = FriendRequestResult.Invoke(from1, (bool)FRR.Result);
+                    }
+                    break;
+                case DataType.Key_Exchange:
+                    try
+                    {
+                        KeyExchange? KE = JsonSerializer.Deserialize<KeyExchange>(e.Data);
+                        if (KE is not null)
+                            ClientEncryption.File.Channels.AddKey(KE.channel,
+                                ClientEncryption.Encoder.GetString(Encryption.RSA.Decrypt(Convert.FromBase64String(KE.key), ClientEncryption.ofkey)));
+                    }
+                    catch (Exception ex)
+                    {
+                        Exception(ex);
+                    }
+
+                    break;
+                default:
+                    Console.WriteLine("Unknown");
+                    break;
+            }
+        }
+        catch (Exception exception)
+        {
+            Exception(exception);
+        }
+    }
+}
\ No newline at end of file
diff --git a/Luski.net/MainServer.cs b/Luski.net/MainServer.cs
new file mode 100644
index 0000000..1b23222
--- /dev/null
+++ b/Luski.net/MainServer.cs
@@ -0,0 +1,171 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.Json.Serialization.Metadata;
+using System.Threading;
+using System.Threading.Tasks;
+using Luski.net.Enums;
+using Luski.net.Interfaces;
+using Luski.net.JsonTypes.BaseTypes;
+using Luski.net.JsonTypes.HTTP;
+using Luski.net.Structures.Main;
+using Luski.net.Structures.Public;
+
+namespace Luski.net;
+
+public partial class MainServer : Server
+{
+    public MainSocketAppUser User { get; internal set; } = default!;
+    
+    public async Task<TChannel> GetChannel<TChannel>(long Channel, CancellationToken CancellationToken) where TChannel : MainSocketChannel, new()
+    {
+        TChannel Return = new();
+        switch (Return)
+        {
+            case MainSocketDMChannel:
+                Return = (await GetChannel(Channel, MainSocketDMChannelContext.Default.MainSocketDMChannel, CancellationToken) as TChannel)!;
+                break;
+            case MainSocketGroupChannel:
+                Return = (await GetChannel(Channel, MainSocketGroupChannelContext.Default.MainSocketGroupChannel, CancellationToken) as TChannel)!;
+                break;
+            case MainSocketTextChannel:
+                Return = (await GetChannel(Channel, MainSocketTextChannelContext.Default.MainSocketTextChannel, CancellationToken) as TChannel)!;
+                break;
+            case MainSocketChannel:
+                Return = (await GetChannel(Channel, MainSocketChannelContext.Default.MainSocketChannel, CancellationToken) as TChannel)!;
+                break;
+            case null:
+                throw new NullReferenceException(nameof(TChannel));
+            default:
+                throw new Exception("Unknown channel type");
+        }
+        return Return;
+    }
+    
+    internal async Task<TChannel> GetChannel<TChannel>(long id, JsonTypeInfo<TChannel> Json, CancellationToken CancellationToken) where TChannel : MainSocketChannel, new()
+    {
+        TChannel request;
+        if (chans.Count > 0 && chans.Any(s => s.Id == id))
+        {
+            return chans.Where(s => s is TChannel && s.Id == id).Cast<TChannel>().FirstOrDefault()!;
+        }
+        while (true)
+        {
+            if (CanRequest)
+            {
+                request = await GetFromServer($"SocketChannel/Get/{id}", Json, CancellationToken);
+                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 (MainSocketChannel? p in chans.Where(s => s.Id == request.Id))
+                {
+                    chans.Remove(p);
+                }
+            }
+            chans.Add(request);
+            return request;
+        }
+        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 Task<Tuser> GetUser<Tuser>(long UserID, CancellationToken CancellationToken) where Tuser : MainSocketUserBase, new()
+    {
+        Tuser user = new();
+        switch (user)
+        {
+            case MainSocketAppUser:
+                user = (GetUser(UserID, MainSocketAppUserContext.Default.MainSocketAppUser, CancellationToken).Result as Tuser)!;
+                break;
+            case MainSocketUserBase:
+                user = (GetUser(UserID, MainSocketUserBaseContext.Default.MainSocketUserBase, CancellationToken).Result as Tuser)!;
+                break;
+            case null:
+                throw new NullReferenceException(nameof(Tuser));
+            default:
+                throw new Exception("Unknown channel type");
+        }
+
+        return Task.FromResult(user);
+    }
+    
+    public async Task<MainSocketMessage> GetMessage(long id, CancellationToken CancellationToken)
+    {
+        MainSocketMessage message;
+        while (true)
+        {
+            if (CanRequest)
+            {
+                message = await GetFromServer("socketmessage",
+                    MainSocketMessageContext.Default.MainSocketMessage,
+                    CancellationToken,
+                    new System.Collections.Generic.KeyValuePair<string, string?>("msg_id", id.ToString()));
+                break;
+            }
+        }
+        if (message is not null) return message;
+        throw new Exception("Server did not return a message");
+    }
+    
+    /// <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;
+    }
+    
+    internal async Task<Tuser> GetUser<Tuser>(long UserId, JsonTypeInfo<Tuser> Json, CancellationToken CancellationToken) where Tuser : MainSocketUserBase, new()
+    {
+        Tuser 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",
+                    Json,
+                    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);
+            }
+        }
+        poeople.Add(user);
+        return user;
+    }
+}
\ No newline at end of file
diff --git a/Luski.net/PublicServer.cs b/Luski.net/PublicServer.cs
new file mode 100644
index 0000000..63bbd3e
--- /dev/null
+++ b/Luski.net/PublicServer.cs
@@ -0,0 +1,6 @@
+namespace Luski.net;
+
+public class PublicServer : Server
+{
+    
+}
\ No newline at end of file
diff --git a/Luski.net/Server.Events.cs b/Luski.net/Server.Events.cs
index 132efcd..e1cb506 100644
--- a/Luski.net/Server.Events.cs
+++ b/Luski.net/Server.Events.cs
@@ -1,20 +1,22 @@
 using System;
 using System.Threading.Tasks;
 using Luski.net.Interfaces;
-using Luski.net.JsonTypes;
-using Luski.net.Structures;
 
 namespace Luski.net;
 
-public partial class Server<TUser>
+public partial class Server
 {
-    public event Func<SocketMessage, Task>? MessageReceived;
-
     public event Func<IUser, IUser, Task>? UserStatusUpdate;
 
-    public event Func<MainSocketRemoteUser, Task>? ReceivedFriendRequest;
-
-    public event Func<MainSocketRemoteUser, bool, Task>? FriendRequestResult;
-    
     public event Func<Exception, Task>? OnError;
+    
+    internal void Exception(Exception e)
+    {
+        if (OnError is not null) OnError.Invoke(e);
+    }
+    
+    internal void StatusUpdate(IUser u1, IUser u2)
+    {
+        if (UserStatusUpdate is not null) UserStatusUpdate.Invoke(u1, u2);
+    }
 }
\ No newline at end of file
diff --git a/Luski.net/Server.Globals.cs b/Luski.net/Server.Globals.cs
index 4959487..1a81f79 100644
--- a/Luski.net/Server.Globals.cs
+++ b/Luski.net/Server.Globals.cs
@@ -4,23 +4,24 @@ using System.IO;
 using Luski.net.Enums;
 using Luski.net.Interfaces;
 using Luski.net.JsonTypes;
+using Luski.net.Structures;
 using Luski.net.Structures.Main;
 using Luski.net.Structures.Public;
 using WebSocketSharp;
 
 namespace Luski.net;
 
-public partial class Server<TUser> where TUser : class, IAppUser, new()
+public partial class Server
 {
     public ServerType ServerType { get; internal set; } = ServerType.Public;
     public string Domain { get; internal set; } = default!;
-    public IAppUser IAppUser => User;
-    public TUser User { get; internal set; }
+    public ServerCacheMode CacheMode { get; set; } = ServerCacheMode.None;
     public string ApiVersion { get; internal set; } = "v1";
-    private WebSocket? ServerOut;
+    internal WebSocket? ServerOut;
     internal  string? Token = null, Error = null, gen = null;
     internal bool CanRequest = false, login = false;
     internal List<IUser> poeople = new();
+    public long UserID { get; internal set; } = 0;
     internal List<MainSocketChannel> chans { get; set; } = new();
     public string Cache
     {
@@ -33,7 +34,7 @@ public partial class Server<TUser> where TUser : class, IAppUser, new()
                 if (!Directory.Exists(path)) Directory.CreateDirectory(path);
                 path += "Data/";
                 if (!Directory.Exists(path)) Directory.CreateDirectory(path);
-                path += User.Id + "/";
+                path += UserID + "/";
                 if (!Directory.Exists(path)) Directory.CreateDirectory(path);
                 path += "Cache/";
                 if (!Directory.Exists(path)) Directory.CreateDirectory(path);
diff --git a/Luski.net/Server.Incoming.cs b/Luski.net/Server.Incoming.cs
index 75f9347..f749c14 100644
--- a/Luski.net/Server.Incoming.cs
+++ b/Luski.net/Server.Incoming.cs
@@ -1,131 +1,12 @@
 using System;
-using System.Text.Json;
-using System.Threading;
-using JacobTechEncryption;
-using Luski.net.Enums;
-using Luski.net.JsonTypes;
-using Luski.net.JsonTypes.BaseTypes;
-using Luski.net.JsonTypes.HTTP;
-using Luski.net.JsonTypes.WSS;
-using Luski.net.Structures;
-using Luski.net.Structures.Main;
 using WebSocketSharp;
 
 namespace Luski.net;
 
-public partial class Server<TUser>
+public partial class Server
 {
-    private void ServerOut_OnError(object? sender, WebSocketSharp.ErrorEventArgs e)
+    internal void ServerOut_OnError(object? sender, ErrorEventArgs e)
     {
-        if (OnError is not null) OnError.Invoke(new Exception(e.Message));
-    }
-    
-    private void DataFromServer(object? sender, MessageEventArgs e)
-    {
-        if (e.IsPing) return;
-        try
-        {
-            Console.WriteLine("From Server: {0}", e.Data);
-            IncomingWSS? data = JsonSerializer.Deserialize(e.Data, IncomingWSSContext.Default.IncomingWSS);
-            switch (data?.Type)
-            {
-                case DataType.Login:
-                    Console.WriteLine("Pre auth");
-                    WSSLogin n = JsonSerializer.Deserialize(e.Data, WSSLoginContext.Default.WSSLogin)!;
-                    Token = n.Token;
-                    Console.WriteLine("Token: {0}",Token);
-                    break;
-                case DataType.Error:
-                    if (Token is null)
-                    {
-                        Error = data.Error;
-                    }
-                    else
-                    {
-                        if (OnError is not null)
-                        {
-                            _ = OnError.Invoke(new Exception(data.Error));
-                        }
-                    }
-                    break;
-                case DataType.Message_Create:
-                    if (MessageReceived is not null)
-                    {
-                        SocketMessage? m = JsonSerializer.Deserialize<SocketMessage>(e.Data);
-                        if (m is not null)
-                        {
-                            m.decrypt(ClientEncryption.File.Channels.GetKey(m.ChannelID), CancellationToken.None);
-                            _ = MessageReceived.Invoke(m);
-                        }
-                    }
-                    break;
-                case DataType.Status_Update:
-                    if (UserStatusUpdate is not null)
-                    {
-                        StatusUpdate? SU = JsonSerializer.Deserialize<StatusUpdate>(e.Data);
-                        if (SU is not null)
-                        {
-                            MainSocketRemoteUser after = GetUser(SU.id, MainSocketRemoteUserContext.Default.MainSocketRemoteUser, CancellationToken.None).Result;
-                            after.Status = SU.after;
-                            MainSocketRemoteUser before = after.Clone();
-                            before.Status = SU.before;
-                            _ = UserStatusUpdate.Invoke(before, after);
-                        }
-                    }
-                    break;
-                case DataType.Friend_Request:
-                    if (ReceivedFriendRequest is not null)
-                    {
-                        FriendRequest? request =
-                            JsonSerializer.Deserialize(e.Data, FriendRequestContext.Default.FriendRequest);
-                        if (request is not null)
-                            _ = ReceivedFriendRequest.Invoke(GetUser(request.Id,
-                                MainSocketRemoteUserContext.Default.MainSocketRemoteUser,
-                                CancellationToken.None).Result);
-                    }
-                    break;
-                case DataType.Friend_Request_Result:
-                    if (FriendRequestResult is not null)
-                    {
-                        FriendRequestResult? FRR = JsonSerializer.Deserialize<FriendRequestResult>(e.Data);
-                        if (FRR is not null && FRR.Channel is not null && FRR.Id is not null &&
-                            FRR.Result is not null)
-                        {
-                            MainSocketDMChannel chan = GetChannel((long)FRR.Channel,
-                                MainSocketDMChannelContext.Default.MainSocketDMChannel,
-                                CancellationToken.None).Result;
-                            chans.Add(chan);
-                            MainSocketRemoteUser from1 = GetUser((long)FRR.Id,
-                                MainSocketRemoteUserContext.Default.MainSocketRemoteUser,
-                                CancellationToken.None).Result;
-                            //from1.Channel = chan;
-                            _ = FriendRequestResult.Invoke(from1, (bool)FRR.Result);
-                        }
-                    }
-                    break;
-                case DataType.Key_Exchange:
-                    try
-                    {
-                        KeyExchange? KE = JsonSerializer.Deserialize<KeyExchange>(e.Data);
-                        if (KE is not null)
-                            ClientEncryption.File.Channels.AddKey(KE.channel,
-                                ClientEncryption.Encoder.GetString(Encryption.RSA.Decrypt(Convert.FromBase64String(KE.key), ClientEncryption.ofkey)));
-                    }
-                    catch (Exception ex)
-                    {
-                        if (OnError is not null) OnError.Invoke(ex);
-                    }
-
-                    break;
-                default:
-                    Console.WriteLine("Unknown");
-                    break;
-            }
-        }
-        catch (Exception exception)
-        {
-            if (OnError is not null) _ = OnError.Invoke(exception);
-            else throw exception;
-        }
+        this.Exception(new Exception(e.Message));
     }
 }
\ No newline at end of file
diff --git a/Luski.net/Server.cs b/Luski.net/Server.cs
index 814b71d..6420dbd 100644
--- a/Luski.net/Server.cs
+++ b/Luski.net/Server.cs
@@ -20,7 +20,7 @@ using File = System.IO.File;
 
 namespace Luski.net;
 
-public partial class Server<TUser> : IServer
+public partial class Server
 {
     internal Server()
     { }
@@ -35,161 +35,6 @@ public partial class Server<TUser> : IServer
         return File.ReadAllBytes($"{Cache}/servers/{Domain}");
     }
 
-    public async Task<Tuser> GetUser<Tuser>(long UserID, CancellationToken CancellationToken) where Tuser : SocketUserBase, new()
-    {
-        Tuser user = new();
-        switch (user)
-        {
-            case MainSocketAppUser:
-                user = (GetUser(UserID, MainSocketAppUserContext.Default.MainSocketAppUser, CancellationToken).Result as Tuser)!;
-                break;
-            case PublicSocketAppUser:
-                user = (GetUser(UserID, PublicSocketAppUserContext.Default.PublicSocketAppUser, CancellationToken).Result as Tuser)!;
-                break;
-            case SocketUserBase:
-                user = (GetUser(UserID, SocketUserBaseContext.Default.SocketUserBase, CancellationToken).Result as Tuser)!;
-                break;
-            case null:
-                throw new NullReferenceException(nameof(Tuser));
-            default:
-                throw new Exception("Unknown channel type");
-        }
-
-        return user;
-    }
-    
-    public async Task<TChannel> GetChannel<TChannel>(long Channel, CancellationToken CancellationToken) where TChannel : MainSocketChannel, new()
-    {
-        TChannel Return = new();
-        switch (Return)
-        {
-            case MainSocketDMChannel:
-                Return = (await GetChannel(Channel, MainSocketDMChannelContext.Default.MainSocketDMChannel, CancellationToken) as TChannel)!;
-                break;
-            case MainSocketGroupChannel:
-                Return = (await GetChannel(Channel, MainSocketGroupChannelContext.Default.MainSocketGroupChannel, CancellationToken) as TChannel)!;
-                break;
-            case MainSocketTextChannel:
-                Return = (await GetChannel(Channel, MainSocketTextChannelContext.Default.MainSocketTextChannel, CancellationToken) as TChannel)!;
-                break;
-            case MainSocketChannel:
-                Return = (await GetChannel(Channel, MainSocketChannelContext.Default.MainSocketChannel, CancellationToken) as TChannel)!;
-                break;
-            case null:
-                throw new NullReferenceException(nameof(TChannel));
-            default:
-                throw new Exception("Unknown channel type");
-        }
-        return Return;
-    }
-    
-    internal async Task<TChannel> GetChannel<TChannel>(long id, JsonTypeInfo<TChannel> Json, CancellationToken CancellationToken) where TChannel : MainSocketChannel, new()
-    {
-        TChannel request;
-        if (chans.Count > 0 && chans.Any(s => s.Id == id))
-        {
-            return chans.Where(s => s is TChannel && s.Id == id).Cast<TChannel>().FirstOrDefault()!;
-        }
-        while (true)
-        {
-            if (CanRequest)
-            {
-                request = await GetFromServer($"SocketChannel/Get/{id}", Json, CancellationToken);
-                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 (MainSocketChannel? p in chans.Where(s => s.Id == request.Id))
-                {
-                    chans.Remove(p);
-                }
-            }
-            chans.Add(request);
-            return request;
-        }
-        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<SocketMessage> GetMessage(long id, CancellationToken CancellationToken)
-    {
-        SocketMessage message;
-        while (true)
-        {
-            if (CanRequest)
-            {
-                message = await GetFromServer("socketmessage",
-                    SocketMessageContext.Default.SocketMessage,
-                    CancellationToken,
-                    new System.Collections.Generic.KeyValuePair<string, string?>("msg_id", id.ToString()));
-                break;
-            }
-        }
-        if (message is not null) return message;
-        throw new Exception("Server did not return a message");
-    }
-    
-    /// <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 as SocketUserBase)!.Status = Status;
-        return Task.CompletedTask;
-    }
-    
-    internal async Task<Tuser> GetUser<Tuser>(long UserId, JsonTypeInfo<Tuser> Json, CancellationToken CancellationToken) where Tuser : SocketUserBase, new()
-    {
-        Tuser 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",
-                    Json,
-                    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);
-            }
-        }
-        poeople.Add(user);
-        return user;
-    }
-
     public void SendServer<Tvalue>(Tvalue Payload, JsonTypeInfo<Tvalue> jsonTypeInfo) where Tvalue : IncomingWSS
     {
         ServerOut?.Send(JsonSerializer.Serialize(Payload, jsonTypeInfo));
diff --git a/Luski.net/Structures/Main/MainSocketAppUser.cs b/Luski.net/Structures/Main/MainSocketAppUser.cs
index 7d3dc8d..20e3a59 100755
--- a/Luski.net/Structures/Main/MainSocketAppUser.cs
+++ b/Luski.net/Structures/Main/MainSocketAppUser.cs
@@ -14,14 +14,19 @@ using Luski.net.JsonTypes;
 
 namespace Luski.net.Structures.Main;
 
-public class MainSocketAppUser : SocketUserBase, IAppUser
+public class MainSocketAppUser : MainSocketUserBase, IAppUser
 {
+    [JsonPropertyName("selected_channel")]
+    [JsonInclude]
+    public long SelectedChannel { get; internal set; } = default!;
     [JsonPropertyName("username")]
     [JsonInclude]
     public string Username { get; internal set; } = default!;
     [JsonPropertyName("flags")]
     [JsonInclude]
     public UserFlag Flags { get; internal set; } = default!;
+
+    public MainServer Server { get; internal set; } = default!;
     
     [JsonIgnore]
     public IReadOnlyList<MainSocketChannel> Channels
@@ -35,17 +40,17 @@ public class MainSocketAppUser : SocketUserBase, IAppUser
                     _Channels = new List<MainSocketChannel>();
                     foreach (long channel in ChannelIdList)
                     {
-                        MainSocketChannel s = (Server as Server<MainSocketAppUser>).GetChannel(channel,
+                        MainSocketChannel s = Server.GetChannel(channel,
                             MainSocketChannelContext.Default.MainSocketChannel, CancellationToken.None).Result;
-                        (Server as Server<MainSocketAppUser>)!.chans.Remove(s);
+                        Server.chans.Remove(s);
                         switch (s.Type)
                         {
                             case ChannelType.GROUP:
-                                _Channels.Add((Server as Server<MainSocketAppUser>).GetChannel(channel,
+                                _Channels.Add(Server.GetChannel(channel,
                                     MainSocketGroupChannelContext.Default.MainSocketGroupChannel, CancellationToken.None).Result);
                                 break;
                             case ChannelType.DM:
-                                _Channels.Add((Server as Server<MainSocketAppUser>).GetChannel(channel,
+                                _Channels.Add(Server.GetChannel(channel,
                                     MainSocketDMChannelContext.Default.MainSocketDMChannel, CancellationToken.None).Result);
                                 break;
                         }
@@ -100,9 +105,6 @@ public class MainSocketAppUser : SocketUserBase, IAppUser
             return _Friends.AsReadOnly();
         }
     }
-    [JsonPropertyName("selected_channel")]
-    [JsonInclude]
-    public long SelectedChannel { get; internal set; } = default!;
     [JsonPropertyName("channels")]
     [JsonInclude]
     public long[] ChannelIdList { get; internal set; } = default!;
@@ -127,33 +129,33 @@ public class MainSocketAppUser : SocketUserBase, IAppUser
 
     internal void AddFriend(MainSocketRemoteUser User)
     {
-        if ((Server as Server<MainSocketAppUser>)!.poeople.Any(s => s.Id == User.Id))
+        if (Server.poeople.Any(s => s.Id == User.Id))
         {
-            IEnumerable<IUser> b = (Server as Server<MainSocketAppUser>)!.poeople.Where(s => s.Id == User.Id);
+            IEnumerable<IUser> b = Server.poeople.Where(s => s.Id == User.Id);
             foreach (IUser item in b)
             {
-                (Server as Server<MainSocketAppUser>)!.poeople.Remove(item);
+                Server.poeople.Remove(item);
             }
-            (Server as Server<MainSocketAppUser>)!.poeople.Add(User);
+            Server.poeople.Add(User);
         }
         else
         {
-            (Server as Server<MainSocketAppUser>)!.poeople.Add(User);
+            Server.poeople.Add(User);
         }
         _Friends.Add(User);
     }
 
     internal void RemoveFriendRequest(MainSocketRemoteUser User)
     {
-        if ((Server as Server<MainSocketAppUser>)!.poeople.Any(s => s.Id == User.Id))
+        if (Server.poeople.Any(s => s.Id == User.Id))
         {
-            IEnumerable<IUser> b = (Server as Server<MainSocketAppUser>)!.poeople.Where(s => s.Id == User.Id);
+            IEnumerable<IUser> b = Server.poeople.Where(s => s.Id == User.Id);
             foreach (IUser item in b)
             {
-                (Server as Server<MainSocketAppUser>)!.poeople.Remove(item);
+                Server.poeople.Remove(item);
             }
-        }
-        (Server as Server<MainSocketAppUser>)!.poeople.Add(User);
+        } 
+        Server.poeople.Add(User);
         foreach (MainSocketRemoteUser user in _FriendRequests)
         {
             if (User.Id == user.Id)
@@ -165,18 +167,18 @@ public class MainSocketAppUser : SocketUserBase, IAppUser
 
     internal void AddFriendRequest(MainSocketRemoteUser User)
     {
-        if ((Server as Server<MainSocketAppUser>)!.poeople.Any(s => s.Id == User.Id))
+        if (Server.poeople.Any(s => s.Id == User.Id))
         {
-            IEnumerable<IUser> b = (Server as Server<MainSocketAppUser>)!.poeople.Where(s => s.Id == User.Id);
+            IEnumerable<IUser> b = Server.poeople.Where(s => s.Id == User.Id);
             foreach (IUser item in b)
             {
-                (Server as Server<MainSocketAppUser>)!.poeople.Remove(item);
+                Server.poeople.Remove(item);
             }
-            (Server as Server<MainSocketAppUser>)!.poeople.Add(User);
+            Server.poeople.Add(User);
         }
         else
         {
-            (Server as Server<MainSocketAppUser>)!.poeople.Add(User);
+            Server.poeople.Add(User);
         }
         _FriendRequests.Add(User);
     }
diff --git a/Luski.net/Structures/Main/MainSocketChannel.cs b/Luski.net/Structures/Main/MainSocketChannel.cs
index a46b6e1..5d5bdd2 100755
--- a/Luski.net/Structures/Main/MainSocketChannel.cs
+++ b/Luski.net/Structures/Main/MainSocketChannel.cs
@@ -34,7 +34,9 @@ public class MainSocketChannel : IncomingHTTP
     [JsonPropertyName("type")]
     [JsonInclude]
     public ChannelType Type { get; internal set; } = default!;
-    public IServer Server { get; internal set; }
+
+    public MainServer Server { get; internal set; } = default!;
+    
     [JsonPropertyName("members")]
     [JsonInclude]
     public long[] MemberIdList { get; internal set; } = default!;
@@ -49,8 +51,8 @@ public class MainSocketChannel : IncomingHTTP
                 _members = new();
                 foreach (long member in MemberIdList)
                 {
-                    if (member != Server.IAppUser!.Id) _members.Add(Server.GetUser<MainSocketRemoteUser>(member, CancellationToken.None).Result);
-                    else _members.Add(Server.IAppUser);
+                    if (member != Server.User.Id) _members.Add(Server.GetUser<MainSocketRemoteUser>(member, CancellationToken.None).Result);
+                    else _members.Add(Server.User);
                 }
             }
             return _members.AsReadOnly();
@@ -74,7 +76,7 @@ public class MainSocketChannel : IncomingHTTP
             MaxDegreeOfParallelism = num
         }, i =>
         {
-            if (i.Id != (Server as Server<MainSocketAppUser>).User?.Id)
+            if (i.Id != Server.User.Id)
             {
                 long key = i.GetUserKey(CancellationToken).Result;
                 if (true)
diff --git a/Luski.net/Structures/Main/MainSocketDMChannel.cs b/Luski.net/Structures/Main/MainSocketDMChannel.cs
index c330a3d..8e9b77f 100755
--- a/Luski.net/Structures/Main/MainSocketDMChannel.cs
+++ b/Luski.net/Structures/Main/MainSocketDMChannel.cs
@@ -14,7 +14,7 @@ public class MainSocketDMChannel : MainSocketTextChannel
             if (_user is null)
             {
                 var list = MemberIdList.ToList();
-                list.Remove(Server.IAppUser.Id);
+                list.Remove(Server.User.Id);
                 _user = Server.GetUser<MainSocketRemoteUser>(list.FirstOrDefault(), CancellationToken.None).Result;
             }
             return _user;
diff --git a/Luski.net/Structures/SocketMessage.cs b/Luski.net/Structures/Main/MainSocketMessage.cs
similarity index 77%
rename from Luski.net/Structures/SocketMessage.cs
rename to Luski.net/Structures/Main/MainSocketMessage.cs
index 5e41bda..f51ca04 100755
--- a/Luski.net/Structures/SocketMessage.cs
+++ b/Luski.net/Structures/Main/MainSocketMessage.cs
@@ -1,20 +1,17 @@
 using Luski.net.Interfaces;
 using Luski.net.JsonTypes.BaseTypes;
 using System;
-using System.Linq;
-using System.Net.Http;
 using System.Text;
-using System.Text.Json;
 using System.Text.Json.Serialization;
 using System.Threading;
 using System.Threading.Tasks;
 using JacobTechEncryption;
 
-namespace Luski.net.Structures;
+namespace Luski.net.Structures.Main;
 
-public class SocketMessage : IncomingHTTP
+public class MainSocketMessage : IncomingHTTP
 {
-    public IServer Server { get; }
+    public MainServer Server { get; internal set; } = default!;
     [JsonPropertyName("id")]
     [JsonInclude]
     public long Id { get; internal set; } = default!;
@@ -32,8 +29,8 @@ public class SocketMessage : IncomingHTTP
     public File[]? Files { get; internal set; } = default!;
     public async Task<IUser> GetAuthor(CancellationToken CancellationToken)
     {
-        if (Server.IAppUser!.Id != AuthorID) return await Server.GetUser<SocketUserBase>(AuthorID, CancellationToken);
-        else return Server.IAppUser;
+        if (Server.User.Id != AuthorID) return await Server.GetUser<MainSocketUserBase>(AuthorID, CancellationToken);
+        else return Server.User;
     }
 
     internal void decrypt(string? key, CancellationToken CancellationToken)
@@ -51,12 +48,12 @@ public class SocketMessage : IncomingHTTP
     }
 }
 
-[JsonSerializable(typeof(SocketMessage))]
+[JsonSerializable(typeof(MainSocketMessage))]
 [JsonSourceGenerationOptions(
     GenerationMode = JsonSourceGenerationMode.Default,
     PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
     WriteIndented = false)]
-public partial class SocketMessageContext : JsonSerializerContext
+public partial class MainSocketMessageContext : JsonSerializerContext
 {
 
 }
diff --git a/Luski.net/Structures/Main/MainSocketRemoteUser.cs b/Luski.net/Structures/Main/MainSocketRemoteUser.cs
index 9ac8862..34ab431 100755
--- a/Luski.net/Structures/Main/MainSocketRemoteUser.cs
+++ b/Luski.net/Structures/Main/MainSocketRemoteUser.cs
@@ -9,10 +9,11 @@ using System.Text.Json.Serialization;
 using System.Threading.Tasks;
 using Luski.net.Enums.Main;
 using Luski.net.Structures;
+using Luski.net.Structures.Main;
 
-namespace Luski.net.Structures;
+namespace Luski.net.Structures.Main;
 
-public class MainSocketRemoteUser : SocketUserBase
+public class MainSocketRemoteUser : MainSocketUserBase
 {
     [JsonPropertyName("friend_status")]
     [JsonInclude]
diff --git a/Luski.net/Structures/Main/MainSocketTextChannel.cs b/Luski.net/Structures/Main/MainSocketTextChannel.cs
index ce83d2e..f07062a 100755
--- a/Luski.net/Structures/Main/MainSocketTextChannel.cs
+++ b/Luski.net/Structures/Main/MainSocketTextChannel.cs
@@ -17,9 +17,9 @@ namespace Luski.net.Structures.Main;
 
 public class MainSocketTextChannel : MainSocketChannel
 {
-    public async Task<SocketMessage> GetMessage(long ID, CancellationToken CancellationToken)
+    public async Task<MainSocketMessage> GetMessage(long ID, CancellationToken CancellationToken)
     {
-        return await (Server as Server<MainSocketAppUser>)!.GetMessage(ID, CancellationToken);
+        return await Server.GetMessage(ID, CancellationToken);
     }
 
     public async Task<byte[]> GetPicture(CancellationToken CancellationToken)
@@ -36,7 +36,7 @@ public class MainSocketTextChannel : MainSocketChannel
         }
     }
 
-    public async Task<IReadOnlyList<SocketMessage>> GetMessages(long Message_Id, CancellationToken CancellationToken, int count = 50)
+    public async Task<IReadOnlyList<MainSocketMessage>> GetMessages(long Message_Id, CancellationToken CancellationToken, int count = 50)
     {
         if (count > 200)
         {
@@ -61,7 +61,7 @@ public class MainSocketTextChannel : MainSocketChannel
 
                 string? key = ClientEncryption.File.Channels.GetKey(Id);
                 if (data is null) throw new Exception("Invalid data from server");
-                if (data.Messages is null) data.Messages = Array.Empty<SocketMessage>();
+                if (data.Messages is null) data.Messages = Array.Empty<MainSocketMessage>();
                 Parallel.ForEach(data.Messages, new ParallelOptions()
                 {
                     MaxDegreeOfParallelism = num
@@ -70,7 +70,7 @@ public class MainSocketTextChannel : MainSocketChannel
                     i.decrypt(key, CancellationToken);
                 });
                 key = null;
-                return await Task.FromResult(data.Messages.ToList().AsReadOnly() as IReadOnlyList<SocketMessage>);
+                return await Task.FromResult(data.Messages.ToList().AsReadOnly() as IReadOnlyList<MainSocketMessage>);
             }
             else
             {
@@ -79,7 +79,7 @@ public class MainSocketTextChannel : MainSocketChannel
         }
     }
 
-    public async Task<IReadOnlyList<SocketMessage>> GetMessages(CancellationToken CancellationToken, int count = 50)
+    public async Task<IReadOnlyList<MainSocketMessage>> GetMessages(CancellationToken CancellationToken, int count = 50)
     {
         try
         {
@@ -106,7 +106,7 @@ public class MainSocketTextChannel : MainSocketChannel
                     int num = Convert.ToInt32(Math.Ceiling((Environment.ProcessorCount * 5) * 2.0));
                     if (num == 0) num = 1;
                     string? key = ClientEncryption.File.Channels.GetKey(Id);
-                    if (data.Messages is null) data.Messages = Array.Empty<SocketMessage>();
+                    if (data.Messages is null) data.Messages = Array.Empty<MainSocketMessage>();
                     Parallel.ForEach(data.Messages, new ParallelOptions()
                     {
                         MaxDegreeOfParallelism = num
@@ -116,7 +116,7 @@ public class MainSocketTextChannel : MainSocketChannel
                     });
                     key = null;
                     Console.WriteLine($"Messages decrypted in {(DateTime.Now - start).TotalSeconds}");
-                    return await Task.FromResult(data.Messages.ToList().AsReadOnly() as IReadOnlyList<SocketMessage>);
+                    return await Task.FromResult(data.Messages.ToList().AsReadOnly() as IReadOnlyList<MainSocketMessage>);
                 }
                 else
                 {
diff --git a/Luski.net/Structures/SocketUserBase.cs b/Luski.net/Structures/Main/MainSocketUserBase.cs
similarity index 85%
rename from Luski.net/Structures/SocketUserBase.cs
rename to Luski.net/Structures/Main/MainSocketUserBase.cs
index f29c9ec..7b63322 100644
--- a/Luski.net/Structures/SocketUserBase.cs
+++ b/Luski.net/Structures/Main/MainSocketUserBase.cs
@@ -5,10 +5,11 @@ using Luski.net.Enums;
 using Luski.net.Interfaces;
 using Luski.net.JsonTypes.BaseTypes;
 
-namespace Luski.net.Structures;
+namespace Luski.net.Structures.Main;
 
-public class SocketUserBase : IncomingHTTP, IUser
+public class MainSocketUserBase : IncomingHTTP, IUser
 {
+    public MainServer Server { get; internal set; } = default!;
     [JsonPropertyName("id")]
     [JsonInclude]
     public long Id { get; internal set; } = default!;
@@ -21,9 +22,6 @@ public class SocketUserBase : IncomingHTTP, IUser
     [JsonPropertyName("picture_type")]
     [JsonInclude]
     public PictureType PictureType { get; internal set; } = default!;
-    [JsonIgnore]
-    public IServer Server { get; internal set; } = default!;
-    
     public async Task<byte[]> GetAvatar(CancellationToken CancellationToken)
     {
         if (Server.Cache != null)
@@ -41,13 +39,13 @@ public class SocketUserBase : IncomingHTTP, IUser
     }
 }
 
-[JsonSerializable(typeof(SocketUserBase))]
+[JsonSerializable(typeof(MainSocketUserBase))]
 [JsonSourceGenerationOptions(
     GenerationMode = JsonSourceGenerationMode.Default,
     PropertyNamingPolicy = JsonKnownNamingPolicy.Unspecified,
     WriteIndented = false,
     DefaultIgnoreCondition = JsonIgnoreCondition.Never)]
-internal partial class SocketUserBaseContext : JsonSerializerContext
+internal partial class MainSocketUserBaseContext : JsonSerializerContext
 {
 
 }
\ No newline at end of file
diff --git a/Luski.net/Structures/SocketBulkMessage.cs b/Luski.net/Structures/Main/SocketBulkMessage.cs
similarity index 83%
rename from Luski.net/Structures/SocketBulkMessage.cs
rename to Luski.net/Structures/Main/SocketBulkMessage.cs
index 3ec44d4..5a5b336 100755
--- a/Luski.net/Structures/SocketBulkMessage.cs
+++ b/Luski.net/Structures/Main/SocketBulkMessage.cs
@@ -1,13 +1,13 @@
 using Luski.net.JsonTypes.BaseTypes;
 using System.Text.Json.Serialization;
 
-namespace Luski.net.Structures;
+namespace Luski.net.Structures.Main;
 
 internal class SocketBulkMessage : IncomingHTTP
 {
     [JsonPropertyName("messages")]
     [JsonInclude]
-    public SocketMessage[]? Messages { get; set; } = default!;
+    public MainSocketMessage[]? Messages { get; set; } = default!;
 }
 
 [JsonSerializable(typeof(SocketBulkMessage))]
diff --git a/Luski.net/Structures/Public/MainSocketUserBase.cs b/Luski.net/Structures/Public/MainSocketUserBase.cs
new file mode 100644
index 0000000..0252a20
--- /dev/null
+++ b/Luski.net/Structures/Public/MainSocketUserBase.cs
@@ -0,0 +1,51 @@
+using System.Text.Json.Serialization;
+using System.Threading;
+using System.Threading.Tasks;
+using Luski.net.Enums;
+using Luski.net.Interfaces;
+using Luski.net.JsonTypes.BaseTypes;
+
+namespace Luski.net.Structures.Public;
+
+public class PublicSocketUserBase : IncomingHTTP, IUser
+{
+    public PublicServer Server { get; internal set; } = default!;
+    [JsonPropertyName("id")]
+    [JsonInclude]
+    public long Id { get; internal set; } = default!;
+    [JsonPropertyName("username")]
+    [JsonInclude]
+    public string DisplayName { get; internal set; } = default!;
+    [JsonPropertyName("status")]
+    [JsonInclude]
+    public UserStatus Status { get; internal set; } = default!;
+    [JsonPropertyName("picture_type")]
+    [JsonInclude]
+    public PictureType PictureType { get; internal set; } = default!;
+    public async Task<byte[]> GetAvatar(CancellationToken CancellationToken)
+    {
+        if (Server.Cache != null)
+        {
+            bool isc = System.IO.File.Exists($"{Server.Cache}/avatars/{Id}");
+            if (!isc) await Server.GetFromServer($"socketuserprofile/Avatar/{Id}", $"{Server.Cache}/avatars/{Id}", CancellationToken);
+        }
+        return System.IO.File.ReadAllBytes($"{Server.Cache}/avatars/{Id}");
+    }
+
+    public Task<long> GetUserKey(CancellationToken CancellationToken)
+    {
+        string data = Server.GetFromServer($"Keys/GetUserKey/{Id}", CancellationToken).Content.ReadAsStringAsync().Result;
+        return Task.FromResult(long.Parse(data));
+    }
+}
+
+[JsonSerializable(typeof(PublicSocketUserBase))]
+[JsonSourceGenerationOptions(
+    GenerationMode = JsonSourceGenerationMode.Default,
+    PropertyNamingPolicy = JsonKnownNamingPolicy.Unspecified,
+    WriteIndented = false,
+    DefaultIgnoreCondition = JsonIgnoreCondition.Never)]
+internal partial class PublicSocketUserBaseContext : JsonSerializerContext
+{
+
+}
\ No newline at end of file
diff --git a/Luski.net/Structures/Public/PublicSocketAppUser.cs b/Luski.net/Structures/Public/PublicSocketAppUser.cs
index 0b7250b..65706f5 100755
--- a/Luski.net/Structures/Public/PublicSocketAppUser.cs
+++ b/Luski.net/Structures/Public/PublicSocketAppUser.cs
@@ -10,10 +10,11 @@ using System.Threading.Tasks;
 using JacobTechEncryption;
 using Luski.net.Enums;
 using Luski.net.Enums.Main;
+using Luski.net.Structures.Main;
 
 namespace Luski.net.Structures.Public;
 
-public class PublicSocketAppUser : SocketUserBase, IAppUser
+public class PublicSocketAppUser : PublicSocketUserBase, IAppUser
 {
     [JsonPropertyName("selected_channel")]
     [JsonInclude]