From a41a929e7f9f365e6eff6cf8f1b82967dd656222 Mon Sep 17 00:00:00 2001 From: Marcel Baumgartner Date: Mon, 3 Apr 2023 19:45:01 +0200 Subject: [PATCH 01/10] Added subscription edit --- .../Views/Admin/Subscriptions/Edit.razor | 168 ++++++++++++++++++ Moonlight/resources/lang/de_de.lang | 1 + 2 files changed, 169 insertions(+) create mode 100644 Moonlight/Shared/Views/Admin/Subscriptions/Edit.razor diff --git a/Moonlight/Shared/Views/Admin/Subscriptions/Edit.razor b/Moonlight/Shared/Views/Admin/Subscriptions/Edit.razor new file mode 100644 index 00000000..87dd733c --- /dev/null +++ b/Moonlight/Shared/Views/Admin/Subscriptions/Edit.razor @@ -0,0 +1,168 @@ +@page "/admin/subscriptions/edit/{Id:int}" +@using Moonlight.App.Models.Forms +@using Moonlight.App.Models.Misc +@using Moonlight.App.Repositories +@using Moonlight.App.Services +@using Moonlight.App.Database.Entities + +@inject NavigationManager NavigationManager +@inject SubscriptionRepository SubscriptionRepository +@inject SubscriptionAdminService SubscriptionAdminService + + +
+ + @if (Subscription == null) + { +
+ No subscription with this id has been found +
+ } + else + { + + +
+ +
+ +
+ +
+ +
+ @foreach (var limitPart in Limits.Chunk(3)) + { +
+ @foreach (var limit in limitPart) + { +
+
+ +
+ +
+ +
+ +
+
+
+ Options +
+
+ +
+
+ + +
+
+
+
+ } +
+ } +
+ +
+ + +
+
+ } +
+
+
+ +@code +{ + [Parameter] + public int Id { get; set; } + + private Subscription? Subscription; + + private SubscriptionDataModel Model = new(); + private List Limits = new(); + + private async Task OnSubmit() + { + Subscription!.Name = Model.Name; + Subscription.Description = Model.Description; + + SubscriptionRepository.Update(Subscription); + + await SubscriptionAdminService.SaveLimits(Subscription, Limits.ToArray()); + + NavigationManager.NavigateTo("/admin/subscriptions"); + } + + private async Task Load(LazyLoader arg) + { + Subscription = SubscriptionRepository + .Get() + .FirstOrDefault(x => x.Id == Id); + + if (Subscription != null) + { + Model.Name = Subscription.Name; + Model.Description = Subscription.Description; + + Limits = (await SubscriptionAdminService.GetLimits(Subscription)).ToList(); + } + } +} \ No newline at end of file diff --git a/Moonlight/resources/lang/de_de.lang b/Moonlight/resources/lang/de_de.lang index 0cfc0d21..b56f294a 100644 --- a/Moonlight/resources/lang/de_de.lang +++ b/Moonlight/resources/lang/de_de.lang @@ -462,3 +462,4 @@ Create subscription;Create subscription Options;Options Amount;Amount Do you really want to delete it?;Do you really want to delete it? +Save subscription;Save subscription From 2298bab71e98cc3ae60bd8e04a22f60284db4c9a Mon Sep 17 00:00:00 2001 From: Marcel Baumgartner Date: Mon, 3 Apr 2023 21:23:27 +0200 Subject: [PATCH 02/10] Base implementation of smart deploy for servers, order screen, subscription service --- .../App/Models/Forms/ServerOrderDataModel.cs | 14 ++ .../App/Models/Misc/SubscriptionLimit.cs | 6 + Moonlight/App/Services/SmartDeployService.cs | 64 +++++++ Moonlight/App/Services/SubscriptionService.cs | 22 ++- Moonlight/Program.cs | 1 + Moonlight/Shared/Layouts/MainLayout.razor | 3 +- .../{Servers.razor => Servers/Index.razor} | 0 Moonlight/Shared/Views/Servers/New.razor | 174 ++++++++++++++++++ Moonlight/resources/lang/de_de.lang | 12 ++ 9 files changed, 287 insertions(+), 9 deletions(-) create mode 100644 Moonlight/App/Models/Forms/ServerOrderDataModel.cs create mode 100644 Moonlight/App/Services/SmartDeployService.cs rename Moonlight/Shared/Views/{Servers.razor => Servers/Index.razor} (100%) create mode 100644 Moonlight/Shared/Views/Servers/New.razor diff --git a/Moonlight/App/Models/Forms/ServerOrderDataModel.cs b/Moonlight/App/Models/Forms/ServerOrderDataModel.cs new file mode 100644 index 00000000..778096f5 --- /dev/null +++ b/Moonlight/App/Models/Forms/ServerOrderDataModel.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.DataAnnotations; +using Moonlight.App.Database.Entities; + +namespace Moonlight.App.Models.Forms; + +public class ServerOrderDataModel +{ + [Required(ErrorMessage = "You need to enter a name")] + [MaxLength(32, ErrorMessage = "The name cannot be longer that 32 characters")] + public string Name { get; set; } = ""; + + [Required(ErrorMessage = "You need to specify a server image")] + public Image Image { get; set; } +} \ No newline at end of file diff --git a/Moonlight/App/Models/Misc/SubscriptionLimit.cs b/Moonlight/App/Models/Misc/SubscriptionLimit.cs index 6e77abaf..21d59100 100644 --- a/Moonlight/App/Models/Misc/SubscriptionLimit.cs +++ b/Moonlight/App/Models/Misc/SubscriptionLimit.cs @@ -5,6 +5,12 @@ public class SubscriptionLimit public string Identifier { get; set; } = ""; public int Amount { get; set; } public List Options { get; set; } = new(); + + public string? ReadValue(string key) + { + var d = Options.FirstOrDefault(x => string.Equals(x.Key, key, StringComparison.InvariantCultureIgnoreCase)); + return d?.Value; + } public class LimitOption { diff --git a/Moonlight/App/Services/SmartDeployService.cs b/Moonlight/App/Services/SmartDeployService.cs new file mode 100644 index 00000000..0585c1dd --- /dev/null +++ b/Moonlight/App/Services/SmartDeployService.cs @@ -0,0 +1,64 @@ +using Moonlight.App.Database.Entities; +using Moonlight.App.Repositories; + +namespace Moonlight.App.Services; + +public class SmartDeployService +{ + private readonly NodeRepository NodeRepository; + private readonly NodeService NodeService; + + public SmartDeployService(NodeRepository nodeRepository, NodeService nodeService) + { + NodeRepository = nodeRepository; + NodeService = nodeService; + } + + public async Task GetNode() + { + var data = new Dictionary(); + + foreach (var node in NodeRepository.Get().ToArray()) + { + var u = await GetUsageScore(node); + + if(u != 0) + data.Add(node, u); + } + + if (!data.Any()) + return null; + + return data.MaxBy(x => x.Value).Key; + } + + private async Task GetUsageScore(Node node) + { + var score = 0; + + try + { + var cpuStats = await NodeService.GetCpuStats(node); + var memoryStats = await NodeService.GetMemoryStats(node); + var diskStats = await NodeService.GetDiskStats(node); + + var cpuWeight = 0.5; // Weight of CPU usage in the final score + var memoryWeight = 0.3; // Weight of memory usage in the final score + var diskSpaceWeight = 0.2; // Weight of free disk space in the final score + + var cpuScore = (1 - cpuStats.Usage) * cpuWeight; // CPU score is based on the inverse of CPU usage + var memoryScore = (1 - (memoryStats.Used / 1024)) * memoryWeight; // Memory score is based on the percentage of free memory + var diskSpaceScore = (double) diskStats.FreeBytes / 1000000000 * diskSpaceWeight; // Disk space score is based on the amount of free disk space in GB + + var finalScore = cpuScore + memoryScore + diskSpaceScore; + + return finalScore; + } + catch (Exception e) + { + // ignored + } + + return score; + } +} \ No newline at end of file diff --git a/Moonlight/App/Services/SubscriptionService.cs b/Moonlight/App/Services/SubscriptionService.cs index f5e77c95..9d35fe4b 100644 --- a/Moonlight/App/Services/SubscriptionService.cs +++ b/Moonlight/App/Services/SubscriptionService.cs @@ -82,16 +82,19 @@ public class SubscriptionService { var configSection = ConfigService.GetSection("Moonlight").GetSection("Subscriptions"); - var defaultLimits = configSection.GetValue("defaultLimits"); + var defaultLimits = configSection.GetValue("DefaultLimits"); var subscription = await GetCurrent(); if (subscription == null) { - var foundDefault = defaultLimits.FirstOrDefault(x => x.Identifier == identifier); + if (defaultLimits != null) + { + var foundDefault = defaultLimits.FirstOrDefault(x => x.Identifier == identifier); - if (foundDefault != null) - return foundDefault; + if (foundDefault != null) + return foundDefault; + } return new() { @@ -109,11 +112,14 @@ public class SubscriptionService if (foundLimit != null) return foundLimit; - - var foundDefault = defaultLimits.FirstOrDefault(x => x.Identifier == identifier); - if (foundDefault != null) - return foundDefault; + if (defaultLimits != null) + { + var foundDefault = defaultLimits.FirstOrDefault(x => x.Identifier == identifier); + + if (foundDefault != null) + return foundDefault; + } return new() { diff --git a/Moonlight/Program.cs b/Moonlight/Program.cs index d7629715..cb4fdcf3 100644 --- a/Moonlight/Program.cs +++ b/Moonlight/Program.cs @@ -91,6 +91,7 @@ namespace Moonlight builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); + builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); diff --git a/Moonlight/Shared/Layouts/MainLayout.razor b/Moonlight/Shared/Layouts/MainLayout.razor index b2de0364..f4f29aa4 100644 --- a/Moonlight/Shared/Layouts/MainLayout.razor +++ b/Moonlight/Shared/Layouts/MainLayout.razor @@ -153,7 +153,8 @@ await JsRuntime.InvokeVoidAsync("document.body.removeAttribute", "data-kt-app-page-loading"); await JsRuntime.InvokeVoidAsync("KTMenu.createInstances"); await JsRuntime.InvokeVoidAsync("KTDrawer.createInstances"); - await JsRuntime.InvokeVoidAsync("createSnow"); + + //await JsRuntime.InvokeVoidAsync("createSnow"); await SessionService.Register(); diff --git a/Moonlight/Shared/Views/Servers.razor b/Moonlight/Shared/Views/Servers/Index.razor similarity index 100% rename from Moonlight/Shared/Views/Servers.razor rename to Moonlight/Shared/Views/Servers/Index.razor diff --git a/Moonlight/Shared/Views/Servers/New.razor b/Moonlight/Shared/Views/Servers/New.razor new file mode 100644 index 00000000..5fb01f0e --- /dev/null +++ b/Moonlight/Shared/Views/Servers/New.razor @@ -0,0 +1,174 @@ +@page "/servers/new" +@using Moonlight.App.Services +@using Moonlight.App.Database.Entities +@using Moonlight.App.Models.Forms +@using Moonlight.App.Models.Misc +@using Moonlight.App.Repositories + +@inject SubscriptionService SubscriptionService +@inject ImageRepository ImageRepository +@inject SmartTranslateService SmartTranslateService +@inject SmartDeployService SmartDeployService + + + @if (DeployNode == null) + { +
+
+ Not found image +
+

+ No node found +

+

+ No node found to deploy to found +

+
+
+
+ } + else + { +
+
+
+
+
+

+ Server details +

+
+
+
+
+
+ +
@(DeployNode.Name)
+
+ @if (Model.Image != null) + { + var limit = Images[Model.Image]; + +
+ +
@(Model.Image.Name)
+
+ +
+ +
+ @{ + var cpu = limit.ReadValue("cpu"); + + if (cpu == null) + cpu = "N/A"; + else + cpu = (int.Parse(cpu) / 100).ToString(); + } + @(cpu) Cores +
+
+ +
+ +
@(limit.ReadValue("memory")) MB
+
+ +
+ +
@(limit.ReadValue("disk")) MB
+
+ } +
+
+
+
+
+
+
+
+

+ Configure your server +

+
+
+
+ + +
+ +
+ @if (Images.Any()) + { + + + + + + } + else + { +
+ + You reached the maximum amount of servers for every image of your subscription: @(Subscription == null ? SmartTranslateService.Translate("Default") : Subscription.Name) + +
+ } +
+
+
+
+
+ } +
+ +@code +{ + private Node? DeployNode; + private Subscription? Subscription; + + private Dictionary Images = new(); + + private ServerOrderDataModel Model = new(); + + private async Task Load(LazyLoader lazyLoader) + { + // Reset state + Images.Clear(); + Model = new(); + + await lazyLoader.SetText(SmartTranslateService.Translate("Loading your subscription")); + Subscription = await SubscriptionService.GetCurrent(); + + await lazyLoader.SetText(SmartTranslateService.Translate("Searching for deploy node")); + + DeployNode = await SmartDeployService.GetNode(); + + await lazyLoader.SetText(SmartTranslateService.Translate("Searching for available images")); + + var images = ImageRepository.Get().ToArray(); + + foreach (var image in images) + { + var limit = await SubscriptionService.GetLimit("image." + image.Id); + + if (limit.Amount > 0) + { + Images.Add(image, limit); + } + } + } + + private async Task OnValidSubmit() + { + } +} \ No newline at end of file diff --git a/Moonlight/resources/lang/de_de.lang b/Moonlight/resources/lang/de_de.lang index b56f294a..bcb775a2 100644 --- a/Moonlight/resources/lang/de_de.lang +++ b/Moonlight/resources/lang/de_de.lang @@ -463,3 +463,15 @@ Options;Options Amount;Amount Do you really want to delete it?;Do you really want to delete it? Save subscription;Save subscription +Loading your subscription;Loading your subscription +Searching for deploy node;Searching for deploy node +Searching for available images;Searching for available images +Server details;Server details +Configure your server;Configure your server +Default;Default +No images available;No images available +You reached the maximum amount of servers for every image of your subscription;You reached the maximum amount of servers for every image of your subscription +No node found;No node found +No node found to deploy to found;No node found to deploy to found +You need to specify a server image;You need to specify a server image +CPU;CPU From bb7be3b820bc1ef5f20d51a111f398309064bc79 Mon Sep 17 00:00:00 2001 From: Marcel Baumgartner Date: Tue, 4 Apr 2023 01:23:07 +0200 Subject: [PATCH 03/10] Added subscription ui for user --- .../App/Services/Interop/AlertService.cs | 47 +++++++- .../App/Services/Interop/ClipboardService.cs | 5 + Moonlight/App/Services/SubscriptionService.cs | 62 ++++------ .../Views/Admin/Subscriptions/Index.razor | 35 +++++- .../Shared/Views/Profile/Subscriptions.razor | 112 ++++++++++++++++++ .../Views/Servers/{New.razor => Create.razor} | 56 ++++++++- Moonlight/resources/lang/de_de.lang | 16 +++ .../wwwroot/assets/media/svg/subscription.svg | 38 ++++++ 8 files changed, 329 insertions(+), 42 deletions(-) create mode 100644 Moonlight/Shared/Views/Profile/Subscriptions.razor rename Moonlight/Shared/Views/Servers/{New.razor => Create.razor} (78%) create mode 100644 Moonlight/wwwroot/assets/media/svg/subscription.svg diff --git a/Moonlight/App/Services/Interop/AlertService.cs b/Moonlight/App/Services/Interop/AlertService.cs index d03d4ef9..7e6bcb25 100644 --- a/Moonlight/App/Services/Interop/AlertService.cs +++ b/Moonlight/App/Services/Interop/AlertService.cs @@ -5,10 +5,12 @@ namespace Moonlight.App.Services.Interop; public class AlertService { private readonly SweetAlertService SweetAlertService; + private readonly SmartTranslateService SmartTranslateService; - public AlertService(SweetAlertService service) + public AlertService(SweetAlertService service, SmartTranslateService smartTranslateService) { SweetAlertService = service; + SmartTranslateService = smartTranslateService; } public async Task Info(string title, string desciption) @@ -21,6 +23,11 @@ public class AlertService }); } + public async Task Info(string desciption) + { + await Info("", desciption); + } + public async Task Success(string title, string desciption) { await SweetAlertService.FireAsync(new SweetAlertOptions() @@ -31,6 +38,11 @@ public class AlertService }); } + public async Task Success(string desciption) + { + await Success("", desciption); + } + public async Task Warning(string title, string desciption) { await SweetAlertService.FireAsync(new SweetAlertOptions() @@ -41,6 +53,11 @@ public class AlertService }); } + public async Task Warning(string desciption) + { + await Warning("", desciption); + } + public async Task Error(string title, string desciption) { await SweetAlertService.FireAsync(new SweetAlertOptions() @@ -51,6 +68,11 @@ public class AlertService }); } + public async Task Error(string desciption) + { + await Error("", desciption); + } + public async Task YesNo(string title, string desciption, string yesText, string noText) { var result = await SweetAlertService.FireAsync(new SweetAlertOptions() @@ -79,4 +101,27 @@ public class AlertService return result.Value; } + + public async Task ConfirmMath() + { + var r = new Random(); + var i1 = r.Next(5, 15); + var i2 = r.Next(5, 15); + + var input = await Text( + SmartTranslateService.Translate("Confirm"), + SmartTranslateService.Translate($"{i1} + {i2} ="), + "" + ); + + if (int.TryParse(input, out int i)) + { + if (i == i1 + i2) + { + return true; + } + } + + return false; + } } \ No newline at end of file diff --git a/Moonlight/App/Services/Interop/ClipboardService.cs b/Moonlight/App/Services/Interop/ClipboardService.cs index 79fa4202..a7c806c9 100644 --- a/Moonlight/App/Services/Interop/ClipboardService.cs +++ b/Moonlight/App/Services/Interop/ClipboardService.cs @@ -15,4 +15,9 @@ public class ClipboardService { await JsRuntime.InvokeVoidAsync("copyTextToClipboard", data); } + public async Task Copy(string data) + { + await JsRuntime.InvokeVoidAsync("copyTextToClipboard", data); + } + } \ No newline at end of file diff --git a/Moonlight/App/Services/SubscriptionService.cs b/Moonlight/App/Services/SubscriptionService.cs index 9d35fe4b..de23692a 100644 --- a/Moonlight/App/Services/SubscriptionService.cs +++ b/Moonlight/App/Services/SubscriptionService.cs @@ -78,55 +78,45 @@ public class SubscriptionService await OneTimeJwtService.Revoke(code); } + public async Task Cancel() + { + if (await GetCurrent() != null) + { + var user = await GetCurrentUser(); + + user.CurrentSubscription = null; + + UserRepository.Update(user); + } + } + public async Task GetLimit(string identifier) { - var configSection = ConfigService.GetSection("Moonlight").GetSection("Subscriptions"); - - var defaultLimits = configSection.GetValue("DefaultLimits"); - var subscription = await GetCurrent(); if (subscription == null) { - if (defaultLimits != null) - { - var foundDefault = defaultLimits.FirstOrDefault(x => x.Identifier == identifier); - - if (foundDefault != null) - return foundDefault; - } - return new() { Identifier = identifier, Amount = 0 }; } - else + + var subscriptionLimits = + JsonConvert.DeserializeObject(subscription.LimitsJson) + ?? Array.Empty(); + + var foundLimit = subscriptionLimits.FirstOrDefault(x => x.Identifier == identifier); + + if (foundLimit != null) + return foundLimit; + + return new() { - var subscriptionLimits = - JsonConvert.DeserializeObject(subscription.LimitsJson) - ?? Array.Empty(); - - var foundLimit = subscriptionLimits.FirstOrDefault(x => x.Identifier == identifier); - - if (foundLimit != null) - return foundLimit; - - if (defaultLimits != null) - { - var foundDefault = defaultLimits.FirstOrDefault(x => x.Identifier == identifier); - - if (foundDefault != null) - return foundDefault; - } - - return new() - { - Identifier = identifier, - Amount = 0 - }; - } + Identifier = identifier, + Amount = 0 + }; } private async Task GetCurrentUser() diff --git a/Moonlight/Shared/Views/Admin/Subscriptions/Index.razor b/Moonlight/Shared/Views/Admin/Subscriptions/Index.razor index 83c20654..e7182f6a 100644 --- a/Moonlight/Shared/Views/Admin/Subscriptions/Index.razor +++ b/Moonlight/Shared/Views/Admin/Subscriptions/Index.razor @@ -3,10 +3,15 @@ @using Moonlight.App.Database.Entities @using Moonlight.App.Repositories @using BlazorTable +@using Moonlight.App.Services.Interop @inject SmartTranslateService SmartTranslateService @inject SubscriptionRepository SubscriptionRepository +@inject SubscriptionAdminService SubscriptionAdminService +@inject AlertService AlertService +@inject ClipboardService ClipboardService +
@@ -36,9 +41,16 @@ - + @@ -66,7 +78,24 @@ private async Task Delete(Subscription subscription) { SubscriptionRepository.Delete(subscription); - + await LazyLoader.Reload(); } + + private async Task GenerateCode(Subscription subscription) + { + var durationText = await AlertService.Text( + SmartTranslateService.Translate("Duration"), + SmartTranslateService.Translate("Enter duration of subscription"), + "30" + ); + + if (int.TryParse(durationText, out int duration)) + { + var code = await SubscriptionAdminService.GenerateCode(subscription, duration); + + await ClipboardService.Copy(code); + await AlertService.Success(SmartTranslateService.Translate("Copied code to clipboard")); + } + } } \ No newline at end of file diff --git a/Moonlight/Shared/Views/Profile/Subscriptions.razor b/Moonlight/Shared/Views/Profile/Subscriptions.razor new file mode 100644 index 00000000..c8382775 --- /dev/null +++ b/Moonlight/Shared/Views/Profile/Subscriptions.razor @@ -0,0 +1,112 @@ +@page "/profile/subscriptions" + +@using Moonlight.Shared.Components.Navigations +@using Moonlight.App.Services +@using Moonlight.App.Database.Entities +@using Moonlight.App.Helpers +@using Moonlight.App.Services.Interop + +@inject ConfigService ConfigService +@inject AlertService AlertService +@inject SubscriptionService SubscriptionService +@inject SmartTranslateService SmartTranslateService + + + +
+
+
+ Subscription +
+
+
+ + @if (Subscription == null) + { + var config = ConfigService + .GetSection("Moonlight") + .GetSection("Subscriptions") + .GetSection("Sellpass"); + + var enableSellpass = config.GetValue("Enable"); + var url = config.GetValue("Url"); + +

+
+ + + +
+

+ + if (enableSellpass) + { + + } + } + else + { + var d = User.SubscriptionSince.AddDays(User.SubscriptionDuration).ToUniversalTime(); + +

+ Active until @(Formatter.FormatDateOnly(d)) +

+

+ Current subscription: @(Subscription.Name) +

+

+ @(Subscription.Description) +

+

+ We will send you a notification upon subscription expiration +

+
+ + +
+ } +
+
+
+
+
+ +@code +{ + [CascadingParameter] + public User User { get; set; } + + private Subscription? Subscription; + private LazyLoader LazyLoader; + + private string Code = ""; + + private async Task Load(LazyLoader arg) + { + Subscription = await SubscriptionService.GetCurrent(); + } + + private async Task Cancel() + { + if (await AlertService.ConfirmMath()) + { + await SubscriptionService.Cancel(); + await LazyLoader.Reload(); + } + } + + private async Task OnSubmit() + { + await SubscriptionService.ApplyCode(Code); + Code = ""; + await LazyLoader.Reload(); + } +} \ No newline at end of file diff --git a/Moonlight/Shared/Views/Servers/New.razor b/Moonlight/Shared/Views/Servers/Create.razor similarity index 78% rename from Moonlight/Shared/Views/Servers/New.razor rename to Moonlight/Shared/Views/Servers/Create.razor index 5fb01f0e..85ec9d91 100644 --- a/Moonlight/Shared/Views/Servers/New.razor +++ b/Moonlight/Shared/Views/Servers/Create.razor @@ -1,14 +1,20 @@ -@page "/servers/new" +@page "/servers/create" @using Moonlight.App.Services @using Moonlight.App.Database.Entities @using Moonlight.App.Models.Forms @using Moonlight.App.Models.Misc @using Moonlight.App.Repositories +@using Moonlight.App.Repositories.Servers +@using Microsoft.EntityFrameworkCore +@using Moonlight.App.Exceptions @inject SubscriptionService SubscriptionService @inject ImageRepository ImageRepository @inject SmartTranslateService SmartTranslateService @inject SmartDeployService SmartDeployService +@inject ServerRepository ServerRepository +@inject NavigationManager NavigationManager +@inject ServerService ServerService @if (DeployNode == null) @@ -133,6 +139,9 @@ @code { + [CascadingParameter] + public User User { get; set; } + private Node? DeployNode; private Subscription? Subscription; @@ -163,12 +172,55 @@ if (limit.Amount > 0) { - Images.Add(image, limit); + var serversCount = ServerRepository + .Get() + .Include(x => x.Owner) + .Include(x => x.Image) + .Where(x => x.Owner.Id == User.Id) + .Count(x => x.Image.Id == image.Id); + + if(serversCount < limit.Amount) + Images.Add(image, limit); } } } private async Task OnValidSubmit() { + var limit = await SubscriptionService.GetLimit("image." + Model.Image.Id); + + if (limit.Amount > 0) + { + var serversCount = ServerRepository + .Get() + .Include(x => x.Owner) + .Include(x => x.Image) + .Where(x => x.Owner.Id == User.Id) + .Count(x => x.Image.Id == Model.Image.Id); + + if (serversCount < limit.Amount) + { + if(int.TryParse(limit.ReadValue("cpu"), out int cpu) && + int.TryParse(limit.ReadValue("memory"), out int memory) && + int.TryParse(limit.ReadValue("disk"), out int disk)) + { + var server = await ServerService.Create( + Model.Name, + cpu, + memory, + disk, + User, + Model.Image, + DeployNode + ); + + NavigationManager.NavigateTo($"/server/{server.Uuid}"); + } + else + { + throw new DisplayException("Limits cannot be parsed"); + } + } + } } } \ No newline at end of file diff --git a/Moonlight/resources/lang/de_de.lang b/Moonlight/resources/lang/de_de.lang index bcb775a2..23a0c02f 100644 --- a/Moonlight/resources/lang/de_de.lang +++ b/Moonlight/resources/lang/de_de.lang @@ -475,3 +475,19 @@ No node found;No node found No node found to deploy to found;No node found to deploy to found You need to specify a server image;You need to specify a server image CPU;CPU +Compress;Compress +Decompress;Decompress +Cleanup exception;Cleanup exception +Error creating server on wings;Error creating server on wings +Enter code;Enter code +Create code;Create code +Duration;Duration +Enter duration of subscription;Enter duration of subscription +Copied code to clipboard;Copied code to clipboard +Current subscription;Current subscription +7 + 7 =;7 + 7 = +1 + 8 =;1 + 8 = +8 + 4 =;8 + 4 = +8 + 1 =;8 + 1 = +1 + 1 =;1 + 1 = +6 + 6 =;6 + 6 = diff --git a/Moonlight/wwwroot/assets/media/svg/subscription.svg b/Moonlight/wwwroot/assets/media/svg/subscription.svg new file mode 100644 index 00000000..6022690d --- /dev/null +++ b/Moonlight/wwwroot/assets/media/svg/subscription.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 52bd991a72a72fcbb9342685a509879a16d2bff7 Mon Sep 17 00:00:00 2001 From: Marcel Baumgartner Date: Tue, 4 Apr 2023 01:24:15 +0200 Subject: [PATCH 04/10] Update AlertService.cs --- Moonlight/App/Services/Interop/AlertService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moonlight/App/Services/Interop/AlertService.cs b/Moonlight/App/Services/Interop/AlertService.cs index 7e6bcb25..24a15fa4 100644 --- a/Moonlight/App/Services/Interop/AlertService.cs +++ b/Moonlight/App/Services/Interop/AlertService.cs @@ -110,7 +110,7 @@ public class AlertService var input = await Text( SmartTranslateService.Translate("Confirm"), - SmartTranslateService.Translate($"{i1} + {i2} ="), + $"{i1} + {i2} =", "" ); From 1a39faff9e80ff8e405256dcf5f69ab9fe44092f Mon Sep 17 00:00:00 2001 From: Marcel Baumgartner Date: Tue, 4 Apr 2023 01:29:11 +0200 Subject: [PATCH 05/10] Update de_de.lang --- Moonlight/resources/lang/de_de.lang | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Moonlight/resources/lang/de_de.lang b/Moonlight/resources/lang/de_de.lang index c60df72b..106c3ea6 100644 --- a/Moonlight/resources/lang/de_de.lang +++ b/Moonlight/resources/lang/de_de.lang @@ -461,4 +461,13 @@ Add new limit;Add new limit Create subscription;Create subscription Options;Options Amount;Amount -Do you really want to delete it?;Do you really want to delete it? \ No newline at end of file +Do you really want to delete it?;Do you really want to delete it? +Loading your subscription;Loading your subscription +Searching for deploy node;Searching for deploy node +Searching for available images;Searching for available images +Server details;Server details +Configure your server;Configure your server +Default;Default +You reached the maximum amount of servers for every image of your subscription;You reached the maximum amount of servers for every image of your subscription +Personal information;Personal information +Enter code;Enter code From ef58478232856ec47847ee872ae71ed3cd18373b Mon Sep 17 00:00:00 2001 From: Marcel Baumgartner Date: Tue, 4 Apr 2023 01:54:06 +0200 Subject: [PATCH 06/10] Added server rename setting --- .../App/Models/Forms/ServerRenameDataModel.cs | 10 +++++ .../ServerControl/ServerSettings.razor | 2 + .../Settings/ServerRenameSetting.razor | 41 +++++++++++++++++++ Moonlight/Shared/Views/Servers/Create.razor | 2 +- Moonlight/resources/lang/de_de.lang | 3 ++ 5 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 Moonlight/App/Models/Forms/ServerRenameDataModel.cs create mode 100644 Moonlight/Shared/Components/ServerControl/Settings/ServerRenameSetting.razor diff --git a/Moonlight/App/Models/Forms/ServerRenameDataModel.cs b/Moonlight/App/Models/Forms/ServerRenameDataModel.cs new file mode 100644 index 00000000..619ee328 --- /dev/null +++ b/Moonlight/App/Models/Forms/ServerRenameDataModel.cs @@ -0,0 +1,10 @@ +using System.ComponentModel.DataAnnotations; + +namespace Moonlight.App.Models.Forms; + +public class ServerRenameDataModel +{ + [Required(ErrorMessage = "You need to enter a name")] + [MaxLength(32, ErrorMessage = "The name cannot be longer that 32 characters")] + public string Name { get; set; } +} \ No newline at end of file diff --git a/Moonlight/Shared/Components/ServerControl/ServerSettings.razor b/Moonlight/Shared/Components/ServerControl/ServerSettings.razor index 280936c6..ed01706a 100644 --- a/Moonlight/Shared/Components/ServerControl/ServerSettings.razor +++ b/Moonlight/Shared/Components/ServerControl/ServerSettings.razor @@ -53,6 +53,8 @@ if(Tags.Contains("pythonfile")) Settings.Add("Python file", typeof(PythonFileSetting)); + Settings.Add("Server rename", typeof(ServerRenameSetting)); + Settings.Add("Server reset", typeof(ServerResetSetting)); return Task.CompletedTask; diff --git a/Moonlight/Shared/Components/ServerControl/Settings/ServerRenameSetting.razor b/Moonlight/Shared/Components/ServerControl/Settings/ServerRenameSetting.razor new file mode 100644 index 00000000..2c8185d4 --- /dev/null +++ b/Moonlight/Shared/Components/ServerControl/Settings/ServerRenameSetting.razor @@ -0,0 +1,41 @@ +@using Moonlight.App.Repositories.Servers +@using Moonlight.App.Database.Entities +@using Moonlight.App.Models.Forms + +@inject ServerRepository ServerRepository + +
+ + +
+ + +
+
+
+
+ +@code +{ + [CascadingParameter] + public Server CurrentServer { get; set; } + + private ServerRenameDataModel Model = new(); + private LazyLoader LazyLoader; + + private Task Load(LazyLoader arg) + { + Model.Name = CurrentServer.Name; + + return Task.CompletedTask; + } + + private async Task Rename() + { + CurrentServer.Name = Model.Name; + + ServerRepository.Update(CurrentServer); + + await LazyLoader.Reload(); + } +} \ No newline at end of file diff --git a/Moonlight/Shared/Views/Servers/Create.razor b/Moonlight/Shared/Views/Servers/Create.razor index 85ec9d91..90003403 100644 --- a/Moonlight/Shared/Views/Servers/Create.razor +++ b/Moonlight/Shared/Views/Servers/Create.razor @@ -179,7 +179,7 @@ .Where(x => x.Owner.Id == User.Id) .Count(x => x.Image.Id == image.Id); - if(serversCount < limit.Amount) + if(serversCount <= limit.Amount) Images.Add(image, limit); } } diff --git a/Moonlight/resources/lang/de_de.lang b/Moonlight/resources/lang/de_de.lang index 106c3ea6..047455cc 100644 --- a/Moonlight/resources/lang/de_de.lang +++ b/Moonlight/resources/lang/de_de.lang @@ -471,3 +471,6 @@ Default;Default You reached the maximum amount of servers for every image of your subscription;You reached the maximum amount of servers for every image of your subscription Personal information;Personal information Enter code;Enter code +Server rename;Server rename +Create code;Create code +Save subscription;Save subscription From 217de0cd3fc4be7894a4f13a30f33779e95baeac Mon Sep 17 00:00:00 2001 From: Marcel Baumgartner Date: Tue, 4 Apr 2023 02:01:37 +0200 Subject: [PATCH 07/10] Nothing important --- Moonlight/Shared/Views/Servers/Create.razor | 2 +- Moonlight/resources/lang/de_de.lang | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Moonlight/Shared/Views/Servers/Create.razor b/Moonlight/Shared/Views/Servers/Create.razor index 90003403..de782e1d 100644 --- a/Moonlight/Shared/Views/Servers/Create.razor +++ b/Moonlight/Shared/Views/Servers/Create.razor @@ -179,7 +179,7 @@ .Where(x => x.Owner.Id == User.Id) .Count(x => x.Image.Id == image.Id); - if(serversCount <= limit.Amount) + if(serversCount <= limit.Amount) //TODO: FIX COUNTING Images.Add(image, limit); } } diff --git a/Moonlight/resources/lang/de_de.lang b/Moonlight/resources/lang/de_de.lang index 047455cc..8e6714e3 100644 --- a/Moonlight/resources/lang/de_de.lang +++ b/Moonlight/resources/lang/de_de.lang @@ -474,3 +474,7 @@ Enter code;Enter code Server rename;Server rename Create code;Create code Save subscription;Save subscription +Enter your information;Enter your information +You need to enter your full name in order to use moonlight;You need to enter your full name in order to use moonlight +No node found;No node found +No node found to deploy to found;No node found to deploy to found From 888fd556a7c163d02fd7c105dc9b8ed2e1aeaae2 Mon Sep 17 00:00:00 2001 From: Marcel Baumgartner Date: Tue, 4 Apr 2023 16:04:58 +0200 Subject: [PATCH 08/10] Added server delete. Tweaked setting names --- Moonlight/App/Services/ServerService.cs | 36 ++++++++++++------- .../ServerControl/ServerSettings.razor | 9 ++--- .../Settings/ServerDeleteSetting.razor | 29 +++++++++++++++ .../Shared/Views/Admin/Servers/Edit.razor | 4 ++- 4 files changed, 61 insertions(+), 17 deletions(-) create mode 100644 Moonlight/Shared/Components/ServerControl/Settings/ServerDeleteSetting.razor diff --git a/Moonlight/App/Services/ServerService.cs b/Moonlight/App/Services/ServerService.cs index 7969bd78..8ec47c9f 100644 --- a/Moonlight/App/Services/ServerService.cs +++ b/Moonlight/App/Services/ServerService.cs @@ -1,11 +1,9 @@ -using Logging.Net; -using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; using Moonlight.App.Database; using Moonlight.App.Database.Entities; using Moonlight.App.Exceptions; using Moonlight.App.Helpers; -using Moonlight.App.Models.Files; -using Moonlight.App.Models.Files.Accesses; +using Moonlight.App.Helpers.Files; using Moonlight.App.Models.Misc; using Moonlight.App.Models.Wings; using Moonlight.App.Models.Wings.Requests; @@ -13,6 +11,7 @@ using Moonlight.App.Models.Wings.Resources; using Moonlight.App.Repositories; using Moonlight.App.Repositories.Servers; using Moonlight.App.Services.LogServices; +using FileAccess = Moonlight.App.Helpers.Files.FileAccess; namespace Moonlight.App.Services; @@ -30,7 +29,6 @@ public class ServerService private readonly SecurityLogService SecurityLogService; private readonly AuditLogService AuditLogService; private readonly ErrorLogService ErrorLogService; - private readonly string AppUrl; public ServerService( ServerRepository serverRepository, @@ -58,8 +56,6 @@ public class ServerService SecurityLogService = securityLogService; AuditLogService = auditLogService; ErrorLogService = errorLogService; - - AppUrl = ConfigService.GetSection("Moonlight").GetValue("AppUrl"); } private Server EnsureNodeData(Server s) @@ -225,17 +221,17 @@ public class ServerService return $"https://{server.Node.Fqdn}:{server.Node.HttpPort}/download/backup?token={token}"; } - public Task CreateFileAccess(Server s, User user) // We need the user to create the launch url + public Task CreateFileAccess(Server s, User user) // We need the user to create the launch url { Server server = EnsureNodeData(s); return Task.FromResult( - (IFileAccess)new WingsFileAccess( + (FileAccess)new WingsFileAccess( WingsApiHelper, - server, - user, WingsJwtHelper, - AppUrl + server, + ConfigService, + user ) ); } @@ -383,4 +379,20 @@ public class ServerService throw new Exception("User and owner id do not match"); } } + + public async Task Sync(Server s) + { + var server = EnsureNodeData(s); + + await WingsApiHelper.Post(server.Node, $"api/servers/{server.Uuid}/sync", null); + } + + public async Task Delete(Server s) + { + var server = EnsureNodeData(s); + + await WingsApiHelper.Delete(server.Node, $"api/servers/{server.Uuid}", null); + + ServerRepository.Delete(s); + } } \ No newline at end of file diff --git a/Moonlight/Shared/Components/ServerControl/ServerSettings.razor b/Moonlight/Shared/Components/ServerControl/ServerSettings.razor index ed01706a..cd17ceed 100644 --- a/Moonlight/Shared/Components/ServerControl/ServerSettings.razor +++ b/Moonlight/Shared/Components/ServerControl/ServerSettings.razor @@ -1,5 +1,4 @@ -@using PteroConsole.NET -@using Moonlight.App.Database.Entities +@using Moonlight.App.Database.Entities @using Moonlight.Shared.Components.ServerControl.Settings @using Microsoft.AspNetCore.Components.Rendering @@ -53,9 +52,11 @@ if(Tags.Contains("pythonfile")) Settings.Add("Python file", typeof(PythonFileSetting)); - Settings.Add("Server rename", typeof(ServerRenameSetting)); + Settings.Add("Rename", typeof(ServerRenameSetting)); - Settings.Add("Server reset", typeof(ServerResetSetting)); + Settings.Add("Reset", typeof(ServerResetSetting)); + + Settings.Add("Delete", typeof(ServerDeleteSetting)); return Task.CompletedTask; } diff --git a/Moonlight/Shared/Components/ServerControl/Settings/ServerDeleteSetting.razor b/Moonlight/Shared/Components/ServerControl/Settings/ServerDeleteSetting.razor new file mode 100644 index 00000000..aeb8bd69 --- /dev/null +++ b/Moonlight/Shared/Components/ServerControl/Settings/ServerDeleteSetting.razor @@ -0,0 +1,29 @@ +@using Moonlight.App.Database.Entities +@using Moonlight.App.Services +@using Moonlight.App.Services.Interop + +@inject SmartTranslateService SmartTranslateService +@inject AlertService AlertService +@inject NavigationManager NavigationManager +@inject ServerService ServerService + + + + +@code +{ + [CascadingParameter] + public Server CurrentServer { get; set; } + + private async Task OnClick() + { + if (await AlertService.ConfirmMath()) + { + await ServerService.Delete(CurrentServer); + NavigationManager.NavigateTo("/servers", true); + } + } +} \ No newline at end of file diff --git a/Moonlight/Shared/Views/Admin/Servers/Edit.razor b/Moonlight/Shared/Views/Admin/Servers/Edit.razor index b3fc0b9a..95020ed6 100644 --- a/Moonlight/Shared/Views/Admin/Servers/Edit.razor +++ b/Moonlight/Shared/Views/Admin/Servers/Edit.razor @@ -8,6 +8,7 @@ @inject SmartTranslateService SmartTranslateService @inject ServerRepository ServerRepository +@inject ServerService ServerService @inject ImageRepository ImageRepository @@ -197,7 +198,8 @@ private async Task Save() { - ServerRepository.Update(Server); + ServerRepository.Update(Server!); + //await ServerService.Sync(Server!); I dont know if we need this, because wings should resync the data while restarting anyway await LazyLoader.Reload(); } From 29874a22bddf634fe3cbab186bb98a77c8f08413 Mon Sep 17 00:00:00 2001 From: Marcel Baumgartner Date: Tue, 4 Apr 2023 16:27:54 +0200 Subject: [PATCH 09/10] Added server node status screen check thingy --- Moonlight/Shared/Views/Server/Index.razor | 246 ++++++++++-------- Moonlight/resources/lang/de_de.lang | 4 + .../wwwroot/assets/media/svg/serverdown.svg | 1 + 3 files changed, 147 insertions(+), 104 deletions(-) create mode 100644 Moonlight/wwwroot/assets/media/svg/serverdown.svg diff --git a/Moonlight/Shared/Views/Server/Index.razor b/Moonlight/Shared/Views/Server/Index.razor index a6a6567d..eccbd3f9 100644 --- a/Moonlight/Shared/Views/Server/Index.razor +++ b/Moonlight/Shared/Views/Server/Index.razor @@ -17,6 +17,7 @@ @inject ServerRepository ServerRepository @inject WingsConsoleHelper WingsConsoleHelper @inject MessageService MessageService +@inject NodeService NodeService @inject NavigationManager NavigationManager @implements IDisposable @@ -26,10 +27,12 @@ {
- Not found image + Not found image
-

