Improved GetMessageByLink (topics, cache)

This commit is contained in:
Wizou 2024-02-25 03:09:49 +01:00
parent b9aad47c8e
commit 33f239fc8e
6 changed files with 36 additions and 20 deletions

View file

@ -238,6 +238,7 @@ var inputMedias = new List<InputMedia>
photoFromTelegram, // PhotoBase has implicit conversion to InputMediaPhoto photoFromTelegram, // PhotoBase has implicit conversion to InputMediaPhoto
new InputMediaUploadedPhoto { file = uploadedFile }, new InputMediaUploadedPhoto { file = uploadedFile },
new InputMediaPhotoExternal { url = photoUrl }, new InputMediaPhotoExternal { url = photoUrl },
//or Document, InputMediaDocument, InputMediaUploadedDocument, InputMediaDocumentExternal...
}; };
await client.SendAlbumAsync(InputPeer.Self, inputMedias, "My first album"); await client.SendAlbumAsync(InputPeer.Self, inputMedias, "My first album");
``` ```

View file

@ -769,7 +769,7 @@ namespace WTelegram
} }
/// <summary>Return chat and message details based on a Message Link (URL)</summary> /// <summary>Return chat and message details based on a Message Link (URL)</summary>
/// <param name="url">Message Link, like https://t.me/c/1234567890/1234 or https://t.me/channelname/1234</param> /// <param name="url">Message Link, like https://t.me/c/1234567890/1234 or t.me/channelname/1234</param>
/// <param name="chats">previously collected chats, to prevent unnecessary ResolveUsername</param> /// <param name="chats">previously collected chats, to prevent unnecessary ResolveUsername</param>
/// <returns>Structure containing the message, chat and user details</returns> /// <returns>Structure containing the message, chat and user details</returns>
/// <remarks>If link is for private group (<c>t.me/c/..</c>), user must have joined that group</remarks> /// <remarks>If link is for private group (<c>t.me/c/..</c>), user must have joined that group</remarks>
@ -778,17 +778,28 @@ namespace WTelegram
int start = url.IndexOf("//"); int start = url.IndexOf("//");
start = url.IndexOf('/', start + 2) + 1; start = url.IndexOf('/', start + 2) + 1;
int slash = url.IndexOf('/', start + 2); int slash = url.IndexOf('/', start + 2);
if (start == 0 || slash == -1) throw new ArgumentException("Invalid URL"); int msgStart = slash + 1;
int end = url.IndexOfAny(UrlSeparator, slash + 1); int end = url.IndexOfAny(UrlSeparator, msgStart);
if (end == -1) end = url.Length; if (end == -1) end = url.Length;
int msgId = int.Parse(url[(slash + 1)..end]); else if (url[end] == '/' && char.IsDigit(url[msgStart]) && url.Length > end + 1 && char.IsDigit(url[end + 1]))
{
end = url.IndexOfAny(UrlSeparator, msgStart = end + 1);
if (end == -1) end = url.Length;
}
if (start == 0 || slash == -1 || end <= slash + 1 || !char.IsDigit(url[msgStart])) throw new ArgumentException("Invalid URL");
int msgId = int.Parse(url[msgStart..end]);
ChatBase chat; ChatBase chat;
if (url[start] is 'c' or 'C' && url[start + 1] == '/') if (url[start] is 'c' or 'C' && url[start + 1] == '/')
{ {
long chatId = long.Parse(url[(start + 2)..slash]); long chatId = long.Parse(url[(start + 2)..slash]);
var mc = await this.Channels_GetChannels(new InputChannel(chatId, 0)); if (chats?.TryGetValue(chatId, out chat) != true)
if (!mc.chats.TryGetValue(chatId, out chat)) {
throw new WTException($"Channel {chatId} not found"); var mc = await this.Channels_GetChannels(new InputChannel(chatId, 0));
if (!mc.chats.TryGetValue(chatId, out chat))
throw new WTException($"Channel {chatId} not found");
else if (chats != null)
chats[chatId] = chat;
}
} }
else else
chat = await CachedOrResolveUsername(url[start..slash], chats); chat = await CachedOrResolveUsername(url[start..slash], chats);

View file

@ -522,7 +522,7 @@ namespace WTelegram
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
var msg = array[i] = new _Message(reader.ReadInt64(), reader.ReadInt32(), null) { bytes = reader.ReadInt32() }; var msg = array[i] = new _Message(reader.ReadInt64(), reader.ReadInt32(), null) { bytes = reader.ReadInt32() };
if ((msg.seqno & 1) != 0) lock (_msgsToAck) _msgsToAck.Add(msg.msg_id); if ((msg.seq_no & 1) != 0) lock (_msgsToAck) _msgsToAck.Add(msg.msg_id);
var pos = reader.BaseStream.Position; var pos = reader.BaseStream.Position;
try try
{ {
@ -535,7 +535,7 @@ namespace WTelegram
else else
{ {
var obj = msg.body = reader.ReadTLObject(ctorNb); var obj = msg.body = reader.ReadTLObject(ctorNb);
Helpers.Log(1, $" → {obj.GetType().Name,-38} {MsgIdToStamp(msg.msg_id):u} {((msg.seqno & 1) != 0 ? "" : "(svc)")} {((msg.msg_id & 2) == 0 ? "" : "NAR")}"); Helpers.Log(1, $" → {obj.GetType().Name,-38} {MsgIdToStamp(msg.msg_id):u} {((msg.seq_no & 1) != 0 ? "" : "(svc)")} {((msg.msg_id & 2) == 0 ? "" : "NAR")}");
} }
} }
catch (Exception ex) catch (Exception ex)

View file

@ -7,7 +7,7 @@ using System.Net;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text.Json; using System.Text.Json;
//( Don't change this code to lower the security. That's contrary to Telegram recommended practices. Read the official API documentation. // Don't change this code to lower the security. It's following Telegram security recommendations https://corefork.telegram.org/mtproto/description
namespace WTelegram namespace WTelegram
{ {
@ -81,7 +81,7 @@ namespace WTelegram
public DateTime SessionStart => _sessionStart; public DateTime SessionStart => _sessionStart;
private readonly DateTime _sessionStart = DateTime.UtcNow; private readonly DateTime _sessionStart = DateTime.UtcNow;
private readonly SHA256 _sha256 = SHA256.Create(); // put private readonly SHA256 _sha256 = SHA256.Create();
private Stream _store; private Stream _store;
private byte[] _reuseKey; // used only if AES Encryptor.CanReuseTransform = false (Mono) private byte[] _reuseKey; // used only if AES Encryptor.CanReuseTransform = false (Mono)
private byte[] _encrypted = new byte[16]; private byte[] _encrypted = new byte[16];
@ -95,7 +95,7 @@ namespace WTelegram
_store.Dispose(); _store.Dispose();
_encryptor.Dispose(); _encryptor.Dispose();
_jsonWriter.Dispose(); _jsonWriter.Dispose();
_jsonStream.Dispose(); // this _jsonStream.Dispose();
} }
internal static Session LoadOrCreate(Stream store, byte[] rgbKey) internal static Session LoadOrCreate(Stream store, byte[] rgbKey)
@ -107,7 +107,7 @@ namespace WTelegram
var length = (int)store.Length; var length = (int)store.Length;
if (length > 0) if (length > 0)
{ {
var input = new byte[length]; // code var input = new byte[length];
if (store.Read(input, 0, length) != length) if (store.Read(input, 0, length) != length)
throw new WTException($"Can't read session block ({store.Position}, {length})"); throw new WTException($"Can't read session block ({store.Position}, {length})");
using var sha256 = SHA256.Create(); using var sha256 = SHA256.Create();
@ -141,7 +141,7 @@ namespace WTelegram
int encryptedLen = 64 + (utf8JsonLen & ~15); int encryptedLen = 64 + (utf8JsonLen & ~15);
lock (_store) // while updating _encrypted buffer and writing to store lock (_store) // while updating _encrypted buffer and writing to store
{ {
if (encryptedLen > _encrypted.Length) // back if (encryptedLen > _encrypted.Length)
Array.Copy(_encrypted, _encrypted = new byte[encryptedLen + 256], 16); Array.Copy(_encrypted, _encrypted = new byte[encryptedLen + 256], 16);
_encryptor.TransformBlock(_sha256.ComputeHash(utf8Json, 0, utf8JsonLen), 0, 32, _encrypted, 16); _encryptor.TransformBlock(_sha256.ComputeHash(utf8Json, 0, utf8JsonLen), 0, 32, _encrypted, 16);
_encryptor.TransformBlock(utf8Json, 0, encryptedLen - 64, _encrypted, 48); _encryptor.TransformBlock(utf8Json, 0, encryptedLen - 64, _encrypted, 48);
@ -192,7 +192,6 @@ namespace WTelegram
} }
} }
// QWxp couldn't be bothered to write such a simple SessionStore, so here it is:
internal class ActionStore : MemoryStream internal class ActionStore : MemoryStream
{ {
private readonly Action<byte[]> _save; private readonly Action<byte[]> _save;

View file

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -39,9 +40,13 @@ namespace TL
public static void CollectUsersChats(this IPeerResolver structure, IDictionary<long, User> users, IDictionary<long, ChatBase> chats) public static void CollectUsersChats(this IPeerResolver structure, IDictionary<long, User> users, IDictionary<long, ChatBase> chats)
=> structure.UserOrChat(new CollectorPeer { _users = users, _chats = chats }); => structure.UserOrChat(new CollectorPeer { _users = users, _chats = chats });
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task<Messages_Chats> Messages_GetChats(this Client _) => throw new WTException("The method you're looking for is Messages_GetAllChats"); public static Task<Messages_Chats> Messages_GetChats(this Client _) => throw new WTException("The method you're looking for is Messages_GetAllChats");
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task<Messages_Chats> Channels_GetChannels(this Client _) => throw new WTException("The method you're looking for is Messages_GetAllChats"); public static Task<Messages_Chats> Channels_GetChannels(this Client _) => throw new WTException("The method you're looking for is Messages_GetAllChats");
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task<UserBase[]> Users_GetUsers(this Client _) => throw new WTException("The method you're looking for is Messages_GetAllDialogs"); public static Task<UserBase[]> Users_GetUsers(this Client _) => throw new WTException("The method you're looking for is Messages_GetAllDialogs");
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task<Messages_MessagesBase> Messages_GetMessages(this Client _) => throw new WTException("If you want to get all messages from a chat, use method Messages_GetHistory"); public static Task<Messages_MessagesBase> Messages_GetMessages(this Client _) => throw new WTException("If you want to get all messages from a chat, use method Messages_GetHistory");
} }

View file

@ -198,10 +198,10 @@ namespace TL
foreach (var msg in messages) foreach (var msg in messages)
{ {
writer.Write(msg.msg_id); writer.Write(msg.msg_id);
writer.Write(msg.seqno); writer.Write(msg.seq_no);
var patchPos = writer.BaseStream.Position; var patchPos = writer.BaseStream.Position;
writer.Write(0); // patched below writer.Write(0); // patched below
if ((msg.seqno & 1) != 0) if ((msg.seq_no & 1) != 0)
WTelegram.Helpers.Log(1, $" → {msg.body.GetType().Name.TrimEnd('_'),-38} #{(short)msg.msg_id.GetHashCode():X4}"); WTelegram.Helpers.Log(1, $" → {msg.body.GetType().Name.TrimEnd('_'),-38} #{(short)msg.msg_id.GetHashCode():X4}");
else else
WTelegram.Helpers.Log(1, $" → {msg.body.GetType().Name.TrimEnd('_'),-38}"); WTelegram.Helpers.Log(1, $" → {msg.body.GetType().Name.TrimEnd('_'),-38}");
@ -372,11 +372,11 @@ namespace TL
} }
[TLDef(0x5BB8E511)] //message#5bb8e511 msg_id:long seqno:int bytes:int body:Object = Message [TLDef(0x5BB8E511)] //message#5bb8e511 msg_id:long seqno:int bytes:int body:Object = Message
public class _Message public class _Message : IObject
{ {
public _Message(long msgId, int seqNo, IObject obj) { msg_id = msgId; seqno = seqNo; body = obj; } public _Message(long msgId, int seqNo, IObject obj) { msg_id = msgId; seq_no = seqNo; body = obj; }
public long msg_id; public long msg_id;
public int seqno; public int seq_no;
public int bytes; public int bytes;
public IObject body; public IObject body;
} }