mirror of
https://github.com/wiz0u/WTelegramClient.git
synced 2025-12-06 06:52:01 +01:00
Handle BadMsgNotification 32/33 by renewing session
This commit is contained in:
parent
bafe3c56bd
commit
e1132f653b
6
FAQ.md
6
FAQ.md
|
|
@ -32,9 +32,9 @@ This might require adding a reference *(and `using`)* to the Microsoft.VisualBas
|
||||||
|
|
||||||
#### 4. I get the error `CHAT_ID_INVALID` or `CHANNEL_INVALID`
|
#### 4. I get the error `CHAT_ID_INVALID` or `CHANNEL_INVALID`
|
||||||
|
|
||||||
First, you should distinguish between Chat, Channel and Group/Supergroup: See Terminology in [ReadMe](README.md#Terminology-in-Telegram-Client-API)
|
First, you should distinguish between Chat, Channel and Group/Supergroup: See Terminology in [ReadMe](README.md#Terminology-in-Telegram-Client-API).
|
||||||
Most chat groups are in fact not a simple `Chat` but rather a (super)group (= a `Channel` without the `broadcast` flag)
|
Common chat groups are usually not a simple `Chat` but rather a supergroup: a `Channel` without the `broadcast` flag
|
||||||
Some TL methods only applies to simple Chat, and some only applies to Channels.
|
Some TL methods only applies to simple `Chat`, and some only applies to `Channel`.
|
||||||
|
|
||||||
A simple `Chat` can be queried using their `chat_id` only.
|
A simple `Chat` can be queried using their `chat_id` only.
|
||||||
But a `Channel` must be queried using an `InputChannel` or `InputPeerChannel` object that specifies the `channel_id` as well as an `access_hash` that proves you are allowed to access it.
|
But a `Channel` must be queried using an `InputChannel` or `InputPeerChannel` object that specifies the `channel_id` as well as an `access_hash` that proves you are allowed to access it.
|
||||||
|
|
|
||||||
|
|
@ -106,9 +106,9 @@ await client.SendMessageAsync(target, "Hello, World");
|
||||||
# Terminology in Telegram Client API
|
# Terminology in Telegram Client API
|
||||||
|
|
||||||
In the API, Telegram uses some terms/classnames that can be confusing as they differ from the terms shown to end-users:
|
In the API, Telegram uses some terms/classnames that can be confusing as they differ from the terms shown to end-users:
|
||||||
- `Channel` : A (large) chat group *(sometimes called supergroup)* or a broadcast channel (the `broadcast` flag differenciate those)
|
- `Channel` : A (large or public) chat group *(sometimes called supergroup)* or a broadcast channel (the `broadcast` flag differenciate those)
|
||||||
- `Chat` : A private simple chat group with few people (it may be migrated to a supergroup/channel when it doesn't fit anymore)
|
- `Chat` : A private simple chat group with less than 200 members (it may be migrated to a supergroup `Channel` with a new ID when it gets bigger or public, in which case the old `Chat` will still exist but be `deactivated`)
|
||||||
- Chats : In plural, it means either `Chat` or `Channel`
|
- chats : In plural or general meaning, it means either `Chat` or `Channel`
|
||||||
- `Peer` : Either a `Chat`, `Channel` or a private chat with a `User`
|
- `Peer` : Either a `Chat`, `Channel` or a private chat with a `User`
|
||||||
- Dialog : The current status of a chat with a `Peer` *(draft, last message, unread count, pinned...)*
|
- Dialog : The current status of a chat with a `Peer` *(draft, last message, unread count, pinned...)*
|
||||||
- DC (DataCenter) : There are a few datacenters depending on where in the world the user (or an uploaded media file) is from.
|
- DC (DataCenter) : There are a few datacenters depending on where in the world the user (or an uploaded media file) is from.
|
||||||
|
|
|
||||||
|
|
@ -837,19 +837,6 @@ namespace WTelegram
|
||||||
if (msgCopy?.orig_message?.body != null)
|
if (msgCopy?.orig_message?.body != null)
|
||||||
await HandleMessageAsync(msgCopy.orig_message.body);
|
await HandleMessageAsync(msgCopy.orig_message.body);
|
||||||
break;
|
break;
|
||||||
case BadServerSalt badServerSalt:
|
|
||||||
_dcSession.Salt = badServerSalt.new_server_salt;
|
|
||||||
if (badServerSalt.bad_msg_id == _dcSession.LastSentMsgId)
|
|
||||||
{
|
|
||||||
var newMsgId = await SendAsync(_lastSentMsg, true);
|
|
||||||
lock (_pendingRequests)
|
|
||||||
if (_pendingRequests.TryGetValue(badServerSalt.bad_msg_id, out var t))
|
|
||||||
{
|
|
||||||
_pendingRequests.Remove(badServerSalt.bad_msg_id);
|
|
||||||
_pendingRequests[newMsgId] = t;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TL.Methods.Ping ping:
|
case TL.Methods.Ping ping:
|
||||||
_ = SendAsync(new Pong { msg_id = _lastRecvMsgId, ping_id = ping.ping_id }, false);
|
_ = SendAsync(new Pong { msg_id = _lastRecvMsgId, ping_id = ping.ping_id }, false);
|
||||||
break;
|
break;
|
||||||
|
|
@ -864,17 +851,48 @@ namespace WTelegram
|
||||||
case MsgsAck msgsAck:
|
case MsgsAck msgsAck:
|
||||||
break; // we don't do anything with these, for now
|
break; // we don't do anything with these, for now
|
||||||
case BadMsgNotification badMsgNotification:
|
case BadMsgNotification badMsgNotification:
|
||||||
{
|
await _sendSemaphore.WaitAsync();
|
||||||
|
bool retryLast = badMsgNotification.bad_msg_id == _dcSession.LastSentMsgId;
|
||||||
|
var lastSentMsg = _lastSentMsg;
|
||||||
|
_sendSemaphore.Release();
|
||||||
Helpers.Log(4, $"BadMsgNotification {badMsgNotification.error_code} for msg #{(short)badMsgNotification.bad_msg_id.GetHashCode():X4}");
|
Helpers.Log(4, $"BadMsgNotification {badMsgNotification.error_code} for msg #{(short)badMsgNotification.bad_msg_id.GetHashCode():X4}");
|
||||||
var tcs = PullPendingRequest(badMsgNotification.bad_msg_id).tcs;
|
switch (badMsgNotification.error_code)
|
||||||
if (tcs != null)
|
{
|
||||||
|
case 32: // msg_seqno too low (the server has already received a message with a lower msg_id but with either a higher or an equal and odd seqno)
|
||||||
|
case 33: // msg_seqno too high (similarly, there is a message with a higher msg_id but with either a lower or an equal and odd seqno)
|
||||||
|
if (_dcSession.Seqno <= 1)
|
||||||
|
retryLast = false;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Reset(false, false);
|
||||||
|
_dcSession.Renew();
|
||||||
|
await ConnectAsync();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 48: // incorrect server salt (in this case, the bad_server_salt response is received with the correct salt, and the message is to be re-sent with it)
|
||||||
|
_dcSession.Salt = ((BadServerSalt)badMsgNotification).new_server_salt;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
retryLast = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (retryLast)
|
||||||
|
{
|
||||||
|
var newMsgId = await SendAsync(lastSentMsg, true);
|
||||||
|
lock (_pendingRequests)
|
||||||
|
if (_pendingRequests.TryGetValue(badMsgNotification.bad_msg_id, out var t))
|
||||||
|
{
|
||||||
|
_pendingRequests.Remove(badMsgNotification.bad_msg_id);
|
||||||
|
_pendingRequests[newMsgId] = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (PullPendingRequest(badMsgNotification.bad_msg_id).tcs is TaskCompletionSource<object> tcs)
|
||||||
{
|
{
|
||||||
if (_bareRequest == badMsgNotification.bad_msg_id) _bareRequest = 0;
|
if (_bareRequest == badMsgNotification.bad_msg_id) _bareRequest = 0;
|
||||||
tcs.SetException(new ApplicationException($"BadMsgNotification {badMsgNotification.error_code}"));
|
tcs.SetException(new ApplicationException($"BadMsgNotification {badMsgNotification.error_code}"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
OnUpdate(obj);
|
OnUpdate(obj);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (_bareRequest != 0)
|
if (_bareRequest != 0)
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ namespace WTelegram
|
||||||
public static Action<int, string> Log { get; set; } = DefaultLogger;
|
public static Action<int, string> Log { get; set; } = DefaultLogger;
|
||||||
|
|
||||||
/// <summary>For serializing indented Json with fields included</summary>
|
/// <summary>For serializing indented Json with fields included</summary>
|
||||||
public static readonly JsonSerializerOptions JsonOptions = new() { IncludeFields = true, WriteIndented = true };
|
public static readonly JsonSerializerOptions JsonOptions = new() { IncludeFields = true, WriteIndented = true, IgnoreReadOnlyProperties = true };
|
||||||
|
|
||||||
public static V GetOrCreate<K, V>(this Dictionary<K, V> dictionary, K key) where V : new()
|
public static V GetOrCreate<K, V>(this Dictionary<K, V> dictionary, K key) where V : new()
|
||||||
=> dictionary.TryGetValue(key, out V value) ? value : dictionary[key] = new V();
|
=> dictionary.TryGetValue(key, out V value) ? value : dictionary[key] = new V();
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ namespace WTelegram
|
||||||
internal Client Client;
|
internal Client Client;
|
||||||
internal int DcID => DataCenter?.id ?? 0;
|
internal int DcID => DataCenter?.id ?? 0;
|
||||||
internal IPEndPoint EndPoint => DataCenter == null ? null : new(IPAddress.Parse(DataCenter.ip_address), DataCenter.port);
|
internal IPEndPoint EndPoint => DataCenter == null ? null : new(IPAddress.Parse(DataCenter.ip_address), DataCenter.port);
|
||||||
|
internal void Renew() { Helpers.Log(3, $"Renewing session on DC {DcID}..."); Id = Helpers.RandomLong(); Seqno = 0; LastSentMsgId = 0; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public DateTime SessionStart => _sessionStart;
|
public DateTime SessionStart => _sessionStart;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue