From 96f9660b48db854820d1140d6dc27ca06efc0cba Mon Sep 17 00:00:00 2001 From: Ruslan Iarmukhamedov Date: Fri, 25 Oct 2019 09:32:04 +0600 Subject: [PATCH] Adds ConfigureAwait(false) and CancellationToken to all async methods --- TLSharp.Core/Auth/Authenticator.cs | 19 +- TLSharp.Core/Network/MtProtoPlainSender.cs | 33 ++-- TLSharp.Core/Network/MtProtoSender.cs | 59 +++--- TLSharp.Core/Network/TcpTransport.cs | 32 ++-- TLSharp.Core/TelegramClient.cs | 203 ++++++++++++++------- TLSharp.Core/Utils/UploadHelper.cs | 33 ++-- 6 files changed, 243 insertions(+), 136 deletions(-) diff --git a/TLSharp.Core/Auth/Authenticator.cs b/TLSharp.Core/Auth/Authenticator.cs index f63523c..c56dffc 100644 --- a/TLSharp.Core/Auth/Authenticator.cs +++ b/TLSharp.Core/Auth/Authenticator.cs @@ -1,35 +1,38 @@ -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) { + 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.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.EncryptedAnswer), token).ConfigureAwait(false); - var step3Response = step3.FromBytes(await sender.Receive()); + var step3Response = step3.FromBytes(await sender.Receive(token).ConfigureAwait(false)); return step3Response; } diff --git a/TLSharp.Core/Network/MtProtoPlainSender.cs b/TLSharp.Core/Network/MtProtoPlainSender.cs index efc2fa8..e468084 100644 --- a/TLSharp.Core/Network/MtProtoPlainSender.cs +++ b/TLSharp.Core/Network/MtProtoPlainSender.cs @@ -1,24 +1,27 @@ using System; using System.IO; +using System.Threading; using System.Threading.Tasks; namespace TLSharp.Core.Network { public class MtProtoPlainSender { - private int timeOffset; - private long lastMessageId; - private Random random; - private TcpTransport _transport; + private int _timeOffset; + private long _lastMessageId; + private readonly Random _random; + private readonly TcpTransport _transport; public MtProtoPlainSender(TcpTransport transport) { _transport = transport; - random = new Random(); + _random = new Random(); } - public async Task Send(byte[] data) + public async Task Send(byte[] data, CancellationToken token) { + 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) { - var result = await _transport.Receive(); + token.ThrowIfCancellationRequested(); + + var result = await _transport.Receive(token).ConfigureAwait(false); using (var memoryStream = new MemoryStream(result.Body)) { @@ -57,17 +62,17 @@ namespace TLSharp.Core.Network private long GetNewMessageId() { long time = Convert.ToInt64((DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalMilliseconds); - long newMessageId = ((time / 1000 + timeOffset) << 32) | + long newMessageId = ((time / 1000 + _timeOffset) << 32) | ((time % 1000) << 22) | - (random.Next(524288) << 2); // 2^19 + (_random.Next(524288) << 2); // 2^19 // [ unix timestamp : 32 bit] [ milliseconds : 10 bit ] [ buffer space : 1 bit ] [ random : 19 bit ] [ msg_id type : 2 bit ] = [ msg_id : 64 bit ] - if (lastMessageId >= newMessageId) + if (_lastMessageId >= newMessageId) { - newMessageId = lastMessageId + 4; + newMessageId = _lastMessageId + 4; } - lastMessageId = newMessageId; + _lastMessageId = newMessageId; return newMessageId; } diff --git a/TLSharp.Core/Network/MtProtoSender.cs b/TLSharp.Core/Network/MtProtoSender.cs index a0361a2..ff412e1 100644 --- a/TLSharp.Core/Network/MtProtoSender.cs +++ b/TLSharp.Core/Network/MtProtoSender.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; using System.Text.RegularExpressions; @@ -34,8 +33,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) { + token.ThrowIfCancellationRequested(); + // TODO: refactor if (needConfirmation.Any()) { @@ -44,7 +45,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(); } } @@ -54,14 +55,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) { + token.ThrowIfCancellationRequested(); + request.MessageId = _session.GetNewMessageId(); byte[] msgKey; @@ -90,7 +93,7 @@ namespace TLSharp.Core.Network writer.Write(msgKey); writer.Write(ciphertext); - await _transport.Send(ciphertextPacket.GetBuffer()); + await _transport.Send(ciphertextPacket.GetBuffer(), token).ConfigureAwait(false); } } } @@ -127,37 +130,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) { 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) { + 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, TeleSharp.TL.TLMethod request, CancellationToken token) { + token.ThrowIfCancellationRequested(); + // TODO: check salt // TODO: check sessionid // TODO: check seqno @@ -171,7 +180,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); @@ -189,7 +198,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); @@ -201,7 +210,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: @@ -233,14 +242,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, TeleSharp.TL.TLMethod request, CancellationToken token) { + 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; @@ -412,8 +423,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, TeleSharp.TL.TLMethod request, CancellationToken token) { + token.ThrowIfCancellationRequested(); + uint code = messageReader.ReadUInt32(); ulong badMsgId = messageReader.ReadUInt64(); int badMsgSeqNo = messageReader.ReadInt32(); @@ -425,7 +438,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"); @@ -491,8 +504,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, TeleSharp.TL.TLMethod request, CancellationToken token) { + token.ThrowIfCancellationRequested(); + uint code = messageReader.ReadUInt32(); int size = messageReader.ReadInt32(); for (int i = 0; i < size; i++) @@ -503,7 +518,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..c40a6de 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 @@ -11,7 +12,7 @@ namespace TLSharp.Core.Network { private readonly TcpClient _tcpClient; private readonly NetworkStream _stream; - private int sendCounter = 0; + private int _sendCounter; public TcpTransport(string address, int port, TcpClientConnectionHandler handler = null) { @@ -32,27 +33,29 @@ namespace TLSharp.Core.Network } } - public async Task Send(byte[] packet) + public async Task Send(byte[] packet, CancellationToken token) { if (!_tcpClient.Connected) throw new InvalidOperationException("Client not connected to server."); - var tcpMessage = new TcpMessage(sendCounter, packet); + var tcpMessage = new TcpMessage(_sendCounter, packet); - await _stream.WriteAsync(tcpMessage.Encode(), 0, tcpMessage.Encode().Length); - sendCounter++; + await _stream.WriteAsync(tcpMessage.Encode(), 0, tcpMessage.Encode().Length, token).ConfigureAwait(false); + _sendCounter++; } - public async Task Receive() + public async Task Receive(CancellationToken token) { 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); int readBytes = 0; @@ -62,7 +65,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,8 +73,9 @@ 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); byte[] rv = new byte[packetLengthBytes.Length + seqBytes.Length + body.Length]; @@ -91,13 +95,7 @@ namespace TLSharp.Core.Network return new TcpMessage(seq, body); } - public bool IsConnected - { - get - { - return this._tcpClient.Connected; - } - } + public bool IsConnected => _tcpClient.Connected; public void Dispose() diff --git a/TLSharp.Core/TelegramClient.cs b/TLSharp.Core/TelegramClient.cs index f7e0258..5fadabe 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; @@ -12,7 +13,6 @@ using TeleSharp.TL.Help; using TeleSharp.TL.Messages; using TeleSharp.TL.Upload; using TLSharp.Core.Auth; -using TLSharp.Core.MTProto.Crypto; using TLSharp.Core.Network; using TLSharp.Core.Utils; using TLAuthorization = TeleSharp.TL.Auth.TLAuthorization; @@ -23,16 +23,12 @@ namespace TLSharp.Core { private MtProtoSender _sender; private TcpTransport _transport; - private string _apiHash = ""; - private int _apiId = 0; - private Session _session; - private List dcOptions; - private TcpClientConnectionHandler _handler; + private readonly string _apiHash = ""; + private readonly int _apiId; + private List _dcOptions; + private readonly TcpClientConnectionHandler _handler; - public Session Session - { - get { return _session; } - } + public Session Session { get; } public TelegramClient(int apiId, string apiHash, ISessionStore store = null, string sessionUserId = "session", TcpClientConnectionHandler handler = null) @@ -49,20 +45,27 @@ namespace TLSharp.Core _apiId = apiId; _handler = handler; - _session = Session.TryLoadOrCreateNew(store, sessionUserId); - _transport = new TcpTransport(_session.DataCenter.Address, _session.DataCenter.Port, _handler); + Session = Session.TryLoadOrCreateNew(store, sessionUserId); + _transport = new TcpTransport(Session.DataCenter.Address, Session.DataCenter.Port, _handler); } public async Task ConnectAsync(bool reconnect = false) { - if (_session.AuthKey == null || reconnect) + await ConnectAsync(CancellationToken.None, reconnect).ConfigureAwait(false); + } + + public async Task ConnectAsync(CancellationToken token, bool reconnect = false) + { + token.ThrowIfCancellationRequested(); + + if (Session.AuthKey == null || reconnect) { - var result = await Authenticator.DoAuthentication(_transport); - _session.AuthKey = result.AuthKey; - _session.TimeOffset = result.TimeOffset; + var result = await Authenticator.DoAuthentication(_transport, token).ConfigureAwait(false); + Session.AuthKey = result.AuthKey; + Session.TimeOffset = result.TimeOffset; } - _sender = new MtProtoSender(_transport, _session); + _sender = new MtProtoSender(_transport, Session); //set-up layer var config = new TLRequestGetConfig(); @@ -76,41 +79,43 @@ 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(); + _dcOptions = ((TLConfig)invokewithLayer.Response).DcOptions.ToList(); } - private async Task ReconnectToDcAsync(int dcId) + private async Task ReconnectToDcAsync(int dcId, CancellationToken token) { - if (dcOptions == null || !dcOptions.Any()) + token.ThrowIfCancellationRequested(); + + if (_dcOptions == null || !_dcOptions.Any()) throw new InvalidOperationException($"Can't reconnect. Establish initial connection first."); TLExportedAuthorization exported = null; - if (_session.TLUser != null) + 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); + var dc = _dcOptions.First(d => d.Id == dcId); var dataCenter = new DataCenter (dcId, dc.IpAddress, dc.Port); _transport = new TcpTransport(dc.IpAddress, dc.Port, _handler); - _session.DataCenter = dataCenter; + Session.DataCenter = dataCenter; - await ConnectAsync(true); + await ConnectAsync(token, true).ConfigureAwait(false); - if (_session.TLUser != null) + 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) { if (_sender == null) throw new InvalidOperationException("Not connected!"); @@ -120,19 +125,19 @@ 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) { - if (_session.DataCenter.DataCenterId.HasValue && - _session.DataCenter.DataCenterId.Value == e.DC) + if (Session.DataCenter.DataCenterId.HasValue && + Session.DataCenter.DataCenterId.Value == e.DC) { 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; } @@ -141,34 +146,49 @@ namespace TLSharp.Core public bool IsUserAuthorized() { - return _session.TLUser != null; + return Session.TLUser != null; } public async Task IsPhoneRegisteredAsync(string phoneNumber) + { + return await IsPhoneRegisteredAsync(phoneNumber, CancellationToken.None).ConfigureAwait(false); + } + + public async Task IsPhoneRegisteredAsync(string phoneNumber, CancellationToken token) { 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) + { + return await SendCodeRequestAsync(phoneNumber, CancellationToken.None).ConfigureAwait(false); + } + + public async Task SendCodeRequestAsync(string phoneNumber, CancellationToken token) { 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) + { + return await MakeAuthAsync(phoneNumber, phoneCodeHash, code, CancellationToken.None).ConfigureAwait(false); + } + + public async Task MakeAuthAsync(string phoneNumber, string phoneCodeHash, string code, CancellationToken token) { if (String.IsNullOrWhiteSpace(phoneNumber)) throw new ArgumentNullException(nameof(phoneNumber)); @@ -181,24 +201,35 @@ 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() + { + return await GetPasswordSetting(CancellationToken.None).ConfigureAwait(false); + } + + public async Task GetPasswordSetting(CancellationToken token) { 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) { + return await MakeAuthWithPasswordAsync(password, password_str, CancellationToken.None).ConfigureAwait(false); + } + + public async Task MakeAuthWithPasswordAsync(TLPassword password, string password_str, CancellationToken token) + { + token.ThrowIfCancellationRequested(); byte[] password_Bytes = Encoding.UTF8.GetBytes(password_str); IEnumerable rv = password.CurrentSalt.Concat(password_Bytes).Concat(password.CurrentSalt); @@ -208,7 +239,7 @@ namespace TLSharp.Core var request = new TLRequestCheckPassword() { PasswordHash = password_hash }; - await RequestWithDcMigration(request); + await RequestWithDcMigration(request, token).ConfigureAwait(false); OnUserAuthenticated(((TLUser)request.Response.User)); @@ -216,18 +247,29 @@ namespace TLSharp.Core } public async Task SignUpAsync(string phoneNumber, string phoneCodeHash, string code, string firstName, string lastName) + { + return await SignUpAsync(phoneNumber, phoneCodeHash, code, firstName, lastName, CancellationToken.None).ConfigureAwait(false); + } + + public async Task SignUpAsync(string phoneNumber, string phoneCodeHash, string code, string firstName, string lastName, CancellationToken token) { 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) { - await RequestWithDcMigration(methodToExecute); + return await SendRequestAsync(methodToExecute, CancellationToken.None).ConfigureAwait(false); + } + + public async Task SendRequestAsync(TLMethod methodToExecute, CancellationToken token) + { + await RequestWithDcMigration(methodToExecute, token).ConfigureAwait(false); var result = methodToExecute.GetType().GetProperty("Response").GetValue(methodToExecute); @@ -235,16 +277,26 @@ namespace TLSharp.Core } public async Task GetContactsAsync() + { + return await GetContactsAsync(CancellationToken.None).ConfigureAwait(false); + } + + public async Task GetContactsAsync(CancellationToken token) { if (!IsUserAuthorized()) throw new InvalidOperationException("Authorize user first!"); var req = new TLRequestGetContacts() { Hash = "" }; - return await SendRequestAsync(req); + return await SendRequestAsync(req, token).ConfigureAwait(false); } public async Task SendMessageAsync(TLAbsInputPeer peer, string message) + { + return await SendMessageAsync(peer, message, CancellationToken.None).ConfigureAwait(false); + } + + public async Task SendMessageAsync(TLAbsInputPeer peer, string message, CancellationToken token) { if (!IsUserAuthorized()) throw new InvalidOperationException("Authorize user first!"); @@ -255,20 +307,30 @@ namespace TLSharp.Core Peer = peer, Message = message, RandomId = Helpers.GenerateRandomLong() - }); + }, token).ConfigureAwait(false); } public async Task SendTypingAsync(TLAbsInputPeer peer) + { + return await SendTypingAsync(peer, CancellationToken.None).ConfigureAwait(false); + } + + public async Task SendTypingAsync(TLAbsInputPeer peer, CancellationToken token) { var req = new TLRequestSetTyping() { Action = new TLSendMessageTypingAction(), Peer = peer }; - return await SendRequestAsync(req); + return await SendRequestAsync(req, token).ConfigureAwait(false); } public async Task GetUserDialogsAsync(int offsetDate = 0, int offsetId = 0, TLAbsInputPeer offsetPeer = null, int limit = 100) + { + return await GetUserDialogsAsync(CancellationToken.None, offsetDate, offsetId, offsetPeer, limit).ConfigureAwait(false); + } + + public async Task GetUserDialogsAsync(CancellationToken token, int offsetDate = 0, int offsetId = 0, TLAbsInputPeer offsetPeer = null, int limit = 100) { if (!IsUserAuthorized()) throw new InvalidOperationException("Authorize user first!"); @@ -283,10 +345,15 @@ namespace TLSharp.Core OffsetPeer = offsetPeer, Limit = limit }; - return await SendRequestAsync(req); + return await SendRequestAsync(req, token).ConfigureAwait(false); } public async Task SendUploadedPhoto(TLAbsInputPeer peer, TLAbsInputFile file, string caption) + { + return await SendUploadedPhoto(peer, file, caption, CancellationToken.None).ConfigureAwait(false); + } + + public async Task SendUploadedPhoto(TLAbsInputPeer peer, TLAbsInputFile file, string caption, CancellationToken token) { return await SendRequestAsync(new TLRequestSendMedia() { @@ -295,11 +362,15 @@ namespace TLSharp.Core 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) + public async Task SendUploadedDocument(TLAbsInputPeer peer, TLAbsInputFile file, string caption, string mimeType, TLVector attributes) + { + return await SendUploadedDocument(peer, file, caption, mimeType, attributes, CancellationToken.None).ConfigureAwait(false); + } + + public async Task SendUploadedDocument(TLAbsInputPeer peer, TLAbsInputFile file, string caption, string mimeType, TLVector attributes, CancellationToken token) { return await SendRequestAsync(new TLRequestSendMedia() { @@ -314,10 +385,15 @@ namespace TLSharp.Core Attributes = attributes }, Peer = peer - }); + }, token).ConfigureAwait(false); } public async Task GetFile(TLAbsInputFileLocation location, int filePartSize, int offset = 0) + { + return await GetFile(location, filePartSize, CancellationToken.None, offset).ConfigureAwait(false); + } + + public async Task GetFile(TLAbsInputFileLocation location, int filePartSize, CancellationToken token, int offset = 0) { TLFile result = null; result = await SendRequestAsync(new TLRequestGetFile() @@ -325,16 +401,16 @@ namespace TLSharp.Core Location = location, Limit = filePartSize, Offset = offset - }); + }, token).ConfigureAwait(false); return result; } - public async Task SendPingAsync() + public async Task SendPingAsync(CancellationToken token) { - 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, CancellationToken token, int offsetId = 0, int offsetDate = 0, int addOffset = 0, int limit = 100, int maxId = 0, int minId = 0) { if (!IsUserAuthorized()) throw new InvalidOperationException("Authorize user first!"); @@ -349,7 +425,7 @@ namespace TLSharp.Core MaxId = maxId, MinId = minId }; - return await SendRequestAsync(req); + return await SendRequestAsync(req, token).ConfigureAwait(false); } /// @@ -359,6 +435,11 @@ namespace TLSharp.Core /// Max result count /// public async Task SearchUserAsync(string q, int limit = 10) + { + return await SearchUserAsync(q, CancellationToken.None, limit).ConfigureAwait(false); + } + + public async Task SearchUserAsync(string q, CancellationToken token, int limit = 10) { var r = new TeleSharp.TL.Contacts.TLRequestSearch { @@ -366,15 +447,15 @@ namespace TLSharp.Core Limit = limit }; - return await SendRequestAsync(r); + return await SendRequestAsync(r, token).ConfigureAwait(false); } private void OnUserAuthenticated(TLUser TLUser) { - _session.TLUser = TLUser; - _session.SessionExpires = int.MaxValue; + Session.TLUser = TLUser; + Session.SessionExpires = int.MaxValue; - _session.Save(); + Session.Save(); } public bool IsConnected diff --git a/TLSharp.Core/Utils/UploadHelper.cs b/TLSharp.Core/Utils/UploadHelper.cs index 3471c51..dba0fac 100644 --- a/TLSharp.Core/Utils/UploadHelper.cs +++ b/TLSharp.Core/Utils/UploadHelper.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; 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; @@ -30,9 +30,14 @@ namespace TLSharp.Core.Utils } public static async Task UploadFile(this TelegramClient client, string name, StreamReader reader) + { + return await UploadFile(client, name, reader, CancellationToken.None).ConfigureAwait(false); + } + + public static async Task UploadFile(this TelegramClient client, string name, StreamReader reader, CancellationToken token) { 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 +82,10 @@ namespace TLSharp.Core.Utils } private static async Task UploadFile(string name, StreamReader reader, - TelegramClient client, bool isBigFileUpload) + TelegramClient client, bool isBigFileUpload, CancellationToken token) { + token.ThrowIfCancellationRequested(); + var file = GetFile(reader); var fileParts = GetFileParts(file); @@ -97,7 +104,7 @@ namespace TLSharp.Core.Utils FilePart = partNumber, Bytes = part, FileTotalParts = partsCount - }); + }, token).ConfigureAwait(false); } else { @@ -106,7 +113,7 @@ namespace TLSharp.Core.Utils FileId = file_id, FilePart = partNumber, Bytes = part - }); + }, token).ConfigureAwait(false); } partNumber++; } @@ -120,16 +127,14 @@ namespace TLSharp.Core.Utils Parts = partsCount }; } - else + + return new TLInputFile { - return new TLInputFile - { - Id = file_id, - Name = name, - Parts = partsCount, - Md5Checksum = GetFileHash(file) - }; - } + Id = file_id, + Name = name, + Parts = partsCount, + Md5Checksum = GetFileHash(file) + }; } } }