* Adds a CancellationToken to the "event" API so that it can be interrupted.

* There's also a new event that allows a client app to know whether it's safe to do requests without interfering with the event loop.
This commit is contained in:
Paulo Rogerio Panhoto 2018-01-08 16:51:33 -02:00
parent 936a26c6bd
commit 9ad192c6d6
3 changed files with 69 additions and 6 deletions

View file

@ -154,9 +154,9 @@ namespace TLSharp.Core.Network
return null;
}
public async Task<byte[]> Receive()
public async Task<byte[]> Receive(CancellationToken token)
{
var result = DecodeMessage ((await _transport.Receieve ()).Body);
var result = DecodeMessage ((await _transport.Receieve (token)).Body);
using (var messageStream = new MemoryStream (result.Item1, false))
using (var messageReader = new BinaryReader (messageStream))

View file

@ -1,6 +1,7 @@
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
namespace TLSharp.Core.Network
@ -86,6 +87,56 @@ namespace TLSharp.Core.Network
return new TcpMessage(seq, body);
}
public async Task<TcpMessage> Receieve(CancellationToken token)
{
var stream = _tcpClient.GetStream();
var packetLengthBytes = new byte[4];
if (await stream.ReadAsync(packetLengthBytes, 0, 4, token) != 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)
throw new InvalidOperationException("Couldn't read the sequence");
int seq = BitConverter.ToInt32(seqBytes, 0);
int readBytes = 0;
var body = new byte[packetLength - 12];
int neededToRead = packetLength - 12;
do
{
var bodyByte = new byte[packetLength - 12];
var availableBytes = await stream.ReadAsync(bodyByte, 0, neededToRead);
neededToRead -= availableBytes;
Buffer.BlockCopy(bodyByte, 0, body, readBytes, availableBytes);
readBytes += availableBytes;
}
while (readBytes != packetLength - 12);
var crcBytes = new byte[4];
if (await stream.ReadAsync(crcBytes, 0, 4) != 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];
Buffer.BlockCopy(packetLengthBytes, 0, rv, 0, packetLengthBytes.Length);
Buffer.BlockCopy(seqBytes, 0, rv, packetLengthBytes.Length, seqBytes.Length);
Buffer.BlockCopy(body, 0, rv, packetLengthBytes.Length + seqBytes.Length, body.Length);
var crc32 = new Ionic.Crc.CRC32();
crc32.SlurpBlock(rv, 0, rv.Length);
var validChecksum = crc32.Crc32Result;
if (checksum != validChecksum)
{
throw new InvalidOperationException("invalid checksum! skip");
}
return new TcpMessage(seq, body);
}
public bool IsConnected
{
get

View file

@ -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;
@ -31,8 +32,10 @@ namespace TLSharp.Core
private TcpClientConnectionHandler _handler;
public delegate void UpdatesEvent (TelegramClient source, TLAbsUpdates updates);
public delegate void ClientEvent(TelegramClient source);
public event UpdatesEvent Updates;
public event ClientEvent IdleLoop;
public Session Session { get { return _session; } }
@ -113,11 +116,20 @@ namespace TLSharp.Core
}
}
public async Task MainLoopAsync()
public async Task MainLoopAsync(CancellationTokenSource source)
{
for (;;)
{
await WaitEventAsync();
try
{
await WaitEventAsync(source.Token);
} catch (OperationCanceledException)
{
}
finally
{
IdleLoop(this);
}
}
}
@ -146,9 +158,9 @@ namespace TLSharp.Core
}
}
public async Task WaitEventAsync()
public async Task WaitEventAsync(CancellationToken token)
{
await _sender.Receive ();
await _sender.Receive (token);
}
public bool IsUserAuthorized()