diff --git a/README.md b/README.md index 5cc63cf..77c5aa4 100644 --- a/README.md +++ b/README.md @@ -151,6 +151,220 @@ To download file you should call **GetFile** method Full code you can see at [DownloadFileFromContactTest](https://github.com/sochix/TLSharp/blob/master/TLSharp.Tests/TLSharpTests.cs#L167) +# Events Sample code +```csharp +using System; +using System.Threading.Tasks; +using TeleSharp.TL; +using TLSharp.Core; +using System.Linq; +using TeleSharp.TL.Messages; + +namespace TLSharpPOC +{ + class MainClass + { + const int APIId = 0; + const string APIHash = "???"; + const string phone = "???"; + public static void Main(string[] args) + { + new MainClass().MainAsync(args).Wait(); + } + + private async Task MainAsync(string[] args) + { + TelegramClient client = null; + + client = new TelegramClient(APIId, APIHash); + // subscribe an event to receive live messages + client.Updates += ClientUpdates; + await client.ConnectAsync(); + Console.WriteLine($"Authorised: {client.IsUserAuthorized()}"); + TLUser user = null; + // -- If the user has already authenticated, this step will prevent account from being blocked as it + // -- reuses the data from last authorisation. + if (client.IsUserAuthorized()) + user = client.Session.TLUser; + else + { + var registered = await client.IsPhoneRegisteredAsync(phone); + var hash = await client.SendCodeRequestAsync(phone); + Console.Write("Code: "); + var code = Console.ReadLine(); + if (!registered) + { + Console.WriteLine($"Sign up {phone}"); + user = await client.SignUpAsync(phone, hash, code, "First", "Last"); + } + Console.WriteLine($"Sign in {phone}"); + user = await client.MakeAuthAsync(phone, hash, code); + } + + var contacts = await client.GetContactsAsync(); + Console.WriteLine("Contacts:"); + foreach (var contact in contacts.Users.OfType()) + { + var contactUser = contact as TLUser; + Console.WriteLine($"\t{contact.Id} {contact.Phone} {contact.FirstName} {contact.LastName}"); + } + + + var dialogs = (TLDialogs) await client.GetUserDialogsAsync(); + Console.WriteLine("Channels: "); + foreach (var channelObj in dialogs.Chats.OfType()) + { + var channel = channelObj as TLChannel; + Console.WriteLine($"\tChat: {channel.Title}"); + } + + Console.WriteLine("Groups:"); + TLChat chat = null; + foreach (var chatObj in dialogs.Chats.OfType()) + { + chat = chatObj as TLChat; + Console.WriteLine($"Chat name: {chat.Title}"); + var request = new TLRequestGetFullChat() { ChatId = chat.Id }; + var fullChat = await client.SendRequestAsync(request); + + var participants = (fullChat.FullChat as TeleSharp.TL.TLChatFull).Participants as TLChatParticipants; + foreach (var p in participants.Participants) + { + if (p is TLChatParticipant chatParticipant) + { + Console.WriteLine($"\t{chatParticipant.UserId}"); + } + else if (p is TLChatParticipantAdmin chatParticipantAdmin) + { + Console.WriteLine($"\t{chatParticipantAdmin.UserId}**"); + } + else if (p is TLChatParticipantCreator chatParticipantCreator) + { + Console.WriteLine($"\t{chatParticipantCreator.UserId}**"); + } + } + + var peer = new TLInputPeerChat() { ChatId = chat.Id }; + var msg = await client.GetHistoryAsync(peer, 0, 0, 0); + Console.WriteLine(msg); + if (msg is TLMessages messages) + { + foreach (var message in messages.Messages) + { + if (message is TLMessage m1) + { + Console.WriteLine($"\t\t{m1.Id} {m1.Message}"); + } + else if (message is TLMessageService msgService) + { + Console.WriteLine($"\t\t{msgService.Id} {msgService.Action}"); + } + } + } + else if (msg is TLMessagesSlice messagesSlice) + { + bool done = false; + int total = 0; + while (!done) + { + foreach (var m1 in messagesSlice.Messages) + { + if (m1 is TLMessage message) + { + Console.WriteLine($"\t\t{message.Id} {message.Message}"); + ++total; + } + else if (m1 is TLMessageService messageService) + { + Console.WriteLine($"\t\t{messageService.Id} {messageService.Action}"); + ++total; + done = messageService.Action is TLMessageActionChatCreate; + } + } + msg = await client.GetHistoryAsync(peer, total, 0, 0); + } + } + } + + // -- Wait in a loop to handle incoming updates. No need to poll. + while(true) + { + await client.WaitEventAsync(TimeSpan.FromSeconds(1)); + } + } + + private void ClientUpdates(TelegramClient client, TLAbsUpdates updates) + { + Console.WriteLine($"Got update: {updates}"); + if (updates is TLUpdateShort updateShort) + { + Console.WriteLine($"Short: {updateShort.Update}"); + if (updateShort.Update is TLUpdateUserStatus status) + { + Console.WriteLine($"User {status.UserId} is {status.Status}"); + if (status.Status is TLUserStatusOnline) + { + var peer = new TLInputPeerUser() { UserId = status.UserId }; + client.SendMessageAsync(peer, "Você está online.").Wait(); + } + } + } + else if (updates is TLUpdateShortMessage message) + { + Console.WriteLine($"Message: {message.Message}"); + MarkMessageRead(client, new TLInputPeerUser() { UserId = message.UserId }, message.Id); + } + else if (updates is TLUpdateShortChatMessage shortChatMessage) + { + Console.WriteLine($"Chat Message: {shortChatMessage.Message}"); + MarkMessageRead(client, new TLInputPeerChat() { ChatId = shortChatMessage.ChatId }, shortChatMessage.Id); + } + else if (updates is TLUpdates allUpdates) + { + foreach (var update in allUpdates.Updates) + { + Console.WriteLine($"\t{update}"); + if (update is TLUpdateNewChannelMessage metaMessage) + { + var channelMsg = metaMessage.Message as TLMessage; + Console.WriteLine($"Channel message: {channelMsg.Message}"); + var channel = allUpdates.Chats[0] as TLChannel; + MarkMessageRead(client, + new TLInputPeerChannel() { ChannelId = channel.Id, AccessHash = channel.AccessHash.Value }, + channelMsg.Id); + } + } + + foreach (var user in allUpdates.Users) + { + Console.WriteLine($"{user}"); + } + + foreach (var chat in allUpdates.Chats) + { + Console.WriteLine($"{chat}"); + } + } + } + + private void MarkMessageRead(TelegramClient client, TLAbsInputPeer peer, int id) + { + try + { + var request = new TLRequestReadHistory(); + request.MaxId = id; + request.Peer = peer; + client.SendRequestAsync(request).Wait(); + } + catch (InvalidOperationException e) + { + Console.WriteLine($"MarkMessageRead Error: {e.Message}"); + } + } + } +} +``` + # Available Methods For your convenience TLSharp have wrappers for several Telegram API methods. You could add your own, see details below. diff --git a/TLSharp.Core/Network/MtProtoSender.cs b/TLSharp.Core/Network/MtProtoSender.cs index d57b0b5..8d8e0da 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.IO.Compression; using System.Linq; @@ -24,8 +23,14 @@ namespace TLSharp.Core.Network private readonly TcpTransport transport; private readonly Session session; + private readonly uint UpdatesTooLongID = (uint) new TLUpdatesTooLong().Constructor; + public readonly List needConfirmation = new List(); + public delegate void HandleUpdates (TLAbsUpdates updates); + + public event HandleUpdates UpdatesEvent; + public MtProtoSender(TcpTransport transport, Session session) { this.transport = transport; @@ -60,7 +65,6 @@ namespace TLSharp.Core.Network } } - using (var memory = new MemoryStream()) using (var writer = new BinaryWriter(memory)) { @@ -90,11 +94,12 @@ namespace TLSharp.Core.Network plaintextWriter.Write(packet.Length); plaintextWriter.Write(packet); - msgKey = Helpers.CalcMsgKey(plaintextPacket.GetBuffer()); - ciphertext = AES.EncryptAES(Helpers.CalcKey(session.AuthKey.Data, msgKey, true), plaintextPacket.GetBuffer()); + var buffer = plaintextPacket.GetBuffer(); + msgKey = Helpers.CalcMsgKey(buffer); + ciphertext = AES.EncryptAES(Helpers.CalcKey(session.AuthKey.Data, msgKey, true), + plaintextPacket.GetBuffer()); } } - using (MemoryStream ciphertextPacket = makeMemory(8 + 16 + ciphertext.Length)) { using (BinaryWriter writer = new BinaryWriter(ciphertextPacket)) @@ -108,6 +113,23 @@ namespace TLSharp.Core.Network } } + private async Task Ack(CancellationToken token = default(CancellationToken)) + { + token.ThrowIfCancellationRequested(); + + if (needConfirmation.Any()) + { + var ackRequest = new AckRequest(needConfirmation); + using (var memory = new MemoryStream()) + using (var writer = new BinaryWriter(memory)) + { + ackRequest.SerializeBody(writer); + await Send(memory.ToArray(), ackRequest); + needConfirmation.Clear(); + } + } + } + private Tuple DecodeMessage(byte[] body) { byte[] message; @@ -147,9 +169,9 @@ namespace TLSharp.Core.Network var result = DecodeMessage((await transport.Receive(token).ConfigureAwait(false)).Body); 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, token); + await ProcessMessageAsync(result.Item2, result.Item3, messageReader, request, token); } token.ThrowIfCancellationRequested(); @@ -158,6 +180,21 @@ namespace TLSharp.Core.Network return null; } + public async Task Receive(TimeSpan timeToWait, CancellationToken token = default(CancellationToken)) + { + var result = DecodeMessage((await transport.Receive(timeToWait)).Body); + + using (var messageStream = new MemoryStream(result.Item1, false)) + using (var messageReader = new BinaryReader(messageStream)) + { + await ProcessMessageAsync(result.Item2, result.Item3, messageReader, null); + } + + token.ThrowIfCancellationRequested(); + + return null; + } + public async Task SendPingAsync(CancellationToken token = default(CancellationToken)) { token.ThrowIfCancellationRequested(); @@ -173,7 +210,7 @@ namespace TLSharp.Core.Network await Receive(pingRequest, token).ConfigureAwait(false); } - private bool processMessage(ulong messageId, int sequence, BinaryReader messageReader, TLMethod request, CancellationToken token = default(CancellationToken)) + private async Task ProcessMessageAsync(ulong messageId, int sequence, BinaryReader messageReader, TeleSharp.TL.TLMethod request, CancellationToken token = default(CancellationToken)) { token.ThrowIfCancellationRequested(); @@ -181,8 +218,10 @@ namespace TLSharp.Core.Network // TODO: check sessionid // TODO: check seqno + //logger.debug("processMessage: msg_id {0}, sequence {1}, data {2}", BitConverter.ToString(((MemoryStream)messageReader.BaseStream).GetBuffer(), (int) messageReader.BaseStream.Position, (int) (messageReader.BaseStream.Length - messageReader.BaseStream.Position)).Replace("-","").ToLower()); needConfirmation.Add(messageId); + await Ack(token); uint code = messageReader.ReadUInt32(); messageReader.BaseStream.Position -= 4; @@ -190,7 +229,7 @@ namespace TLSharp.Core.Network { case 0x73f1f8dc: // container //logger.debug("MSG container"); - return HandleContainer(messageId, sequence, messageReader, request, token); + return await HandleContainerAsync(messageId, sequence, messageReader, request, token); case 0x7abe77ec: // ping //logger.debug("MSG ping"); return HandlePing(messageId, sequence, messageReader); @@ -208,7 +247,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, token); + return await HandleBadServerSaltAsync(messageId, sequence, messageReader, request, token); case 0xa7eff811: // bad_msg_notification //logger.debug("MSG bad_msg_notification"); return HandleBadMsgNotification(messageId, sequence, messageReader); @@ -220,39 +259,61 @@ 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, token); + return await HandleGzipPackedAsync(messageId, sequence, messageReader, request, token); case 0xe317af7e: case 0xd3f45784: case 0x2b2fbd4e: case 0x78d4dec1: case 0x725b04c3: case 0x74ae4240: - return HandleUpdate(messageId, sequence, messageReader); + case 0x11f1331c: + return HandleUpdate(code, sequence, messageReader, request); default: - //logger.debug("unknown message: {0}", code); return false; } } - private bool HandleUpdate(ulong messageId, int sequence, BinaryReader messageReader) + private bool HandleUpdate(uint code, int sequence, BinaryReader messageReader, TLMethod request) { - return false; - - /* - try - { - UpdatesEvent(TL.Parse(messageReader)); - return true; - } - catch (Exception e) - { - logger.warning("update processing exception: {0}", e); - return false; - } - */ + var update = ParseUpdate(code, messageReader); + if (update != null && UpdatesEvent != null) + { + UpdatesEvent(update); + } + return true; } - private bool HandleGzipPacked(ulong messageId, int sequence, BinaryReader messageReader, TLMethod request, CancellationToken token = default(CancellationToken)) + private TLAbsUpdates ParseUpdate(uint code, BinaryReader messageReader) + { + switch (code) + { + case 0xe317af7e: + return DecodeUpdate(messageReader); + case 0x914fbf11: + return DecodeUpdate (messageReader); + case 0x16812688: + return DecodeUpdate (messageReader); + case 0x78d4dec1: + return DecodeUpdate (messageReader); + case 0x725b04c3: + return DecodeUpdate (messageReader); + case 0x74ae4240: + return DecodeUpdate (messageReader); + case 0x11f1331c: + return DecodeUpdate (messageReader); + default: + return null; + } + } + + private TLAbsUpdates DecodeUpdate(BinaryReader messageReader) where T : TLAbsUpdates + { + var ms = messageReader.BaseStream as MemoryStream; + var update = (T)ObjectUtils.DeserializeObject(messageReader); + return update; + } + + private async Task HandleGzipPackedAsync(ulong messageId, int sequence, BinaryReader messageReader, TeleSharp.TL.TLMethod request, CancellationToken token = default(CancellationToken)) { token.ThrowIfCancellationRequested(); @@ -269,7 +330,7 @@ namespace TLSharp.Core.Network } using (BinaryReader compressedReader = new BinaryReader(ms)) { - processMessage(messageId, sequence, compressedReader, request, token); + await ProcessMessageAsync(messageId, sequence, compressedReader, request, token); } } @@ -305,6 +366,7 @@ namespace TLSharp.Core.Network { // rpc_error int errorCode = messageReader.ReadInt32(); string errorMessage = Serializers.String.Read(messageReader); + Console.Error.WriteLine($"ERROR: {errorMessage} - {errorCode}"); if (errorMessage.StartsWith("FLOOD_WAIT_")) { @@ -415,7 +477,7 @@ namespace TLSharp.Core.Network throw new InvalidOperationException("invalid container"); } - throw new NotImplementedException("This should never happens"); + throw new NotImplementedException("This should never happen!"); /* logger.debug("bad_msg_notification: msgid {0}, seq {1}, errorcode {2}", requestId, requestSequence, errorCode); @@ -435,7 +497,7 @@ namespace TLSharp.Core.Network return true; } - private bool HandleBadServerSalt(ulong messageId, int sequence, BinaryReader messageReader, TLMethod request, CancellationToken token = default(CancellationToken)) + private async Task HandleBadServerSaltAsync(ulong messageId, int sequence, BinaryReader messageReader, TeleSharp.TL.TLMethod request, CancellationToken token = default(CancellationToken)) { token.ThrowIfCancellationRequested(); @@ -450,7 +512,7 @@ namespace TLSharp.Core.Network session.Salt = newSalt; //resend - Send(request, token); + await Send(request, token); /* if(!runningRequests.ContainsKey(badMsgId)) { logger.debug("bad server salt on unknown message"); @@ -516,7 +578,7 @@ namespace TLSharp.Core.Network return false; } - private bool HandleContainer(ulong messageId, int sequence, BinaryReader messageReader, TLMethod request, CancellationToken token = default(CancellationToken)) + private async Task HandleContainerAsync(ulong messageId, int sequence, BinaryReader messageReader, TeleSharp.TL.TLMethod request, CancellationToken token = default(CancellationToken)) { token.ThrowIfCancellationRequested(); @@ -530,11 +592,16 @@ namespace TLSharp.Core.Network long beginPosition = messageReader.BaseStream.Position; try { - if (!processMessage(innerMessageId, sequence, messageReader, request, token)) + var processedMessage = await ProcessMessageAsync(innerMessageId, sequence, messageReader, request, token); + if (!processedMessage) { messageReader.BaseStream.Position = beginPosition + innerLength; } } + catch (InvalidOperationException e) + { + throw; + } catch (Exception e) { // logger.error("failed to process message in container: {0}", e); diff --git a/TLSharp.Core/Network/Sniffer.cs b/TLSharp.Core/Network/Sniffer.cs new file mode 100644 index 0000000..a1033bc --- /dev/null +++ b/TLSharp.Core/Network/Sniffer.cs @@ -0,0 +1,25 @@ +using System; +using System.Text; + +namespace TLSharp.Core.Network +{ + public static class Sniffer + { + public static string MessageOut(byte[] data) + { + return WriteMessage(new StringBuilder("[OUT]:"), data); + } + + public static string MessageIn(byte[] data) + { + return WriteMessage(new StringBuilder("[IN]:"), data); + } + + private static string WriteMessage(StringBuilder log, byte[] data) + { + foreach (var b in data) + log.AppendFormat(" {0:x2}", b); + return log.ToString(); + } + } +} diff --git a/TLSharp.Core/Network/TcpTransport.cs b/TLSharp.Core/Network/TcpTransport.cs index cfc7956..0433df3 100644 --- a/TLSharp.Core/Network/TcpTransport.cs +++ b/TLSharp.Core/Network/TcpTransport.cs @@ -15,6 +15,7 @@ namespace TLSharp.Core.Network private readonly TcpClient tcpClient; private readonly NetworkStream stream; private int sendCounter = 0; + private CancellationTokenSource tokenSource = new CancellationTokenSource(); public TcpTransport(string address, int port, TcpClientConnectionHandler handler = null) { @@ -54,11 +55,76 @@ namespace TLSharp.Core.Network public async Task Receive(CancellationToken token = default(CancellationToken)) { + var stream = tcpClient.GetStream(); + var packetLengthBytes = new byte[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) + 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 Crc32(); + var computedChecksum = crc32.ComputeHash(rv).Reverse(); + + if (!crcBytes.SequenceEqual(computedChecksum)) + { + throw new InvalidOperationException("invalid checksum! skip"); + } + + return new TcpMessage(seq, body); + } + + public async Task Receive(TimeSpan timeToWait) + { + var stream = tcpClient.GetStream(); + + var packetLengthBytes = new byte[4]; + var token = tokenSource.Token; + stream.ReadTimeout = (int)timeToWait.TotalMilliseconds; + int bytes = 0; + try + { + bytes = stream.Read(packetLengthBytes, 0, 4); + } + catch (System.IO.IOException io) + { + var socketError = io.InnerException as SocketException; + if (socketError != null && socketError.SocketErrorCode == SocketError.TimedOut) + throw new OperationCanceledException(); + throw; + } + if (bytes != 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, token).ConfigureAwait(false) != 4) throw new InvalidOperationException("Couldn't read the sequence"); @@ -106,7 +172,6 @@ namespace TLSharp.Core.Network } } - public void Dispose() { if (tcpClient.Connected) diff --git a/TLSharp.Core/TLSharp.Core.csproj b/TLSharp.Core/TLSharp.Core.csproj index 9924ab2..62bdc6c 100644 --- a/TLSharp.Core/TLSharp.Core.csproj +++ b/TLSharp.Core/TLSharp.Core.csproj @@ -75,6 +75,7 @@ + diff --git a/TLSharp.Core/TelegramClient.cs b/TLSharp.Core/TelegramClient.cs index e5b0819..666f430 100644 --- a/TLSharp.Core/TelegramClient.cs +++ b/TLSharp.Core/TelegramClient.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; @@ -25,6 +25,7 @@ namespace TLSharp.Core public class TelegramClient : IDisposable { private MtProtoSender sender; + private AuthKey key; private TcpTransport transport; private string apiHash = String.Empty; private int apiId = 0; @@ -33,6 +34,15 @@ namespace TLSharp.Core private TcpClientConnectionHandler handler; private DataCenterIPVersion dcIpVersion; + private bool looping = true; + + public delegate void UpdatesEvent (TelegramClient source, TLAbsUpdates updates); + public delegate void ClientEvent(TelegramClient source); + + public event UpdatesEvent Updates; + public event ClientEvent ScheduledTasks; + public event ClientEvent IdleTasks; + public Session Session { get { return session; } @@ -80,6 +90,7 @@ namespace TLSharp.Core } sender = new MtProtoSender(transport, session); + sender.UpdatesEvent += SenderUpdatesEvent; //set-up layer var config = new TLRequestGetConfig(); @@ -149,6 +160,50 @@ namespace TLSharp.Core } } + public void Close() + { + looping = false; + } + + public async Task MainLoopAsync(TimeSpan timeToWait, CancellationToken token = default(CancellationToken)) + { + var lastPing = DateTime.UtcNow; + await SendPingAsync(); + while (looping) + { + try + { + await WaitEventAsync(timeToWait, token); + } + catch (OperationCanceledException) + { + // Handle timeout, no problem + } + finally + { + var now = DateTime.UtcNow; + if ((now - lastPing).TotalSeconds >= 30) + { + await SendPingAsync(); + lastPing = now; + } + if (ScheduledTasks != null) + { + ScheduledTasks.Invoke(this); + ScheduledTasks = null; + } + IdleTasks?.Invoke(this); + } + + token.ThrowIfCancellationRequested(); + } + } + + private void SenderUpdatesEvent (TLAbsUpdates updates) + { + Updates?.Invoke(this, updates); + } + private async Task RequestWithDcMigration(TLMethod request, CancellationToken token = default(CancellationToken)) { if (sender == null) @@ -178,6 +233,11 @@ namespace TLSharp.Core } } + public async Task WaitEventAsync(TimeSpan timeToWait, CancellationToken token = default(CancellationToken)) + { + await sender.Receive (timeToWait, token); + } + public bool IsUserAuthorized() { return session.TLUser != null; diff --git a/TLSharp.Tests.NUnit/Test.cs b/TLSharp.Tests.NUnit/Test.cs index 40e54ac..3696b07 100644 --- a/TLSharp.Tests.NUnit/Test.cs +++ b/TLSharp.Tests.NUnit/Test.cs @@ -81,5 +81,11 @@ namespace TLSharp.Tests { await base.SendMessageByUserNameTest(); } + + [Test] + public override async Task GetUpdatesForUser() + { + await base.GetUpdatesForUser(); + } } } diff --git a/TLSharp.Tests.VS/TLSharpTestsVs.cs b/TLSharp.Tests.VS/TLSharpTestsVs.cs index 8f6c58d..ccb7ea7 100644 --- a/TLSharp.Tests.VS/TLSharpTestsVs.cs +++ b/TLSharp.Tests.VS/TLSharpTestsVs.cs @@ -79,5 +79,12 @@ namespace TLSharp.Tests { await base.SendMessageByUserNameTest(); } + + [TestMethod] + public override async Task GetUpdatesForUser() + { + await base.GetUpdatesForUser(); + } + } } diff --git a/TLSharp.Tests/TLSharpTests.cs b/TLSharp.Tests/TLSharpTests.cs index 6acde72..8f2cfe5 100644 --- a/TLSharp.Tests/TLSharpTests.cs +++ b/TLSharp.Tests/TLSharpTests.cs @@ -1,5 +1,6 @@  using System; +using System.Collections.Generic; using System.Configuration; using System.Diagnostics; using System.IO; @@ -11,7 +12,6 @@ using TeleSharp.TL; using TeleSharp.TL.Messages; using TLSharp.Core; using TLSharp.Core.Exceptions; -using TLSharp.Core.Network; using TLSharp.Core.Network.Exceptions; using TLSharp.Core.Utils; @@ -269,7 +269,7 @@ namespace TLSharp.Tests Version = document.Version }, document.Size); - + Assert.IsTrue(resFile.Bytes.Length > 0); } @@ -284,7 +284,7 @@ namespace TLSharp.Tests var user = result.Users .OfType() .FirstOrDefault(x => x.Id == 5880094); - + var photo = ((TLUserProfilePhoto)user.Photo); var photoLocation = (TLFileLocation) photo.PhotoBig; @@ -377,5 +377,72 @@ namespace TLSharp.Tests Thread.Sleep(3000); await client.SendMessageAsync(new TLInputPeerUser() { UserId = user.Id }, "TEST"); } + + public virtual async Task GetUpdatesForUser() + { + IList newMsgs = new List(); + TLUser user = null; + var updateMsg = "Send yourself an UPDATE_1 message to trigger update during loop"; + + var client = NewClient(); + await client.ConnectAsync(); + + if (client.IsUserAuthorized()) + user = client.Session.TLUser; + + else + { + var hash = await client.SendCodeRequestAsync(NumberToAuthenticate); + var code = CodeToAuthenticate; // you can change code in debugger too + if (string.IsNullOrWhiteSpace(code)) + { + throw new Exception("CodeToAuthenticate is empty in the app.config file, fill it with the code you just got now by SMS/Telegram"); + } + + try + { + user = await client.MakeAuthAsync(NumberToAuthenticate, hash, code); + } + catch (CloudPasswordNeededException) + { + var passwordSetting = await client.GetPasswordSetting(); + var password = PasswordToAuthenticate; + user = await client.MakeAuthWithPasswordAsync(passwordSetting, password); + } + catch (InvalidPhoneCodeException ex) + { + throw new Exception("CodeToAuthenticate is wrong in the app.config file, fill it with the code you just got now by SMS/Telegram", ex); + } + } + + // Things to note:- If the updates are not getting triggered, please re-authenticate the user + // Would trigger the updates on a seperate thread if possible + + client.Updates += (TelegramClient tclient, TLAbsUpdates updates) => + { + if (updates is TLUpdates) + { + var allUpdates = updates as TLUpdates; + + foreach (var update in allUpdates.Updates) + { + if (update is TLUpdateNewMessage) + { + var metaMsg = update as TLUpdateNewMessage; + var msg = metaMsg.Message as TLMessage; + newMsgs.Add(msg); + } + } + } + }; + + Console.WriteLine(updateMsg); + Debug.WriteLine(updateMsg); + + await client.MainLoopAsync(new TimeSpan(0, 0, 1)); + + Assert.IsTrue(newMsgs.Count == 1); + Assert.IsTrue(newMsgs.First().Message.Equals("UPDATE_1")); + } } -} +} \ No newline at end of file