From 280bc3c411017c9e5a42f40cd73dbeacc8dbf446 Mon Sep 17 00:00:00 2001 From: Wizou <11647984+wiz0u@users.noreply.github.com> Date: Tue, 20 Sep 2022 17:30:32 +0200 Subject: [PATCH] Alternative/simplified constructor & login method --- src/Client.cs | 96 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 89 insertions(+), 7 deletions(-) diff --git a/src/Client.cs b/src/Client.cs index 68099fb..5548888 100644 --- a/src/Client.cs +++ b/src/Client.cs @@ -47,8 +47,10 @@ namespace WTelegram public bool Disconnected => _tcpClient != null && !(_tcpClient.Client?.Connected ?? false); /// ID of the current logged-in user or 0 public long UserId => _session.UserId; + /// Info about the current logged-in user + public User User { get; private set; } - private readonly Func _config; + private Func _config; private readonly Session _session; private string _apiHash; private Session.DCSession _dcSession; @@ -76,6 +78,16 @@ namespace WTelegram #endif private bool _paddedMode; + public Client(int apiID, string apiHash, string sessionPathname = null) + : this(what => what switch + { + "api_id" => apiID.ToString(), + "api_hash" => apiHash, + "session_pathname" => sessionPathname, + _ => null + }) + { } + /// Welcome to WTelegramClient! 🙂 /// Config callback, is queried for: api_id, api_hash, session_pathname /// if specified, must support initial Length & Read() of a session, then calls to Write() the updated session. Other calls can be ignored @@ -202,7 +214,11 @@ namespace WTelegram } } if (resetUser) + { + _loginCfg = default; _session.UserId = 0; + User = null; + } } private Session.DCSession GetOrCreateDCSession(int dcId, DcOption.Flags flags) @@ -858,14 +874,77 @@ namespace WTelegram } } + /// Login as a user with given phone number (or resume previous session)
Call this method again to provide additional requested login information
+ /// First call should be with phone number
Further calls should be with the requested configuration value + /// Configuration item requested to continue login, or when login is successful
+ /// Possible values: verification_code, name (signup), password (2FA)
+ /// + public async Task Login(string loginInfo) + { + if (_loginCfg.request == default) RunLoginAsync(loginInfo); + else + { + if (await _loginCfg.request.Task == null) return null; + loginInfo ??= AskConfig(await _loginCfg.request.Task); + _loginCfg.request = new(); + _loginCfg.response.SetResult(loginInfo); + } + return await _loginCfg.request.Task; + } + private (TaskCompletionSource request, TaskCompletionSource response) _loginCfg; + private async void RunLoginAsync(string phone) + { + _loginCfg.request = new(); + var prevConfig = _config; + _config = what => + { + if (prevConfig(what) is string value) return value; + switch (what) + { + case "phone_number": return phone; + case "last_name": break; + case "first_name": what = "name"; goto case "email"; + case "email": case "email_verification_code": + case "password": case "verification_code": _loginCfg.response = new(); _loginCfg.request.SetResult(what); break; + default: return null; + }; + value = _loginCfg.response.Task.Result; + if (what == "name" && value != null) + { + var lf = value.IndexOf('\n'); + if (lf < 0) lf = value.IndexOf(' '); + _loginCfg.response = new(); + _loginCfg.response.SetResult(lf < 0 ? "" : value[(lf + 1)..]); + value = lf < 0 ? value : value[0..lf]; + return value; + } + return value; + }; + try + { + // Login logic is executed on TaskScheduler while request TCS are still received on current SynchronizationContext + await Task.Run(() => LoginUserIfNeeded()); + _loginCfg.request.SetResult(null); + } + catch (Exception ex) + { + _loginCfg.request.SetException(ex); + } + finally + { + _config = prevConfig; + } + } + /// Login as a bot (if not already logged-in). - /// Config callback is queried for: bot_token + /// bot token, or if token is provided by Config callback + /// Config callback may be queried for: bot_token ///
Bots can only call API methods marked with [bots: ✓] in their documentation.
/// Detail about the logged-in bot - public async Task LoginBotIfNeeded() + public async Task LoginBotIfNeeded(string bot_token = null) { await ConnectAsync(); - string botToken = Config("bot_token"); + string botToken = bot_token ?? Config("bot_token"); if (_session.UserId != 0) // a user is already logged-in { try @@ -875,7 +954,7 @@ namespace WTelegram if (self.id == long.Parse(botToken.Split(':')[0])) { _session.UserId = _dcSession.UserId = self.id; - return self; + return User = self; } Helpers.Log(3, $"Current logged user {self.id} mismatched bot_token. Logging out and in..."); } @@ -885,6 +964,7 @@ namespace WTelegram } await this.Auth_LogOut(); _session.UserId = _dcSession.UserId = 0; + User = null; } var authorization = await this.Auth_ImportBotAuthorization(0, _session.ApiId, _apiHash ??= Config("api_hash"), botToken); return LoginAlreadyDone(authorization); @@ -912,7 +992,7 @@ namespace WTelegram self.phone == string.Concat((phone_number = Config("phone_number")).Where(char.IsDigit))) { _session.UserId = _dcSession.UserId = self.id; - return self; + return User = self; } var mismatch = $"Current logged user {self.id} mismatched user_id or phone_number"; Helpers.Log(3, mismatch); @@ -925,6 +1005,7 @@ namespace WTelegram Helpers.Log(3, $"Proceeding to logout and login..."); await this.Auth_LogOut(); _session.UserId = _dcSession.UserId = 0; + User = null; } phone_number ??= Config("phone_number"); Auth_SentCode sentCode; @@ -1052,7 +1133,7 @@ namespace WTelegram throw new ApplicationException("Failed to get Authorization: " + authorization.GetType().Name); _session.UserId = _dcSession.UserId = user.id; lock (_session) _session.Save(); - return user; + return User = user; } private MsgsAck CheckMsgsToAck() @@ -1233,6 +1314,7 @@ namespace WTelegram else if (code == 500 && message == "AUTH_RESTART") { _session.UserId = 0; // force a full login authorization flow, next time + User = null; lock (_session) _session.Save(); } throw new RpcException(code, message, x);