mirror of
https://github.com/wiz0u/WTelegramClient.git
synced 2026-02-05 23:24:18 +01:00
Support for FLOOD_WAIT_X
This commit is contained in:
parent
70f9a61e17
commit
39f03ed78f
13
README.md
13
README.md
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 };
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue