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);