resolvePeer doesn't work for private channels #76

Closed
opened 2024-11-09 18:24:44 +03:00 by maxim-lobanov · 1 comment
maxim-lobanov commented 2024-11-09 18:24:44 +03:00 (Migrated from github.com)

I have faced with problem that GetMessageByLink (and probably some other methods) fail for private channels.
When I call this method for message in private channel, method fails with error:

peer <peerId> is not found in local cache

Looks like resolvePeer method doesn't work well for private channels. See my investigation below.

To Reproduce

Call client.GetMessageByLink("https://t.me/c/1339581220/20441")

Expected behavior

GetMessageByLink should resolve message correctly.

Environment

Issue doesn't depend on exact environment. It is reproduced with latest version of mtcute.

Investigation and potential root cause

All mtcute methods call resolvePeer method under hood.
resolvePeer method searches for peer in cache. If peer is not found in cache, resolvePeer tries to resolve peer using Telegram API.
It calls two different API methods based on peer id format:

Public telegram channels have links like https://t.me/science/3774 where science is channel name. resolvePeer works fine because contacts.resolveUsername works for public channels.
Private telegram channels have links like https://t.me/c/1339581220/20441 where 1339581220 is channel Id. resolvePeer fails to resolve channel by Id and fails.

I think resolvePeer should be improved with additional case for private telegram channels. In case if peer id is channel id, resolvePeer method should call channels.getChannels API.

Workaround

I managed to overcome this bug using the following code. Obviously, it is just a workaround and correct fix will be improving resolvePeer to handle private channels correctly.

let message: Message | null = null
try {
    message = await client.getMessageByLink(url)
} catch (err) {
    if (url.startsWith("https://t.me/c/") && `${err}`.includes("is not found in local cache")) {
        // parse channel id from url like "https://t.me/c/1339581220/20441"
        const channelId = parseInt(url.split("/")[4])
        // resolve peer using "channels.getChannels" API method
        const res = await client.call({
            _: 'channels.getChannels',
            id: [{
                _: 'inputChannel',
                channelId: channelId,
                accessHash: Long.ZERO
            }],
        })
        // save resolved peer to cache
        client.storage.peers.store(res.chats[0])
        // now, this method will work as expected
        message = await client.getMessageByLink(url)
    }
}
I have faced with problem that `GetMessageByLink` (and probably some other methods) fail for private channels. When I call this method for message in private channel, method fails with error: ``` peer <peerId> is not found in local cache ``` Looks like `resolvePeer` method doesn't work well for private channels. See my investigation below. ## To Reproduce Call `client.GetMessageByLink("https://t.me/c/1339581220/20441")` ## Expected behavior `GetMessageByLink` should resolve message correctly. ## Environment Issue doesn't depend on exact environment. It is reproduced with latest version of mtcute. ## Investigation and potential root cause All mtcute methods call [resolvePeer](https://github.com/mtcute/mtcute/blob/6b4978210a0e432b1bd36d7de6172af181a3518b/packages/core/src/highlevel/methods/users/resolve-peer.ts#L46) method under hood. `resolvePeer` method searches for peer in cache. If peer is not found in cache, `resolvePeer` tries to resolve peer using Telegram API. It calls two different API methods based on peer id format: - [contacts.resolvePhone](https://github.com/mtcute/mtcute/blob/6b4978210a0e432b1bd36d7de6172af181a3518b/packages/core/src/highlevel/methods/users/resolve-peer.ts#L76C25-L76C46) if provided input looks like phone number - [contacts.resolveUsername](https://github.com/mtcute/mtcute/blob/6b4978210a0e432b1bd36d7de6172af181a3518b/packages/core/src/highlevel/methods/users/resolve-peer.ts#L95C25-L95C49) in other cases. Public telegram channels have links like `https://t.me/science/3774` where `science` is channel name. `resolvePeer` works fine because `contacts.resolveUsername` works for public channels. Private telegram channels have links like `https://t.me/c/1339581220/20441` where `1339581220` is channel Id. `resolvePeer` fails to resolve channel by Id and fails. I think `resolvePeer` should be improved with additional case for private telegram channels. In case if peer id is channel id, `resolvePeer` method should call `channels.getChannels` API. ## Workaround I managed to overcome this bug using the following code. Obviously, it is just a workaround and correct fix will be improving `resolvePeer` to handle private channels correctly. ```ts let message: Message | null = null try { message = await client.getMessageByLink(url) } catch (err) { if (url.startsWith("https://t.me/c/") && `${err}`.includes("is not found in local cache")) { // parse channel id from url like "https://t.me/c/1339581220/20441" const channelId = parseInt(url.split("/")[4]) // resolve peer using "channels.getChannels" API method const res = await client.call({ _: 'channels.getChannels', id: [{ _: 'inputChannel', channelId: channelId, accessHash: Long.ZERO }], }) // save resolved peer to cache client.storage.peers.store(res.chats[0]) // now, this method will work as expected message = await client.getMessageByLink(url) } } ```
teidesu commented 2024-11-09 19:21:11 +03:00 (Migrated from github.com)

your investigation is unfortunately not exactly correct. getMessageByLink correctly detects the channel id, but the peer is not cached and thus mtcute cannot reliably get it.

using it with access_hash=0 is a workaround that is very fragile and works in some very limited cases, the better solution would be to use findDialogs, as mentioned in the faq

(btw, instead of parsing like that you might want to use links.message.parse. and explicitly saving the peer is not necessary, it's cached automatically.)

the one thing i could improve with resolvePeer is to try fetching the channel with access_hash=0 and only then fail, but im not sure i want to do additional implicit network requests. might be worth it putting it behind some feature flag.

your investigation is unfortunately not exactly correct. `getMessageByLink` correctly detects the channel id, but the peer is not cached and thus mtcute cannot reliably get it. using it with `access_hash=0` is a workaround that is very fragile and works in some very limited cases, the better solution would be to use `findDialogs`, as mentioned in [the faq](https://mtcute.dev/guide/intro/faq.html#why-do-i-get-peer-id-invalid-mtpeernotfounderror) (btw, instead of parsing like that you might want to use [links.message.parse](https://ref.mtcute.dev/functions/_mtcute_core.utils.links.message.html). and explicitly saving the peer is not necessary, it's cached automatically.) the one thing i could improve with `resolvePeer` is to try fetching the channel with `access_hash=0` and only then fail, but im not sure i want to do additional implicit network requests. might be worth it putting it behind some feature flag.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: teidesu/mtcute#76
No description provided.