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