feat(core): isPeerAvailable method

This commit is contained in:
alina 🌸 2024-09-28 17:26:26 +03:00
parent baa8d287c6
commit c92292249b
Signed by: teidesu
SSH key fingerprint: SHA256:uNeCpw6aTSU4aIObXLvHfLkDa82HWH9EiOj9AXOIRpI
4 changed files with 128 additions and 23 deletions

View file

@ -264,6 +264,7 @@ import { getMyUsername } from './methods/users/get-my-username.js'
import { getProfilePhoto } from './methods/users/get-profile-photo.js' import { getProfilePhoto } from './methods/users/get-profile-photo.js'
import { getProfilePhotos } from './methods/users/get-profile-photos.js' import { getProfilePhotos } from './methods/users/get-profile-photos.js'
import { getUsers } from './methods/users/get-users.js' import { getUsers } from './methods/users/get-users.js'
import { isPeerAvailable } from './methods/users/is-peer-available.js'
import { iterProfilePhotos } from './methods/users/iter-profile-photos.js' import { iterProfilePhotos } from './methods/users/iter-profile-photos.js'
import { resolvePeerMany } from './methods/users/resolve-peer-many.js' import { resolvePeerMany } from './methods/users/resolve-peer-many.js'
import { resolveChannel, resolvePeer, resolveUser } from './methods/users/resolve-peer.js' import { resolveChannel, resolvePeer, resolveUser } from './methods/users/resolve-peer.js'
@ -5536,6 +5537,27 @@ export interface TelegramClient extends ITelegramClient {
* @param ids Users' identifiers. Can be ID, username, phone number, `"me"`, `"self"` or TL object * @param ids Users' identifiers. Can be ID, username, phone number, `"me"`, `"self"` or TL object
*/ */
getUsers(ids: MaybeArray<InputPeerLike>): Promise<(User | null)[]> getUsers(ids: MaybeArray<InputPeerLike>): Promise<(User | null)[]>
/**
* Check whether a given peer ID can be used to actually
* interact with the Telegram API.
* This method checks the internal peers cache for the given
* input peer, and returns `true` if it is available there.
*
* You can think of this method as a stripped down version of
* {@link resolvePeer}, which only returns `true` or `false`.
*
* > **Note:** This method works offline and never sends any requests.
* > This means that when passing a username or phone number, it will
* > only return `true` if the user with that username/phone number
* > is cached in the storage, and will not try to resolve the peer by calling the API,
* > which *may* lead to false negatives.
*
* **Available**: both users and bots
*
* @returns
*/
isPeerAvailable(
peerId: InputPeerLike): Promise<boolean>
/** /**
* Iterate over profile photos * Iterate over profile photos
* *
@ -6529,6 +6551,9 @@ TelegramClient.prototype.getProfilePhotos = function (...args) {
TelegramClient.prototype.getUsers = function (...args) { TelegramClient.prototype.getUsers = function (...args) {
return getUsers(this._client, ...args) return getUsers(this._client, ...args)
} }
TelegramClient.prototype.isPeerAvailable = function (...args) {
return isPeerAvailable(this._client, ...args)
}
TelegramClient.prototype.iterProfilePhotos = function (...args) { TelegramClient.prototype.iterProfilePhotos = function (...args) {
return iterProfilePhotos(this._client, ...args) return iterProfilePhotos(this._client, ...args)
} }

View file

@ -263,6 +263,7 @@ export { getMyUsername } from './methods/users/get-my-username.js'
export { getProfilePhoto } from './methods/users/get-profile-photo.js' export { getProfilePhoto } from './methods/users/get-profile-photo.js'
export { getProfilePhotos } from './methods/users/get-profile-photos.js' export { getProfilePhotos } from './methods/users/get-profile-photos.js'
export { getUsers } from './methods/users/get-users.js' export { getUsers } from './methods/users/get-users.js'
export { isPeerAvailable } from './methods/users/is-peer-available.js'
export { iterProfilePhotos } from './methods/users/iter-profile-photos.js' export { iterProfilePhotos } from './methods/users/iter-profile-photos.js'
export { resolvePeerMany } from './methods/users/resolve-peer-many.js' export { resolvePeerMany } from './methods/users/resolve-peer-many.js'
export { resolvePeer } from './methods/users/resolve-peer.js' export { resolvePeer } from './methods/users/resolve-peer.js'

View file

@ -0,0 +1,71 @@
import { parseMarkedPeerId } from '../../../utils/peer-utils.js'
import type { ITelegramClient } from '../../client.types'
import type { InputPeerLike } from '../../types'
import { _normalizePeerId } from './resolve-peer.js'
/**
* Check whether a given peer ID can be used to actually
* interact with the Telegram API.
* This method checks the internal peers cache for the given
* input peer, and returns `true` if it is available there.
*
* You can think of this method as a stripped down version of
* {@link resolvePeer}, which only returns `true` or `false`.
*
* > **Note:** This method works offline and never sends any requests.
* > This means that when passing a username or phone number, it will
* > only return `true` if the user with that username/phone number
* > is cached in the storage, and will not try to resolve the peer by calling the API,
* > which *may* lead to false negatives.
*
* @returns
*/
export async function isPeerAvailable(
client: ITelegramClient,
peerId: InputPeerLike,
): Promise<boolean> {
peerId = _normalizePeerId(peerId)
if (typeof peerId === 'object') {
// InputPeer (actual one, not mtcute.*)
return true
}
if (typeof peerId === 'number') {
const fromStorage = await client.storage.peers.getById(peerId)
if (fromStorage) return true
// in some cases, the server allows bots to use access_hash=0.
const [peerType] = parseMarkedPeerId(peerId)
if (peerType === 'chat' || client.storage.self.getCached(true)?.isBot) {
return true
}
return false
}
if (typeof peerId === 'string') {
if (peerId === 'self' || peerId === 'me') {
// inputPeerSelf is always available
return true
}
peerId = peerId.replace(/[@+\s()]/g, '')
if (peerId.match(/^\d+$/)) {
// phone number
const fromStorage = await client.storage.peers.getByPhone(peerId)
if (fromStorage) return true
} else {
// username
const fromStorage = await client.storage.peers.getByUsername(peerId)
if (fromStorage) return true
}
return false
}
return false
}

View file

@ -8,19 +8,7 @@ import { MtPeerNotFoundError } from '../../types/errors.js'
import type { InputPeerLike } from '../../types/peers/index.js' import type { InputPeerLike } from '../../types/peers/index.js'
import { toInputChannel, toInputPeer, toInputUser } from '../../utils/peer-utils.js' import { toInputChannel, toInputPeer, toInputUser } from '../../utils/peer-utils.js'
// @available=both export function _normalizePeerId(peerId: InputPeerLike): number | string | tl.TypeInputPeer {
/**
* Get the `InputPeer` of a known peer id.
* Useful when an `InputPeer` is needed in Raw API.
*
* @param peerId The peer identifier that you want to extract the `InputPeer` from.
* @param force Whether to force re-fetch the peer from the server (only for usernames and phone numbers)
*/
export async function resolvePeer(
client: ITelegramClient,
peerId: InputPeerLike,
force = false,
): Promise<tl.TypeInputPeer> {
// for convenience we also accept tl and User/Chat objects directly // for convenience we also accept tl and User/Chat objects directly
if (typeof peerId === 'object') { if (typeof peerId === 'object') {
if (tl.isAnyPeer(peerId)) { if (tl.isAnyPeer(peerId)) {
@ -36,16 +24,36 @@ export async function resolvePeer(
if (typeof peerId === 'object') { if (typeof peerId === 'object') {
switch (peerId._) { switch (peerId._) {
case 'mtcute.dummyInputPeerMinUser': case 'mtcute.dummyInputPeerMinUser':
peerId = peerId.userId return peerId.userId
break
case 'mtcute.dummyInputPeerMinChannel': case 'mtcute.dummyInputPeerMinChannel':
peerId = toggleChannelIdMark(peerId.channelId) return toggleChannelIdMark(peerId.channelId)
break
default: default:
return peerId return peerId
} }
} }
return peerId
}
// @available=both
/**
* Get the `InputPeer` of a known peer id.
* Useful when an `InputPeer` is needed in Raw API.
*
* @param peerId The peer identifier that you want to extract the `InputPeer` from.
* @param force Whether to force re-fetch the peer from the server (only for usernames and phone numbers)
*/
export async function resolvePeer(
client: ITelegramClient,
peerId: InputPeerLike,
force = false,
): Promise<tl.TypeInputPeer> {
peerId = _normalizePeerId(peerId)
if (typeof peerId === 'object') {
// InputPeer (actual one, not mtcute.*)
return peerId
}
if (typeof peerId === 'number' && !force) { if (typeof peerId === 'number' && !force) {
const fromStorage = await client.storage.peers.getById(peerId) const fromStorage = await client.storage.peers.getById(peerId)
if (fromStorage) return fromStorage if (fromStorage) return fromStorage
@ -152,7 +160,7 @@ export async function resolvePeer(
// if it's not the case, we'll get an `PEER_ID_INVALID` error anyways // if it's not the case, we'll get an `PEER_ID_INVALID` error anyways
const [peerType, bareId] = parseMarkedPeerId(peerId) const [peerType, bareId] = parseMarkedPeerId(peerId)
if (peerType !== 'chat' && !client.storage.self.getCached(true)?.isBot) { if (!(peerType === 'chat' || client.storage.self.getCached(true)?.isBot)) {
throw new MtPeerNotFoundError(`Peer ${peerId} is not found in local cache`) throw new MtPeerNotFoundError(`Peer ${peerId} is not found in local cache`)
} }