/// <summary> /// Attempts to handle the message on our side in the case it's a backend update /// </summary> /// <param name="Message">The update in question</param> /// <returns>True if the message was handled. Otherwise, false.</returns> private async Task <bool> ProcessUpdate(TLObject Message) { Logger.Log(Logger.Level.Info, $"Beginning internal update processing of \"{(string)Message["body"]["_"]}\""); try { if (((int)Message["seqno"] & 0x01) != 0) { Logger.Log(Logger.Level.Debug, $"Adding \"{(long)Message["msg_id"]}\" to be acked"); PendingAcks.Add((long)Message["msg_id"]); } var args = new object[] { this, new TLObjectEventArgs(new TLObject(Message["body"])) }; UpdateReceivedEvent.RaiseEventSafe(ref args); return((Message["body"].Value <string>("_")) switch { "bad_server_salt" => ProcessBadSalt(Message), "bad_msg_notification" => ProcessBadMsgNotification(Message), "future_salts" => ProcessFutureSalts(Message), "gzip_packed" => await ProcessGzipPacked(Message), "msg_container" => ProcessMessageContainer(Message), "msg_detailed_info" => ProcessMessageDetailedInfo(Message), "msg_new_detailed_info" => ProcessNewMessageDetailedInfo(Message), "msg_resend_req" => ProcessMessageResendRequest(Message), "msgs_ack" => ProcessMessageAck(Message), "msgs_all_info" => ProcessMessageInfoAll(Message), "msgs_state_req" => ProcessMessageStateReqest(Message), "new_session_created" => ProcessNewSessionCreated(Message), "pong" => ProcessPong(Message), "rpc_result" => await ProcessRPCResult(Message), _ => true, }); }
private async Task AckHandlerMethod(CancellationToken cancellationToken) { while (!cancellationToken.IsCancellationRequested) { try { // Send every three minutes await Task.Delay(3 * 60 * 1000, cancellationToken); // Don't run this time if there aren't any messages to acknowledge if (!PendingAcks.Any()) { continue; } // Take all the required acks out of the bag var acks = new List <long>(); while (PendingAcks.TryTake(out var ack)) { acks.Add(ack); } Logger.Log(Logger.Level.Debug, $"Found {acks.Count} messages that need acknowledgement. Adding them to the payload."); // Create a request that contains the list of acks var Acks_Request = new RequestState(Schema.msgs_ack(new { msg_ids = acks })); // Add the request to both the send queue (to be sent to the server) and // the sent acks queue (in case we need to resend. We don't want to place // in pending since there shouldn't be a response. SendQueue.Add(Acks_Request); SentAcks.Put(Acks_Request); // Send the acks to the server // ToDo: If the user will be polling for updates, can we skip this line // and let the acks be sent for us? Task unawaited = Task.Run(() => ProcessSendQueue()); } catch (TaskCanceledException) { // We don't really care if the task was cancelled. break; } catch (ObjectDisposedException) { // We don't really care if the task was cancelled. break; } catch (Exception ex) { // ToDo: Do we really want to skip all acks when this happens? Likely we // will encounter the same error again if we reprocess... Logger.Log(Logger.Level.Error, $"An error occurred process acks. Skipping.\n\n{ex.Message}"); } } }