Removes deployment.json from discord bot.
This commit is contained in:
parent
777e414f0a
commit
fde19383df
|
@ -22,11 +22,11 @@ namespace GethPlugin
|
||||||
GethBootstrapNode GetBootstrapRecord();
|
GethBootstrapNode GetBootstrapRecord();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GethNode : IGethNode
|
public class DeploymentGethNode : BaseGethNode, IGethNode
|
||||||
{
|
{
|
||||||
private readonly ILog log;
|
private readonly ILog log;
|
||||||
|
|
||||||
public GethNode(ILog log, GethDeployment startResult)
|
public DeploymentGethNode(ILog log, GethDeployment startResult)
|
||||||
{
|
{
|
||||||
this.log = log;
|
this.log = log;
|
||||||
StartResult = startResult;
|
StartResult = startResult;
|
||||||
|
@ -35,6 +35,59 @@ namespace GethPlugin
|
||||||
public GethDeployment StartResult { get; }
|
public GethDeployment StartResult { get; }
|
||||||
public RunningContainer Container => StartResult.Container;
|
public RunningContainer Container => StartResult.Container;
|
||||||
|
|
||||||
|
public GethBootstrapNode GetBootstrapRecord()
|
||||||
|
{
|
||||||
|
var address = StartResult.Container.GetInternalAddress(GethContainerRecipe.ListenPortTag);
|
||||||
|
|
||||||
|
return new GethBootstrapNode(
|
||||||
|
publicKey: StartResult.PubKey,
|
||||||
|
ipAddress: address.Host.Replace("http://", ""),
|
||||||
|
port: address.Port
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override NethereumInteraction StartInteraction()
|
||||||
|
{
|
||||||
|
var address = StartResult.Container.GetAddress(log, GethContainerRecipe.HttpPortTag);
|
||||||
|
var account = StartResult.Account;
|
||||||
|
|
||||||
|
var creator = new NethereumInteractionCreator(log, address.Host, address.Port, account.PrivateKey);
|
||||||
|
return creator.CreateWorkflow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CustomGethNode : BaseGethNode, IGethNode
|
||||||
|
{
|
||||||
|
private readonly ILog log;
|
||||||
|
private readonly string gethHost;
|
||||||
|
private readonly int gethPort;
|
||||||
|
private readonly string privateKey;
|
||||||
|
|
||||||
|
public GethDeployment StartResult => throw new NotImplementedException();
|
||||||
|
public RunningContainer Container => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public CustomGethNode(ILog log, string gethHost, int gethPort, string privateKey)
|
||||||
|
{
|
||||||
|
this.log = log;
|
||||||
|
this.gethHost = gethHost;
|
||||||
|
this.gethPort = gethPort;
|
||||||
|
this.privateKey = privateKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GethBootstrapNode GetBootstrapRecord()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override NethereumInteraction StartInteraction()
|
||||||
|
{
|
||||||
|
var creator = new NethereumInteractionCreator(log, gethHost, gethPort, privateKey);
|
||||||
|
return creator.CreateWorkflow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class BaseGethNode
|
||||||
|
{
|
||||||
public Ether GetEthBalance()
|
public Ether GetEthBalance()
|
||||||
{
|
{
|
||||||
return StartInteraction().GetEthBalance().Eth();
|
return StartInteraction().GetEthBalance().Eth();
|
||||||
|
@ -70,26 +123,6 @@ namespace GethPlugin
|
||||||
StartInteraction().SendTransaction(contractAddress, function);
|
StartInteraction().SendTransaction(contractAddress, function);
|
||||||
}
|
}
|
||||||
|
|
||||||
public GethBootstrapNode GetBootstrapRecord()
|
|
||||||
{
|
|
||||||
var address = StartResult.Container.GetInternalAddress(GethContainerRecipe.ListenPortTag);
|
|
||||||
|
|
||||||
return new GethBootstrapNode(
|
|
||||||
publicKey: StartResult.PubKey,
|
|
||||||
ipAddress: address.Host.Replace("http://", ""),
|
|
||||||
port: address.Port
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private NethereumInteraction StartInteraction()
|
|
||||||
{
|
|
||||||
var address = StartResult.Container.GetAddress(log, GethContainerRecipe.HttpPortTag);
|
|
||||||
var account = StartResult.Account;
|
|
||||||
|
|
||||||
var creator = new NethereumInteractionCreator(log, address.Host, address.Port, account.PrivateKey);
|
|
||||||
return creator.CreateWorkflow();
|
|
||||||
}
|
|
||||||
|
|
||||||
public decimal? GetSyncedBlockNumber()
|
public decimal? GetSyncedBlockNumber()
|
||||||
{
|
{
|
||||||
return StartInteraction().GetSyncedBlockNumber();
|
return StartInteraction().GetSyncedBlockNumber();
|
||||||
|
@ -99,5 +132,7 @@ namespace GethPlugin
|
||||||
{
|
{
|
||||||
return StartInteraction().IsContractAvailable(abi, contractAddress);
|
return StartInteraction().IsContractAvailable(abi, contractAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected abstract NethereumInteraction StartInteraction();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ namespace GethPlugin
|
||||||
public IGethNode WrapGethContainer(GethDeployment startResult)
|
public IGethNode WrapGethContainer(GethDeployment startResult)
|
||||||
{
|
{
|
||||||
startResult = SerializeGate.Gate(startResult);
|
startResult = SerializeGate.Gate(startResult);
|
||||||
return new GethNode(tools.GetLog(), startResult);
|
return new DeploymentGethNode(tools.GetLog(), startResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Log(string msg)
|
private void Log(string msg)
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
using BiblioTech.Options;
|
|
||||||
using CodexPlugin;
|
|
||||||
|
|
||||||
namespace BiblioTech
|
|
||||||
{
|
|
||||||
public abstract class BaseDeploymentCommand : BaseCommand
|
|
||||||
{
|
|
||||||
protected override async Task Invoke(CommandContext context)
|
|
||||||
{
|
|
||||||
var proceed = await OnInvoke(context);
|
|
||||||
if (!proceed) return;
|
|
||||||
|
|
||||||
var deployments = Program.DeploymentFilesMonitor.GetDeployments();
|
|
||||||
if (deployments.Length == 0)
|
|
||||||
{
|
|
||||||
await context.Followup("No deployments are currently available.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (deployments.Length > 1)
|
|
||||||
{
|
|
||||||
await context.Followup("Multiple deployments are online. I don't know which one to pick!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var codexDeployment = deployments.Single();
|
|
||||||
await ExecuteDeploymentCommand(context, codexDeployment);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract Task ExecuteDeploymentCommand(CommandContext context, CodexDeployment codexDeployment);
|
|
||||||
|
|
||||||
protected virtual Task<bool> OnInvoke(CommandContext context)
|
|
||||||
{
|
|
||||||
return Task.FromResult(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +1,89 @@
|
||||||
using BiblioTech.Options;
|
using BiblioTech.Options;
|
||||||
using CodexContractsPlugin;
|
using CodexContractsPlugin;
|
||||||
using CodexPlugin;
|
|
||||||
using Core;
|
|
||||||
using GethPlugin;
|
using GethPlugin;
|
||||||
|
using Logging;
|
||||||
|
|
||||||
namespace BiblioTech
|
namespace BiblioTech
|
||||||
{
|
{
|
||||||
public abstract class BaseGethCommand : BaseDeploymentCommand
|
public static class GethInput
|
||||||
{
|
{
|
||||||
private readonly CoreInterface ci;
|
private const string GethHostVar = "GETH_HOST";
|
||||||
|
private const string GethPortVar = "GETH_HTTP_PORT";
|
||||||
|
private const string GethPrivKeyVar = "GETH_PRIVATE_KEY";
|
||||||
|
private const string MarketplaceAddressVar = "CODEXCONTRACTS_MARKETPLACEADDRESS";
|
||||||
|
private const string TokenAddressVar = "CODEXCONTRACTS_TOKENADDRESS";
|
||||||
|
private const string AbiVar = "CODEXCONTRACTS_ABI";
|
||||||
|
|
||||||
public BaseGethCommand(CoreInterface ci)
|
static GethInput()
|
||||||
{
|
{
|
||||||
this.ci = ci;
|
var error = new List<string>();
|
||||||
|
var gethHost = GetEnvVar(error, GethHostVar);
|
||||||
|
var gethPort = Convert.ToInt32(GetEnvVar(error, GethPortVar));
|
||||||
|
var privateKey = GetEnvVar(error, GethPrivKeyVar);
|
||||||
|
var marketplaceAddress = GetEnvVar(error, MarketplaceAddressVar);
|
||||||
|
var tokenAddress = GetEnvVar(error, TokenAddressVar);
|
||||||
|
var abi = GetEnvVar(error, AbiVar);
|
||||||
|
|
||||||
|
if (error.Any())
|
||||||
|
{
|
||||||
|
LoadError = string.Join(", ", error);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GethHost = gethHost!;
|
||||||
|
GethPort = gethPort;
|
||||||
|
PrivateKey = privateKey!;
|
||||||
|
MarketplaceAddress = marketplaceAddress!;
|
||||||
|
TokenAddress = tokenAddress!;
|
||||||
|
ABI = abi!;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task ExecuteDeploymentCommand(CommandContext context, CodexDeployment codexDeployment)
|
public static string GethHost { get; } = string.Empty;
|
||||||
{
|
public static int GethPort { get; }
|
||||||
var gethDeployment = codexDeployment.GethDeployment;
|
public static string PrivateKey { get; } = string.Empty;
|
||||||
var contractsDeployment = codexDeployment.CodexContractsDeployment;
|
public static string MarketplaceAddress { get; } = string.Empty;
|
||||||
|
public static string TokenAddress { get; } = string.Empty;
|
||||||
|
public static string ABI { get; } = string.Empty;
|
||||||
|
public static string LoadError { get; } = string.Empty;
|
||||||
|
|
||||||
var gethNode = ci.WrapGethDeployment(gethDeployment);
|
private static string? GetEnvVar(List<string> error, string name)
|
||||||
var contracts = ci.WrapCodexContractsDeployment(gethNode, contractsDeployment);
|
{
|
||||||
|
var result = Environment.GetEnvironmentVariable(name);
|
||||||
|
if (string.IsNullOrEmpty(result)) error.Add($"'{name}' is not set.");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class BaseGethCommand : BaseCommand
|
||||||
|
{
|
||||||
|
protected override async Task Invoke(CommandContext context)
|
||||||
|
{
|
||||||
|
var log = new ConsoleLog();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(GethInput.LoadError))
|
||||||
|
{
|
||||||
|
var msg = "Geth input incorrect: " + GethInput.LoadError;
|
||||||
|
log.Error(msg);
|
||||||
|
if (IsInAdminChannel(context.Command))
|
||||||
|
{
|
||||||
|
await context.Followup(msg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await context.Followup("I'm sorry, there seems to be a configuration error.");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var contractsDeployment = new CodexContractsDeployment(
|
||||||
|
marketplaceAddress: GethInput.MarketplaceAddress,
|
||||||
|
abi: GethInput.ABI,
|
||||||
|
tokenAddress: GethInput.TokenAddress
|
||||||
|
);
|
||||||
|
|
||||||
|
var gethNode = new CustomGethNode(log, GethInput.GethHost, GethInput.GethPort, GethInput.PrivateKey);
|
||||||
|
var contracts = new CodexContractsAccess(log, gethNode, contractsDeployment);
|
||||||
|
|
||||||
await Execute(context, gethNode, contracts);
|
await Execute(context, gethNode, contracts);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,20 +9,13 @@ namespace BiblioTech.Commands
|
||||||
{
|
{
|
||||||
private readonly ClearUserAssociationCommand clearCommand = new ClearUserAssociationCommand();
|
private readonly ClearUserAssociationCommand clearCommand = new ClearUserAssociationCommand();
|
||||||
private readonly ReportCommand reportCommand = new ReportCommand();
|
private readonly ReportCommand reportCommand = new ReportCommand();
|
||||||
private readonly DeployListCommand deployListCommand = new DeployListCommand();
|
|
||||||
private readonly DeployUploadCommand deployUploadCommand = new DeployUploadCommand();
|
|
||||||
private readonly DeployRemoveCommand deployRemoveCommand = new DeployRemoveCommand();
|
|
||||||
private readonly WhoIsCommand whoIsCommand = new WhoIsCommand();
|
private readonly WhoIsCommand whoIsCommand = new WhoIsCommand();
|
||||||
private readonly NetInfoCommand netInfoCommand;
|
|
||||||
private readonly DebugPeerCommand debugPeerCommand;
|
|
||||||
private readonly AddSprCommand addSprCommand;
|
private readonly AddSprCommand addSprCommand;
|
||||||
private readonly ClearSprsCommand clearSprsCommand;
|
private readonly ClearSprsCommand clearSprsCommand;
|
||||||
private readonly GetSprCommand getSprCommand;
|
private readonly GetSprCommand getSprCommand;
|
||||||
|
|
||||||
public AdminCommand(CoreInterface ci, SprCommand sprCommand)
|
public AdminCommand(SprCommand sprCommand)
|
||||||
{
|
{
|
||||||
netInfoCommand = new NetInfoCommand(ci);
|
|
||||||
debugPeerCommand = new DebugPeerCommand(ci);
|
|
||||||
addSprCommand = new AddSprCommand(sprCommand);
|
addSprCommand = new AddSprCommand(sprCommand);
|
||||||
clearSprsCommand = new ClearSprsCommand(sprCommand);
|
clearSprsCommand = new ClearSprsCommand(sprCommand);
|
||||||
getSprCommand = new GetSprCommand(sprCommand);
|
getSprCommand = new GetSprCommand(sprCommand);
|
||||||
|
@ -36,12 +29,7 @@ namespace BiblioTech.Commands
|
||||||
{
|
{
|
||||||
clearCommand,
|
clearCommand,
|
||||||
reportCommand,
|
reportCommand,
|
||||||
deployListCommand,
|
|
||||||
deployUploadCommand,
|
|
||||||
deployRemoveCommand,
|
|
||||||
whoIsCommand,
|
whoIsCommand,
|
||||||
netInfoCommand,
|
|
||||||
debugPeerCommand,
|
|
||||||
addSprCommand,
|
addSprCommand,
|
||||||
clearSprsCommand,
|
clearSprsCommand,
|
||||||
getSprCommand
|
getSprCommand
|
||||||
|
@ -63,15 +51,9 @@ namespace BiblioTech.Commands
|
||||||
|
|
||||||
await clearCommand.CommandHandler(context);
|
await clearCommand.CommandHandler(context);
|
||||||
await reportCommand.CommandHandler(context);
|
await reportCommand.CommandHandler(context);
|
||||||
await deployListCommand.CommandHandler(context);
|
|
||||||
await deployUploadCommand.CommandHandler(context);
|
|
||||||
await deployRemoveCommand.CommandHandler(context);
|
|
||||||
await whoIsCommand.CommandHandler(context);
|
await whoIsCommand.CommandHandler(context);
|
||||||
await netInfoCommand.CommandHandler(context);
|
|
||||||
await debugPeerCommand.CommandHandler(context);
|
|
||||||
await addSprCommand.CommandHandler(context);
|
await addSprCommand.CommandHandler(context);
|
||||||
await clearSprsCommand.CommandHandler(context);
|
await clearSprsCommand.CommandHandler(context);
|
||||||
await deployUploadCommand.CommandHandler(context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ClearUserAssociationCommand : SubCommandOption
|
public class ClearUserAssociationCommand : SubCommandOption
|
||||||
|
@ -126,95 +108,6 @@ namespace BiblioTech.Commands
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DeployListCommand : SubCommandOption
|
|
||||||
{
|
|
||||||
public DeployListCommand()
|
|
||||||
: base("list", "Lists current deployments.")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override async Task onSubCommand(CommandContext context)
|
|
||||||
{
|
|
||||||
var deployments = Program.DeploymentFilesMonitor.GetDeployments();
|
|
||||||
if (!deployments.Any())
|
|
||||||
{
|
|
||||||
await context.Followup("No deployments available.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var nl = Environment.NewLine;
|
|
||||||
await context.Followup(deployments.Select(FormatDeployment).ToArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
private string FormatDeployment(CodexDeployment deployment)
|
|
||||||
{
|
|
||||||
var m = deployment.Metadata;
|
|
||||||
return $"'{m.Name}' ({m.StartUtc.ToString("o")})";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class DeployUploadCommand : SubCommandOption
|
|
||||||
{
|
|
||||||
private readonly FileAttachementOption fileOption = new FileAttachementOption(
|
|
||||||
name: "json",
|
|
||||||
description: "Codex-deployment json to add.",
|
|
||||||
isRequired: true);
|
|
||||||
|
|
||||||
public DeployUploadCommand()
|
|
||||||
: base("add", "Upload a new deployment JSON file.")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override CommandOption[] Options => new[] { fileOption };
|
|
||||||
|
|
||||||
protected override async Task onSubCommand(CommandContext context)
|
|
||||||
{
|
|
||||||
var file = await fileOption.Parse(context);
|
|
||||||
if (file == null) return;
|
|
||||||
|
|
||||||
var result = await Program.DeploymentFilesMonitor.DownloadDeployment(file);
|
|
||||||
if (result)
|
|
||||||
{
|
|
||||||
await context.Followup("Success!");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await context.Followup("That didn't work.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class DeployRemoveCommand : SubCommandOption
|
|
||||||
{
|
|
||||||
private readonly StringOption stringOption = new StringOption(
|
|
||||||
name: "name",
|
|
||||||
description: "Name of deployment to remove.",
|
|
||||||
isRequired: true);
|
|
||||||
|
|
||||||
public DeployRemoveCommand()
|
|
||||||
: base("remove", "Removes a deployment file.")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override CommandOption[] Options => new[] { stringOption };
|
|
||||||
|
|
||||||
protected override async Task onSubCommand(CommandContext context)
|
|
||||||
{
|
|
||||||
var str = await stringOption.Parse(context);
|
|
||||||
if (string.IsNullOrEmpty(str)) return;
|
|
||||||
|
|
||||||
var result = Program.DeploymentFilesMonitor.DeleteDeployment(str);
|
|
||||||
if (result)
|
|
||||||
{
|
|
||||||
await context.Followup("Success!");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await context.Followup("That didn't work.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class WhoIsCommand : SubCommandOption
|
public class WhoIsCommand : SubCommandOption
|
||||||
{
|
{
|
||||||
private readonly UserOption userOption = new UserOption("User", isRequired: false);
|
private readonly UserOption userOption = new UserOption("User", isRequired: false);
|
||||||
|
@ -248,152 +141,6 @@ namespace BiblioTech.Commands
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class AdminDeploymentCommand : SubCommandOption
|
|
||||||
{
|
|
||||||
private readonly CoreInterface ci;
|
|
||||||
|
|
||||||
public AdminDeploymentCommand(CoreInterface ci, string name, string description)
|
|
||||||
: base(name, description)
|
|
||||||
{
|
|
||||||
this.ci = ci;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task<T?> OnDeployment<T>(CommandContext context, Func<ICodexNodeGroup, string, T> action)
|
|
||||||
{
|
|
||||||
var deployment = Program.DeploymentFilesMonitor.GetDeployments().SingleOrDefault();
|
|
||||||
if (deployment == null)
|
|
||||||
{
|
|
||||||
await context.Followup("No deployment found.");
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
if (deployment.CodexInstances == null || !deployment.CodexInstances.Any())
|
|
||||||
{
|
|
||||||
await context.Followup("No codex instances were deployed.");
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var group = ci.WrapCodexContainers(deployment.CodexInstances.Select(i => i.Containers).ToArray());
|
|
||||||
var result = action(group, deployment.Metadata.Name);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var message = new[]
|
|
||||||
{
|
|
||||||
"Failed to wrap nodes with exception: "
|
|
||||||
};
|
|
||||||
var exceptionMessage = ex.ToString().Split(Environment.NewLine);
|
|
||||||
|
|
||||||
await context.Followup(message.Concat(exceptionMessage).ToArray());
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class NetInfoCommand : AdminDeploymentCommand
|
|
||||||
{
|
|
||||||
public NetInfoCommand(CoreInterface ci)
|
|
||||||
: base(ci, name: "netinfo",
|
|
||||||
description: "Fetches info endpoints of codex nodes.")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override async Task onSubCommand(CommandContext context)
|
|
||||||
{
|
|
||||||
var report = await OnDeployment(context, CreateNetInfoReport);
|
|
||||||
if (report != null && report.Any())
|
|
||||||
{
|
|
||||||
await context.Followup(report);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private string[] CreateNetInfoReport(ICodexNodeGroup group, string name)
|
|
||||||
{
|
|
||||||
var content = new List<string>
|
|
||||||
{
|
|
||||||
$"{DateTime.UtcNow.ToString("o")} - {group.Count()} Codex nodes.",
|
|
||||||
$"Deployment name: '{name}'."
|
|
||||||
};
|
|
||||||
|
|
||||||
foreach (var node in group)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var info = node.GetDebugInfo();
|
|
||||||
var json = JsonConvert.SerializeObject(info, Formatting.Indented);
|
|
||||||
var jsonLines = json.Split(Environment.NewLine);
|
|
||||||
content.Add($"Node '{node.GetName()}' responded with:");
|
|
||||||
content.Add("---");
|
|
||||||
content.AddRange(jsonLines);
|
|
||||||
content.Add("---");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
content.Add($"Node '{node.GetName()}' failed to respond with exception: " + ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return content.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class DebugPeerCommand : AdminDeploymentCommand
|
|
||||||
{
|
|
||||||
private readonly StringOption peerIdOption = new StringOption("peerid", "id of peer to try and reach.", true);
|
|
||||||
|
|
||||||
public DebugPeerCommand(CoreInterface ci)
|
|
||||||
: base(ci, name: "debugpeer",
|
|
||||||
description: "Calls debug/peer on each codex node.")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override CommandOption[] Options => new[] { peerIdOption };
|
|
||||||
|
|
||||||
protected override async Task onSubCommand(CommandContext context)
|
|
||||||
{
|
|
||||||
var peerId = await peerIdOption.Parse(context);
|
|
||||||
if (string.IsNullOrEmpty(peerId)) return;
|
|
||||||
|
|
||||||
var report = await OnDeployment(context, (group, name) => CreateDebugPeerReport(group, name, peerId));
|
|
||||||
if (report != null && report.Any())
|
|
||||||
{
|
|
||||||
await context.Followup(report);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private string[] CreateDebugPeerReport(ICodexNodeGroup group, string name, string peerId)
|
|
||||||
{
|
|
||||||
var content = new List<string>
|
|
||||||
{
|
|
||||||
$"{DateTime.UtcNow.ToString("o")} - {group.Count()} Codex nodes.",
|
|
||||||
$"Deployment name: '{name}'.",
|
|
||||||
$"Calling debug/peer for '{peerId}'."
|
|
||||||
};
|
|
||||||
|
|
||||||
foreach (var node in group)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var info = node.GetDebugPeer(peerId);
|
|
||||||
var json = JsonConvert.SerializeObject(info, Formatting.Indented);
|
|
||||||
var jsonLines = json.Split(Environment.NewLine);
|
|
||||||
content.Add($"Node '{node.GetName()}' responded with:");
|
|
||||||
content.Add("---");
|
|
||||||
content.AddRange(jsonLines);
|
|
||||||
content.Add("---");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
content.Add($"Node '{node.GetName()}' failed to respond with exception: " + ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return content.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class AddSprCommand : SubCommandOption
|
public class AddSprCommand : SubCommandOption
|
||||||
{
|
{
|
||||||
private readonly SprCommand sprCommand;
|
private readonly SprCommand sprCommand;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using BiblioTech.Options;
|
using BiblioTech.Options;
|
||||||
using CodexContractsPlugin;
|
using CodexContractsPlugin;
|
||||||
|
using CodexPlugin;
|
||||||
using Core;
|
using Core;
|
||||||
using GethPlugin;
|
using GethPlugin;
|
||||||
|
|
||||||
|
@ -12,8 +13,7 @@ namespace BiblioTech.Commands
|
||||||
description: "If set, get balance for another user. (Optional, admin-only)",
|
description: "If set, get balance for another user. (Optional, admin-only)",
|
||||||
isRequired: false);
|
isRequired: false);
|
||||||
|
|
||||||
public GetBalanceCommand(CoreInterface ci, UserAssociateCommand userAssociateCommand)
|
public GetBalanceCommand(UserAssociateCommand userAssociateCommand)
|
||||||
: base(ci)
|
|
||||||
{
|
{
|
||||||
this.userAssociateCommand = userAssociateCommand;
|
this.userAssociateCommand = userAssociateCommand;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
using BiblioTech.Options;
|
using BiblioTech.Options;
|
||||||
using CodexContractsPlugin;
|
using CodexContractsPlugin;
|
||||||
using Core;
|
|
||||||
using GethPlugin;
|
using GethPlugin;
|
||||||
|
|
||||||
namespace BiblioTech.Commands
|
namespace BiblioTech.Commands
|
||||||
|
@ -14,8 +13,7 @@ namespace BiblioTech.Commands
|
||||||
isRequired: false);
|
isRequired: false);
|
||||||
private readonly UserAssociateCommand userAssociateCommand;
|
private readonly UserAssociateCommand userAssociateCommand;
|
||||||
|
|
||||||
public MintCommand(CoreInterface ci, UserAssociateCommand userAssociateCommand)
|
public MintCommand(UserAssociateCommand userAssociateCommand)
|
||||||
: base(ci)
|
|
||||||
{
|
{
|
||||||
this.userAssociateCommand = userAssociateCommand;
|
this.userAssociateCommand = userAssociateCommand;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,8 +27,6 @@ namespace BiblioTech.Commands
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// private commands
|
|
||||||
|
|
||||||
var result = Program.UserRepo.AssociateUserWithAddress(user, data);
|
var result = Program.UserRepo.AssociateUserWithAddress(user, data);
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,119 +0,0 @@
|
||||||
using CodexPlugin;
|
|
||||||
using Discord;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
|
|
||||||
namespace BiblioTech
|
|
||||||
{
|
|
||||||
public class DeploymentsFilesMonitor
|
|
||||||
{
|
|
||||||
private readonly List<CodexDeployment> deployments = new List<CodexDeployment>();
|
|
||||||
|
|
||||||
public void Initialize()
|
|
||||||
{
|
|
||||||
LoadDeployments();
|
|
||||||
}
|
|
||||||
|
|
||||||
public CodexDeployment[] GetDeployments()
|
|
||||||
{
|
|
||||||
return deployments.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> DownloadDeployment(IAttachment file)
|
|
||||||
{
|
|
||||||
using var http = new HttpClient();
|
|
||||||
var response = await http.GetAsync(file.Url);
|
|
||||||
var str = await response.Content.ReadAsStringAsync();
|
|
||||||
if (string.IsNullOrEmpty(str)) return false;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var deploy = JsonConvert.DeserializeObject<CodexDeployment>(str);
|
|
||||||
var names = deployments.Select(d => d.Metadata.Name).ToArray();
|
|
||||||
if (deploy != null && IsDeploymentOk(deploy) && !names.Contains(deploy.Metadata.Name))
|
|
||||||
{
|
|
||||||
var targetFile = Path.Combine(Program.Config.EndpointsPath, Guid.NewGuid().ToString().ToLowerInvariant() + ".json");
|
|
||||||
File.WriteAllText(targetFile, str);
|
|
||||||
LoadDeployments();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool DeleteDeployment(string deploymentName)
|
|
||||||
{
|
|
||||||
var path = Program.Config.EndpointsPath;
|
|
||||||
if (!Directory.Exists(path)) return false;
|
|
||||||
var files = Directory.GetFiles(path);
|
|
||||||
|
|
||||||
foreach (var file in files)
|
|
||||||
{
|
|
||||||
var deploy = ProcessFile(file);
|
|
||||||
if (deploy != null && deploy.Metadata.Name == deploymentName)
|
|
||||||
{
|
|
||||||
File.Delete(file);
|
|
||||||
LoadDeployments();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsDeploymentOk(CodexDeployment? deploy)
|
|
||||||
{
|
|
||||||
if (deploy == null) return false;
|
|
||||||
if (deploy.GethDeployment == null) return false;
|
|
||||||
if (deploy.GethDeployment.Containers == null) return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LoadDeployments()
|
|
||||||
{
|
|
||||||
deployments.Clear();
|
|
||||||
var path = Program.Config.EndpointsPath;
|
|
||||||
if (!Directory.Exists(path))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(path);
|
|
||||||
File.WriteAllText(Path.Combine(path, "readme.txt"), "Place codex-deployment.json here.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var files = Directory.GetFiles(path);
|
|
||||||
deployments.AddRange(files
|
|
||||||
.Select(ProcessFile)
|
|
||||||
.Where(d => d != null)
|
|
||||||
.Cast<CodexDeployment>()
|
|
||||||
.Distinct(new DeploymentNameEqual()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private CodexDeployment? ProcessFile(string filename)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var lines = string.Join(" ", File.ReadAllLines(filename));
|
|
||||||
return JsonConvert.DeserializeObject<CodexDeployment>(lines);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class DeploymentNameEqual : IEqualityComparer<CodexDeployment>
|
|
||||||
{
|
|
||||||
public bool Equals(CodexDeployment? x, CodexDeployment? y)
|
|
||||||
{
|
|
||||||
if (x == null && y == null) return true;
|
|
||||||
if (x == null || y == null) return false;
|
|
||||||
return x.Metadata.Name == y.Metadata.Name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GetHashCode([DisallowNull] CodexDeployment obj)
|
|
||||||
{
|
|
||||||
return obj.Metadata.Name.GetHashCode();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +1,7 @@
|
||||||
using ArgsUniform;
|
using ArgsUniform;
|
||||||
using BiblioTech.Commands;
|
using BiblioTech.Commands;
|
||||||
using Core;
|
|
||||||
using Discord;
|
using Discord;
|
||||||
using Discord.WebSocket;
|
using Discord.WebSocket;
|
||||||
using Logging;
|
|
||||||
|
|
||||||
namespace BiblioTech
|
namespace BiblioTech
|
||||||
{
|
{
|
||||||
|
@ -12,7 +10,6 @@ namespace BiblioTech
|
||||||
private DiscordSocketClient client = null!;
|
private DiscordSocketClient client = null!;
|
||||||
|
|
||||||
public static Configuration Config { get; private set; } = null!;
|
public static Configuration Config { get; private set; } = null!;
|
||||||
public static DeploymentsFilesMonitor DeploymentFilesMonitor { get; } = new DeploymentsFilesMonitor();
|
|
||||||
public static UserRepo UserRepo { get; } = new UserRepo();
|
public static UserRepo UserRepo { get; } = new UserRepo();
|
||||||
public static AdminChecker AdminChecker { get; } = new AdminChecker();
|
public static AdminChecker AdminChecker { get; } = new AdminChecker();
|
||||||
|
|
||||||
|
@ -21,8 +18,6 @@ namespace BiblioTech
|
||||||
var uniformArgs = new ArgsUniform<Configuration>(PrintHelp, args);
|
var uniformArgs = new ArgsUniform<Configuration>(PrintHelp, args);
|
||||||
Config = uniformArgs.Parse();
|
Config = uniformArgs.Parse();
|
||||||
|
|
||||||
DeploymentFilesMonitor.Initialize();
|
|
||||||
|
|
||||||
EnsurePath(Config.DataPath);
|
EnsurePath(Config.DataPath);
|
||||||
EnsurePath(Config.UserDataPath);
|
EnsurePath(Config.UserDataPath);
|
||||||
EnsurePath(Config.EndpointsPath);
|
EnsurePath(Config.EndpointsPath);
|
||||||
|
@ -36,26 +31,14 @@ namespace BiblioTech
|
||||||
client = new DiscordSocketClient();
|
client = new DiscordSocketClient();
|
||||||
client.Log += Log;
|
client.Log += Log;
|
||||||
|
|
||||||
ProjectPlugin.Load<CodexPlugin.CodexPlugin>();
|
|
||||||
ProjectPlugin.Load<GethPlugin.GethPlugin>();
|
|
||||||
ProjectPlugin.Load<CodexContractsPlugin.CodexContractsPlugin>();
|
|
||||||
|
|
||||||
var entryPoint = new EntryPoint(new ConsoleLog(), new KubernetesWorkflow.Configuration(
|
|
||||||
kubeConfigFile: Config.KubeConfigFile,
|
|
||||||
operationTimeout: TimeSpan.FromMinutes(5),
|
|
||||||
retryDelay: TimeSpan.FromSeconds(10),
|
|
||||||
kubernetesNamespace: Config.KubeNamespace), "datafiles");
|
|
||||||
|
|
||||||
var ci = entryPoint.CreateInterface();
|
|
||||||
|
|
||||||
var associateCommand = new UserAssociateCommand();
|
var associateCommand = new UserAssociateCommand();
|
||||||
var sprCommand = new SprCommand();
|
var sprCommand = new SprCommand();
|
||||||
var handler = new CommandHandler(client,
|
var handler = new CommandHandler(client,
|
||||||
new GetBalanceCommand(ci, associateCommand),
|
new GetBalanceCommand(associateCommand),
|
||||||
new MintCommand(ci, associateCommand),
|
new MintCommand(associateCommand),
|
||||||
sprCommand,
|
sprCommand,
|
||||||
associateCommand,
|
associateCommand,
|
||||||
new AdminCommand(ci, sprCommand)
|
new AdminCommand(sprCommand)
|
||||||
);
|
);
|
||||||
|
|
||||||
await client.LoginAsync(TokenType.Bot, Config.ApplicationToken);
|
await client.LoginAsync(TokenType.Bot, Config.ApplicationToken);
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
using Discord;
|
using Discord;
|
||||||
using GethPlugin;
|
using GethPlugin;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Utils;
|
|
||||||
|
|
||||||
namespace BiblioTech
|
namespace BiblioTech
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue