Program.cs 10 KB

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