From c00b48ede098f2747d15844d0fe73fd2a9b5de20 Mon Sep 17 00:00:00 2001 From: CheshireCaat Date: Mon, 27 Jan 2020 10:03:45 +0300 Subject: [PATCH] Improvements for async methods Added CancellationToken with default value to all async methods in TLSharp.Core Added ConfigureAwait(false) to all async methods in TLSharp.Core SendRequestAsync replaced to SendAuthenticatedRequestAsync in methods that need auth Private modifier in SendAuthenticatedRequestAsync changed to internal Based on PR created by @IaRuslan --- TLSharp.Core/Auth/Authenticator.cs | 38 ++-- TLSharp.Core/Network/MtProtoPlainSender.cs | 13 +- TLSharp.Core/Network/MtProtoSender.cs | 59 +++--- TLSharp.Core/Network/TcpTransport.cs | 15 +- TLSharp.Core/TelegramClient.cs | 197 ++++++++++++--------- TLSharp.Core/Utils/UploadHelper.cs | 17 +- 6 files changed, 198 insertions(+), 141 deletions(-) diff --git a/TLSharp.Core/Auth/Authenticator.cs b/TLSharp.Core/Auth/Authenticator.cs index f63523c..65149d6 100644 --- a/TLSharp.Core/Auth/Authenticator.cs +++ b/TLSharp.Core/Auth/Authenticator.cs @@ -1,37 +1,45 @@ -using System.Threading.Tasks; +using System.Threading; +using System.Threading.Tasks; using TLSharp.Core.Network; namespace TLSharp.Core.Auth { public static class Authenticator { - public static async Task DoAuthentication(TcpTransport transport) + public static async Task DoAuthentication(TcpTransport transport, CancellationToken token = default(CancellationToken)) { + token.ThrowIfCancellationRequested(); + var sender = new MtProtoPlainSender(transport); var step1 = new Step1_PQRequest(); - await sender.Send(step1.ToBytes()); - var step1Response = step1.FromBytes(await sender.Receive()); + await sender.Send(step1.ToBytes(), token).ConfigureAwait(false); + var step1Response = step1.FromBytes(await sender.Receive(token) + .ConfigureAwait(false)); var step2 = new Step2_DHExchange(); await sender.Send(step2.ToBytes( - step1Response.Nonce, - step1Response.ServerNonce, - step1Response.Fingerprints, - step1Response.Pq)); + step1Response.Nonce, + step1Response.ServerNonce, + step1Response.Fingerprints, + step1Response.Pq), token) + .ConfigureAwait(false); - var step2Response = step2.FromBytes(await sender.Receive()); + var step2Response = step2.FromBytes(await sender.Receive(token) + .ConfigureAwait(false)); var step3 = new Step3_CompleteDHExchange(); await sender.Send(step3.ToBytes( - step2Response.Nonce, - step2Response.ServerNonce, - step2Response.NewNonce, - step2Response.EncryptedAnswer)); + step2Response.Nonce, + step2Response.ServerNonce, + step2Response.NewNonce, + step2Response.EncryptedAnswer), token) + .ConfigureAwait(false); - var step3Response = step3.FromBytes(await sender.Receive()); + var step3Response = step3.FromBytes(await sender.Receive(token) + .ConfigureAwait(false)); return step3Response; } } -} +} \ No newline at end of file diff --git a/TLSharp.Core/Network/MtProtoPlainSender.cs b/TLSharp.Core/Network/MtProtoPlainSender.cs index efc2fa8..d5d40e9 100644 --- a/TLSharp.Core/Network/MtProtoPlainSender.cs +++ b/TLSharp.Core/Network/MtProtoPlainSender.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Threading; using System.Threading.Tasks; namespace TLSharp.Core.Network @@ -17,8 +18,10 @@ namespace TLSharp.Core.Network random = new Random(); } - public async Task Send(byte[] data) + public async Task Send(byte[] data, CancellationToken token = default(CancellationToken)) { + token.ThrowIfCancellationRequested(); + using (var memoryStream = new MemoryStream()) { using (var binaryWriter = new BinaryWriter(memoryStream)) @@ -30,14 +33,16 @@ namespace TLSharp.Core.Network byte[] packet = memoryStream.ToArray(); - await _transport.Send(packet); + await _transport.Send(packet, token).ConfigureAwait(false); } } } - public async Task Receive() + public async Task Receive(CancellationToken token = default(CancellationToken)) { - var result = await _transport.Receive(); + token.ThrowIfCancellationRequested(); + + var result = await _transport.Receive(token).ConfigureAwait(false); using (var memoryStream = new MemoryStream(result.Body)) { diff --git a/TLSharp.Core/Network/MtProtoSender.cs b/TLSharp.Core/Network/MtProtoSender.cs index 243e447..73a0abc 100644 --- a/TLSharp.Core/Network/MtProtoSender.cs +++ b/TLSharp.Core/Network/MtProtoSender.cs @@ -7,6 +7,7 @@ using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using Ionic.Zlib; +using TeleSharp.TL; using TLSharp.Core.Exceptions; using TLSharp.Core.MTProto; using TLSharp.Core.MTProto.Crypto; @@ -36,8 +37,10 @@ namespace TLSharp.Core.Network return confirmed ? _session.Sequence++ * 2 + 1 : _session.Sequence * 2; } - public async Task Send(TeleSharp.TL.TLMethod request) + public async Task Send(TeleSharp.TL.TLMethod request, CancellationToken token = default(CancellationToken)) { + token.ThrowIfCancellationRequested(); + // TODO: refactor if (needConfirmation.Any()) { @@ -46,7 +49,7 @@ namespace TLSharp.Core.Network using (var writer = new BinaryWriter(memory)) { ackRequest.SerializeBody(writer); - await Send(memory.ToArray(), ackRequest); + await Send(memory.ToArray(), ackRequest, token).ConfigureAwait(false); needConfirmation.Clear(); } } @@ -56,14 +59,16 @@ namespace TLSharp.Core.Network using (var writer = new BinaryWriter(memory)) { request.SerializeBody(writer); - await Send(memory.ToArray(), request); + await Send(memory.ToArray(), request, token).ConfigureAwait(false); } _session.Save(); } - public async Task Send(byte[] packet, TeleSharp.TL.TLMethod request) + public async Task Send(byte[] packet, TeleSharp.TL.TLMethod request, CancellationToken token = default(CancellationToken)) { + token.ThrowIfCancellationRequested(); + request.MessageId = _session.GetNewMessageId(); byte[] msgKey; @@ -92,7 +97,7 @@ namespace TLSharp.Core.Network writer.Write(msgKey); writer.Write(ciphertext); - await _transport.Send(ciphertextPacket.GetBuffer()); + await _transport.Send(ciphertextPacket.GetBuffer(), token).ConfigureAwait(false); } } } @@ -129,37 +134,43 @@ namespace TLSharp.Core.Network return new Tuple(message, remoteMessageId, remoteSequence); } - public async Task Receive(TeleSharp.TL.TLMethod request) + public async Task Receive(TeleSharp.TL.TLMethod request, CancellationToken token = default(CancellationToken)) { while (!request.ConfirmReceived) { - var result = DecodeMessage((await _transport.Receive()).Body); + var result = DecodeMessage((await _transport.Receive(token).ConfigureAwait(false)).Body); using (var messageStream = new MemoryStream(result.Item1, false)) using (var messageReader = new BinaryReader(messageStream)) { - processMessage(result.Item2, result.Item3, messageReader, request); + processMessage(result.Item2, result.Item3, messageReader, request, token); } + + token.ThrowIfCancellationRequested(); } return null; } - public async Task SendPingAsync() + public async Task SendPingAsync(CancellationToken token = default(CancellationToken)) { + token.ThrowIfCancellationRequested(); + var pingRequest = new PingRequest(); using (var memory = new MemoryStream()) using (var writer = new BinaryWriter(memory)) { pingRequest.SerializeBody(writer); - await Send(memory.ToArray(), pingRequest); + await Send(memory.ToArray(), pingRequest, token).ConfigureAwait(false); } - await Receive(pingRequest); + await Receive(pingRequest, token).ConfigureAwait(false); } - private bool processMessage(ulong messageId, int sequence, BinaryReader messageReader, TeleSharp.TL.TLMethod request) + private bool processMessage(ulong messageId, int sequence, BinaryReader messageReader, TLMethod request, CancellationToken token = default(CancellationToken)) { + token.ThrowIfCancellationRequested(); + // TODO: check salt // TODO: check sessionid // TODO: check seqno @@ -173,7 +184,7 @@ namespace TLSharp.Core.Network { case 0x73f1f8dc: // container //logger.debug("MSG container"); - return HandleContainer(messageId, sequence, messageReader, request); + return HandleContainer(messageId, sequence, messageReader, request, token); case 0x7abe77ec: // ping //logger.debug("MSG ping"); return HandlePing(messageId, sequence, messageReader); @@ -191,7 +202,7 @@ namespace TLSharp.Core.Network return HandleMsgsAck(messageId, sequence, messageReader); case 0xedab447b: // bad_server_salt //logger.debug("MSG bad_server_salt"); - return HandleBadServerSalt(messageId, sequence, messageReader, request); + return HandleBadServerSalt(messageId, sequence, messageReader, request, token); case 0xa7eff811: // bad_msg_notification //logger.debug("MSG bad_msg_notification"); return HandleBadMsgNotification(messageId, sequence, messageReader); @@ -203,7 +214,7 @@ namespace TLSharp.Core.Network return HandleRpcResult(messageId, sequence, messageReader, request); case 0x3072cfa1: // gzip_packed //logger.debug("MSG gzip_packed"); - return HandleGzipPacked(messageId, sequence, messageReader, request); + return HandleGzipPacked(messageId, sequence, messageReader, request, token); case 0xe317af7e: case 0xd3f45784: case 0x2b2fbd4e: @@ -235,14 +246,16 @@ namespace TLSharp.Core.Network */ } - private bool HandleGzipPacked(ulong messageId, int sequence, BinaryReader messageReader, TeleSharp.TL.TLMethod request) + private bool HandleGzipPacked(ulong messageId, int sequence, BinaryReader messageReader, TLMethod request, CancellationToken token = default(CancellationToken)) { + token.ThrowIfCancellationRequested(); + uint code = messageReader.ReadUInt32(); byte[] packedData = GZipStream.UncompressBuffer(Serializers.Bytes.Read(messageReader)); using (MemoryStream packedStream = new MemoryStream(packedData, false)) using (BinaryReader compressedReader = new BinaryReader(packedStream)) { - processMessage(messageId, sequence, compressedReader, request); + processMessage(messageId, sequence, compressedReader, request, token); } return true; @@ -414,8 +427,10 @@ namespace TLSharp.Core.Network return true; } - private bool HandleBadServerSalt(ulong messageId, int sequence, BinaryReader messageReader, TeleSharp.TL.TLMethod request) + private bool HandleBadServerSalt(ulong messageId, int sequence, BinaryReader messageReader, TLMethod request, CancellationToken token = default(CancellationToken)) { + token.ThrowIfCancellationRequested(); + uint code = messageReader.ReadUInt32(); ulong badMsgId = messageReader.ReadUInt64(); int badMsgSeqNo = messageReader.ReadInt32(); @@ -427,7 +442,7 @@ namespace TLSharp.Core.Network _session.Salt = newSalt; //resend - Send(request); + Send(request, token); /* if(!runningRequests.ContainsKey(badMsgId)) { logger.debug("bad server salt on unknown message"); @@ -493,8 +508,10 @@ namespace TLSharp.Core.Network return false; } - private bool HandleContainer(ulong messageId, int sequence, BinaryReader messageReader, TeleSharp.TL.TLMethod request) + private bool HandleContainer(ulong messageId, int sequence, BinaryReader messageReader, TLMethod request, CancellationToken token = default(CancellationToken)) { + token.ThrowIfCancellationRequested(); + uint code = messageReader.ReadUInt32(); int size = messageReader.ReadInt32(); for (int i = 0; i < size; i++) @@ -505,7 +522,7 @@ namespace TLSharp.Core.Network long beginPosition = messageReader.BaseStream.Position; try { - if (!processMessage(innerMessageId, sequence, messageReader, request)) + if (!processMessage(innerMessageId, sequence, messageReader, request, token)) { messageReader.BaseStream.Position = beginPosition + innerLength; } diff --git a/TLSharp.Core/Network/TcpTransport.cs b/TLSharp.Core/Network/TcpTransport.cs index d501751..058ff01 100644 --- a/TLSharp.Core/Network/TcpTransport.cs +++ b/TLSharp.Core/Network/TcpTransport.cs @@ -1,6 +1,7 @@ using System; using System.Net; using System.Net.Sockets; +using System.Threading; using System.Threading.Tasks; namespace TLSharp.Core.Network @@ -32,26 +33,26 @@ namespace TLSharp.Core.Network } } - public async Task Send(byte[] packet) + public async Task Send(byte[] packet, CancellationToken token = default(CancellationToken)) { if (!_tcpClient.Connected) throw new InvalidOperationException("Client not connected to server."); var tcpMessage = new TcpMessage(sendCounter, packet); - await _stream.WriteAsync(tcpMessage.Encode(), 0, tcpMessage.Encode().Length); + await _stream.WriteAsync(tcpMessage.Encode(), 0, tcpMessage.Encode().Length, token).ConfigureAwait(false); sendCounter++; } - public async Task Receive() + public async Task Receive(CancellationToken token = default(CancellationToken)) { var packetLengthBytes = new byte[4]; - if (await _stream.ReadAsync(packetLengthBytes, 0, 4) != 4) + if (await _stream.ReadAsync(packetLengthBytes, 0, 4, token).ConfigureAwait(false) != 4) throw new InvalidOperationException("Couldn't read the packet length"); int packetLength = BitConverter.ToInt32(packetLengthBytes, 0); var seqBytes = new byte[4]; - if (await _stream.ReadAsync(seqBytes, 0, 4) != 4) + if (await _stream.ReadAsync(seqBytes, 0, 4, token).ConfigureAwait(false) != 4) throw new InvalidOperationException("Couldn't read the sequence"); int seq = BitConverter.ToInt32(seqBytes, 0); @@ -62,7 +63,7 @@ namespace TLSharp.Core.Network do { var bodyByte = new byte[packetLength - 12]; - var availableBytes = await _stream.ReadAsync(bodyByte, 0, neededToRead); + var availableBytes = await _stream.ReadAsync(bodyByte, 0, neededToRead, token).ConfigureAwait(false); neededToRead -= availableBytes; Buffer.BlockCopy(bodyByte, 0, body, readBytes, availableBytes); readBytes += availableBytes; @@ -70,7 +71,7 @@ namespace TLSharp.Core.Network while (readBytes != packetLength - 12); var crcBytes = new byte[4]; - if (await _stream.ReadAsync(crcBytes, 0, 4) != 4) + if (await _stream.ReadAsync(crcBytes, 0, 4, token).ConfigureAwait(false) != 4) throw new InvalidOperationException("Couldn't read the crc"); int checksum = BitConverter.ToInt32(crcBytes, 0); diff --git a/TLSharp.Core/TelegramClient.cs b/TLSharp.Core/TelegramClient.cs index 9bddb95..9fcad4c 100644 --- a/TLSharp.Core/TelegramClient.cs +++ b/TLSharp.Core/TelegramClient.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Text; +using System.Threading; using System.Threading.Tasks; using TeleSharp.TL; using TeleSharp.TL.Account; @@ -55,11 +56,13 @@ namespace TLSharp.Core _transport = new TcpTransport(_session.DataCenter.Address, _session.DataCenter.Port, _handler); } - public async Task ConnectAsync(bool reconnect = false) + public async Task ConnectAsync(bool reconnect = false, CancellationToken token = default(CancellationToken)) { + token.ThrowIfCancellationRequested(); + if (_session.AuthKey == null || reconnect) { - var result = await Authenticator.DoAuthentication(_transport); + var result = await Authenticator.DoAuthentication(_transport, token).ConfigureAwait(false); _session.AuthKey = result.AuthKey; _session.TimeOffset = result.TimeOffset; } @@ -78,14 +81,16 @@ namespace TLSharp.Core SystemVersion = "Win 10.0" }; var invokewithLayer = new TLRequestInvokeWithLayer() { Layer = 66, Query = request }; - await _sender.Send(invokewithLayer); - await _sender.Receive(invokewithLayer); + await _sender.Send(invokewithLayer, token).ConfigureAwait(false); + await _sender.Receive(invokewithLayer, token).ConfigureAwait(false); dcOptions = ((TLConfig)invokewithLayer.Response).DcOptions.ToList(); } - private async Task ReconnectToDcAsync(int dcId) + private async Task ReconnectToDcAsync(int dcId, CancellationToken token = default(CancellationToken)) { + token.ThrowIfCancellationRequested(); + if (dcOptions == null || !dcOptions.Any()) throw new InvalidOperationException($"Can't reconnect. Establish initial connection first."); @@ -93,7 +98,7 @@ namespace TLSharp.Core if (_session.TLUser != null) { TLRequestExportAuthorization exportAuthorization = new TLRequestExportAuthorization() { DcId = dcId }; - exported = await SendRequestAsync(exportAuthorization); + exported = await SendRequestAsync(exportAuthorization, token).ConfigureAwait(false); } var dc = dcOptions.First(d => d.Id == dcId); @@ -102,17 +107,17 @@ namespace TLSharp.Core _transport = new TcpTransport(dc.IpAddress, dc.Port, _handler); _session.DataCenter = dataCenter; - await ConnectAsync(true); + await ConnectAsync(true, token).ConfigureAwait(false); if (_session.TLUser != null) { TLRequestImportAuthorization importAuthorization = new TLRequestImportAuthorization() { Id = exported.Id, Bytes = exported.Bytes }; - var imported = await SendRequestAsync(importAuthorization); + var imported = await SendRequestAsync(importAuthorization, token).ConfigureAwait(false); OnUserAuthenticated(((TLUser)imported.User)); } } - private async Task RequestWithDcMigration(TLMethod request) + private async Task RequestWithDcMigration(TLMethod request, CancellationToken token = default(CancellationToken)) { if (_sender == null) throw new InvalidOperationException("Not connected!"); @@ -122,8 +127,8 @@ namespace TLSharp.Core { try { - await _sender.Send(request); - await _sender.Receive(request); + await _sender.Send(request, token).ConfigureAwait(false); + await _sender.Receive(request, token).ConfigureAwait(false); completed = true; } catch(DataCenterMigrationException e) @@ -134,7 +139,7 @@ namespace TLSharp.Core throw new Exception($"Telegram server replied requesting a migration to DataCenter {e.DC} when this connection was already using this DataCenter", e); } - await ReconnectToDcAsync(e.DC); + await ReconnectToDcAsync(e.DC, token).ConfigureAwait(false); // prepare the request for another try request.ConfirmReceived = false; } @@ -146,31 +151,31 @@ namespace TLSharp.Core return _session.TLUser != null; } - public async Task IsPhoneRegisteredAsync(string phoneNumber) + public async Task IsPhoneRegisteredAsync(string phoneNumber, CancellationToken token = default(CancellationToken)) { if (String.IsNullOrWhiteSpace(phoneNumber)) throw new ArgumentNullException(nameof(phoneNumber)); var authCheckPhoneRequest = new TLRequestCheckPhone() { PhoneNumber = phoneNumber }; - await RequestWithDcMigration(authCheckPhoneRequest); + await RequestWithDcMigration(authCheckPhoneRequest, token).ConfigureAwait(false); return authCheckPhoneRequest.Response.PhoneRegistered; } - public async Task SendCodeRequestAsync(string phoneNumber) + public async Task SendCodeRequestAsync(string phoneNumber, CancellationToken token = default(CancellationToken)) { if (String.IsNullOrWhiteSpace(phoneNumber)) throw new ArgumentNullException(nameof(phoneNumber)); var request = new TLRequestSendCode() { PhoneNumber = phoneNumber, ApiId = _apiId, ApiHash = _apiHash }; - await RequestWithDcMigration(request); + await RequestWithDcMigration(request, token).ConfigureAwait(false); return request.Response.PhoneCodeHash; } - public async Task MakeAuthAsync(string phoneNumber, string phoneCodeHash, string code) + public async Task MakeAuthAsync(string phoneNumber, string phoneCodeHash, string code, CancellationToken token = default(CancellationToken)) { if (String.IsNullOrWhiteSpace(phoneNumber)) throw new ArgumentNullException(nameof(phoneNumber)); @@ -183,24 +188,26 @@ namespace TLSharp.Core var request = new TLRequestSignIn() { PhoneNumber = phoneNumber, PhoneCodeHash = phoneCodeHash, PhoneCode = code }; - await RequestWithDcMigration(request); + await RequestWithDcMigration(request, token).ConfigureAwait(false); OnUserAuthenticated(((TLUser)request.Response.User)); return ((TLUser)request.Response.User); } - public async Task GetPasswordSetting() + public async Task GetPasswordSetting(CancellationToken token = default(CancellationToken)) { var request = new TLRequestGetPassword(); - await RequestWithDcMigration(request); + await RequestWithDcMigration(request, token).ConfigureAwait(false); return ((TLPassword)request.Response); } - public async Task MakeAuthWithPasswordAsync(TLPassword password, string password_str) + public async Task MakeAuthWithPasswordAsync(TLPassword password, string password_str, CancellationToken token = default(CancellationToken)) { + token.ThrowIfCancellationRequested(); + byte[] password_Bytes = Encoding.UTF8.GetBytes(password_str); IEnumerable rv = password.CurrentSalt.Concat(password_Bytes).Concat(password.CurrentSalt); @@ -209,105 +216,114 @@ namespace TLSharp.Core var request = new TLRequestCheckPassword() { PasswordHash = password_hash }; - await RequestWithDcMigration(request); + await RequestWithDcMigration(request, token).ConfigureAwait(false); OnUserAuthenticated(((TLUser)request.Response.User)); return ((TLUser)request.Response.User); } - public async Task SignUpAsync(string phoneNumber, string phoneCodeHash, string code, string firstName, string lastName) + public async Task SignUpAsync(string phoneNumber, string phoneCodeHash, string code, string firstName, string lastName, CancellationToken token = default(CancellationToken)) { var request = new TLRequestSignUp() { PhoneNumber = phoneNumber, PhoneCode = code, PhoneCodeHash = phoneCodeHash, FirstName = firstName, LastName = lastName }; - await RequestWithDcMigration(request); + await RequestWithDcMigration(request, token).ConfigureAwait(false); OnUserAuthenticated(((TLUser)request.Response.User)); return ((TLUser)request.Response.User); } - public async Task SendRequestAsync(TLMethod methodToExecute) + public async Task SendRequestAsync(TLMethod methodToExecute, CancellationToken token = default(CancellationToken)) { - await RequestWithDcMigration(methodToExecute); + await RequestWithDcMigration(methodToExecute, token).ConfigureAwait(false); var result = methodToExecute.GetType().GetProperty("Response").GetValue(methodToExecute); return (T)result; } - private async Task SendAuthenticatedRequestAsync (TLMethod methodToExecute) + internal async Task SendAuthenticatedRequestAsync (TLMethod methodToExecute, CancellationToken token = default(CancellationToken)) { if (!IsUserAuthorized()) throw new InvalidOperationException("Authorize user first!"); - return await SendRequestAsync(methodToExecute); + return await SendRequestAsync(methodToExecute, token) + .ConfigureAwait(false); } - public async Task UpdateUsernameAsync(string username) + public async Task UpdateUsernameAsync(string username, CancellationToken token = default(CancellationToken)) { var req = new TLRequestUpdateUsername { Username = username }; - return await SendAuthenticatedRequestAsync(req); + return await SendAuthenticatedRequestAsync(req, token) + .ConfigureAwait(false); } - public async Task CheckUsernameAsync(string username) + public async Task CheckUsernameAsync(string username, CancellationToken token = default(CancellationToken)) { var req = new TLRequestCheckUsername { Username = username }; - return await SendAuthenticatedRequestAsync(req); + return await SendAuthenticatedRequestAsync(req, token) + .ConfigureAwait(false); } - public async Task ImportContactsAsync(IReadOnlyList contacts) + public async Task ImportContactsAsync(IReadOnlyList contacts, CancellationToken token = default(CancellationToken)) { var req = new TLRequestImportContacts { Contacts = new TLVector(contacts)}; - return await SendAuthenticatedRequestAsync(req); + return await SendAuthenticatedRequestAsync(req, token) + .ConfigureAwait(false); } - public async Task DeleteContactsAsync(IReadOnlyList users) + public async Task DeleteContactsAsync(IReadOnlyList users, CancellationToken token = default(CancellationToken)) { var req = new TLRequestDeleteContacts {Id = new TLVector(users)}; - return await SendAuthenticatedRequestAsync(req); + return await SendAuthenticatedRequestAsync(req, token) + .ConfigureAwait(false); } - public async Task DeleteContactAsync(TLAbsInputUser user) + public async Task DeleteContactAsync(TLAbsInputUser user, CancellationToken token = default(CancellationToken)) { var req = new TLRequestDeleteContact {Id = user}; - return await SendAuthenticatedRequestAsync(req); + return await SendAuthenticatedRequestAsync(req, token) + .ConfigureAwait(false); } - public async Task GetContactsAsync() + public async Task GetContactsAsync(CancellationToken token = default(CancellationToken)) { var req = new TLRequestGetContacts() { Hash = "" }; - return await SendAuthenticatedRequestAsync(req); + return await SendAuthenticatedRequestAsync(req, token) + .ConfigureAwait(false); } - public async Task SendMessageAsync(TLAbsInputPeer peer, string message) + public async Task SendMessageAsync(TLAbsInputPeer peer, string message, CancellationToken token = default(CancellationToken)) { return await SendAuthenticatedRequestAsync( - new TLRequestSendMessage() - { - Peer = peer, - Message = message, - RandomId = Helpers.GenerateRandomLong() - }); + new TLRequestSendMessage() + { + Peer = peer, + Message = message, + RandomId = Helpers.GenerateRandomLong() + }, token) + .ConfigureAwait(false); } - public async Task SendTypingAsync(TLAbsInputPeer peer) + public async Task SendTypingAsync(TLAbsInputPeer peer, CancellationToken token = default(CancellationToken)) { var req = new TLRequestSetTyping() { Action = new TLSendMessageTypingAction(), Peer = peer }; - return await SendRequestAsync(req); + return await SendAuthenticatedRequestAsync(req, token) + .ConfigureAwait(false); } - public async Task GetUserDialogsAsync(int offsetDate = 0, int offsetId = 0, TLAbsInputPeer offsetPeer = null, int limit = 100) + public async Task GetUserDialogsAsync(int offsetDate = 0, int offsetId = 0, TLAbsInputPeer offsetPeer = null, int limit = 100, CancellationToken token = default(CancellationToken)) { if (offsetPeer == null) offsetPeer = new TLInputPeerSelf(); @@ -319,58 +335,63 @@ namespace TLSharp.Core OffsetPeer = offsetPeer, Limit = limit }; - return await SendAuthenticatedRequestAsync(req); + return await SendAuthenticatedRequestAsync(req, token) + .ConfigureAwait(false); } - public async Task SendUploadedPhoto(TLAbsInputPeer peer, TLAbsInputFile file, string caption) + public async Task SendUploadedPhoto(TLAbsInputPeer peer, TLAbsInputFile file, string caption, CancellationToken token = default(CancellationToken)) { - return await SendRequestAsync(new TLRequestSendMedia() - { - RandomId = Helpers.GenerateRandomLong(), - Background = false, - ClearDraft = false, - Media = new TLInputMediaUploadedPhoto() { File = file, Caption = caption }, - Peer = peer - }); + return await SendAuthenticatedRequestAsync(new TLRequestSendMedia() + { + RandomId = Helpers.GenerateRandomLong(), + Background = false, + ClearDraft = false, + Media = new TLInputMediaUploadedPhoto() { File = file, Caption = caption }, + Peer = peer + }, token) + .ConfigureAwait(false); } public async Task SendUploadedDocument( - TLAbsInputPeer peer, TLAbsInputFile file, string caption, string mimeType, TLVector attributes) + TLAbsInputPeer peer, TLAbsInputFile file, string caption, string mimeType, TLVector attributes, CancellationToken token = default(CancellationToken)) { - return await SendRequestAsync(new TLRequestSendMedia() - { - RandomId = Helpers.GenerateRandomLong(), - Background = false, - ClearDraft = false, - Media = new TLInputMediaUploadedDocument() + return await SendAuthenticatedRequestAsync(new TLRequestSendMedia() { - File = file, - Caption = caption, - MimeType = mimeType, - Attributes = attributes - }, - Peer = peer - }); + RandomId = Helpers.GenerateRandomLong(), + Background = false, + ClearDraft = false, + Media = new TLInputMediaUploadedDocument() + { + File = file, + Caption = caption, + MimeType = mimeType, + Attributes = attributes + }, + Peer = peer + }, token) + .ConfigureAwait(false); } - public async Task GetFile(TLAbsInputFileLocation location, int filePartSize, int offset = 0) + public async Task GetFile(TLAbsInputFileLocation location, int filePartSize, int offset = 0, CancellationToken token = default(CancellationToken)) { TLFile result = null; - result = await SendRequestAsync(new TLRequestGetFile() - { - Location = location, - Limit = filePartSize, - Offset = offset - }); + result = await SendAuthenticatedRequestAsync(new TLRequestGetFile + { + Location = location, + Limit = filePartSize, + Offset = offset + }, token) + .ConfigureAwait(false); return result; } - public async Task SendPingAsync() + public async Task SendPingAsync(CancellationToken token = default(CancellationToken)) { - await _sender.SendPingAsync(); + await _sender.SendPingAsync(token) + .ConfigureAwait(false); } - public async Task GetHistoryAsync(TLAbsInputPeer peer, int offsetId = 0, int offsetDate = 0, int addOffset = 0, int limit = 100, int maxId = 0, int minId = 0) + public async Task GetHistoryAsync(TLAbsInputPeer peer, int offsetId = 0, int offsetDate = 0, int addOffset = 0, int limit = 100, int maxId = 0, int minId = 0, CancellationToken token = default(CancellationToken)) { var req = new TLRequestGetHistory() { @@ -382,7 +403,8 @@ namespace TLSharp.Core MaxId = maxId, MinId = minId }; - return await SendAuthenticatedRequestAsync(req); + return await SendAuthenticatedRequestAsync(req, token) + .ConfigureAwait(false); } /// @@ -391,7 +413,7 @@ namespace TLSharp.Core /// User or chat name /// Max result count /// - public async Task SearchUserAsync(string q, int limit = 10) + public async Task SearchUserAsync(string q, int limit = 10, CancellationToken token = default(CancellationToken)) { var r = new TeleSharp.TL.Contacts.TLRequestSearch { @@ -399,7 +421,8 @@ namespace TLSharp.Core Limit = limit }; - return await SendRequestAsync(r); + return await SendAuthenticatedRequestAsync(r, token) + .ConfigureAwait(false); } private void OnUserAuthenticated(TLUser TLUser) diff --git a/TLSharp.Core/Utils/UploadHelper.cs b/TLSharp.Core/Utils/UploadHelper.cs index 3471c51..41256a7 100644 --- a/TLSharp.Core/Utils/UploadHelper.cs +++ b/TLSharp.Core/Utils/UploadHelper.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; using System.Security.Cryptography; using System.Text; +using System.Threading; using System.Threading.Tasks; using TeleSharp.TL; using TeleSharp.TL.Upload; @@ -29,10 +30,10 @@ namespace TLSharp.Core.Utils return md5_checksum; } - public static async Task UploadFile(this TelegramClient client, string name, StreamReader reader) + public static async Task UploadFile(this TelegramClient client, string name, StreamReader reader, CancellationToken token = default(CancellationToken)) { const long tenMb = 10 * 1024 * 1024; - return await UploadFile(name, reader, client, reader.BaseStream.Length >= tenMb); + return await UploadFile(name, reader, client, reader.BaseStream.Length >= tenMb, token).ConfigureAwait(false); } private static byte[] GetFile(StreamReader reader) @@ -77,8 +78,10 @@ namespace TLSharp.Core.Utils } private static async Task UploadFile(string name, StreamReader reader, - TelegramClient client, bool isBigFileUpload) + TelegramClient client, bool isBigFileUpload, CancellationToken token = default(CancellationToken)) { + token.ThrowIfCancellationRequested(); + var file = GetFile(reader); var fileParts = GetFileParts(file); @@ -91,22 +94,22 @@ namespace TLSharp.Core.Utils if (isBigFileUpload) { - await client.SendRequestAsync(new TLRequestSaveBigFilePart + await client.SendAuthenticatedRequestAsync(new TLRequestSaveBigFilePart { FileId = file_id, FilePart = partNumber, Bytes = part, FileTotalParts = partsCount - }); + }, token).ConfigureAwait(false); } else { - await client.SendRequestAsync(new TLRequestSaveFilePart + await client.SendAuthenticatedRequestAsync(new TLRequestSaveFilePart { FileId = file_id, FilePart = partNumber, Bytes = part - }); + }, token).ConfigureAwait(false); } partNumber++; }