From 2d4dc14f9331338595a74c6e1abd9e2fcbbea7a7 Mon Sep 17 00:00:00 2001 From: jvyden Date: Thu, 18 Nov 2021 15:27:20 -0500 Subject: [PATCH 01/21] Fix ShouldOnlyShowUsersLevels test --- ProjectLighthouse.Tests/Tests/SlotTests.cs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/ProjectLighthouse.Tests/Tests/SlotTests.cs b/ProjectLighthouse.Tests/Tests/SlotTests.cs index 65abac0f..52f4d690 100644 --- a/ProjectLighthouse.Tests/Tests/SlotTests.cs +++ b/ProjectLighthouse.Tests/Tests/SlotTests.cs @@ -17,13 +17,18 @@ namespace LBPUnion.ProjectLighthouse.Tests User userA = await database.CreateUser("unitTestUser0"); User userB = await database.CreateUser("unitTestUser1"); - Location l = new(); + Location l = new() + { + X = 0, + Y = 0, + }; database.Locations.Add(l); await database.SaveChangesAsync(); Slot slotA = new() { Creator = userA, + CreatorId = userA.UserId, Name = "slotA", Location = l, LocationId = l.Id, @@ -33,6 +38,7 @@ namespace LBPUnion.ProjectLighthouse.Tests Slot slotB = new() { Creator = userB, + CreatorId = userB.UserId, Name = "slotB", Location = l, LocationId = l.Id, @@ -49,8 +55,10 @@ namespace LBPUnion.ProjectLighthouse.Tests LoginResult loginResult = await this.Authenticate(); - HttpResponseMessage respMessageA = await this.AuthenticatedRequest("LITTLEBIGPLANETPS3_XML/slots/by?u=unitTestUser0", loginResult.AuthTicket); - HttpResponseMessage respMessageB = await this.AuthenticatedRequest("LITTLEBIGPLANETPS3_XML/slots/by?u=unitTestUser1", loginResult.AuthTicket); + HttpResponseMessage respMessageA = await this.AuthenticatedRequest + ("LITTLEBIGPLANETPS3_XML/slots/by?u=unitTestUser0&pageStart=1&pageSize=1", loginResult.AuthTicket); + HttpResponseMessage respMessageB = await this.AuthenticatedRequest + ("LITTLEBIGPLANETPS3_XML/slots/by?u=unitTestUser1&pageStart=1&pageSize=1", loginResult.AuthTicket); Assert.True(respMessageA.IsSuccessStatusCode); Assert.True(respMessageB.IsSuccessStatusCode); From dc429f2c8adfbc0f1b83307242fd2ff723d3e8b0 Mon Sep 17 00:00:00 2001 From: jvyden Date: Thu, 18 Nov 2021 15:31:37 -0500 Subject: [PATCH 02/21] Use im-open/process-dotnet-test-results@v2.0.1 --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8ee41701..5477e569 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -60,13 +60,13 @@ jobs: - name: Process Test Results (Control) if: ${{ matrix.os.prettyName == 'Linux' }} - uses: im-open/process-dotnet-test-results@v2.0.0 + uses: im-open/process-dotnet-test-results@v2.0.1 with: github-token: ${{ secrets.GITHUB_TOKEN }} - name: Process Test Results if: ${{ matrix.os.prettyName != 'Linux' }} - uses: im-open/process-dotnet-test-results@v2.0.0 + uses: im-open/process-dotnet-test-results@v2.0.1 with: github-token: ${{ secrets.GITHUB_TOKEN }} create-status-check: false From b0b35d6ae89f849f6557bf2d559a4f65cef1da0b Mon Sep 17 00:00:00 2001 From: jvyden Date: Thu, 18 Nov 2021 18:27:29 -0500 Subject: [PATCH 03/21] Add section on running tests to readme --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e45b3290..f3ff44b4 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ Finally, take a break. Chances are that took a while. ## Contributing Tips -### Database +### Database migrations Some modifications may require updates to the database schema. You can automatically create a migration file by: @@ -72,6 +72,12 @@ Some modifications may require updates to the database schema. You can automatic you're doing. 4. Running `dotnet ef migrations add --project ProjectLighthouse`. +### Running tests + +You can run tests either through your IDE or by running `dotnet tests`. + +Keep in mind while running database tests you need to have `LIGHTHOUSE_DB_CONNECTION_STRING` set. + ## Compatibility across games and platforms | Game | Console (PS3/Vita) | Emulator (RPCS3) | Next-Gen (PS4/PS5) | From 5d40c42c5730439b9d3718326c7173200e8481eb Mon Sep 17 00:00:00 2001 From: jvyden Date: Thu, 18 Nov 2021 18:33:39 -0500 Subject: [PATCH 04/21] Add string.ToSafeXml() May resolve #61 --- .../Helpers/Extensions/StringExtensions.cs | 2 ++ .../Serialization/LbpSerializer.cs | 18 ++++++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/ProjectLighthouse/Helpers/Extensions/StringExtensions.cs b/ProjectLighthouse/Helpers/Extensions/StringExtensions.cs index 72ef05af..0d4d4df1 100644 --- a/ProjectLighthouse/Helpers/Extensions/StringExtensions.cs +++ b/ProjectLighthouse/Helpers/Extensions/StringExtensions.cs @@ -6,5 +6,7 @@ namespace LBPUnion.ProjectLighthouse.Helpers.Extensions public static class StringExtensions { public static string ToFileName(this string text) => Path.GetInvalidFileNameChars().Aggregate(text, (current, c) => current.Replace(c.ToString(), "")); + + public static string ToSafeXml(this string text) => text.Replace("<", "<").Replace(">", ">"); } } \ No newline at end of file diff --git a/ProjectLighthouse/Serialization/LbpSerializer.cs b/ProjectLighthouse/Serialization/LbpSerializer.cs index cfa64535..73a0c7f1 100644 --- a/ProjectLighthouse/Serialization/LbpSerializer.cs +++ b/ProjectLighthouse/Serialization/LbpSerializer.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; +using LBPUnion.ProjectLighthouse.Helpers.Extensions; namespace LBPUnion.ProjectLighthouse.Serialization { @@ -12,22 +13,27 @@ namespace LBPUnion.ProjectLighthouse.Serialization [SuppressMessage("ReSharper", "UnusedMember.Global")] public static class LbpSerializer { + // IMPORTANT: All functions using values must call .ToSafeXml(); public static string BlankElement(string key) => $"<{key}>"; - public static string StringElement(KeyValuePair pair) => $"<{pair.Key}>{pair.Value}"; + public static string StringElement(KeyValuePair pair) => $"<{pair.Key}>{pair.Value.ToString().ToSafeXml()}"; - public static string StringElement(string key, bool value) => $"<{key}>{value.ToString().ToLower()}"; + public static string StringElement(string key, bool value) => $"<{key}>{value.ToString().ToLower().ToSafeXml()}"; - public static string StringElement(string key, object value) => $"<{key}>{value}"; + public static string StringElement(string key, object value) => $"<{key}>{value.ToString().ToSafeXml()}"; public static string TaggedStringElement (KeyValuePair pair, KeyValuePair tagPair) - => $"<{pair.Key} {tagPair.Key}=\"{tagPair.Value}\">{pair.Value}"; + => $"<{pair.Key} {tagPair.Key}=\"{tagPair.Value.ToString().ToSafeXml()}\">{pair.Value.ToString().ToSafeXml()}"; - public static string TaggedStringElement(string key, object value, string tagKey, object tagValue) => $"<{key} {tagKey}=\"{tagValue}\">{value}"; + public static string TaggedStringElement + (string key, object value, string tagKey, object tagValue) + => $"<{key} {tagKey}=\"{tagValue.ToString().ToSafeXml()}\">{value.ToString().ToSafeXml()}"; public static string TaggedStringElement(string key, object value, Dictionary attrKeyValuePairs) - => $"<{key} " + attrKeyValuePairs.Aggregate(string.Empty, (current, kvp) => current + $"{kvp.Key}=\"{kvp.Value}\" ") + $">{value}"; + => $"<{key} " + + attrKeyValuePairs.Aggregate(string.Empty, (current, kvp) => current + $"{kvp.Key}=\"{kvp.Value.ToString().ToSafeXml()}\" ") + + $">{value.ToString().ToSafeXml()}"; public static string Elements (params KeyValuePair[] pairs) From eb0d91914c707c465d7258a23aab159c7066a844 Mon Sep 17 00:00:00 2001 From: jvyden Date: Thu, 18 Nov 2021 18:38:27 -0500 Subject: [PATCH 05/21] Revert "Add string.ToSafeXml()" This reverts commit 5d40c42c5730439b9d3718326c7173200e8481eb. --- .../Helpers/Extensions/StringExtensions.cs | 2 -- .../Serialization/LbpSerializer.cs | 18 ++++++------------ 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/ProjectLighthouse/Helpers/Extensions/StringExtensions.cs b/ProjectLighthouse/Helpers/Extensions/StringExtensions.cs index 0d4d4df1..72ef05af 100644 --- a/ProjectLighthouse/Helpers/Extensions/StringExtensions.cs +++ b/ProjectLighthouse/Helpers/Extensions/StringExtensions.cs @@ -6,7 +6,5 @@ namespace LBPUnion.ProjectLighthouse.Helpers.Extensions public static class StringExtensions { public static string ToFileName(this string text) => Path.GetInvalidFileNameChars().Aggregate(text, (current, c) => current.Replace(c.ToString(), "")); - - public static string ToSafeXml(this string text) => text.Replace("<", "<").Replace(">", ">"); } } \ No newline at end of file diff --git a/ProjectLighthouse/Serialization/LbpSerializer.cs b/ProjectLighthouse/Serialization/LbpSerializer.cs index 73a0c7f1..cfa64535 100644 --- a/ProjectLighthouse/Serialization/LbpSerializer.cs +++ b/ProjectLighthouse/Serialization/LbpSerializer.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; -using LBPUnion.ProjectLighthouse.Helpers.Extensions; namespace LBPUnion.ProjectLighthouse.Serialization { @@ -13,27 +12,22 @@ namespace LBPUnion.ProjectLighthouse.Serialization [SuppressMessage("ReSharper", "UnusedMember.Global")] public static class LbpSerializer { - // IMPORTANT: All functions using values must call .ToSafeXml(); public static string BlankElement(string key) => $"<{key}>"; - public static string StringElement(KeyValuePair pair) => $"<{pair.Key}>{pair.Value.ToString().ToSafeXml()}"; + public static string StringElement(KeyValuePair pair) => $"<{pair.Key}>{pair.Value}"; - public static string StringElement(string key, bool value) => $"<{key}>{value.ToString().ToLower().ToSafeXml()}"; + public static string StringElement(string key, bool value) => $"<{key}>{value.ToString().ToLower()}"; - public static string StringElement(string key, object value) => $"<{key}>{value.ToString().ToSafeXml()}"; + public static string StringElement(string key, object value) => $"<{key}>{value}"; public static string TaggedStringElement (KeyValuePair pair, KeyValuePair tagPair) - => $"<{pair.Key} {tagPair.Key}=\"{tagPair.Value.ToString().ToSafeXml()}\">{pair.Value.ToString().ToSafeXml()}"; + => $"<{pair.Key} {tagPair.Key}=\"{tagPair.Value}\">{pair.Value}"; - public static string TaggedStringElement - (string key, object value, string tagKey, object tagValue) - => $"<{key} {tagKey}=\"{tagValue.ToString().ToSafeXml()}\">{value.ToString().ToSafeXml()}"; + public static string TaggedStringElement(string key, object value, string tagKey, object tagValue) => $"<{key} {tagKey}=\"{tagValue}\">{value}"; public static string TaggedStringElement(string key, object value, Dictionary attrKeyValuePairs) - => $"<{key} " + - attrKeyValuePairs.Aggregate(string.Empty, (current, kvp) => current + $"{kvp.Key}=\"{kvp.Value.ToString().ToSafeXml()}\" ") + - $">{value.ToString().ToSafeXml()}"; + => $"<{key} " + attrKeyValuePairs.Aggregate(string.Empty, (current, kvp) => current + $"{kvp.Key}=\"{kvp.Value}\" ") + $">{value}"; public static string Elements (params KeyValuePair[] pairs) From 616649e96a7567bd1918700ae8cd589fb5255fc7 Mon Sep 17 00:00:00 2001 From: jvyden Date: Thu, 18 Nov 2021 18:51:18 -0500 Subject: [PATCH 06/21] Implement sizeOfResources in Slot Closes #45 --- ProjectLighthouse/Helpers/FileHelper.cs | 2 ++ ProjectLighthouse/Types/Levels/Slot.cs | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ProjectLighthouse/Helpers/FileHelper.cs b/ProjectLighthouse/Helpers/FileHelper.cs index f519effa..92084b7c 100644 --- a/ProjectLighthouse/Helpers/FileHelper.cs +++ b/ProjectLighthouse/Helpers/FileHelper.cs @@ -78,6 +78,8 @@ namespace LBPUnion.ProjectLighthouse.Helpers public static bool ResourceExists(string hash) => File.Exists(GetResourcePath(hash)); + public static int ResourceSize(string hash) => (int)new FileInfo(GetResourcePath(hash)).Length; + public static void EnsureDirectoryCreated(string path) { if (!Directory.Exists(path)) Directory.CreateDirectory(path ?? throw new ArgumentNullException(nameof(path))); diff --git a/ProjectLighthouse/Types/Levels/Slot.cs b/ProjectLighthouse/Types/Levels/Slot.cs index f21c7240..ff0c580e 100644 --- a/ProjectLighthouse/Types/Levels/Slot.cs +++ b/ProjectLighthouse/Types/Levels/Slot.cs @@ -3,6 +3,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using System.Xml.Serialization; +using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Serialization; using LBPUnion.ProjectLighthouse.Types.Profiles; @@ -195,7 +196,8 @@ namespace LBPUnion.ProjectLighthouse.Types.Levels public string SerializeResources() { - return this.Resources.Aggregate("", (current, resource) => current + LbpSerializer.StringElement("resource", resource)); + return this.Resources.Aggregate("", (current, resource) => current + LbpSerializer.StringElement("resource", resource)) + + LbpSerializer.StringElement("sizeOfResources", this.Resources.Sum(FileHelper.ResourceSize)); } public string Serialize(RatedLevel? yourRatingStats = null, VisitedLevel? yourVisitedStats = null) From 4542bd331363dd725e4309633135c22942c16d6a Mon Sep 17 00:00:00 2001 From: jvyden Date: Thu, 18 Nov 2021 18:55:53 -0500 Subject: [PATCH 07/21] Add Clear Queued Levels endpoint Closes #43 --- ProjectLighthouse/Controllers/ListController.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ProjectLighthouse/Controllers/ListController.cs b/ProjectLighthouse/Controllers/ListController.cs index 4e3014f8..f4139dc1 100644 --- a/ProjectLighthouse/Controllers/ListController.cs +++ b/ProjectLighthouse/Controllers/ListController.cs @@ -90,6 +90,19 @@ namespace LBPUnion.ProjectLighthouse.Controllers return this.Ok(); } + [HttpPost("lolcatftw/clear")] + public async Task ClearQueuedLevels() + { + User? user = await this.database.UserFromRequest(this.Request); + if (user == null) return this.StatusCode(403, ""); + + this.database.QueuedLevels.RemoveRange(this.database.QueuedLevels.Where(q => q.UserId == user.UserId)); + + await this.database.SaveChangesAsync(); + + return this.Ok(); + } + #endregion #region Hearted Levels From 09c72eb9c2c7d85485305aa91af5bf23e46944cc Mon Sep 17 00:00:00 2001 From: jvyden Date: Thu, 18 Nov 2021 19:30:37 -0500 Subject: [PATCH 08/21] Implement file hashing on upload Closes #25 --- ProjectLighthouse.Tests/LighthouseTest.cs | 9 +++++++++ ProjectLighthouse.Tests/Tests/UploadTests.cs | 10 +++++----- ProjectLighthouse/Controllers/ResourcesController.cs | 7 ++++++- ProjectLighthouse/Helpers/HashHelper.cs | 12 ++++++------ 4 files changed, 26 insertions(+), 12 deletions(-) diff --git a/ProjectLighthouse.Tests/LighthouseTest.cs b/ProjectLighthouse.Tests/LighthouseTest.cs index df207d74..3efb3684 100644 --- a/ProjectLighthouse.Tests/LighthouseTest.cs +++ b/ProjectLighthouse.Tests/LighthouseTest.cs @@ -1,6 +1,7 @@ using System.Diagnostics.CodeAnalysis; using System.IO; using System.Net.Http; +using System.Text; using System.Threading.Tasks; using System.Xml.Serialization; using LBPUnion.ProjectLighthouse.Helpers; @@ -55,6 +56,14 @@ namespace LBPUnion.ProjectLighthouse.Tests return this.Client.SendAsync(requestMessage); } + public async Task UploadFileEndpointRequest(string filePath) + { + byte[] bytes = Encoding.UTF8.GetBytes(await File.ReadAllTextAsync(filePath)); + string hash = HashHelper.Sha1Hash(bytes); + + return await this.Client.PostAsync($"/LITTLEBIGPLANETPS3_XML/upload/{hash}", new ByteArrayContent(bytes)); + } + public async Task UploadFileRequest(string endpoint, string filePath) => await this.Client.PostAsync(endpoint, new StringContent(await File.ReadAllTextAsync(filePath))); diff --git a/ProjectLighthouse.Tests/Tests/UploadTests.cs b/ProjectLighthouse.Tests/Tests/UploadTests.cs index 41612256..fb73be01 100644 --- a/ProjectLighthouse.Tests/Tests/UploadTests.cs +++ b/ProjectLighthouse.Tests/Tests/UploadTests.cs @@ -17,35 +17,35 @@ namespace LBPUnion.ProjectLighthouse.Tests [Fact] public async Task ShouldNotAcceptScript() { - HttpResponseMessage response = await this.UploadFileRequest("/LITTLEBIGPLANETPS3_XML/upload/scriptTest", "ExampleFiles/TestScript.ff"); + HttpResponseMessage response = await this.UploadFileEndpointRequest("ExampleFiles/TestScript.ff"); Assert.False(response.IsSuccessStatusCode); } [Fact] public async Task ShouldNotAcceptFarc() { - HttpResponseMessage response = await this.UploadFileRequest("/LITTLEBIGPLANETPS3_XML/upload/farcTest", "ExampleFiles/TestFarc.farc"); + HttpResponseMessage response = await this.UploadFileEndpointRequest("ExampleFiles/TestFarc.farc"); Assert.False(response.IsSuccessStatusCode); } [Fact] public async Task ShouldNotAcceptGarbage() { - HttpResponseMessage response = await this.UploadFileRequest("/LITTLEBIGPLANETPS3_XML/upload/garbageTest", "ExampleFiles/TestGarbage.bin"); + HttpResponseMessage response = await this.UploadFileEndpointRequest("ExampleFiles/TestGarbage.bin"); Assert.False(response.IsSuccessStatusCode); } [Fact] public async Task ShouldAcceptTexture() { - HttpResponseMessage response = await this.UploadFileRequest("/LITTLEBIGPLANETPS3_XML/upload/textureTest", "ExampleFiles/TestTexture.tex"); + HttpResponseMessage response = await this.UploadFileEndpointRequest("ExampleFiles/TestTexture.tex"); Assert.True(response.IsSuccessStatusCode); } [Fact] public async Task ShouldAcceptLevel() { - HttpResponseMessage response = await this.UploadFileRequest("/LITTLEBIGPLANETPS3_XML/upload/levelTest", "ExampleFiles/TestLevel.lvl"); + HttpResponseMessage response = await this.UploadFileEndpointRequest("ExampleFiles/TestLevel.lvl"); Assert.True(response.IsSuccessStatusCode); } } diff --git a/ProjectLighthouse/Controllers/ResourcesController.cs b/ProjectLighthouse/Controllers/ResourcesController.cs index 3680bbfd..d1a438db 100644 --- a/ProjectLighthouse/Controllers/ResourcesController.cs +++ b/ProjectLighthouse/Controllers/ResourcesController.cs @@ -54,7 +54,6 @@ namespace LBPUnion.ProjectLighthouse.Controllers [AllowSynchronousIo] public async Task UploadResource(string hash) { - string assetsDirectory = FileHelper.ResourcePath; string path = FileHelper.GetResourcePath(hash); @@ -70,6 +69,12 @@ namespace LBPUnion.ProjectLighthouse.Controllers return this.UnprocessableEntity(); } + if (HashHelper.Sha1Hash(file.Data) != hash) + { + Logger.Log($"File hash does not match the uploaded file! (hash: {hash}, type: {file.FileType})", LoggerLevelResources.Instance); + return this.Conflict(); + } + Logger.Log($"File is OK! (hash: {hash}, type: {file.FileType})", LoggerLevelResources.Instance); await IOFile.WriteAllBytesAsync(path, file.Data); return this.Ok(); diff --git a/ProjectLighthouse/Helpers/HashHelper.cs b/ProjectLighthouse/Helpers/HashHelper.cs index ffda6e17..838a22a4 100644 --- a/ProjectLighthouse/Helpers/HashHelper.cs +++ b/ProjectLighthouse/Helpers/HashHelper.cs @@ -11,7 +11,7 @@ namespace LBPUnion.ProjectLighthouse.Helpers [SuppressMessage("ReSharper", "UnusedMember.Global")] public static class HashHelper { -// private static readonly SHA1 sha1 = SHA1.Create(); + private static readonly SHA1 sha1 = SHA1.Create(); private static readonly SHA256 sha256 = SHA256.Create(); private static readonly Random random = new(); @@ -67,11 +67,11 @@ namespace LBPUnion.ProjectLighthouse.Helpers public static string Sha256Hash(string str) => Sha256Hash(Encoding.UTF8.GetBytes(str)); - public static string Sha256Hash(byte[] bytes) - { - byte[] hash = sha256.ComputeHash(bytes); - return Encoding.UTF8.GetString(hash, 0, hash.Length); - } + public static string Sha256Hash(byte[] bytes) => BitConverter.ToString(sha256.ComputeHash(bytes)).Replace("-", ""); + + public static string Sha1Hash(string str) => Sha1Hash(Encoding.UTF8.GetBytes(str)); + + public static string Sha1Hash(byte[] bytes) => BitConverter.ToString(sha1.ComputeHash(bytes)).Replace("-", ""); public static string BCryptHash(string str) => BCrypt.Net.BCrypt.HashPassword(str); From 249b1d582c4a34ba99edbae39baf64dd9214d0d1 Mon Sep 17 00:00:00 2001 From: jvyden Date: Thu, 18 Nov 2021 19:34:28 -0500 Subject: [PATCH 09/21] Fix ShouldOnlyShowUsersLevels test --- ProjectLighthouse/Helpers/FileHelper.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/ProjectLighthouse/Helpers/FileHelper.cs b/ProjectLighthouse/Helpers/FileHelper.cs index 92084b7c..f85b3113 100644 --- a/ProjectLighthouse/Helpers/FileHelper.cs +++ b/ProjectLighthouse/Helpers/FileHelper.cs @@ -78,7 +78,17 @@ namespace LBPUnion.ProjectLighthouse.Helpers public static bool ResourceExists(string hash) => File.Exists(GetResourcePath(hash)); - public static int ResourceSize(string hash) => (int)new FileInfo(GetResourcePath(hash)).Length; + public static int ResourceSize(string hash) + { + try + { + return (int)new FileInfo(GetResourcePath(hash)).Length; + } + catch + { + return 0; + } + } public static void EnsureDirectoryCreated(string path) { From 2f817f9aa85e216712843a27495bafbc287febc7 Mon Sep 17 00:00:00 2001 From: jvyden Date: Thu, 18 Nov 2021 23:01:27 -0500 Subject: [PATCH 10/21] Remove AllowSynchronousIOAttribute --- .../Controllers/ResourcesController.cs | 1 - .../Helpers/AllowSynchronousIOAttribute.cs | 21 ------------------- 2 files changed, 22 deletions(-) delete mode 100644 ProjectLighthouse/Helpers/AllowSynchronousIOAttribute.cs diff --git a/ProjectLighthouse/Controllers/ResourcesController.cs b/ProjectLighthouse/Controllers/ResourcesController.cs index d1a438db..adb7734b 100644 --- a/ProjectLighthouse/Controllers/ResourcesController.cs +++ b/ProjectLighthouse/Controllers/ResourcesController.cs @@ -51,7 +51,6 @@ namespace LBPUnion.ProjectLighthouse.Controllers // TODO: check if this is a valid hash [HttpPost("upload/{hash}")] - [AllowSynchronousIo] public async Task UploadResource(string hash) { string assetsDirectory = FileHelper.ResourcePath; diff --git a/ProjectLighthouse/Helpers/AllowSynchronousIOAttribute.cs b/ProjectLighthouse/Helpers/AllowSynchronousIOAttribute.cs deleted file mode 100644 index 1054f1a7..00000000 --- a/ProjectLighthouse/Helpers/AllowSynchronousIOAttribute.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using Microsoft.AspNetCore.Http.Features; -using Microsoft.AspNetCore.Mvc.Filters; - -namespace LBPUnion.ProjectLighthouse.Helpers -{ - // Yoinked from https://stackoverflow.com/a/68530667 - // Thanks to T-moty! - /// - /// Allows synchronous stream operations for this request. - /// - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] - public class AllowSynchronousIoAttribute : ActionFilterAttribute - { - public override void OnResultExecuting(ResultExecutingContext context) - { - IHttpBodyControlFeature syncIoFeature = context.HttpContext.Features.Get(); - if (syncIoFeature != null) syncIoFeature.AllowSynchronousIO = true; - } - } -} \ No newline at end of file From 5de122f1d5f10b15961a6e65ab4a9b856eab34f1 Mon Sep 17 00:00:00 2001 From: jvyden Date: Thu, 18 Nov 2021 23:04:33 -0500 Subject: [PATCH 11/21] Rename ServerSettings to ServerStatics --- ProjectLighthouse.Tests/DatabaseFact.cs | 4 ++-- ProjectLighthouse.Tests/Tests/AuthenticationTests.cs | 4 ++-- ProjectLighthouse/Controllers/LoginController.cs | 2 +- ProjectLighthouse/Controllers/SlotsController.cs | 4 ++-- ProjectLighthouse/Database.cs | 2 +- ProjectLighthouse/Program.cs | 2 +- .../Settings/{ServerSettings.cs => ServerStatics.cs} | 2 +- ProjectLighthouse/Types/User.cs | 8 ++++---- 8 files changed, 14 insertions(+), 14 deletions(-) rename ProjectLighthouse/Types/Settings/{ServerSettings.cs => ServerStatics.cs} (96%) diff --git a/ProjectLighthouse.Tests/DatabaseFact.cs b/ProjectLighthouse.Tests/DatabaseFact.cs index 7fdc1524..216ea62a 100644 --- a/ProjectLighthouse.Tests/DatabaseFact.cs +++ b/ProjectLighthouse.Tests/DatabaseFact.cs @@ -8,8 +8,8 @@ namespace LBPUnion.ProjectLighthouse.Tests { public DatabaseFact() { - ServerSettings.DbConnectionString = "server=127.0.0.1;uid=root;pwd=lighthouse;database=lighthouse"; - if (!ServerSettings.DbConnected) + ServerStatics.DbConnectionString = "server=127.0.0.1;uid=root;pwd=lighthouse;database=lighthouse"; + if (!ServerStatics.DbConnected) { this.Skip = "Database not available"; } diff --git a/ProjectLighthouse.Tests/Tests/AuthenticationTests.cs b/ProjectLighthouse.Tests/Tests/AuthenticationTests.cs index 893648e0..24684ec6 100644 --- a/ProjectLighthouse.Tests/Tests/AuthenticationTests.cs +++ b/ProjectLighthouse.Tests/Tests/AuthenticationTests.cs @@ -28,7 +28,7 @@ namespace LBPUnion.ProjectLighthouse.Tests Assert.True(response.IsSuccessStatusCode); string responseContent = await response.Content.ReadAsStringAsync(); Assert.Contains("MM_AUTH=", responseContent); - Assert.Contains(ServerSettings.ServerName, responseContent); + Assert.Contains(ServerStatics.ServerName, responseContent); } [DatabaseFact] @@ -41,7 +41,7 @@ namespace LBPUnion.ProjectLighthouse.Tests Assert.NotNull(loginResult.LbpEnvVer); Assert.Contains("MM_AUTH=", loginResult.AuthTicket); - Assert.Equal(ServerSettings.ServerName, loginResult.LbpEnvVer); + Assert.Equal(ServerStatics.ServerName, loginResult.LbpEnvVer); } [DatabaseFact] diff --git a/ProjectLighthouse/Controllers/LoginController.cs b/ProjectLighthouse/Controllers/LoginController.cs index d3e4df74..6bce4863 100644 --- a/ProjectLighthouse/Controllers/LoginController.cs +++ b/ProjectLighthouse/Controllers/LoginController.cs @@ -65,7 +65,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers new LoginResult { AuthTicket = "MM_AUTH=" + token.UserToken, - LbpEnvVer = ServerSettings.ServerName, + LbpEnvVer = ServerStatics.ServerName, }.Serialize() ); } diff --git a/ProjectLighthouse/Controllers/SlotsController.cs b/ProjectLighthouse/Controllers/SlotsController.cs index 48e45184..38a2f5c3 100644 --- a/ProjectLighthouse/Controllers/SlotsController.cs +++ b/ProjectLighthouse/Controllers/SlotsController.cs @@ -41,7 +41,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers .Include(s => s.Location) .Where(s => s.Creator!.Username == user.Username) .Skip(pageStart - 1) - .Take(Math.Min(pageSize, ServerSettings.EntitledSlots)), + .Take(Math.Min(pageSize, ServerStatics.EntitledSlots)), string.Empty, (current, slot) => current + slot.Serialize() ); @@ -55,7 +55,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers new Dictionary { { - "hint_start", pageStart + Math.Min(pageSize, ServerSettings.EntitledSlots) + "hint_start", pageStart + Math.Min(pageSize, ServerStatics.EntitledSlots) }, { "total", user.UsedSlots diff --git a/ProjectLighthouse/Database.cs b/ProjectLighthouse/Database.cs index 20898272..58d725bc 100644 --- a/ProjectLighthouse/Database.cs +++ b/ProjectLighthouse/Database.cs @@ -30,7 +30,7 @@ namespace LBPUnion.ProjectLighthouse public DbSet RatedLevels { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder options) - => options.UseMySql(ServerSettings.DbConnectionString, MySqlServerVersion.LatestSupportedServerVersion); + => options.UseMySql(ServerStatics.DbConnectionString, MySqlServerVersion.LatestSupportedServerVersion); public async Task CreateUser(string username) { diff --git a/ProjectLighthouse/Program.cs b/ProjectLighthouse/Program.cs index d3136b16..be5bc197 100644 --- a/ProjectLighthouse/Program.cs +++ b/ProjectLighthouse/Program.cs @@ -29,7 +29,7 @@ namespace LBPUnion.ProjectLighthouse Logger.Log("Welcome to Project Lighthouse!", LoggerLevelStartup.Instance); Logger.Log("Determining if the database is available...", LoggerLevelStartup.Instance); - bool dbConnected = ServerSettings.DbConnected; + bool dbConnected = ServerStatics.DbConnected; Logger.Log(dbConnected ? "Connected to the database." : "Database unavailable! Exiting.", LoggerLevelStartup.Instance); if (!dbConnected) Environment.Exit(1); diff --git a/ProjectLighthouse/Types/Settings/ServerSettings.cs b/ProjectLighthouse/Types/Settings/ServerStatics.cs similarity index 96% rename from ProjectLighthouse/Types/Settings/ServerSettings.cs rename to ProjectLighthouse/Types/Settings/ServerStatics.cs index daaa3e95..fe1a3a78 100644 --- a/ProjectLighthouse/Types/Settings/ServerSettings.cs +++ b/ProjectLighthouse/Types/Settings/ServerStatics.cs @@ -5,7 +5,7 @@ using LBPUnion.ProjectLighthouse.Logging; namespace LBPUnion.ProjectLighthouse.Types.Settings { - public static class ServerSettings + public static class ServerStatics { /// /// The maximum amount of slots allowed on users' earth diff --git a/ProjectLighthouse/Types/User.cs b/ProjectLighthouse/Types/User.cs index 83c0806a..d872d2df 100644 --- a/ProjectLighthouse/Types/User.cs +++ b/ProjectLighthouse/Types/User.cs @@ -100,7 +100,7 @@ namespace LBPUnion.ProjectLighthouse.Types LbpSerializer.StringElement("game", this.Game) + this.SerializeSlots(gameVersion == GameVersion.LittleBigPlanetVita) + LbpSerializer.StringElement("lists", this.Lists) + - LbpSerializer.StringElement("lists_quota", ServerSettings.ListsQuota) + // technically not a part of the user but LBP expects it + LbpSerializer.StringElement("lists_quota", ServerStatics.ListsQuota) + // technically not a part of the user but LBP expects it LbpSerializer.StringElement("biography", this.Biography) + LbpSerializer.StringElement("reviewCount", this.Reviews) + LbpSerializer.StringElement("commentCount", this.Comments) + @@ -142,7 +142,7 @@ namespace LBPUnion.ProjectLighthouse.Types /// /// The number of slots remaining on the earth /// - public int FreeSlots => ServerSettings.EntitledSlots - this.UsedSlots; + public int FreeSlots => ServerStatics.EntitledSlots - this.UsedSlots; private static readonly string[] slotTypes = { @@ -172,12 +172,12 @@ namespace LBPUnion.ProjectLighthouse.Types slotTypesLocal = slotTypes; } - slots += LbpSerializer.StringElement("entitledSlots", ServerSettings.EntitledSlots); + slots += LbpSerializer.StringElement("entitledSlots", ServerStatics.EntitledSlots); slots += LbpSerializer.StringElement("freeSlots", this.FreeSlots); foreach (string slotType in slotTypesLocal) { - slots += LbpSerializer.StringElement(slotType + "EntitledSlots", ServerSettings.EntitledSlots); + slots += LbpSerializer.StringElement(slotType + "EntitledSlots", ServerStatics.EntitledSlots); // ReSharper disable once StringLiteralTypo slots += LbpSerializer.StringElement(slotType + slotType == "crossControl" ? "PurchsedSlots" : "PurchasedSlots", 0); slots += LbpSerializer.StringElement(slotType + "FreeSlots", this.FreeSlots); From f636fcb3d7b0173e99aaedc22449536e9964297e Mon Sep 17 00:00:00 2001 From: jvyden Date: Thu, 18 Nov 2021 23:42:15 -0500 Subject: [PATCH 12/21] Add config loading, saving, and upgrading --- .gitignore | 1 + .../Controllers/MessageController.cs | 9 +- ProjectLighthouse/Helpers/EulaHelper.cs | 10 --- ProjectLighthouse/Logging/LoggerLevels.cs | 6 ++ ProjectLighthouse/Program.cs | 4 + .../Types/Settings/ServerSettings.cs | 84 +++++++++++++++++++ 6 files changed, 98 insertions(+), 16 deletions(-) create mode 100644 ProjectLighthouse/Types/Settings/ServerSettings.cs diff --git a/.gitignore b/.gitignore index 1c626784..585487d8 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ riderModule.iml /ProjectLighthouse/logs/* /ProjectLighthouse/ProjectLighthouse.csproj.user .vs/ +lighthouse.config.json \ No newline at end of file diff --git a/ProjectLighthouse/Controllers/MessageController.cs b/ProjectLighthouse/Controllers/MessageController.cs index 26ec9d3e..beab0d93 100644 --- a/ProjectLighthouse/Controllers/MessageController.cs +++ b/ProjectLighthouse/Controllers/MessageController.cs @@ -4,6 +4,7 @@ using Kettu; using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Types; +using LBPUnion.ProjectLighthouse.Types.Settings; using Microsoft.AspNetCore.Mvc; namespace LBPUnion.ProjectLighthouse.Controllers @@ -21,11 +22,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers } [HttpGet("eula")] - public async Task Eula() - { - User user = await this.database.UserFromRequest(this.Request); - return user == null ? this.StatusCode(403, "") : this.Ok(EulaHelper.PrivateInstanceNoticeOrBlank + "\n" + $"{EulaHelper.License}\n"); - } + public IActionResult Eula() => this.Ok(ServerSettings.Instance.EulaText + "\n" + $"{EulaHelper.License}\n"); [HttpGet("announce")] public async Task Announce() @@ -33,7 +30,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers User user = await this.database.UserFromRequest(this.Request); if (user == null) return this.StatusCode(403, ""); - return this.Ok($"You are now logged in as user {user.Username} (id {user.UserId}).\n\n" + EulaHelper.PrivateInstanceNoticeOrBlank); + return this.Ok($"You are now logged in as user {user.Username} (id {user.UserId}).\n\n" + ServerSettings.Instance.EulaText); } [HttpGet("notification")] diff --git a/ProjectLighthouse/Helpers/EulaHelper.cs b/ProjectLighthouse/Helpers/EulaHelper.cs index bf59ff2c..03c91a38 100644 --- a/ProjectLighthouse/Helpers/EulaHelper.cs +++ b/ProjectLighthouse/Helpers/EulaHelper.cs @@ -1,5 +1,3 @@ -using System.Diagnostics.CodeAnalysis; - namespace LBPUnion.ProjectLighthouse.Helpers { public static class EulaHelper @@ -17,13 +15,5 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see ."; - - public const string PrivateInstanceNotice = @"This server is a private testing instance. -Please do not make anything public for now, and keep in mind security isn't as tight as a full release would."; - - [SuppressMessage("ReSharper", "HeuristicUnreachableCode")] - public const string PrivateInstanceNoticeOrBlank = ShowPrivateInstanceNotice ? PrivateInstanceNotice : ""; - - public const bool ShowPrivateInstanceNotice = false; } } \ No newline at end of file diff --git a/ProjectLighthouse/Logging/LoggerLevels.cs b/ProjectLighthouse/Logging/LoggerLevels.cs index 2fb28109..3b169f6e 100644 --- a/ProjectLighthouse/Logging/LoggerLevels.cs +++ b/ProjectLighthouse/Logging/LoggerLevels.cs @@ -51,6 +51,12 @@ namespace LBPUnion.ProjectLighthouse.Logging public override string Name => "Photos"; } + public class LoggerLevelConfig : LoggerLevel + { + public static readonly LoggerLevelConfig Instance = new(); + public override string Name => "Config"; + } + public class LoggerLevelAspNet : LoggerLevel { diff --git a/ProjectLighthouse/Program.cs b/ProjectLighthouse/Program.cs index be5bc197..8c2c4e6d 100644 --- a/ProjectLighthouse/Program.cs +++ b/ProjectLighthouse/Program.cs @@ -28,6 +28,10 @@ namespace LBPUnion.ProjectLighthouse Logger.AddLogger(new LighthouseFileLogger()); Logger.Log("Welcome to Project Lighthouse!", LoggerLevelStartup.Instance); + + // This loads the config, see ServerSettings.cs for more information + Logger.Log("Loaded config file version " + ServerSettings.Instance.ConfigVersion, LoggerLevelStartup.Instance); + Logger.Log("Determining if the database is available...", LoggerLevelStartup.Instance); bool dbConnected = ServerStatics.DbConnected; Logger.Log(dbConnected ? "Connected to the database." : "Database unavailable! Exiting.", LoggerLevelStartup.Instance); diff --git a/ProjectLighthouse/Types/Settings/ServerSettings.cs b/ProjectLighthouse/Types/Settings/ServerSettings.cs new file mode 100644 index 00000000..7f8c1815 --- /dev/null +++ b/ProjectLighthouse/Types/Settings/ServerSettings.cs @@ -0,0 +1,84 @@ +using System; +using System.IO; +using System.Text.Json; +using System.Text.Json.Serialization; +using JetBrains.Annotations; +using Kettu; +using LBPUnion.ProjectLighthouse.Logging; + +namespace LBPUnion.ProjectLighthouse.Types.Settings +{ + [Serializable] + public class ServerSettings + { + static ServerSettings() + { + if (File.Exists(ConfigFileName)) + { + string configFile = File.ReadAllText(ConfigFileName); + + Instance = JsonSerializer.Deserialize(configFile) ?? throw new ArgumentNullException(nameof(ConfigFileName)); + + if (Instance.ConfigVersion >= CurrentConfigVersion) return; + + Logger.Log($"Upgrading config file from version {Instance.ConfigVersion} to version {CurrentConfigVersion}", LoggerLevelConfig.Instance); + Instance.ConfigVersion = CurrentConfigVersion; + configFile = JsonSerializer.Serialize + ( + Instance, + typeof(ServerSettings), + new JsonSerializerOptions + { + WriteIndented = true, + } + ); + + File.WriteAllText(ConfigFileName, configFile); + } + else + { + string configFile = JsonSerializer.Serialize + ( + new ServerSettings(), + typeof(ServerSettings), + new JsonSerializerOptions + { + WriteIndented = true, + } + ); + + File.WriteAllText(ConfigFileName, configFile); + + Logger.Log + ( + "The configuration file was not found. " + + "A blank configuration file has been created for you at " + + $"{Path.Combine(Environment.CurrentDirectory, ConfigFileName)}", + LoggerLevelConfig.Instance + ); + + Environment.Exit(1); + } + } + + #region Meta + + [NotNull] + public static ServerSettings Instance; + + public const int CurrentConfigVersion = 1; + + [JsonPropertyName("ConfigVersionDoNotModifyOrYouWillBeSlapped")] + public int ConfigVersion { get; set; } = CurrentConfigVersion; + + public const string ConfigFileName = "lighthouse.config.json"; + + #endregion Meta + + public string InfluxOrg { get; set; } = ""; + public string InfluxBucket { get; set; } = ""; + public string InfluxToken { get; set; } = ""; + + public string EulaText { get; set; } = ""; + } +} \ No newline at end of file From 479057fdcc6faab8abb4612fe8a0e5efdaa86285 Mon Sep 17 00:00:00 2001 From: jvyden Date: Fri, 19 Nov 2021 00:18:21 -0500 Subject: [PATCH 13/21] Add ability for git version/branch to be embedded in builds of lighthouse --- .gitignore | 4 +- ProjectLighthouse/Helpers/GitVersionHelper.cs | 39 +++++++++++++++++++ ProjectLighthouse/Program.cs | 2 + ProjectLighthouse/ProjectLighthouse.csproj | 14 ++++++- 4 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 ProjectLighthouse/Helpers/GitVersionHelper.cs diff --git a/.gitignore b/.gitignore index 585487d8..d03fbb3d 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,6 @@ riderModule.iml /ProjectLighthouse/logs/* /ProjectLighthouse/ProjectLighthouse.csproj.user .vs/ -lighthouse.config.json \ No newline at end of file +lighthouse.config.json +gitBranch.txt +gitVersion.txt \ No newline at end of file diff --git a/ProjectLighthouse/Helpers/GitVersionHelper.cs b/ProjectLighthouse/Helpers/GitVersionHelper.cs new file mode 100644 index 00000000..ecfe9d78 --- /dev/null +++ b/ProjectLighthouse/Helpers/GitVersionHelper.cs @@ -0,0 +1,39 @@ +using System; +using System.IO; +using Kettu; +using LBPUnion.ProjectLighthouse.Logging; + +namespace LBPUnion.ProjectLighthouse.Helpers +{ + public static class GitVersionHelper + { + static GitVersionHelper() + { + try + { + CommitHash = readManifestFile("gitVersion.txt"); + Branch = readManifestFile("gitBranch.txt"); + CanCheckForUpdates = true; + } + catch + { + Logger.Log("Project Lighthouse was built incorrectly. Please make sure git is available when building.", LoggerLevelStartup.Instance); + CommitHash = "invalid"; + Branch = "invalid"; + CanCheckForUpdates = false; + } + } + + private static string readManifestFile(string fileName) + { + using Stream stream = typeof(Program).Assembly.GetManifestResourceStream($"{typeof(Program).Namespace}.{fileName}"); + using StreamReader reader = new(stream ?? throw new Exception("The assembly or manifest resource is null.")); + + return reader.ReadToEnd().Trim(); + } + + public static string CommitHash { get; set; } + public static string Branch { get; set; } + public static bool CanCheckForUpdates { get; set; } + } +} \ No newline at end of file diff --git a/ProjectLighthouse/Program.cs b/ProjectLighthouse/Program.cs index 8c2c4e6d..030f20d2 100644 --- a/ProjectLighthouse/Program.cs +++ b/ProjectLighthouse/Program.cs @@ -1,6 +1,7 @@ using System; using System.Diagnostics; using Kettu; +using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Types.Settings; using Microsoft.AspNetCore.Hosting; @@ -28,6 +29,7 @@ namespace LBPUnion.ProjectLighthouse Logger.AddLogger(new LighthouseFileLogger()); Logger.Log("Welcome to Project Lighthouse!", LoggerLevelStartup.Instance); + Logger.Log($"Running {ServerStatics.ServerName} {GitVersionHelper.CommitHash}@{GitVersionHelper.Branch}", LoggerLevelStartup.Instance); // This loads the config, see ServerSettings.cs for more information Logger.Log("Loaded config file version " + ServerSettings.Instance.ConfigVersion, LoggerLevelStartup.Instance); diff --git a/ProjectLighthouse/ProjectLighthouse.csproj b/ProjectLighthouse/ProjectLighthouse.csproj index 51f3117d..082c9930 100644 --- a/ProjectLighthouse/ProjectLighthouse.csproj +++ b/ProjectLighthouse/ProjectLighthouse.csproj @@ -21,7 +21,19 @@ - + + + Always + + + + Always + + + + + + From 76aeb54da0a90bf137b88ef553f4c6af9e591d36 Mon Sep 17 00:00:00 2001 From: jvyden Date: Fri, 19 Nov 2021 00:22:14 -0500 Subject: [PATCH 14/21] Add dirty commit warning --- ProjectLighthouse/Helpers/GitVersionHelper.cs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/ProjectLighthouse/Helpers/GitVersionHelper.cs b/ProjectLighthouse/Helpers/GitVersionHelper.cs index ecfe9d78..857728fe 100644 --- a/ProjectLighthouse/Helpers/GitVersionHelper.cs +++ b/ProjectLighthouse/Helpers/GitVersionHelper.cs @@ -17,11 +17,27 @@ namespace LBPUnion.ProjectLighthouse.Helpers } catch { - Logger.Log("Project Lighthouse was built incorrectly. Please make sure git is available when building.", LoggerLevelStartup.Instance); + Logger.Log + ( + "Project Lighthouse was built incorrectly. Please make sure git is available when building. " + + "Because of this, you will not be notified of updates.", + LoggerLevelStartup.Instance + ); CommitHash = "invalid"; Branch = "invalid"; CanCheckForUpdates = false; } + + if (IsDirty) + { + Logger.Log + ( + "This is a modified version of Project Lighthouse. " + + "Please make sure you are properly disclosing the source code to any users who may be using this instance.", + LoggerLevelStartup.Instance + ); + CanCheckForUpdates = false; + } } private static string readManifestFile(string fileName) @@ -34,6 +50,7 @@ namespace LBPUnion.ProjectLighthouse.Helpers public static string CommitHash { get; set; } public static string Branch { get; set; } + public static bool IsDirty => CommitHash.EndsWith("-dirty"); public static bool CanCheckForUpdates { get; set; } } } \ No newline at end of file From 177befde9184d7cba052c18598857b05b632fbea Mon Sep 17 00:00:00 2001 From: jvyden Date: Fri, 19 Nov 2021 00:25:41 -0500 Subject: [PATCH 15/21] Add DbConnectionString to config --- ProjectLighthouse.Tests/DatabaseFact.cs | 2 +- ProjectLighthouse/Database.cs | 2 +- ProjectLighthouse/Types/Settings/ServerSettings.cs | 4 +++- ProjectLighthouse/Types/Settings/ServerStatics.cs | 11 ----------- 4 files changed, 5 insertions(+), 14 deletions(-) diff --git a/ProjectLighthouse.Tests/DatabaseFact.cs b/ProjectLighthouse.Tests/DatabaseFact.cs index 216ea62a..df9a357c 100644 --- a/ProjectLighthouse.Tests/DatabaseFact.cs +++ b/ProjectLighthouse.Tests/DatabaseFact.cs @@ -8,7 +8,7 @@ namespace LBPUnion.ProjectLighthouse.Tests { public DatabaseFact() { - ServerStatics.DbConnectionString = "server=127.0.0.1;uid=root;pwd=lighthouse;database=lighthouse"; + ServerSettings.Instance.DbConnectionString = "server=127.0.0.1;uid=root;pwd=lighthouse;database=lighthouse"; if (!ServerStatics.DbConnected) { this.Skip = "Database not available"; diff --git a/ProjectLighthouse/Database.cs b/ProjectLighthouse/Database.cs index 58d725bc..a7051327 100644 --- a/ProjectLighthouse/Database.cs +++ b/ProjectLighthouse/Database.cs @@ -30,7 +30,7 @@ namespace LBPUnion.ProjectLighthouse public DbSet RatedLevels { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder options) - => options.UseMySql(ServerStatics.DbConnectionString, MySqlServerVersion.LatestSupportedServerVersion); + => options.UseMySql(ServerSettings.Instance.DbConnectionString, MySqlServerVersion.LatestSupportedServerVersion); public async Task CreateUser(string username) { diff --git a/ProjectLighthouse/Types/Settings/ServerSettings.cs b/ProjectLighthouse/Types/Settings/ServerSettings.cs index 7f8c1815..ae80e28e 100644 --- a/ProjectLighthouse/Types/Settings/ServerSettings.cs +++ b/ProjectLighthouse/Types/Settings/ServerSettings.cs @@ -66,7 +66,7 @@ namespace LBPUnion.ProjectLighthouse.Types.Settings [NotNull] public static ServerSettings Instance; - public const int CurrentConfigVersion = 1; + public const int CurrentConfigVersion = 2; [JsonPropertyName("ConfigVersionDoNotModifyOrYouWillBeSlapped")] public int ConfigVersion { get; set; } = CurrentConfigVersion; @@ -80,5 +80,7 @@ namespace LBPUnion.ProjectLighthouse.Types.Settings public string InfluxToken { get; set; } = ""; public string EulaText { get; set; } = ""; + + public string DbConnectionString { get; set; } = "server=127.0.0.1;uid=root;pwd=lighthouse;database=lighthouse"; } } \ No newline at end of file diff --git a/ProjectLighthouse/Types/Settings/ServerStatics.cs b/ProjectLighthouse/Types/Settings/ServerStatics.cs index fe1a3a78..24be656f 100644 --- a/ProjectLighthouse/Types/Settings/ServerStatics.cs +++ b/ProjectLighthouse/Types/Settings/ServerStatics.cs @@ -16,17 +16,6 @@ namespace LBPUnion.ProjectLighthouse.Types.Settings public const string ServerName = "ProjectLighthouse"; - private static string? dbConnectionString; - - public static string DbConnectionString { - get { - if (dbConnectionString == null) return dbConnectionString = Environment.GetEnvironmentVariable("LIGHTHOUSE_DB_CONNECTION_STRING") ?? ""; - - return dbConnectionString; - } - set => dbConnectionString = value; - } - public static bool DbConnected { get { try From cbe8fbc2b4e658f81f7c26f7824d78e34084c2c0 Mon Sep 17 00:00:00 2001 From: jvyden Date: Fri, 19 Nov 2021 00:42:46 -0500 Subject: [PATCH 16/21] Fix unit tests breaking due to config changes --- ProjectLighthouse.Tests/DatabaseFact.cs | 1 + ProjectLighthouse/Types/Settings/ServerSettings.cs | 2 ++ ProjectLighthouse/Types/Settings/ServerStatics.cs | 3 +++ 3 files changed, 6 insertions(+) diff --git a/ProjectLighthouse.Tests/DatabaseFact.cs b/ProjectLighthouse.Tests/DatabaseFact.cs index df9a357c..a62ecd5a 100644 --- a/ProjectLighthouse.Tests/DatabaseFact.cs +++ b/ProjectLighthouse.Tests/DatabaseFact.cs @@ -8,6 +8,7 @@ namespace LBPUnion.ProjectLighthouse.Tests { public DatabaseFact() { + ServerSettings.Instance = new ServerSettings(); ServerSettings.Instance.DbConnectionString = "server=127.0.0.1;uid=root;pwd=lighthouse;database=lighthouse"; if (!ServerStatics.DbConnected) { diff --git a/ProjectLighthouse/Types/Settings/ServerSettings.cs b/ProjectLighthouse/Types/Settings/ServerSettings.cs index ae80e28e..7b9b8c04 100644 --- a/ProjectLighthouse/Types/Settings/ServerSettings.cs +++ b/ProjectLighthouse/Types/Settings/ServerSettings.cs @@ -13,6 +13,8 @@ namespace LBPUnion.ProjectLighthouse.Types.Settings { static ServerSettings() { + if (ServerStatics.IsUnitTesting) return; // Unit testing, we don't want to read configurations here since the tests will provide their own + if (File.Exists(ConfigFileName)) { string configFile = File.ReadAllText(ConfigFileName); diff --git a/ProjectLighthouse/Types/Settings/ServerStatics.cs b/ProjectLighthouse/Types/Settings/ServerStatics.cs index 24be656f..a6b29548 100644 --- a/ProjectLighthouse/Types/Settings/ServerStatics.cs +++ b/ProjectLighthouse/Types/Settings/ServerStatics.cs @@ -1,5 +1,6 @@ #nullable enable using System; +using System.Linq; using Kettu; using LBPUnion.ProjectLighthouse.Logging; @@ -29,5 +30,7 @@ namespace LBPUnion.ProjectLighthouse.Types.Settings } } } + + public static bool IsUnitTesting => AppDomain.CurrentDomain.GetAssemblies().Any(assembly => assembly.FullName.StartsWith("xunit")); } } \ No newline at end of file From 0ada6efe45da090150449ce20bb953ee2769192d Mon Sep 17 00:00:00 2001 From: jvyden Date: Fri, 19 Nov 2021 00:45:59 -0500 Subject: [PATCH 17/21] Fix ShouldReturnForbiddenWhenNotAuthenticated tests --- ProjectLighthouse.Tests/Tests/AuthenticationTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProjectLighthouse.Tests/Tests/AuthenticationTests.cs b/ProjectLighthouse.Tests/Tests/AuthenticationTests.cs index 24684ec6..346b957b 100644 --- a/ProjectLighthouse.Tests/Tests/AuthenticationTests.cs +++ b/ProjectLighthouse.Tests/Tests/AuthenticationTests.cs @@ -59,7 +59,7 @@ namespace LBPUnion.ProjectLighthouse.Tests [DatabaseFact] public async Task ShouldReturnForbiddenWhenNotAuthenticated() { - HttpResponseMessage response = await this.Client.GetAsync("/LITTLEBIGPLANETPS3_XML/eula"); + HttpResponseMessage response = await this.Client.GetAsync("/LITTLEBIGPLANETPS3_XML/announce"); Assert.False(response.IsSuccessStatusCode); Assert.True(response.StatusCode == HttpStatusCode.Forbidden); } From 3c42c0cf556e391ec4803d4371b3bccff7727073 Mon Sep 17 00:00:00 2001 From: jvyden Date: Fri, 19 Nov 2021 01:45:47 -0500 Subject: [PATCH 18/21] InfluxDB Logging support --- .../Controllers/StatisticsController.cs | 15 ++---- ProjectLighthouse/Helpers/InfluxHelper.cs | 48 +++++++++++++++++++ ProjectLighthouse/Helpers/StatisticsHelper.cs | 17 +++++++ ProjectLighthouse/Logging/LoggerLevels.cs | 6 +++ ProjectLighthouse/Program.cs | 6 +++ ProjectLighthouse/ProjectLighthouse.csproj | 1 + .../Types/Settings/ServerSettings.cs | 8 ++-- 7 files changed, 87 insertions(+), 14 deletions(-) create mode 100644 ProjectLighthouse/Helpers/InfluxHelper.cs create mode 100644 ProjectLighthouse/Helpers/StatisticsHelper.cs diff --git a/ProjectLighthouse/Controllers/StatisticsController.cs b/ProjectLighthouse/Controllers/StatisticsController.cs index 9deb12c4..eb945419 100644 --- a/ProjectLighthouse/Controllers/StatisticsController.cs +++ b/ProjectLighthouse/Controllers/StatisticsController.cs @@ -1,9 +1,7 @@ -using System.Linq; using System.Threading.Tasks; using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Serialization; using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; namespace LBPUnion.ProjectLighthouse.Controllers { @@ -20,18 +18,13 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpGet("playersInPodCount")] [HttpGet("totalPlayerCount")] - public async Task TotalPlayerCount() - { - int recentMatches = await this.database.LastMatches.Where(l => TimestampHelper.Timestamp - l.Timestamp < 60).CountAsync(); - - return this.Ok(recentMatches.ToString()); - } + public async Task TotalPlayerCount() => this.Ok((await StatisticsHelper.RecentMatches()).ToString()!); [HttpGet("planetStats")] public async Task PlanetStats() { - int totalSlotCount = await this.database.Slots.CountAsync(); - int mmPicksCount = await this.database.Slots.CountAsync(s => s.TeamPick); + int totalSlotCount = await StatisticsHelper.SlotCount(); + int mmPicksCount = await StatisticsHelper.MMPicksCount(); return this.Ok ( @@ -41,6 +34,6 @@ namespace LBPUnion.ProjectLighthouse.Controllers } [HttpGet("planetStats/totalLevelCount")] - public async Task TotalLevelCount() => this.Ok((await this.database.Slots.CountAsync()).ToString()); + public async Task TotalLevelCount() => this.Ok((await StatisticsHelper.SlotCount()).ToString()); } } \ No newline at end of file diff --git a/ProjectLighthouse/Helpers/InfluxHelper.cs b/ProjectLighthouse/Helpers/InfluxHelper.cs new file mode 100644 index 00000000..cd5b844e --- /dev/null +++ b/ProjectLighthouse/Helpers/InfluxHelper.cs @@ -0,0 +1,48 @@ +using System.Threading; +using System.Threading.Tasks; +using InfluxDB.Client; +using InfluxDB.Client.Writes; +using Kettu; +using LBPUnion.ProjectLighthouse.Logging; +using LBPUnion.ProjectLighthouse.Types.Settings; + +namespace LBPUnion.ProjectLighthouse.Helpers +{ + public static class InfluxHelper + { + public static readonly InfluxDBClient Client = InfluxDBClientFactory.Create(ServerSettings.Instance.InfluxUrl, ServerSettings.Instance.InfluxToken); + + public static async void Log() + { + WriteApi writeApi = Client.GetWriteApi(); + PointData point = PointData.Measurement("lighthouse").Field("playerCount", await StatisticsHelper.RecentMatches()); + + writeApi.WritePoint(ServerSettings.Instance.InfluxBucket, ServerSettings.Instance.InfluxOrg, point); + + writeApi.Flush(); + } + + public static async Task StartLogging() + { + await Client.ReadyAsync(); + Logger.Log("InfluxDB is now ready.", LoggerLevelInflux.Instance); + Thread t = new Thread + ( + delegate() + { + while (true) + { + Thread.Sleep(5000); + #pragma warning disable CS4014 + Log(); + #pragma warning restore CS4014 + Logger.Log("Logged.", LoggerLevelInflux.Instance); + } + } + ); + t.IsBackground = true; + t.Name = "InfluxDB Logger"; + t.Start(); + } + } +} \ No newline at end of file diff --git a/ProjectLighthouse/Helpers/StatisticsHelper.cs b/ProjectLighthouse/Helpers/StatisticsHelper.cs new file mode 100644 index 00000000..99e42cab --- /dev/null +++ b/ProjectLighthouse/Helpers/StatisticsHelper.cs @@ -0,0 +1,17 @@ +using System.Linq; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; + +namespace LBPUnion.ProjectLighthouse.Helpers +{ + public static class StatisticsHelper + { + private static readonly Database database = new(); + + public static async Task RecentMatches() => await database.LastMatches.Where(l => TimestampHelper.Timestamp - l.Timestamp < 60).CountAsync(); + + public static async Task SlotCount() => await database.Slots.CountAsync(); + + public static async Task MMPicksCount() => await database.Slots.CountAsync(s => s.TeamPick); + } +} \ No newline at end of file diff --git a/ProjectLighthouse/Logging/LoggerLevels.cs b/ProjectLighthouse/Logging/LoggerLevels.cs index 3b169f6e..9d81a53b 100644 --- a/ProjectLighthouse/Logging/LoggerLevels.cs +++ b/ProjectLighthouse/Logging/LoggerLevels.cs @@ -57,6 +57,12 @@ namespace LBPUnion.ProjectLighthouse.Logging public override string Name => "Config"; } + public class LoggerLevelInflux : LoggerLevel + { + public static readonly LoggerLevelInflux Instance = new(); + public override string Name => "Influx"; + } + public class LoggerLevelAspNet : LoggerLevel { diff --git a/ProjectLighthouse/Program.cs b/ProjectLighthouse/Program.cs index 030f20d2..e03ba6f5 100644 --- a/ProjectLighthouse/Program.cs +++ b/ProjectLighthouse/Program.cs @@ -44,6 +44,12 @@ namespace LBPUnion.ProjectLighthouse Logger.Log("Migrating database...", LoggerLevelDatabase.Instance); MigrateDatabase(database); + if (ServerSettings.Instance.InfluxEnabled) + { + Logger.Log("Influx logging is enabled. Starting influx logging...", LoggerLevelStartup.Instance); + InfluxHelper.StartLogging(); + } + stopwatch.Stop(); Logger.Log($"Ready! Startup took {stopwatch.ElapsedMilliseconds}ms. Passing off control to ASP.NET...", LoggerLevelStartup.Instance); diff --git a/ProjectLighthouse/ProjectLighthouse.csproj b/ProjectLighthouse/ProjectLighthouse.csproj index 082c9930..b576a35c 100644 --- a/ProjectLighthouse/ProjectLighthouse.csproj +++ b/ProjectLighthouse/ProjectLighthouse.csproj @@ -9,6 +9,7 @@ + diff --git a/ProjectLighthouse/Types/Settings/ServerSettings.cs b/ProjectLighthouse/Types/Settings/ServerSettings.cs index 7b9b8c04..fcdc9a8f 100644 --- a/ProjectLighthouse/Types/Settings/ServerSettings.cs +++ b/ProjectLighthouse/Types/Settings/ServerSettings.cs @@ -68,7 +68,7 @@ namespace LBPUnion.ProjectLighthouse.Types.Settings [NotNull] public static ServerSettings Instance; - public const int CurrentConfigVersion = 2; + public const int CurrentConfigVersion = 3; [JsonPropertyName("ConfigVersionDoNotModifyOrYouWillBeSlapped")] public int ConfigVersion { get; set; } = CurrentConfigVersion; @@ -77,9 +77,11 @@ namespace LBPUnion.ProjectLighthouse.Types.Settings #endregion Meta - public string InfluxOrg { get; set; } = ""; - public string InfluxBucket { get; set; } = ""; + public bool InfluxEnabled { get; set; } = false; + public string InfluxOrg { get; set; } = "lighthouse"; + public string InfluxBucket { get; set; } = "lighthouse"; public string InfluxToken { get; set; } = ""; + public string InfluxUrl { get; set; } = "http://localhost:8086"; public string EulaText { get; set; } = ""; From 8703a391008a4c0675b369831bca8268928e0c2b Mon Sep 17 00:00:00 2001 From: jvyden Date: Fri, 19 Nov 2021 02:21:49 -0500 Subject: [PATCH 19/21] Add InfluxLogger for Kettu, log slot counts --- ProjectLighthouse/Helpers/InfluxHelper.cs | 12 +++++---- ProjectLighthouse/Logging/InfluxLogger.cs | 27 +++++++++++++++++++ ProjectLighthouse/Program.cs | 3 +++ .../Types/Settings/ServerSettings.cs | 5 ++-- 4 files changed, 40 insertions(+), 7 deletions(-) create mode 100644 ProjectLighthouse/Logging/InfluxLogger.cs diff --git a/ProjectLighthouse/Helpers/InfluxHelper.cs b/ProjectLighthouse/Helpers/InfluxHelper.cs index cd5b844e..166429fc 100644 --- a/ProjectLighthouse/Helpers/InfluxHelper.cs +++ b/ProjectLighthouse/Helpers/InfluxHelper.cs @@ -14,8 +14,10 @@ namespace LBPUnion.ProjectLighthouse.Helpers public static async void Log() { - WriteApi writeApi = Client.GetWriteApi(); - PointData point = PointData.Measurement("lighthouse").Field("playerCount", await StatisticsHelper.RecentMatches()); + using WriteApi writeApi = Client.GetWriteApi(); + PointData point = PointData.Measurement("lighthouse") + .Field("playerCount", await StatisticsHelper.RecentMatches()) + .Field("slotCount", await StatisticsHelper.SlotCount()); writeApi.WritePoint(ServerSettings.Instance.InfluxBucket, ServerSettings.Instance.InfluxOrg, point); @@ -26,17 +28,17 @@ namespace LBPUnion.ProjectLighthouse.Helpers { await Client.ReadyAsync(); Logger.Log("InfluxDB is now ready.", LoggerLevelInflux.Instance); - Thread t = new Thread + Thread t = new ( delegate() { while (true) { - Thread.Sleep(5000); #pragma warning disable CS4014 Log(); #pragma warning restore CS4014 - Logger.Log("Logged.", LoggerLevelInflux.Instance); +// Logger.Log("Logged.", LoggerLevelInflux.Instance); + Thread.Sleep(60000); } } ); diff --git a/ProjectLighthouse/Logging/InfluxLogger.cs b/ProjectLighthouse/Logging/InfluxLogger.cs new file mode 100644 index 00000000..a4ab28e9 --- /dev/null +++ b/ProjectLighthouse/Logging/InfluxLogger.cs @@ -0,0 +1,27 @@ +using InfluxDB.Client; +using InfluxDB.Client.Writes; +using Kettu; +using LBPUnion.ProjectLighthouse.Helpers; +using LBPUnion.ProjectLighthouse.Types.Settings; + +namespace LBPUnion.ProjectLighthouse.Logging +{ + public class InfluxLogger : LoggerBase + { + + public override void Send(LoggerLine line) + { + string channel = string.IsNullOrEmpty(line.LoggerLevel.Channel) ? "" : $"[{line.LoggerLevel.Channel}] "; + + string level = $"{$"{line.LoggerLevel.Name} {channel}".TrimEnd()}"; + string content = line.LineData; + + using WriteApi writeApi = InfluxHelper.Client.GetWriteApi(); + + PointData point = PointData.Measurement("lighthouseLog").Field("level", level).Field("content", content); + + writeApi.WritePoint(ServerSettings.Instance.InfluxBucket, ServerSettings.Instance.InfluxOrg, point); + } + public override bool AllowMultiple => false; + } +} \ No newline at end of file diff --git a/ProjectLighthouse/Program.cs b/ProjectLighthouse/Program.cs index e03ba6f5..695e2470 100644 --- a/ProjectLighthouse/Program.cs +++ b/ProjectLighthouse/Program.cs @@ -47,7 +47,10 @@ namespace LBPUnion.ProjectLighthouse if (ServerSettings.Instance.InfluxEnabled) { Logger.Log("Influx logging is enabled. Starting influx logging...", LoggerLevelStartup.Instance); + #pragma warning disable CS4014 InfluxHelper.StartLogging(); + #pragma warning restore CS4014 + if (ServerSettings.Instance.InfluxLoggingEnabled) Logger.AddLogger(new InfluxLogger()); } stopwatch.Stop(); diff --git a/ProjectLighthouse/Types/Settings/ServerSettings.cs b/ProjectLighthouse/Types/Settings/ServerSettings.cs index fcdc9a8f..405e90db 100644 --- a/ProjectLighthouse/Types/Settings/ServerSettings.cs +++ b/ProjectLighthouse/Types/Settings/ServerSettings.cs @@ -68,7 +68,7 @@ namespace LBPUnion.ProjectLighthouse.Types.Settings [NotNull] public static ServerSettings Instance; - public const int CurrentConfigVersion = 3; + public const int CurrentConfigVersion = 4; [JsonPropertyName("ConfigVersionDoNotModifyOrYouWillBeSlapped")] public int ConfigVersion { get; set; } = CurrentConfigVersion; @@ -77,7 +77,8 @@ namespace LBPUnion.ProjectLighthouse.Types.Settings #endregion Meta - public bool InfluxEnabled { get; set; } = false; + public bool InfluxEnabled { get; set; } + public bool InfluxLoggingEnabled { get; set; } public string InfluxOrg { get; set; } = "lighthouse"; public string InfluxBucket { get; set; } = "lighthouse"; public string InfluxToken { get; set; } = ""; From 325d55e458bd919e7482af9b87da3d86bacd2a70 Mon Sep 17 00:00:00 2001 From: jvyden Date: Fri, 19 Nov 2021 15:46:24 -0500 Subject: [PATCH 20/21] Make player timeout 2 minutes --- ProjectLighthouse/Helpers/StatisticsHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProjectLighthouse/Helpers/StatisticsHelper.cs b/ProjectLighthouse/Helpers/StatisticsHelper.cs index 99e42cab..c127c7d2 100644 --- a/ProjectLighthouse/Helpers/StatisticsHelper.cs +++ b/ProjectLighthouse/Helpers/StatisticsHelper.cs @@ -8,7 +8,7 @@ namespace LBPUnion.ProjectLighthouse.Helpers { private static readonly Database database = new(); - public static async Task RecentMatches() => await database.LastMatches.Where(l => TimestampHelper.Timestamp - l.Timestamp < 60).CountAsync(); + public static async Task RecentMatches() => await database.LastMatches.Where(l => TimestampHelper.Timestamp - l.Timestamp < 120).CountAsync(); public static async Task SlotCount() => await database.Slots.CountAsync(); From 443bb1fc02a91401d6d4ae0fbf944387d845c4e7 Mon Sep 17 00:00:00 2001 From: jvyden Date: Fri, 19 Nov 2021 20:38:29 -0500 Subject: [PATCH 21/21] Increase player timeout to 5 minutes --- ProjectLighthouse/Helpers/StatisticsHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProjectLighthouse/Helpers/StatisticsHelper.cs b/ProjectLighthouse/Helpers/StatisticsHelper.cs index c127c7d2..3a43ed81 100644 --- a/ProjectLighthouse/Helpers/StatisticsHelper.cs +++ b/ProjectLighthouse/Helpers/StatisticsHelper.cs @@ -8,7 +8,7 @@ namespace LBPUnion.ProjectLighthouse.Helpers { private static readonly Database database = new(); - public static async Task RecentMatches() => await database.LastMatches.Where(l => TimestampHelper.Timestamp - l.Timestamp < 120).CountAsync(); + public static async Task RecentMatches() => await database.LastMatches.Where(l => TimestampHelper.Timestamp - l.Timestamp < 300).CountAsync(); public static async Task SlotCount() => await database.Slots.CountAsync();