/// <summary> /// Add a new expected reply to the stack. Should be called internally only - New messages should be sent via TelegramAPI.GetExpectedReply /// </summary> /// <param name="e"></param> /// <param name="trySendImmediately">Try and send the message immediately, assuming nothing is outstanding. Will jump the queue, but not override any existing messages</param> /// <returns>An integer specifying the message id. -1 indicates it is queueed, long.MinValue indicates a failure</returns> public long newExpectedReply(ExpectedReply e, bool trySendImmediately) { //flag the user as present in the chat if (e.isPrivateMessage) { markPresence(e.userID, e.chatID, e.userName); } //check if we can send it? Get the messageID back long messageID = -1; //is this a message to a group? if (!e.isPrivateMessage) { //send, dont queue. //TODO - doesnt handle group PMs messageID = e.sendMessage(); } //this is a PM. Does the user have anything in the queue? else if (!userHasOutstandingMessages(e.userID)) { //send the message. messageID = e.sendMessage(); //queue if it was a question if (e.expectsReply) { expectedReplies.Add(e); } } //If they have messages in the queue, and we want to jump ahead, has one already been asked, or are we open? else if (trySendImmediately && !userHasOutstandingQuestions(e.userID)) { Roboto.log.log("Message jumping queue due to immediatemode", logging.loglevel.verbose); //send the message, grab the ID. messageID = e.sendMessage(); //did it work/ if (messageID == long.MinValue) { Roboto.log.log("Tried to send message using immediateMode, but it failed.", logging.loglevel.warn); return(messageID); } //queue if it was a question else if (e.expectsReply) { expectedReplies.Add(e); } } else { //chuck it on the stack if its going to be queued expectedReplies.Add(e); } //make sure we are in a safe state. This will make sure if we sent a message-only, that the next message(s) are processed. expectedReplyHousekeeping(); return(messageID); }
/// <summary> /// Make sure any reply processing is being done /// </summary> public void expectedReplyHousekeeping() { //Build up a list of user IDs //List<int> userIDs = new List<int>(); //foreach (ExpectedReply e in expectedReplies) { userIDs.Add(e.userID); } //userIDs = (List<int>)userIDs.Distinct<int>(); try { List <long> userIDs = expectedReplies.Select(e => e.userID).Distinct().ToList <long>(); //remove any invalid messages List <ExpectedReply> messagesToRemove = expectedReplies.Where(e => e.outboundMessageID > 0 && e.expectsReply == false).ToList(); if (messagesToRemove.Count > 0) { Roboto.log.log("Removing " + messagesToRemove.Count() + " messages from queue as they are sent and dont require a reply", logging.loglevel.warn); } foreach (ExpectedReply e in messagesToRemove) { expectedReplies.Remove(e); } foreach (long userID in userIDs) { bool retry = true; while (retry) { //for each user, check if a message has been sent, and track the oldest message ExpectedReply oldest = null; List <ExpectedReply> userReplies = expectedReplies.Where(e => e.userID == userID).ToList(); //try find a message to send. Drop out if we already have a sent message on the stack (waiting for a reply) bool sent = false; foreach (ExpectedReply e in userReplies) { if (e.isSent()) { sent = true; } //message is waiting else { if (oldest == null || e.timeLogged < oldest.timeLogged) { oldest = e; } } } //send the message if neccessary if (!sent && oldest != null) { oldest.sendMessage(); if (!oldest.expectsReply) { expectedReplies.Remove(oldest); } //make sure we are in a safe state. This will make sure if we sent a message-only, that the next message(s) are processed. } //what do we do next? if (sent == true) { retry = false; } // drop out if we have a message awaiting an answer else if (oldest == null) { retry = false; } // drop out if we have no messages to send else if (oldest.expectsReply) { retry = false; } //drop out if we sent a message that expects a reply } } } catch (Exception e) { Roboto.log.log("Error during expected reply housekeeping " + e.ToString(), logging.loglevel.critical); } }