CollectUsersChats helper for your dictionaries (min-aware). CollectAccessHash won't collect 'min' access_hash.

This commit is contained in:
Wizou 2022-02-14 02:02:13 +01:00
parent 0667d36ed8
commit 4e07c03a0b
5 changed files with 42 additions and 5 deletions

View file

@ -29,8 +29,7 @@ namespace WTelegramClientTest
if (dialogsBase is Messages_Dialogs dialogs) if (dialogsBase is Messages_Dialogs dialogs)
while (dialogs.dialogs.Length != 0) while (dialogs.dialogs.Length != 0)
{ {
foreach (var (id, user) in dialogs.users) _users[id] = user; dialogs.CollectUsersChats(_users, _chats);
foreach (var (id, chat) in dialogs.chats) _chats[id] = chat;
var lastDialog = dialogs.dialogs[^1]; var lastDialog = dialogs.dialogs[^1];
var lastMsg = dialogs.messages.LastOrDefault(m => m.Peer.ID == lastDialog.Peer.ID && m.ID == lastDialog.TopMessage); var lastMsg = dialogs.messages.LastOrDefault(m => m.Peer.ID == lastDialog.Peer.ID && m.ID == lastDialog.TopMessage);
var offsetPeer = dialogs.UserOrChat(lastDialog).ToInputPeer(); var offsetPeer = dialogs.UserOrChat(lastDialog).ToInputPeer();
@ -50,8 +49,7 @@ namespace WTelegramClientTest
private static void Client_Update(IObject arg) private static void Client_Update(IObject arg)
{ {
if (arg is not UpdatesBase updates) return; if (arg is not UpdatesBase updates) return;
foreach (var (id, user) in updates.Users) _users[id] = user; updates.CollectUsersChats(_users, _chats);
foreach (var (id, chat) in updates.Chats) _chats[id] = chat;
foreach (var update in updates.UpdateList) foreach (var update in updates.UpdateList)
switch (update) switch (update)
{ {

2
FAQ.md
View file

@ -61,6 +61,8 @@ So you can just pass that structure you already have, in place of the `Input...`
* 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`.
You can then retrieve it with `client.GetAccessHashFor<User/Channel/Photo/Document>(id)` You can then retrieve it with `client.GetAccessHashFor<User/Channel/Photo/Document>(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).*
<a name="dev-versions"></a> <a name="dev-versions"></a>
#### 5. I need to test a feature that has been developed but not yet released in WTelegramClient nuget #### 5. I need to test a feature that has been developed but not yet released in WTelegramClient nuget

View file

@ -1175,11 +1175,16 @@ namespace WTelegram
lock (_accessHashes) lock (_accessHashes)
_accessHashes.GetOrCreate(typeof(T))[id] = access_hash; _accessHashes.GetOrCreate(typeof(T))[id] = access_hash;
} }
static readonly FieldInfo userFlagsField = typeof(User).GetField("flags");
static readonly FieldInfo channelFlagsField = typeof(Channel).GetField("flags");
internal void CollectField(FieldInfo fieldInfo, object obj, object access_hash) internal void CollectField(FieldInfo fieldInfo, object obj, object access_hash)
{ {
if (fieldInfo.Name != "access_hash") return; if (fieldInfo.Name != "access_hash") return;
if (access_hash is not long accessHash) return; if (access_hash is not long accessHash) return;
var type = fieldInfo.ReflectedType; var type = fieldInfo.ReflectedType;
if ((type == typeof(User) && ((User.Flags)userFlagsField.GetValue(obj)).HasFlag(User.Flags.min)) ||
(type == typeof(Channel) && ((Channel.Flags)channelFlagsField.GetValue(obj)).HasFlag(Channel.Flags.min)))
return; // access_hash from Min constructors are mostly useless. see https://core.telegram.org/api/min
if (type.GetField("id") is not FieldInfo idField) return; if (type.GetField("id") is not FieldInfo idField) return;
if (idField.GetValue(obj) is not long id) if (idField.GetValue(obj) is not long id)
if (idField.GetValue(obj) is not int idInt) return; if (idField.GetValue(obj) is not int idInt) return;

View file

@ -518,6 +518,38 @@ namespace TL
} }
} }
public static class Helpers
{
private class CollectorPeer : Peer
{
public override long ID => 0;
internal Dictionary<long, User> _users;
internal Dictionary<long, ChatBase> _chats;
internal override IPeerInfo UserOrChat(Dictionary<long, User> users, Dictionary<long, ChatBase> chats)
{
lock (_users)
foreach (var user in users.Values)
if (user != null)
if (!user.flags.HasFlag(User.Flags.min) || !_users.TryGetValue(user.id, out var prevUser) || prevUser.flags.HasFlag(User.Flags.min))
_users[user.id] = user;
lock (_chats)
foreach (var kvp in chats)
if (kvp.Value is not Channel channel)
_chats[kvp.Key] = kvp.Value;
else if (!channel.flags.HasFlag(Channel.Flags.min) || !_chats.TryGetValue(channel.id, out var prevChat) || prevChat is not Channel prevChannel || prevChannel.flags.HasFlag(Channel.Flags.min))
_chats[kvp.Key] = channel;
return null;
}
}
/// <summary>Accumulate users/chats found in this structure in your dictionaries, ignoring <see href="https://core.telegram.org/api/min">Min constructors</see> when the full object is already stored</summary>
/// <param name="structure">The structure having a <c>users</c></param>
/// <param name="users"></param>
/// <param name="chats"></param>
public static void CollectUsersChats(this IPeerResolver structure, Dictionary<long, User> users, Dictionary<long, ChatBase> chats)
=> structure.UserOrChat(new CollectorPeer { _users = users, _chats = chats });
}
public static class Markdown public static class Markdown
{ {
/// <summary>Converts a <a href="https://core.telegram.org/bots/api/#markdownv2-style">Markdown text</a> into the (Entities + plain text) format used by Telegram messages</summary> /// <summary>Converts a <a href="https://core.telegram.org/bots/api/#markdownv2-style">Markdown text</a> into the (Entities + plain text) format used by Telegram messages</summary>

View file

@ -13,7 +13,7 @@ namespace TL
public interface IMethod<ReturnType> : IObject { } public interface IMethod<ReturnType> : IObject { }
public interface IPeerResolver { IPeerInfo UserOrChat(Peer peer); } public interface IPeerResolver { IPeerInfo UserOrChat(Peer peer); }
public static class Serialization internal static class Serialization
{ {
internal static void WriteTLObject<T>(this BinaryWriter writer, T obj) where T : IObject internal static void WriteTLObject<T>(this BinaryWriter writer, T obj) where T : IObject
{ {