From 766e2f5c20f7f22c2c42d3d9e6698863571d421d Mon Sep 17 00:00:00 2001 From: benbierens Date: Wed, 18 Oct 2023 14:59:39 +0200 Subject: [PATCH] Very basic endpoint pinging that might not even work. --- Tools/BiblioTech/CodexEndpoints.cs | 10 +++ Tools/BiblioTech/CommandHandler.cs | 61 ---------------- Tools/BiblioTech/Configuration.cs | 7 +- Tools/BiblioTech/DeploymentFilesMonitor.cs | 47 ------------ Tools/BiblioTech/EndpointsFilesMonitor.cs | 78 ++++++++++++++++++++ Tools/BiblioTech/EndpointsMonitor.cs | 81 +++++++++++++++++++++ Tools/BiblioTech/HelloWorldCommand.cs | 3 - Tools/BiblioTech/HelloWorldModule.cs | 14 ---- Tools/BiblioTech/Program.cs | 23 +++--- Tools/BiblioTech/StatusCommand.cs | 50 +++++++++++++ Tools/BiblioTech/docker/docker-compose.yaml | 2 +- 11 files changed, 239 insertions(+), 137 deletions(-) create mode 100644 Tools/BiblioTech/CodexEndpoints.cs delete mode 100644 Tools/BiblioTech/CommandHandler.cs delete mode 100644 Tools/BiblioTech/DeploymentFilesMonitor.cs create mode 100644 Tools/BiblioTech/EndpointsFilesMonitor.cs create mode 100644 Tools/BiblioTech/EndpointsMonitor.cs delete mode 100644 Tools/BiblioTech/HelloWorldModule.cs create mode 100644 Tools/BiblioTech/StatusCommand.cs diff --git a/Tools/BiblioTech/CodexEndpoints.cs b/Tools/BiblioTech/CodexEndpoints.cs new file mode 100644 index 00000000..706c27b6 --- /dev/null +++ b/Tools/BiblioTech/CodexEndpoints.cs @@ -0,0 +1,10 @@ +using Utils; + +namespace BiblioTech +{ + public class CodexEndpoints + { + public string Name { get; set; } = string.Empty; + public Address[] Addresses { get; set; } = Array.Empty
(); + } +} diff --git a/Tools/BiblioTech/CommandHandler.cs b/Tools/BiblioTech/CommandHandler.cs deleted file mode 100644 index 42290a5b..00000000 --- a/Tools/BiblioTech/CommandHandler.cs +++ /dev/null @@ -1,61 +0,0 @@ -using Discord.Commands; -using Discord.WebSocket; -using System.Reflection; - -namespace BiblioTech -{ - public class CommandHandler - { - private readonly DiscordSocketClient client; - private readonly CommandService commands; - - // Retrieve client and CommandService instance via ctor - public CommandHandler(DiscordSocketClient client, CommandService commands) - { - this.commands = commands; - this.client = client; - } - - public async Task InstallCommandsAsync() - { - // Hook the MessageReceived event into our command handler - client.MessageReceived += HandleCommandAsync; - - // Here we discover all of the command modules in the entry - // assembly and load them. Starting from Discord.NET 2.0, a - // service provider is required to be passed into the - // module registration method to inject the - // required dependencies. - // - // If you do not use Dependency Injection, pass null. - // See Dependency Injection guide for more information. - await commands.AddModulesAsync(assembly: Assembly.GetEntryAssembly(), - services: null); - } - - private async Task HandleCommandAsync(SocketMessage messageParam) - { - // Don't process the command if it was a system message - var message = messageParam as SocketUserMessage; - if (message == null) return; - - // Create a number to track where the prefix ends and the command begins - int argPos = 0; - - // Determine if the message is a command based on the prefix and make sure no bots trigger commands - if (message.Author.IsBot) return; - if (!message.HasMentionPrefix(client.CurrentUser, ref argPos) && - !message.Content.StartsWith("!")) return; - - // Create a WebSocket-based command context based on the message - var context = new SocketCommandContext(client, message); - - // Execute the command with the command context we just - // created, along with the service provider for precondition checks. - await commands.ExecuteAsync( - context: context, - argPos: argPos, - services: null); - } - } -} diff --git a/Tools/BiblioTech/Configuration.cs b/Tools/BiblioTech/Configuration.cs index 73b2fa8c..94a8ec3a 100644 --- a/Tools/BiblioTech/Configuration.cs +++ b/Tools/BiblioTech/Configuration.cs @@ -7,7 +7,10 @@ namespace BiblioTech [Uniform("token", "t", "TOKEN", true, "Discord Application Token")] public string ApplicationToken { get; set; } = string.Empty; - [Uniform("deploys", "d", "DEPLOYS", false, "Path where deployment JSONs are located.")] - public string DeploymentsPath { get; set; } = "deploys"; + [Uniform("server-name", "sn", "SERVERNAME", true, "Name of the Discord server")] + public string ServerName { get; set; } = string.Empty; + + [Uniform("endpoints", "e", "ENDPOINTS", false, "Path where endpoint JSONs are located. Also accepts codex-deployment JSONs.")] + public string EndpointsPath { get; set; } = "endpoints"; } } diff --git a/Tools/BiblioTech/DeploymentFilesMonitor.cs b/Tools/BiblioTech/DeploymentFilesMonitor.cs deleted file mode 100644 index 0d8f0540..00000000 --- a/Tools/BiblioTech/DeploymentFilesMonitor.cs +++ /dev/null @@ -1,47 +0,0 @@ -using CodexPlugin; -using Newtonsoft.Json; - -namespace BiblioTech -{ - public class DeploymentFilesMonitor - { - private DateTime lastUpdate = DateTime.MinValue; - private CodexDeployment[] deployments = Array.Empty(); - - public CodexDeployment[] GetDeployments() - { - if (ShouldUpdate()) - { - UpdateDeployments(); - } - - return deployments; - } - - private void UpdateDeployments() - { - lastUpdate = DateTime.UtcNow; - var path = Program.Config.DeploymentsPath; - var files = Directory.GetFiles(path); - deployments = files.Select(ProcessFile).Where(d => d != null).Cast().ToArray(); - } - - private CodexDeployment? ProcessFile(string filename) - { - try - { - var lines = File.ReadAllLines(filename); - return JsonConvert.DeserializeObject(string.Join(" ", lines)); - } - catch - { - return null; - } - } - - private bool ShouldUpdate() - { - return !deployments.Any() || (DateTime.UtcNow - lastUpdate) > TimeSpan.FromMinutes(10); - } - } -} diff --git a/Tools/BiblioTech/EndpointsFilesMonitor.cs b/Tools/BiblioTech/EndpointsFilesMonitor.cs new file mode 100644 index 00000000..9136740d --- /dev/null +++ b/Tools/BiblioTech/EndpointsFilesMonitor.cs @@ -0,0 +1,78 @@ +using CodexPlugin; +using KubernetesWorkflow; +using Newtonsoft.Json; +using Utils; + +namespace BiblioTech +{ + public class EndpointsFilesMonitor + { + private DateTime lastUpdate = DateTime.MinValue; + private CodexEndpoints[] endpoints = Array.Empty(); + + public CodexEndpoints[] GetEndpoints() + { + if (ShouldUpdate()) + { + UpdateEndpoints(); + } + + return endpoints; + } + + private void UpdateEndpoints() + { + lastUpdate = DateTime.UtcNow; + var path = Program.Config.EndpointsPath; + if (!Directory.Exists(path)) + { + Directory.CreateDirectory(path); + File.WriteAllText(Path.Combine(path, "readme.txt"), "Place codex-deployment.json or codex-endpoints.json here."); + return; + } + + var files = Directory.GetFiles(path); + endpoints = files.Select(ProcessFile).Where(d => d != null).Cast().ToArray(); + } + + private CodexEndpoints? ProcessFile(string filename) + { + try + { + var lines = string.Join(" ", File.ReadAllLines(filename)); + try + { + return JsonConvert.DeserializeObject(lines); + } + catch { } + + return ConvertToEndpoints(JsonConvert.DeserializeObject(lines)); + } + catch + { + return null; + } + } + + private CodexEndpoints? ConvertToEndpoints(CodexDeployment? codexDeployment) + { + if (codexDeployment == null) return null; + + return new CodexEndpoints + { + Name = "codex-deployment-" + codexDeployment.Metadata.StartUtc.ToString("o"), + Addresses = codexDeployment.CodexContainers.Select(ConvertToAddress).ToArray() + }; + } + + private Address ConvertToAddress(RunningContainer rc) + { + return rc.ClusterExternalAddress; + } + + private bool ShouldUpdate() + { + return !endpoints.Any() || (DateTime.UtcNow - lastUpdate) > TimeSpan.FromMinutes(10); + } + } +} diff --git a/Tools/BiblioTech/EndpointsMonitor.cs b/Tools/BiblioTech/EndpointsMonitor.cs new file mode 100644 index 00000000..27e61bd2 --- /dev/null +++ b/Tools/BiblioTech/EndpointsMonitor.cs @@ -0,0 +1,81 @@ +using CodexPlugin; +using Core; +using KubernetesWorkflow; + +namespace BiblioTech +{ + public class EndpointsMonitor + { + private readonly EndpointsFilesMonitor fileMonitor; + private readonly EntryPoint entryPoint; + private DateTime lastUpdate = DateTime.MinValue; + private string report = string.Empty; + + public EndpointsMonitor(EndpointsFilesMonitor fileMonitor, EntryPoint entryPoint) + { + this.fileMonitor = fileMonitor; + this.entryPoint = entryPoint; + } + + public async Task GetReport() + { + if (ShouldUpdate()) + { + await UpdateReport(); + } + + return report; + } + + private async Task UpdateReport() + { + lastUpdate = DateTime.UtcNow; + + var endpoints = fileMonitor.GetEndpoints(); + if (!endpoints.Any()) + { + report = "There are no networks currently online."; + } + else + { + var nl = Environment.NewLine; + report = $"There are {endpoints.Length} networks online." + nl; + for (var i = 0; i < endpoints.Length; i++) + { + var e = endpoints[i]; + report += $" [{i} - {e.Name}] = {await GetStatusMessage(e)}"; + } + } + } + + private async Task GetStatusMessage(CodexEndpoints e) + { + var success = 0; + foreach (var addr in e.Addresses) + { + await Task.Run(() => + { + // this is definitely not going to work: + var rc = new RunningContainer(null!, null!, null!, "", addr, addr); + + var access = new CodexAccess(entryPoint.Tools, rc, null!); + var debugInfo = access.GetDebugInfo(); + + if (!string.IsNullOrEmpty(debugInfo.id)) + { + success++; + } + }); + } + + return $"{success} / {e.Addresses.Length} online."; + // todo: analyze returned peerIDs to say something about + // the number of none-test-net managed nodes seen on the network. + } + + private bool ShouldUpdate() + { + return string.IsNullOrEmpty(report) || (DateTime.UtcNow - lastUpdate) > TimeSpan.FromMinutes(10); + } + } +} diff --git a/Tools/BiblioTech/HelloWorldCommand.cs b/Tools/BiblioTech/HelloWorldCommand.cs index ac58f2f2..8659acf1 100644 --- a/Tools/BiblioTech/HelloWorldCommand.cs +++ b/Tools/BiblioTech/HelloWorldCommand.cs @@ -61,8 +61,5 @@ namespace BiblioTech Console.WriteLine(json); } } - - - } } diff --git a/Tools/BiblioTech/HelloWorldModule.cs b/Tools/BiblioTech/HelloWorldModule.cs deleted file mode 100644 index f0e711bd..00000000 --- a/Tools/BiblioTech/HelloWorldModule.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Discord.Commands; - -namespace BiblioTech -{ - public class HelloWorldModule : ModuleBase - { - [Command("say")] - [Summary("Echoes a message.")] - public Task SayAsync([Remainder][Summary("The text to echo")] string echo) - { - return ReplyAsync("I say: " + echo); - } - } -} diff --git a/Tools/BiblioTech/Program.cs b/Tools/BiblioTech/Program.cs index 4950f26f..e063f122 100644 --- a/Tools/BiblioTech/Program.cs +++ b/Tools/BiblioTech/Program.cs @@ -1,9 +1,8 @@ using ArgsUniform; +using Core; using Discord; -using Discord.Commands; -using Discord.Net; using Discord.WebSocket; -using Newtonsoft.Json; +using Logging; namespace BiblioTech { @@ -12,7 +11,7 @@ namespace BiblioTech private DiscordSocketClient client = null!; public static Configuration Config { get; private set; } = null!; - public static DeploymentFilesMonitor DeploymentFilesMonitor { get; } = new DeploymentFilesMonitor(); + public static EndpointsFilesMonitor DeploymentFilesMonitor { get; } = new EndpointsFilesMonitor(); public static Task Main(string[] args) { @@ -28,12 +27,18 @@ namespace BiblioTech client = new DiscordSocketClient(); client.Log += Log; - var helloWorld = new HelloWorldCommand(client); + ProjectPlugin.Load(); + var entryPoint = new EntryPoint(new ConsoleLog(), new KubernetesWorkflow.Configuration( + kubeConfigFile: null, // todo: readonly file + operationTimeout: TimeSpan.FromMinutes(5), + retryDelay: TimeSpan.FromSeconds(10), + kubernetesNamespace: "not-applicable"), "datafiles"); - //var cmdService = new CommandService(); - //var handler = new CommandHandler(client, cmdService); - //await handler.InstallCommandsAsync(); - //Console.WriteLine("Command handler installed..."); + var fileMonitor = new EndpointsFilesMonitor(); + var monitor = new EndpointsMonitor(fileMonitor, entryPoint); + + var statusCommand = new StatusCommand(client, monitor); + //var helloWorld = new HelloWorldCommand(client); Example for how to do arguments. await client.LoginAsync(TokenType.Bot, Config.ApplicationToken); await client.StartAsync(); diff --git a/Tools/BiblioTech/StatusCommand.cs b/Tools/BiblioTech/StatusCommand.cs new file mode 100644 index 00000000..9d081c0b --- /dev/null +++ b/Tools/BiblioTech/StatusCommand.cs @@ -0,0 +1,50 @@ +using Discord.Net; +using Discord.WebSocket; +using Discord; +using Newtonsoft.Json; +using Core; + +namespace BiblioTech +{ + public class StatusCommand + { + private const string CommandName = "status"; + private readonly DiscordSocketClient client; + private readonly EndpointsMonitor monitor; + + public StatusCommand(DiscordSocketClient client, EndpointsMonitor monitor) + { + this.client = client; + this.monitor = monitor; + + client.Ready += Client_Ready; + client.SlashCommandExecuted += SlashCommandHandler; + } + + private async Task SlashCommandHandler(SocketSlashCommand command) + { + if (command.CommandName != CommandName) return; + + await command.RespondAsync(await monitor.GetReport()); + } + + private async Task Client_Ready() + { + var guild = client.Guilds.Single(g => g.Name == Program.Config.ServerName); + + var guildCommand = new SlashCommandBuilder() + .WithName(CommandName) + .WithDescription("Display status of test net."); + + try + { + await guild.CreateApplicationCommandAsync(guildCommand.Build()); + } + catch (HttpException exception) + { + var json = JsonConvert.SerializeObject(exception.Errors, Formatting.Indented); + Console.WriteLine(json); + } + } + } +} diff --git a/Tools/BiblioTech/docker/docker-compose.yaml b/Tools/BiblioTech/docker/docker-compose.yaml index f283ac72..dae80e44 100644 --- a/Tools/BiblioTech/docker/docker-compose.yaml +++ b/Tools/BiblioTech/docker/docker-compose.yaml @@ -3,4 +3,4 @@ services: image: thatbenbierens/codex-discordbot:initial environment: - TOKEN=tokenplz - - DEPLOYS=deploypath + - SERVERNAME=ThatBen's server