Program.cs 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. using System;
  2. using System.Diagnostics;
  3. using System.Threading.Tasks;
  4. using DiscordBot;
  5. using RestSharp;
  6. using System.Collections.Generic;
  7. using System.Threading;
  8. using System.Text;
  9. using System.Linq;
  10. using TFABot.Git;
  11. using LibGit2Sharp;
  12. using System.Reflection;
  13. namespace TFABot
  14. {
  15. public class Program
  16. {
  17. static enumRunState RunState = enumRunState.Run;
  18. public enum enumRunState : int
  19. {
  20. Stop=0,
  21. Run=1,
  22. Restart=2,
  23. Update=3,
  24. PreviousVersion=4,
  25. MonoArgs=5,
  26. Error = 100
  27. }
  28. static uint AlarmOffWarningMinutes=30;
  29. static public Dictionary<string,string> SettingsList = new Dictionary<string, string>();
  30. static public Dictionary<string,clsUser> UserList = new Dictionary<string, clsUser>();
  31. static public Dictionary<string,clsNetwork> NetworkList = new Dictionary<string, clsNetwork>();
  32. static public Dictionary<string,clsNode> NodesList = new Dictionary<string, clsNode>();
  33. static public Dictionary<string,clsNodeGroup> NodeGroupList = new Dictionary<string, clsNodeGroup>();
  34. static public Dictionary<string,clsNotificationPolicy> NotificationPolicyList = new Dictionary<string, clsNotificationPolicy>();
  35. static public DateTime AppStarted = DateTime.UtcNow;
  36. static public clsAlarmManager AlarmManager = new clsAlarmManager();
  37. static public ManualResetEvent ApplicationHold = new ManualResetEvent(false);
  38. static public clsSpreadsheet Spreadsheet;
  39. static public clsBotClient Bot;
  40. static public String BotURL {get; private set;}
  41. static public String BotName;
  42. public enum EnumAlarmState { Off, On, Silent }
  43. static public DateTime AlarmOffTime;
  44. static public uint AlarmOffWarningMultiplier;
  45. static public DateTime? AlarmStateTimeout;
  46. static public EnumAlarmState _alarmState = EnumAlarmState.On;
  47. static public EnumAlarmState AlarmState
  48. { get
  49. {
  50. return _alarmState;
  51. }
  52. private set
  53. {
  54. if (_alarmState != value)
  55. {
  56. _alarmState = value;
  57. if (value == EnumAlarmState.Off) //New state off
  58. {
  59. AlarmOffTime = DateTime.UtcNow;
  60. AlarmOffWarningMultiplier=0;
  61. }
  62. else if (value == EnumAlarmState.On) //New state on
  63. {
  64. AlarmStateTimeout = null;
  65. }
  66. }
  67. }
  68. }
  69. public static int Main(string[] args)
  70. {
  71. AlarmState = EnumAlarmState.On;
  72. try
  73. {
  74. Console.WriteLine($"Git commit: {clsVersion.GitCommitHash}");
  75. if (clsVersion.VersionChangeFlag) Console.WriteLine("NEW VERSION DETECTED");
  76. Console.WriteLine($"ARGS={Environment.CommandLine}");
  77. BotURL = Environment.GetEnvironmentVariable("BOTURL");
  78. if (String.IsNullOrEmpty(BotURL))
  79. {
  80. Console.WriteLine("'BOTURL' Google Spreadsheet URL missing.");
  81. return (int)enumRunState.Error;
  82. }
  83. Console.WriteLine($"URL={BotURL}");
  84. Spreadsheet = new clsSpreadsheet(BotURL);
  85. var log = Spreadsheet.LoadSettings();
  86. Console.WriteLine(log);
  87. SettingsList.TryGetValue("BotName", out BotName);
  88. String value;
  89. if (SettingsList.TryGetValue("AlarmOffWarningMinutes", out value)) uint.TryParse(value,out AlarmOffWarningMinutes);
  90. String DiscordToken;
  91. if (!SettingsList.TryGetValue("Discord-Token", out DiscordToken))
  92. {
  93. Console.WriteLine("Discord-Token not found");
  94. return (int)enumRunState.Error;
  95. }
  96. clsEmail.GetSettings();
  97. Console.WriteLine("Starting monitoring");
  98. const int apiTimeout = 2000;
  99. const int loopWait = 3000;
  100. DateTime LastBotStart = DateTime.UtcNow;
  101. int BotErrorCounter = 0;
  102. using (Bot = new clsBotClient(DiscordToken))
  103. {
  104. Bot.RunAsync();
  105. if (log.Contains("rror:")) Bot.SendAlert($"```{log}```");
  106. while (RunState == enumRunState.Run)
  107. {
  108. //Query every node.
  109. foreach (var node in Program.NodesList.Values.Where(x=>x.Monitor))
  110. {
  111. node.GetHeightAsync(apiTimeout);
  112. }
  113. ApplicationHold.WaitOne(apiTimeout); //Wait for the timeout
  114. foreach (var group in NodeGroupList.Values)
  115. {
  116. group.Monitor();
  117. }
  118. foreach(var network in NetworkList.Values)
  119. {
  120. network.CheckStall();
  121. }
  122. if (AlarmStateTimeout.HasValue)
  123. {
  124. if (AlarmStateTimeout.Value < DateTime.UtcNow) AlarmState = EnumAlarmState.On;
  125. }
  126. else if (AlarmState == EnumAlarmState.Off && (DateTime.UtcNow - AlarmOffTime).TotalMinutes > (AlarmOffWarningMinutes*(AlarmOffWarningMultiplier+1)))
  127. {
  128. Bot.Our_BotAlert.SendMessageAsync($"Warning, the Alarm has been off {(DateTime.UtcNow - AlarmOffTime).TotalMinutes:0} minutes. Forget to reset it?");
  129. AlarmOffWarningMultiplier++;
  130. }
  131. AlarmManager.Process();
  132. //Check the status of the Discord connection. If it disconnects, it doesn't always restart.
  133. if (!Bot.LastHeartbeatd.HasValue || (DateTime.UtcNow - Bot.LastHeartbeatd.Value).TotalSeconds > 90)
  134. {
  135. if ((DateTime.UtcNow - LastBotStart).TotalSeconds > 120)
  136. {
  137. Console.WriteLine("Discord not connected. Restarting.....");
  138. BotErrorCounter++;
  139. if (BotErrorCounter == 2) clsEmail.EmailAlertList("Bot: Discord not connected.");
  140. Bot._client.Dispose();
  141. LastBotStart = DateTime.UtcNow;
  142. Bot = new clsBotClient(DiscordToken);
  143. Bot.RunAsync();
  144. }
  145. }
  146. else
  147. {
  148. BotErrorCounter = 0;
  149. }
  150. ApplicationHold.WaitOne(loopWait);
  151. }
  152. Console.WriteLine($"Exit Code: {RunState} ({(int)RunState})");
  153. switch(RunState)
  154. {
  155. case enumRunState.Update:
  156. Program.Bot.Our_BotAlert.SendMessageAsync("Shutting down to update. Back soon. :grin:").Wait(1000);
  157. break;
  158. case enumRunState.Restart:
  159. Program.Bot.Our_BotAlert.SendMessageAsync("Shutting down to restart. :relieved:").Wait(1000);
  160. break;
  161. case enumRunState.MonoArgs:
  162. Program.Bot.Our_BotAlert.SendMessageAsync("Shutting down to restart in Debug mode. :spy:").Wait(1000);
  163. break;
  164. case enumRunState.Stop:
  165. Program.Bot.Our_BotAlert.SendMessageAsync("Goodbye! :sleeping:").Wait(1000);
  166. break;
  167. }
  168. }
  169. return (int)RunState;
  170. } catch (Exception ex)
  171. {
  172. Console.WriteLine($"ERROR: {ex.Message}");
  173. return (int)enumRunState.Error;
  174. }
  175. }
  176. static public void SendAlert(String message)
  177. {
  178. if (AlarmState == EnumAlarmState.On || AlarmState == EnumAlarmState.Silent)
  179. Bot.Our_BotAlert.SendMessageAsync(message);
  180. }
  181. static public void SetRunState(enumRunState runState)
  182. {
  183. RunState = runState;
  184. ApplicationHold.Set();
  185. }
  186. static public String GetNodes()
  187. {
  188. var cd = new clsColumnDisplay();
  189. cd.AppendCol("Node");
  190. cd.AppendCol("Host");
  191. cd.AppendCol("Ver");
  192. cd.AppendCol("Height");
  193. cd.AppendCol("Ave reply");
  194. cd.AppendCharLine('-');
  195. foreach (var group in NodeGroupList)
  196. {
  197. foreach (var node in NodesList.Values.Where(x=>x.Group == group.Key))
  198. {
  199. node.AppendDisplayColumns(ref cd);
  200. cd.NewLine();
  201. }
  202. }
  203. return cd.ToString();
  204. }
  205. static public void SetAlarmState(EnumAlarmState state, TimeSpan? timeout = null)
  206. {
  207. if (timeout.HasValue) AlarmStateTimeout = DateTime.UtcNow.Add(timeout.Value);
  208. AlarmState = state;
  209. }
  210. }
  211. }