From 80d16fe4a4896a847908b2c512ae86b31f28e82d Mon Sep 17 00:00:00 2001 From: solarin Date: Fri, 3 Apr 2020 17:05:06 +0400 Subject: [PATCH 01/15] Added an IPv4/IPv6 toggle to TelegramClient constructor --- TLSharp.Core/DataCenterIPVersion.cs | 30 + TLSharp.Core/TelegramClient.cs | 870 ++++++++++++++-------------- 2 files changed, 479 insertions(+), 421 deletions(-) create mode 100644 TLSharp.Core/DataCenterIPVersion.cs diff --git a/TLSharp.Core/DataCenterIPVersion.cs b/TLSharp.Core/DataCenterIPVersion.cs new file mode 100644 index 0000000..9b22794 --- /dev/null +++ b/TLSharp.Core/DataCenterIPVersion.cs @@ -0,0 +1,30 @@ +namespace TLSharp.Core +{ + /// + /// When the Telegram server responds with a set of addresses to connect to, DataCenterIPVersion indicates a preference + /// for how to choose the IP address to connect to + /// + public enum DataCenterIPVersion + { + /// + /// Prefers IPv6 addresses if any is passed by Telegram + /// + Default = 0, + /// + /// Takes only IPv4 addresses + /// + OnlyIPv4 = 1, + /// + /// Takes only IPv6 addresses + /// + OnlyIPv6 = 2, + /// + /// Connection to IPv4 addresses is preferred to IPv6 addresses + /// + PreferIPv4 = 3, + /// + /// Connection to IPv6 addresses is preferred to IPv6 addresses + /// + PreferIPv6 = 4, + } +} diff --git a/TLSharp.Core/TelegramClient.cs b/TLSharp.Core/TelegramClient.cs index 46e0ad4..997dfd5 100644 --- a/TLSharp.Core/TelegramClient.cs +++ b/TLSharp.Core/TelegramClient.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Configuration; +using System.Data; using System.Linq; using System.Security.Cryptography; using System.Text; @@ -22,433 +24,459 @@ using TLAuthorization = TeleSharp.TL.Auth.TLAuthorization; namespace TLSharp.Core { - public class TelegramClient : IDisposable - { - private MtProtoSender sender; - private TcpTransport transport; - private string apiHash = String.Empty; - private int apiId = 0; - private Session session; - private List dcOptions; - private TcpClientConnectionHandler handler; - - public Session Session - { - get { return session; } - } - - public TelegramClient(int apiId, string apiHash, - ISessionStore store = null, string sessionUserId = "session", TcpClientConnectionHandler handler = null) - { - if (apiId == default(int)) - throw new MissingApiConfigurationException("API_ID"); - if (string.IsNullOrEmpty(apiHash)) - throw new MissingApiConfigurationException("API_HASH"); - - if (store == null) - store = new FileSessionStore(); - - this.apiHash = apiHash; - this.apiId = apiId; - this.handler = handler; - - session = Session.TryLoadOrCreateNew(store, sessionUserId); - transport = new TcpTransport (session.DataCenter.Address, session.DataCenter.Port, this.handler); - } - - public async Task ConnectAsync(bool reconnect = false, CancellationToken token = default(CancellationToken)) - { - token.ThrowIfCancellationRequested(); - - if (session.AuthKey == null || reconnect) - { - var result = await Authenticator.DoAuthentication(transport, token).ConfigureAwait(false); - session.AuthKey = result.AuthKey; - session.TimeOffset = result.TimeOffset; - } - - sender = new MtProtoSender(transport, session); - - //set-up layer - var config = new TLRequestGetConfig(); - var request = new TLRequestInitConnection() - { - ApiId = apiId, - AppVersion = "1.0.0", - DeviceModel = "PC", - LangCode = "en", - Query = config, - SystemVersion = "Win 10.0" - }; - var invokewithLayer = new TLRequestInvokeWithLayer() { Layer = 66, Query = request }; - await sender.Send(invokewithLayer, token).ConfigureAwait(false); - await sender.Receive(invokewithLayer, token).ConfigureAwait(false); - - dcOptions = ((TLConfig)invokewithLayer.Response).DcOptions.ToList(); - } - - private async Task ReconnectToDcAsync(int dcId, CancellationToken token = default(CancellationToken)) - { - token.ThrowIfCancellationRequested(); - - if (dcOptions == null || !dcOptions.Any()) - throw new InvalidOperationException($"Can't reconnect. Establish initial connection first."); - - TLExportedAuthorization exported = null; - if (session.TLUser != null) - { - TLRequestExportAuthorization exportAuthorization = new TLRequestExportAuthorization() { DcId = dcId }; - exported = await SendRequestAsync(exportAuthorization, token).ConfigureAwait(false); - } - - 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; - - await ConnectAsync(true, token).ConfigureAwait(false); - - if (session.TLUser != null) - { - TLRequestImportAuthorization importAuthorization = new TLRequestImportAuthorization() { Id = exported.Id, Bytes = exported.Bytes }; - var imported = await SendRequestAsync(importAuthorization, token).ConfigureAwait(false); - OnUserAuthenticated((TLUser)imported.User); - } - } - - private async Task RequestWithDcMigration(TLMethod request, CancellationToken token = default(CancellationToken)) - { - if (sender == null) - throw new InvalidOperationException("Not connected!"); - - var completed = false; - while(!completed) - { - try - { - 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) - { - 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, token).ConfigureAwait(false); - // prepare the request for another try - request.ConfirmReceived = false; - } - } - } - - public bool IsUserAuthorized() - { - return session.TLUser != null; - } - - public async Task IsPhoneRegisteredAsync(string phoneNumber, CancellationToken token = default(CancellationToken)) - { - if (String.IsNullOrWhiteSpace(phoneNumber)) - throw new ArgumentNullException(nameof(phoneNumber)); - - var authCheckPhoneRequest = new TLRequestCheckPhone() { PhoneNumber = phoneNumber }; - - await RequestWithDcMigration(authCheckPhoneRequest, token).ConfigureAwait(false); - - return authCheckPhoneRequest.Response.PhoneRegistered; - } - - public async Task SendCodeRequestAsync(string phoneNumber, CancellationToken token = default(CancellationToken)) - { - if (String.IsNullOrWhiteSpace(phoneNumber)) - throw new ArgumentNullException(nameof(phoneNumber)); - - var request = new TLRequestSendCode() { PhoneNumber = phoneNumber, ApiId = apiId, ApiHash = apiHash }; - - await RequestWithDcMigration(request, token).ConfigureAwait(false); - - return request.Response.PhoneCodeHash; - } - - public async Task MakeAuthAsync(string phoneNumber, string phoneCodeHash, string code, CancellationToken token = default(CancellationToken)) - { - if (String.IsNullOrWhiteSpace(phoneNumber)) - throw new ArgumentNullException(nameof(phoneNumber)); - if (String.IsNullOrWhiteSpace(phoneCodeHash)) - throw new ArgumentNullException(nameof(phoneCodeHash)); + public class TelegramClient : IDisposable + { + private MtProtoSender sender; + private TcpTransport transport; + private string apiHash = String.Empty; + private int apiId = 0; + private Session session; + private List dcOptions; + private TcpClientConnectionHandler handler; + private DataCenterIPVersion dcIpVersion; + + public Session Session + { + get { return session; } + } + + /// + /// Creates a new TelegramClient + /// + /// The API ID provided by Telegram. Get one at https://my.telegram.org + /// The API Hash provided by Telegram. Get one at https://my.telegram.org + /// An ISessionStore object that will handle the session + /// The name of the session that tracks login info about this TelegramClient connection + /// A delegate to invoke when a connection is needed and that will return a TcpClient that will be used to connect + /// Indicates the preferred IpAddress version to use to connect to a Telegram server + public TelegramClient(int apiId, string apiHash, + ISessionStore store = null, string sessionUserId = "session", TcpClientConnectionHandler handler = null, DataCenterIPVersion dcIpVersion = DataCenterIPVersion.Default) + { + if (apiId == default(int)) + throw new MissingApiConfigurationException("API_ID"); + if (string.IsNullOrEmpty(apiHash)) + throw new MissingApiConfigurationException("API_HASH"); + + if (store == null) + store = new FileSessionStore(); + + this.apiHash = apiHash; + this.apiId = apiId; + this.handler = handler; + this.dcIpVersion = dcIpVersion; + + session = Session.TryLoadOrCreateNew(store, sessionUserId); + transport = new TcpTransport(session.DataCenter.Address, session.DataCenter.Port, this.handler); + } + + public async Task ConnectAsync(bool reconnect = false, CancellationToken token = default(CancellationToken)) + { + token.ThrowIfCancellationRequested(); + + if (session.AuthKey == null || reconnect) + { + var result = await Authenticator.DoAuthentication(transport, token).ConfigureAwait(false); + session.AuthKey = result.AuthKey; + session.TimeOffset = result.TimeOffset; + } + + sender = new MtProtoSender(transport, session); + + //set-up layer + var config = new TLRequestGetConfig(); + var request = new TLRequestInitConnection() + { + ApiId = apiId, + AppVersion = "1.0.0", + DeviceModel = "PC", + LangCode = "en", + Query = config, + SystemVersion = "Win 10.0" + }; + var invokewithLayer = new TLRequestInvokeWithLayer() { Layer = 66, Query = request }; + await sender.Send(invokewithLayer, token).ConfigureAwait(false); + await sender.Receive(invokewithLayer, token).ConfigureAwait(false); + + dcOptions = ((TLConfig)invokewithLayer.Response).DcOptions.ToList(); + } + + private async Task ReconnectToDcAsync(int dcId, CancellationToken token = default(CancellationToken)) + { + token.ThrowIfCancellationRequested(); + + if (dcOptions == null || !dcOptions.Any()) + throw new InvalidOperationException($"Can't reconnect. Establish initial connection first."); + + TLExportedAuthorization exported = null; + if (session.TLUser != null) + { + TLRequestExportAuthorization exportAuthorization = new TLRequestExportAuthorization() { DcId = dcId }; + exported = await SendRequestAsync(exportAuthorization, token).ConfigureAwait(false); + } + + var dcs = dcOptions.Where(d => d.Id == dcId + && ( + (dcIpVersion == DataCenterIPVersion.Default) // any + || (d.Ipv6 && dcIpVersion == DataCenterIPVersion.OnlyIPv6) // selects only ipv6 addresses + || (!d.Ipv6 && dcIpVersion == DataCenterIPVersion.OnlyIPv4) // selects only ipv4 addresses + || dcIpVersion == DataCenterIPVersion.PreferIPv4 // we can take both types of address + || dcIpVersion == DataCenterIPVersion.PreferIPv6 // we can take both types of address + ) + ).OrderBy(d => d.Ipv6); + + if (dcs.Count() == 0) + throw new Exception($"Telegram server didn't provide us with any IPAddress that matches your preferences. If you chose OnlyIPvX, try switch to PreferIPvX instead."); + + var dc = dcIpVersion == DataCenterIPVersion.PreferIPv4 ? dcs.First() : dcs.Last(); // ipv4 addresses are at the beginning of the list because it was ordered + + var dataCenter = new DataCenter(dcId, dc.IpAddress, dc.Port); + + transport = new TcpTransport(dc.IpAddress, dc.Port, handler); + session.DataCenter = dataCenter; + + await ConnectAsync(true, token).ConfigureAwait(false); + + if (session.TLUser != null) + { + TLRequestImportAuthorization importAuthorization = new TLRequestImportAuthorization() { Id = exported.Id, Bytes = exported.Bytes }; + var imported = await SendRequestAsync(importAuthorization, token).ConfigureAwait(false); + OnUserAuthenticated((TLUser)imported.User); + } + } + + private async Task RequestWithDcMigration(TLMethod request, CancellationToken token = default(CancellationToken)) + { + if (sender == null) + throw new InvalidOperationException("Not connected!"); + + var completed = false; + while (!completed) + { + try + { + 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) + { + throw new Exception($"Telegram server replied requesting a migration to DataCenter {e.DC} when this connection was already using this DataCenter", e); + } - if (String.IsNullOrWhiteSpace(code)) - throw new ArgumentNullException(nameof(code)); - - var request = new TLRequestSignIn() { PhoneNumber = phoneNumber, PhoneCodeHash = phoneCodeHash, PhoneCode = code }; + await ReconnectToDcAsync(e.DC, token).ConfigureAwait(false); + // prepare the request for another try + request.ConfirmReceived = false; + } + } + } - await RequestWithDcMigration(request, token).ConfigureAwait(false); + public bool IsUserAuthorized() + { + return session.TLUser != null; + } - OnUserAuthenticated(((TLUser)request.Response.User)); + public async Task IsPhoneRegisteredAsync(string phoneNumber, CancellationToken token = default(CancellationToken)) + { + if (String.IsNullOrWhiteSpace(phoneNumber)) + throw new ArgumentNullException(nameof(phoneNumber)); - return ((TLUser)request.Response.User); - } - - public async Task GetPasswordSetting(CancellationToken token = default(CancellationToken)) - { - var request = new TLRequestGetPassword(); + var authCheckPhoneRequest = new TLRequestCheckPhone() { PhoneNumber = phoneNumber }; - await RequestWithDcMigration(request, token).ConfigureAwait(false); + await RequestWithDcMigration(authCheckPhoneRequest, token).ConfigureAwait(false); - return (TLPassword)request.Response; - } + return authCheckPhoneRequest.Response.PhoneRegistered; + } - public async Task MakeAuthWithPasswordAsync(TLPassword password, string password_str, CancellationToken token = default(CancellationToken)) - { - token.ThrowIfCancellationRequested(); - - byte[] password_Bytes = Encoding.UTF8.GetBytes(password_str); - IEnumerable rv = password.CurrentSalt.Concat(password_Bytes).Concat(password.CurrentSalt); - - SHA256Managed hashstring = new SHA256Managed(); - var password_hash = hashstring.ComputeHash(rv.ToArray()); - - var request = new TLRequestCheckPassword() { PasswordHash = password_hash }; - - await RequestWithDcMigration(request, token).ConfigureAwait(false); - - OnUserAuthenticated((TLUser)request.Response.User); - - return (TLUser)request.Response.User; - } - - public async Task SignUpAsync(string phoneNumber, string phoneCodeHash, string code, string firstName, string lastName, CancellationToken token = default(CancellationToken)) - { - var request = new TLRequestSignUp() { PhoneNumber = phoneNumber, PhoneCode = code, PhoneCodeHash = phoneCodeHash, FirstName = firstName, LastName = lastName }; - - await RequestWithDcMigration(request, token).ConfigureAwait(false); - - OnUserAuthenticated((TLUser)request.Response.User); - - return (TLUser)request.Response.User; - } - - public async Task SendRequestAsync(TLMethod methodToExecute, CancellationToken token = default(CancellationToken)) - { - await RequestWithDcMigration(methodToExecute, token).ConfigureAwait(false); - - var result = methodToExecute.GetType().GetProperty("Response").GetValue(methodToExecute); - - return (T)result; - } - - internal async Task SendAuthenticatedRequestAsync (TLMethod methodToExecute, CancellationToken token = default(CancellationToken)) - { - if (!IsUserAuthorized()) - throw new InvalidOperationException("Authorize user first!"); - - return await SendRequestAsync(methodToExecute, token) - .ConfigureAwait(false); - } - - public async Task UpdateUsernameAsync(string username, CancellationToken token = default(CancellationToken)) - { - var req = new TLRequestUpdateUsername { Username = username }; - - return await SendAuthenticatedRequestAsync(req, token) - .ConfigureAwait(false); - } - - public async Task CheckUsernameAsync(string username, CancellationToken token = default(CancellationToken)) - { - var req = new TLRequestCheckUsername { Username = username }; - - return await SendAuthenticatedRequestAsync(req, token) - .ConfigureAwait(false); - } - - public async Task ImportContactsAsync(IReadOnlyList contacts, CancellationToken token = default(CancellationToken)) - { - var req = new TLRequestImportContacts { Contacts = new TLVector(contacts)}; - - return await SendAuthenticatedRequestAsync(req, token) - .ConfigureAwait(false); - } - - public async Task DeleteContactsAsync(IReadOnlyList users, CancellationToken token = default(CancellationToken)) - { - var req = new TLRequestDeleteContacts {Id = new TLVector(users)}; - - return await SendAuthenticatedRequestAsync(req, token) - .ConfigureAwait(false); - } - - public async Task DeleteContactAsync(TLAbsInputUser user, CancellationToken token = default(CancellationToken)) - { - var req = new TLRequestDeleteContact {Id = user}; - - return await SendAuthenticatedRequestAsync(req, token) - .ConfigureAwait(false); - } - - public async Task GetContactsAsync(CancellationToken token = default(CancellationToken)) - { - var req = new TLRequestGetContacts() { Hash = "" }; - - return await SendAuthenticatedRequestAsync(req, token) - .ConfigureAwait(false); - } - - public async Task SendMessageAsync(TLAbsInputPeer peer, string message, CancellationToken token = default(CancellationToken)) - { - return await SendAuthenticatedRequestAsync( - new TLRequestSendMessage() - { - Peer = peer, - Message = message, - RandomId = Helpers.GenerateRandomLong() - }, token) - .ConfigureAwait(false); - } - - public async Task SendTypingAsync(TLAbsInputPeer peer, CancellationToken token = default(CancellationToken)) - { - var req = new TLRequestSetTyping() - { - Action = new TLSendMessageTypingAction(), - Peer = peer - }; - return await SendAuthenticatedRequestAsync(req, token) - .ConfigureAwait(false); - } - - public async Task GetUserDialogsAsync(int offsetDate = 0, int offsetId = 0, TLAbsInputPeer offsetPeer = null, int limit = 100, CancellationToken token = default(CancellationToken)) - { - if (offsetPeer == null) - offsetPeer = new TLInputPeerSelf(); - - var req = new TLRequestGetDialogs() - { - OffsetDate = offsetDate, - OffsetId = offsetId, - OffsetPeer = offsetPeer, - Limit = limit - }; - return await SendAuthenticatedRequestAsync(req, token) - .ConfigureAwait(false); - } - - public async Task SendUploadedPhoto(TLAbsInputPeer peer, TLAbsInputFile file, string caption, CancellationToken token = default(CancellationToken)) - { - return await SendAuthenticatedRequestAsync(new TLRequestSendMedia() - { - RandomId = Helpers.GenerateRandomLong(), - Background = false, - ClearDraft = false, - Media = new TLInputMediaUploadedPhoto() { File = file, Caption = caption }, - Peer = peer - }, token) - .ConfigureAwait(false); - } - - public async Task SendUploadedDocument( - TLAbsInputPeer peer, TLAbsInputFile file, string caption, string mimeType, TLVector attributes, CancellationToken token = default(CancellationToken)) - { - return await SendAuthenticatedRequestAsync(new TLRequestSendMedia() - { - RandomId = Helpers.GenerateRandomLong(), - Background = false, - ClearDraft = false, - Media = new TLInputMediaUploadedDocument() - { - File = file, - Caption = caption, - MimeType = mimeType, - Attributes = attributes - }, - Peer = peer - }, token) - .ConfigureAwait(false); - } - - public async Task GetFile(TLAbsInputFileLocation location, int filePartSize, int offset = 0, CancellationToken token = default(CancellationToken)) - { - TLFile result = await SendAuthenticatedRequestAsync(new TLRequestGetFile - { - Location = location, - Limit = filePartSize, - Offset = offset - }, token) - .ConfigureAwait(false); - return result; - } - - public async Task SendPingAsync(CancellationToken token = default(CancellationToken)) - { - 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, CancellationToken token = default(CancellationToken)) - { - var req = new TLRequestGetHistory() - { - Peer = peer, - OffsetId = offsetId, - OffsetDate = offsetDate, - AddOffset = addOffset, - Limit = limit, - MaxId = maxId, - MinId = minId - }; - return await SendAuthenticatedRequestAsync(req, token) - .ConfigureAwait(false); - } - - /// - /// Serch user or chat. API: contacts.search#11f812d8 q:string limit:int = contacts.Found; - /// - /// User or chat name - /// Max result count - /// - public async Task SearchUserAsync(string q, int limit = 10, CancellationToken token = default(CancellationToken)) - { - var r = new TeleSharp.TL.Contacts.TLRequestSearch - { - Q = q, - Limit = limit - }; - - return await SendAuthenticatedRequestAsync(r, token) - .ConfigureAwait(false); - } - - private void OnUserAuthenticated(TLUser TLUser) - { - session.TLUser = TLUser; - session.SessionExpires = int.MaxValue; - - session.Save(); - } - - public bool IsConnected - { - get - { - if (transport == null) - return false; - return transport.IsConnected; - } - } - - public void Dispose() - { - if (transport != null) - { - transport.Dispose(); - transport = null; - } - } - } + public async Task SendCodeRequestAsync(string phoneNumber, CancellationToken token = default(CancellationToken)) + { + if (String.IsNullOrWhiteSpace(phoneNumber)) + throw new ArgumentNullException(nameof(phoneNumber)); + + var request = new TLRequestSendCode() { PhoneNumber = phoneNumber, ApiId = apiId, ApiHash = apiHash }; + + await RequestWithDcMigration(request, token).ConfigureAwait(false); + + return request.Response.PhoneCodeHash; + } + + public async Task MakeAuthAsync(string phoneNumber, string phoneCodeHash, string code, CancellationToken token = default(CancellationToken)) + { + if (String.IsNullOrWhiteSpace(phoneNumber)) + throw new ArgumentNullException(nameof(phoneNumber)); + + if (String.IsNullOrWhiteSpace(phoneCodeHash)) + throw new ArgumentNullException(nameof(phoneCodeHash)); + + if (String.IsNullOrWhiteSpace(code)) + throw new ArgumentNullException(nameof(code)); + + var request = new TLRequestSignIn() { PhoneNumber = phoneNumber, PhoneCodeHash = phoneCodeHash, PhoneCode = code }; + + await RequestWithDcMigration(request, token).ConfigureAwait(false); + + OnUserAuthenticated(((TLUser)request.Response.User)); + + return ((TLUser)request.Response.User); + } + + public async Task GetPasswordSetting(CancellationToken token = default(CancellationToken)) + { + var request = new TLRequestGetPassword(); + + await RequestWithDcMigration(request, token).ConfigureAwait(false); + + return (TLPassword)request.Response; + } + + public async Task MakeAuthWithPasswordAsync(TLPassword password, string password_str, CancellationToken token = default(CancellationToken)) + { + token.ThrowIfCancellationRequested(); + + byte[] password_Bytes = Encoding.UTF8.GetBytes(password_str); + IEnumerable rv = password.CurrentSalt.Concat(password_Bytes).Concat(password.CurrentSalt); + + SHA256Managed hashstring = new SHA256Managed(); + var password_hash = hashstring.ComputeHash(rv.ToArray()); + + var request = new TLRequestCheckPassword() { PasswordHash = password_hash }; + + await RequestWithDcMigration(request, token).ConfigureAwait(false); + + OnUserAuthenticated((TLUser)request.Response.User); + + return (TLUser)request.Response.User; + } + + public async Task SignUpAsync(string phoneNumber, string phoneCodeHash, string code, string firstName, string lastName, CancellationToken token = default(CancellationToken)) + { + var request = new TLRequestSignUp() { PhoneNumber = phoneNumber, PhoneCode = code, PhoneCodeHash = phoneCodeHash, FirstName = firstName, LastName = lastName }; + + await RequestWithDcMigration(request, token).ConfigureAwait(false); + + OnUserAuthenticated((TLUser)request.Response.User); + + return (TLUser)request.Response.User; + } + + public async Task SendRequestAsync(TLMethod methodToExecute, CancellationToken token = default(CancellationToken)) + { + await RequestWithDcMigration(methodToExecute, token).ConfigureAwait(false); + + var result = methodToExecute.GetType().GetProperty("Response").GetValue(methodToExecute); + + return (T)result; + } + + internal async Task SendAuthenticatedRequestAsync(TLMethod methodToExecute, CancellationToken token = default(CancellationToken)) + { + if (!IsUserAuthorized()) + throw new InvalidOperationException("Authorize user first!"); + + return await SendRequestAsync(methodToExecute, token) + .ConfigureAwait(false); + } + + public async Task UpdateUsernameAsync(string username, CancellationToken token = default(CancellationToken)) + { + var req = new TLRequestUpdateUsername { Username = username }; + + return await SendAuthenticatedRequestAsync(req, token) + .ConfigureAwait(false); + } + + public async Task CheckUsernameAsync(string username, CancellationToken token = default(CancellationToken)) + { + var req = new TLRequestCheckUsername { Username = username }; + + return await SendAuthenticatedRequestAsync(req, token) + .ConfigureAwait(false); + } + + public async Task ImportContactsAsync(IReadOnlyList contacts, CancellationToken token = default(CancellationToken)) + { + var req = new TLRequestImportContacts { Contacts = new TLVector(contacts) }; + + return await SendAuthenticatedRequestAsync(req, token) + .ConfigureAwait(false); + } + + public async Task DeleteContactsAsync(IReadOnlyList users, CancellationToken token = default(CancellationToken)) + { + var req = new TLRequestDeleteContacts { Id = new TLVector(users) }; + + return await SendAuthenticatedRequestAsync(req, token) + .ConfigureAwait(false); + } + + public async Task DeleteContactAsync(TLAbsInputUser user, CancellationToken token = default(CancellationToken)) + { + var req = new TLRequestDeleteContact { Id = user }; + + return await SendAuthenticatedRequestAsync(req, token) + .ConfigureAwait(false); + } + + public async Task GetContactsAsync(CancellationToken token = default(CancellationToken)) + { + var req = new TLRequestGetContacts() { Hash = "" }; + + return await SendAuthenticatedRequestAsync(req, token) + .ConfigureAwait(false); + } + + public async Task SendMessageAsync(TLAbsInputPeer peer, string message, CancellationToken token = default(CancellationToken)) + { + return await SendAuthenticatedRequestAsync( + new TLRequestSendMessage() + { + Peer = peer, + Message = message, + RandomId = Helpers.GenerateRandomLong() + }, token) + .ConfigureAwait(false); + } + + public async Task SendTypingAsync(TLAbsInputPeer peer, CancellationToken token = default(CancellationToken)) + { + var req = new TLRequestSetTyping() + { + Action = new TLSendMessageTypingAction(), + Peer = peer + }; + return await SendAuthenticatedRequestAsync(req, token) + .ConfigureAwait(false); + } + + public async Task GetUserDialogsAsync(int offsetDate = 0, int offsetId = 0, TLAbsInputPeer offsetPeer = null, int limit = 100, CancellationToken token = default(CancellationToken)) + { + if (offsetPeer == null) + offsetPeer = new TLInputPeerSelf(); + + var req = new TLRequestGetDialogs() + { + OffsetDate = offsetDate, + OffsetId = offsetId, + OffsetPeer = offsetPeer, + Limit = limit + }; + return await SendAuthenticatedRequestAsync(req, token) + .ConfigureAwait(false); + } + + public async Task SendUploadedPhoto(TLAbsInputPeer peer, TLAbsInputFile file, string caption, CancellationToken token = default(CancellationToken)) + { + return await SendAuthenticatedRequestAsync(new TLRequestSendMedia() + { + RandomId = Helpers.GenerateRandomLong(), + Background = false, + ClearDraft = false, + Media = new TLInputMediaUploadedPhoto() { File = file, Caption = caption }, + Peer = peer + }, token) + .ConfigureAwait(false); + } + + public async Task SendUploadedDocument( + TLAbsInputPeer peer, TLAbsInputFile file, string caption, string mimeType, TLVector attributes, CancellationToken token = default(CancellationToken)) + { + return await SendAuthenticatedRequestAsync(new TLRequestSendMedia() + { + RandomId = Helpers.GenerateRandomLong(), + Background = false, + ClearDraft = false, + Media = new TLInputMediaUploadedDocument() + { + File = file, + Caption = caption, + MimeType = mimeType, + Attributes = attributes + }, + Peer = peer + }, token) + .ConfigureAwait(false); + } + + public async Task GetFile(TLAbsInputFileLocation location, int filePartSize, int offset = 0, CancellationToken token = default(CancellationToken)) + { + TLFile result = await SendAuthenticatedRequestAsync(new TLRequestGetFile + { + Location = location, + Limit = filePartSize, + Offset = offset + }, token) + .ConfigureAwait(false); + return result; + } + + public async Task SendPingAsync(CancellationToken token = default(CancellationToken)) + { + 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, CancellationToken token = default(CancellationToken)) + { + var req = new TLRequestGetHistory() + { + Peer = peer, + OffsetId = offsetId, + OffsetDate = offsetDate, + AddOffset = addOffset, + Limit = limit, + MaxId = maxId, + MinId = minId + }; + return await SendAuthenticatedRequestAsync(req, token) + .ConfigureAwait(false); + } + + /// + /// Serch user or chat. API: contacts.search#11f812d8 q:string limit:int = contacts.Found; + /// + /// User or chat name + /// Max result count + /// + public async Task SearchUserAsync(string q, int limit = 10, CancellationToken token = default(CancellationToken)) + { + var r = new TeleSharp.TL.Contacts.TLRequestSearch + { + Q = q, + Limit = limit + }; + + return await SendAuthenticatedRequestAsync(r, token) + .ConfigureAwait(false); + } + + private void OnUserAuthenticated(TLUser TLUser) + { + session.TLUser = TLUser; + session.SessionExpires = int.MaxValue; + + session.Save(); + } + + public bool IsConnected + { + get + { + if (transport == null) + return false; + return transport.IsConnected; + } + } + + public void Dispose() + { + if (transport != null) + { + transport.Dispose(); + transport = null; + } + } + } } From e067688a48a71eb3fdf271f6124d8023865b4a61 Mon Sep 17 00:00:00 2001 From: solarin Date: Fri, 3 Apr 2020 17:15:53 +0400 Subject: [PATCH 02/15] tabs-> 4 spaces added the csproj --- TLSharp.Core/TLSharp.Core.csproj | 1 + TLSharp.Core/TelegramClient.cs | 832 +++++++++++++++---------------- 2 files changed, 417 insertions(+), 416 deletions(-) diff --git a/TLSharp.Core/TLSharp.Core.csproj b/TLSharp.Core/TLSharp.Core.csproj index c09f394..07a3270 100644 --- a/TLSharp.Core/TLSharp.Core.csproj +++ b/TLSharp.Core/TLSharp.Core.csproj @@ -48,6 +48,7 @@ + diff --git a/TLSharp.Core/TelegramClient.cs b/TLSharp.Core/TelegramClient.cs index 997dfd5..cee8c00 100644 --- a/TLSharp.Core/TelegramClient.cs +++ b/TLSharp.Core/TelegramClient.cs @@ -25,458 +25,458 @@ using TLAuthorization = TeleSharp.TL.Auth.TLAuthorization; namespace TLSharp.Core { - public class TelegramClient : IDisposable - { - private MtProtoSender sender; - private TcpTransport transport; - private string apiHash = String.Empty; - private int apiId = 0; - private Session session; - private List dcOptions; - private TcpClientConnectionHandler handler; - private DataCenterIPVersion dcIpVersion; - - public Session Session - { - get { return session; } - } - - /// - /// Creates a new TelegramClient - /// - /// The API ID provided by Telegram. Get one at https://my.telegram.org - /// The API Hash provided by Telegram. Get one at https://my.telegram.org - /// An ISessionStore object that will handle the session - /// The name of the session that tracks login info about this TelegramClient connection - /// A delegate to invoke when a connection is needed and that will return a TcpClient that will be used to connect - /// Indicates the preferred IpAddress version to use to connect to a Telegram server - public TelegramClient(int apiId, string apiHash, - ISessionStore store = null, string sessionUserId = "session", TcpClientConnectionHandler handler = null, DataCenterIPVersion dcIpVersion = DataCenterIPVersion.Default) - { - if (apiId == default(int)) - throw new MissingApiConfigurationException("API_ID"); - if (string.IsNullOrEmpty(apiHash)) - throw new MissingApiConfigurationException("API_HASH"); - - if (store == null) - store = new FileSessionStore(); - - this.apiHash = apiHash; - this.apiId = apiId; - this.handler = handler; - this.dcIpVersion = dcIpVersion; - - session = Session.TryLoadOrCreateNew(store, sessionUserId); - transport = new TcpTransport(session.DataCenter.Address, session.DataCenter.Port, this.handler); - } - - public async Task ConnectAsync(bool reconnect = false, CancellationToken token = default(CancellationToken)) - { - token.ThrowIfCancellationRequested(); - - if (session.AuthKey == null || reconnect) - { - var result = await Authenticator.DoAuthentication(transport, token).ConfigureAwait(false); - session.AuthKey = result.AuthKey; - session.TimeOffset = result.TimeOffset; - } - - sender = new MtProtoSender(transport, session); - - //set-up layer - var config = new TLRequestGetConfig(); - var request = new TLRequestInitConnection() - { - ApiId = apiId, - AppVersion = "1.0.0", - DeviceModel = "PC", - LangCode = "en", - Query = config, - SystemVersion = "Win 10.0" - }; - var invokewithLayer = new TLRequestInvokeWithLayer() { Layer = 66, Query = request }; - await sender.Send(invokewithLayer, token).ConfigureAwait(false); - await sender.Receive(invokewithLayer, token).ConfigureAwait(false); - - dcOptions = ((TLConfig)invokewithLayer.Response).DcOptions.ToList(); - } - - private async Task ReconnectToDcAsync(int dcId, CancellationToken token = default(CancellationToken)) - { - token.ThrowIfCancellationRequested(); - - if (dcOptions == null || !dcOptions.Any()) - throw new InvalidOperationException($"Can't reconnect. Establish initial connection first."); - - TLExportedAuthorization exported = null; - if (session.TLUser != null) - { - TLRequestExportAuthorization exportAuthorization = new TLRequestExportAuthorization() { DcId = dcId }; - exported = await SendRequestAsync(exportAuthorization, token).ConfigureAwait(false); - } - - var dcs = dcOptions.Where(d => d.Id == dcId - && ( - (dcIpVersion == DataCenterIPVersion.Default) // any - || (d.Ipv6 && dcIpVersion == DataCenterIPVersion.OnlyIPv6) // selects only ipv6 addresses - || (!d.Ipv6 && dcIpVersion == DataCenterIPVersion.OnlyIPv4) // selects only ipv4 addresses - || dcIpVersion == DataCenterIPVersion.PreferIPv4 // we can take both types of address - || dcIpVersion == DataCenterIPVersion.PreferIPv6 // we can take both types of address - ) - ).OrderBy(d => d.Ipv6); - - if (dcs.Count() == 0) - throw new Exception($"Telegram server didn't provide us with any IPAddress that matches your preferences. If you chose OnlyIPvX, try switch to PreferIPvX instead."); - - var dc = dcIpVersion == DataCenterIPVersion.PreferIPv4 ? dcs.First() : dcs.Last(); // ipv4 addresses are at the beginning of the list because it was ordered - - var dataCenter = new DataCenter(dcId, dc.IpAddress, dc.Port); - - transport = new TcpTransport(dc.IpAddress, dc.Port, handler); - session.DataCenter = dataCenter; - - await ConnectAsync(true, token).ConfigureAwait(false); - - if (session.TLUser != null) - { - TLRequestImportAuthorization importAuthorization = new TLRequestImportAuthorization() { Id = exported.Id, Bytes = exported.Bytes }; - var imported = await SendRequestAsync(importAuthorization, token).ConfigureAwait(false); - OnUserAuthenticated((TLUser)imported.User); - } - } - - private async Task RequestWithDcMigration(TLMethod request, CancellationToken token = default(CancellationToken)) - { - if (sender == null) - throw new InvalidOperationException("Not connected!"); - - var completed = false; - while (!completed) - { - try - { - 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) - { - throw new Exception($"Telegram server replied requesting a migration to DataCenter {e.DC} when this connection was already using this DataCenter", e); - } + public class TelegramClient : IDisposable + { + private MtProtoSender sender; + private TcpTransport transport; + private string apiHash = String.Empty; + private int apiId = 0; + private Session session; + private List dcOptions; + private TcpClientConnectionHandler handler; + private DataCenterIPVersion dcIpVersion; + + public Session Session + { + get { return session; } + } + + /// + /// Creates a new TelegramClient + /// + /// The API ID provided by Telegram. Get one at https://my.telegram.org + /// The API Hash provided by Telegram. Get one at https://my.telegram.org + /// An ISessionStore object that will handle the session + /// The name of the session that tracks login info about this TelegramClient connection + /// A delegate to invoke when a connection is needed and that will return a TcpClient that will be used to connect + /// Indicates the preferred IpAddress version to use to connect to a Telegram server + public TelegramClient(int apiId, string apiHash, + ISessionStore store = null, string sessionUserId = "session", TcpClientConnectionHandler handler = null, DataCenterIPVersion dcIpVersion = DataCenterIPVersion.Default) + { + if (apiId == default(int)) + throw new MissingApiConfigurationException("API_ID"); + if (string.IsNullOrEmpty(apiHash)) + throw new MissingApiConfigurationException("API_HASH"); + + if (store == null) + store = new FileSessionStore(); + + this.apiHash = apiHash; + this.apiId = apiId; + this.handler = handler; + this.dcIpVersion = dcIpVersion; + + session = Session.TryLoadOrCreateNew(store, sessionUserId); + transport = new TcpTransport(session.DataCenter.Address, session.DataCenter.Port, this.handler); + } + + public async Task ConnectAsync(bool reconnect = false, CancellationToken token = default(CancellationToken)) + { + token.ThrowIfCancellationRequested(); + + if (session.AuthKey == null || reconnect) + { + var result = await Authenticator.DoAuthentication(transport, token).ConfigureAwait(false); + session.AuthKey = result.AuthKey; + session.TimeOffset = result.TimeOffset; + } + + sender = new MtProtoSender(transport, session); + + //set-up layer + var config = new TLRequestGetConfig(); + var request = new TLRequestInitConnection() + { + ApiId = apiId, + AppVersion = "1.0.0", + DeviceModel = "PC", + LangCode = "en", + Query = config, + SystemVersion = "Win 10.0" + }; + var invokewithLayer = new TLRequestInvokeWithLayer() { Layer = 66, Query = request }; + await sender.Send(invokewithLayer, token).ConfigureAwait(false); + await sender.Receive(invokewithLayer, token).ConfigureAwait(false); + + dcOptions = ((TLConfig)invokewithLayer.Response).DcOptions.ToList(); + } + + private async Task ReconnectToDcAsync(int dcId, CancellationToken token = default(CancellationToken)) + { + token.ThrowIfCancellationRequested(); + + if (dcOptions == null || !dcOptions.Any()) + throw new InvalidOperationException($"Can't reconnect. Establish initial connection first."); + + TLExportedAuthorization exported = null; + if (session.TLUser != null) + { + TLRequestExportAuthorization exportAuthorization = new TLRequestExportAuthorization() { DcId = dcId }; + exported = await SendRequestAsync(exportAuthorization, token).ConfigureAwait(false); + } + + var dcs = dcOptions.Where(d => d.Id == dcId + && ( + (dcIpVersion == DataCenterIPVersion.Default) // any + || (d.Ipv6 && dcIpVersion == DataCenterIPVersion.OnlyIPv6) // selects only ipv6 addresses + || (!d.Ipv6 && dcIpVersion == DataCenterIPVersion.OnlyIPv4) // selects only ipv4 addresses + || dcIpVersion == DataCenterIPVersion.PreferIPv4 // we can take both types of address + || dcIpVersion == DataCenterIPVersion.PreferIPv6 // we can take both types of address + ) + ).OrderBy(d => d.Ipv6); + + if (dcs.Count() == 0) + throw new Exception($"Telegram server didn't provide us with any IPAddress that matches your preferences. If you chose OnlyIPvX, try switch to PreferIPvX instead."); + + var dc = dcIpVersion == DataCenterIPVersion.PreferIPv4 ? dcs.First() : dcs.Last(); // ipv4 addresses are at the beginning of the list because it was ordered + + var dataCenter = new DataCenter(dcId, dc.IpAddress, dc.Port); + + transport = new TcpTransport(dc.IpAddress, dc.Port, handler); + session.DataCenter = dataCenter; + + await ConnectAsync(true, token).ConfigureAwait(false); + + if (session.TLUser != null) + { + TLRequestImportAuthorization importAuthorization = new TLRequestImportAuthorization() { Id = exported.Id, Bytes = exported.Bytes }; + var imported = await SendRequestAsync(importAuthorization, token).ConfigureAwait(false); + OnUserAuthenticated((TLUser)imported.User); + } + } + + private async Task RequestWithDcMigration(TLMethod request, CancellationToken token = default(CancellationToken)) + { + if (sender == null) + throw new InvalidOperationException("Not connected!"); + + var completed = false; + while (!completed) + { + try + { + 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) + { + 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, token).ConfigureAwait(false); - // prepare the request for another try - request.ConfirmReceived = false; - } - } - } + await ReconnectToDcAsync(e.DC, token).ConfigureAwait(false); + // prepare the request for another try + request.ConfirmReceived = false; + } + } + } - public bool IsUserAuthorized() - { - return session.TLUser != null; - } + public bool IsUserAuthorized() + { + return session.TLUser != null; + } - public async Task IsPhoneRegisteredAsync(string phoneNumber, CancellationToken token = default(CancellationToken)) - { - if (String.IsNullOrWhiteSpace(phoneNumber)) - throw new ArgumentNullException(nameof(phoneNumber)); + public async Task IsPhoneRegisteredAsync(string phoneNumber, CancellationToken token = default(CancellationToken)) + { + if (String.IsNullOrWhiteSpace(phoneNumber)) + throw new ArgumentNullException(nameof(phoneNumber)); - var authCheckPhoneRequest = new TLRequestCheckPhone() { PhoneNumber = phoneNumber }; + var authCheckPhoneRequest = new TLRequestCheckPhone() { PhoneNumber = phoneNumber }; - await RequestWithDcMigration(authCheckPhoneRequest, token).ConfigureAwait(false); + await RequestWithDcMigration(authCheckPhoneRequest, token).ConfigureAwait(false); - return authCheckPhoneRequest.Response.PhoneRegistered; - } + return authCheckPhoneRequest.Response.PhoneRegistered; + } - public async Task SendCodeRequestAsync(string phoneNumber, CancellationToken token = default(CancellationToken)) - { - if (String.IsNullOrWhiteSpace(phoneNumber)) - throw new ArgumentNullException(nameof(phoneNumber)); + public async Task SendCodeRequestAsync(string phoneNumber, CancellationToken token = default(CancellationToken)) + { + if (String.IsNullOrWhiteSpace(phoneNumber)) + throw new ArgumentNullException(nameof(phoneNumber)); - var request = new TLRequestSendCode() { PhoneNumber = phoneNumber, ApiId = apiId, ApiHash = apiHash }; + var request = new TLRequestSendCode() { PhoneNumber = phoneNumber, ApiId = apiId, ApiHash = apiHash }; - await RequestWithDcMigration(request, token).ConfigureAwait(false); + await RequestWithDcMigration(request, token).ConfigureAwait(false); - return request.Response.PhoneCodeHash; - } + return request.Response.PhoneCodeHash; + } - public async Task MakeAuthAsync(string phoneNumber, string phoneCodeHash, string code, CancellationToken token = default(CancellationToken)) - { - if (String.IsNullOrWhiteSpace(phoneNumber)) - throw new ArgumentNullException(nameof(phoneNumber)); + public async Task MakeAuthAsync(string phoneNumber, string phoneCodeHash, string code, CancellationToken token = default(CancellationToken)) + { + if (String.IsNullOrWhiteSpace(phoneNumber)) + throw new ArgumentNullException(nameof(phoneNumber)); - if (String.IsNullOrWhiteSpace(phoneCodeHash)) - throw new ArgumentNullException(nameof(phoneCodeHash)); + if (String.IsNullOrWhiteSpace(phoneCodeHash)) + throw new ArgumentNullException(nameof(phoneCodeHash)); - if (String.IsNullOrWhiteSpace(code)) - throw new ArgumentNullException(nameof(code)); + if (String.IsNullOrWhiteSpace(code)) + throw new ArgumentNullException(nameof(code)); - var request = new TLRequestSignIn() { PhoneNumber = phoneNumber, PhoneCodeHash = phoneCodeHash, PhoneCode = code }; + var request = new TLRequestSignIn() { PhoneNumber = phoneNumber, PhoneCodeHash = phoneCodeHash, PhoneCode = code }; - await RequestWithDcMigration(request, token).ConfigureAwait(false); + 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 GetPasswordSetting(CancellationToken token = default(CancellationToken)) - { - var request = new TLRequestGetPassword(); + public async Task GetPasswordSetting(CancellationToken token = default(CancellationToken)) + { + var request = new TLRequestGetPassword(); - await RequestWithDcMigration(request, token).ConfigureAwait(false); + await RequestWithDcMigration(request, token).ConfigureAwait(false); - return (TLPassword)request.Response; - } + return (TLPassword)request.Response; + } - public async Task MakeAuthWithPasswordAsync(TLPassword password, string password_str, CancellationToken token = default(CancellationToken)) - { - token.ThrowIfCancellationRequested(); + public async Task MakeAuthWithPasswordAsync(TLPassword password, string password_str, CancellationToken token = default(CancellationToken)) + { + token.ThrowIfCancellationRequested(); - byte[] password_Bytes = Encoding.UTF8.GetBytes(password_str); - IEnumerable rv = password.CurrentSalt.Concat(password_Bytes).Concat(password.CurrentSalt); + byte[] password_Bytes = Encoding.UTF8.GetBytes(password_str); + IEnumerable rv = password.CurrentSalt.Concat(password_Bytes).Concat(password.CurrentSalt); - SHA256Managed hashstring = new SHA256Managed(); - var password_hash = hashstring.ComputeHash(rv.ToArray()); + SHA256Managed hashstring = new SHA256Managed(); + var password_hash = hashstring.ComputeHash(rv.ToArray()); - var request = new TLRequestCheckPassword() { PasswordHash = password_hash }; + var request = new TLRequestCheckPassword() { PasswordHash = password_hash }; - await RequestWithDcMigration(request, token).ConfigureAwait(false); + 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 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 }; + public async Task SignUpAsync(string phoneNumber, string phoneCodeHash, string code, string firstName, string lastName, CancellationToken token = default(CancellationToken)) + { + var request = new TLRequestSignUp() { PhoneNumber = phoneNumber, PhoneCode = code, PhoneCodeHash = phoneCodeHash, FirstName = firstName, LastName = lastName }; - await RequestWithDcMigration(request, token).ConfigureAwait(false); + 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 SendRequestAsync(TLMethod methodToExecute, CancellationToken token = default(CancellationToken)) - { - await RequestWithDcMigration(methodToExecute, token).ConfigureAwait(false); + public async Task SendRequestAsync(TLMethod methodToExecute, CancellationToken token = default(CancellationToken)) + { + 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; + } - internal async Task SendAuthenticatedRequestAsync(TLMethod methodToExecute, CancellationToken token = default(CancellationToken)) - { - if (!IsUserAuthorized()) - throw new InvalidOperationException("Authorize user first!"); + internal async Task SendAuthenticatedRequestAsync(TLMethod methodToExecute, CancellationToken token = default(CancellationToken)) + { + if (!IsUserAuthorized()) + throw new InvalidOperationException("Authorize user first!"); - return await SendRequestAsync(methodToExecute, token) - .ConfigureAwait(false); - } + return await SendRequestAsync(methodToExecute, token) + .ConfigureAwait(false); + } - public async Task UpdateUsernameAsync(string username, CancellationToken token = default(CancellationToken)) - { - var req = new TLRequestUpdateUsername { Username = username }; + public async Task UpdateUsernameAsync(string username, CancellationToken token = default(CancellationToken)) + { + var req = new TLRequestUpdateUsername { Username = username }; - return await SendAuthenticatedRequestAsync(req, token) - .ConfigureAwait(false); - } - - public async Task CheckUsernameAsync(string username, CancellationToken token = default(CancellationToken)) - { - var req = new TLRequestCheckUsername { Username = username }; - - return await SendAuthenticatedRequestAsync(req, token) - .ConfigureAwait(false); - } - - public async Task ImportContactsAsync(IReadOnlyList contacts, CancellationToken token = default(CancellationToken)) - { - var req = new TLRequestImportContacts { Contacts = new TLVector(contacts) }; - - return await SendAuthenticatedRequestAsync(req, token) - .ConfigureAwait(false); - } - - public async Task DeleteContactsAsync(IReadOnlyList users, CancellationToken token = default(CancellationToken)) - { - var req = new TLRequestDeleteContacts { Id = new TLVector(users) }; - - return await SendAuthenticatedRequestAsync(req, token) - .ConfigureAwait(false); - } - - public async Task DeleteContactAsync(TLAbsInputUser user, CancellationToken token = default(CancellationToken)) - { - var req = new TLRequestDeleteContact { Id = user }; - - return await SendAuthenticatedRequestAsync(req, token) - .ConfigureAwait(false); - } - - public async Task GetContactsAsync(CancellationToken token = default(CancellationToken)) - { - var req = new TLRequestGetContacts() { Hash = "" }; - - return await SendAuthenticatedRequestAsync(req, token) - .ConfigureAwait(false); - } - - public async Task SendMessageAsync(TLAbsInputPeer peer, string message, CancellationToken token = default(CancellationToken)) - { - return await SendAuthenticatedRequestAsync( - new TLRequestSendMessage() - { - Peer = peer, - Message = message, - RandomId = Helpers.GenerateRandomLong() - }, token) - .ConfigureAwait(false); - } - - public async Task SendTypingAsync(TLAbsInputPeer peer, CancellationToken token = default(CancellationToken)) - { - var req = new TLRequestSetTyping() - { - Action = new TLSendMessageTypingAction(), - Peer = peer - }; - return await SendAuthenticatedRequestAsync(req, token) - .ConfigureAwait(false); - } - - public async Task GetUserDialogsAsync(int offsetDate = 0, int offsetId = 0, TLAbsInputPeer offsetPeer = null, int limit = 100, CancellationToken token = default(CancellationToken)) - { - if (offsetPeer == null) - offsetPeer = new TLInputPeerSelf(); - - var req = new TLRequestGetDialogs() - { - OffsetDate = offsetDate, - OffsetId = offsetId, - OffsetPeer = offsetPeer, - Limit = limit - }; - return await SendAuthenticatedRequestAsync(req, token) - .ConfigureAwait(false); - } - - public async Task SendUploadedPhoto(TLAbsInputPeer peer, TLAbsInputFile file, string caption, CancellationToken token = default(CancellationToken)) - { - return await SendAuthenticatedRequestAsync(new TLRequestSendMedia() - { - RandomId = Helpers.GenerateRandomLong(), - Background = false, - ClearDraft = false, - Media = new TLInputMediaUploadedPhoto() { File = file, Caption = caption }, - Peer = peer - }, token) - .ConfigureAwait(false); - } - - public async Task SendUploadedDocument( - TLAbsInputPeer peer, TLAbsInputFile file, string caption, string mimeType, TLVector attributes, CancellationToken token = default(CancellationToken)) - { - return await SendAuthenticatedRequestAsync(new TLRequestSendMedia() - { - RandomId = Helpers.GenerateRandomLong(), - Background = false, - ClearDraft = false, - Media = new TLInputMediaUploadedDocument() - { - File = file, - Caption = caption, - MimeType = mimeType, - Attributes = attributes - }, - Peer = peer - }, token) - .ConfigureAwait(false); - } - - public async Task GetFile(TLAbsInputFileLocation location, int filePartSize, int offset = 0, CancellationToken token = default(CancellationToken)) - { - TLFile result = await SendAuthenticatedRequestAsync(new TLRequestGetFile - { - Location = location, - Limit = filePartSize, - Offset = offset - }, token) - .ConfigureAwait(false); - return result; - } - - public async Task SendPingAsync(CancellationToken token = default(CancellationToken)) - { - 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, CancellationToken token = default(CancellationToken)) - { - var req = new TLRequestGetHistory() - { - Peer = peer, - OffsetId = offsetId, - OffsetDate = offsetDate, - AddOffset = addOffset, - Limit = limit, - MaxId = maxId, - MinId = minId - }; - return await SendAuthenticatedRequestAsync(req, token) - .ConfigureAwait(false); - } - - /// - /// Serch user or chat. API: contacts.search#11f812d8 q:string limit:int = contacts.Found; - /// - /// User or chat name - /// Max result count - /// - public async Task SearchUserAsync(string q, int limit = 10, CancellationToken token = default(CancellationToken)) - { - var r = new TeleSharp.TL.Contacts.TLRequestSearch - { - Q = q, - Limit = limit - }; - - return await SendAuthenticatedRequestAsync(r, token) - .ConfigureAwait(false); - } - - private void OnUserAuthenticated(TLUser TLUser) - { - session.TLUser = TLUser; - session.SessionExpires = int.MaxValue; - - session.Save(); - } - - public bool IsConnected - { - get - { - if (transport == null) - return false; - return transport.IsConnected; - } - } - - public void Dispose() - { - if (transport != null) - { - transport.Dispose(); - transport = null; - } - } - } + return await SendAuthenticatedRequestAsync(req, token) + .ConfigureAwait(false); + } + + public async Task CheckUsernameAsync(string username, CancellationToken token = default(CancellationToken)) + { + var req = new TLRequestCheckUsername { Username = username }; + + return await SendAuthenticatedRequestAsync(req, token) + .ConfigureAwait(false); + } + + public async Task ImportContactsAsync(IReadOnlyList contacts, CancellationToken token = default(CancellationToken)) + { + var req = new TLRequestImportContacts { Contacts = new TLVector(contacts) }; + + return await SendAuthenticatedRequestAsync(req, token) + .ConfigureAwait(false); + } + + public async Task DeleteContactsAsync(IReadOnlyList users, CancellationToken token = default(CancellationToken)) + { + var req = new TLRequestDeleteContacts { Id = new TLVector(users) }; + + return await SendAuthenticatedRequestAsync(req, token) + .ConfigureAwait(false); + } + + public async Task DeleteContactAsync(TLAbsInputUser user, CancellationToken token = default(CancellationToken)) + { + var req = new TLRequestDeleteContact { Id = user }; + + return await SendAuthenticatedRequestAsync(req, token) + .ConfigureAwait(false); + } + + public async Task GetContactsAsync(CancellationToken token = default(CancellationToken)) + { + var req = new TLRequestGetContacts() { Hash = "" }; + + return await SendAuthenticatedRequestAsync(req, token) + .ConfigureAwait(false); + } + + public async Task SendMessageAsync(TLAbsInputPeer peer, string message, CancellationToken token = default(CancellationToken)) + { + return await SendAuthenticatedRequestAsync( + new TLRequestSendMessage() + { + Peer = peer, + Message = message, + RandomId = Helpers.GenerateRandomLong() + }, token) + .ConfigureAwait(false); + } + + public async Task SendTypingAsync(TLAbsInputPeer peer, CancellationToken token = default(CancellationToken)) + { + var req = new TLRequestSetTyping() + { + Action = new TLSendMessageTypingAction(), + Peer = peer + }; + return await SendAuthenticatedRequestAsync(req, token) + .ConfigureAwait(false); + } + + public async Task GetUserDialogsAsync(int offsetDate = 0, int offsetId = 0, TLAbsInputPeer offsetPeer = null, int limit = 100, CancellationToken token = default(CancellationToken)) + { + if (offsetPeer == null) + offsetPeer = new TLInputPeerSelf(); + + var req = new TLRequestGetDialogs() + { + OffsetDate = offsetDate, + OffsetId = offsetId, + OffsetPeer = offsetPeer, + Limit = limit + }; + return await SendAuthenticatedRequestAsync(req, token) + .ConfigureAwait(false); + } + + public async Task SendUploadedPhoto(TLAbsInputPeer peer, TLAbsInputFile file, string caption, CancellationToken token = default(CancellationToken)) + { + return await SendAuthenticatedRequestAsync(new TLRequestSendMedia() + { + RandomId = Helpers.GenerateRandomLong(), + Background = false, + ClearDraft = false, + Media = new TLInputMediaUploadedPhoto() { File = file, Caption = caption }, + Peer = peer + }, token) + .ConfigureAwait(false); + } + + public async Task SendUploadedDocument( + TLAbsInputPeer peer, TLAbsInputFile file, string caption, string mimeType, TLVector attributes, CancellationToken token = default(CancellationToken)) + { + return await SendAuthenticatedRequestAsync(new TLRequestSendMedia() + { + RandomId = Helpers.GenerateRandomLong(), + Background = false, + ClearDraft = false, + Media = new TLInputMediaUploadedDocument() + { + File = file, + Caption = caption, + MimeType = mimeType, + Attributes = attributes + }, + Peer = peer + }, token) + .ConfigureAwait(false); + } + + public async Task GetFile(TLAbsInputFileLocation location, int filePartSize, int offset = 0, CancellationToken token = default(CancellationToken)) + { + TLFile result = await SendAuthenticatedRequestAsync(new TLRequestGetFile + { + Location = location, + Limit = filePartSize, + Offset = offset + }, token) + .ConfigureAwait(false); + return result; + } + + public async Task SendPingAsync(CancellationToken token = default(CancellationToken)) + { + 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, CancellationToken token = default(CancellationToken)) + { + var req = new TLRequestGetHistory() + { + Peer = peer, + OffsetId = offsetId, + OffsetDate = offsetDate, + AddOffset = addOffset, + Limit = limit, + MaxId = maxId, + MinId = minId + }; + return await SendAuthenticatedRequestAsync(req, token) + .ConfigureAwait(false); + } + + /// + /// Serch user or chat. API: contacts.search#11f812d8 q:string limit:int = contacts.Found; + /// + /// User or chat name + /// Max result count + /// + public async Task SearchUserAsync(string q, int limit = 10, CancellationToken token = default(CancellationToken)) + { + var r = new TeleSharp.TL.Contacts.TLRequestSearch + { + Q = q, + Limit = limit + }; + + return await SendAuthenticatedRequestAsync(r, token) + .ConfigureAwait(false); + } + + private void OnUserAuthenticated(TLUser TLUser) + { + session.TLUser = TLUser; + session.SessionExpires = int.MaxValue; + + session.Save(); + } + + public bool IsConnected + { + get + { + if (transport == null) + return false; + return transport.IsConnected; + } + } + + public void Dispose() + { + if (transport != null) + { + transport.Dispose(); + transport = null; + } + } + } } From 92ca5a9ac112db86f193dbee1107404fd6126263 Mon Sep 17 00:00:00 2001 From: solarin Date: Fri, 3 Apr 2020 17:35:18 +0400 Subject: [PATCH 03/15] + GetFullChat to get the info of a chat + GetAllChats to get all available user's chats + MakeAuthBotAsync to authenticate a bot instead of a user --- TLSharp.Core/TelegramClient.cs | 63 ++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/TLSharp.Core/TelegramClient.cs b/TLSharp.Core/TelegramClient.cs index cee8c00..d4906a8 100644 --- a/TLSharp.Core/TelegramClient.cs +++ b/TLSharp.Core/TelegramClient.cs @@ -434,6 +434,69 @@ namespace TLSharp.Core .ConfigureAwait(false); } + /// + /// Authenticates a Bot + /// + /// The token of the bot to authenticate + /// + /// The TLUser descriptor + public async Task MakeAuthBotAsync(string botAuthToken, CancellationToken token = default(CancellationToken)) + { + if (String.IsNullOrWhiteSpace(botAuthToken)) + { + throw new ArgumentNullException(nameof(botAuthToken)); + } + + var request = new TLRequestImportBotAuthorization() { BotAuthToken = botAuthToken, ApiId = apiId, ApiHash = apiHash }; + + await RequestWithDcMigration(request, token).ConfigureAwait(false); + + OnUserAuthenticated(((TLUser)request.Response.User)); + + return ((TLUser)request.Response.User); + } + + /// + /// Gets the full information of a specified chat + /// + /// The ID of the chat we want the info of + /// + /// + public async Task GetFullChat(int chatId, CancellationToken token = default(CancellationToken)) + { + var req = new TLRequestGetFullChat() { ChatId = chatId }; + var fchat = await SendRequestAsync(req).ConfigureAwait(false); + + return fchat; + } + + /// + /// Gets the list of chats opened by the authenticated user. + /// Throws an exception if the authenticated user is a bot. + /// + /// + /// The list of chats opened by the authenticated user + public async Task GetAllChats(CancellationToken token = default(CancellationToken)) + { + return await GetAllChats(null, token); + } + + /// + /// Gets the list of chats opened by the authenticated user except the passed ones. + /// Throws an exception if the authenticated user is a bot. + /// + /// The IDs of the chats that we don't want to be returned + /// + /// The list of chats opened by the authenticated user + public async Task GetAllChats(int[] exceptIds = null, CancellationToken token = default(CancellationToken)) + { + var ichats = new TeleSharp.TL.TLVector(); // we can't pass a null argument to the TLRequestGetChats + if (exceptIds != null) + Array.ForEach(exceptIds, x => ichats.Add(x)); + var chatInfo = await SendRequestAsync(new TLRequestGetChats() { Id = ichats }).ConfigureAwait(false); + return chatInfo; + } + /// /// Serch user or chat. API: contacts.search#11f812d8 q:string limit:int = contacts.Found; /// From 406a73b89c21e1ac1797aea11de8bff664ba03f3 Mon Sep 17 00:00:00 2001 From: solarin Date: Fri, 3 Apr 2020 17:55:21 +0400 Subject: [PATCH 04/15] fixed typos and spaces --- TLSharp.Core/DataCenterIPVersion.cs | 10 ++--- TLSharp.Core/TelegramClient.cs | 63 ----------------------------- 2 files changed, 5 insertions(+), 68 deletions(-) diff --git a/TLSharp.Core/DataCenterIPVersion.cs b/TLSharp.Core/DataCenterIPVersion.cs index 9b22794..9c908ac 100644 --- a/TLSharp.Core/DataCenterIPVersion.cs +++ b/TLSharp.Core/DataCenterIPVersion.cs @@ -4,26 +4,26 @@ /// When the Telegram server responds with a set of addresses to connect to, DataCenterIPVersion indicates a preference /// for how to choose the IP address to connect to /// - public enum DataCenterIPVersion + public enum DataCenterIPVersion { /// /// Prefers IPv6 addresses if any is passed by Telegram /// - Default = 0, + Default = 0, /// /// Takes only IPv4 addresses /// - OnlyIPv4 = 1, + OnlyIPv4 = 1, /// /// Takes only IPv6 addresses /// - OnlyIPv6 = 2, + OnlyIPv6 = 2, /// /// Connection to IPv4 addresses is preferred to IPv6 addresses /// PreferIPv4 = 3, /// - /// Connection to IPv6 addresses is preferred to IPv6 addresses + /// Connection to IPv6 addresses is preferred to IPv4 addresses /// PreferIPv6 = 4, } diff --git a/TLSharp.Core/TelegramClient.cs b/TLSharp.Core/TelegramClient.cs index d4906a8..cee8c00 100644 --- a/TLSharp.Core/TelegramClient.cs +++ b/TLSharp.Core/TelegramClient.cs @@ -434,69 +434,6 @@ namespace TLSharp.Core .ConfigureAwait(false); } - /// - /// Authenticates a Bot - /// - /// The token of the bot to authenticate - /// - /// The TLUser descriptor - public async Task MakeAuthBotAsync(string botAuthToken, CancellationToken token = default(CancellationToken)) - { - if (String.IsNullOrWhiteSpace(botAuthToken)) - { - throw new ArgumentNullException(nameof(botAuthToken)); - } - - var request = new TLRequestImportBotAuthorization() { BotAuthToken = botAuthToken, ApiId = apiId, ApiHash = apiHash }; - - await RequestWithDcMigration(request, token).ConfigureAwait(false); - - OnUserAuthenticated(((TLUser)request.Response.User)); - - return ((TLUser)request.Response.User); - } - - /// - /// Gets the full information of a specified chat - /// - /// The ID of the chat we want the info of - /// - /// - public async Task GetFullChat(int chatId, CancellationToken token = default(CancellationToken)) - { - var req = new TLRequestGetFullChat() { ChatId = chatId }; - var fchat = await SendRequestAsync(req).ConfigureAwait(false); - - return fchat; - } - - /// - /// Gets the list of chats opened by the authenticated user. - /// Throws an exception if the authenticated user is a bot. - /// - /// - /// The list of chats opened by the authenticated user - public async Task GetAllChats(CancellationToken token = default(CancellationToken)) - { - return await GetAllChats(null, token); - } - - /// - /// Gets the list of chats opened by the authenticated user except the passed ones. - /// Throws an exception if the authenticated user is a bot. - /// - /// The IDs of the chats that we don't want to be returned - /// - /// The list of chats opened by the authenticated user - public async Task GetAllChats(int[] exceptIds = null, CancellationToken token = default(CancellationToken)) - { - var ichats = new TeleSharp.TL.TLVector(); // we can't pass a null argument to the TLRequestGetChats - if (exceptIds != null) - Array.ForEach(exceptIds, x => ichats.Add(x)); - var chatInfo = await SendRequestAsync(new TLRequestGetChats() { Id = ichats }).ConfigureAwait(false); - return chatInfo; - } - /// /// Serch user or chat. API: contacts.search#11f812d8 q:string limit:int = contacts.Found; /// From 54781b235fe41de637498a9b25457b5d83214132 Mon Sep 17 00:00:00 2001 From: solarin Date: Fri, 3 Apr 2020 17:57:48 +0400 Subject: [PATCH 05/15] + GetFullChat to get the info of a chat + GetAllChats to get all available user's chats + MakeAuthBotAsync to authenticate a bot instead of a user --- TLSharp.Core/TelegramClient.cs | 63 ++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/TLSharp.Core/TelegramClient.cs b/TLSharp.Core/TelegramClient.cs index cee8c00..d4906a8 100644 --- a/TLSharp.Core/TelegramClient.cs +++ b/TLSharp.Core/TelegramClient.cs @@ -434,6 +434,69 @@ namespace TLSharp.Core .ConfigureAwait(false); } + /// + /// Authenticates a Bot + /// + /// The token of the bot to authenticate + /// + /// The TLUser descriptor + public async Task MakeAuthBotAsync(string botAuthToken, CancellationToken token = default(CancellationToken)) + { + if (String.IsNullOrWhiteSpace(botAuthToken)) + { + throw new ArgumentNullException(nameof(botAuthToken)); + } + + var request = new TLRequestImportBotAuthorization() { BotAuthToken = botAuthToken, ApiId = apiId, ApiHash = apiHash }; + + await RequestWithDcMigration(request, token).ConfigureAwait(false); + + OnUserAuthenticated(((TLUser)request.Response.User)); + + return ((TLUser)request.Response.User); + } + + /// + /// Gets the full information of a specified chat + /// + /// The ID of the chat we want the info of + /// + /// + public async Task GetFullChat(int chatId, CancellationToken token = default(CancellationToken)) + { + var req = new TLRequestGetFullChat() { ChatId = chatId }; + var fchat = await SendRequestAsync(req).ConfigureAwait(false); + + return fchat; + } + + /// + /// Gets the list of chats opened by the authenticated user. + /// Throws an exception if the authenticated user is a bot. + /// + /// + /// The list of chats opened by the authenticated user + public async Task GetAllChats(CancellationToken token = default(CancellationToken)) + { + return await GetAllChats(null, token); + } + + /// + /// Gets the list of chats opened by the authenticated user except the passed ones. + /// Throws an exception if the authenticated user is a bot. + /// + /// The IDs of the chats that we don't want to be returned + /// + /// The list of chats opened by the authenticated user + public async Task GetAllChats(int[] exceptIds = null, CancellationToken token = default(CancellationToken)) + { + var ichats = new TeleSharp.TL.TLVector(); // we can't pass a null argument to the TLRequestGetChats + if (exceptIds != null) + Array.ForEach(exceptIds, x => ichats.Add(x)); + var chatInfo = await SendRequestAsync(new TLRequestGetChats() { Id = ichats }).ConfigureAwait(false); + return chatInfo; + } + /// /// Serch user or chat. API: contacts.search#11f812d8 q:string limit:int = contacts.Found; /// From 2d4aa3e8f90222c9271b7bffa59824af3d14605e Mon Sep 17 00:00:00 2001 From: "Andres G. Aragoneses" Date: Fri, 31 Jan 2020 14:39:19 +0800 Subject: [PATCH 06/15] style: more consistent naming removing underscores There were less places with underscores in field names than places without them, so we now are consistent with the most abundant occurrence. --- TLSharp.Core/DataCenterIPVersion.cs | 30 ----- TLSharp.Core/TLSharp.Core.csproj | 1 - TLSharp.Core/TelegramClient.cs | 173 +++++++--------------------- 3 files changed, 41 insertions(+), 163 deletions(-) delete mode 100644 TLSharp.Core/DataCenterIPVersion.cs diff --git a/TLSharp.Core/DataCenterIPVersion.cs b/TLSharp.Core/DataCenterIPVersion.cs deleted file mode 100644 index 9c908ac..0000000 --- a/TLSharp.Core/DataCenterIPVersion.cs +++ /dev/null @@ -1,30 +0,0 @@ -namespace TLSharp.Core -{ - /// - /// When the Telegram server responds with a set of addresses to connect to, DataCenterIPVersion indicates a preference - /// for how to choose the IP address to connect to - /// - public enum DataCenterIPVersion - { - /// - /// Prefers IPv6 addresses if any is passed by Telegram - /// - Default = 0, - /// - /// Takes only IPv4 addresses - /// - OnlyIPv4 = 1, - /// - /// Takes only IPv6 addresses - /// - OnlyIPv6 = 2, - /// - /// Connection to IPv4 addresses is preferred to IPv6 addresses - /// - PreferIPv4 = 3, - /// - /// Connection to IPv6 addresses is preferred to IPv4 addresses - /// - PreferIPv6 = 4, - } -} diff --git a/TLSharp.Core/TLSharp.Core.csproj b/TLSharp.Core/TLSharp.Core.csproj index 07a3270..c09f394 100644 --- a/TLSharp.Core/TLSharp.Core.csproj +++ b/TLSharp.Core/TLSharp.Core.csproj @@ -48,7 +48,6 @@ - diff --git a/TLSharp.Core/TelegramClient.cs b/TLSharp.Core/TelegramClient.cs index d4906a8..46e0ad4 100644 --- a/TLSharp.Core/TelegramClient.cs +++ b/TLSharp.Core/TelegramClient.cs @@ -1,7 +1,5 @@ using System; using System.Collections.Generic; -using System.Configuration; -using System.Data; using System.Linq; using System.Security.Cryptography; using System.Text; @@ -24,7 +22,6 @@ using TLAuthorization = TeleSharp.TL.Auth.TLAuthorization; namespace TLSharp.Core { - public class TelegramClient : IDisposable { private MtProtoSender sender; @@ -34,24 +31,14 @@ namespace TLSharp.Core private Session session; private List dcOptions; private TcpClientConnectionHandler handler; - private DataCenterIPVersion dcIpVersion; public Session Session { get { return session; } } - /// - /// Creates a new TelegramClient - /// - /// The API ID provided by Telegram. Get one at https://my.telegram.org - /// The API Hash provided by Telegram. Get one at https://my.telegram.org - /// An ISessionStore object that will handle the session - /// The name of the session that tracks login info about this TelegramClient connection - /// A delegate to invoke when a connection is needed and that will return a TcpClient that will be used to connect - /// Indicates the preferred IpAddress version to use to connect to a Telegram server public TelegramClient(int apiId, string apiHash, - ISessionStore store = null, string sessionUserId = "session", TcpClientConnectionHandler handler = null, DataCenterIPVersion dcIpVersion = DataCenterIPVersion.Default) + ISessionStore store = null, string sessionUserId = "session", TcpClientConnectionHandler handler = null) { if (apiId == default(int)) throw new MissingApiConfigurationException("API_ID"); @@ -64,10 +51,9 @@ namespace TLSharp.Core this.apiHash = apiHash; this.apiId = apiId; this.handler = handler; - this.dcIpVersion = dcIpVersion; session = Session.TryLoadOrCreateNew(store, sessionUserId); - transport = new TcpTransport(session.DataCenter.Address, session.DataCenter.Port, this.handler); + transport = new TcpTransport (session.DataCenter.Address, session.DataCenter.Port, this.handler); } public async Task ConnectAsync(bool reconnect = false, CancellationToken token = default(CancellationToken)) @@ -115,22 +101,8 @@ namespace TLSharp.Core exported = await SendRequestAsync(exportAuthorization, token).ConfigureAwait(false); } - var dcs = dcOptions.Where(d => d.Id == dcId - && ( - (dcIpVersion == DataCenterIPVersion.Default) // any - || (d.Ipv6 && dcIpVersion == DataCenterIPVersion.OnlyIPv6) // selects only ipv6 addresses - || (!d.Ipv6 && dcIpVersion == DataCenterIPVersion.OnlyIPv4) // selects only ipv4 addresses - || dcIpVersion == DataCenterIPVersion.PreferIPv4 // we can take both types of address - || dcIpVersion == DataCenterIPVersion.PreferIPv6 // we can take both types of address - ) - ).OrderBy(d => d.Ipv6); - - if (dcs.Count() == 0) - throw new Exception($"Telegram server didn't provide us with any IPAddress that matches your preferences. If you chose OnlyIPvX, try switch to PreferIPvX instead."); - - var dc = dcIpVersion == DataCenterIPVersion.PreferIPv4 ? dcs.First() : dcs.Last(); // ipv4 addresses are at the beginning of the list because it was ordered - - var dataCenter = new DataCenter(dcId, dc.IpAddress, dc.Port); + 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; @@ -151,7 +123,7 @@ namespace TLSharp.Core throw new InvalidOperationException("Not connected!"); var completed = false; - while (!completed) + while(!completed) { try { @@ -159,7 +131,7 @@ namespace TLSharp.Core await sender.Receive(request, token).ConfigureAwait(false); completed = true; } - catch (DataCenterMigrationException e) + catch(DataCenterMigrationException e) { if (session.DataCenter.DataCenterId.HasValue && session.DataCenter.DataCenterId.Value == e.DC) @@ -213,7 +185,7 @@ namespace TLSharp.Core if (String.IsNullOrWhiteSpace(code)) throw new ArgumentNullException(nameof(code)); - + var request = new TLRequestSignIn() { PhoneNumber = phoneNumber, PhoneCodeHash = phoneCodeHash, PhoneCode = code }; await RequestWithDcMigration(request, token).ConfigureAwait(false); @@ -222,7 +194,7 @@ namespace TLSharp.Core return ((TLUser)request.Response.User); } - + public async Task GetPasswordSetting(CancellationToken token = default(CancellationToken)) { var request = new TLRequestGetPassword(); @@ -254,7 +226,7 @@ namespace TLSharp.Core public async Task SignUpAsync(string phoneNumber, string phoneCodeHash, string code, string firstName, string lastName, CancellationToken token = default(CancellationToken)) { var request = new TLRequestSignUp() { PhoneNumber = phoneNumber, PhoneCode = code, PhoneCodeHash = phoneCodeHash, FirstName = firstName, LastName = lastName }; - + await RequestWithDcMigration(request, token).ConfigureAwait(false); OnUserAuthenticated((TLUser)request.Response.User); @@ -271,7 +243,7 @@ namespace TLSharp.Core return (T)result; } - internal async Task SendAuthenticatedRequestAsync(TLMethod methodToExecute, CancellationToken token = default(CancellationToken)) + internal async Task SendAuthenticatedRequestAsync (TLMethod methodToExecute, CancellationToken token = default(CancellationToken)) { if (!IsUserAuthorized()) throw new InvalidOperationException("Authorize user first!"); @@ -298,7 +270,7 @@ namespace TLSharp.Core public async Task ImportContactsAsync(IReadOnlyList contacts, CancellationToken token = default(CancellationToken)) { - var req = new TLRequestImportContacts { Contacts = new TLVector(contacts) }; + var req = new TLRequestImportContacts { Contacts = new TLVector(contacts)}; return await SendAuthenticatedRequestAsync(req, token) .ConfigureAwait(false); @@ -306,7 +278,7 @@ namespace TLSharp.Core public async Task DeleteContactsAsync(IReadOnlyList users, CancellationToken token = default(CancellationToken)) { - var req = new TLRequestDeleteContacts { Id = new TLVector(users) }; + var req = new TLRequestDeleteContacts {Id = new TLVector(users)}; return await SendAuthenticatedRequestAsync(req, token) .ConfigureAwait(false); @@ -314,7 +286,7 @@ namespace TLSharp.Core public async Task DeleteContactAsync(TLAbsInputUser user, CancellationToken token = default(CancellationToken)) { - var req = new TLRequestDeleteContact { Id = user }; + var req = new TLRequestDeleteContact {Id = user}; return await SendAuthenticatedRequestAsync(req, token) .ConfigureAwait(false); @@ -357,10 +329,10 @@ namespace TLSharp.Core offsetPeer = new TLInputPeerSelf(); var req = new TLRequestGetDialogs() - { - OffsetDate = offsetDate, - OffsetId = offsetId, - OffsetPeer = offsetPeer, + { + OffsetDate = offsetDate, + OffsetId = offsetId, + OffsetPeer = offsetPeer, Limit = limit }; return await SendAuthenticatedRequestAsync(req, token) @@ -370,13 +342,13 @@ namespace TLSharp.Core public async Task SendUploadedPhoto(TLAbsInputPeer peer, TLAbsInputFile file, string caption, CancellationToken token = default(CancellationToken)) { return await SendAuthenticatedRequestAsync(new TLRequestSendMedia() - { - RandomId = Helpers.GenerateRandomLong(), - Background = false, - ClearDraft = false, - Media = new TLInputMediaUploadedPhoto() { File = file, Caption = caption }, - Peer = peer - }, token) + { + RandomId = Helpers.GenerateRandomLong(), + Background = false, + ClearDraft = false, + Media = new TLInputMediaUploadedPhoto() { File = file, Caption = caption }, + Peer = peer + }, token) .ConfigureAwait(false); } @@ -384,30 +356,30 @@ namespace TLSharp.Core TLAbsInputPeer peer, TLAbsInputFile file, string caption, string mimeType, TLVector attributes, CancellationToken token = default(CancellationToken)) { return await SendAuthenticatedRequestAsync(new TLRequestSendMedia() - { - RandomId = Helpers.GenerateRandomLong(), - Background = false, - ClearDraft = false, - Media = new TLInputMediaUploadedDocument() { - File = file, - Caption = caption, - MimeType = mimeType, - Attributes = attributes - }, - Peer = peer - }, token) + RandomId = Helpers.GenerateRandomLong(), + Background = false, + ClearDraft = false, + Media = new TLInputMediaUploadedDocument() + { + File = file, + Caption = caption, + MimeType = mimeType, + Attributes = attributes + }, + Peer = peer + }, token) .ConfigureAwait(false); } public async Task GetFile(TLAbsInputFileLocation location, int filePartSize, int offset = 0, CancellationToken token = default(CancellationToken)) { TLFile result = await SendAuthenticatedRequestAsync(new TLRequestGetFile - { - Location = location, - Limit = filePartSize, - Offset = offset - }, token) + { + Location = location, + Limit = filePartSize, + Offset = offset + }, token) .ConfigureAwait(false); return result; } @@ -434,69 +406,6 @@ namespace TLSharp.Core .ConfigureAwait(false); } - /// - /// Authenticates a Bot - /// - /// The token of the bot to authenticate - /// - /// The TLUser descriptor - public async Task MakeAuthBotAsync(string botAuthToken, CancellationToken token = default(CancellationToken)) - { - if (String.IsNullOrWhiteSpace(botAuthToken)) - { - throw new ArgumentNullException(nameof(botAuthToken)); - } - - var request = new TLRequestImportBotAuthorization() { BotAuthToken = botAuthToken, ApiId = apiId, ApiHash = apiHash }; - - await RequestWithDcMigration(request, token).ConfigureAwait(false); - - OnUserAuthenticated(((TLUser)request.Response.User)); - - return ((TLUser)request.Response.User); - } - - /// - /// Gets the full information of a specified chat - /// - /// The ID of the chat we want the info of - /// - /// - public async Task GetFullChat(int chatId, CancellationToken token = default(CancellationToken)) - { - var req = new TLRequestGetFullChat() { ChatId = chatId }; - var fchat = await SendRequestAsync(req).ConfigureAwait(false); - - return fchat; - } - - /// - /// Gets the list of chats opened by the authenticated user. - /// Throws an exception if the authenticated user is a bot. - /// - /// - /// The list of chats opened by the authenticated user - public async Task GetAllChats(CancellationToken token = default(CancellationToken)) - { - return await GetAllChats(null, token); - } - - /// - /// Gets the list of chats opened by the authenticated user except the passed ones. - /// Throws an exception if the authenticated user is a bot. - /// - /// The IDs of the chats that we don't want to be returned - /// - /// The list of chats opened by the authenticated user - public async Task GetAllChats(int[] exceptIds = null, CancellationToken token = default(CancellationToken)) - { - var ichats = new TeleSharp.TL.TLVector(); // we can't pass a null argument to the TLRequestGetChats - if (exceptIds != null) - Array.ForEach(exceptIds, x => ichats.Add(x)); - var chatInfo = await SendRequestAsync(new TLRequestGetChats() { Id = ichats }).ConfigureAwait(false); - return chatInfo; - } - /// /// Serch user or chat. API: contacts.search#11f812d8 q:string limit:int = contacts.Found; /// From 00fb3ae5007910377c6e97e14c46a491ffecea50 Mon Sep 17 00:00:00 2001 From: solarin Date: Fri, 3 Apr 2020 20:31:44 +0400 Subject: [PATCH 07/15] removed the previously added changed not pertinent to this PR --- TLSharp.Core/TelegramClient.cs | 63 ++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/TLSharp.Core/TelegramClient.cs b/TLSharp.Core/TelegramClient.cs index 46e0ad4..b282a59 100644 --- a/TLSharp.Core/TelegramClient.cs +++ b/TLSharp.Core/TelegramClient.cs @@ -406,6 +406,69 @@ namespace TLSharp.Core .ConfigureAwait(false); } + /// + /// Authenticates a Bot + /// + /// The token of the bot to authenticate + /// + /// The TLUser descriptor + public async Task MakeAuthBotAsync(string botAuthToken, CancellationToken token = default(CancellationToken)) + { + if (String.IsNullOrWhiteSpace(botAuthToken)) + { + throw new ArgumentNullException(nameof(botAuthToken)); + } + + var request = new TLRequestImportBotAuthorization() { BotAuthToken = botAuthToken, ApiId = apiId, ApiHash = apiHash }; + + await RequestWithDcMigration(request, token).ConfigureAwait(false); + + OnUserAuthenticated(((TLUser)request.Response.User)); + + return ((TLUser)request.Response.User); + } + + /// + /// Gets the full information of a specified chat + /// + /// The ID of the chat we want the info of + /// + /// + public async Task GetFullChat(int chatId, CancellationToken token = default(CancellationToken)) + { + var req = new TLRequestGetFullChat() { ChatId = chatId }; + var fchat = await SendRequestAsync(req).ConfigureAwait(false); + + return fchat; + } + + /// + /// Gets the list of chats opened by the authenticated user. + /// Throws an exception if the authenticated user is a bot. + /// + /// + /// The list of chats opened by the authenticated user + public async Task GetAllChats(CancellationToken token = default(CancellationToken)) + { + return await GetAllChats(null, token); + } + + /// + /// Gets the list of chats opened by the authenticated user except the passed ones. + /// Throws an exception if the authenticated user is a bot. + /// + /// The IDs of the chats that we don't want to be returned + /// + /// The list of chats opened by the authenticated user + public async Task GetAllChats(int[] exceptIds = null, CancellationToken token = default(CancellationToken)) + { + var ichats = new TeleSharp.TL.TLVector(); // we can't pass a null argument to the TLRequestGetChats + if (exceptIds != null) + Array.ForEach(exceptIds, x => ichats.Add(x)); + var chatInfo = await SendRequestAsync(new TLRequestGetChats() { Id = ichats }).ConfigureAwait(false); + return chatInfo; + } + /// /// Serch user or chat. API: contacts.search#11f812d8 q:string limit:int = contacts.Found; /// From 65ff8ccbc10abda6e59864c9b3d0b36def8d70b6 Mon Sep 17 00:00:00 2001 From: solarin Date: Sun, 5 Apr 2020 15:42:48 +0400 Subject: [PATCH 08/15] --- TLSharp.Core/TLSharp.Core.csproj | 4 +- TLSharp.Core/TelegramClient.cs | 167 ++++++++++++++++++++++++++----- 2 files changed, 147 insertions(+), 24 deletions(-) diff --git a/TLSharp.Core/TLSharp.Core.csproj b/TLSharp.Core/TLSharp.Core.csproj index c09f394..eedca93 100644 --- a/TLSharp.Core/TLSharp.Core.csproj +++ b/TLSharp.Core/TLSharp.Core.csproj @@ -88,7 +88,9 @@ TeleSharp.TL - + + +