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
This commit is contained in:
CheshireCaat 2020-01-27 10:03:45 +03:00
parent 1ccafe22a3
commit c5a2c816fc
6 changed files with 198 additions and 141 deletions

View file

@ -1,37 +1,45 @@
using System.Threading.Tasks; using System.Threading;
using System.Threading.Tasks;
using TLSharp.Core.Network; using TLSharp.Core.Network;
namespace TLSharp.Core.Auth namespace TLSharp.Core.Auth
{ {
public static class Authenticator public static class Authenticator
{ {
public static async Task<Step3_Response> DoAuthentication(TcpTransport transport) public static async Task<Step3_Response> DoAuthentication(TcpTransport transport, CancellationToken token = default(CancellationToken))
{ {
token.ThrowIfCancellationRequested();
var sender = new MtProtoPlainSender(transport); var sender = new MtProtoPlainSender(transport);
var step1 = new Step1_PQRequest(); var step1 = new Step1_PQRequest();
await sender.Send(step1.ToBytes()); await sender.Send(step1.ToBytes(), token).ConfigureAwait(false);
var step1Response = step1.FromBytes(await sender.Receive()); var step1Response = step1.FromBytes(await sender.Receive(token)
.ConfigureAwait(false));
var step2 = new Step2_DHExchange(); var step2 = new Step2_DHExchange();
await sender.Send(step2.ToBytes( await sender.Send(step2.ToBytes(
step1Response.Nonce, step1Response.Nonce,
step1Response.ServerNonce, step1Response.ServerNonce,
step1Response.Fingerprints, 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(); var step3 = new Step3_CompleteDHExchange();
await sender.Send(step3.ToBytes( await sender.Send(step3.ToBytes(
step2Response.Nonce, step2Response.Nonce,
step2Response.ServerNonce, step2Response.ServerNonce,
step2Response.NewNonce, 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; return step3Response;
} }
} }
} }

View file

@ -1,5 +1,6 @@
using System; using System;
using System.IO; using System.IO;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace TLSharp.Core.Network namespace TLSharp.Core.Network
@ -17,8 +18,10 @@ namespace TLSharp.Core.Network
random = new Random(); 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 memoryStream = new MemoryStream())
{ {
using (var binaryWriter = new BinaryWriter(memoryStream)) using (var binaryWriter = new BinaryWriter(memoryStream))
@ -30,14 +33,16 @@ namespace TLSharp.Core.Network
byte[] packet = memoryStream.ToArray(); byte[] packet = memoryStream.ToArray();
await _transport.Send(packet); await _transport.Send(packet, token).ConfigureAwait(false);
} }
} }
} }
public async Task<byte[]> Receive() public async Task<byte[]> 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)) using (var memoryStream = new MemoryStream(result.Body))
{ {

View file

@ -7,6 +7,7 @@ using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ionic.Zlib; using Ionic.Zlib;
using TeleSharp.TL;
using TLSharp.Core.Exceptions; using TLSharp.Core.Exceptions;
using TLSharp.Core.MTProto; using TLSharp.Core.MTProto;
using TLSharp.Core.MTProto.Crypto; using TLSharp.Core.MTProto.Crypto;
@ -36,8 +37,10 @@ namespace TLSharp.Core.Network
return confirmed ? _session.Sequence++ * 2 + 1 : _session.Sequence * 2; 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 // TODO: refactor
if (needConfirmation.Any()) if (needConfirmation.Any())
{ {
@ -46,7 +49,7 @@ namespace TLSharp.Core.Network
using (var writer = new BinaryWriter(memory)) using (var writer = new BinaryWriter(memory))
{ {
ackRequest.SerializeBody(writer); ackRequest.SerializeBody(writer);
await Send(memory.ToArray(), ackRequest); await Send(memory.ToArray(), ackRequest, token).ConfigureAwait(false);
needConfirmation.Clear(); needConfirmation.Clear();
} }
} }
@ -56,14 +59,16 @@ namespace TLSharp.Core.Network
using (var writer = new BinaryWriter(memory)) using (var writer = new BinaryWriter(memory))
{ {
request.SerializeBody(writer); request.SerializeBody(writer);
await Send(memory.ToArray(), request); await Send(memory.ToArray(), request, token).ConfigureAwait(false);
} }
_session.Save(); _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(); request.MessageId = _session.GetNewMessageId();
byte[] msgKey; byte[] msgKey;
@ -92,7 +97,7 @@ namespace TLSharp.Core.Network
writer.Write(msgKey); writer.Write(msgKey);
writer.Write(ciphertext); 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<byte[], ulong, int>(message, remoteMessageId, remoteSequence); return new Tuple<byte[], ulong, int>(message, remoteMessageId, remoteSequence);
} }
public async Task<byte[]> Receive(TeleSharp.TL.TLMethod request) public async Task<byte[]> Receive(TeleSharp.TL.TLMethod request, CancellationToken token = default(CancellationToken))
{ {
while (!request.ConfirmReceived) 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 messageStream = new MemoryStream(result.Item1, false))
using (var messageReader = new BinaryReader(messageStream)) 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; return null;
} }
public async Task SendPingAsync() public async Task SendPingAsync(CancellationToken token = default(CancellationToken))
{ {
token.ThrowIfCancellationRequested();
var pingRequest = new PingRequest(); var pingRequest = new PingRequest();
using (var memory = new MemoryStream()) using (var memory = new MemoryStream())
using (var writer = new BinaryWriter(memory)) using (var writer = new BinaryWriter(memory))
{ {
pingRequest.SerializeBody(writer); 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 salt
// TODO: check sessionid // TODO: check sessionid
// TODO: check seqno // TODO: check seqno
@ -173,7 +184,7 @@ namespace TLSharp.Core.Network
{ {
case 0x73f1f8dc: // container case 0x73f1f8dc: // container
//logger.debug("MSG container"); //logger.debug("MSG container");
return HandleContainer(messageId, sequence, messageReader, request); return HandleContainer(messageId, sequence, messageReader, request, token);
case 0x7abe77ec: // ping case 0x7abe77ec: // ping
//logger.debug("MSG ping"); //logger.debug("MSG ping");
return HandlePing(messageId, sequence, messageReader); return HandlePing(messageId, sequence, messageReader);
@ -191,7 +202,7 @@ namespace TLSharp.Core.Network
return HandleMsgsAck(messageId, sequence, messageReader); return HandleMsgsAck(messageId, sequence, messageReader);
case 0xedab447b: // bad_server_salt case 0xedab447b: // bad_server_salt
//logger.debug("MSG 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 case 0xa7eff811: // bad_msg_notification
//logger.debug("MSG bad_msg_notification"); //logger.debug("MSG bad_msg_notification");
return HandleBadMsgNotification(messageId, sequence, messageReader); return HandleBadMsgNotification(messageId, sequence, messageReader);
@ -203,7 +214,7 @@ namespace TLSharp.Core.Network
return HandleRpcResult(messageId, sequence, messageReader, request); return HandleRpcResult(messageId, sequence, messageReader, request);
case 0x3072cfa1: // gzip_packed case 0x3072cfa1: // gzip_packed
//logger.debug("MSG gzip_packed"); //logger.debug("MSG gzip_packed");
return HandleGzipPacked(messageId, sequence, messageReader, request); return HandleGzipPacked(messageId, sequence, messageReader, request, token);
case 0xe317af7e: case 0xe317af7e:
case 0xd3f45784: case 0xd3f45784:
case 0x2b2fbd4e: 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(); uint code = messageReader.ReadUInt32();
byte[] packedData = GZipStream.UncompressBuffer(Serializers.Bytes.Read(messageReader)); byte[] packedData = GZipStream.UncompressBuffer(Serializers.Bytes.Read(messageReader));
using (MemoryStream packedStream = new MemoryStream(packedData, false)) using (MemoryStream packedStream = new MemoryStream(packedData, false))
using (BinaryReader compressedReader = new BinaryReader(packedStream)) using (BinaryReader compressedReader = new BinaryReader(packedStream))
{ {
processMessage(messageId, sequence, compressedReader, request); processMessage(messageId, sequence, compressedReader, request, token);
} }
return true; return true;
@ -414,8 +427,10 @@ namespace TLSharp.Core.Network
return true; 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(); uint code = messageReader.ReadUInt32();
ulong badMsgId = messageReader.ReadUInt64(); ulong badMsgId = messageReader.ReadUInt64();
int badMsgSeqNo = messageReader.ReadInt32(); int badMsgSeqNo = messageReader.ReadInt32();
@ -427,7 +442,7 @@ namespace TLSharp.Core.Network
_session.Salt = newSalt; _session.Salt = newSalt;
//resend //resend
Send(request); Send(request, token);
/* /*
if(!runningRequests.ContainsKey(badMsgId)) { if(!runningRequests.ContainsKey(badMsgId)) {
logger.debug("bad server salt on unknown message"); logger.debug("bad server salt on unknown message");
@ -493,8 +508,10 @@ namespace TLSharp.Core.Network
return false; 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(); uint code = messageReader.ReadUInt32();
int size = messageReader.ReadInt32(); int size = messageReader.ReadInt32();
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
@ -505,7 +522,7 @@ namespace TLSharp.Core.Network
long beginPosition = messageReader.BaseStream.Position; long beginPosition = messageReader.BaseStream.Position;
try try
{ {
if (!processMessage(innerMessageId, sequence, messageReader, request)) if (!processMessage(innerMessageId, sequence, messageReader, request, token))
{ {
messageReader.BaseStream.Position = beginPosition + innerLength; messageReader.BaseStream.Position = beginPosition + innerLength;
} }

View file

@ -1,6 +1,7 @@
using System; using System;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace TLSharp.Core.Network 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) if (!_tcpClient.Connected)
throw new InvalidOperationException("Client not connected to server."); 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); await _stream.WriteAsync(tcpMessage.Encode(), 0, tcpMessage.Encode().Length, token).ConfigureAwait(false);
sendCounter++; sendCounter++;
} }
public async Task<TcpMessage> Receive() public async Task<TcpMessage> Receive(CancellationToken token = default(CancellationToken))
{ {
var packetLengthBytes = new byte[4]; 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"); throw new InvalidOperationException("Couldn't read the packet length");
int packetLength = BitConverter.ToInt32(packetLengthBytes, 0); int packetLength = BitConverter.ToInt32(packetLengthBytes, 0);
var seqBytes = new byte[4]; 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"); throw new InvalidOperationException("Couldn't read the sequence");
int seq = BitConverter.ToInt32(seqBytes, 0); int seq = BitConverter.ToInt32(seqBytes, 0);
@ -62,7 +63,7 @@ namespace TLSharp.Core.Network
do do
{ {
var bodyByte = new byte[packetLength - 12]; 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; neededToRead -= availableBytes;
Buffer.BlockCopy(bodyByte, 0, body, readBytes, availableBytes); Buffer.BlockCopy(bodyByte, 0, body, readBytes, availableBytes);
readBytes += availableBytes; readBytes += availableBytes;
@ -70,7 +71,7 @@ namespace TLSharp.Core.Network
while (readBytes != packetLength - 12); while (readBytes != packetLength - 12);
var crcBytes = new byte[4]; 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"); throw new InvalidOperationException("Couldn't read the crc");
int checksum = BitConverter.ToInt32(crcBytes, 0); int checksum = BitConverter.ToInt32(crcBytes, 0);

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using TeleSharp.TL; using TeleSharp.TL;
using TeleSharp.TL.Account; using TeleSharp.TL.Account;
@ -55,11 +56,13 @@ namespace TLSharp.Core
_transport = new TcpTransport(_session.DataCenter.Address, _session.DataCenter.Port, _handler); _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) 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.AuthKey = result.AuthKey;
_session.TimeOffset = result.TimeOffset; _session.TimeOffset = result.TimeOffset;
} }
@ -78,14 +81,16 @@ namespace TLSharp.Core
SystemVersion = "Win 10.0" SystemVersion = "Win 10.0"
}; };
var invokewithLayer = new TLRequestInvokeWithLayer() { Layer = 66, Query = request }; var invokewithLayer = new TLRequestInvokeWithLayer() { Layer = 66, Query = request };
await _sender.Send(invokewithLayer); await _sender.Send(invokewithLayer, token).ConfigureAwait(false);
await _sender.Receive(invokewithLayer); 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 = default(CancellationToken))
{ {
token.ThrowIfCancellationRequested();
if (dcOptions == null || !dcOptions.Any()) if (dcOptions == null || !dcOptions.Any())
throw new InvalidOperationException($"Can't reconnect. Establish initial connection first."); throw new InvalidOperationException($"Can't reconnect. Establish initial connection first.");
@ -93,7 +98,7 @@ namespace TLSharp.Core
if (_session.TLUser != null) if (_session.TLUser != null)
{ {
TLRequestExportAuthorization exportAuthorization = new TLRequestExportAuthorization() { DcId = dcId }; TLRequestExportAuthorization exportAuthorization = new TLRequestExportAuthorization() { DcId = dcId };
exported = await SendRequestAsync<TLExportedAuthorization>(exportAuthorization); exported = await SendRequestAsync<TLExportedAuthorization>(exportAuthorization, token).ConfigureAwait(false);
} }
var dc = dcOptions.First(d => d.Id == dcId); var dc = dcOptions.First(d => d.Id == dcId);
@ -102,17 +107,17 @@ namespace TLSharp.Core
_transport = new TcpTransport(dc.IpAddress, dc.Port, _handler); _transport = new TcpTransport(dc.IpAddress, dc.Port, _handler);
_session.DataCenter = dataCenter; _session.DataCenter = dataCenter;
await ConnectAsync(true); await ConnectAsync(true, token).ConfigureAwait(false);
if (_session.TLUser != null) if (_session.TLUser != null)
{ {
TLRequestImportAuthorization importAuthorization = new TLRequestImportAuthorization() { Id = exported.Id, Bytes = exported.Bytes }; TLRequestImportAuthorization importAuthorization = new TLRequestImportAuthorization() { Id = exported.Id, Bytes = exported.Bytes };
var imported = await SendRequestAsync<TLAuthorization>(importAuthorization); var imported = await SendRequestAsync<TLAuthorization>(importAuthorization, token).ConfigureAwait(false);
OnUserAuthenticated(((TLUser)imported.User)); OnUserAuthenticated(((TLUser)imported.User));
} }
} }
private async Task RequestWithDcMigration(TLMethod request) private async Task RequestWithDcMigration(TLMethod request, CancellationToken token = default(CancellationToken))
{ {
if (_sender == null) if (_sender == null)
throw new InvalidOperationException("Not connected!"); throw new InvalidOperationException("Not connected!");
@ -122,8 +127,8 @@ namespace TLSharp.Core
{ {
try try
{ {
await _sender.Send(request); await _sender.Send(request, token).ConfigureAwait(false);
await _sender.Receive(request); await _sender.Receive(request, token).ConfigureAwait(false);
completed = true; completed = true;
} }
catch(DataCenterMigrationException e) 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); 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 // prepare the request for another try
request.ConfirmReceived = false; request.ConfirmReceived = false;
} }
@ -146,31 +151,31 @@ namespace TLSharp.Core
return _session.TLUser != null; return _session.TLUser != null;
} }
public async Task<bool> IsPhoneRegisteredAsync(string phoneNumber) public async Task<bool> IsPhoneRegisteredAsync(string phoneNumber, CancellationToken token = default(CancellationToken))
{ {
if (String.IsNullOrWhiteSpace(phoneNumber)) if (String.IsNullOrWhiteSpace(phoneNumber))
throw new ArgumentNullException(nameof(phoneNumber)); throw new ArgumentNullException(nameof(phoneNumber));
var authCheckPhoneRequest = new TLRequestCheckPhone() { PhoneNumber = phoneNumber }; var authCheckPhoneRequest = new TLRequestCheckPhone() { PhoneNumber = phoneNumber };
await RequestWithDcMigration(authCheckPhoneRequest); await RequestWithDcMigration(authCheckPhoneRequest, token).ConfigureAwait(false);
return authCheckPhoneRequest.Response.PhoneRegistered; return authCheckPhoneRequest.Response.PhoneRegistered;
} }
public async Task<string> SendCodeRequestAsync(string phoneNumber) public async Task<string> SendCodeRequestAsync(string phoneNumber, CancellationToken token = default(CancellationToken))
{ {
if (String.IsNullOrWhiteSpace(phoneNumber)) if (String.IsNullOrWhiteSpace(phoneNumber))
throw new ArgumentNullException(nameof(phoneNumber)); throw new ArgumentNullException(nameof(phoneNumber));
var request = new TLRequestSendCode() { PhoneNumber = phoneNumber, ApiId = _apiId, ApiHash = _apiHash }; var request = new TLRequestSendCode() { PhoneNumber = phoneNumber, ApiId = _apiId, ApiHash = _apiHash };
await RequestWithDcMigration(request); await RequestWithDcMigration(request, token).ConfigureAwait(false);
return request.Response.PhoneCodeHash; return request.Response.PhoneCodeHash;
} }
public async Task<TLUser> MakeAuthAsync(string phoneNumber, string phoneCodeHash, string code) public async Task<TLUser> MakeAuthAsync(string phoneNumber, string phoneCodeHash, string code, CancellationToken token = default(CancellationToken))
{ {
if (String.IsNullOrWhiteSpace(phoneNumber)) if (String.IsNullOrWhiteSpace(phoneNumber))
throw new ArgumentNullException(nameof(phoneNumber)); throw new ArgumentNullException(nameof(phoneNumber));
@ -183,24 +188,26 @@ namespace TLSharp.Core
var request = new TLRequestSignIn() { PhoneNumber = phoneNumber, PhoneCodeHash = phoneCodeHash, PhoneCode = code }; var request = new TLRequestSignIn() { PhoneNumber = phoneNumber, PhoneCodeHash = phoneCodeHash, PhoneCode = code };
await RequestWithDcMigration(request); await RequestWithDcMigration(request, token).ConfigureAwait(false);
OnUserAuthenticated(((TLUser)request.Response.User)); OnUserAuthenticated(((TLUser)request.Response.User));
return ((TLUser)request.Response.User); return ((TLUser)request.Response.User);
} }
public async Task<TLPassword> GetPasswordSetting() public async Task<TLPassword> GetPasswordSetting(CancellationToken token = default(CancellationToken))
{ {
var request = new TLRequestGetPassword(); var request = new TLRequestGetPassword();
await RequestWithDcMigration(request); await RequestWithDcMigration(request, token).ConfigureAwait(false);
return ((TLPassword)request.Response); return ((TLPassword)request.Response);
} }
public async Task<TLUser> MakeAuthWithPasswordAsync(TLPassword password, string password_str) public async Task<TLUser> MakeAuthWithPasswordAsync(TLPassword password, string password_str, CancellationToken token = default(CancellationToken))
{ {
token.ThrowIfCancellationRequested();
byte[] password_Bytes = Encoding.UTF8.GetBytes(password_str); byte[] password_Bytes = Encoding.UTF8.GetBytes(password_str);
IEnumerable<byte> rv = password.CurrentSalt.Concat(password_Bytes).Concat(password.CurrentSalt); IEnumerable<byte> rv = password.CurrentSalt.Concat(password_Bytes).Concat(password.CurrentSalt);
@ -209,105 +216,114 @@ namespace TLSharp.Core
var request = new TLRequestCheckPassword() { PasswordHash = password_hash }; var request = new TLRequestCheckPassword() { PasswordHash = password_hash };
await RequestWithDcMigration(request); await RequestWithDcMigration(request, token).ConfigureAwait(false);
OnUserAuthenticated(((TLUser)request.Response.User)); OnUserAuthenticated(((TLUser)request.Response.User));
return ((TLUser)request.Response.User); return ((TLUser)request.Response.User);
} }
public async Task<TLUser> SignUpAsync(string phoneNumber, string phoneCodeHash, string code, string firstName, string lastName) public async Task<TLUser> 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 }; 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)); OnUserAuthenticated(((TLUser)request.Response.User));
return ((TLUser)request.Response.User); return ((TLUser)request.Response.User);
} }
public async Task<T> SendRequestAsync<T>(TLMethod methodToExecute) public async Task<T> SendRequestAsync<T>(TLMethod methodToExecute, CancellationToken token = default(CancellationToken))
{ {
await RequestWithDcMigration(methodToExecute); await RequestWithDcMigration(methodToExecute, token).ConfigureAwait(false);
var result = methodToExecute.GetType().GetProperty("Response").GetValue(methodToExecute); var result = methodToExecute.GetType().GetProperty("Response").GetValue(methodToExecute);
return (T)result; return (T)result;
} }
private async Task<T> SendAuthenticatedRequestAsync<T> (TLMethod methodToExecute) internal async Task<T> SendAuthenticatedRequestAsync<T> (TLMethod methodToExecute, CancellationToken token = default(CancellationToken))
{ {
if (!IsUserAuthorized()) if (!IsUserAuthorized())
throw new InvalidOperationException("Authorize user first!"); throw new InvalidOperationException("Authorize user first!");
return await SendRequestAsync<T>(methodToExecute); return await SendRequestAsync<T>(methodToExecute, token)
.ConfigureAwait(false);
} }
public async Task<TLUser> UpdateUsernameAsync(string username) public async Task<TLUser> UpdateUsernameAsync(string username, CancellationToken token = default(CancellationToken))
{ {
var req = new TLRequestUpdateUsername { Username = username }; var req = new TLRequestUpdateUsername { Username = username };
return await SendAuthenticatedRequestAsync<TLUser>(req); return await SendAuthenticatedRequestAsync<TLUser>(req, token)
.ConfigureAwait(false);
} }
public async Task<bool> CheckUsernameAsync(string username) public async Task<bool> CheckUsernameAsync(string username, CancellationToken token = default(CancellationToken))
{ {
var req = new TLRequestCheckUsername { Username = username }; var req = new TLRequestCheckUsername { Username = username };
return await SendAuthenticatedRequestAsync<bool>(req); return await SendAuthenticatedRequestAsync<bool>(req, token)
.ConfigureAwait(false);
} }
public async Task<TLImportedContacts> ImportContactsAsync(IReadOnlyList<TLInputPhoneContact> contacts) public async Task<TLImportedContacts> ImportContactsAsync(IReadOnlyList<TLInputPhoneContact> contacts, CancellationToken token = default(CancellationToken))
{ {
var req = new TLRequestImportContacts { Contacts = new TLVector<TLInputPhoneContact>(contacts)}; var req = new TLRequestImportContacts { Contacts = new TLVector<TLInputPhoneContact>(contacts)};
return await SendAuthenticatedRequestAsync<TLImportedContacts>(req); return await SendAuthenticatedRequestAsync<TLImportedContacts>(req, token)
.ConfigureAwait(false);
} }
public async Task<bool> DeleteContactsAsync(IReadOnlyList<TLAbsInputUser> users) public async Task<bool> DeleteContactsAsync(IReadOnlyList<TLAbsInputUser> users, CancellationToken token = default(CancellationToken))
{ {
var req = new TLRequestDeleteContacts {Id = new TLVector<TLAbsInputUser>(users)}; var req = new TLRequestDeleteContacts {Id = new TLVector<TLAbsInputUser>(users)};
return await SendAuthenticatedRequestAsync<bool>(req); return await SendAuthenticatedRequestAsync<bool>(req, token)
.ConfigureAwait(false);
} }
public async Task<TLLink> DeleteContactAsync(TLAbsInputUser user) public async Task<TLLink> DeleteContactAsync(TLAbsInputUser user, CancellationToken token = default(CancellationToken))
{ {
var req = new TLRequestDeleteContact {Id = user}; var req = new TLRequestDeleteContact {Id = user};
return await SendAuthenticatedRequestAsync<TLLink>(req); return await SendAuthenticatedRequestAsync<TLLink>(req, token)
.ConfigureAwait(false);
} }
public async Task<TLContacts> GetContactsAsync() public async Task<TLContacts> GetContactsAsync(CancellationToken token = default(CancellationToken))
{ {
var req = new TLRequestGetContacts() { Hash = "" }; var req = new TLRequestGetContacts() { Hash = "" };
return await SendAuthenticatedRequestAsync<TLContacts>(req); return await SendAuthenticatedRequestAsync<TLContacts>(req, token)
.ConfigureAwait(false);
} }
public async Task<TLAbsUpdates> SendMessageAsync(TLAbsInputPeer peer, string message) public async Task<TLAbsUpdates> SendMessageAsync(TLAbsInputPeer peer, string message, CancellationToken token = default(CancellationToken))
{ {
return await SendAuthenticatedRequestAsync<TLAbsUpdates>( return await SendAuthenticatedRequestAsync<TLAbsUpdates>(
new TLRequestSendMessage() new TLRequestSendMessage()
{ {
Peer = peer, Peer = peer,
Message = message, Message = message,
RandomId = Helpers.GenerateRandomLong() RandomId = Helpers.GenerateRandomLong()
}); }, token)
.ConfigureAwait(false);
} }
public async Task<Boolean> SendTypingAsync(TLAbsInputPeer peer) public async Task<Boolean> SendTypingAsync(TLAbsInputPeer peer, CancellationToken token = default(CancellationToken))
{ {
var req = new TLRequestSetTyping() var req = new TLRequestSetTyping()
{ {
Action = new TLSendMessageTypingAction(), Action = new TLSendMessageTypingAction(),
Peer = peer Peer = peer
}; };
return await SendRequestAsync<Boolean>(req); return await SendAuthenticatedRequestAsync<Boolean>(req, token)
.ConfigureAwait(false);
} }
public async Task<TLAbsDialogs> GetUserDialogsAsync(int offsetDate = 0, int offsetId = 0, TLAbsInputPeer offsetPeer = null, int limit = 100) public async Task<TLAbsDialogs> GetUserDialogsAsync(int offsetDate = 0, int offsetId = 0, TLAbsInputPeer offsetPeer = null, int limit = 100, CancellationToken token = default(CancellationToken))
{ {
if (offsetPeer == null) if (offsetPeer == null)
offsetPeer = new TLInputPeerSelf(); offsetPeer = new TLInputPeerSelf();
@ -319,58 +335,63 @@ namespace TLSharp.Core
OffsetPeer = offsetPeer, OffsetPeer = offsetPeer,
Limit = limit Limit = limit
}; };
return await SendAuthenticatedRequestAsync<TLAbsDialogs>(req); return await SendAuthenticatedRequestAsync<TLAbsDialogs>(req, token)
.ConfigureAwait(false);
} }
public async Task<TLAbsUpdates> SendUploadedPhoto(TLAbsInputPeer peer, TLAbsInputFile file, string caption) public async Task<TLAbsUpdates> SendUploadedPhoto(TLAbsInputPeer peer, TLAbsInputFile file, string caption, CancellationToken token = default(CancellationToken))
{ {
return await SendRequestAsync<TLAbsUpdates>(new TLRequestSendMedia() return await SendAuthenticatedRequestAsync<TLAbsUpdates>(new TLRequestSendMedia()
{ {
RandomId = Helpers.GenerateRandomLong(), RandomId = Helpers.GenerateRandomLong(),
Background = false, Background = false,
ClearDraft = false, ClearDraft = false,
Media = new TLInputMediaUploadedPhoto() { File = file, Caption = caption }, Media = new TLInputMediaUploadedPhoto() { File = file, Caption = caption },
Peer = peer Peer = peer
}); }, token)
.ConfigureAwait(false);
} }
public async Task<TLAbsUpdates> SendUploadedDocument( public async Task<TLAbsUpdates> SendUploadedDocument(
TLAbsInputPeer peer, TLAbsInputFile file, string caption, string mimeType, TLVector<TLAbsDocumentAttribute> attributes) TLAbsInputPeer peer, TLAbsInputFile file, string caption, string mimeType, TLVector<TLAbsDocumentAttribute> attributes, CancellationToken token = default(CancellationToken))
{ {
return await SendRequestAsync<TLAbsUpdates>(new TLRequestSendMedia() return await SendAuthenticatedRequestAsync<TLAbsUpdates>(new TLRequestSendMedia()
{
RandomId = Helpers.GenerateRandomLong(),
Background = false,
ClearDraft = false,
Media = new TLInputMediaUploadedDocument()
{ {
File = file, RandomId = Helpers.GenerateRandomLong(),
Caption = caption, Background = false,
MimeType = mimeType, ClearDraft = false,
Attributes = attributes Media = new TLInputMediaUploadedDocument()
}, {
Peer = peer File = file,
}); Caption = caption,
MimeType = mimeType,
Attributes = attributes
},
Peer = peer
}, token)
.ConfigureAwait(false);
} }
public async Task<TLFile> GetFile(TLAbsInputFileLocation location, int filePartSize, int offset = 0) public async Task<TLFile> GetFile(TLAbsInputFileLocation location, int filePartSize, int offset = 0, CancellationToken token = default(CancellationToken))
{ {
TLFile result = null; TLFile result = null;
result = await SendRequestAsync<TLFile>(new TLRequestGetFile() result = await SendAuthenticatedRequestAsync<TLFile>(new TLRequestGetFile
{ {
Location = location, Location = location,
Limit = filePartSize, Limit = filePartSize,
Offset = offset Offset = offset
}); }, token)
.ConfigureAwait(false);
return result; 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<TLAbsMessages> GetHistoryAsync(TLAbsInputPeer peer, int offsetId = 0, int offsetDate = 0, int addOffset = 0, int limit = 100, int maxId = 0, int minId = 0) public async Task<TLAbsMessages> 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() var req = new TLRequestGetHistory()
{ {
@ -382,7 +403,8 @@ namespace TLSharp.Core
MaxId = maxId, MaxId = maxId,
MinId = minId MinId = minId
}; };
return await SendAuthenticatedRequestAsync<TLAbsMessages>(req); return await SendAuthenticatedRequestAsync<TLAbsMessages>(req, token)
.ConfigureAwait(false);
} }
/// <summary> /// <summary>
@ -391,7 +413,7 @@ namespace TLSharp.Core
/// <param name="q">User or chat name</param> /// <param name="q">User or chat name</param>
/// <param name="limit">Max result count</param> /// <param name="limit">Max result count</param>
/// <returns></returns> /// <returns></returns>
public async Task<TLFound> SearchUserAsync(string q, int limit = 10) public async Task<TLFound> SearchUserAsync(string q, int limit = 10, CancellationToken token = default(CancellationToken))
{ {
var r = new TeleSharp.TL.Contacts.TLRequestSearch var r = new TeleSharp.TL.Contacts.TLRequestSearch
{ {
@ -399,7 +421,8 @@ namespace TLSharp.Core
Limit = limit Limit = limit
}; };
return await SendRequestAsync<TLFound>(r); return await SendAuthenticatedRequestAsync<TLFound>(r, token)
.ConfigureAwait(false);
} }
private void OnUserAuthenticated(TLUser TLUser) private void OnUserAuthenticated(TLUser TLUser)

View file

@ -4,6 +4,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using TeleSharp.TL; using TeleSharp.TL;
using TeleSharp.TL.Upload; using TeleSharp.TL.Upload;
@ -29,10 +30,10 @@ namespace TLSharp.Core.Utils
return md5_checksum; return md5_checksum;
} }
public static async Task<TLAbsInputFile> UploadFile(this TelegramClient client, string name, StreamReader reader) public static async Task<TLAbsInputFile> UploadFile(this TelegramClient client, string name, StreamReader reader, CancellationToken token = default(CancellationToken))
{ {
const long tenMb = 10 * 1024 * 1024; 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) private static byte[] GetFile(StreamReader reader)
@ -77,8 +78,10 @@ namespace TLSharp.Core.Utils
} }
private static async Task<TLAbsInputFile> UploadFile(string name, StreamReader reader, private static async Task<TLAbsInputFile> UploadFile(string name, StreamReader reader,
TelegramClient client, bool isBigFileUpload) TelegramClient client, bool isBigFileUpload, CancellationToken token = default(CancellationToken))
{ {
token.ThrowIfCancellationRequested();
var file = GetFile(reader); var file = GetFile(reader);
var fileParts = GetFileParts(file); var fileParts = GetFileParts(file);
@ -91,22 +94,22 @@ namespace TLSharp.Core.Utils
if (isBigFileUpload) if (isBigFileUpload)
{ {
await client.SendRequestAsync<bool>(new TLRequestSaveBigFilePart await client.SendAuthenticatedRequestAsync<bool>(new TLRequestSaveBigFilePart
{ {
FileId = file_id, FileId = file_id,
FilePart = partNumber, FilePart = partNumber,
Bytes = part, Bytes = part,
FileTotalParts = partsCount FileTotalParts = partsCount
}); }, token).ConfigureAwait(false);
} }
else else
{ {
await client.SendRequestAsync<bool>(new TLRequestSaveFilePart await client.SendAuthenticatedRequestAsync<bool>(new TLRequestSaveFilePart
{ {
FileId = file_id, FileId = file_id,
FilePart = partNumber, FilePart = partNumber,
Bytes = part Bytes = part
}); }, token).ConfigureAwait(false);
} }
partNumber++; partNumber++;
} }