diff --git a/FAQ.md b/FAQ.md index d8cc57b..f48c5ee 100644 --- a/FAQ.md +++ b/FAQ.md @@ -1,6 +1,6 @@ ## FAQ -#### 1. How to remove the Console logs ? +#### 1. How to remove the Console logs? Writing the library logs to the Console is the default behavior of the `WTelegram.Helpers.Log` delegate. You can change the delegate with the `+=` operator to **also** write them somewhere else, or with the `=` operator to prevent them from being printed to screen and instead write them somewhere (file, logger, ...). @@ -14,7 +14,7 @@ The WTelegram.session file contains the authentication keys negociated for the c You could switch the current user via an `Auth_Logout` followed by a `LoginUserIfNeeded` but that would require the user to sign in with a verification_code each time. -Instead, if you want to deal with multiple users, the recommended solution is to have a different session file for each user. This can be done by having your Config callback reply with a different filename (or folder) for "**session_pathname**" for each user. +Instead, if you want to deal with multiple users from the same machine, the recommended solution is to have a different session file for each user. This can be done by having your Config callback reply with a different filename (or folder) for "**session_pathname**" for each user. This way, you can keep separate session files (each with their authentication keys) for each user. If you need to manage these user accounts in parallel, you can create multiple instances of WTelegram.Client, and give them a Config callback that will select a different session file. @@ -97,14 +97,13 @@ Here are some key points: *(the above section is derived from [gotd SUPPORT.md](https://github.com/gotd/td/blob/main/.github/SUPPORT.md))* - -#### 8. I can't import phone numbers. I get error PHONE_NUMBER_BANNED or FLOOD_WAIT_84200 +#### 8. I can't import phone numbers. I get error PHONE_NUMBER_BANNED or FLOOD_WAIT_8xxxx You can get these kind of problems if you abuse Telegram [Terms of Service](https://telegram.org/tos) or make excessive requests. You can try to wait more between the requests, wait for a day or two to see if the requests become possible again. -If you think your phone number was banned for a bad reason, you may try to contact [recover@telegram.org](mailto:recover@telegram.org), explaining what you were doing. +If you think your phone number was banned for a wrong reason, you may try to contact [recover@telegram.org](mailto:recover@telegram.org), explaining what you were doing. In any case, WTelegramClient is not responsible for the bad usage of the library and we are not affiliated to Telegram teams, so there is nothing we can do. diff --git a/README.md b/README.md index 1f13cd6..223165c 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ There are other configuration items that are queried to your method but returnin Those shown above are the only ones that have no default values and should be provided by your method. Returning `null` for verification_code or password will show a prompt for console apps, or an error otherwise. -Another simpler approach is to pass `Environment.GetEnvironmentVariable` as the config callback and define the configuration items as environment variables. +Another simple approach is to pass `Environment.GetEnvironmentVariable` as the config callback and define the configuration items as environment variables. Undefined variables get the default `null` behavior. Finally, if you want to redirect the library logs to your logger instead of the Console, you can install a delegate in the `WTelegram.Helpers.Log` static property. @@ -101,7 +101,7 @@ Console.WriteLine($"Sending a message in chat {chatId}: {target.Title}"); await client.SendMessageAsync(target, "Hello, World"); ``` -You can find more useful code snippets in [EXAMPLES.md](https://github.com/wiz0u/WTelegramClient/blob/master/EXAMPLES.md) and in the [Examples subdirectory](https://github.com/wiz0u/WTelegramClient/tree/master/Examples). +➡️ You can find more useful code snippets in [EXAMPLES.md](https://github.com/wiz0u/WTelegramClient/blob/master/EXAMPLES.md) and in the [Examples subdirectory](https://github.com/wiz0u/WTelegramClient/tree/master/Examples). # Terminology in Telegram Client API @@ -142,6 +142,6 @@ Secret chats (end-to-end encryption, PFS) and connection to CDN DCs have not bee Please don't use this library for Spam or Scam. Respect Telegram [Terms of Service](https://telegram.org/tos) or you might get banned from Telegram servers. Developers feedbacks are welcome in the Telegram support group [@WTelegramClient](https://t.me/WTelegramClient) -You can also check our [Frequently Asked Questions](https://github.com/wiz0u/WTelegramClient/blob/master/FAQ.md) for more help and troubleshooting guide. +You can also check our [📖 Frequently Asked Questions](https://github.com/wiz0u/WTelegramClient/blob/master/FAQ.md) for more help and troubleshooting guide. -If you like this library, please [consider a donation](http://wizou.fr/donate.html). ❤ This will help the project keep going. +If you like this library, please [consider a donation](http://wizou.fr/donate.html).❤ This will help the project keep going. diff --git a/src/Client.cs b/src/Client.cs index d399dcc..17ec6e2 100644 --- a/src/Client.cs +++ b/src/Client.cs @@ -63,6 +63,7 @@ namespace WTelegram private CancellationTokenSource _cts; private int _reactorReconnects = 0; private const int FilePartSize = 512 * 1024; + private const string ConnectionShutDown = "Could not read payload length : Connection shut down"; private readonly SemaphoreSlim _parallelTransfers = new(10); // max parallel part uploads/downloads #if MTPROTO1 private readonly SHA1 _sha1 = SHA1.Create(); @@ -391,7 +392,7 @@ namespace WTelegram try { if (await FullReadAsync(stream, data, 4, cts.Token) != 4) - throw new ApplicationException("Could not read payload length : Connection shut down"); + throw new ApplicationException(ConnectionShutDown); int payloadLen = BinaryPrimitives.ReadInt32LittleEndian(data); if (payloadLen > data.Length) data = new byte[payloadLen]; @@ -405,17 +406,20 @@ namespace WTelegram catch (Exception ex) // an exception in RecvAsync is always fatal { if (cts.IsCancellationRequested) return; - Helpers.Log(5, $"An exception occured in the reactor: {ex}"); + Helpers.Log(5, $"{_dcSession.DcID}>An exception occured in the reactor: {ex}"); var oldSemaphore = _sendSemaphore; await oldSemaphore.WaitAsync(cts.Token); // prevent any sending while we reconnect var reactorError = new ReactorError { Exception = ex }; try { + lock (_msgsToAck) _msgsToAck.Clear(); + Reset(false, false); _reactorReconnects = (_reactorReconnects + 1) % MaxAutoReconnects; + if (!IsMainDC && _pendingRequests.Count <= 1 && ex is ApplicationException { Message: ConnectionShutDown } or IOException { InnerException: SocketException }) + if (_pendingRequests.Values.FirstOrDefault() is var (type, tcs) && (type is null || type == typeof(Pong))) + _reactorReconnects = 0; if (_reactorReconnects != 0) { - lock (_msgsToAck) _msgsToAck.Clear(); - Reset(false, false); await Task.Delay(5000); await ConnectAsync(); // start a new reactor after 5 secs lock (_pendingRequests) // retry all pending requests @@ -450,7 +454,6 @@ namespace WTelegram { oldSemaphore.Release(); } - cts.Cancel(); // always stop the reactor } if (obj != null) await HandleMessageAsync(obj); @@ -584,8 +587,8 @@ namespace WTelegram writer.Write(0L); // int64 auth_key_id = 0 (Unencrypted) writer.Write(msgId); // int64 message_id writer.Write(0); // int32 message_data_length (to be patched) - writer.WriteTLObject(msg); // bytes message_data Helpers.Log(1, $"{_dcSession.DcID}>Sending {msg.GetType().Name.TrimEnd('_')}..."); + writer.WriteTLObject(msg); // bytes message_data BinaryPrimitives.WriteInt32LittleEndian(memStream.GetBuffer().AsSpan(20), (int)memStream.Length - 24); // patch message_data_length } else @@ -603,11 +606,11 @@ namespace WTelegram clearWriter.Write(msgId); // int64 message_id clearWriter.Write(seqno); // int32 msg_seqno clearWriter.Write(0); // int32 message_data_length (to be patched) - clearWriter.WriteTLObject(msg); // bytes message_data if ((seqno & 1) != 0) Helpers.Log(1, $"{_dcSession.DcID}>Sending {msg.GetType().Name.TrimEnd('_'),-40} #{(short)msgId.GetHashCode():X4}"); else Helpers.Log(1, $"{_dcSession.DcID}>Sending {msg.GetType().Name.TrimEnd('_'),-40} {MsgIdToStamp(msgId):u} (svc)"); + clearWriter.WriteTLObject(msg); // bytes message_data int clearLength = (int)clearStream.Length - prepend; // length before padding (= 32 + message_data_length) int padding = (0x7FFFFFF0 - clearLength) % 16; #if !MTPROTO1 diff --git a/src/TL.cs b/src/TL.cs index 779c992..6e5f70e 100644 --- a/src/TL.cs +++ b/src/TL.cs @@ -178,9 +178,9 @@ namespace TL writer.Write(0); // patched below writer.WriteTLObject(msg.body); if ((msg.seqno & 1) != 0) - WTelegram.Helpers.Log(1, $" Sending → {msg.body.GetType().Name.TrimEnd('_'),-40} #{(short)msg.msg_id.GetHashCode():X4}"); + WTelegram.Helpers.Log(1, $" → {msg.body.GetType().Name.TrimEnd('_'),-38} #{(short)msg.msg_id.GetHashCode():X4}"); else - WTelegram.Helpers.Log(1, $" Sending → {msg.body.GetType().Name.TrimEnd('_'),-40}"); + WTelegram.Helpers.Log(1, $" → {msg.body.GetType().Name.TrimEnd('_'),-38}"); writer.BaseStream.Position = patchPos; writer.Write((int)(writer.BaseStream.Length - patchPos - 4)); // patch bytes field writer.Seek(0, SeekOrigin.End);