Program.cs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  1. using System;
  2. using System.Linq;
  3. using System.Threading.Tasks;
  4. using Telegram.Bot;
  5. using Telegram.Bot.Args;
  6. using Telegram.Bot.Types;
  7. using Telegram.Bot.Types.Enums;
  8. using System.Net.Http;
  9. using System.Threading;
  10. using EFDatabase;
  11. using Microsoft.EntityFrameworkCore;
  12. using Quartz;
  13. using Quartz.Impl;
  14. namespace EthermineBotTelegramCore
  15. {
  16. partial class Program
  17. {
  18. static ITelegramBotClient botClient;
  19. static botdb Botdb;
  20. private static async Task Main(string[] args)
  21. {
  22. botClient = new TelegramBotClient("1785154817:AAGhXD9yQVn9HPdWTcmGJUBeZ8nA50SzHbY");
  23. var me = botClient.GetMeAsync().Result;
  24. {
  25. string message = $"Hello, World! I am user {me.Id} and my name is {me.FirstName}.";
  26. Console.WriteLine(message);
  27. await Logger.LogInfo(message);
  28. }
  29. //enter credentials for DB
  30. if (args.Length >= 2)
  31. {
  32. AppSettings.user = args[0];
  33. AppSettings.password = args[1];
  34. }
  35. else
  36. {
  37. Console.Out.Write("User:");
  38. AppSettings.user = Console.ReadLine();
  39. Console.Out.Write("Password:");
  40. AppSettings.password = Console.ReadLine();
  41. }
  42. //init DB
  43. Botdb = new botdb();
  44. if (Botdb.Database.CanConnect())
  45. {
  46. // Grab the Scheduler instance from the Factory
  47. StdSchedulerFactory factory = new StdSchedulerFactory();
  48. IScheduler scheduler = await factory.GetScheduler();
  49. // and start it off
  50. await scheduler.Start();
  51. // define the job and tie it to our HelloJob class
  52. IJobDetail job = JobBuilder.Create<DataUpdater>()
  53. .WithIdentity("job1", "group1")
  54. .UsingJobData("connectionString", "server=" + AppSettings.dbIp + ";port=3306;database=botdb;uid=" + AppSettings.user + "; pwd=" + AppSettings.password)
  55. .Build();
  56. // Trigger the job to run now, and then repeat it
  57. ITrigger trigger = TriggerBuilder.Create()
  58. .WithIdentity("trigger1", "group1")
  59. .StartNow()
  60. .WithSimpleSchedule(x => x
  61. .WithIntervalInSeconds(240)
  62. .RepeatForever())
  63. .Build();
  64. // Tell quartz to schedule the job using our trigger
  65. await scheduler.ScheduleJob(job, trigger);
  66. {
  67. string message = "Scheduler started!";
  68. Console.WriteLine(message);
  69. await Logger.LogInfo(message);
  70. }
  71. Thread.Sleep(5000);
  72. //start receive messages
  73. botClient.OnMessage += BotOnMessage;
  74. botClient.StartReceiving();
  75. Console.WriteLine("Press any key to exit");
  76. Console.ReadKey();
  77. Logger.Stop();
  78. await scheduler.Shutdown();
  79. botClient.StopReceiving();
  80. }
  81. else
  82. {
  83. string message = "Don't connected! Check auth data and restart!";
  84. Console.WriteLine(message);
  85. await Logger.LogError(message);
  86. Logger.Stop();
  87. }
  88. }
  89. private static async void BotOnMessage(object sender, MessageEventArgs e) {
  90. if (e.Message.Text != null)
  91. {
  92. Console.WriteLine($"Received a text message in chat {e.Message.Chat.Id}.");
  93. char[] delimeters = { ' ', '@' };
  94. var message = e.Message;
  95. if (message == null || message.Type != MessageType.Text)
  96. return;
  97. string command = message.Text.Split(delimeters).First();
  98. switch (command)
  99. {
  100. // add user into database
  101. case "/start":
  102. await Logger.LogInfo(
  103. $"Received a text message {command} in chat {e.Message.Chat.Id}.");
  104. AddUser(e.Message.Chat);
  105. break;
  106. // add user into database
  107. case "/stop":
  108. await Logger.LogInfo(
  109. $"Received a text message {command} in chat {e.Message.Chat.Id}.");
  110. DeleteUser(e.Message.Chat);
  111. break;
  112. // connect wallet to user
  113. case "/setwallet":
  114. await Logger.LogInfo(
  115. $"Received a text message {command} in chat {e.Message.Chat.Id}.");
  116. SetWallet(e);
  117. break;
  118. // get actual data from ethermine
  119. case "/actual":
  120. await Logger.LogInfo(
  121. $"Received a text message {command} in chat {e.Message.Chat.Id}.");
  122. if (message.Text.Split(' ').Length > 1)
  123. GetActualData(e);
  124. else
  125. GetActualDataFromDatabase(e.Message.Chat);
  126. break;
  127. // get actual data from ethermine
  128. case "/rate":
  129. await Logger.LogInfo(
  130. $"Received a text message {message.Text.Split(delimeters).First()} in chat {e.Message.Chat.Id}.");
  131. GetActualRate(e);
  132. break;
  133. // send help
  134. case "/help":
  135. await Logger.LogInfo(
  136. $"Received a text message {message.Text.Split(delimeters).First()} in chat {e.Message.Chat.Id}.");
  137. await SendHelp(e.Message.Chat);
  138. break;
  139. // send last payout
  140. case "/lastpayout":
  141. await Logger.LogInfo(
  142. $"Received a text message {message.Text.Split(delimeters).First()} in chat {e.Message.Chat.Id}.");
  143. await GetLastPayout(e.Message.Chat);
  144. break;
  145. default:
  146. if (e.Message.Chat.Id > 0)
  147. await botClient.SendTextMessageAsync(
  148. chatId: e.Message.Chat,
  149. text: "Incorrect message");
  150. break;
  151. }
  152. }
  153. }
  154. //send reauest to pool api and gets back json than parse it and send message with data from it
  155. private static async void GetActualData(MessageEventArgs e)
  156. {
  157. try
  158. {
  159. var url = AppSettings.poolApiUrl + "/miner/" + e.Message.Text.Split(' ')[1] + "/currentStats";
  160. var currnentStats = JsonDownloader._download_serialized_json_data<JsonCurrentStats>(url);
  161. await botClient.SendTextMessageAsync(
  162. chatId: e.Message.Chat,
  163. text: "Updated: " + DateTimeOffset.FromUnixTimeSeconds(currnentStats.data.time).LocalDateTime
  164. .ToString("f") + "\n"
  165. + "Reported Hashrate: " + Math.Round(currnentStats.data.reportedHashrate / 1000000D, 3) +
  166. " MH/s\n"
  167. + "Current Hashrate: " + Math.Round(currnentStats.data.currentHashrate / 1000000D, 3) +
  168. " MH/s\n"
  169. + "Valid Shares: " + currnentStats.data.validShares + "\n"
  170. + "Stale Shares: " + currnentStats.data.staleShares + "\n"
  171. + "Workers: " + currnentStats.data.activeWorkers + "\n"
  172. + "Unpaid Balance: " + Math.Round(currnentStats.data.unpaid / Math.Pow(10, 18), 5) + AppSettings.currency + "\n");
  173. }
  174. catch (Exception exception)
  175. {
  176. await Console.Out.WriteLineAsync("An exception occurred while executing /actual command. See log file to get full info.");
  177. await Logger.LogError("An exception occurred while executing /actual command.");
  178. await Logger.LogError(exception.Message);
  179. await Logger.LogError(exception.Source);
  180. await Logger.LogError(exception.StackTrace);
  181. await botClient.SendTextMessageAsync(
  182. chatId: e.Message.Chat,
  183. text: "An exception occurred while executing this command.");
  184. }
  185. }
  186. //get last data from tables miners and workers from DB and send message to user
  187. private static async void GetActualDataFromDatabase(Chat e)
  188. {
  189. try
  190. {
  191. var wallet = Botdb.users
  192. .Where(u => u.chat_id == e.Id)
  193. .Select(u => u.wallet)
  194. .FirstOrDefault();
  195. if (wallet != null)
  196. {
  197. var lastMinerRecord = Botdb.miners
  198. .Where(w => w.wallet == wallet)
  199. .OrderByDescending(w => w.time)
  200. .FirstOrDefault();
  201. if (lastMinerRecord != null)
  202. {
  203. //var lastWorkerRecord = new workers();
  204. long lastTime = Botdb.workers
  205. .Where(w => w.wallet == wallet)
  206. .Max(w => w.time);
  207. var lastWorkerRecord = Botdb.workers
  208. .Where(w => w.wallet == wallet && w.time == lastTime)
  209. .OrderByDescending(w => w.time)
  210. .ToList();
  211. if (lastWorkerRecord.First() != null)
  212. {
  213. await botClient.SendTextMessageAsync(
  214. chatId: e,
  215. text: $"Miner {lastMinerRecord.wallet} stats:\n" +
  216. "Updated: " + DateTimeOffset.FromUnixTimeSeconds(lastMinerRecord.time)
  217. .LocalDateTime
  218. .ToString("f") + "\n"
  219. + "Reported Hashrate: " + Math.Round(lastMinerRecord.reported_hashrate / 1000000D, 3) + " MH/s\n"
  220. + "Current Hashrate: " + Math.Round(lastMinerRecord.current_hashrate / 1000000D, 3) + " MH/s\n"
  221. + "Valid Shares: " + lastMinerRecord.valid_shares + "\n"
  222. + "Stale Shares: " + lastMinerRecord.stale_shares + "\n"
  223. + "Workers: " + lastMinerRecord.workers + "\n"
  224. + "Unpaid Balance: " + Math.Round(lastMinerRecord.unpaid / Math.Pow(10, 18), 5) + AppSettings.currency +
  225. "\n");
  226. for (int i = 0; i < lastWorkerRecord.Count; i++)
  227. {
  228. Thread.Sleep(1000);
  229. if (i!=0 && i%20 == 0) //TODO SOMETIHNG BETTER THAN USUAL TIMER
  230. Thread.Sleep(30000);
  231. try
  232. {
  233. await botClient.SendTextMessageAsync(
  234. chatId: e,
  235. text: $"Worker {lastWorkerRecord[i].worker} stats:\n" +
  236. "Updated: " + DateTimeOffset.FromUnixTimeSeconds(lastWorkerRecord[i].time)
  237. .LocalDateTime
  238. .ToString("f") + "\n"
  239. + "Reported Hashrate: " + Math.Round(lastWorkerRecord[i].reported_hashrate / 1000000D, 3) + " MH/s\n"
  240. + "Current Hashrate: " + Math.Round(lastWorkerRecord[i].current_hashrate / 1000000D, 3) + " MH/s\n"
  241. + "Valid Shares: " + lastWorkerRecord[i].valid_shares + "\n"
  242. + "Stale Shares: " + lastWorkerRecord[i].stale_shares + "\n"
  243. + "Unpaid Balance: " + Math.Round(lastWorkerRecord[i].worker_unpaid / Math.Pow(10, 18), 5) + AppSettings.currency +
  244. "\n");
  245. }
  246. catch (HttpRequestException exception)
  247. {
  248. await Console.Out.WriteLineAsync("An exception occurred on sending messages while executing /actual command.");
  249. await Logger.LogError(exception.Message);
  250. await Logger.LogError(exception.Source);
  251. await Logger.LogError(exception.StackTrace);
  252. }
  253. }
  254. }
  255. else
  256. {
  257. await botClient.SendTextMessageAsync(
  258. chatId: e,
  259. text: "No workers data for now!");
  260. }
  261. }
  262. else
  263. {
  264. await botClient.SendTextMessageAsync(
  265. chatId: e,
  266. text: "No miner data for now!");
  267. }
  268. }
  269. else
  270. {
  271. await botClient.SendTextMessageAsync(
  272. chatId: e,
  273. text: "Set wallet at first! Use /setwallet");
  274. }
  275. }
  276. catch (Exception exception)
  277. {
  278. await Console.Out.WriteLineAsync("An exception occurred while executing /actual command. See log file to get full info.");
  279. await Logger.LogError("An exception occurred while executing /actual command.");
  280. await Logger.LogError(exception.Message);
  281. await Logger.LogError(exception.Source);
  282. await Logger.LogError(exception.StackTrace);
  283. await botClient.SendTextMessageAsync(
  284. chatId: e,
  285. text: "An exception occurred while executing this command.");
  286. }
  287. }
  288. private static async void GetActualRate(MessageEventArgs e)
  289. {
  290. try
  291. {
  292. var url = AppSettings.poolApiUrl + "/networkStats";
  293. var networkStats = JsonDownloader._download_serialized_json_data<JsonNetworkStats>(url);
  294. await botClient.SendTextMessageAsync(
  295. chatId: e.Message.Chat,
  296. text: "ETH: " + Math.Round(networkStats.data.usd, 2) + "\n"
  297. + "BTC: " + Math.Round(networkStats.data.usd / networkStats.data.btc, 2)
  298. );
  299. }
  300. catch (Exception exception)
  301. {
  302. await Console.Out.WriteLineAsync("An exception occurred while executing /rate command. See log file to get full info.");
  303. await Logger.LogError("An exception occurred while executing /rate command.");
  304. await Logger.LogError(exception.Message);
  305. await Logger.LogError(exception.Source);
  306. await Logger.LogError(exception.StackTrace);
  307. await botClient.SendTextMessageAsync(
  308. chatId: e.Message.Chat,
  309. text: "An exception occurred while executing this command.");
  310. }
  311. }
  312. private static async void AddUser(Chat e)
  313. {
  314. try
  315. {
  316. if (Botdb.users.Where(users => users.chat_id == e.Id).FirstOrDefault() == null)
  317. {
  318. var newuser = new users();
  319. newuser.chat_id = e.Id;
  320. Botdb.users.Add(newuser);
  321. Botdb.SaveChanges();
  322. await botClient.SendTextMessageAsync(
  323. chatId: e,
  324. text: "Added new user to database. Now you can connect your miner wallet using command /setwallet <address>");
  325. }
  326. else
  327. {
  328. await botClient.SendTextMessageAsync(
  329. chatId: e,
  330. text: "Already registered");
  331. }
  332. }
  333. catch (Exception exception)
  334. {
  335. await Console.Out.WriteLineAsync("An exception occurred while executing /start command. See log file to get full info.");
  336. await Logger.LogError("An exception occurred while executing /start command.");
  337. await Logger.LogError(exception.Message);
  338. await Logger.LogError(exception.Source);
  339. await Logger.LogError(exception.StackTrace);
  340. await botClient.SendTextMessageAsync(
  341. chatId: e,
  342. text: "An exception occurred while executing this command.");
  343. }
  344. }
  345. private static async void SetWallet(MessageEventArgs e)
  346. {
  347. try
  348. {
  349. if (Botdb.users.Where(u => u.chat_id == e.Message.Chat.Id).FirstOrDefault() != null)
  350. {
  351. if (e.Message.Text.Split(' ')[1].Length > 2)
  352. {
  353. if (e.Message.Text.Split(' ')[1].Contains("0x"))
  354. {
  355. Botdb.users.Where(u => u.chat_id == e.Message.Chat.Id).FirstOrDefault().wallet =
  356. e.Message.Text.Split(' ')[1];
  357. }
  358. else
  359. {
  360. Botdb.users.Where(u => u.chat_id == e.Message.Chat.Id).FirstOrDefault().wallet =
  361. "0x" + e.Message.Text.Split(' ')[1];
  362. }
  363. await Botdb.SaveChangesAsync();
  364. await botClient.SendTextMessageAsync(
  365. chatId: e.Message.Chat,
  366. text: $"Wallet {"0x" + e.Message.Text.Split(' ')[1]} set!");
  367. }
  368. else
  369. {
  370. await botClient.SendTextMessageAsync(
  371. chatId: e.Message.Chat,
  372. text: "Too short!");
  373. }
  374. //Botdb.SaveChanges();
  375. }
  376. else
  377. {
  378. await botClient.SendTextMessageAsync(
  379. chatId: e.Message.Chat,
  380. text: "You not registered! Type /start first!");
  381. }
  382. }
  383. catch (Exception exception)
  384. {
  385. await Console.Out.WriteLineAsync("An exception occurred while executing /setwallet command. See log file to get full info.");
  386. await Logger.LogError("An exception occurred while executing /setwallet command.");
  387. await Logger.LogError(exception.Message);
  388. await Logger.LogError(exception.Source);
  389. await Logger.LogError(exception.StackTrace);
  390. await botClient.SendTextMessageAsync(
  391. chatId: e.Message.Chat,
  392. text: "An exception occurred while executing this command.");
  393. }
  394. }
  395. static async void DeleteUser(Chat e)
  396. {
  397. try
  398. {
  399. if (Botdb.users.Where(users => users.chat_id == e.Id).FirstOrDefault() != null)
  400. {
  401. var deletableWallet = Botdb.users.Where(u => u.chat_id == e.Id).First().wallet;
  402. if (Botdb.users.Where(u => u.wallet == deletableWallet).Count() > 1)
  403. {
  404. Botdb.users.RemoveRange(Botdb.users.Where(u=> u.chat_id == e.Id));
  405. }
  406. else
  407. {
  408. Botdb.workers.RemoveRange(Botdb.workers.Where(w=> w.wallet == deletableWallet));
  409. Botdb.miners.RemoveRange(Botdb.miners.Where(m=> m.wallet == deletableWallet));
  410. Botdb.payouts.RemoveRange(Botdb.payouts.Where(p=> p.wallet == deletableWallet));
  411. Botdb.users.RemoveRange(Botdb.users.Where(u=> u.chat_id == e.Id));
  412. }
  413. await Botdb.SaveChangesAsync();
  414. await botClient.SendTextMessageAsync(
  415. chatId: e,
  416. text: "Done!");
  417. }
  418. else
  419. {
  420. await botClient.SendTextMessageAsync(
  421. chatId: e,
  422. text: "Already deleted");
  423. }
  424. }
  425. catch (Exception exception)
  426. {
  427. await Console.Out.WriteLineAsync("An exception occurred while executing /delete command. See log file to get full info.");
  428. await Logger.LogError("An exception occurred while executing /delete command.");
  429. await Logger.LogError(exception.Message);
  430. await Logger.LogError(exception.Source);
  431. await Logger.LogError(exception.StackTrace);
  432. await botClient.SendTextMessageAsync(
  433. chatId: e,
  434. text: "An exception occurred while executing this command.");
  435. }
  436. }
  437. //gets data from pool API in json, calculates unpaid for each worker and adds it to DB
  438. //public static async Task UpdateData()
  439. static async Task SendHelp(Chat e)
  440. {
  441. try
  442. {
  443. await botClient.SendTextMessageAsync(
  444. chatId: e,
  445. text: $"This is bot tracks your miner stats and calculates unpaid per worker.\n"
  446. + $"How to start:\n"
  447. + $"1) \"/start\" - it will add you to database\n"
  448. + $"2) \"/setwallet <wallet>\" - it will set wallet for tracking, bot will start to add info about your miner and workers to database\n"
  449. + $"3) \"/actual\" - it will send you up to date data about your worker\n"
  450. + $"4) \"/lastpayout\" - it will send you last payout data with calculated worker unpaid for that period if avaliable\n"
  451. + $"5) \"/stop\" - it will clear all data about you from database\n"
  452. + $"Additional commands:\n"
  453. + $"\"/rate\" - get actual ETH and BTC rate from ethermine\n"
  454. + $"\"/actual <wallet>\" - get up to date data about any wallet without unpaid per worker\n");
  455. }
  456. catch (Exception exception)
  457. {
  458. await Console.Out.WriteLineAsync("An exception occurred while executing /help command. See log file to get full info.");
  459. await Logger.LogError(exception.Message);
  460. await Logger.LogError(exception.Source);
  461. await Logger.LogError(exception.StackTrace);
  462. await botClient.SendTextMessageAsync(
  463. chatId: e,
  464. text: "An exception occurred while executing this command.");
  465. }
  466. }
  467. static async Task GetLastPayout(Chat e)
  468. {
  469. try
  470. {
  471. var wallet = Botdb.users
  472. .Where(u => u.chat_id == e.Id)
  473. .Select(u => u.wallet)
  474. .FirstOrDefault();
  475. if (wallet != null)
  476. {
  477. //TODO rewrite this
  478. long payoutTime;
  479. try
  480. {
  481. payoutTime = Botdb.payouts
  482. .Where(p => p.wallet == wallet)
  483. .OrderByDescending(p => p.time)
  484. .Select(p => p.time)
  485. .MaxAsync().Result;
  486. }
  487. catch (Exception exception)
  488. {
  489. string message = $"No payouts data for {wallet}! Time is set to 0!";
  490. await Console.Out.WriteLineAsync(message);
  491. await Logger.LogWarn(message);
  492. //await Logger.LogError(exception.Message);
  493. //await Logger.LogError(exception.Source);
  494. //await Logger.LogError(exception.StackTrace);
  495. payoutTime = 0;
  496. }
  497. var dbPayoutRecords = Botdb.payouts
  498. .Where(p => p.wallet == wallet && p.time == payoutTime)
  499. .OrderByDescending(p => p.time);
  500. if (dbPayoutRecords.FirstOrDefault() != null)
  501. {
  502. string message = "Payout date: " +
  503. DateTimeOffset.FromUnixTimeSeconds(dbPayoutRecords.First().time).LocalDateTime
  504. .ToString("f") + "\n" + "Amount: " +
  505. Math.Round(dbPayoutRecords.First().amount / 1000000000000000000D, 5) + AppSettings.currency + "\n";
  506. foreach (var payoutRecord in dbPayoutRecords)
  507. {
  508. message +=
  509. $"Worker {payoutRecord.worker} paid: {Math.Round(payoutRecord.worker_amount / 1000000000000000000D, 5)} {AppSettings.currency}\n";
  510. }
  511. message += "Data source: Bot database \n";
  512. await botClient.SendTextMessageAsync(
  513. chatId: e,
  514. text: message);
  515. }
  516. else
  517. {
  518. var url = AppSettings.poolApiUrl + "/miner/" + wallet + "/payouts";
  519. var payouts = JsonDownloader._download_serialized_json_data<JsonPayouts>(url);
  520. await botClient.SendTextMessageAsync(
  521. chatId: e,
  522. text: "Payout date: " + DateTimeOffset.FromUnixTimeSeconds(payouts.data[0].paidOn).LocalDateTime.ToString("f") + "\n"
  523. + "Amount: " + Math.Round(payouts.data[0].amount / 1000000000000000000D, 5) + AppSettings.currency + "\n"
  524. + "Data source: Ethermine API \n");
  525. }
  526. }
  527. else
  528. {
  529. await botClient.SendTextMessageAsync(
  530. chatId: e,
  531. text: "Set wallet at first! Use /setwallet");
  532. }
  533. }
  534. catch (Exception exception)
  535. {
  536. await Console.Out.WriteLineAsync("An exception occurred while executing /lastpayout command. See log file to get full info.");
  537. await Logger.LogError(exception.Message);
  538. await Logger.LogError(exception.Source);
  539. await Logger.LogError(exception.StackTrace);
  540. await botClient.SendTextMessageAsync(
  541. chatId: e,
  542. text: "An exception occurred while executing this command.");
  543. }
  544. }
  545. }
  546. }