diff --git a/packages/client/src/methods/chats/get-chat-members.ts b/packages/client/src/methods/chats/get-chat-members.ts index 31301910..39495062 100644 --- a/packages/client/src/methods/chats/get-chat-members.ts +++ b/packages/client/src/methods/chats/get-chat-members.ts @@ -102,24 +102,31 @@ export async function getChatMembers( const type = params.type ?? 'recent' let filter: tl.TypeChannelParticipantsFilter - if (type === 'all') { - filter = { _: 'channelParticipantsSearch', q } - } else if (type === 'banned') { - filter = { _: 'channelParticipantsKicked', q } - } else if (type === 'restricted') { - filter = { _: 'channelParticipantsBanned', q } - } else if (type === 'mention') { - filter = { _: 'channelParticipantsMentions', q } - } else if (type === 'bots') { - filter = { _: 'channelParticipantsBots' } - } else if (type === 'recent') { - filter = { _: 'channelParticipantsRecent' } - } else if (type === 'admins') { - filter = { _: 'channelParticipantsAdmins' } - } else if (type === 'contacts') { - filter = { _: 'channelParticipantsContacts', q } - } else { - return type as never + switch (type) { + case 'all': + filter = { _: 'channelParticipantsSearch', q } + break + case 'banned': + filter = { _: 'channelParticipantsKicked', q } + break + case 'restricted': + filter = { _: 'channelParticipantsBanned', q } + break + case 'mention': + filter = { _: 'channelParticipantsMentions', q } + break + case 'bots': + filter = { _: 'channelParticipantsBots' } + break + case 'recent': + filter = { _: 'channelParticipantsRecent' } + break + case 'admins': + filter = { _: 'channelParticipantsAdmins' } + break + case 'contacts': + filter = { _: 'channelParticipantsContacts', q } + break } const res = await this.call({ diff --git a/packages/client/src/methods/updates.ts b/packages/client/src/methods/updates.ts index 3b8c6b93..c218ff88 100644 --- a/packages/client/src/methods/updates.ts +++ b/packages/client/src/methods/updates.ts @@ -208,8 +208,7 @@ async function _loadDifference( qts: 0, }) - if (diff._ === 'updates.differenceEmpty') - return + if (diff._ === 'updates.differenceEmpty') return if (diff._ === 'updates.differenceTooLong') { this._pts = diff.pts @@ -340,7 +339,8 @@ async function _loadChannelDifference( } diff.messages.forEach((message) => { - if (noDispatch && noDispatch.msg[channelId]?.[message.id]) return + if (noDispatch && noDispatch.msg[channelId]?.[message.id]) + return this.dispatchUpdate(message, users, chats) }) @@ -409,351 +409,359 @@ export function _handleUpdate( // i tried my best to follow the documentation, but i still may have missed something. // feel free to contribute! // reference: https://core.telegram.org/api/updates - if (update._ === 'updatesTooLong') { - // "there are too many events pending to be pushed to the client", we need to fetch them manually - await _loadDifference.call(this, noDispatchIndex) - } else if ( - update._ === 'updates' || - update._ === 'updatesCombined' - ) { - // const seqStart = - // update._ === 'updatesCombined' - // ? update.seqStart - // : update.seq - // const nextLocalSeq = this._seq + 1 - // - // debug('received %s (seq_start=%d, seq_end=%d)', update._, seqStart, update.seq) - // - // if (nextLocalSeq > seqStart) - // // "the updates were already applied, and must be ignored" - // return - // if (nextLocalSeq < seqStart) - // // "there's an updates gap that must be filled" - // // loading difference will also load any updates contained - // // in this update, so we discard it - // return await _loadDifference.call(this) + switch (update._) { + case 'updatesTooLong': // "there are too many events pending to be pushed to the client", we need to fetch them manually + await _loadDifference.call(this, noDispatchIndex) + break + case 'updates': + case 'updatesCombined': { + // const seqStart = + // update._ === 'updatesCombined' + // ? update.seqStart + // : update.seq + // const nextLocalSeq = this._seq + 1 + // + // debug('received %s (seq_start=%d, seq_end=%d)', update._, seqStart, update.seq) + // + // if (nextLocalSeq > seqStart) + // // "the updates were already applied, and must be ignored" + // return + // if (nextLocalSeq < seqStart) + // // "there's an updates gap that must be filled" + // // loading difference will also load any updates contained + // // in this update, so we discard it + // return await _loadDifference.call(this) - await this._cachePeersFrom(update) - const { users, chats } = createUsersChatsIndex(update) + await this._cachePeersFrom(update) + const { users, chats } = createUsersChatsIndex(update) - for (const upd of update.updates) { - if (upd._ === 'updateChannelTooLong') { - if (upd.pts) { - this._cpts[upd.channelId] = upd.pts - } - await _loadChannelDifference.call( - this, - upd.channelId, - noDispatchIndex - ) - continue - } - - const channelId = extractChannelIdFromUpdate(upd) - const pts = 'pts' in upd ? upd.pts : undefined - const ptsCount = - 'ptsCount' in upd ? upd.ptsCount : undefined - - if (pts !== undefined && ptsCount !== undefined) { - let nextLocalPts - if (channelId === undefined) - nextLocalPts = this._pts + ptsCount - else if (channelId in this._cpts) - nextLocalPts = this._cpts[channelId] + ptsCount - else { - const saved = await this.storage.getChannelPts( - channelId - ) - if (saved) { - this._cpts[channelId] = saved - nextLocalPts = saved + ptsCount - } else { - nextLocalPts = null + for (const upd of update.updates) { + if (upd._ === 'updateChannelTooLong') { + if (upd.pts) { + this._cpts[upd.channelId] = upd.pts } + await _loadChannelDifference.call( + this, + upd.channelId, + noDispatchIndex + ) + continue } - if (nextLocalPts) { - if (nextLocalPts > pts) - // "the update was already applied, and must be ignored" - return - if (nextLocalPts < pts) - if (channelId) { - // "there's an update gap that must be filled" - await _loadChannelDifference.call( - this, - channelId, - noDispatchIndex - ) - continue + const channelId = extractChannelIdFromUpdate(upd) + const pts = 'pts' in upd ? upd.pts : undefined + const ptsCount = + 'ptsCount' in upd ? upd.ptsCount : undefined + + if (pts !== undefined && ptsCount !== undefined) { + let nextLocalPts + if (channelId === undefined) + nextLocalPts = this._pts + ptsCount + else if (channelId in this._cpts) + nextLocalPts = this._cpts[channelId] + ptsCount + else { + const saved = await this.storage.getChannelPts( + channelId + ) + if (saved) { + this._cpts[channelId] = saved + nextLocalPts = saved + ptsCount } else { - return await _loadDifference.call(this) + nextLocalPts = null } - } + } - if (!isDummyUpdate(upd) && !noDispatch) { + if (nextLocalPts) { + if (nextLocalPts > pts) + // "the update was already applied, and must be ignored" + return + if (nextLocalPts < pts) + if (channelId) { + // "there's an update gap that must be filled" + await _loadChannelDifference.call( + this, + channelId, + noDispatchIndex + ) + continue + } else { + return await _loadDifference.call(this) + } + } + + if (!isDummyUpdate(upd) && !noDispatch) { + this.dispatchUpdate(upd, users, chats) + } + + if (channelId) { + this._cpts[channelId] = pts + } else { + this._pts = pts + } + } else if (!noDispatch) { this.dispatchUpdate(upd, users, chats) } + } - if (channelId) { - this._cpts[channelId] = pts - } else { - this._pts = pts - } + if (!isDummyUpdates(update)) { + // this._seq = update.seq + this._date = update.date + } + break + } + case 'updateShort': { + const upd = update.update + if (upd._ === 'updateDcOptions' && this._config) { + ;(this._config as tl.Mutable).dcOptions = + upd.dcOptions + } else if (upd._ === 'updateConfig') { + this._config = await this.call({ _: 'help.getConfig' }) } else if (!noDispatch) { - this.dispatchUpdate(upd, users, chats) + this.dispatchUpdate(upd, {}, {}) } - } - if (!isDummyUpdates(update)) { - // this._seq = update.seq this._date = update.date + break } - } else if (update._ === 'updateShort') { - const upd = update.update - if (upd._ === 'updateDcOptions' && this._config) { - ;(this._config as tl.Mutable).dcOptions = - upd.dcOptions - } else if (upd._ === 'updateConfig') { - this._config = await this.call({ _: 'help.getConfig' }) - } else if (!noDispatch) { - this.dispatchUpdate(upd, {}, {}) - } + case 'updateShortMessage': { + if (noDispatch) return - this._date = update.date - } else if (update._ === 'updateShortMessage') { - if (noDispatch) return - - const message: tl.RawMessage = { - _: 'message', - out: update.out, - mentioned: update.mentioned, - mediaUnread: update.mediaUnread, - silent: update.silent, - id: update.id, - fromId: { - _: 'peerUser', - userId: update.out ? this._userId! : update.userId, - }, - peerId: { - _: 'peerUser', - userId: update.userId, - }, - fwdFrom: update.fwdFrom, - viaBotId: update.viaBotId, - replyTo: update.replyTo, - date: update.date, - message: update.message, - entities: update.entities, - ttlPeriod: update.ttlPeriod, - } - - // now we need to fetch info about users involved. - // since this update is only used for PM, we can just - // fetch the current user and the other user. - // additionally, we need to handle "forwarded from" - // field, as it may contain a user OR a channel - const fwdFrom = update.fwdFrom?.fromId - ? peerToInputPeer(update.fwdFrom.fromId) - : undefined - - let rawUsers: tl.TypeUser[] - { - const id: tl.TypeInputUser[] = [ - { _: 'inputUserSelf' }, - { - _: 'inputUser', + const message: tl.RawMessage = { + _: 'message', + out: update.out, + mentioned: update.mentioned, + mediaUnread: update.mediaUnread, + silent: update.silent, + id: update.id, + fromId: { + _: 'peerUser', + userId: update.out ? this._userId! : update.userId, + }, + peerId: { + _: 'peerUser', userId: update.userId, - accessHash: bigInt.zero, }, - ] - - if (fwdFrom) { - const inputUser = normalizeToInputUser(fwdFrom) - if (inputUser) id.push(inputUser) + fwdFrom: update.fwdFrom, + viaBotId: update.viaBotId, + replyTo: update.replyTo, + date: update.date, + message: update.message, + entities: update.entities, + ttlPeriod: update.ttlPeriod, } - rawUsers = await this.call({ - _: 'users.getUsers', - id, - }) + // now we need to fetch info about users involved. + // since this update is only used for PM, we can just + // fetch the current user and the other user. + // additionally, we need to handle "forwarded from" + // field, as it may contain a user OR a channel + const fwdFrom = update.fwdFrom?.fromId + ? peerToInputPeer(update.fwdFrom.fromId) + : undefined - if (rawUsers.length !== id.length) { - // other user failed to load. - // first try checking for input peer in storage - const saved = await this.storage.getPeerById( - update.userId - ) - if (saved) { - id[1] = normalizeToInputUser(saved)! + let rawUsers: tl.TypeUser[] + { + const id: tl.TypeInputUser[] = [ + { _: 'inputUserSelf' }, + { + _: 'inputUser', + userId: update.userId, + accessHash: bigInt.zero, + }, + ] - rawUsers = await this.call({ - _: 'users.getUsers', - id, - }) + if (fwdFrom) { + const inputUser = normalizeToInputUser(fwdFrom) + if (inputUser) id.push(inputUser) } - } - if (rawUsers.length !== id.length) { - // not saved (or invalid hash), not found by id - // find that user in dialogs (since the update - // is about an incoming message, dialog with that - // user should be one of the first) - const dialogs = await this.call({ - _: 'messages.getDialogs', - offsetDate: 0, - offsetId: 0, - offsetPeer: { _: 'inputPeerEmpty' }, - limit: 20, - hash: 0, + + rawUsers = await this.call({ + _: 'users.getUsers', + id, }) - if (dialogs._ === 'messages.dialogsNotModified') return - const user = dialogs.users.find( - (it) => it.id === update.userId - ) - if (!user) { - debug( - "received updateShortMessage, but wasn't able to find User" + if (rawUsers.length !== id.length) { + // other user failed to load. + // first try checking for input peer in storage + const saved = await this.storage.getPeerById( + update.userId ) - return + if (saved) { + id[1] = normalizeToInputUser(saved)! + + rawUsers = await this.call({ + _: 'users.getUsers', + id, + }) + } + } + if (rawUsers.length !== id.length) { + // not saved (or invalid hash), not found by id + // find that user in dialogs (since the update + // is about an incoming message, dialog with that + // user should be one of the first) + const dialogs = await this.call({ + _: 'messages.getDialogs', + offsetDate: 0, + offsetId: 0, + offsetPeer: { _: 'inputPeerEmpty' }, + limit: 20, + hash: 0, + }) + if (dialogs._ === 'messages.dialogsNotModified') + return + + const user = dialogs.users.find( + (it) => it.id === update.userId + ) + if (!user) { + debug( + "received updateShortMessage, but wasn't able to find User" + ) + return + } + rawUsers.push(user) } - rawUsers.push(user) } + let rawChats: tl.TypeChat[] = [] + if (fwdFrom) { + const inputChannel = normalizeToInputChannel(fwdFrom) + if (inputChannel) + rawChats = await this.call({ + _: 'channels.getChannels', + id: [inputChannel], + }).then((res) => res.chats) + } + + this._date = update.date + this._pts = update.pts + + const { users, chats } = createUsersChatsIndex({ + users: rawUsers, + chats: rawChats, + }) + this.dispatchUpdate(message, users, chats) + break } - let rawChats: tl.TypeChat[] = [] - if (fwdFrom) { - const inputChannel = normalizeToInputChannel(fwdFrom) - if (inputChannel) - rawChats = await this.call({ - _: 'channels.getChannels', - id: [inputChannel], - }).then((res) => res.chats) - } + case 'updateShortChatMessage': { + if (noDispatch) return - this._date = update.date - this._pts = update.pts - - const { users, chats } = createUsersChatsIndex({ - users: rawUsers, - chats: rawChats, - }) - this.dispatchUpdate(message, users, chats) - } else if (update._ === 'updateShortChatMessage') { - if (noDispatch) return - - const message: tl.RawMessage = { - _: 'message', - out: update.out, - mentioned: update.mentioned, - mediaUnread: update.mediaUnread, - silent: update.silent, - id: update.id, - fromId: { - _: 'peerUser', - userId: update.fromId, - }, - peerId: { - _: 'peerChat', - chatId: update.chatId, - }, - fwdFrom: update.fwdFrom, - viaBotId: update.viaBotId, - replyTo: update.replyTo, - date: update.date, - message: update.message, - entities: update.entities, - ttlPeriod: update.ttlPeriod, - } - - // similarly to updateShortMessage, we need to fetch the sender - // user and the chat, and also handle "forwarded from" info. - const fwdFrom = update.fwdFrom?.fromId - ? peerToInputPeer(update.fwdFrom.fromId) - : undefined - - let rawUsers: tl.TypeUser[] - { - const id: tl.TypeInputUser[] = [ - { - _: 'inputUser', + const message: tl.RawMessage = { + _: 'message', + out: update.out, + mentioned: update.mentioned, + mediaUnread: update.mediaUnread, + silent: update.silent, + id: update.id, + fromId: { + _: 'peerUser', userId: update.fromId, - accessHash: bigInt.zero, }, - ] + peerId: { + _: 'peerChat', + chatId: update.chatId, + }, + fwdFrom: update.fwdFrom, + viaBotId: update.viaBotId, + replyTo: update.replyTo, + date: update.date, + message: update.message, + entities: update.entities, + ttlPeriod: update.ttlPeriod, + } + + // similarly to updateShortMessage, we need to fetch the sender + // user and the chat, and also handle "forwarded from" info. + const fwdFrom = update.fwdFrom?.fromId + ? peerToInputPeer(update.fwdFrom.fromId) + : undefined + + let rawUsers: tl.TypeUser[] + { + const id: tl.TypeInputUser[] = [ + { + _: 'inputUser', + userId: update.fromId, + accessHash: bigInt.zero, + }, + ] + + if (fwdFrom) { + const inputUser = normalizeToInputUser(fwdFrom) + if (inputUser) id.push(inputUser) + } + + rawUsers = await this.call({ + _: 'users.getUsers', + id, + }) + + if (rawUsers.length !== id.length) { + // user failed to load. + // first try checking for input peer in storage + const saved = await this.storage.getPeerById( + update.fromId + ) + if (saved) { + id[0] = normalizeToInputUser(saved)! + + rawUsers = await this.call({ + _: 'users.getUsers', + id, + }) + } + } + if (rawUsers.length !== id.length) { + // not saved (or invalid hash), not found by id + // find that user in chat participants list + const res = await this.call({ + _: 'messages.getFullChat', + chatId: update.chatId, + }) + + const user = res.users.find( + (it) => it.id === update.fromId + ) + if (!user) { + debug( + "received updateShortChatMessage, but wasn't able to find User" + ) + return + } + rawUsers.push(user) + } + } + const rawChats = await this.call({ + _: 'messages.getChats', + id: [update.chatId], + }).then((res) => res.chats) if (fwdFrom) { - const inputUser = normalizeToInputUser(fwdFrom) - if (inputUser) id.push(inputUser) - } - - rawUsers = await this.call({ - _: 'users.getUsers', - id, - }) - - if (rawUsers.length !== id.length) { - // user failed to load. - // first try checking for input peer in storage - const saved = await this.storage.getPeerById( - update.fromId - ) - if (saved) { - id[0] = normalizeToInputUser(saved)! - - rawUsers = await this.call({ - _: 'users.getUsers', - id, + const inputChannel = normalizeToInputChannel(fwdFrom) + if (inputChannel) { + const res = await this.call({ + _: 'channels.getChannels', + id: [inputChannel], }) + rawChats.push(...res.chats) } } - if (rawUsers.length !== id.length) { - // not saved (or invalid hash), not found by id - // find that user in chat participants list - const res = await this.call({ - _: 'messages.getFullChat', - chatId: update.chatId, - }) - const user = res.users.find( - (it) => it.id === update.fromId - ) - if (!user) { - debug( - "received updateShortChatMessage, but wasn't able to find User" - ) - return - } - rawUsers.push(user) - } + this._date = update.date + this._pts = update.pts + + const { users, chats } = createUsersChatsIndex({ + users: rawUsers, + chats: rawChats, + }) + this.dispatchUpdate(message, users, chats) + break } - const rawChats = await this.call({ - _: 'messages.getChats', - id: [update.chatId], - }).then((res) => res.chats) - - if (fwdFrom) { - const inputChannel = normalizeToInputChannel(fwdFrom) - if (inputChannel) { - const res = await this.call({ - _: 'channels.getChannels', - id: [inputChannel], - }) - rawChats.push(...res.chats) - } - } - - this._date = update.date - this._pts = update.pts - - const { users, chats } = createUsersChatsIndex({ - users: rawUsers, - chats: rawChats, - }) - this.dispatchUpdate(message, users, chats) - } else if (update._ === 'updateShortSentMessage') { - // only store the new pts and date values - // we never need to dispatch this - this._date = update.date - this._pts = update.pts + case 'updateShortSentMessage': // only store the new pts and date values + // we never need to dispatch this + this._date = update.date + this._pts = update.pts + break } }) .catch((err) => this._emitError(err)) diff --git a/packages/client/src/methods/users/resolve-peer.ts b/packages/client/src/methods/users/resolve-peer.ts index 3fbf4bfa..57ac66dd 100644 --- a/packages/client/src/methods/users/resolve-peer.ts +++ b/packages/client/src/methods/users/resolve-peer.ts @@ -56,33 +56,37 @@ export async function resolvePeer( const peerType = getBasicPeerType(peerId) - if (peerType === 'user') { - await this.call({ - _: 'users.getUsers', - id: [ - { - _: 'inputUser', - userId: peerId, - accessHash: bigInt.zero, - }, - ], - }) - } else if (peerType === 'chat') { - await this.call({ - _: 'messages.getChats', - id: [-peerId], - }) - } else if (peerType === 'channel') { - await this.call({ - _: 'channels.getChannels', - id: [ - { - _: 'inputChannel', - channelId: MAX_CHANNEL_ID - peerId, - accessHash: bigInt.zero, - }, - ], - }) + switch (peerType) { + case 'user': + await this.call({ + _: 'users.getUsers', + id: [ + { + _: 'inputUser', + userId: peerId, + accessHash: bigInt.zero, + }, + ], + }) + break + case 'chat': + await this.call({ + _: 'messages.getChats', + id: [-peerId], + }) + break + case 'channel': + await this.call({ + _: 'channels.getChannels', + id: [ + { + _: 'inputChannel', + channelId: MAX_CHANNEL_ID - peerId, + accessHash: bigInt.zero, + }, + ], + }) + break } const fromStorage = await this.storage.getPeerById(peerId) diff --git a/packages/client/src/types/media/thumbnail.ts b/packages/client/src/types/media/thumbnail.ts index 5ff66493..0a5cf4fe 100644 --- a/packages/client/src/types/media/thumbnail.ts +++ b/packages/client/src/types/media/thumbnail.ts @@ -75,29 +75,32 @@ export class Thumbnail extends FileLocation { | (() => tl.TypeInputFileLocation | Buffer) let size, width, height: number - if (sz._ === 'photoStrippedSize') { - location = strippedPhotoToJpg(sz.bytes) - width = height = NaN - size = location.length - } else if (sz._ === 'photoPathSize') { - // lazily - location = () => svgPathToFile(this._path!) - width = height = NaN - size = Infinity // this doesn't really matter - } else { - location = { - _: - media._ === 'photo' - ? 'inputPhotoFileLocation' - : 'inputDocumentFileLocation', - id: media.id, - fileReference: media.fileReference, - accessHash: media.accessHash, - thumbSize: sz.type, - } - width = sz.w - height = sz.h - size = sz._ === 'photoSize' ? sz.size : Math.max(...sz.sizes) + switch (sz._) { + case 'photoStrippedSize': + location = strippedPhotoToJpg(sz.bytes) + width = height = NaN + size = location.length + break + case 'photoPathSize': // lazily + location = () => svgPathToFile(this._path!) + width = height = NaN + size = Infinity // this doesn't really matter + break + default: + location = { + _: + media._ === 'photo' + ? 'inputPhotoFileLocation' + : 'inputDocumentFileLocation', + id: media.id, + fileReference: media.fileReference, + accessHash: media.accessHash, + thumbSize: sz.type, + } + width = sz.w + height = sz.h + size = sz._ === 'photoSize' ? sz.size : Math.max(...sz.sizes) + break } super(client, location, size, media.dcId) diff --git a/packages/client/src/types/messages/message.ts b/packages/client/src/types/messages/message.ts index f0c29d4f..2ef37c53 100644 --- a/packages/client/src/types/messages/message.ts +++ b/packages/client/src/types/messages/message.ts @@ -272,22 +272,26 @@ export class Message { if (fwd.fromName) { sender = fwd.fromName } else if (fwd.fromId) { - if (fwd.fromId._ === 'peerChannel') { - sender = new Chat( - this.client, - this._chats[fwd.fromId.channelId] - ) - } else if (fwd.fromId._ === 'peerUser') { - sender = new User( - this.client, - this._users[fwd.fromId.userId] - ) - } else - throw new MtCuteTypeAssertionError( - 'Message#forward (@ raw.fwdFrom.fromId)', - 'peerUser | peerChannel', - fwd.fromId._ - ) + switch (fwd.fromId._) { + case 'peerChannel': + sender = new Chat( + this.client, + this._chats[fwd.fromId.channelId] + ) + break + case 'peerUser': + sender = new User( + this.client, + this._users[fwd.fromId.userId] + ) + break + default: + throw new MtCuteTypeAssertionError( + 'Message#forward (@ raw.fwdFrom.fromId)', + 'peerUser | peerChannel', + fwd.fromId._ + ) + } } else { this._forward = null return this._forward @@ -431,31 +435,39 @@ export class Message { } else { const rm = this.raw.replyMarkup let markup: ReplyMarkup | null - if (rm._ === 'replyKeyboardHide') { - markup = { - type: 'reply_hide', - selective: rm.selective, - } - } else if (rm._ === 'replyKeyboardForceReply') { - markup = { - type: 'force_reply', - singleUse: rm.singleUse, - selective: rm.selective, - } - } else if (rm._ === 'replyKeyboardMarkup') { - markup = { - type: 'reply', - resize: rm.resize, - singleUse: rm.singleUse, - selective: rm.selective, - buttons: BotKeyboard._rowsTo2d(rm.rows), - } - } else if (rm._ === 'replyInlineMarkup') { - markup = { - type: 'inline', - buttons: BotKeyboard._rowsTo2d(rm.rows), - } - } else markup = null + switch (rm._) { + case 'replyKeyboardHide': + markup = { + type: 'reply_hide', + selective: rm.selective, + } + break + case 'replyKeyboardForceReply': + markup = { + type: 'force_reply', + singleUse: rm.singleUse, + selective: rm.selective, + } + break + case 'replyKeyboardMarkup': + markup = { + type: 'reply', + resize: rm.resize, + singleUse: rm.singleUse, + selective: rm.selective, + buttons: BotKeyboard._rowsTo2d(rm.rows), + } + break + case 'replyInlineMarkup': + markup = { + type: 'inline', + buttons: BotKeyboard._rowsTo2d(rm.rows), + } + break + default: + markup = null + break + } this._markup = markup } diff --git a/packages/client/src/types/peers/user.ts b/packages/client/src/types/peers/user.ts index 9342995c..e7b601bf 100644 --- a/packages/client/src/types/peers/user.ts +++ b/packages/client/src/types/peers/user.ts @@ -126,21 +126,29 @@ export class User { ret = 'long_time_ago' } else if (bot) { ret = 'bot' - } else if (us._ === 'userStatusOnline') { - ret = 'online' - date = new Date(us.expires * 1000) - } else if (us._ === 'userStatusOffline') { - ret = 'offline' - date = new Date(us.wasOnline * 1000) - } else if (us._ === 'userStatusRecently') { - ret = 'recently' - } else if (us._ === 'userStatusLastWeek') { - ret = 'within_week' - } else if (us._ === 'userStatusLastMonth') { - ret = 'within_month' - } else { - ret = 'long_time_ago' - } + } else + switch (us._) { + case 'userStatusOnline': + ret = 'online' + date = new Date(us.expires * 1000) + break + case 'userStatusOffline': + ret = 'offline' + date = new Date(us.wasOnline * 1000) + break + case 'userStatusRecently': + ret = 'recently' + break + case 'userStatusLastWeek': + ret = 'within_week' + break + case 'userStatusLastMonth': + ret = 'within_month' + break + default: + ret = 'long_time_ago' + break + } return { status: ret, diff --git a/packages/core/src/base-client.ts b/packages/core/src/base-client.ts index 827af1fb..89e10113 100644 --- a/packages/core/src/base-client.ts +++ b/packages/core/src/base-client.ts @@ -652,39 +652,45 @@ export class BaseTelegramClient { continue } - if (peer._ === 'user') { - parsedPeers.push({ - id: peer.id, - accessHash: peer.accessHash!, - username: peer.username?.toLowerCase() ?? null, - phone: peer.phone ?? null, - type: peer.bot ? 'bot' : 'user', - updated: 0, - fromMessage: peer.fromMessage, - }) - } else if (peer._ === 'chat' || peer._ === 'chatForbidden') { - parsedPeers.push({ - id: -peer.id, - accessHash: bigInt.zero, - username: null, - phone: null, - type: 'group', - updated: 0, - fromMessage: peer.fromMessage, - }) - } else if (peer._ === 'channel' || peer._ === 'channelForbidden') { - parsedPeers.push({ - id: MAX_CHANNEL_ID - peer.id, - accessHash: peer.accessHash!, - username: - peer._ === 'channel' - ? peer.username?.toLowerCase() ?? null - : null, - phone: null, - type: peer.broadcast ? 'channel' : 'supergroup', - updated: 0, - fromMessage: peer.fromMessage, - }) + switch (peer._) { + case 'user': + parsedPeers.push({ + id: peer.id, + accessHash: peer.accessHash!, + username: peer.username?.toLowerCase() ?? null, + phone: peer.phone ?? null, + type: peer.bot ? 'bot' : 'user', + updated: 0, + fromMessage: peer.fromMessage, + }) + break + case 'chat': + case 'chatForbidden': + parsedPeers.push({ + id: -peer.id, + accessHash: bigInt.zero, + username: null, + phone: null, + type: 'group', + updated: 0, + fromMessage: peer.fromMessage, + }) + break + case 'channel': + case 'channelForbidden': + parsedPeers.push({ + id: MAX_CHANNEL_ID - peer.id, + accessHash: peer.accessHash!, + username: + peer._ === 'channel' + ? peer.username?.toLowerCase() ?? null + : null, + phone: null, + type: peer.broadcast ? 'channel' : 'supergroup', + updated: 0, + fromMessage: peer.fromMessage, + }) + break } } diff --git a/packages/core/src/utils/peer-utils.ts b/packages/core/src/utils/peer-utils.ts index cc9661db..96af196b 100644 --- a/packages/core/src/utils/peer-utils.ts +++ b/packages/core/src/utils/peer-utils.ts @@ -74,9 +74,14 @@ export function getBasicPeerType(peer: tl.TypePeer | number): BasicPeerType { export function markedPeerIdToBare(peerId: number): number { const type = getBasicPeerType(peerId) - if (type === 'user') return peerId - else if (type === 'chat') return -peerId - else if (type === 'channel') return MAX_CHANNEL_ID - peerId + switch (type) { + case 'user': + return peerId + case 'chat': + return -peerId + case 'channel': + return MAX_CHANNEL_ID - peerId + } throw new Error('Invalid marked peer id') } diff --git a/packages/html-parser/src/index.ts b/packages/html-parser/src/index.ts index f0e77038..0a7b5613 100644 --- a/packages/html-parser/src/index.ts +++ b/packages/html-parser/src/index.ts @@ -60,88 +60,99 @@ export class HtmlMessageEntityParser implements IMessageEntityParser { name = name.toLowerCase() let entity: tl.TypeMessageEntity - if (name === 'b' || name === 'strong') { - entity = { - _: 'messageEntityBold', - offset: plainText.length, - length: 0, - } - } else if (name === 'i' || name === 'em') { - entity = { - _: 'messageEntityItalic', - offset: plainText.length, - length: 0, - } - } else if (name === 'u') { - entity = { - _: 'messageEntityUnderline', - offset: plainText.length, - length: 0, - } - } else if ( - name === 's' || - name === 'del' || - name === 'strike' - ) { - entity = { - _: 'messageEntityStrike', - offset: plainText.length, - length: 0, - } - } else if (name === 'blockquote') { - entity = { - _: 'messageEntityBlockquote', - offset: plainText.length, - length: 0, - } - } else if (name === 'code') { - entity = { - _: 'messageEntityCode', - offset: plainText.length, - length: 0, - } - } else if (name === 'pre') { - entity = { - _: 'messageEntityPre', - offset: plainText.length, - length: 0, - language: attribs.language ?? '', - } - } else if (name === 'a') { - const url = attribs.href - if (!url) return + switch (name) { + case 'b': + case 'strong': + entity = { + _: 'messageEntityBold', + offset: plainText.length, + length: 0, + } + break + case 'i': + case 'em': + entity = { + _: 'messageEntityItalic', + offset: plainText.length, + length: 0, + } + break + case 'u': + entity = { + _: 'messageEntityUnderline', + offset: plainText.length, + length: 0, + } + break + case 's': + case 'del': + case 'strike': + entity = { + _: 'messageEntityStrike', + offset: plainText.length, + length: 0, + } + break + case 'blockquote': + entity = { + _: 'messageEntityBlockquote', + offset: plainText.length, + length: 0, + } + break + case 'code': + entity = { + _: 'messageEntityCode', + offset: plainText.length, + length: 0, + } + break + case 'pre': + entity = { + _: 'messageEntityPre', + offset: plainText.length, + length: 0, + language: attribs.language ?? '', + } + break + case 'a': + const url = attribs.href + if (!url) return - const mention = MENTION_REGEX.exec(url) - if (mention) { - const accessHash = mention[2] - if (accessHash) { - entity = { - _: 'inputMessageEntityMentionName', - offset: plainText.length, - length: 0, - userId: { - _: 'inputUser', + const mention = MENTION_REGEX.exec(url) + if (mention) { + const accessHash = mention[2] + if (accessHash) { + entity = { + _: 'inputMessageEntityMentionName', + offset: plainText.length, + length: 0, + userId: { + _: 'inputUser', + userId: parseInt(mention[1]), + accessHash: bigInt(accessHash, 16), + }, + } + } else { + entity = { + _: 'messageEntityMentionName', + offset: plainText.length, + length: 0, userId: parseInt(mention[1]), - accessHash: bigInt(accessHash, 16), - }, + } } } else { entity = { - _: 'messageEntityMentionName', + _: 'messageEntityTextUrl', offset: plainText.length, length: 0, - userId: parseInt(mention[1]), + url, } } - } else { - entity = { - _: 'messageEntityTextUrl', - offset: plainText.length, - length: 0, - url, - } - } - } else return + break + default: + return + } if (!(name in stacks)) { stacks[name] = [] @@ -232,48 +243,56 @@ export class HtmlMessageEntityParser implements IMessageEntityParser { ) const type = entity.type - if ( - type === 'bold' || - type === 'italic' || - type === 'underline' || - type === 'strikethrough' - ) { - html.push(`<${type[0]}>${entityText}`) - } else if ( - type === 'code' || - type === 'pre' || - type === 'blockquote' - ) { - html.push( - `<${type}${ - type === 'pre' && entity.language - ? ` language="${entity.language}"` - : '' - }>${ - this._syntaxHighlighter - ? this._syntaxHighlighter( - entityText, - entity.language! - ) - : entityText - }` - ) - } else if (type === 'email') { - html.push(`${entityText}`) - } else if (type === 'url') { - html.push(`${entityText}`) - } else if (type === 'text_link') { - html.push( - `${entityText}` - ) - } else if (type == 'text_mention') { - html.push( - `${entityText}` - ) - } else skip = true + switch (type) { + case 'bold': + case 'italic': + case 'underline': + case 'strikethrough': + html.push(`<${type[0]}>${entityText}`) + break + case 'code': + case 'pre': + case 'blockquote': + html.push( + `<${type}${ + type === 'pre' && entity.language + ? ` language="${entity.language}"` + : '' + }>${ + this._syntaxHighlighter + ? this._syntaxHighlighter( + entityText, + entity.language! + ) + : entityText + }` + ) + break + case 'email': + html.push( + `${entityText}` + ) + break + case 'url': + html.push(`${entityText}`) + break + case 'text_link': + html.push( + `${entityText}` + ) + break + case 'text_mention': + html.push( + `${entityText}` + ) + break + default: + skip = true + break + } lastOffset = relativeOffset + (skip ? 0 : length) } diff --git a/packages/markdown-parser/src/index.ts b/packages/markdown-parser/src/index.ts index 2f60387d..70161515 100644 --- a/packages/markdown-parser/src/index.ts +++ b/packages/markdown-parser/src/index.ts @@ -209,10 +209,20 @@ export class MarkdownMessageEntityParser implements IMessageEntityParser { | 'Underline' | 'Strike' | null = null - if (c === '_') type = 'Italic' - else if (c === '*') type = 'Bold' - else if (c === '-') type = 'Underline' - else if (c === '~') type = 'Strike' + switch (c) { + case '_': + type = 'Italic' + break + case '*': + type = 'Bold' + break + case '-': + type = 'Underline' + break + case '~': + type = 'Strike' + break + } if (type) { if (!(type in stacks)) stacks[type] = [] @@ -288,32 +298,43 @@ export class MarkdownMessageEntityParser implements IMessageEntityParser { } let startTag, endTag: string - if (type === 'bold') { - startTag = endTag = TAG_BOLD - } else if (type === 'italic') { - startTag = endTag = TAG_ITALIC - } else if (type === 'underline') { - startTag = endTag = TAG_UNDERLINE - } else if (type === 'strikethrough') { - startTag = endTag = TAG_STRIKE - } else if (type === 'code') { - startTag = endTag = TAG_CODE - } else if (type === 'pre') { - startTag = TAG_PRE + switch (type) { + case 'bold': + startTag = endTag = TAG_BOLD + break + case 'italic': + startTag = endTag = TAG_ITALIC + break + case 'underline': + startTag = endTag = TAG_UNDERLINE + break + case 'strikethrough': + startTag = endTag = TAG_STRIKE + break + case 'code': + startTag = endTag = TAG_CODE + break + case 'pre': + startTag = TAG_PRE - if (entity.language) { - startTag += entity.language - } + if (entity.language) { + startTag += entity.language + } - startTag += '\n' - endTag = '\n' + TAG_PRE - } else if (type === 'text_link') { - startTag = '[' - endTag = `](${entity.url!})` - } else if (type === 'text_mention') { - startTag = '[' - endTag = `](tg://user?id=${entity.userId!})` - } else continue + startTag += '\n' + endTag = '\n' + TAG_PRE + break + case 'text_link': + startTag = '[' + endTag = `](${entity.url!})` + break + case 'text_mention': + startTag = '[' + endTag = `](tg://user?id=${entity.userId!})` + break + default: + continue + } insert.push([start, startTag]) insert.push([end, endTag])