From beaa67c280b7b666de7ef0dedf160fd9232969cd Mon Sep 17 00:00:00 2001 From: benbierens Date: Fri, 15 Dec 2023 11:02:06 +0100 Subject: [PATCH 1/3] Adds transaction links to mint output --- .../NethereumWorkflow/NethereumInteraction.cs | 6 ++++-- .../CodexContractsAccess.cs | 12 ++++++------ .../ContractInteractions.cs | 8 ++++---- ProjectPlugins/GethPlugin/GethNode.cs | 18 +++++++++--------- Tools/BiblioTech/Commands/MintCommand.cs | 17 +++++++++++------ 5 files changed, 34 insertions(+), 27 deletions(-) diff --git a/Framework/NethereumWorkflow/NethereumInteraction.cs b/Framework/NethereumWorkflow/NethereumInteraction.cs index cbe5028..1efef81 100644 --- a/Framework/NethereumWorkflow/NethereumInteraction.cs +++ b/Framework/NethereumWorkflow/NethereumInteraction.cs @@ -17,11 +17,12 @@ namespace NethereumWorkflow this.web3 = web3; } - public void SendEth(string toAddress, decimal ethAmount) + public string SendEth(string toAddress, decimal ethAmount) { log.Debug(); var receipt = Time.Wait(web3.Eth.GetEtherTransferService().TransferEtherAndWaitForReceiptAsync(toAddress, ethAmount)); if (!receipt.Succeeded()) throw new Exception("Unable to send Eth"); + return receipt.TransactionHash; } public decimal GetEthBalance() @@ -44,12 +45,13 @@ namespace NethereumWorkflow return Time.Wait(handler.QueryAsync(contractAddress, function)); } - public void SendTransaction(string contractAddress, TFunction function) where TFunction : FunctionMessage, new() + public string SendTransaction(string contractAddress, TFunction function) where TFunction : FunctionMessage, new() { log.Debug(); var handler = web3.Eth.GetContractTransactionHandler(); var receipt = Time.Wait(handler.SendRequestAndWaitForReceiptAsync(contractAddress, function)); if (!receipt.Succeeded()) throw new Exception("Unable to perform contract transaction."); + return receipt.TransactionHash; } public decimal? GetSyncedBlockNumber() diff --git a/ProjectPlugins/CodexContractsPlugin/CodexContractsAccess.cs b/ProjectPlugins/CodexContractsPlugin/CodexContractsAccess.cs index 0959a16..1d2a699 100644 --- a/ProjectPlugins/CodexContractsPlugin/CodexContractsAccess.cs +++ b/ProjectPlugins/CodexContractsPlugin/CodexContractsAccess.cs @@ -7,8 +7,8 @@ namespace CodexContractsPlugin { CodexContractsDeployment Deployment { get; } - void MintTestTokens(IHasEthAddress owner, TestToken testTokens); - void MintTestTokens(EthAddress ethAddress, TestToken testTokens); + string MintTestTokens(IHasEthAddress owner, TestToken testTokens); + string MintTestTokens(EthAddress ethAddress, TestToken testTokens); TestToken GetTestTokenBalance(IHasEthAddress owner); TestToken GetTestTokenBalance(EthAddress ethAddress); } @@ -27,15 +27,15 @@ namespace CodexContractsPlugin public CodexContractsDeployment Deployment { get; } - public void MintTestTokens(IHasEthAddress owner, TestToken testTokens) + public string MintTestTokens(IHasEthAddress owner, TestToken testTokens) { - MintTestTokens(owner.EthAddress, testTokens); + return MintTestTokens(owner.EthAddress, testTokens); } - public void MintTestTokens(EthAddress ethAddress, TestToken testTokens) + public string MintTestTokens(EthAddress ethAddress, TestToken testTokens) { var interaction = new ContractInteractions(log, gethNode); - interaction.MintTestTokens(ethAddress, testTokens.Amount, Deployment.TokenAddress); + return interaction.MintTestTokens(ethAddress, testTokens.Amount, Deployment.TokenAddress); } public TestToken GetTestTokenBalance(IHasEthAddress owner) diff --git a/ProjectPlugins/CodexContractsPlugin/ContractInteractions.cs b/ProjectPlugins/CodexContractsPlugin/ContractInteractions.cs index 753a8c7..a1c7ef6 100644 --- a/ProjectPlugins/CodexContractsPlugin/ContractInteractions.cs +++ b/ProjectPlugins/CodexContractsPlugin/ContractInteractions.cs @@ -26,10 +26,10 @@ namespace CodexContractsPlugin return gethNode.Call(marketplaceAddress, function); } - public void MintTestTokens(EthAddress address, decimal amount, string tokenAddress) + public string MintTestTokens(EthAddress address, decimal amount, string tokenAddress) { log.Debug($"{amount} -> {address} (token: {tokenAddress})"); - MintTokens(address.Address, amount, tokenAddress); + return MintTokens(address.Address, amount, tokenAddress); } public decimal GetBalance(string tokenAddress, string account) @@ -56,7 +56,7 @@ namespace CodexContractsPlugin } } - private void MintTokens(string account, decimal amount, string tokenAddress) + private string MintTokens(string account, decimal amount, string tokenAddress) { log.Debug($"({tokenAddress}) {amount} --> {account}"); if (string.IsNullOrEmpty(account)) throw new ArgumentException("Invalid arguments for MintTestTokens"); @@ -67,7 +67,7 @@ namespace CodexContractsPlugin Amount = amount.ToBig() }; - gethNode.SendTransaction(tokenAddress, function); + return gethNode.SendTransaction(tokenAddress, function); } private bool IsBlockNumberOK() diff --git a/ProjectPlugins/GethPlugin/GethNode.cs b/ProjectPlugins/GethPlugin/GethNode.cs index 36ae392..d2e2122 100644 --- a/ProjectPlugins/GethPlugin/GethNode.cs +++ b/ProjectPlugins/GethPlugin/GethNode.cs @@ -13,10 +13,10 @@ namespace GethPlugin Ether GetEthBalance(); Ether GetEthBalance(IHasEthAddress address); Ether GetEthBalance(EthAddress address); - void SendEth(IHasEthAddress account, Ether eth); - void SendEth(EthAddress account, Ether eth); + string SendEth(IHasEthAddress account, Ether eth); + string SendEth(EthAddress account, Ether eth); TResult Call(string contractAddress, TFunction function) where TFunction : FunctionMessage, new(); - void SendTransaction(string contractAddress, TFunction function) where TFunction : FunctionMessage, new(); + string SendTransaction(string contractAddress, TFunction function) where TFunction : FunctionMessage, new(); decimal? GetSyncedBlockNumber(); bool IsContractAvailable(string abi, string contractAddress); GethBootstrapNode GetBootstrapRecord(); @@ -103,14 +103,14 @@ namespace GethPlugin return StartInteraction().GetEthBalance(address.Address).Eth(); } - public void SendEth(IHasEthAddress owner, Ether eth) + public string SendEth(IHasEthAddress owner, Ether eth) { - SendEth(owner.EthAddress, eth); + return SendEth(owner.EthAddress, eth); } - public void SendEth(EthAddress account, Ether eth) + public string SendEth(EthAddress account, Ether eth) { - StartInteraction().SendEth(account.Address, eth.Eth); + return StartInteraction().SendEth(account.Address, eth.Eth); } public TResult Call(string contractAddress, TFunction function) where TFunction : FunctionMessage, new() @@ -118,9 +118,9 @@ namespace GethPlugin return StartInteraction().Call(contractAddress, function); } - public void SendTransaction(string contractAddress, TFunction function) where TFunction : FunctionMessage, new() + public string SendTransaction(string contractAddress, TFunction function) where TFunction : FunctionMessage, new() { - StartInteraction().SendTransaction(contractAddress, function); + return StartInteraction().SendTransaction(contractAddress, function); } public decimal? GetSyncedBlockNumber() diff --git a/Tools/BiblioTech/Commands/MintCommand.cs b/Tools/BiblioTech/Commands/MintCommand.cs index cc50a2a..125ade8 100644 --- a/Tools/BiblioTech/Commands/MintCommand.cs +++ b/Tools/BiblioTech/Commands/MintCommand.cs @@ -47,12 +47,12 @@ namespace BiblioTech.Commands { if (ShouldMintTestTokens(contracts, addr)) { - contracts.MintTestTokens(addr, defaultTestTokensToMint); - report.Add($"Minted {defaultTestTokensToMint}."); + var transaction = contracts.MintTestTokens(addr, defaultTestTokensToMint); + report.Add($"Minted {defaultTestTokensToMint}. ({FormatTransactionLink(transaction)})"); return defaultTestTokensToMint; } - report.Add("TestToken balance over threshold."); + report.Add("TestToken balance over threshold. (No TestTokens minted.)"); return 0.TestTokens(); } @@ -60,11 +60,11 @@ namespace BiblioTech.Commands { if (ShouldSendEth(gethNode, addr)) { - gethNode.SendEth(addr, defaultEthToSend); - report.Add($"Sent {defaultEthToSend}."); + var transaction = gethNode.SendEth(addr, defaultEthToSend); + report.Add($"Sent {defaultEthToSend}. ({FormatTransactionLink(transaction)})"); return defaultEthToSend; } - report.Add("Eth balance is over threshold."); + report.Add("Eth balance is over threshold. (No Eth sent.)"); return 0.Eth(); } @@ -79,5 +79,10 @@ namespace BiblioTech.Commands var eth = gethNode.GetEthBalance(addr); return eth.Eth < 1.0m; } + + private string FormatTransactionLink(string transaction) + { + return $"https://explorer.testnet.codex.storage/tx/{transaction}"; + } } } From 03283414cb9654581c4025ec7f0806850d9bd4e1 Mon Sep 17 00:00:00 2001 From: benbierens Date: Fri, 15 Dec 2023 11:09:15 +0100 Subject: [PATCH 2/3] Adds transaction ID to record of user activity --- Tools/BiblioTech/Commands/MintCommand.cs | 12 ++++++------ Tools/BiblioTech/Transaction.cs | 14 ++++++++++++++ Tools/BiblioTech/UserRepo.cs | 17 ++++++++++++----- 3 files changed, 32 insertions(+), 11 deletions(-) create mode 100644 Tools/BiblioTech/Transaction.cs diff --git a/Tools/BiblioTech/Commands/MintCommand.cs b/Tools/BiblioTech/Commands/MintCommand.cs index 125ade8..2481aa0 100644 --- a/Tools/BiblioTech/Commands/MintCommand.cs +++ b/Tools/BiblioTech/Commands/MintCommand.cs @@ -43,29 +43,29 @@ namespace BiblioTech.Commands await context.Followup(string.Join(Environment.NewLine, report)); } - private TestToken ProcessTokens(ICodexContracts contracts, EthAddress addr, List report) + private Transaction? ProcessTokens(ICodexContracts contracts, EthAddress addr, List report) { if (ShouldMintTestTokens(contracts, addr)) { var transaction = contracts.MintTestTokens(addr, defaultTestTokensToMint); report.Add($"Minted {defaultTestTokensToMint}. ({FormatTransactionLink(transaction)})"); - return defaultTestTokensToMint; + return new Transaction(defaultTestTokensToMint, transaction); } report.Add("TestToken balance over threshold. (No TestTokens minted.)"); - return 0.TestTokens(); + return null; } - private Ether ProcessEth(IGethNode gethNode, EthAddress addr, List report) + private Transaction? ProcessEth(IGethNode gethNode, EthAddress addr, List report) { if (ShouldSendEth(gethNode, addr)) { var transaction = gethNode.SendEth(addr, defaultEthToSend); report.Add($"Sent {defaultEthToSend}. ({FormatTransactionLink(transaction)})"); - return defaultEthToSend; + return new Transaction(defaultEthToSend, transaction); } report.Add("Eth balance is over threshold. (No Eth sent.)"); - return 0.Eth(); + return null; } private bool ShouldMintTestTokens(ICodexContracts contracts, EthAddress addr) diff --git a/Tools/BiblioTech/Transaction.cs b/Tools/BiblioTech/Transaction.cs new file mode 100644 index 0000000..a19814a --- /dev/null +++ b/Tools/BiblioTech/Transaction.cs @@ -0,0 +1,14 @@ +namespace BiblioTech +{ + public class Transaction + { + public Transaction(T tokenAmount, string transactionHash) + { + TokenAmount = tokenAmount; + TransactionHash = transactionHash; + } + + public T TokenAmount { get; } + public string TransactionHash { get; } + } +} diff --git a/Tools/BiblioTech/UserRepo.cs b/Tools/BiblioTech/UserRepo.cs index 237f0a5..23b25d5 100644 --- a/Tools/BiblioTech/UserRepo.cs +++ b/Tools/BiblioTech/UserRepo.cs @@ -25,7 +25,7 @@ namespace BiblioTech } } - public void AddMintEventForUser(IUser user, EthAddress usedAddress, Ether eth, TestToken tokens) + public void AddMintEventForUser(IUser user, EthAddress usedAddress, Transaction? eth, Transaction? tokens) { lock (repoLock) { @@ -67,7 +67,14 @@ namespace BiblioTech } foreach (var me in userData.MintEvents) { - result.Add($"{me.Utc.ToString("o")} - Minted {me.EthReceived} and {me.TestTokensMinted} to {me.UsedAddress}."); + if (me.EthReceived != null) + { + result.Add($"{me.Utc.ToString("o")} - Sent {me.EthReceived.TokenAmount} to {me.UsedAddress}. ({me.EthReceived.TransactionHash})"); + } + if (me.TestTokensMinted != null) + { + result.Add($"{me.Utc.ToString("o")} - Minted {me.TestTokensMinted.TokenAmount} to {me.UsedAddress}. ({me.TestTokensMinted.TransactionHash})"); + } } } } @@ -221,7 +228,7 @@ namespace BiblioTech public class UserMintEvent { - public UserMintEvent(DateTime utc, EthAddress usedAddress, Ether ethReceived, TestToken testTokensMinted) + public UserMintEvent(DateTime utc, EthAddress usedAddress, Transaction? ethReceived, Transaction? testTokensMinted) { Utc = utc; UsedAddress = usedAddress; @@ -231,7 +238,7 @@ namespace BiblioTech public DateTime Utc { get; } public EthAddress UsedAddress { get; } - public Ether EthReceived { get; } - public TestToken TestTokensMinted { get; } + public Transaction? EthReceived { get; } + public Transaction? TestTokensMinted { get; } } } From 62987449189c4501c7467c98e9ec50532d482cea Mon Sep 17 00:00:00 2001 From: benbierens Date: Mon, 18 Dec 2023 11:27:28 +0100 Subject: [PATCH 3/3] Better logging --- Framework/Logging/FileLog.cs | 17 +++++++++++++ Tools/BiblioTech/AdminChecker.cs | 16 +++++++++++-- Tools/BiblioTech/BaseCommand.cs | 6 +++-- Tools/BiblioTech/CommandHandler.cs | 10 +++++++- .../BiblioTech/Commands/GetBalanceCommand.cs | 2 -- Tools/BiblioTech/Commands/MintCommand.cs | 7 +++--- Tools/BiblioTech/Configuration.cs | 14 ++++++----- Tools/BiblioTech/Program.cs | 24 +++++++++++++------ Tools/BiblioTech/RandomBusyMessage.cs | 2 +- 9 files changed, 74 insertions(+), 24 deletions(-) create mode 100644 Framework/Logging/FileLog.cs diff --git a/Framework/Logging/FileLog.cs b/Framework/Logging/FileLog.cs new file mode 100644 index 0000000..cc5e995 --- /dev/null +++ b/Framework/Logging/FileLog.cs @@ -0,0 +1,17 @@ +namespace Logging +{ + public class FileLog : BaseLog + { + public FileLog(string fullFilename) + { + FullFilename = fullFilename; + } + + public string FullFilename { get; } + + protected override string GetFullName() + { + return FullFilename; + } + } +} diff --git a/Tools/BiblioTech/AdminChecker.cs b/Tools/BiblioTech/AdminChecker.cs index 4701520..e1c82cd 100644 --- a/Tools/BiblioTech/AdminChecker.cs +++ b/Tools/BiblioTech/AdminChecker.cs @@ -1,4 +1,5 @@ -using Discord.WebSocket; +using Discord; +using Discord.WebSocket; namespace BiblioTech { @@ -7,6 +8,7 @@ namespace BiblioTech private SocketGuild guild = null!; private ulong[] adminIds = Array.Empty(); private DateTime lastUpdate = DateTime.MinValue; + private ISocketMessageChannel adminChannel = null!; public void SetGuild(SocketGuild guild) { @@ -20,11 +22,21 @@ namespace BiblioTech return adminIds.Contains(userId); } - public bool IsAdminChannel(ISocketMessageChannel channel) + public bool IsAdminChannel(IChannel channel) { return channel.Name == Program.Config.AdminChannelName; } + public ISocketMessageChannel GetAdminChannel() + { + return adminChannel; + } + + public void SetAdminChannel(ISocketMessageChannel adminChannel) + { + this.adminChannel = adminChannel; + } + private bool ShouldUpdate() { return !adminIds.Any() || (DateTime.UtcNow - lastUpdate) > TimeSpan.FromMinutes(10); diff --git a/Tools/BiblioTech/BaseCommand.cs b/Tools/BiblioTech/BaseCommand.cs index dc23d68..44695fd 100644 --- a/Tools/BiblioTech/BaseCommand.cs +++ b/Tools/BiblioTech/BaseCommand.cs @@ -17,22 +17,24 @@ namespace BiblioTech try { + Program.Log.Log($"Responding to '{Name}'"); var context = new CommandContext(command, command.Data.Options); await command.RespondAsync(StartingMessage, ephemeral: IsEphemeral(context)); await Invoke(context); } catch (Exception ex) { + var msg = "Failed with exception: " + ex; if (IsInAdminChannel(command)) { - var msg = "Failed with exception: " + ex; await command.FollowupAsync(msg.Substring(0, Math.Min(1900, msg.Length))); } else { await command.FollowupAsync("Something failed while trying to do that...", ephemeral: true); + await Program.AdminChecker.GetAdminChannel().SendMessageAsync(msg); } - Console.WriteLine(ex); + Program.Log.Error(msg); } } diff --git a/Tools/BiblioTech/CommandHandler.cs b/Tools/BiblioTech/CommandHandler.cs index 88b45aa..800ac4b 100644 --- a/Tools/BiblioTech/CommandHandler.cs +++ b/Tools/BiblioTech/CommandHandler.cs @@ -23,18 +23,26 @@ namespace BiblioTech { var guild = client.Guilds.Single(g => g.Name == Program.Config.ServerName); Program.AdminChecker.SetGuild(guild); + Program.Log.Log($"Initializing for guild: '{guild.Name}'"); + + var adminChannels = guild.TextChannels.Where(Program.AdminChecker.IsAdminChannel).ToArray(); + if (adminChannels == null || !adminChannels.Any()) throw new Exception("No admin message channel"); + Program.AdminChecker.SetAdminChannel(adminChannels.First()); var builders = commands.Select(c => { + var msg = $"Building command '{c.Name}' with options: "; var builder = new SlashCommandBuilder() .WithName(c.Name) .WithDescription(c.Description); foreach (var option in c.Options) { + msg += option.Name + " "; builder.AddOption(option.Build()); } + Program.Log.Log(msg); return builder; }); @@ -48,7 +56,7 @@ namespace BiblioTech catch (HttpException exception) { var json = JsonConvert.SerializeObject(exception.Errors, Formatting.Indented); - Console.WriteLine(json); + Program.Log.Error(json); } } diff --git a/Tools/BiblioTech/Commands/GetBalanceCommand.cs b/Tools/BiblioTech/Commands/GetBalanceCommand.cs index 60118f5..964d7c2 100644 --- a/Tools/BiblioTech/Commands/GetBalanceCommand.cs +++ b/Tools/BiblioTech/Commands/GetBalanceCommand.cs @@ -1,7 +1,5 @@ using BiblioTech.Options; using CodexContractsPlugin; -using CodexPlugin; -using Core; using GethPlugin; namespace BiblioTech.Commands diff --git a/Tools/BiblioTech/Commands/MintCommand.cs b/Tools/BiblioTech/Commands/MintCommand.cs index 2481aa0..aa2ccf6 100644 --- a/Tools/BiblioTech/Commands/MintCommand.cs +++ b/Tools/BiblioTech/Commands/MintCommand.cs @@ -48,7 +48,7 @@ namespace BiblioTech.Commands if (ShouldMintTestTokens(contracts, addr)) { var transaction = contracts.MintTestTokens(addr, defaultTestTokensToMint); - report.Add($"Minted {defaultTestTokensToMint}. ({FormatTransactionLink(transaction)})"); + report.Add($"Minted {defaultTestTokensToMint} {FormatTransactionLink(transaction)}"); return new Transaction(defaultTestTokensToMint, transaction); } @@ -61,7 +61,7 @@ namespace BiblioTech.Commands if (ShouldSendEth(gethNode, addr)) { var transaction = gethNode.SendEth(addr, defaultEthToSend); - report.Add($"Sent {defaultEthToSend}. ({FormatTransactionLink(transaction)})"); + report.Add($"Sent {defaultEthToSend} {FormatTransactionLink(transaction)}"); return new Transaction(defaultEthToSend, transaction); } report.Add("Eth balance is over threshold. (No Eth sent.)"); @@ -82,7 +82,8 @@ namespace BiblioTech.Commands private string FormatTransactionLink(string transaction) { - return $"https://explorer.testnet.codex.storage/tx/{transaction}"; + var url = $"https://explorer.testnet.codex.storage/tx/{transaction}"; + return $"- [View on block explorer]({url}){Environment.NewLine}Transaction ID - `{transaction}`"; } } } diff --git a/Tools/BiblioTech/Configuration.cs b/Tools/BiblioTech/Configuration.cs index eb58870..bce62ea 100644 --- a/Tools/BiblioTech/Configuration.cs +++ b/Tools/BiblioTech/Configuration.cs @@ -19,12 +19,6 @@ namespace BiblioTech [Uniform("admin-channel-name", "ac", "ADMINCHANNELNAME", true, "Name of the Discord server channel where admin commands are allowed.")] public string AdminChannelName { get; set; } = "admin-channel"; - [Uniform("kube-config", "kc", "KUBECONFIG", true, "Path to Kubeconfig file. Use a Kubeconfig with read-only access.")] - public string KubeConfigFile { get; set; } = "null"; - - [Uniform("kube-namespace", "kn", "KUBENAMESPACE", true, "Kubernetes namespace.")] - public string KubeNamespace { get; set; } = string.Empty; - public string EndpointsPath { get @@ -40,5 +34,13 @@ namespace BiblioTech return Path.Combine(DataPath, "users"); } } + + public string LogPath + { + get + { + return Path.Combine(DataPath, "logs"); + } + } } } diff --git a/Tools/BiblioTech/Program.cs b/Tools/BiblioTech/Program.cs index f759d97..22e68f8 100644 --- a/Tools/BiblioTech/Program.cs +++ b/Tools/BiblioTech/Program.cs @@ -2,6 +2,7 @@ using BiblioTech.Commands; using Discord; using Discord.WebSocket; +using Logging; namespace BiblioTech { @@ -11,13 +12,19 @@ namespace BiblioTech public static Configuration Config { get; private set; } = null!; public static UserRepo UserRepo { get; } = new UserRepo(); - public static AdminChecker AdminChecker { get; } = new AdminChecker(); + public static AdminChecker AdminChecker { get; private set; } = null!; + public static ILog Log { get; private set; } = null!; public static Task Main(string[] args) { var uniformArgs = new ArgsUniform(PrintHelp, args); Config = uniformArgs.Parse(); + Log = new LogSplitter( + new FileLog(Path.Combine(Config.LogPath, "discordbot.log")), + new ConsoleLog() + ); + EnsurePath(Config.DataPath); EnsurePath(Config.UserDataPath); EnsurePath(Config.EndpointsPath); @@ -27,9 +34,9 @@ namespace BiblioTech public async Task MainAsync() { - Console.WriteLine("Starting Codex Discord Bot..."); + Log.Log("Starting Codex Discord Bot..."); client = new DiscordSocketClient(); - client.Log += Log; + client.Log += ClientLog; var associateCommand = new UserAssociateCommand(); var sprCommand = new SprCommand(); @@ -43,18 +50,21 @@ namespace BiblioTech await client.LoginAsync(TokenType.Bot, Config.ApplicationToken); await client.StartAsync(); - Console.WriteLine("Running..."); + + AdminChecker = new AdminChecker(); + + Log.Log("Running..."); await Task.Delay(-1); } private static void PrintHelp() { - Console.WriteLine("BiblioTech - Codex Discord Bot"); + Log.Log("BiblioTech - Codex Discord Bot"); } - private Task Log(LogMessage msg) + private Task ClientLog(LogMessage msg) { - Console.WriteLine(msg.ToString()); + Log.Log("DiscordClient: " + msg.ToString()); return Task.CompletedTask; } diff --git a/Tools/BiblioTech/RandomBusyMessage.cs b/Tools/BiblioTech/RandomBusyMessage.cs index 5582767..baa370e 100644 --- a/Tools/BiblioTech/RandomBusyMessage.cs +++ b/Tools/BiblioTech/RandomBusyMessage.cs @@ -19,7 +19,7 @@ public static string Get() { - return messages[random.Next(messages.Length)]; + return "Hold on: " + messages[random.Next(messages.Length)]; } } }