From 74bba5721e32684ddd03cfb75be20aa8f0a18278 Mon Sep 17 00:00:00 2001
From: Wizou <11647984+wiz0u@users.noreply.github.com>
Date: Mon, 14 Feb 2022 15:17:15 +0100
Subject: [PATCH] Updated docs. Negative PingInterval
---
EXAMPLES.md | 67 ++++++++++++---------------------------------------
FAQ.md | 36 +++++++++++++++------------
README.md | 4 +--
src/Client.cs | 9 ++++---
4 files changed, 44 insertions(+), 72 deletions(-)
diff --git a/EXAMPLES.md b/EXAMPLES.md
index a5466a6..d29ae3e 100644
--- a/EXAMPLES.md
+++ b/EXAMPLES.md
@@ -1,13 +1,16 @@
## Example programs using WTelegramClient
-The following codes can be saved into a Program.cs file with the only addition of some `using` on top of file, like
+For these examples to work as a fully-functional Program.cs, be sure to start with these lines:
```csharp
using System;
using System.Linq;
using TL;
+
+using var client = new WTelegram.Client(Environment.GetEnvironmentVariable);
+var myself = await client.LoginUserIfNeeded();
```
-Those examples use environment variables for configuration so make sure to
+In this case, environment variables are used for configuration so make sure to
go to your **Project Properties > Debug > Environment variables**
and add at least these variables with adequate value: **api_id, api_hash, phone_number**
@@ -19,8 +22,6 @@ More examples can also be found in answers to [StackOverflow questions](https://
### Send a message to someone by @username
```csharp
-using var client = new WTelegram.Client(Environment.GetEnvironmentVariable);
-await client.LoginUserIfNeeded();
var resolved = await client.Contacts_ResolveUsername("username"); // without the @
await client.SendMessageAsync(resolved, "Hello!");
```
@@ -30,8 +31,6 @@ If the username is invalid/unused, the API call raises an exception.*
### Send a message to someone by phone number
```csharp
-using var client = new WTelegram.Client(Environment.GetEnvironmentVariable);
-await client.LoginUserIfNeeded();
var contacts = await client.Contacts_ImportContacts(new[] { new InputPhoneContact { phone = "+PHONENUMBER" } });
if (contacts.imported.Length > 0)
await client.SendMessageAsync(contacts.users[contacts.imported[0].user_id], "Hello!");
@@ -42,17 +41,14 @@ if (contacts.imported.Length > 0)
### Send a Markdown or HTML-formatted message to ourself (Saved Messages)
```csharp
-using var client = new WTelegram.Client(Environment.GetEnvironmentVariable);
-var user = await client.LoginUserIfNeeded();
-
// Markdown-style text:
-var text = $"Hello __dear *{Markdown.Escape(user.first_name)}*__\n" +
+var text = $"Hello __dear *{Markdown.Escape(myself.first_name)}*__\n" +
"Enjoy this `userbot` written with [WTelegramClient](https://github.com/wiz0u/WTelegramClient)";
var entities = client.MarkdownToEntities(ref text);
await client.SendMessageAsync(InputPeer.Self, text, entities: entities);
// HTML-formatted text:
-var text2 = $"Hello dear {HtmlText.Escape(user.first_name)}\n" +
+var text2 = $"Hello dear {HtmlText.Escape(myself.first_name)}\n" +
"Enjoy this userbot written with WTelegramClient";
var entities2 = client.HtmlToEntities(ref text2);
await client.SendMessageAsync(InputPeer.Self, text2, entities: entities2);
@@ -63,10 +59,6 @@ See [MarkdownV2 formatting style](https://core.telegram.org/bots/api/#markdownv2
### Fun with stickers, GIFs, dice, and animated emojies
```csharp
-using var client = new WTelegram.Client(Environment.GetEnvironmentVariable);
-var user = await client.LoginUserIfNeeded();
-var random = new Random();
-
// • List all stickerSets the user has added to his account
var allStickers = await client.Messages_GetAllStickers();
foreach (var stickerSet in allStickers.sets)
@@ -75,7 +67,7 @@ foreach (var stickerSet in allStickers.sets)
// • Send a random sticker from the user's favorites stickers
var favedStickers = await client.Messages_GetFavedStickers();
-var stickerDoc = favedStickers.stickers[random.Next(favedStickers.stickers.Length)];
+var stickerDoc = favedStickers.stickers[new Random().Next(favedStickers.stickers.Length)];
await client.SendMessageAsync(InputPeer.Self, null, new InputMediaDocument { id = stickerDoc });
// • Send a specific sticker given the stickerset shortname and emoticon
@@ -95,7 +87,7 @@ await client.SendMediaAsync(InputPeer.Self, null, inputFile);
// • Send a random dice/game-of-chance effect from the list of available "dices", see https://core.telegram.org/api/dice
var appConfig = await client.Help_GetAppConfig();
var emojies_send_dice = appConfig["emojies_send_dice"] as string[];
-var dice_emoji = emojies_send_dice[random.Next(emojies_send_dice.Length)];
+var dice_emoji = emojies_send_dice[new Random().Next(emojies_send_dice.Length)];
var diceMsg = await client.SendMessageAsync(InputPeer.Self, null, new InputMediaDice { emoticon = dice_emoji });
Console.WriteLine("Dice result:" + ((MessageMediaDice)diceMsg.media).value);
@@ -116,8 +108,6 @@ await Task.Delay(5000);
### List all chats (groups/channels) the user is in and send a message to one
```csharp
-using var client = new WTelegram.Client(Environment.GetEnvironmentVariable);
-await client.LoginUserIfNeeded();
var chats = await client.Messages_GetAllChats();
foreach (var (id, chat) in chats.chats)
if (chat.IsActive)
@@ -136,8 +126,6 @@ but the old `Chat` will be marked with flag [deactivated] and should not be used
### Schedule a message to be sent to a chat
```csharp
-using var client = new WTelegram.Client(Environment.GetEnvironmentVariable);
-await client.LoginUserIfNeeded();
var chats = await client.Messages_GetAllChats();
InputPeer peer = chats.chats[1234567890]; // the chat we want
DateTime when = DateTime.UtcNow.AddMinutes(3);
@@ -150,8 +138,6 @@ await client.SendMessageAsync(peer, "This will be posted in 3 minutes", schedule
const int ChatId = 1234567890; // the chat we want
const string Filepath = @"C:\...\photo.jpg";
-using var client = new WTelegram.Client(Environment.GetEnvironmentVariable);
-await client.LoginUserIfNeeded();
var chats = await client.Messages_GetAllChats();
InputPeer peer = chats.chats[ChatId];
var inputFile = await client.UploadFileAsync(Filepath);
@@ -182,8 +168,6 @@ await client.SendAlbumAsync(InputPeer.Self, inputMedias, "My first album");
### List all dialogs (chats/groups/channels/user chat) the user is in
```csharp
-using var client = new WTelegram.Client(Environment.GetEnvironmentVariable);
-await client.LoginUserIfNeeded();
var dialogs = await client.Messages_GetDialogs();
while (dialogs.Dialogs.Length != 0)
{
@@ -205,10 +189,8 @@ See also the `Main` method in [Examples/Program_ListenUpdates.cs](Examples/Progr
### Get all members from a chat
-For a simple Chat: (see Terminology in [ReadMe](README.md#terminology))
+For a simple Chat: *(see Terminology in [ReadMe](README.md#terminology))*
```csharp
-using var client = new WTelegram.Client(Environment.GetEnvironmentVariable);
-await client.LoginUserIfNeeded();
var chatFull = await client.Messages_GetFullChat(1234567890); // the chat we want
foreach (var (id, user) in chatFull.users)
Console.WriteLine(user);
@@ -216,8 +198,6 @@ foreach (var (id, user) in chatFull.users)
For a Channel/Group:
```csharp
-using var client = new WTelegram.Client(Environment.GetEnvironmentVariable);
-await client.LoginUserIfNeeded();
var chats = await client.Messages_GetAllChats();
var channel = (Channel)chats.chats[1234567890]; // the channel we want
for (int offset = 0; ;)
@@ -233,8 +213,6 @@ for (int offset = 0; ;)
For big Channel/Group, Telegram servers might limit the number of members you can obtain with the normal above method.
In this case, you can use this helper method, but it can take several minutes to complete:
```csharp
-using var client = new WTelegram.Client(Environment.GetEnvironmentVariable);
-await client.LoginUserIfNeeded();
var chats = await client.Messages_GetAllChats();
var channel = (Channel)chats.chats[1234567890]; // the channel we want
var participants = await client.Channels_GetAllParticipants(channel);
@@ -243,8 +221,6 @@ var participants = await client.Channels_GetAllParticipants(channel);
### Join a channel/group by @channelname
```csharp
-using var client = new WTelegram.Client(Environment.GetEnvironmentVariable);
-await client.LoginUserIfNeeded();
var resolved = await client.Contacts_ResolveUsername("channelname"); // without the @
if (resolved.Chat is Channel channel)
await client.Channels_JoinChannel(channel);
@@ -253,8 +229,6 @@ if (resolved.Chat is Channel channel)
### Add/Invite/Remove someone in a chat
```csharp
-using var client = new WTelegram.Client(Environment.GetEnvironmentVariable);
-await client.LoginUserIfNeeded();
var chats = await client.Messages_GetAllChats();
var chat = chats.chats[1234567890]; // the target chat
```
@@ -284,8 +258,6 @@ await client.DeleteChatUser(chat, user);
### Get all messages (history) from a chat
```csharp
-using var client = new WTelegram.Client(Environment.GetEnvironmentVariable);
-await client.LoginUserIfNeeded();
var chats = await client.Messages_GetAllChats();
InputPeer peer = chats.chats[1234567890]; // the chat we want
for (int offset_id = 0; ;)
@@ -303,8 +275,6 @@ for (int offset_id = 0; ;)
### Retrieve the current user's contacts list
There are two different methods. Here is the simpler one:
```csharp
-using var client = new WTelegram.Client(Environment.GetEnvironmentVariable);
-await client.LoginUserIfNeeded();
var contacts = await client.Contacts_GetContacts();
foreach (User contact in contacts.users.Values)
Console.WriteLine($"{contact} {contact.phone}");
@@ -315,8 +285,6 @@ Here is an example on how to implement it:
```csharp
using TL.Methods; // methods as structures, for Invoke* calls
-using var client = new WTelegram.Client(Environment.GetEnvironmentVariable);
-await client.LoginUserIfNeeded();
var takeout = await client.Account_InitTakeoutSession(contacts: true);
var finishTakeout = new Account_FinishTakeoutSession();
try
@@ -349,12 +317,12 @@ See the `DisplayMessage` method in [Examples/Program_ListenUpdates.cs](Examples/
You can filter specific chats the message are posted in, by looking at the `Message.peer_id` field.
-### Download media files you forward to yourself (Saved Messages)
+### Downloading photos, medias, files
This is done using the helper method `client.DownloadFileAsync(file, outputStream)`
-that simplify the download of a photo/document/file once you get a reference to its location.
+that simplify the download of a photo/document/file once you get a reference to its location *(through updates or API calls)*.
-See [Examples/Program_DownloadSavedMedia.cs](Examples/Program_DownloadSavedMedia.cs).
+See [Examples/Program_DownloadSavedMedia.cs](Examples/Program_DownloadSavedMedia.cs) that download all media files you forward to yourself (Saved Messages)
### Collect Access Hash and save them for later use
@@ -375,7 +343,7 @@ client.TcpHandler = async (address, port) =>
var proxy = new Socks5ProxyClient(ProxyHost, ProxyPort, ProxyUsername, ProxyPassword);
return proxy.CreateConnection(address, port);
};
-var user = await client.LoginUserIfNeeded();
+var myself = await client.LoginUserIfNeeded();
```
or with [xNetStandard](https://www.nuget.org/packages/xNetStandard/):
```csharp
@@ -390,11 +358,10 @@ MTProxy (MTProto proxy) can be used to prevent ISP blocks, through the `client.M
```csharp
using var client = new WTelegram.Client(Environment.GetEnvironmentVariable);
client.MTProxyUrl = "http://t.me/proxy?server=...&port=...&secret=...";
-var user = await client.LoginUserIfNeeded();
+var myself = await client.LoginUserIfNeeded();
```
*Note: WTelegramClient always uses transport obfuscation when connecting to Telegram servers, even without MTProxy*
-
### Change logging settings
By default, WTelegramClient logs are displayed on the Console screen.
@@ -430,7 +397,7 @@ await client.Account_UpdatePasswordSettings(password, new Account_PasswordInputS
flags = Account_PasswordInputSettings.Flags.has_new_algo,
new_password_hash = new_password_hash?.A,
new_algo = accountPassword.new_algo,
- hint = "new hint",
+ hint = "new password hint",
});
```
@@ -439,8 +406,6 @@ await client.Account_UpdatePasswordSettings(password, new Account_PasswordInputS
### Send a message reaction on pinned messages
This code fetches the available reactions in a given chat, and sends the first reaction emoji (usually 👍) on the last 2 pinned messages:
```csharp
-using var client = new WTelegram.Client(Environment.GetEnvironmentVariable);
-await client.LoginUserIfNeeded();
var chats = await client.Messages_GetAllChats();
var chat = chats.chats[1234567890]; // the chat we want
var full = await client.GetFullChat(chat);
diff --git a/FAQ.md b/FAQ.md
index 8e4c775..e243a33 100644
--- a/FAQ.md
+++ b/FAQ.md
@@ -1,11 +1,15 @@
## FAQ
+Before asking questions, make sure to **[read through the ReadMe first](README.md)**,
+take a look at the [example programs](EXAMPLES.md) or [StackOverflow questions](https://stackoverflow.com/questions/tagged/wtelegramclient),
+and refer to the [API method list](https://corefork.telegram.org/methods) for the full range of Telegram services available in this library.
+
#### 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, ...).
-In any case, it is not recommended to totally ignore those logs because you wouldn't be able to analyze a problem after it happens.
+In any case, it is not recommended to totally ignore those logs because you wouldn't be able to diagnose a problem after it happens.
Read the [example about logging settings](EXAMPLES.md#logging) for how to write logs to a file.
@@ -27,23 +31,24 @@ Also please note that the session files are encrypted with your api_hash (or ses
Your api_id/api_hash represents your application, and shouldn't change with each user account the application will manage.
-#### 3. How to use the library in a WinForms or WPF application
+
+#### 3. How to use the library in a WinForms, WPF or ASP.NET application
-The library should work without a problem in a GUI application.
+The library should work without a problem in such applications.
The difficulty might be in your Config callback when the user must enter the verification code or password, as you can't use `Console.ReadLine` here.
-An easy solution is to call `Interaction.InputBox("Enter verification code")` instead.
+For GUI apps, an easy solution is to call `Interaction.InputBox("Enter verification code")` instead.
This might require adding a reference *(and `using`)* to the Microsoft.VisualBasic assembly.
A more complex solution requires the use of a `ManualResetEventSlim` that you will wait for in Config callback,
-and when the user has provided the verification_code through your GUI, you "set" the event to release your Config callback so it can return the code.
-([download a full example](https://github.com/wiz0u/WTelegramClient/raw/master/Examples/WinForms_app.zip))
+and when the user has provided the verification_code through your app, you "set" the event to release your Config callback so it can return the code.
+You can download such full example apps [for WinForms](https://github.com/wiz0u/WTelegramClient/raw/master/Examples/WinForms_app.zip) and [for ASP.NET](https://github.com/wiz0u/WTelegramClient/raw/master/Examples/ASPnet_webapp.zip)
#### 4. Where to get the access_hash? Why the error `CHANNEL_INVALID` or `USER_ID_INVALID`?
An `access_hash` is required by Telegram when dealing with a channel, user, photo, document, etc...
-This serves as a proof that you are entitled to access it (otherwise, anybody with the ID could access it)
+This serves as a proof that the logged-in user is entitled to access it (otherwise, anybody with the ID could access it)
> A small private `Chat` don't need an access_hash and can be queried using their `chat_id` only.
However most common chat groups are not `Chat` but a `Channel` supergroup (without the `broadcast` flag). See [Terminology in ReadMe](README.md#terminology).
@@ -58,17 +63,18 @@ Once you obtained the description structure, there are 3 methods for building yo
you will see that they have conversion implicit operators or methods that can create the `Input...` structure for you automatically.
So you can just pass that structure you already have, in place of the `Input...` argument, it will work!
* Alternatively, you can manually create the `Input...` structure yourself by extracting the `access_hash` from the **description structure**
-* If you have enabled the [CollectAccessHash system](EXAMPLES.md#collect-access-hash) at the start of your session, it will have collected the `access_hash`.
+* If you have enabled the [CollectAccessHash system](EXAMPLES.md#collect-access-hash) at the start of your session, it will have collected the `access_hash` automatically when you obtained the description structure.
You can then retrieve it with `client.GetAccessHashFor(id)`
-⚠️ *`access_hash` obtained from a User or Channel with flag `min` may not be used for most requests. See [Min constructors](https://core.telegram.org/api/min).*
+⚠️ *An `access_hash` obtained from a User/Channel structure with flag `min` may not be used for most requests. See [Min constructors](https://core.telegram.org/api/min).*
#### 5. I need to test a feature that has been developed but not yet released in WTelegramClient nuget
The developmental versions of the library are available through Azure DevOps as part of the Continuous Integration builds after each Github commit.
-You can access these versions for testing in your program by going to our [private nuget feed](https://dev.azure.com/wiz0u/WTelegramClient/_packaging?_a=package&feed=WTelegramClient&view=overview&package=WTelegramClient&protocolType=NuGet), then click on "Connect to feed" and follow the steps.
+You can access these versions for testing in your program by going to our [private nuget feed](https://dev.azure.com/wiz0u/WTelegramClient/_packaging?_a=package&feed=WTelegramClient&view=overview&package=WTelegramClient&protocolType=NuGet),
+then click on "Connect to feed" and follow the steps to setup your dev environment.
After that, you should be able to see/install the pre-release versions in your Nuget package manager and install them in your application. *(make sure you enable the **pre-release** checkbox)*
@@ -95,7 +101,7 @@ You can get these kind of problems if you abuse Telegram [Terms of Service](http
You can try to wait more between the requests, wait for a day or two to see if the requests become possible again.
>ℹ️ For FLOOD_WAIT_X with X < 60 seconds (see `client.FloodRetryThreshold`), WTelegramClient will automatically wait the specified delay and retry the request for you.
-An account that was limited due to reported spam might receive PEER_FLOOD errors. Read [Telegram Spam FAQ](https://telegram.org/faq_spam) to learn more.
+An account that was restricted due to reported spam might receive PEER_FLOOD errors. Read [Telegram Spam FAQ](https://telegram.org/faq_spam) to learn more.
If you think your phone number was banned from Telegram for a wrong reason, you may try to contact [recover@telegram.org](mailto:recover@telegram.org), explaining what you were doing.
@@ -113,7 +119,7 @@ From the [official documentation](https://core.telegram.org/api/obtaining_api_id
> Due to excessive abuse of the Telegram API, **all accounts that sign up or log in using unofficial Telegram clients are automatically
> put under observation** to avoid violations of the [Terms of Service](https://core.telegram.org/api/terms).
-Here are some key points:
+Here are some advices from [another similar library](https://github.com/gotd/td/blob/main/.github/SUPPORT.md#how-to-not-get-banned):
1. This client is unofficial, Telegram treats such clients suspiciously, especially fresh ones.
2. Use regular bots instead of userbots whenever possible.
@@ -125,8 +131,6 @@ Here are some key points:
* Do not abuse, spam or use it for other suspicious activities.
* Implement a rate limiting system.
-*(the above section is derived from [gotd SUPPORT.md](https://github.com/gotd/td/blob/main/.github/SUPPORT.md))*
-
If your client displays Telegram channels to the user, you have to support and display [official sponsored messages](https://core.telegram.org/api/sponsored-messages).
@@ -196,11 +200,11 @@ So you can either:
- Build your code in RELEASE mode
- Modify your config callback to reply to "server_address" with the IP address of Telegram production servers (as found on your API development tools)
-2) After `ConnectAsync()`, are you calling `LoginUserIfNeeded()`?
+2) Did you call `LoginUserIfNeeded()`?
If you don't authenticate as a user (or bot), you have access to a very limited subset of Telegram APIs
3) Did you use `await` with every Client methods?
-This library is completely Task-based and you should learn, understand and use the [asynchronous model of C# programming](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/) before proceeding further.
+This library is completely Task-based. You should learn, understand and use the [asynchronous model of C# programming](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/) before proceeding further.
4) Is your program ending immediately instead of waiting for Updates?
Your program must be running/waiting continuously in order for the background Task to receive and process the Updates. So make sure your main program doesn't end immediately. For a console program, this is typical done by waiting for a key or some close event.
diff --git a/README.md b/README.md
index ec23ab2..87bdc35 100644
--- a/README.md
+++ b/README.md
@@ -19,8 +19,8 @@ After installing WTelegramClient through Nuget, your first Console program will
static async Task Main(string[] _)
{
using var client = new WTelegram.Client();
- var user = await client.LoginUserIfNeeded();
- Console.WriteLine($"We are logged-in as {user.username ?? user.first_name + " " + user.last_name} (id {user.id})");
+ var my = await client.LoginUserIfNeeded();
+ Console.WriteLine($"We are logged-in as {my.username ?? my.first_name + " " + my.last_name} (id {my.id})");
}
```
When run, this will prompt you interactively for your App **api_hash** and **api_id** (that you obtain through Telegram's [API development tools](https://my.telegram.org/apps) page) and try to connect to Telegram servers.
diff --git a/src/Client.cs b/src/Client.cs
index 7a7476a..7750bc7 100644
--- a/src/Client.cs
+++ b/src/Client.cs
@@ -445,12 +445,15 @@ namespace WTelegram
int ping_id = _random.Next();
while (!ct.IsCancellationRequested)
{
- await Task.Delay(PingInterval * 1000, ct);
+ await Task.Delay(Math.Abs(PingInterval) * 1000, ct);
if (_saltChangeCounter > 0) --_saltChangeCounter;
+ if (PingInterval <= 0)
+ await this.Ping(ping_id++);
+ else // see https://core.telegram.org/api/optimisation#grouping-updates
#if DEBUG
- await this.PingDelayDisconnect(ping_id++, PingInterval * 5);
+ await this.PingDelayDisconnect(ping_id++, PingInterval * 5);
#else
- await this.PingDelayDisconnect(ping_id++, PingInterval * 5 / 4);
+ await this.PingDelayDisconnect(ping_id++, PingInterval * 5 / 4);
#endif
}
}