Server not found

-

+

+ Server not found +

+

A server with that id cannot be found or you have no access for this server

@@ -38,107 +41,126 @@ } else { - if (Console.ConnectionState == ConnectionState.Connected) + if (NodeOnline) { - if (Console.ServerState == ServerState.Installing) + if (Console.ConnectionState == ConnectionState.Connected) { -
-
-
-
- - Server installation is currently running - + if (Console.ServerState == ServerState.Installing) + { +
+
+
+
+ + Server installation is currently running + +
+
-
-
- } - else if (CurrentServer.Installing) - { -
-
-
-
- - Server installation is currently running - + } + else if (CurrentServer.Installing) + { +
+
+
+
+ + Server installation is currently running + +
+
-
-
- } - else - { - - - - - - - @{ - var index = 0; + } + else + { + + + + + + + @{ + var index = 0; - switch (Route) - { - case "files": - index = 1; - break; - case "backups": - index = 2; - break; - case "network": - index = 3; - break; - case "addons": - index = 4; - break; - case "settings": - index = 5; - break; - default: - index = 0; - break; + switch (Route) + { + case "files": + index = 1; + break; + case "backups": + index = 2; + break; + case "network": + index = 3; + break; + case "addons": + index = 4; + break; + case "settings": + index = 5; + break; + default: + index = 0; + break; + } } - } - - @switch (Route) - { - case "files": - - break; - case "backups": - - break; - case "network": - - break; - case "addons": - - break; - case "settings": - - break; - default: - - break; - } - + + @switch (Route) + { + case "files": + + break; + case "backups": + + break; + case "network": + + break; + case "addons": + + break; + case "settings": + + break; + default: + + break; + } + + - + } + } + else + { +
+ Connecting +
} } else { -
- Connecting +
+
+ Not found image +
+

+ Node offline +

+

+ The node the server is running on is currently offline +

+
+
} } @@ -149,7 +171,7 @@ [Parameter] public string ServerUuid { get; set; } - + [CascadingParameter] public User User { get; set; } @@ -159,6 +181,7 @@ private PteroConsole? Console; private Server? CurrentServer; private Node Node; + private bool NodeOnline = false; private Image Image; private NodeAllocation NodeAllocation; private string[] Tags; @@ -205,7 +228,7 @@ .Include(x => x.Owner) .First(x => x.Uuid == uuid); - if (CurrentServer.Owner.Id != User!.Id && User.Admin) + if (CurrentServer.Owner.Id != User!.Id && !User.Admin) CurrentServer = null; } catch (Exception) @@ -215,28 +238,43 @@ if (CurrentServer != null) { - await lazyLoader.SetText("Requesting tags"); + await lazyLoader.SetText("Checking node online status"); - var image = ImageRepository - .Get() - .First(x => x.Id == CurrentServer.Image.Id); - - Tags = JsonConvert.DeserializeObject(image.TagsJson) ?? Array.Empty(); - Image = image; - - await lazyLoader.SetText("Connecting to console"); - - await WingsConsoleHelper.ConnectWings(Console!, CurrentServer); - - MessageService.Subscribe($"server.{CurrentServer.Uuid}.installcomplete", this, server => + try { - Task.Run(() => + //TODO: Implement status caching + var data = await NodeService.GetStatus(CurrentServer.Node); + + if (data != null) + NodeOnline = true; + } + catch (Exception) + { + // ignored + } + + if (NodeOnline) + { + await lazyLoader.SetText("Requesting tags"); + + var image = ImageRepository + .Get() + .First(x => x.Id == CurrentServer.Image.Id); + + Tags = JsonConvert.DeserializeObject(image.TagsJson) ?? Array.Empty(); + Image = image; + + await lazyLoader.SetText("Connecting to console"); + + await WingsConsoleHelper.ConnectWings(Console!, CurrentServer); + + MessageService.Subscribe($"server.{CurrentServer.Uuid}.installcomplete", this, server => { - NavigationManager.NavigateTo(NavigationManager.Uri); + Task.Run(() => { NavigationManager.NavigateTo(NavigationManager.Uri); }); + + return Task.CompletedTask; }); - - return Task.CompletedTask; - }); + } } else { diff --git a/Moonlight/resources/lang/de_de.lang b/Moonlight/resources/lang/de_de.lang index 8e6714e3..429e88a1 100644 --- a/Moonlight/resources/lang/de_de.lang +++ b/Moonlight/resources/lang/de_de.lang @@ -478,3 +478,7 @@ Enter your information;Enter your information You need to enter your full name in order to use moonlight;You need to enter your full name in order to use moonlight No node found;No node found No node found to deploy to found;No node found to deploy to found +Node offline;Node offline +The node the server is running on is currently offline;The node the server is running on is currently offline +Server not found;Server not found +A server with that id cannot be found or you have no access for this server;A server with that id cannot be found or you have no access for this server diff --git a/Moonlight/wwwroot/assets/media/svg/serverdown.svg b/Moonlight/wwwroot/assets/media/svg/serverdown.svg new file mode 100644 index 00000000..ca37dc52 --- /dev/null +++ b/Moonlight/wwwroot/assets/media/svg/serverdown.svg @@ -0,0 +1 @@ +server down \ No newline at end of file From a80807f2464cf8ab85e2c268413d6ab7f4efc4e5 Mon Sep 17 00:00:00 2001 From: Marcel Baumgartner Date: Tue, 4 Apr 2023 16:31:09 +0200 Subject: [PATCH 10/10] Update CacheLogger.cs --- Moonlight/App/Helpers/CacheLogger.cs | 45 ++++++++++++++++++---------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/Moonlight/App/Helpers/CacheLogger.cs b/Moonlight/App/Helpers/CacheLogger.cs index b8feb5ad..ef9e0c37 100644 --- a/Moonlight/App/Helpers/CacheLogger.cs +++ b/Moonlight/App/Helpers/CacheLogger.cs @@ -29,8 +29,11 @@ public class CacheLogger : ILogger } } - public void Info(string s) + public void Info(string? s) { + if (s == null) + return; + lock (Messages) { Messages.Add(new() @@ -39,12 +42,15 @@ public class CacheLogger : ILogger Message = s }); } - + SbLogger.Info(s); } - public void Debug(string s) + public void Debug(string? s) { + if (s == null) + return; + lock (Messages) { Messages.Add(new() @@ -53,12 +59,15 @@ public class CacheLogger : ILogger Message = s }); } - + SbLogger.Debug(s); } - public void Warn(string s) + public void Warn(string? s) { + if (s == null) + return; + lock (Messages) { Messages.Add(new() @@ -67,12 +76,15 @@ public class CacheLogger : ILogger Message = s }); } - + SbLogger.Warn(s); } - public void Error(string s) + public void Error(string? s) { + if (s == null) + return; + lock (Messages) { Messages.Add(new() @@ -81,12 +93,15 @@ public class CacheLogger : ILogger Message = s }); } - + SbLogger.Error(s); } - public void Fatal(string s) + public void Fatal(string? s) { + if (s == null) + return; + lock (Messages) { Messages.Add(new() @@ -95,7 +110,7 @@ public class CacheLogger : ILogger Message = s }); } - + SbLogger.Fatal(s); } @@ -109,7 +124,7 @@ public class CacheLogger : ILogger Message = ex.ToStringDemystified() }); } - + SbLogger.InfoEx(ex); } @@ -123,7 +138,7 @@ public class CacheLogger : ILogger Message = ex.ToStringDemystified() }); } - + SbLogger.DebugEx(ex); } @@ -137,7 +152,7 @@ public class CacheLogger : ILogger Message = ex.ToStringDemystified() }); } - + SbLogger.WarnEx(ex); } @@ -151,7 +166,7 @@ public class CacheLogger : ILogger Message = ex.ToStringDemystified() }); } - + SbLogger.ErrorEx(ex); } @@ -165,7 +180,7 @@ public class CacheLogger : ILogger Message = ex.ToStringDemystified() }); } - + SbLogger.FatalEx(ex); }