mirror of
https://github.com/wiz0u/WTelegramClient.git
synced 2025-12-06 06:52:01 +01:00
deprecate the experimental CollectAccessHash system
This commit is contained in:
parent
8f10df8849
commit
66d8b75463
38
EXAMPLES.md
38
EXAMPLES.md
|
|
@ -76,7 +76,7 @@ var sent2 = await client.SendMessageAsync(InputPeer.Self, text2, entities: entit
|
|||
text2 = client.EntitiesToMarkdown(sent2.message, sent2.entities);
|
||||
```
|
||||
See [HTML formatting style](https://core.telegram.org/bots/api/#html-style) and [MarkdownV2 formatting style](https://core.telegram.org/bots/api/#markdownv2-style) for details.
|
||||
*Note: For the `tg://user?id=` notation to work, that user's access hash must have been collected first ([see below](#collect-access-hash))*
|
||||
*Note: For the `tg://user?id=` notation to work, you need to pass the _users dictionary in arguments ([see below](#collect-users-chats))*
|
||||
|
||||
<a name="list-dialogs"></a>
|
||||
## List all dialogs (chats/groups/channels/user chat) we are currently in
|
||||
|
|
@ -442,13 +442,39 @@ finally
|
|||
```
|
||||
|
||||
<a name="collect-access-hash"></a>
|
||||
## Collect Access Hash and save them for later use
|
||||
<a name="collect-users-chats"></a>
|
||||
<a name="user-or-chat"></a>
|
||||
## Collect Users/Chats description structures and access hash
|
||||
|
||||
You can automate the collection of `access_hash` for the various resources obtained in response to API calls or Updates,
|
||||
so that you don't have to remember them by yourself or ask the API about them each time.
|
||||
Many API calls return a structure with a `users` and a `chats` field at the root of the structure.
|
||||
This is also the case for updates passed to `client.OnUpdate`.
|
||||
|
||||
This is done by activating the experimental `client.CollectAccessHash` system.
|
||||
See [Examples/Program_CollectAccessHash.cs](https://github.com/wiz0u/WTelegramClient/blob/master/Examples/Program_CollectAccessHash.cs?ts=4#L22) for how to enable it, and save/restore them for later use.
|
||||
These two dictionaries give details about the various users/chats that will be typically referenced in subobjects deeper in the structure,
|
||||
typically in the form of a `Peer` object or a `user_id` field.
|
||||
|
||||
In such case, the root structure inherits the `IPeerResolver` interface, and you can use the `UserOrChat(peer)` method to resolve a `Peer`
|
||||
into either a `User` or `ChatBase` (`Chat`,`Channel`...) description structure *(depending what kind of peer it was describing)*
|
||||
|
||||
You can also use the `CollectUsersChats` helper method to collect these 2 fields into 2 aggregate dictionaries to remember details
|
||||
*(including access hashes)* about all the users/chats you've encountered so far.
|
||||
|
||||
Example of usage for `CollectUsersChats`:
|
||||
```csharp
|
||||
static Dictionary<long, User> _users = new();
|
||||
static Dictionary<long, ChatBase> _chats = new();
|
||||
...
|
||||
var dialogs = await client.Messages_GetAllDialogs();
|
||||
dialogs.CollectUsersChats(_users, _chats);
|
||||
...
|
||||
private static async Task OnUpdate(IObject arg)
|
||||
{
|
||||
if (arg is not UpdatesBase updates) return;
|
||||
updates.CollectUsersChats(_users, _chats);
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
*Note: If you need to save/restore those dictionaries between runs of your program, it's up to you to serialize their content to disk*
|
||||
|
||||
<a name="proxy"></a>
|
||||
## Use a proxy or MTProxy to connect to Telegram
|
||||
|
|
|
|||
|
|
@ -1,82 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using TL;
|
||||
|
||||
namespace WTelegramClientTest
|
||||
{
|
||||
static class Program_CollectAccessHash
|
||||
{
|
||||
private const string StateFilename = "SavedState.json";
|
||||
private const long DurovID = 1006503122; // known ID for Durov's Channel
|
||||
private static SavedState savedState = new();
|
||||
|
||||
// go to Project Properties > Debug > Environment variables and add at least these: api_id, api_hash, phone_number
|
||||
static async Task Main(string[] _)
|
||||
{
|
||||
Console.WriteLine("The program demonstrate how to load/save/use collected access hash.");
|
||||
WTelegram.Helpers.Log = (l, s) => System.Diagnostics.Debug.WriteLine(s);
|
||||
using var client = new WTelegram.Client(Environment.GetEnvironmentVariable);
|
||||
client.CollectAccessHash = true;
|
||||
|
||||
if (File.Exists(StateFilename))
|
||||
{
|
||||
Console.WriteLine("Loading previously saved access hashes from disk...");
|
||||
using (var stateStream = File.OpenRead(StateFilename))
|
||||
savedState = await JsonSerializer.DeserializeAsync<SavedState>(stateStream);
|
||||
foreach (var id_hash in savedState.Channels) client.SetAccessHashFor<Channel>(id_hash.Key, id_hash.Value);
|
||||
foreach (var id_hash in savedState.Users) client.SetAccessHashFor<User>(id_hash.Key, id_hash.Value);
|
||||
}
|
||||
|
||||
Console.WriteLine("Connecting to Telegram...");
|
||||
await client.LoginUserIfNeeded();
|
||||
|
||||
var durovAccessHash = client.GetAccessHashFor<Channel>(DurovID);
|
||||
if (durovAccessHash != 0)
|
||||
{
|
||||
// we already know the access hash for Durov's Channel, so we can directly use it
|
||||
Console.WriteLine($"Channel @durov has ID {DurovID} and access hash was already collected: {durovAccessHash:X}");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Zero means the access hash for Durov's Channel was not collected yet.
|
||||
// So we need to obtain it through Client API calls whose results contains the access_hash field, such as:
|
||||
// - Messages_GetAllChats (see Program_GetAllChats.cs for an example on how to use it)
|
||||
// - Messages_GetAllDialogs (see Program_ListenUpdates.cs for an example on how to use it)
|
||||
// - Contacts_ResolveUsername (see below for an example on how to use it)
|
||||
// and many more API methods...
|
||||
// The access_hash fields can be found inside instance of User, Channel, Photo, Document, etc..
|
||||
// usually listed through their base class UserBase, ChatBase, PhotoBase, DocumentBase, etc...
|
||||
Console.WriteLine("Resolving channel @durov to get its ID, access hash and other infos...");
|
||||
var durovResolved = await client.Contacts_ResolveUsername("durov"); // @durov = Durov's Channel
|
||||
if (durovResolved.peer.ID != DurovID)
|
||||
throw new Exception("@durov has changed channel ID ?!");
|
||||
durovAccessHash = client.GetAccessHashFor<Channel>(DurovID); // should have been collected from the previous API result
|
||||
if (durovAccessHash == 0)
|
||||
throw new Exception("No access hash was automatically collected !? (shouldn't happen)");
|
||||
Console.WriteLine($"Channel @durov has ID {DurovID} and access hash was automatically collected: {durovAccessHash:X}");
|
||||
}
|
||||
|
||||
Console.WriteLine("With the access hash, we can now join the channel for example.");
|
||||
await client.Channels_JoinChannel(new InputChannel(DurovID, durovAccessHash));
|
||||
|
||||
Console.WriteLine("Channel joined. Press any key to save and exit");
|
||||
Console.ReadKey(true);
|
||||
|
||||
Console.WriteLine("Saving all collected access hashes to disk for next run...");
|
||||
savedState.Channels = client.AllAccessHashesFor<Channel>().ToList();
|
||||
savedState.Users = client.AllAccessHashesFor<User>().ToList();
|
||||
using (var stateStream = File.Create(StateFilename))
|
||||
await JsonSerializer.SerializeAsync(stateStream, savedState);
|
||||
}
|
||||
|
||||
class SavedState
|
||||
{
|
||||
public List<KeyValuePair<long, long>> Channels { get; set; } = new();
|
||||
public List<KeyValuePair<long, long>> Users { get; set; } = new();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -16,7 +16,9 @@ namespace WTelegram
|
|||
partial class Client
|
||||
{
|
||||
#region Collect Access Hash system
|
||||
/// <summary>Enable the collection of id/access_hash pairs (experimental)<br/>See <see href="https://github.com/wiz0u/WTelegramClient/blob/master/FAQ.md#access-hash"/></summary>
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
/// <summary>Enable the collection of id/access_hash pairs (deprecated)</summary>
|
||||
[Obsolete("This system will be removed in a future version. You should use CollectUsersChats helper on API results or updates instead. See https://wiz0u.github.io/WTelegramClient/EXAMPLES#collect-users-chats")]
|
||||
public bool CollectAccessHash { get; set; }
|
||||
public IEnumerable<KeyValuePair<long, long>> AllAccessHashesFor<T>() where T : IObject => _accessHashes.GetValueOrDefault(typeof(T));
|
||||
private readonly Dictionary<Type, Dictionary<long, long>> _accessHashes = new();
|
||||
|
|
@ -53,6 +55,7 @@ namespace WTelegram
|
|||
lock (_accessHashes)
|
||||
_accessHashes.GetOrCreate(type)[id] = accessHash;
|
||||
}
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
#endregion
|
||||
|
||||
#region Client TL Helpers
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ using System.Linq;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using WTelegram; // for GetValueOrDefault
|
||||
|
||||
namespace TL
|
||||
{
|
||||
|
|
@ -48,8 +49,9 @@ namespace TL
|
|||
/// <param name="client">Client, used for getting access_hash for <c>tg://user?id=</c> URLs</param>
|
||||
/// <param name="text">[in] The Markdown text<br/>[out] The same (plain) text, stripped of all Markdown notation</param>
|
||||
/// <param name="premium">Generate premium entities if any</param>
|
||||
/// <param name="users">Dictionary used for <c>tg://user?id=</c> notation</param>
|
||||
/// <returns>The array of formatting entities that you can pass (along with the plain text) to <see cref="WTelegram.Client.SendMessageAsync">SendMessageAsync</see> or <see cref="WTelegram.Client.SendMediaAsync">SendMediaAsync</see></returns>
|
||||
public static MessageEntity[] MarkdownToEntities(this WTelegram.Client client, ref string text, bool premium = false)
|
||||
public static MessageEntity[] MarkdownToEntities(this WTelegram.Client client, ref string text, bool premium = false, Dictionary<long, User> users = null)
|
||||
{
|
||||
var entities = new List<MessageEntity>();
|
||||
var sb = new StringBuilder(text);
|
||||
|
|
@ -119,7 +121,7 @@ namespace TL
|
|||
else if (c == ')') break;
|
||||
}
|
||||
textUrl.url = sb.ToString(offset + 2, offset2 - offset - 3);
|
||||
if (textUrl.url.StartsWith("tg://user?id=") && long.TryParse(textUrl.url[13..], out var id) && client.GetAccessHashFor<User>(id) is long hash)
|
||||
if (textUrl.url.StartsWith("tg://user?id=") && long.TryParse(textUrl.url[13..], out var id) && (users?.GetValueOrDefault(id)?.access_hash ?? client.GetAccessHashFor<User>(id)) is long hash)
|
||||
entities[lastIndex] = new InputMessageEntityMentionName { offset = textUrl.offset, length = textUrl.length, user_id = new InputUser(id, hash) };
|
||||
else if ((textUrl.url.StartsWith("tg://emoji?id=") || textUrl.url.StartsWith("emoji?id=")) && long.TryParse(textUrl.url[(textUrl.url.IndexOf('=') + 1)..], out id))
|
||||
if (premium) entities[lastIndex] = new MessageEntityCustomEmoji { offset = textUrl.offset, length = textUrl.length, document_id = id };
|
||||
|
|
@ -247,8 +249,9 @@ namespace TL
|
|||
/// <param name="client">Client, used for getting access_hash for <c>tg://user?id=</c> URLs</param>
|
||||
/// <param name="text">[in] The HTML-formatted text<br/>[out] The same (plain) text, stripped of all HTML tags</param>
|
||||
/// <param name="premium">Generate premium entities if any</param>
|
||||
/// <param name="users">Dictionary used for <c>tg://user?id=</c> notation</param>
|
||||
/// <returns>The array of formatting entities that you can pass (along with the plain text) to <see cref="WTelegram.Client.SendMessageAsync">SendMessageAsync</see> or <see cref="WTelegram.Client.SendMediaAsync">SendMediaAsync</see></returns>
|
||||
public static MessageEntity[] HtmlToEntities(this WTelegram.Client client, ref string text, bool premium = false)
|
||||
public static MessageEntity[] HtmlToEntities(this WTelegram.Client client, ref string text, bool premium = false, Dictionary<long, User> users = null)
|
||||
{
|
||||
var entities = new List<MessageEntity>();
|
||||
var sb = new StringBuilder(text);
|
||||
|
|
@ -303,7 +306,7 @@ namespace TL
|
|||
else if (tag.StartsWith("a href=\"") && tag.EndsWith("\""))
|
||||
{
|
||||
tag = tag[8..^1];
|
||||
if (tag.StartsWith("tg://user?id=") && long.TryParse(tag[13..], out var user_id) && client.GetAccessHashFor<User>(user_id) is long hash)
|
||||
if (tag.StartsWith("tg://user?id=") && long.TryParse(tag[13..], out var user_id) && (users?.GetValueOrDefault(user_id)?.access_hash ?? client.GetAccessHashFor<User>(user_id)) is long hash)
|
||||
entities.Add(new InputMessageEntityMentionName { offset = offset, length = -1, user_id = new InputUser(user_id, hash) });
|
||||
else
|
||||
entities.Add(new MessageEntityTextUrl { offset = offset, length = -1, url = tag });
|
||||
|
|
|
|||
|
|
@ -95,7 +95,9 @@ namespace TL
|
|||
if (field.FieldType.IsEnum)
|
||||
if (field.Name == "flags") flags = (uint)value;
|
||||
else if (field.Name == "flags2") flags |= (ulong)(uint)value << 32;
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
if (reader.Client?.CollectAccessHash == true) reader.Client.CollectField(field, obj, value);
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
}
|
||||
return (IObject)obj;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue