Apparently this is what's actually running on the server.

This commit is contained in:
flash 2022-08-30 15:21:00 +00:00
parent 5d2b9f62c1
commit 23f0bd478f
13 changed files with 411 additions and 75 deletions

6
.gitignore vendored
View file

@ -1,6 +1,12 @@
## Ignore Visual Studio temporary files, build results, and ## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons. ## files generated by popular Visual Studio add-ons.
welcome.txt
mariadb.txt
login_key.txt
http-motd.txt
_webdb.txt
# User-specific files # User-specific files
*.suo *.suo
*.user *.user

View file

@ -5,7 +5,7 @@ VisualStudioVersion = 16.0.29025.244
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpChat", "SharpChat\SharpChat.csproj", "{DDB24C19-B802-4C96-AC15-0449C6FC77F2}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpChat", "SharpChat\SharpChat.csproj", "{DDB24C19-B802-4C96-AC15-0449C6FC77F2}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hamakaze", "Hamakaze\Hamakaze.csproj", "{6059200F-141C-42A5-AA3F-E38C9721AEC8}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpChatTest", "SharpChatTest\SharpChatTest.csproj", "{6CD6DB9D-E0FF-4DEB-8E28-0C3EA6BA26B2}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -17,10 +17,10 @@ Global
{DDB24C19-B802-4C96-AC15-0449C6FC77F2}.Debug|Any CPU.Build.0 = Debug|Any CPU {DDB24C19-B802-4C96-AC15-0449C6FC77F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DDB24C19-B802-4C96-AC15-0449C6FC77F2}.Release|Any CPU.ActiveCfg = Release|Any CPU {DDB24C19-B802-4C96-AC15-0449C6FC77F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DDB24C19-B802-4C96-AC15-0449C6FC77F2}.Release|Any CPU.Build.0 = Release|Any CPU {DDB24C19-B802-4C96-AC15-0449C6FC77F2}.Release|Any CPU.Build.0 = Release|Any CPU
{6059200F-141C-42A5-AA3F-E38C9721AEC8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6CD6DB9D-E0FF-4DEB-8E28-0C3EA6BA26B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6059200F-141C-42A5-AA3F-E38C9721AEC8}.Debug|Any CPU.Build.0 = Debug|Any CPU {6CD6DB9D-E0FF-4DEB-8E28-0C3EA6BA26B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6059200F-141C-42A5-AA3F-E38C9721AEC8}.Release|Any CPU.ActiveCfg = Release|Any CPU {6CD6DB9D-E0FF-4DEB-8E28-0C3EA6BA26B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6059200F-141C-42A5-AA3F-E38C9721AEC8}.Release|Any CPU.Build.0 = Release|Any CPU {6CD6DB9D-E0FF-4DEB-8E28-0C3EA6BA26B2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View file

@ -144,19 +144,24 @@ namespace SharpChat {
} }
public void RefreshFlashiiBans() { public void RefreshFlashiiBans() {
FlashiiBan.GetList(bans => { FlashiiBan.GetList(SockChatServer.HttpClient).ContinueWith(x => {
if(!bans.Any()) if(x.IsFaulted) {
Logger.Write($@"Ban Refresh: {x.Exception}");
return;
}
if(!x.Result.Any())
return; return;
lock(BanList) { lock(BanList) {
foreach(FlashiiBan fb in bans) { foreach(FlashiiBan fb in x.Result) {
if(!BanList.OfType<BannedUser>().Any(x => x.UserId == fb.UserId)) if(!BanList.OfType<BannedUser>().Any(x => x.UserId == fb.UserId))
Add(new BannedUser(fb)); Add(new BannedUser(fb));
if(!BanList.OfType<BannedIPAddress>().Any(x => x.Address.ToString() == fb.UserIP)) if(!BanList.OfType<BannedIPAddress>().Any(x => x.Address.ToString() == fb.UserIP))
Add(new BannedIPAddress(fb)); Add(new BannedIPAddress(fb));
} }
} }
}, ex => Logger.Write($@"Ban Refresh: {ex}")); });
} }
public IEnumerable<IBan> All() { public IEnumerable<IBan> All() {

View file

@ -26,7 +26,7 @@ namespace SharpChat {
Channels = new ChannelManager(this); Channels = new ChannelManager(this);
Events = new ChatEventManager(this); Events = new ChatEventManager(this);
BumpTimer = new Timer(e => FlashiiBump.Submit(Users.WithActiveConnections()), null, TimeSpan.Zero, TimeSpan.FromMinutes(1)); BumpTimer = new Timer(e => FlashiiBump.Submit(SockChatServer.HttpClient, Users.WithActiveConnections()), null, TimeSpan.Zero, TimeSpan.FromMinutes(1));
} }
public void Update() { public void Update() {

View file

@ -15,7 +15,7 @@ namespace SharpChat {
public ChatEventManager(ChatContext context) { public ChatEventManager(ChatContext context) {
Context = context; Context = context;
if (!Database.HasDatabase) if (!Database.HasDatabase && !WebDatabase.IsAvailable)
Events = new List<IChatEvent>(); Events = new List<IChatEvent>();
} }
@ -27,6 +27,9 @@ namespace SharpChat {
lock(Events) lock(Events)
Events.Add(evt); Events.Add(evt);
if(WebDatabase.IsAvailable)
WebDatabase.LogEvent(evt);
if(Database.HasDatabase) if(Database.HasDatabase)
Database.LogEvent(evt); Database.LogEvent(evt);
} }
@ -39,6 +42,9 @@ namespace SharpChat {
lock (Events) lock (Events)
Events.Remove(evt); Events.Remove(evt);
if(WebDatabase.IsAvailable)
WebDatabase.DeleteEvent(evt);
if (Database.HasDatabase) if (Database.HasDatabase)
Database.DeleteEvent(evt); Database.DeleteEvent(evt);
@ -49,6 +55,9 @@ namespace SharpChat {
if (seqId < 1) if (seqId < 1)
return null; return null;
if(WebDatabase.IsAvailable)
return WebDatabase.GetEvent(seqId);
if (Database.HasDatabase) if (Database.HasDatabase)
return Database.GetEvent(seqId); return Database.GetEvent(seqId);
@ -60,6 +69,9 @@ namespace SharpChat {
} }
public IEnumerable<IChatEvent> GetTargetLog(IPacketTarget target, int amount = 20, int offset = 0) { public IEnumerable<IChatEvent> GetTargetLog(IPacketTarget target, int amount = 20, int offset = 0) {
if(WebDatabase.IsAvailable)
return WebDatabase.GetEvents(target, amount, offset);
if (Database.HasDatabase) if (Database.HasDatabase)
return Database.GetEvents(target, amount, offset).Reverse(); return Database.GetEvents(target, amount, offset).Reverse();

View file

@ -94,7 +94,7 @@ namespace SharpChat {
public ChatChannel CurrentChannel { get; private set; } public ChatChannel CurrentChannel { get; private set; }
public bool IsSilenced public bool IsSilenced
=> DateTimeOffset.UtcNow - SilencedUntil <= TimeSpan.Zero; => SilencedUntil != null && DateTimeOffset.UtcNow - SilencedUntil <= TimeSpan.Zero;
public bool HasSessions { public bool HasSessions {
get { get {

View file

@ -1,7 +1,9 @@
using Hamakaze; using Microsoft.Win32.SafeHandles;
using System; using System;
using System.Net.Http;
using System.Text.Json; using System.Text.Json;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace SharpChat.Flashii { namespace SharpChat.Flashii {
public class FlashiiAuthRequest { public class FlashiiAuthRequest {
@ -47,13 +49,15 @@ namespace SharpChat.Flashii {
[JsonPropertyName(@"perms")] [JsonPropertyName(@"perms")]
public ChatUserPermissions Permissions { get; set; } public ChatUserPermissions Permissions { get; set; }
public static void Attempt(FlashiiAuthRequest authRequest, Action<FlashiiAuth> onComplete, Action<Exception> onError) { public static async Task<FlashiiAuth> Attempt(HttpClient httpClient, FlashiiAuthRequest authRequest) {
if(httpClient == null)
throw new ArgumentNullException(nameof(httpClient));
if(authRequest == null) if(authRequest == null)
throw new ArgumentNullException(nameof(authRequest)); throw new ArgumentNullException(nameof(authRequest));
#if DEBUG #if DEBUG
if(authRequest.UserId >= 10000) { if (authRequest.UserId >= 10000)
onComplete(new FlashiiAuth { return new FlashiiAuth {
Success = true, Success = true,
UserId = authRequest.UserId, UserId = authRequest.UserId,
Username = @"Misaka-" + (authRequest.UserId - 10000), Username = @"Misaka-" + (authRequest.UserId - 10000),
@ -61,21 +65,21 @@ namespace SharpChat.Flashii {
Rank = 0, Rank = 0,
SilencedUntil = DateTimeOffset.MinValue, SilencedUntil = DateTimeOffset.MinValue,
Permissions = ChatUserPermissions.SendMessage | ChatUserPermissions.EditOwnMessage | ChatUserPermissions.DeleteOwnMessage, Permissions = ChatUserPermissions.SendMessage | ChatUserPermissions.EditOwnMessage | ChatUserPermissions.DeleteOwnMessage,
}); };
return;
}
#endif #endif
HttpRequestMessage hrm = new HttpRequestMessage(@"POST", FlashiiUrls.AUTH); using HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, FlashiiUrls.AUTH) {
hrm.AddHeader(@"X-SharpChat-Signature", authRequest.Hash); Content = new ByteArrayContent(authRequest.GetJSON()),
hrm.SetBody(authRequest.GetJSON()); Headers = {
HttpClient.Send(hrm, (t, r) => { { @"X-SharpChat-Signature", authRequest.Hash },
try { },
onComplete(JsonSerializer.Deserialize<FlashiiAuth>(r.GetBodyBytes())); };
} catch(Exception ex) {
onError(ex); using HttpResponseMessage response = await httpClient.SendAsync(request);
}
}, (t, e) => onError(e)); return JsonSerializer.Deserialize<FlashiiAuth>(
await response.Content.ReadAsByteArrayAsync()
);
} }
} }
} }

View file

@ -1,8 +1,9 @@
using Hamakaze; using System;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Http;
using System.Text.Json; using System.Text.Json;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace SharpChat.Flashii { namespace SharpChat.Flashii {
public class FlashiiBan { public class FlashiiBan {
@ -20,21 +21,19 @@ namespace SharpChat.Flashii {
[JsonPropertyName(@"username")] [JsonPropertyName(@"username")]
public string Username { get; set; } public string Username { get; set; }
public static void GetList(Action<IEnumerable<FlashiiBan>> onComplete, Action<Exception> onError) { public static async Task<IEnumerable<FlashiiBan>> GetList(HttpClient httpClient) {
if(onComplete == null) if(httpClient == null)
throw new ArgumentNullException(nameof(onComplete)); throw new ArgumentNullException(nameof(httpClient));
if(onError == null)
throw new ArgumentNullException(nameof(onError));
HttpRequestMessage hrm = new HttpRequestMessage(@"GET", FlashiiUrls.BANS); using HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, FlashiiUrls.BANS) {
hrm.AddHeader(@"X-SharpChat-Signature", STRING.GetSignedHash()); Headers = {
HttpClient.Send(hrm, (t, r) => { { @"X-SharpChat-Signature", STRING.GetSignedHash() },
try { },
onComplete(JsonSerializer.Deserialize<IEnumerable<FlashiiBan>>(r.GetBodyBytes())); };
} catch(Exception ex) {
onError(ex); using HttpResponseMessage response = await httpClient.SendAsync(request);
}
}, (t, e) => onError(e)); return JsonSerializer.Deserialize<IEnumerable<FlashiiBan>>(await response.Content.ReadAsByteArrayAsync());
} }
} }
} }

View file

@ -1,9 +1,10 @@
using Hamakaze; 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.Json; using System.Text.Json;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace SharpChat.Flashii { namespace SharpChat.Flashii {
public class FlashiiBump { public class FlashiiBump {
@ -13,14 +14,16 @@ namespace SharpChat.Flashii {
[JsonPropertyName(@"ip")] [JsonPropertyName(@"ip")]
public string UserIP { get; set; } public string UserIP { get; set; }
public static void Submit(IEnumerable<ChatUser> users) { public static void Submit(HttpClient httpClient, IEnumerable<ChatUser> users) {
List<FlashiiBump> bups = users.Where(u => u.HasSessions).Select(x => new FlashiiBump { UserId = x.UserId, UserIP = x.RemoteAddresses.First().ToString() }).ToList(); List<FlashiiBump> bups = users.Where(u => u.HasSessions).Select(x => new FlashiiBump { UserId = x.UserId, UserIP = x.RemoteAddresses.First().ToString() }).ToList();
if(bups.Any()) if (bups.Any())
Submit(bups); Submit(httpClient, bups);
} }
public static void Submit(IEnumerable<FlashiiBump> users) { public static void Submit(HttpClient httpClient, IEnumerable<FlashiiBump> users) {
if(httpClient == null)
throw new ArgumentNullException(nameof(httpClient));
if(users == null) if(users == null)
throw new ArgumentNullException(nameof(users)); throw new ArgumentNullException(nameof(users));
if(!users.Any()) if(!users.Any())
@ -28,10 +31,17 @@ namespace SharpChat.Flashii {
byte[] data = JsonSerializer.SerializeToUtf8Bytes(users); byte[] data = JsonSerializer.SerializeToUtf8Bytes(users);
HttpRequestMessage hrm = new HttpRequestMessage(@"POST", FlashiiUrls.BUMP); using HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, FlashiiUrls.BUMP) {
hrm.AddHeader(@"X-SharpChat-Signature", data.GetSignedHash()); Content = new ByteArrayContent(data),
hrm.SetBody(data); Headers = {
HttpClient.Send(hrm, onError: (t, e) => Logger.Write($@"Flashii Bump Error: {e}")); { @"X-SharpChat-Signature", data.GetSignedHash() },
}
};
httpClient.SendAsync(request).ContinueWith(x => {
if(x.IsFaulted)
Logger.Write($@"Flashii Bump Error: {x.Exception}");
});
} }
} }
} }

View file

@ -1,5 +1,7 @@
using Hamakaze; using SharpChat.Flashii;
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading; using System.Threading;
namespace SharpChat { namespace SharpChat {
@ -17,8 +19,19 @@ namespace SharpChat {
Console.WriteLine(@"============================================ DEBUG =="); Console.WriteLine(@"============================================ DEBUG ==");
#endif #endif
HttpClient.Instance.DefaultUserAgent = @"SharpChat/0.9"; #if DEBUG
Console.WriteLine(@"HOLD A KEY TO START A TEST NOW");
Thread.Sleep(1000);
if (Console.KeyAvailable)
switch (Console.ReadKey(true).Key) {
case ConsoleKey.F:
TestMisuzuAuth();
return;
}
#endif
WebDatabase.ReadConfig();
if(!WebDatabase.IsAvailable)
Database.ReadConfig(); Database.ReadConfig();
using ManualResetEvent mre = new ManualResetEvent(false); using ManualResetEvent mre = new ManualResetEvent(false);
@ -26,5 +39,46 @@ namespace SharpChat {
Console.CancelKeyPress += (s, e) => { e.Cancel = true; mre.Set(); }; Console.CancelKeyPress += (s, e) => { e.Cancel = true; mre.Set(); };
mre.WaitOne(); mre.WaitOne();
} }
#if DEBUG
private static void TestMisuzuAuth() {
Console.WriteLine($@"Enter token found on {FlashiiUrls.BASE_URL}/login:");
string[] token = Console.ReadLine().Split(new[] { '_' }, 2);
System.Net.Http.HttpClient httpClient = new System.Net.Http.HttpClient();
httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(@"SharpChat");
FlashiiAuth authRes = FlashiiAuth.Attempt(httpClient, new FlashiiAuthRequest {
UserId = int.Parse(token[0]), Token = token[1], IPAddress = @"1.2.4.8"
}).GetAwaiter().GetResult();
if(authRes.Success) {
Console.WriteLine(@"Auth success!");
Console.WriteLine($@" User ID: {authRes.UserId}");
Console.WriteLine($@" Username: {authRes.Username}");
Console.WriteLine($@" Colour: {authRes.ColourRaw:X8}");
Console.WriteLine($@" Hierarchy: {authRes.Rank}");
Console.WriteLine($@" Silenced: {authRes.SilencedUntil}");
Console.WriteLine($@" Perms: {authRes.Permissions}");
} else {
Console.WriteLine($@"Auth failed: {authRes.Reason}");
return;
}
Console.WriteLine(@"Bumping last seen...");
FlashiiBump.Submit(httpClient, new[] { new ChatUser(authRes) });
Console.WriteLine(@"Fetching ban list...");
IEnumerable<FlashiiBan> bans = FlashiiBan.GetList(httpClient).GetAwaiter().GetResult();
Console.WriteLine($@"{bans.Count()} BANS");
foreach(FlashiiBan ban in bans) {
Console.WriteLine($@"BAN INFO");
Console.WriteLine($@" User ID: {ban.UserId}");
Console.WriteLine($@" Username: {ban.Username}");
Console.WriteLine($@" IP Address: {ban.UserIP}");
Console.WriteLine($@" Expires: {ban.Expires}");
}
}
#endif
} }
} }

View file

@ -10,8 +10,4 @@
<PackageReference Include="MySqlConnector" Version="1.3.11" /> <PackageReference Include="MySqlConnector" Version="1.3.11" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Hamakaze\Hamakaze.csproj" />
</ItemGroup>
</Project> </Project>

View file

@ -8,6 +8,8 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Text; using System.Text;
namespace SharpChat { namespace SharpChat {
@ -37,6 +39,8 @@ namespace SharpChat {
public IWebSocketServer Server { get; } public IWebSocketServer Server { get; }
public ChatContext Context { get; } public ChatContext Context { get; }
public static HttpClient HttpClient { get; }
private IReadOnlyCollection<IChatCommand> Commands { get; } = new IChatCommand[] { private IReadOnlyCollection<IChatCommand> Commands { get; } = new IChatCommand[] {
new AFKCommand(), new AFKCommand(),
}; };
@ -49,6 +53,12 @@ namespace SharpChat {
return Sessions.FirstOrDefault(x => x.Connection == conn); return Sessions.FirstOrDefault(x => x.Connection == conn);
} }
static SockChatServer() {
// "fuck it"
HttpClient = new HttpClient();
HttpClient.DefaultRequestHeaders.UserAgent.ParseAdd(@"SharpChat");
}
public SockChatServer(ushort port) { public SockChatServer(ushort port) {
Logger.Write("Starting Sock Chat server..."); Logger.Write("Starting Sock Chat server...");
@ -162,11 +172,20 @@ namespace SharpChat {
if(args.Length < 3 || !long.TryParse(args[1], out long aUserId)) if(args.Length < 3 || !long.TryParse(args[1], out long aUserId))
break; break;
FlashiiAuth.Attempt(new FlashiiAuthRequest { FlashiiAuth.Attempt(HttpClient, new FlashiiAuthRequest {
UserId = aUserId, UserId = aUserId,
Token = args[2], Token = args[2],
IPAddress = sess.RemoteAddress.ToString(), IPAddress = sess.RemoteAddress.ToString(),
}, auth => { }).ContinueWith(authTask => {
if(authTask.IsFaulted) {
Logger.Write($@"<{sess.Id}> Auth task fail: {authTask.Exception}");
sess.Send(new AuthFailPacket(AuthFailReason.AuthInvalid));
sess.Dispose();
return;
}
FlashiiAuth auth = authTask.Result;
if(!auth.Success) { if(!auth.Success) {
Logger.Debug($@"<{sess.Id}> Auth fail: {auth.Reason}"); Logger.Debug($@"<{sess.Id}> Auth fail: {auth.Reason}");
sess.Send(new AuthFailPacket(AuthFailReason.AuthInvalid)); sess.Send(new AuthFailPacket(AuthFailReason.AuthInvalid));
@ -214,10 +233,6 @@ namespace SharpChat {
} }
Context.HandleJoin(aUser, Context.Channels.DefaultChannel, sess); Context.HandleJoin(aUser, Context.Channels.DefaultChannel, sess);
}, ex => {
Logger.Write($@"<{sess.Id}> Auth task fail: {ex}");
sess.Send(new AuthFailPacket(AuthFailReason.AuthInvalid));
sess.Dispose();
}); });
break; break;
@ -529,7 +544,7 @@ namespace SharpChat {
} }
string createChanName = string.Join('_', parts.Skip(createChanHasHierarchy ? 2 : 1)); string createChanName = string.Join('_', parts.Skip(createChanHasHierarchy ? 2 : 1));
ChatChannel createChan = new() { ChatChannel createChan = new ChatChannel {
Name = createChanName, Name = createChanName,
IsTemporary = !user.Can(ChatUserPermissions.SetChannelPermanent), IsTemporary = !user.Can(ChatUserPermissions.SetChannelPermanent),
Rank = createChanHierarchy, Rank = createChanHierarchy,
@ -816,14 +831,12 @@ namespace SharpChat {
} }
~SockChatServer() ~SockChatServer()
=> DoDispose(); => Dispose(false);
public void Dispose() { public void Dispose()
DoDispose(); => Dispose(true);
GC.SuppressFinalize(this);
}
private void DoDispose() { private void Dispose(bool disposing) {
if(IsDisposed) if(IsDisposed)
return; return;
IsDisposed = true; IsDisposed = true;
@ -831,6 +844,10 @@ namespace SharpChat {
Sessions?.Clear(); Sessions?.Clear();
Server?.Dispose(); Server?.Dispose();
Context?.Dispose(); Context?.Dispose();
HttpClient?.Dispose();
if(disposing)
GC.SuppressFinalize(this);
} }
} }
} }

233
SharpChat/WebDatabase.cs Normal file
View file

@ -0,0 +1,233 @@
using SharpChat.Events;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace SharpChat {
public static class WebDatabase {
private static string EndPoint = null;
public static bool IsAvailable
=> !string.IsNullOrWhiteSpace(EndPoint);
public static void ReadConfig() {
if(!File.Exists(@"webdb.txt"))
return;
string[] config = File.ReadAllLines(@"webdb.txt");
if(config.Length < 1 && !string.IsNullOrWhiteSpace(config[0]))
return;
Init(config[0]);
}
public static void Init(string endPoint) {
EndPoint = endPoint;
}
public static void Deinit() {
EndPoint = null;
}
public static void LogEvent(IChatEvent evt) {
if(evt.SequenceId < 1)
evt.SequenceId = Database.GenerateId();
string sId = evt.SequenceId.ToString();
string sCreated = evt.DateTime.ToUnixTimeSeconds().ToString();
string sType = evt.GetType().FullName;
string sTarget = evt.Target.TargetName ?? string.Empty;
string sFlags = ((byte)evt.Flags).ToString();
string sData = JsonSerializer.Serialize(evt, evt.GetType());
string sSender = evt.Sender?.UserId < 1 ? string.Empty : evt.Sender.UserId.ToString();
string sSenderName = evt.Sender?.Username.ToString() ?? string.Empty;
string sSenderColour = evt.Sender?.Colour.Raw.ToString() ?? string.Empty;
string sSenderRank = evt.Sender?.Rank.ToString() ?? string.Empty;
string sSenderNick = evt.Sender?.Nickname?.ToString() ?? string.Empty;
string sSenderPerms = evt.Sender == null ? string.Empty : ((int)evt.Sender.Permissions).ToString();
string sHash = string.Join('#', @"crev", sId, sCreated, sType, sTarget, sFlags, sSender, sSenderColour, sSenderRank, sSenderPerms, sSenderName, sSenderNick, sData);
MultipartFormDataContent mfdc = new();
mfdc.Add(new StringContent(sId), @"i");
mfdc.Add(new StringContent(sCreated), @"c");
mfdc.Add(new StringContent(sType), @"t");
mfdc.Add(new StringContent(sTarget), @"l");
mfdc.Add(new StringContent(sFlags), @"f");
mfdc.Add(new StringContent(sData), @"d");
mfdc.Add(new StringContent(sSender), @"s");
mfdc.Add(new StringContent(sSenderName), @"su");
mfdc.Add(new StringContent(sSenderColour), @"sc");
mfdc.Add(new StringContent(sSenderRank), @"sr");
mfdc.Add(new StringContent(sSenderNick), @"sn");
mfdc.Add(new StringContent(sSenderPerms), @"sp");
HttpRequestMessage request = new(HttpMethod.Post, EndPoint + @"?m=crev") {
Content = mfdc,
Headers = {
{ @"X-SharpChat-Signature", sHash.GetSignedHash() },
}
};
SockChatServer.HttpClient.SendAsync(request).ContinueWith(x => {
if(x.IsCompleted) {
if(x.Result.Headers.TryGetValues(@"X-SharpChat-Error", out IEnumerable<string> values))
Logger.Write($@"DBS - LogEvent: {values.FirstOrDefault()}");
}
if(x.IsFaulted)
Logger.Write($@"DBS - LogEvent: {x.Exception}");
}).Wait();
}
public static void DeleteEvent(IChatEvent evt) {
string msgId = evt.SequenceId.ToString();
using HttpRequestMessage request = new(HttpMethod.Delete, EndPoint + @"?m=deev&i=" + msgId) {
Headers = {
{ @"X-SharpChat-Signature", (@"deev#" + msgId).GetSignedHash() },
}
};
SockChatServer.HttpClient.SendAsync(request).ContinueWith(x => {
if(x.IsCompleted) {
if(x.Result.Headers.TryGetValues(@"X-SharpChat-Error", out IEnumerable<string> values))
Logger.Write($@"DBS - DeleteEvent: {values.FirstOrDefault()}");
}
if(x.IsFaulted)
Logger.Write($@"DBS - DeleteEvent: {x.Exception}");
}).Wait();
}
private class DatabaseRow {
[JsonPropertyName(@"i")]
public long EventId { get; set; }
[JsonPropertyName(@"s")]
public long EventSenderId { get; set; }
[JsonPropertyName(@"su")]
public string EventSenderName { get; set; }
[JsonPropertyName(@"sc")]
public int EventSenderColour { get; set; }
[JsonPropertyName(@"sr")]
public int EventSenderRank { get; set; }
[JsonPropertyName(@"sn")]
public string EventSenderNick { get; set; }
[JsonPropertyName(@"sp")]
public int EventSenderPerms { get; set; }
[JsonPropertyName(@"c")]
public int EventCreated { get; set; }
[JsonPropertyName(@"t")]
public string EventType { get; set; }
[JsonPropertyName(@"l")]
public string EventTarget { get; set; }
[JsonPropertyName(@"f")]
public byte EventFlags { get; set; }
[JsonPropertyName(@"d")]
public string EventData { get; set; }
}
private static IChatEvent ReadEvent(DatabaseRow row, IPacketTarget target = null) {
Type evtType = Type.GetType(row.EventType);
IChatEvent evt = JsonSerializer.Deserialize(row.EventData, evtType) as IChatEvent;
evt.SequenceId = row.EventId;
evt.Target = target;
evt.TargetName = target?.TargetName ?? row.EventTarget;
evt.Flags = (ChatMessageFlags)row.EventFlags;
evt.DateTime = DateTimeOffset.FromUnixTimeSeconds(row.EventCreated);
if(row.EventSenderId > 0) {
evt.Sender = new BasicUser {
UserId = row.EventSenderId,
Username = row.EventSenderName,
Colour = new ChatColour(row.EventSenderColour),
Rank = row.EventSenderRank,
Nickname = string.IsNullOrEmpty(row.EventSenderNick) ? null : row.EventSenderNick,
Permissions = (ChatUserPermissions)row.EventSenderPerms
};
}
return evt;
}
public static IChatEvent GetEvent(long seqId) {
string sSeqId = seqId.ToString();
using HttpRequestMessage request = new(HttpMethod.Get, EndPoint + @"?m=geev&i=" + sSeqId) {
Headers = {
{ @"X-SharpChat-Signature", (@"geev#" + sSeqId).GetSignedHash() },
}
};
// jesus christ what is this
System.Runtime.CompilerServices.TaskAwaiter<HttpResponseMessage>? awaiter = null;
HttpResponseMessage response = null;
try {
awaiter = SockChatServer.HttpClient.SendAsync(request).GetAwaiter();
response = awaiter.Value.GetResult();
byte[] garbage = response.Content.ReadAsByteArrayAsync().GetAwaiter().GetResult();
return ReadEvent(
(DatabaseRow)JsonSerializer.Deserialize(garbage, typeof(DatabaseRow))
);
} catch(Exception ex) {
Logger.Write($@"DBS - GetEvent: {ex}");
} finally {
if(awaiter.HasValue && awaiter.Value.IsCompleted) {
if(response != null && response.Headers.TryGetValues(@"X-SharpChat-Error", out IEnumerable<string> values))
Logger.Write($@"DBS - GetEvent: {values.FirstOrDefault()}");
}
}
return null;
}
public static IEnumerable<IChatEvent> GetEvents(IPacketTarget target, int amount, int offset) {
List<IChatEvent> events = new();
using HttpRequestMessage request = new(HttpMethod.Get, EndPoint + @"?m=feev&l=" + target.TargetName + @"&a=" + amount + @"&o=" + offset) {
Headers = {
{ @"X-SharpChat-Signature", string.Join('#', @"feev", amount, offset, target.TargetName).GetSignedHash() },
}
};
System.Runtime.CompilerServices.TaskAwaiter<HttpResponseMessage>? awaiter = null;
HttpResponseMessage response = null;
try {
awaiter = SockChatServer.HttpClient.SendAsync(request).GetAwaiter();
response = awaiter.Value.GetResult();
byte[] trash = response.Content.ReadAsByteArrayAsync().GetAwaiter().GetResult();
IEnumerable<DatabaseRow> rows = (IEnumerable<DatabaseRow>)JsonSerializer.Deserialize(trash, typeof(IEnumerable<DatabaseRow>));
foreach(DatabaseRow row in rows)
events.Add(ReadEvent(row, target));
} catch(Exception ex) {
Logger.Write($@"DBS - GetEvents: {ex}");
} finally {
if(awaiter.HasValue && awaiter.Value.IsCompleted) {
if(response != null && response.Headers.TryGetValues(@"X-SharpChat-Error", out IEnumerable<string> values))
Logger.Write($@"DBS - GetEvents: {values.FirstOrDefault()}");
}
}
return events;
}
}
}