Very basic endpoint pinging that might not even work.
This commit is contained in:
parent
888b19d8e5
commit
766e2f5c20
|
@ -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<Address>();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
using CodexPlugin;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BiblioTech
|
||||
{
|
||||
public class DeploymentFilesMonitor
|
||||
{
|
||||
private DateTime lastUpdate = DateTime.MinValue;
|
||||
private CodexDeployment[] deployments = Array.Empty<CodexDeployment>();
|
||||
|
||||
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<CodexDeployment>().ToArray();
|
||||
}
|
||||
|
||||
private CodexDeployment? ProcessFile(string filename)
|
||||
{
|
||||
try
|
||||
{
|
||||
var lines = File.ReadAllLines(filename);
|
||||
return JsonConvert.DeserializeObject<CodexDeployment>(string.Join(" ", lines));
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private bool ShouldUpdate()
|
||||
{
|
||||
return !deployments.Any() || (DateTime.UtcNow - lastUpdate) > TimeSpan.FromMinutes(10);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<CodexEndpoints>();
|
||||
|
||||
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<CodexEndpoints>().ToArray();
|
||||
}
|
||||
|
||||
private CodexEndpoints? ProcessFile(string filename)
|
||||
{
|
||||
try
|
||||
{
|
||||
var lines = string.Join(" ", File.ReadAllLines(filename));
|
||||
try
|
||||
{
|
||||
return JsonConvert.DeserializeObject<CodexEndpoints>(lines);
|
||||
}
|
||||
catch { }
|
||||
|
||||
return ConvertToEndpoints(JsonConvert.DeserializeObject<CodexDeployment>(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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<string> 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<string> 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -61,8 +61,5 @@ namespace BiblioTech
|
|||
Console.WriteLine(json);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
using Discord.Commands;
|
||||
|
||||
namespace BiblioTech
|
||||
{
|
||||
public class HelloWorldModule : ModuleBase<SocketCommandContext>
|
||||
{
|
||||
[Command("say")]
|
||||
[Summary("Echoes a message.")]
|
||||
public Task SayAsync([Remainder][Summary("The text to echo")] string echo)
|
||||
{
|
||||
return ReplyAsync("I say: " + echo);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<CodexPlugin.CodexPlugin>();
|
||||
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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,4 +3,4 @@ services:
|
|||
image: thatbenbierens/codex-discordbot:initial
|
||||
environment:
|
||||
- TOKEN=tokenplz
|
||||
- DEPLOYS=deploypath
|
||||
- SERVERNAME=ThatBen's server
|
||||
|
|
Loading…
Reference in New Issue