/// <summary> /// Check for dormant chats & plugins to purge /// </summary> public void removeDormantChats() { logging.longOp lo_s = new logging.longOp("Dormant Chat Check", chatData.Count()); Roboto.log.log("Checking for Purgable chats / chat data", logging.loglevel.high, Colors.White, false, true); foreach (chat c in chatData.Where(x => x.lastupdate < DateTime.Now.Subtract(new TimeSpan(purgeInactiveChatsAfterXDays, 0, 0, 0))).ToList()) { //check all plugins and remove data if no longer reqd bool isPurgable = c.tryPurgeData(); //if all plugins are purged, delete the chat if (isPurgable) { Roboto.log.log("Purging all data for chat " + c.chatID); Roboto.Settings.stats.logStat(new statItem("Chats Purged", typeof(Roboto))); chatData.Remove(c); } else { Roboto.log.log("Skipping purge of chat " + c.chatID + " as one or more plugins reported they shouldn't be purged"); } lo_s.addone(); } lo_s.complete(); }
/// <summary> /// Called whenever a longop is updated (either title or value) /// Each row (child grid) should represent a longop. /// very messy /// </summary> /// <param name="longOp"></param> public void addOrUpdateLongOp(logging.longOp longOp) { if (!CheckAccess()) { //call ourselves back via the GUI thread. Dispatcher.Invoke(new Action(() => { addOrUpdateLongOp(longOp); })); } else { //does it exist? bool found = false; foreach (Grid g in grpLongOps.Children) { if (g.Tag == longOp) { updateBar(g); found = true; } } if (!found) { Grid g = new Grid(); g.Width = grpLongOps.Width - 10; g.Height = 25; g.HorizontalAlignment = HorizontalAlignment.Left; g.ColumnDefinitions.Add(new ColumnDefinition()); g.ColumnDefinitions.Add(new ColumnDefinition()); g.RowDefinitions.Add(new RowDefinition()); g.Tag = longOp; updateBar(g); if (longOp.Parent != null) { //get the rowid of the parent int parentPos = grpLongOps.Children.Count - 1; int currentPos = 0; foreach (Grid gParent in grpLongOps.Children) { if (gParent.Tag == longOp.Parent) { parentPos = currentPos; } currentPos++; } //insert after parent grpLongOps.Children.Insert(parentPos + 1, g); } else { //no parent, add at end grpLongOps.Children.Add(g); } } } }
private void updateBar(Grid g) { logging.longOp l = (logging.longOp)g.Tag; if (g.Children.Count == 0) { TextBlock lbl = new TextBlock(); lbl.Text = l.name; if (l.Parent != null) { //indent if has a parent Thickness margin = lbl.Margin; margin.Left = 10; lbl.Margin = margin; } ProgressBar p = new ProgressBar(); p.Maximum = l.totalLength; if (l.CurrentPos > p.Maximum) { p.Maximum = l.CurrentPos; } p.Value = l.CurrentPos; if (l.Parent != null) { //indent if has a parent Thickness margin = p.Margin; margin.Left = 10; p.Margin = margin; } Grid.SetColumn(lbl, 0); g.Children.Add(lbl); Grid.SetColumn(p, 1); g.Children.Add(p); } else { TextBlock lbl = (TextBlock)g.Children[0]; lbl.Text = l.name; ProgressBar p = (ProgressBar)g.Children[1]; p.Maximum = l.totalLength; if (l.CurrentPos > p.Maximum) { p.Maximum = l.CurrentPos; } p.Value = l.CurrentPos; } }
/// <summary> /// Perform any housekeeping / startup checks /// </summary> public void startupChecks() { //TODO - temporary code from 2018 - can be removed. Replace any incorrect namespaces in the datafile. foreach (ExpectedReply er in expectedReplies) { if (er.pluginType != null && er.pluginType.StartsWith("Roboto.")) { er.pluginType = "RobotoChatBot." + er.pluginType.Remove(0, 7); } } //TODO - all these checks should be general housekeeping and run on a schedule!!! logging.longOp lo_modules = new logging.longOp("Module Startup Checks", plugins.Count() * 2); foreach (Modules.RobotoModuleTemplate plugin in plugins) { Roboto.log.log("Startup Checks for " + plugin.ToString(), logging.loglevel.warn); //moduledata and chatData startup checks Roboto.log.log("Checking chatdata for " + plugin.ToString(), logging.loglevel.warn); int i = chatData.Count(); foreach (chat c in chatData) { i--; if (i % 100 == 0) { Roboto.log.log(i.ToString() + " remaining", logging.loglevel.verbose); } c.initPlugins(); if (plugin.pluginChatDataType != null) { RobotoModuleChatDataTemplate cd = c.getPluginData(plugin.pluginChatDataType); if (cd != null) { cd.startupChecks(); } } } Roboto.log.log("Checking coredata for " + plugin.ToString(), logging.loglevel.warn); plugin.getPluginData().startupChecks(); lo_modules.addone(); Roboto.log.log("Checking module for " + plugin.ToString(), logging.loglevel.warn); plugin.startupChecks(); lo_modules.addone(); } lo_modules.complete(); }
public void removeProgressBar(logging.longOp l) { if (!CheckAccess()) { //call ourselves back via the GUI thread. Dispatcher.Invoke(new Action(() => { removeProgressBar(l); })); } else { List <Grid> targets = new List <Grid>(); foreach (Grid g in grpLongOps.Children) { if (g.Tag == l) { targets.Add(g); } } foreach (Grid g in targets) { grpLongOps.Children.Remove(g); } } }
/// <summary> /// Perform any housekeeping / startup checks /// </summary> public void startupChecks() { //TODO - all these checks should be general housekeeping and run on a schedule!!! logging.longOp lo_modules = new logging.longOp("Module Startup Checks", plugins.Count() * 2); foreach (Modules.RobotoModuleTemplate plugin in plugins) { Roboto.log.log("Startup Checks for " + plugin.ToString(), logging.loglevel.warn); //moduledata and chatData startup checks Roboto.log.log("Checking chatdata for " + plugin.ToString(), logging.loglevel.warn); int i = chatData.Count(); foreach (chat c in chatData) { i--; if (i % 100 == 0) { Roboto.log.log(i.ToString() + " remaining", logging.loglevel.verbose); } c.initPlugins(); if (plugin.pluginChatDataType != null) { RobotoModuleChatDataTemplate cd = c.getPluginData(plugin.pluginChatDataType); if (cd != null) { cd.startupChecks(); } } } Roboto.log.log("Checking coredata for " + plugin.ToString(), logging.loglevel.warn); plugin.getPluginData().startupChecks(); lo_modules.addone(); Roboto.log.log("Checking module for " + plugin.ToString(), logging.loglevel.warn); plugin.startupChecks(); lo_modules.addone(); } lo_modules.complete(); }
private static void startBackground() { logging.longOp lo_s = new logging.longOp("Core Startup", 5); settings.loadPlugins(); lo_s.addone(); log.log("Loading Settings", logging.loglevel.high); Settings = settings.load(); lo_s.addone(); Settings.validate(); lo_s.addone(); log.initialise(); lo_s.complete(); log.log("I am " + Settings.botUserName, logging.loglevel.critical, Colors.White, false, true); Settings.startupChecks(); //AT THIS POINT THE GAME WILL START PROCESSING INSTRUCTIONS!!! //DONT GO PAST IN STARTUP TEST MODE //---------------------------- int ABANDONALLHOPE = 1; ABANDONALLHOPE++; //---------------------------- Settings.save(); if (Settings.isFirstTimeInitialised) { log.log(@"New XML file created in %appdata%\Roboto\ . Enter your API key in there and restart.", logging.loglevel.critical, Colors.White, false, true); } else { log.log("Starting main thread", logging.loglevel.high); DateTime lastUpdate = DateTime.MinValue; while (!endLoop) { //store the time to prevent hammering the service when its down. Pause for a couple of seconds if things are getting toasty if (lastUpdate > DateTime.Now.Subtract(TimeSpan.FromSeconds(10))) { Roboto.Settings.stats.logStat(new statItem("Hammering Prevention", typeof(Roboto))); log.log("Too quick, sleeping", logging.loglevel.warn); Thread.Sleep(2000); } lastUpdate = DateTime.Now; //TODO - move this code to the webAPI class string updateURL = Settings.telegramAPIURL + Settings.telegramAPIKey + "/getUpdates" + "?offset=" + Settings.getUpdateID() + "&timeout=" + Settings.waitDuration + "&limit=10"; HttpWebRequest request = (HttpWebRequest)WebRequest.Create(updateURL); log.log(".", logging.loglevel.low, Colors.White, true); request.Method = "GET"; request.ContentType = "application/json"; try { WebResponse webResponse = request.GetResponse(); using (Stream webStream = webResponse.GetResponseStream()) { if (webStream != null) { using (StreamReader responseReader = new StreamReader(webStream)) { string response = responseReader.ReadToEnd(); JObject jo = JObject.Parse(response); //success? string path = jo.First.Path; string result = jo.First.First.Value <string>(); if (path != "ok" || result != "True") { endLoop = true; log.log("Failure code from web service", logging.loglevel.high); throw new WebException("Failure code from web service"); } else { int resultID = 0; //open the response and parse it using JSON. Probably only one result, but should be more? foreach (JToken token in jo.SelectTokens("result.[*]"))//jo.Children()) //) records[*].data.importedPath" { string logText = Regex.Replace(token.ToString(), @"(\s|\n|\r|\r\n)+", " "); log.log(logText, logging.loglevel.verbose); //Find out what kind of message this is. //TOP LEVEL TOKENS JToken updateID_TK = token.First; JToken update_TK = updateID_TK.Next.First; //Flag the update ID as processed. int updateID = updateID_TK.First.Value <int>(); Settings.lastUpdate = updateID; //is this for a group chat? long chatID = update_TK.SelectToken("chat.id").Value <long>(); chat chatData = null; if (chatID < 0) { //find the chat chatData = Settings.getChat(chatID); string chatTitle = update_TK.SelectToken("chat.title").Value <string>(); //new chat, add if (chatData == null) { chatData = Settings.addChat(chatID, chatTitle); } if (chatData == null) { throw new DataMisalignedException("Something went wrong creating the new chat data"); } chatData.setTitle(chatTitle); } //Do we have an incoming message? if (update_TK.Path == "result[" + resultID.ToString() + "].message" && update_TK.SelectToken(".text") != null) { //prevent delays - its sent something valid back to us so we are probably OK. lastUpdate = DateTime.MinValue; if (chatData != null) { chatData.resetLastUpdateTime(); } message m = new message(update_TK); //now decide what to do with this stuff. bool processed = false; //check if this is an expected reply, and if so route it to the Settings.parseExpectedReplies(m); //TODO - call plugins in some kind of priority order foreach (Modules.RobotoModuleTemplate plugin in settings.plugins) { //Skip this message if the chat is muted. if (plugin.chatHook && (chatData == null || (chatData.muted == false || plugin.chatIfMuted))) { if ((!processed || plugin.chatEvenIfAlreadyMatched)) { processed = plugin.chatEvent(m, chatData); } } } } else { log.log("No text in update", logging.loglevel.verbose); } //dont know what other update types we want to monitor? //TODO - leave / kicked / chat deleted resultID++; } //NB: ER Housekepeping moved from here as called too frequently } } } } } catch (System.Net.WebException e) { log.log("Web Service Timeout during getUpdates: " + e.ToString(), logging.loglevel.high); Settings.stats.logStat(new statItem("BotAPI Timeouts", typeof(Roboto))); } catch (Exception e) { try { log.log("Exception caught at main loop. " + e.ToString(), logging.loglevel.critical, Colors.White, false, false, false, false, 2); } catch (Exception ex) { Console.Out.WriteLine("-----------------"); Console.Out.WriteLine("Error During LOGGING! Original Error was"); Console.Out.WriteLine(e.Message); Console.Out.WriteLine("Logging Error was"); Console.Out.WriteLine(ex.Message); } } //Perform all background processing, syncing etc.. Settings.backgroundProcessing(false); } log.log("Main loop finishing, saving", logging.loglevel.high); Roboto.Settings.save(); log.log("Saved data, exiting main loop", logging.loglevel.high); //todo - do something to allow window to close? logWindow.unlockExit(); log.log("All data saved cleanly - close the form again to exit", logging.loglevel.critical); } }