diff --git a/Bot/.editorconfig b/Bot/.editorconfig index 619e4ba..77f6ff5 100644 --- a/Bot/.editorconfig +++ b/Bot/.editorconfig @@ -34,6 +34,7 @@ dotnet_diagnostic.CA1852.severity = suggestion # ReSharper resharper_function_never_returns_highlighting = none resharper_arrange_object_creation_when_type_not_evident_highlighting = none +resharper_unused_type_global_highlighting = none # New line preferences csharp_new_line_before_open_brace = all diff --git a/Bot/Clash/Coc.cs b/Bot/Clash/Coc.cs index 399240d..a008a2d 100644 --- a/Bot/Clash/Coc.cs +++ b/Bot/Clash/Coc.cs @@ -178,7 +178,14 @@ internal static async Task BotReadyAsync() _ = Task.Run(Donate25.CheckAsync); while (true) { - await PollAsync(); + try + { + await PollAsync(); + } + catch (Exception ex) + { + await Dc.ExceptionAsync(ex); + } await Task.Delay(20000); } } diff --git a/Bot/Clash/Donate25.cs b/Bot/Clash/Donate25.cs index 95512db..953b8a8 100644 --- a/Bot/Clash/Donate25.cs +++ b/Bot/Clash/Donate25.cs @@ -3,12 +3,12 @@ namespace Hyperstellar.Clash; -internal sealed class Donate25 +internal static class Donate25 { private sealed class Node(long time) { internal long _checkTime = time; - internal ICollection _ids = []; + internal readonly ICollection _ids = []; } private const int TargetPerPerson = 25; // The donation target per week per person @@ -46,41 +46,35 @@ internal static void Init() internal static void AltAdded(string altId, string mainId) { Console.WriteLine($"[Donate25] Removing {altId} -> {mainId} (addalt)"); - foreach (Node node in s_queue) + Node? node = s_queue.FirstOrDefault(n => n._ids.Remove(altId)); + if (node != null) { - if (node._ids.Remove(altId)) - { - Console.WriteLine($"[Donate25] Removed {altId} in {node._checkTime}"); - node._ids.Add(mainId); - Donation altDon = Db.GetDonation(altId)!; - Donation mainDon = Db.GetDonation(mainId)!; - altDon.Delete(); - mainDon.Donated += altDon.Donated; - mainDon.Update(); - Console.WriteLine($"[Donate25] Added {mainId} because it replaced {altId} as main"); - break; - } + Console.WriteLine($"[Donate25] Removed {altId} in {node._checkTime}"); + node._ids.Add(mainId); + Donation altDon = Db.GetDonation(altId)!; + Donation mainDon = Db.GetDonation(mainId)!; + altDon.Delete(); + mainDon.Donated += altDon.Donated; + mainDon.Update(); + Console.WriteLine($"[Donate25] Added {mainId} because it replaced {altId} as main"); } } internal static void MemberRemoved(string id, string? newMainId) { Console.WriteLine($"[Donate25] Removing {id} -> {newMainId}"); - foreach (Node node in s_queue) + Node? node = s_queue.FirstOrDefault(n => n._ids.Remove(id)); + if (node != null) { - if (node._ids.Remove(id)) + Console.WriteLine($"[Donate25] Removed {id} in {node._checkTime}"); + if (newMainId != null) { - Console.WriteLine($"[Donate25] Removed {id} in {node._checkTime}"); - if (newMainId != null) - { - node._ids.Add(newMainId); - Donation donation = Db.GetDonation(id)!; - donation.Delete(); - donation.MainId = newMainId; - donation.Insert(); - Console.WriteLine($"[Donate25] Added {newMainId} because it replaced {id} as main"); - } - break; + node._ids.Add(newMainId); + Donation donation = Db.GetDonation(id)!; + donation.Delete(); + donation.MainId = newMainId; + donation.Insert(); + Console.WriteLine($"[Donate25] Added {newMainId} because it replaced {id} as main"); } } } @@ -110,50 +104,57 @@ internal static void MemberAdded(string id) internal static async Task CheckAsync() { - while (s_queue.Count > 0) + try { - Node node = s_queue.First(); - if (node._ids.Count == 0) + while (s_queue.Count > 0) { - s_queue.Dequeue(); - continue; - } + Node node = s_queue.First(); + if (node._ids.Count == 0) + { + s_queue.Dequeue(); + continue; + } - int waitDelay = (int)((node._checkTime * 1000) - DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()); - await Task.Delay(waitDelay); + int waitDelay = (int)((node._checkTime * 1000) - DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()); + await Task.Delay(waitDelay); - node = s_queue.Dequeue(); - node._checkTime += CheckPeriod; - List violators = []; - foreach (string member in node._ids) - { - IEnumerable alts = new Member(member).GetAltsByMain(); - int altCount = alts.Count(); - int donationTarget = TargetPerPerson * (altCount + 1); - Donation donation = Db.GetDonation(member)!; - if (donation.Donated >= donationTarget) + node = s_queue.Dequeue(); + node._checkTime += CheckPeriod; + List violators = []; + foreach (string member in node._ids) { - Console.WriteLine($"[Donate25] {member} new cycle"); + IEnumerable alts = new Member(member).GetAltsByMain(); + int altCount = alts.Count(); + int donationTarget = TargetPerPerson * (altCount + 1); + Donation donation = Db.GetDonation(member)!; + if (donation.Donated >= donationTarget) + { + Console.WriteLine($"[Donate25] {member} new cycle"); + } + else + { + violators.Add(member); + Console.WriteLine($"[Donate25] {member} violated"); + } + donation.Donated = 0; + donation.Checked = node._checkTime; + donation.Update(); } - else + + if (node._ids.Count > 0) { - violators.Add(member); - Console.WriteLine($"[Donate25] {member} violated"); + s_queue.Enqueue(node); } - donation.Donated = 0; - donation.Checked = node._checkTime; - donation.Update(); - } - if (node._ids.Count > 0) - { - s_queue.Enqueue(node); - } - - if (violators.Count > 0) - { - await Dc.Donate25Async(violators); + if (violators.Count > 0) + { + await Dc.Donate25Async(violators); + } } } + catch (Exception ex) + { + await Dc.ExceptionAsync(ex); + } } } diff --git a/Bot/Discord/Dc.cs b/Bot/Discord/Dc.cs index 949a632..070416d 100644 --- a/Bot/Discord/Dc.cs +++ b/Bot/Discord/Dc.cs @@ -13,11 +13,11 @@ internal sealed class Dc #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. private static SocketTextChannel s_botLog; private static InteractionService s_interactionSvc; + private static IApplication s_botApp; #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. internal static readonly DiscordSocketClient s_bot = new(); - private static Task Log(LogMessage msg) { Console.WriteLine(msg.ToString()); @@ -56,6 +56,7 @@ internal static async Task InitAsync() s_interactionSvc.AddTypeConverter(new MemberConverter()); await s_interactionSvc.AddModulesAsync(Assembly.GetEntryAssembly(), null); await s_bot.LoginAsync(TokenType.Bot, Secrets.s_discord); + s_botApp = await s_bot.GetApplicationInfoAsync(); await s_bot.StartAsync(); } @@ -89,4 +90,25 @@ internal static async Task DonationsChangedAsync(Dictionary violators) => await s_botLog.SendMessageAsync($"[Donate25] {string.Join(", ", violators)}"); + + internal static async Task ExceptionAsync(Exception ex) + { + EmbedBuilder emb = new() + { + Title = ex.Message + }; + if (ex.StackTrace != null) + { + emb.Description = ex.StackTrace; + } + string? exName = ex.GetType().FullName; + if (exName != null) + { + emb.Author = new EmbedAuthorBuilder + { + Name = exName + }; + } + await s_botLog.SendMessageAsync(s_botApp.Owner.Mention, embed: emb.Build()); + } }