public void SetNearestNode(SupernodeStructures.Location location) { var client = new SupernodeClient(); if (location.numNodes > 25) { throw new ArgumentException("invalid number of nodes"); } client.BeginGetNearestNodesInfo(ar => { for (var i = 0; i < ar.Content.data.Count; i++) { if (ar.Content.data[i].status != 1) { continue; } SetHost(ar.Content.data[i].ip); break; } }, location).AsyncWaitHandle.WaitOne(); }
internal async Task ScanTests(SuperNode n) { try { var testTypes = new List <string>() { "node version test", "chain height test", "chain part test", "responsiveness test", "bandwidth test", "computing power test", "ping test", "node balance test" }; var superClient = new SupernodeClient(); superClient.BeginGetTestResults(ar => { try { if (ar.Content.data[0].round != n.LastTest) { var bitArray = new BitArray(new[] { ar.Content.data[0].testResult }); var passed = new bool[32]; bitArray.CopyTo(passed, 0); var passedBits = ToBitInts(bitArray); if (passedBits.Contains(0)) { var msg = "Node: " + n.Alias + "\nWith IP: " + n.IP + " \nfailed tests on " + "\nDate: " + ar.Content.data[0].dateAndTime.Substring(startIndex: 0, length: 10) + "\nTime: " + ar.Content.data[0].dateAndTime.Substring(startIndex: 11, length: 8) + "\n"; for (var index = 0; index < 8; index++) { var pass = passedBits[index]; if (pass == 0) { msg += pass == 0 ? testTypes[index] + ": failed\n" : testTypes[index] + ": passed\n"; } } try { msg += "https://supernodes.nem.io/details/" + n.SNodeID + "\n"; n.LastTest = ar.Content.data[0].round; NodeUtils.UpdateNode(snode: n, chatId: n.OwnedByUser); Console.WriteLine(msg); Nofity(node: n, msg: msg); } catch (Exception e) { Console.WriteLine("node scanner line 199: " + e.StackTrace); if (e.Message.Contains("blocked")) { UserUtils.DeleteUser(n.OwnedByUser); } } } } } catch (Exception ex) { Console.WriteLine("node scanner line 214: " + ex.Message); } }, new SupernodeStructures.TestResultRequestData { alias = n.Alias, numRounds = 1, roundFrom = -1 }); } catch (Exception e) { Console.WriteLine("node scanner line 225" + e.StackTrace); } }
internal void ManageNodes(Chat chat, string text) { var Bot = new TelegramBot(accessToken: ConfigurationManager.AppSettings[name: "accessKey"]); // if the user is not known, add the user to the database if (UserUtils.GetUser(chatId: chat.Id)?.ChatId == null) { // add user based on their chat ID UserUtils.AddUser(userName: chat.Username, chatId: chat.Id); // declare message var msg1 = "You have been automatically registered, one moment please"; // send message notifying they have been registered var reqAction1 = new SendMessage(chatId: chat.Id, text: msg1); // send message Bot.MakeRequestAsync(request: reqAction1); } // set up regex pattern matching sequences. var ip = new Regex(pattern: @"\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b"); var ip2 = new Regex(pattern: @"[a-zA-Z0-9]{1,20}\.[a-zA-Z0-9]{1,20}\.[a-zA-Z0-9]{1,20}"); var ip3 = new Regex(pattern: @"[a-zA-Z0-9]{1,20}\.[a-zA-Z0-9]{1,20}"); // scan list of submitted ip's for any valid sequences var result = ip.Matches(input: text).Cast <Match>().Select(selector: m => m.Value) .Concat(second: ip2.Matches(input: text).Cast <Match>().Select(selector: m => m.Value)) .Concat(second: ip3.Matches(input: text).Cast <Match>().Select(selector: m => m.Value)).ToArray(); // declare a nodeClient to retrieve node data. var snodeClient = new SupernodeClient(); // get a list of all supernodes snodeClient.BeginGetSupernodes(ar => { try { // check submitted list against the list of all supernodes var validNodes = new SupernodeResponseData.Supernodes() { data = new List <SupernodeResponseData.Nodes>() }; foreach (string userIp in result) { foreach (var node in ar.Content.data) { if (userIp != node.ip) { continue; } if (node.payoutAddress == null) { var bot = new TelegramBot(accessToken: ConfigurationManager.AppSettings[name: "accessKey"]); var req = new SendMessage(chatId: chat.Id, text: "One of the nodes you have submitted is invalid, or has not been accepted into the supernode program yet, or it has not recieved its first payment. The invalid node was node registered. Please check your nodes and try again"); bot.MakeRequestAsync(request: req); continue; } validNodes.data.Add(item: node); } } // if the user wants to register a node if (text.StartsWith(value: "/registerNode:") && text != "/registerNode:") { // automatically add the deposit account of each registered node as a monitored account // nodes must be cross referenced with total supernode list to acquire the deposit address // as the supernode API doesnt contain this information string msg1; try { AccountUtils.AddAccount( chatId: chat.Id, accounts: ar.Content.data.Where(predicate: x => validNodes.data.Any(predicate: y => y.ip == x.ip)).ToList() .Select(selector: node => node.payoutAddress).ToList()); var nodesAdded = NodeUtils.AddNode(chatId: chat.Id, nodes: validNodes); // return a message showing which accounts were registered msg1 = ar.Content.data.Count > 0 ? nodesAdded.data.Aggregate(seed: "Nodes registered: \n \n", func: (current, n) => current + n.ip + "\n") : "No nodes were added. It/they may be offline or have an invalid IP. Check your node ip's and try again"; // send message } catch (Exception e) { Console.WriteLine(value: e); msg1 = "Something went wrong, please try again."; } var reqAction1 = new SendMessage(chatId: chat.Id, text: msg1); Bot.MakeRequestAsync(request: reqAction1); } // if a user wants to unregister an account if (text.StartsWith(value: "/unregisterNode:") && text != "/unregisterNode:") { string msg2; try { // declare message assuming nothing goes wrong msg2 = result.Length > 1 ? "Your nodes were removed" : "Your node was removed"; // make sure the user is registered if (UserUtils.GetUser(chatId: chat.Id)?.ChatId != chat.Id) { // if not, tell them var reqAction3 = new SendMessage(chatId: chat.Id, text: "You are not registered"); Bot.MakeRequestAsync(request: reqAction3); return; } // get all user nodes var userNodes = NodeUtils.GetNodeByUser(chatId: chat.Id); // delete any nodes submitted NodeUtils.DeleteNode(chatId: chat.Id, nodes: result.ToList()); // delete any associated deposit accounts that would have been automatically registered AccountUtils.DeleteAccount(chatId: chat.Id, accounts: userNodes.Where(predicate: y => AccountUtils.GetAccountByUser(chatId: chat.Id) .Any(predicate: x => x.EncodedAddress == y.DepositAddress)) .Where(predicate: y => result.Any(predicate: x => x == y.IP)) .Select(selector: acc => acc.DepositAddress).ToList()); } catch (Exception) { msg2 = "Something went wrong. Please try again. If the problem persists, please notify kodtycoon"; } // send a message to notify user of any changes var reqAction2 = new SendMessage(chatId: chat.Id, text: msg2); Bot.MakeRequestAsync(request: reqAction2); } } catch (Exception ex) { Console.WriteLine(ex.StackTrace); } }, 1); }
internal async void RunBot() { var snodeClient = new SupernodeClient(); try { // get access key from congif var Bot = new TelegramBot(accessToken: ConfigurationManager.AppSettings[name: "accessKey"]); // insert access token // get "me" var me = Bot.MakeRequestAsync(request: new GetMe()).Result; // if me is null, connection failed, maybe incorrect access token if (me == null) { Console.WriteLine(value: "GetMe() FAILED. Do you forget to add your AccessToken to App.config?"); Console.WriteLine(value: "(Press ENTER to quit)"); Console.ReadLine(); return; } // print out that connection worked Console.WriteLine(format: "{0} (@{1}) connected!", arg0: me.FirstName, arg1: me.Username); Console.WriteLine(); Console.WriteLine(format: "Find @{0} in Telegram and send him a message - it will be displayed here", arg0: me.Username); Console.WriteLine(value: "(Press ENTER to stop listening and quit)"); // set message update offset long offset = 0; // run continuously while (!stopMe) { Update[] updates; try { updates = Bot.MakeRequestAsync(request: new GetUpdates() { Offset = offset }).Result; } catch (Exception) { Bot = new TelegramBot(accessToken: ConfigurationManager.AppSettings[name: "accessKey"]); continue; } // if none, start next iteration of the loop if (updates == null) { continue; } // repeat following for each update foreach (var update in updates) { // declare the first update as checked offset = update.UpdateId + 1; // get the message text var text = update.Message?.Text; // if empty or null, reiterate loop if (string.IsNullOrEmpty(value: text)) { continue; } // if message is to register or unregister a node do the following if (text.StartsWith(value: "/registerNode:") && text != "/registerNode:" || text.StartsWith(value: "/unregisterNode:") && text != "/unregisterNode:") { // send message to let the user know the bot is working var reqAction = new SendMessage(chatId: update.Message.Chat.Id, text: "One moment please.."); await Bot.MakeRequestAsync(request : reqAction); var t = Task.Run( action: () => new NodeManagement().ManageNodes(chat: update.Message.Chat, text: text)); continue; } if (text == "/dailySummary" || text == "/sevenDaySummary" || text == "/thirtyOneDaySummary" || text.StartsWith(value: "/customSummary:")) { var t = Task.Run( action: () => SummaryCreator.GetSummary(text: text, chat: update.Message.Chat)); continue; } // if a user wants to register an account, not linked to a supernode if (text.StartsWith(value: "/registerAccount:") && text != "/registerAccount:") { var t = Task.Run(action: () => new AccountTask().RegisterAccounts(message: update.Message)); continue; } // if a user wants to unregister an account if (text.StartsWith(value: "/unregisterAccount:") && text != "/unregisterAccount:") { var t = Task.Run( action: () => new AccountTask().UnregisterAccount(message: update.Message, text: text)); continue; } if (text.StartsWith(value: "/optInTxsAcc:") && text != "/optInTxsAcc:") { OptIOAccountUtils.OptInTx(message: update.Message); continue; } if (text.StartsWith(value: "/optOutTxsAcc:") && text != "/optOutTxsAcc:") { OptIOAccountUtils.OptOutTx(message: update.Message); continue; } if (text.StartsWith(value: "/optInHarvestingAcc:") && text != "/optInHarvestingAcc:") { OptIOAccountUtils.OptInHarvesting(message: update.Message); continue; } if (text.StartsWith(value: "/optOutHarvestingAcc:") && text != "/optOutHarvestingAcc:") { OptIOAccountUtils.OptOutHarvesting(message: update.Message); continue; } switch (text) { case "/registerAccount:": { var reqAction = new SendMessage(chatId: update.Message.Chat.Id, text: "To register an account, use the command \"/registerAccount:\" followed by a comma delimited list of accounts"); Bot.MakeRequestAsync(request: reqAction); continue; } case "/unregisterAccount:": { var reqAction = new SendMessage(chatId: update.Message.Chat.Id, text: "To unregister an account, use the commmand \"/unregisterAccount:\" followed by a comma delimited list of accounts"); Bot.MakeRequestAsync(request: reqAction); continue; } case "/registerNode:": { var reqAction = new SendMessage(chatId: update.Message.Chat.Id, text: "To register a node, use the command \"/registerNode:\" followed by a comma delimited list of IP addresses. Addresses consisting of characters are also supported. eg. bob.nem.ninja"); Bot.MakeRequestAsync(request: reqAction); continue; } case "/unregisterNode:": { var reqAction = new SendMessage(chatId: update.Message.Chat.Id, text: "To unregister a node, use the commmand \"/unregisterNode:\" followed by a comma delimited list of IP addresses"); Bot.MakeRequestAsync(request: reqAction); continue; } case "/deleteAccount": { UserUtils.DeleteUser(update.Message.Chat.Id); var reqAction = new SendMessage(chatId: update.Message.Chat.Id, text: "You Account has been removed"); Bot.MakeRequestAsync(request: reqAction); continue; } case "/start": { UserUtils.AddUser(userName: update.Message.From.Username, chatId: update.Message.Chat.Id); var reqAction = new SendMessage(chatId: update.Message.Chat.Id, text: "Hello. \n\n" + "Please start by registering a supernode or NEM acccount. \n" + "When you register a supernode, the deposit account of the supernode is" + " automatically registered under your username and you will start to " + "recieve notifications about failed supernode tests, any transactions " + "associated with the deposit account as well as any blocks the deposit account of each node harvests\n\n" + "If you dont want to get notifications about the supernode depsoit account, simply unregister the " + "account by using the \"/unregisterAccount:\" command followed by the account address you wish to unregister." + "This does not unregister your supernode, rather, only the deposit account associated with it\n\n" + "You can also in opt out of specific notification types for each node or NEM account you have registered. " + "Check out the \"/optIO\" command for more details. You are automatically opted in for all notifications when you register a node or nem account.\n\n" + "Use the \"/myDetails\" command to see the nodes and accounts you have registered, what notifications they are signed up for and some additional information. \n\n" ) { ReplyMarkup = KeyBoards.MainMenu }; Bot.MakeRequestAsync(request: reqAction); continue; } case "/myDetails": { var req = new SendMessage(chatId: update.Message.Chat.Id, text: "One moment please.."); Bot.MakeRequestAsync(request: req); var t = Task.Run(action: () => new MyDetailsTask().ReturnMyDetails(message: update.Message)); continue; } case "/summary": { var req = new SendMessage(chatId: update.Message.Chat.Id, text: "Use the commands below to generate a summary for your accounts. " + "Include a number after custom summary to get a summary of any given" + " days up to the current day") { ReplyMarkup = KeyBoards.SummaryMenu }; Bot.MakeRequestAsync(request: req); continue; } case "/help": { var req = new SendMessage(chatId: update.Message.Chat.Id, text: "https://blog.nem.io/nem-chain-supernode-notifications-telegram-bot/") { ReplyMarkup = KeyBoards.MainMenu }; Bot.MakeRequestAsync(request: req); continue; } case "/back": { var req = new SendMessage(chatId: update.Message.Chat.Id, text: "Main menu") { ReplyMarkup = KeyBoards.MainMenu }; Bot.MakeRequestAsync(request: req); continue; } case "/optIO": { var req = new SendMessage(chatId: update.Message.Chat.Id, text: "Use any of the commands below to opt in or out of any particular notification types. " + "You can either opt in or out of notification types globally for all accounts registered to you" + " or selectively per account.") { ReplyMarkup = KeyBoards.OptMenu }; Bot.MakeRequestAsync(request: req); continue; } case "/optInTxsAcc:": { var req = new SendMessage(chatId: update.Message.Chat.Id, text: "To opt into transaction notifications for a given account or accounts, use the \"/optInTxsAcc:\" command, " + "followed by a list of comma delimeted addresses "); Bot.MakeRequestAsync(request: req); continue; } case "/optOutTxsAcc:": { var req = new SendMessage(chatId: update.Message.Chat.Id, text: "To opt out of transaction notifications for a given account or accounts, " + "use the \"/optOutTxsAcc:\" command, followed by a list of comma delimeted addresses "); Bot.MakeRequestAsync(request: req); continue; } case "/optInHarvestingAcc:": { var req = new SendMessage(chatId: update.Message.Chat.Id, text: "To opt into harvesting notifications for a given account or accounts, " + "use the \"/optInHarvestingAcc:\" command, followed by a list of comma delimeted addresses "); Bot.MakeRequestAsync(request: req); continue; } case "/optOutHarvestingAcc:": { var req = new SendMessage(chatId: update.Message.Chat.Id, text: "To opt out of harvesting notifications for a given account or accounts, " + "use the \"/optOutHarvestingAcc:\" command, followed by a list of comma delimeted addresses "); Bot.MakeRequestAsync(request: req); continue; } case "/optInTxsGlobal": { var accs = AccountUtils.GetAccountByUser(chatId: update.Message.Chat.Id); foreach (var acc in accs) { acc.CheckTxs = true; } AccountUtils.UpdateAccount(accs: accs, user: update.Message.Chat.Id); var req = new SendMessage(chatId: update.Message.Chat.Id, text: "You have opted into transaction notifications"); Bot.MakeRequestAsync(request: req); continue; } case "/optOutTxsGlobal": { var accs = AccountUtils.GetAccountByUser(chatId: update.Message.Chat.Id); foreach (var acc in accs) { acc.CheckTxs = false; } AccountUtils.UpdateAccount(accs: accs, user: update.Message.Chat.Id); var req = new SendMessage(chatId: update.Message.Chat.Id, text: "You have opted out of transaction notifications"); Bot.MakeRequestAsync(request: req); continue; } case "/optInHarvestingGlobal": { var accs = AccountUtils.GetAccountByUser(chatId: update.Message.Chat.Id); foreach (var acc in accs) { acc.CheckBlocks = true; } AccountUtils.UpdateAccount(accs: accs, user: update.Message.Chat.Id); var req = new SendMessage(chatId: update.Message.Chat.Id, text: "You have opted into harvesting notifications"); Bot.MakeRequestAsync(request: req); continue; } case "/optOutHarvestingGlobal": { var accs = AccountUtils.GetAccountByUser(chatId: update.Message.Chat.Id); foreach (var acc in accs) { acc.CheckBlocks = false; } AccountUtils.UpdateAccount(accs: accs, user: update.Message.Chat.Id); var req = new SendMessage(chatId: update.Message.Chat.Id, text: "You have opted out of harvesting notifications"); Bot.MakeRequestAsync(request: req); continue; } case "/harvestingSpace": { var reqAction = new SendMessage(chatId: update.Message.Chat.Id, text: "One moment please.."); Bot.MakeRequestAsync(request: reqAction); var freeNodes = new List <string>(); var nodeClient = new NodeClient(); snodeClient.BeginGetSupernodes(ar => { var r = new Random(); for (var index = r.Next(minValue: 0, maxValue: 320); index < 400; index++) { var node = ar.Content.data[index: index]; nodeClient.Connection.SetHost(host: node.ip); nodeClient.BeginGetUnlockedInfo(ar2 => { if (ar2.Content.NumUnlocked < ar2.Content.MaxUnlocked) { freeNodes.Add(item: node.ip); } }).AsyncWaitHandle.WaitOne(); if (freeNodes.Count == 3) { break; } } var message = string.Join(separator: "\n", values: freeNodes); var req = new SendMessage(chatId: update.Message.Chat.Id, text: message); Bot.MakeRequestAsync(request: req); }, 1); continue; } default: { var req = new SendMessage(chatId: update.Message.Chat.Id, text: "Main menu") { ReplyMarkup = KeyBoards.MainMenu }; Bot.MakeRequestAsync(request: req); continue; } } } } } catch (Exception e) { Console.WriteLine("tele scanner line 478 " + e.StackTrace); } }