refactor(client): improve resolvePeer normalization

This commit is contained in:
teidesu 2021-05-11 23:21:35 +03:00
parent 8b3caeb3d0
commit f19fdf76b8
13 changed files with 218 additions and 144 deletions

View file

@ -2,6 +2,8 @@ import { TelegramClient } from '../../client'
import { InputPeerLike, MtCuteInvalidPeerTypeError } from '../../types'
import { MaybeArray } from '@mtcute/core'
import {
isInputPeerChannel,
isInputPeerChat,
normalizeToInputChannel,
normalizeToInputPeer,
normalizeToInputUser,
@ -24,28 +26,27 @@ export async function addChatMembers(
users: MaybeArray<InputPeerLike>,
forwardCount = 100
): Promise<void> {
const chat = await this.resolvePeer(chatId)
const input = normalizeToInputPeer(chat)
const chat = normalizeToInputPeer(await this.resolvePeer(chatId))
if (!Array.isArray(users)) users = [users]
if (input._ === 'inputPeerChat') {
if (isInputPeerChat(chat)) {
for (const user of users) {
const p = normalizeToInputUser(await this.resolvePeer(user))
if (!p) continue
const updates = await this.call({
_: 'messages.addChatUser',
chatId: input.chatId,
chatId: chat.chatId,
userId: p,
fwdLimit: forwardCount,
})
this._handleUpdate(updates)
}
} else if (input._ === 'inputPeerChannel') {
} else if (isInputPeerChannel(chat)) {
const updates = await this.call({
_: 'channels.inviteToChannel',
channel: normalizeToInputChannel(chat)!,
channel: normalizeToInputChannel(chat),
users: await this.resolvePeerMany(
users as InputPeerLike[],
normalizeToInputUser

View file

@ -1,9 +1,11 @@
import { TelegramClient } from '../../client'
import { InputPeerLike, MtCuteInvalidPeerTypeError } from '../../types'
import {
InputPeerLike,
MtCuteInvalidPeerTypeError,
} from '../../types'
import { normalizeToInputChannel, normalizeToInputPeer } from '../../utils/peer-utils'
isInputPeerChannel,
isInputPeerChat,
normalizeToInputChannel,
normalizeToInputPeer,
} from '../../utils/peer-utils'
/**
* Delete a chat photo
@ -18,23 +20,21 @@ export async function deleteChatPhoto(
chatId: InputPeerLike
): Promise<void> {
const chat = normalizeToInputPeer(await this.resolvePeer(chatId))
if (!(chat._ === 'inputPeerChat' || chat._ === 'inputPeerChannel'))
throw new MtCuteInvalidPeerTypeError(chatId, 'chat or channel')
let res
if (chat._ === 'inputPeerChat') {
if (isInputPeerChat(chat)) {
res = await this.call({
_: 'messages.editChatPhoto',
chatId: chat.chatId,
photo: { _: 'inputChatPhotoEmpty' }
photo: { _: 'inputChatPhotoEmpty' },
})
} else {
} else if (isInputPeerChannel(chat)) {
res = await this.call({
_: 'channels.editPhoto',
channel: normalizeToInputChannel(chat)!,
photo: { _: 'inputChatPhotoEmpty' }
channel: normalizeToInputChannel(chat),
photo: { _: 'inputChatPhotoEmpty' },
})
}
} else throw new MtCuteInvalidPeerTypeError(chatId, 'chat or channel')
this._handleUpdate(res)
}

View file

@ -4,7 +4,7 @@ import {
MtCuteInvalidPeerTypeError,
} from '../../types'
import {
createUsersChatsIndex,
createUsersChatsIndex, isInputPeerChannel, isInputPeerChat, isInputPeerUser,
normalizeToInputChannel,
normalizeToInputPeer,
} from '../../utils/peer-utils'
@ -27,13 +27,15 @@ export async function getChatMember(
userId: InputPeerLike
): Promise<ChatMember> {
const user = normalizeToInputPeer(await this.resolvePeer(userId))
const chat = await this.resolvePeer(chatId)
const chatInput = normalizeToInputPeer(chat)
const chat = normalizeToInputPeer(await this.resolvePeer(chatId))
if (isInputPeerChat(chat)) {
if (!isInputPeerUser(user))
throw new MtCuteInvalidPeerTypeError(userId, 'user')
if (chatInput._ === 'inputPeerChat') {
const res = await this.call({
_: 'messages.getFullChat',
chatId: chatInput.chatId,
chatId: chat.chatId,
})
assertTypeIs(
@ -60,10 +62,10 @@ export async function getChatMember(
}
throw new UserNotParticipantError()
} else if (chatInput._ === 'inputPeerChannel') {
} else if (isInputPeerChannel(chat)) {
const res = await this.call({
_: 'channels.getParticipant',
channel: normalizeToInputChannel(chat)!,
channel: normalizeToInputChannel(chat),
participant: user,
})

View file

@ -5,7 +5,7 @@ import {
} from '../../types'
import { TelegramClient } from '../../client'
import {
createUsersChatsIndex,
createUsersChatsIndex, isInputPeerChannel, isInputPeerChat,
normalizeToInputChannel,
normalizeToInputPeer,
} from '../../utils/peer-utils'
@ -71,10 +71,8 @@ export async function getChatMembers(
if (!params) params = {}
const chat = normalizeToInputPeer(await this.resolvePeer(chatId))
if (chat._ === 'inputPeerUser')
throw new MtCuteInvalidPeerTypeError(chatId, 'chat or channel')
if (chat._ === 'inputPeerChat') {
if (isInputPeerChat(chat)) {
const res = await this.call({
_: 'messages.getFullChat',
chatId: chat.chatId,
@ -99,7 +97,7 @@ export async function getChatMembers(
return members.map((m) => new ChatMember(this, m, users))
}
if (chat._ === 'inputPeerChannel') {
if (isInputPeerChannel(chat)) {
const q = params.query?.toLowerCase() ?? ''
const type = params.type ?? 'recent'
@ -126,7 +124,7 @@ export async function getChatMembers(
const res = await this.call({
_: 'channels.getParticipants',
channel: normalizeToInputChannel(chat)!,
channel: normalizeToInputChannel(chat),
filter,
offset: params.offset ?? 0,
limit: params.limit ?? 200,
@ -143,5 +141,5 @@ export async function getChatMembers(
return res.participants.map(i => new ChatMember(this, i, users))
}
throw new Error('should not happen')
throw new MtCuteInvalidPeerTypeError(chatId, 'chat or channel')
}

View file

@ -2,6 +2,9 @@ import { Chat, InputPeerLike, MtCuteArgumentError } from '../../types'
import { TelegramClient } from '../../client'
import {
INVITE_LINK_REGEX,
isInputPeerChannel,
isInputPeerChat,
isInputPeerUser,
normalizeToInputChannel,
normalizeToInputPeer,
normalizeToInputUser,
@ -26,37 +29,38 @@ export async function getChat(
if (m) {
const res = await this.call({
_: 'messages.checkChatInvite',
hash: m[1]
hash: m[1],
})
if (res._ === 'chatInvite') {
throw new MtCuteArgumentError(`You haven't joined ${JSON.stringify(res.title)}`)
throw new MtCuteArgumentError(
`You haven't joined ${JSON.stringify(res.title)}`
)
}
return new Chat(this, res.chat)
}
}
const peer = await this.resolvePeer(chatId)
const input = normalizeToInputPeer(peer)
const peer = normalizeToInputPeer(await this.resolvePeer(chatId))
let res: tl.TypeChat | tl.TypeUser
if (input._ === 'inputPeerChannel') {
if (isInputPeerChannel(peer)) {
const r = await this.call({
_: 'channels.getChannels',
id: [normalizeToInputChannel(peer)!]
id: [normalizeToInputChannel(peer)],
})
res = r.chats[0]
} else if (input._ === 'inputPeerUser' || input._ === 'inputPeerSelf') {
} else if (isInputPeerUser(peer)) {
const r = await this.call({
_: 'users.getUsers',
id: [normalizeToInputUser(peer)!]
id: [normalizeToInputUser(peer)],
})
res = r[0]
} else if (input._ === 'inputPeerChat') {
} else if (isInputPeerChat(peer)) {
const r = await this.call({
_: 'messages.getChats',
id: [input.chatId]
id: [peer.chatId],
})
res = r.chats[0]
} else throw new Error('should not happen')

View file

@ -1,7 +1,7 @@
import { Chat, InputPeerLike, MtCuteArgumentError } from '../../types'
import { TelegramClient } from '../../client'
import {
INVITE_LINK_REGEX,
INVITE_LINK_REGEX, isInputPeerChannel, isInputPeerChat, isInputPeerUser,
normalizeToInputChannel,
normalizeToInputPeer,
normalizeToInputUser,
@ -38,24 +38,23 @@ export async function getFullChat(
}
}
const peer = await this.resolvePeer(chatId)
const input = normalizeToInputPeer(peer)
const peer = normalizeToInputPeer(await this.resolvePeer(chatId))
let res: tl.messages.TypeChatFull | tl.TypeUserFull
if (input._ === 'inputPeerChannel') {
if (isInputPeerChannel(peer)) {
res = await this.call({
_: 'channels.getFullChannel',
channel: normalizeToInputChannel(peer)!
channel: normalizeToInputChannel(peer)
})
} else if (input._ === 'inputPeerUser' || input._ === 'inputPeerSelf') {
} else if (isInputPeerUser(peer)) {
res = await this.call({
_: 'users.getFullUser',
id: normalizeToInputUser(peer)!
})
} else if (input._ === 'inputPeerChat') {
} else if (isInputPeerChat(peer)) {
res = await this.call({
_: 'messages.getFullChat',
chatId: input.chatId
chatId: peer.chatId
})
} else throw new Error('should not happen')

View file

@ -1,6 +1,7 @@
import { InputPeerLike, MtCuteInvalidPeerTypeError } from '../../types'
import { TelegramClient } from '../../client'
import {
isInputPeerChannel, isInputPeerChat,
normalizeToInputChannel,
normalizeToInputPeer,
} from '../../utils/peer-utils'
@ -17,25 +18,24 @@ export async function leaveChat(
chatId: InputPeerLike,
clear = false
): Promise<void> {
const chat = await this.resolvePeer(chatId)
const input = normalizeToInputPeer(chat)
const chat = normalizeToInputPeer(await this.resolvePeer(chatId))
if (input._ === 'inputPeerChannel') {
if (isInputPeerChannel(chat)) {
const res = await this.call({
_: 'channels.leaveChannel',
channel: normalizeToInputChannel(chat)!,
channel: normalizeToInputChannel(chat),
})
this._handleUpdate(res)
} else if (input._ === 'inputPeerChat') {
} else if (isInputPeerChat(chat)) {
const res = await this.call({
_: 'messages.deleteChatUser',
chatId: input.chatId,
chatId: chat.chatId,
userId: { _: 'inputUserSelf' },
})
this._handleUpdate(res)
if (clear) {
await this.deleteHistory(input)
await this.deleteHistory(chat)
}
} else throw new MtCuteInvalidPeerTypeError(chatId, 'chat or channel')
}

View file

@ -1,8 +1,5 @@
import { TelegramClient } from '../../client'
import {
InputPeerLike,
MtCuteInvalidPeerTypeError,
} from '../../types'
import { InputPeerLike } from '../../types'
import { normalizeToInputPeer } from '../../utils/peer-utils'
/**
@ -20,12 +17,10 @@ export async function setChatDescription(
description: string
): Promise<void> {
const chat = normalizeToInputPeer(await this.resolvePeer(chatId))
if (!(chat._ === 'inputPeerChat' || chat._ === 'inputPeerChannel'))
throw new MtCuteInvalidPeerTypeError(chatId, 'chat or channel')
await this.call({
_: 'messages.editChatAbout',
peer: chat,
about: description
about: description,
})
}

View file

@ -7,6 +7,8 @@ import {
MtCuteInvalidPeerTypeError,
} from '../../types'
import {
isInputPeerChannel,
isInputPeerChat,
normalizeToInputChannel,
normalizeToInputPeer,
} from '../../utils/peer-utils'
@ -34,13 +36,7 @@ export async function setChatPhoto(
previewSec?: number
): Promise<void> {
const chat = normalizeToInputPeer(await this.resolvePeer(chatId))
if (
!(
chat._ === 'inputPeerChat' ||
chat._ === 'inputPeerChannel' ||
chat._ === 'inputPeerChannelFromMessage'
)
)
if (!(isInputPeerChannel(chat) || isInputPeerChat(chat)))
throw new MtCuteInvalidPeerTypeError(chatId, 'chat or channel')
let photo: tl.TypeInputChatPhoto | undefined = undefined
@ -88,7 +84,7 @@ export async function setChatPhoto(
}
let res
if (chat._ === 'inputPeerChat') {
if (isInputPeerChat(chat)) {
res = await this.call({
_: 'messages.editChatPhoto',
chatId: chat.chatId,
@ -97,7 +93,7 @@ export async function setChatPhoto(
} else {
res = await this.call({
_: 'channels.editPhoto',
channel: normalizeToInputChannel(chat)!,
channel: normalizeToInputChannel(chat),
photo,
})
}

View file

@ -3,7 +3,12 @@ import {
InputPeerLike,
MtCuteInvalidPeerTypeError,
} from '../../types'
import { normalizeToInputChannel, normalizeToInputPeer } from '../../utils/peer-utils'
import {
isInputPeerChannel,
isInputPeerChat,
normalizeToInputChannel,
normalizeToInputPeer,
} from '../../utils/peer-utils'
/**
* Change chat title
@ -20,22 +25,21 @@ export async function setChatTitle(
title: string
): Promise<void> {
const chat = normalizeToInputPeer(await this.resolvePeer(chatId))
if (!(chat._ === 'inputPeerChat' || chat._ === 'inputPeerChannel'))
throw new MtCuteInvalidPeerTypeError(chatId, 'chat or channel')
let res
if (chat._ === 'inputPeerChat') {
if (isInputPeerChat(chat)) {
res = await this.call({
_: 'messages.editChatTitle',
chatId: chat.chatId,
title
})
} else {
} else if (isInputPeerChannel(chat)) {
res = await this.call({
_: 'channels.editTitle',
channel: normalizeToInputChannel(chat)!,
channel: normalizeToInputChannel(chat),
title
})
}
} else throw new MtCuteInvalidPeerTypeError(chatId, 'chat or channel')
this._handleUpdate(res)
}

View file

@ -1,7 +1,7 @@
import { TelegramClient } from '../../client'
import { InputPeerLike } from '../../types'
import { MaybeArray } from '@mtcute/core'
import { normalizeToInputChannel, normalizeToInputPeer } from '../../utils/peer-utils'
import { isInputPeerChannel, normalizeToInputChannel, normalizeToInputPeer } from '../../utils/peer-utils'
import { createDummyUpdate } from '../../utils/updates-utils'
import { tl } from '@mtcute/tl'
@ -21,12 +21,11 @@ export async function deleteMessages(
): Promise<void> {
if (!Array.isArray(ids)) ids = [ids]
const peer = await this.resolvePeer(chatId)
const inputPeer = normalizeToInputPeer(peer)
const peer = normalizeToInputPeer(await this.resolvePeer(chatId))
let upd
if (inputPeer._ === 'inputPeerChannel') {
const channel = normalizeToInputChannel(peer)!
if (isInputPeerChannel(peer)) {
const channel = normalizeToInputChannel(peer)
const res = await this.call({
_: 'channels.deleteMessages',
channel,

View file

@ -2,7 +2,9 @@ import { TelegramClient } from '../../client'
import { MaybeArray } from '@mtcute/core'
import {
createUsersChatsIndex,
isInputPeerChannel,
normalizeToInputChannel,
normalizeToInputPeer,
} from '../../utils/peer-utils'
import { tl } from '@mtcute/tl'
import { Message, InputPeerLike, MtCuteTypeAssertionError } from '../../types'
@ -51,7 +53,7 @@ export async function getMessages(
messageIds: MaybeArray<number>,
fromReply = false
): Promise<MaybeArray<Message>> {
const peer = await this.resolvePeer(chatId)
const peer = normalizeToInputPeer(await this.resolvePeer(chatId))
const isSingle = !Array.isArray(messageIds)
if (isSingle) messageIds = [messageIds as number]
@ -63,14 +65,11 @@ export async function getMessages(
}))
const res = await this.call(
peer._ === 'inputPeerChannel' ||
peer._ === 'inputChannel' ||
peer._ === 'inputPeerChannelFromMessage' ||
peer._ === 'inputChannelFromMessage'
isInputPeerChannel(peer)
? {
_: 'channels.getMessages',
id: ids,
channel: normalizeToInputChannel(peer)!,
channel: normalizeToInputChannel(peer),
}
: {
_: 'messages.getMessages',

View file

@ -11,87 +11,164 @@ export function normalizeToInputPeer(
): tl.TypeInputPeer {
if (tl.isAnyInputPeer(res)) return res
if (res._ === 'inputChannelEmpty' || res._ === 'inputUserEmpty') {
switch (res._) {
case 'inputChannelEmpty':
case 'inputUserEmpty':
return { _: 'inputPeerEmpty' }
case 'inputUser':
return {
_: 'inputPeerUser',
userId: res.userId,
accessHash: res.accessHash,
}
if (res._ === 'inputUser') {
return { ...res, _: 'inputPeerUser' }
}
if (res._ === 'inputUserSelf') {
case 'inputUserSelf':
return { _: 'inputPeerSelf' }
case 'inputChannel':
return {
_: 'inputPeerChannel',
channelId: res.channelId,
accessHash: res.accessHash,
}
case 'inputChannelFromMessage':
return {
_: 'inputPeerChannelFromMessage',
channelId: res.channelId,
msgId: res.msgId,
peer: res.peer,
}
case 'inputUserFromMessage':
return {
_: 'inputPeerUserFromMessage',
userId: res.userId,
msgId: res.msgId,
peer: res.peer,
}
}
}
if (res._ === 'inputChannel') {
return { ...res, _: 'inputPeerChannel' }
}
if (res._ === 'inputChannelFromMessage') {
return { ...res, _: 'inputPeerChannelFromMessage' }
}
if (res._ === 'inputUserFromMessage') {
return { ...res, _: 'inputPeerUserFromMessage' }
}
return res as never
}
export function normalizeToInputUser(
res: tl.TypeInputUser | tl.RawInputPeerUser | tl.RawInputPeerUserFromMessage | tl.RawInputPeerSelf
): tl.TypeInputUser
export function normalizeToInputUser(
res: tl.TypeInputPeer | tl.TypeInputUser | tl.TypeInputChannel
): tl.TypeInputUser | null
export function normalizeToInputUser(
res: tl.TypeInputPeer | tl.TypeInputUser | tl.TypeInputChannel
): tl.TypeInputUser | null {
if (tl.isAnyInputUser(res)) return res
if (res._ === 'inputPeerUser') {
return { ...res, _: 'inputUser' }
switch (res._) {
case 'inputPeerUser':
return {
_: 'inputUser',
userId: res.userId,
accessHash: res.accessHash,
}
case 'inputPeerUserFromMessage':
return {
_: 'inputUserFromMessage',
userId: res.userId,
msgId: res.msgId,
peer: res.peer,
}
if (res._ === 'inputPeerUserFromMessage') {
return { ...res, _: 'inputUserFromMessage' }
}
return null
}
export function normalizeToInputChannel(
res: tl.TypeInputChannel | tl.RawInputPeerChannel | tl.RawInputPeerChannelFromMessage
): tl.TypeInputChannel
export function normalizeToInputChannel(
res: tl.TypeInputPeer | tl.TypeInputUser | tl.TypeInputChannel
): tl.TypeInputChannel | null
export function normalizeToInputChannel(
res: tl.TypeInputPeer | tl.TypeInputUser | tl.TypeInputChannel
): tl.TypeInputChannel | null {
if (tl.isAnyInputChannel(res)) return res
if (res._ === 'inputPeerChannel') {
return { ...res, _: 'inputChannel' }
switch (res._) {
case 'inputPeerChannel':
return {
_: 'inputChannel',
channelId: res.channelId,
accessHash: res.accessHash,
}
case 'inputPeerChannelFromMessage':
return {
_: 'inputChannelFromMessage',
channelId: res.channelId,
msgId: res.msgId,
peer: res.peer,
}
if (res._ === 'inputPeerChannelFromMessage') {
return { ...res, _: 'inputChannelFromMessage' }
}
return null
}
export function inputPeerToPeer(inp: tl.TypeInputPeer): tl.TypePeer {
if (inp._ === 'inputPeerUser' || inp._ === 'inputPeerUserFromMessage')
return { _: 'peerUser', userId: inp.userId }
if (inp._ === 'inputPeerChannel' || inp._ === 'inputPeerChannelFromMessage')
return { _: 'peerChannel', channelId: inp.channelId }
if (inp._ === 'inputPeerChat') return { _: 'peerChat', chatId: inp.chatId }
throw new Error(`Cannot convert ${inp._} to peer`)
export function isInputPeerUser(
obj: tl.TypeInputPeer
): obj is
| tl.RawInputPeerUser
| tl.RawInputPeerUserFromMessage
| tl.RawInputPeerSelf {
switch (obj._) {
case 'inputPeerUser':
case 'inputPeerUserFromMessage':
case 'inputPeerSelf':
return true
}
return false
}
export function peerToInputPeer(peer: tl.TypePeer, accessHash = bigInt.zero): tl.TypeInputPeer {
if (peer._ === 'peerUser')
export function isInputPeerChannel(
obj: tl.TypeInputPeer
): obj is tl.RawInputPeerChannel | tl.RawInputPeerChannelFromMessage {
switch (obj._) {
case 'inputPeerChannel':
case 'inputPeerChannelFromMessage':
return true
}
return false
}
export function isInputPeerChat(
obj: tl.TypeInputPeer
): obj is tl.RawInputPeerChat {
return obj._ === 'inputPeerChat'
}
export function inputPeerToPeer(inp: tl.TypeInputPeer): tl.TypePeer {
switch (inp._) {
case 'inputPeerUser':
case 'inputPeerUserFromMessage':
return { _: 'peerUser', userId: inp.userId }
case 'inputPeerChannel':
case 'inputPeerChannelFromMessage':
return { _: 'peerChannel', channelId: inp.channelId }
case 'inputPeerChat':
return { _: 'peerChat', chatId: inp.chatId }
default:
throw new Error(`Cannot convert ${inp._} to peer`)
}
}
export function peerToInputPeer(
peer: tl.TypePeer,
accessHash = bigInt.zero
): tl.TypeInputPeer {
switch (peer._) {
case 'peerUser':
return { _: 'inputPeerUser', userId: peer.userId, accessHash }
if (peer._ === 'peerChannel')
return { _: 'inputPeerChannel', channelId: peer.channelId, accessHash }
if (peer._ === 'peerChat') return { _: 'inputPeerChat', chatId: peer.chatId }
return peer as never
case 'peerChannel':
return {
_: 'inputPeerChannel',
channelId: peer.channelId,
accessHash,
}
case 'peerChat':
return { _: 'inputPeerChat', chatId: peer.chatId }
}
}
export function createUsersChatsIndex(