Support for FLOOD_WAIT_X

This commit is contained in:
Wizou 2021-08-14 08:55:30 +02:00
parent 70f9a61e17
commit 39f03ed78f
3 changed files with 41 additions and 12 deletions

View file

@ -69,6 +69,7 @@ Its `int` argument is the log severity, compatible with the classic [LogLevel en
:information_source: The Telegram API makes extensive usage of base and derived classes, so be ready to use the various syntaxes C# offer to check/cast base classes into the more useful derived classes (`is`, `as`, `case DerivedType` )
To find which derived classes are available for a given base class, the fastest is to check our [TL.Schema.cs](src/TL.Schema.cs) source file as they are listed in groups.
Intellisense tooltips on API structures/methods will also display a web link to the adequate Telegram documentation page.
The Telegram [API object classes](https://core.telegram.org/schema) are defined in the `TL` namespace, and the [API functions](https://core.telegram.org/methods) are available as async methods of `Client`.
@ -102,14 +103,20 @@ await client.SendMessageAsync(target, "Hello, World");
An invalid API request can result in a RpcException being raised, reflecting the [error code and status text](https://core.telegram.org/api/errors) of the problem.
Beyond the TL async methods, the Client class offers a few other methods to simplify the sending of files, medias or messages.
The other configuration items that you can override include: **session_pathname, server_address, device_model, system_version, app_version, system_lang_code, lang_pack, lang_code**
Optional API parameters have a default value of `null` when unset. Passing `null` for a required string/array is the same as *empty* (0-length). Required API parameters/fields can sometimes be set to 0 or `null` when unused (check API documentation).
I've added several useful converters or implicit cast to various API object so that they are more easy to manipulate.
Beyond the TL async methods, the Client class offers a few other methods to simplify the sending of files, medias or messages.
For the moment, this library requires .NET 5.0 minimum.
# Development status
The library is already well usable for many scenarios involving automated steps based on API requests/responses.
The library is usable for most scenarios including (sequential or parallel) automated steps based on API requests/responses, or real-time monitoring of incoming Updates/messages. Secret chats have not been tested yet.
Developers feedback are welcome in the Telegram channel [@WTelegramClient](https://t.me/WTelegramClient)
Here are the main expected developments:
- [x] Encrypt session file

View file

@ -422,22 +422,31 @@ namespace WTelegram
lock (_pendingRequests)
if (_pendingRequests.TryGetValue(msgId, out request))
_pendingRequests.Remove(msgId);
object result;
if (request.type != null)
{
var result = reader.ReadTLValue(request.type);
Helpers.Log(1, $" → {result?.GetType().Name,-47} #{(short)msgId.GetHashCode():X4}");
result = reader.ReadTLValue(request.type);
Log(1, "");
Task.Run(() => request.tcs.SetResult(result)); // to avoid deadlock, see https://blog.stephencleary.com/2012/12/dont-block-in-asynchronous-code.html
return new RpcResult { req_msg_id = msgId, result = result };
}
else
{
var result = reader.ReadTLObject();
result = reader.ReadTLObject();
if (_session.MsgIdToStamp(msgId) >= _session.SessionStart)
Helpers.Log(4, $" → {result?.GetType().Name,-47} for unknown msgId #{(short)msgId.GetHashCode():X4}");
Log(4, "for unknown msgId ");
else
Helpers.Log(1, $" → {result?.GetType().Name,-47} for past msgId #{(short)msgId.GetHashCode():X4}");
Log(1, "for past msgId ");
return new RpcResult { req_msg_id = msgId, result = result };
}
void Log(int level, string msgIdprefix)
{
if (result is RpcError rpcError)
Helpers.Log(4, $" → RpcError {rpcError.error_code,3} {rpcError.error_message,-34} {msgIdprefix}#{(short)msgId.GetHashCode():X4}");
else
Helpers.Log(level, $" → {result?.GetType().Name,-47} {msgIdprefix}#{(short)msgId.GetHashCode():X4}");
}
}
public class RpcException : Exception
@ -467,11 +476,17 @@ namespace WTelegram
{
case X resultX: return resultX;
case RpcError rpcError:
int migrateDC;
if (rpcError.error_code == 303 && ((migrateDC = rpcError.error_message.IndexOf("_MIGRATE_")) > 0))
int number;
if (rpcError.error_code == 303 && ((number = rpcError.error_message.IndexOf("_MIGRATE_")) > 0))
{
migrateDC = int.Parse(rpcError.error_message[(migrateDC + 9)..]);
await MigrateDCAsync(migrateDC);
number = int.Parse(rpcError.error_message[(number + 9)..]);
await MigrateDCAsync(number);
goto retry;
}
else if (rpcError.error_code == 420 && ((number = rpcError.error_message.IndexOf("_WAIT_")) > 0))
{
number = int.Parse(rpcError.error_message[(number + 6)..]);
await Task.Delay(number * 1000);
goto retry;
}
else

View file

@ -13,6 +13,7 @@
{
public abstract int ID { get; }
public abstract string Title { get; }
public abstract bool IsBanned(ChatBannedRights.Flags flags = 0);
protected abstract InputPeer ToInputPeer();
public static implicit operator InputPeer(ChatBase chat) => chat.ToInputPeer();
}
@ -20,24 +21,29 @@
{
public override int ID => id;
public override string Title => null;
public override bool IsBanned(ChatBannedRights.Flags flags = 0) => true;
protected override InputPeer ToInputPeer() => InputPeer.Empty;
}
partial class Chat
{
public override int ID => id;
public override string Title => title;
/// <summary>returns true if you're banned of any of these rights</summary>
public override bool IsBanned(ChatBannedRights.Flags flags = 0) => ((default_banned_rights?.flags ?? 0) & flags) != 0;
protected override InputPeer ToInputPeer() => new InputPeerChat { chat_id = id };
}
partial class ChatForbidden
{
public override int ID => id;
public override string Title => title;
public override bool IsBanned(ChatBannedRights.Flags flags = 0) => true;
protected override InputPeer ToInputPeer() => new InputPeerChat { chat_id = id };
}
partial class Channel
{
public override int ID => id;
public override string Title => title;
public override bool IsBanned(ChatBannedRights.Flags flags = 0) => ((banned_rights?.flags ?? 0) & flags) != 0 || ((default_banned_rights?.flags ?? 0) & flags) != 0;
protected override InputPeer ToInputPeer() => new InputPeerChannel { channel_id = id, access_hash = access_hash };
public static implicit operator InputChannel(Channel channel) => new() { channel_id = channel.id, access_hash = channel.access_hash };
}
@ -45,6 +51,7 @@
{
public override int ID => id;
public override string Title => title;
public override bool IsBanned(ChatBannedRights.Flags flags = 0) => true;
protected override InputPeer ToInputPeer() => new InputPeerChannel { channel_id = id, access_hash = access_hash };
}