refactor(dispatcher): big refactor, moved updates parsing to client, separated raw updates from parsed, moved Conversation to client package
This commit is contained in:
parent
8fb099cfeb
commit
627fdbed2f
27 changed files with 1008 additions and 1343 deletions
|
@ -4,6 +4,7 @@ const fs = require('fs')
|
||||||
const prettier = require('prettier')
|
const prettier = require('prettier')
|
||||||
// not the best way but who cares lol
|
// not the best way but who cares lol
|
||||||
const { createWriter } = require('../../tl/scripts/common')
|
const { createWriter } = require('../../tl/scripts/common')
|
||||||
|
const updates = require('./generate-updates')
|
||||||
|
|
||||||
const targetDir = path.join(__dirname, '../src')
|
const targetDir = path.join(__dirname, '../src')
|
||||||
|
|
||||||
|
@ -299,6 +300,32 @@ async function main() {
|
||||||
)
|
)
|
||||||
output.tab()
|
output.tab()
|
||||||
|
|
||||||
|
output.write(`/**
|
||||||
|
* Register a raw update handler
|
||||||
|
*
|
||||||
|
* @param name Event name
|
||||||
|
* @param handler Raw update handler
|
||||||
|
*/
|
||||||
|
on(name: 'raw_update', handler: ((upd: tl.TypeUpdate | tl.TypeMessage, users: UsersIndex, chats: ChatsIndex) => void)): this
|
||||||
|
/**
|
||||||
|
* Register a parsed update handler
|
||||||
|
*
|
||||||
|
* @param name Event name
|
||||||
|
* @param handler Raw update handler
|
||||||
|
*/
|
||||||
|
on(name: 'update', handler: ((upd: ParsedUpdate) => void)): this`)
|
||||||
|
|
||||||
|
updates.types.forEach((type) => {
|
||||||
|
output.write(`/**
|
||||||
|
* Register ${updates.toSentence(type, 'inline')}
|
||||||
|
*
|
||||||
|
* @param name Event name
|
||||||
|
* @param handler ${updates.toSentence(type, 'full')}
|
||||||
|
*/
|
||||||
|
on(name: '${type.typeName}', handler: ((upd: ${type.updateType}) => void)): this`)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
const printer = ts.createPrinter()
|
const printer = ts.createPrinter()
|
||||||
|
|
||||||
const classContents = []
|
const classContents = []
|
||||||
|
|
326
packages/client/scripts/generate-updates.js
Normal file
326
packages/client/scripts/generate-updates.js
Normal file
|
@ -0,0 +1,326 @@
|
||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
|
const prettier = require('prettier')
|
||||||
|
const {
|
||||||
|
snakeToCamel,
|
||||||
|
camelToPascal,
|
||||||
|
camelToSnake,
|
||||||
|
} = require('../../tl/scripts/common')
|
||||||
|
|
||||||
|
function parseUpdateTypes() {
|
||||||
|
const lines = fs
|
||||||
|
.readFileSync(path.join(__dirname, 'update-types.txt'), 'utf-8')
|
||||||
|
.split('\n')
|
||||||
|
.map((it) => it.trim())
|
||||||
|
.filter((it) => it && it[0] !== '#')
|
||||||
|
|
||||||
|
const ret = []
|
||||||
|
|
||||||
|
for (const line of lines) {
|
||||||
|
const m = line.match(/^([a-z_]+)(?:: ([a-zA-Z]+))? = ([a-zA-Z]+)( \+ State)?$/)
|
||||||
|
if (!m) throw new Error(`invalid syntax: ${line}`)
|
||||||
|
ret.push({
|
||||||
|
typeName: m[1],
|
||||||
|
handlerTypeName: m[2] || camelToPascal(snakeToCamel(m[1])),
|
||||||
|
updateType: m[3],
|
||||||
|
funcName: m[2]
|
||||||
|
? m[2][0].toLowerCase() + m[2].substr(1)
|
||||||
|
: snakeToCamel(m[1]),
|
||||||
|
state: !!m[4]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
function replaceSections(filename, sections, dir = __dirname) {
|
||||||
|
let lines = fs
|
||||||
|
.readFileSync(path.join(dir, '../src', filename), 'utf-8')
|
||||||
|
.split('\n')
|
||||||
|
|
||||||
|
const findMarker = (marker) => {
|
||||||
|
const idx = lines.findIndex((line) => line.trim() === `// ${marker}`)
|
||||||
|
if (idx === -1) throw new Error(marker + ' not found')
|
||||||
|
return idx
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [name, content] of Object.entries(sections)) {
|
||||||
|
const start = findMarker(`begin-${name}`)
|
||||||
|
const end = findMarker(`end-${name}`)
|
||||||
|
|
||||||
|
if (start > end) throw new Error('begin is after end')
|
||||||
|
|
||||||
|
lines.splice(start + 1, end - start - 1, content)
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFileSync(path.join(dir, '../src', filename), lines.join('\n'))
|
||||||
|
}
|
||||||
|
|
||||||
|
const types = parseUpdateTypes()
|
||||||
|
|
||||||
|
async function formatFile(filename, dir = __dirname) {
|
||||||
|
const targetFile = path.join(dir, '../src/', filename)
|
||||||
|
const prettierConfig = await prettier.resolveConfig(targetFile)
|
||||||
|
let fullSource = await fs.promises.readFile(targetFile, 'utf-8')
|
||||||
|
fullSource = await prettier.format(fullSource, {
|
||||||
|
...(prettierConfig || {}),
|
||||||
|
filepath: targetFile,
|
||||||
|
})
|
||||||
|
await fs.promises.writeFile(targetFile, fullSource)
|
||||||
|
}
|
||||||
|
|
||||||
|
function toSentence(type, stype = 'inline') {
|
||||||
|
const name = camelToSnake(type.handlerTypeName)
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/_/g, ' ')
|
||||||
|
|
||||||
|
if (stype === 'inline') {
|
||||||
|
return `${name[0].match(/[aeiouy]/i) ? 'an' : 'a'} ${name} handler`
|
||||||
|
} else if (stype === 'plain') {
|
||||||
|
return `${name} handler`
|
||||||
|
} else {
|
||||||
|
return `${name[0].toUpperCase()}${name.substr(1)} handler`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// function generateHandler() {
|
||||||
|
// const lines = []
|
||||||
|
// const names = ['RawUpdateHandler']
|
||||||
|
//
|
||||||
|
// // imports must be added manually because yeah
|
||||||
|
//
|
||||||
|
// types.forEach((type) => {
|
||||||
|
// if (type.updateType === 'IGNORE') return
|
||||||
|
//
|
||||||
|
// lines.push(
|
||||||
|
// `export type ${type.handlerTypeName}Handler<T = ${type.updateType}` +
|
||||||
|
// `${type.state ? ', S = never' : ''}> = ParsedUpdateHandler<` +
|
||||||
|
// `'${type.typeName}', T${type.state ? ', S' : ''}>`
|
||||||
|
// )
|
||||||
|
// names.push(`${type.handlerTypeName}Handler`)
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// replaceSections('handler.ts', {
|
||||||
|
// codegen:
|
||||||
|
// lines.join('\n') +
|
||||||
|
// '\n\nexport type UpdateHandler = \n' +
|
||||||
|
// names.map((i) => ` | ${i}\n`).join(''),
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// function generateBuilders() {
|
||||||
|
// const lines = []
|
||||||
|
// const imports = ['UpdateHandler']
|
||||||
|
//
|
||||||
|
// types.forEach((type) => {
|
||||||
|
// imports.push(`${type.handlerTypeName}Handler`)
|
||||||
|
//
|
||||||
|
// if (type.updateType === 'IGNORE') {
|
||||||
|
// lines.push(`
|
||||||
|
// /**
|
||||||
|
// * Create ${toSentence(type)}
|
||||||
|
// *
|
||||||
|
// * @param handler ${toSentence(type, 'full')}
|
||||||
|
// */
|
||||||
|
// export function ${type.funcName}(
|
||||||
|
// handler: ${type.handlerTypeName}Handler['callback']
|
||||||
|
// ): ${type.handlerTypeName}Handler
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * Create ${toSentence(type)} with a filter
|
||||||
|
// *
|
||||||
|
// * @param filter Predicate to check the update against
|
||||||
|
// * @param handler ${toSentence(type, 'full')}
|
||||||
|
// */
|
||||||
|
// export function ${type.funcName}(
|
||||||
|
// filter: ${type.handlerTypeName}Handler['check'],
|
||||||
|
// handler: ${type.handlerTypeName}Handler['callback']
|
||||||
|
// ): ${type.handlerTypeName}Handler
|
||||||
|
//
|
||||||
|
// /** @internal */
|
||||||
|
// export function ${type.funcName}(filter: any, handler?: any): ${
|
||||||
|
// type.handlerTypeName
|
||||||
|
// }Handler {
|
||||||
|
// return _create('${type.typeName}', filter, handler)
|
||||||
|
// }
|
||||||
|
// `)
|
||||||
|
// } else {
|
||||||
|
// lines.push(`
|
||||||
|
// /**
|
||||||
|
// * Create ${toSentence(type)}
|
||||||
|
// *
|
||||||
|
// * @param handler ${toSentence(type, 'full')}
|
||||||
|
// */
|
||||||
|
// export function ${type.funcName}(
|
||||||
|
// handler: ${type.handlerTypeName}Handler['callback']
|
||||||
|
// ): ${type.handlerTypeName}Handler
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * Create ${toSentence(type)} with a filter
|
||||||
|
// *
|
||||||
|
// * @param filter Update filter
|
||||||
|
// * @param handler ${toSentence(type, 'full')}
|
||||||
|
// */
|
||||||
|
// export function ${type.funcName}<Mod>(
|
||||||
|
// filter: UpdateFilter<${type.updateType}, Mod>,
|
||||||
|
// handler: ${type.handlerTypeName}Handler<
|
||||||
|
// filters.Modify<${type.updateType}, Mod>
|
||||||
|
// >['callback']
|
||||||
|
// ): ${type.handlerTypeName}Handler
|
||||||
|
//
|
||||||
|
// /** @internal */
|
||||||
|
// export function ${type.funcName}(
|
||||||
|
// filter: any,
|
||||||
|
// handler?: any
|
||||||
|
// ): ${type.handlerTypeName}Handler {
|
||||||
|
// return _create('${type.typeName}', filter, handler)
|
||||||
|
// }
|
||||||
|
// `)
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// replaceSections('builders.ts', {
|
||||||
|
// codegen: lines.join('\n'),
|
||||||
|
// 'codegen-imports':
|
||||||
|
// 'import {\n' +
|
||||||
|
// imports.map((i) => ` ${i},\n`).join('') +
|
||||||
|
// "} from './handler'",
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// function generateDispatcher() {
|
||||||
|
// const lines = []
|
||||||
|
// const declareLines = []
|
||||||
|
// const imports = ['UpdateHandler']
|
||||||
|
//
|
||||||
|
// types.forEach((type) => {
|
||||||
|
// imports.push(`${type.handlerTypeName}Handler`)
|
||||||
|
//
|
||||||
|
// if (type.updateType === 'IGNORE') {
|
||||||
|
// declareLines.push(`
|
||||||
|
// /**
|
||||||
|
// * Register a plain old ${toSentence(type, 'plain')}
|
||||||
|
// *
|
||||||
|
// * @param name Event name
|
||||||
|
// * @param handler ${toSentence(type, 'full')}
|
||||||
|
// */
|
||||||
|
// on(name: '${type.typeName}', handler: ${type.handlerTypeName}Handler['callback']): this
|
||||||
|
// `)
|
||||||
|
//
|
||||||
|
// lines.push(`
|
||||||
|
// /**
|
||||||
|
// * Register ${toSentence(type)} without any filters
|
||||||
|
// *
|
||||||
|
// * @param handler ${toSentence(type, 'full')}
|
||||||
|
// * @param group Handler group index
|
||||||
|
// */
|
||||||
|
// on${type.handlerTypeName}(handler: ${type.handlerTypeName}Handler['callback'], group?: number): void
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * Register ${toSentence(type)} with a filter
|
||||||
|
// *
|
||||||
|
// * @param filter Update filter function
|
||||||
|
// * @param handler ${toSentence(type, 'full')}
|
||||||
|
// * @param group Handler group index
|
||||||
|
// */
|
||||||
|
// on${type.handlerTypeName}(
|
||||||
|
// filter: ${type.handlerTypeName}Handler['check'],
|
||||||
|
// handler: ${type.handlerTypeName}Handler['callback'],
|
||||||
|
// group?: number
|
||||||
|
// ): void
|
||||||
|
//
|
||||||
|
// /** @internal */
|
||||||
|
// on${type.handlerTypeName}(filter: any, handler?: any, group?: number): void {
|
||||||
|
// this._addKnownHandler('${type.funcName}', filter, handler, group)
|
||||||
|
// }
|
||||||
|
// `)
|
||||||
|
// } else {
|
||||||
|
// declareLines.push(`
|
||||||
|
// /**
|
||||||
|
// * Register a plain old ${toSentence(type, 'plain')}
|
||||||
|
// *
|
||||||
|
// * @param name Event name
|
||||||
|
// * @param handler ${toSentence(type, 'full')}
|
||||||
|
// */
|
||||||
|
// on(name: '${type.typeName}', handler: ${type.handlerTypeName}Handler['callback']): this
|
||||||
|
//
|
||||||
|
// `)
|
||||||
|
// lines.push(`
|
||||||
|
// /**
|
||||||
|
// * Register ${toSentence(type)} without any filters
|
||||||
|
// *
|
||||||
|
// * @param handler ${toSentence(type, 'full')}
|
||||||
|
// * @param group Handler group index
|
||||||
|
// */
|
||||||
|
// on${type.handlerTypeName}(handler: ${type.handlerTypeName}Handler${type.state ? `<${type.updateType}, State extends never ? never : UpdateState<State, SceneName>>` : ''}['callback'], group?: number): void
|
||||||
|
//
|
||||||
|
// ${type.state ? `
|
||||||
|
// /**
|
||||||
|
// * Register ${toSentence(type)} with a filter
|
||||||
|
// *
|
||||||
|
// * @param filter Update filter
|
||||||
|
// * @param handler ${toSentence(type, 'full')}
|
||||||
|
// * @param group Handler group index
|
||||||
|
// */
|
||||||
|
// on${type.handlerTypeName}<Mod>(
|
||||||
|
// filter: UpdateFilter<${type.updateType}, Mod, State>,
|
||||||
|
// handler: ${type.handlerTypeName}Handler<filters.Modify<${type.updateType}, Mod>, State extends never ? never : UpdateState<State, SceneName>>['callback'],
|
||||||
|
// group?: number
|
||||||
|
// ): void
|
||||||
|
// ` : ''}
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * Register ${toSentence(type)} with a filter
|
||||||
|
// *
|
||||||
|
// * @param filter Update filter
|
||||||
|
// * @param handler ${toSentence(type, 'full')}
|
||||||
|
// * @param group Handler group index
|
||||||
|
// */
|
||||||
|
// on${type.handlerTypeName}<Mod>(
|
||||||
|
// filter: UpdateFilter<${type.updateType}, Mod>,
|
||||||
|
// handler: ${type.handlerTypeName}Handler<filters.Modify<${type.updateType}, Mod>${type.state ? ', State extends never ? never : UpdateState<State, SceneName>' : ''}>['callback'],
|
||||||
|
// group?: number
|
||||||
|
// ): void
|
||||||
|
//
|
||||||
|
// /** @internal */
|
||||||
|
// on${type.handlerTypeName}(filter: any, handler?: any, group?: number): void {
|
||||||
|
// this._addKnownHandler('${type.funcName}', filter, handler, group)
|
||||||
|
// }
|
||||||
|
// `)
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// replaceSections('dispatcher.ts', {
|
||||||
|
// codegen: lines.join('\n'),
|
||||||
|
// 'codegen-declare': declareLines.join('\n'),
|
||||||
|
// 'codegen-imports':
|
||||||
|
// 'import {\n' +
|
||||||
|
// imports.map((i) => ` ${i},\n`).join('') +
|
||||||
|
// "} from './handler'",
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
|
||||||
|
function generateParsedUpdate() {
|
||||||
|
replaceSections('types/updates/index.ts', {
|
||||||
|
codegen: 'export type ParsedUpdate =\n'
|
||||||
|
+ types.map((typ) => ` | { name: '${typ.typeName}', data: ${typ.updateType} }\n`).join(''),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
generateParsedUpdate()
|
||||||
|
// generateBuilders()
|
||||||
|
// generateHandler()
|
||||||
|
// generateDispatcher()
|
||||||
|
|
||||||
|
// await formatFile('builders.ts')
|
||||||
|
// await formatFile('handler.ts')
|
||||||
|
// await formatFile('dispatcher.ts')
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { types, toSentence, replaceSections, formatFile }
|
||||||
|
|
||||||
|
if (require.main === module) {
|
||||||
|
main().catch(console.error)
|
||||||
|
}
|
|
@ -1,6 +1,4 @@
|
||||||
# format: type_name[: handler_type_name] = update_type[ + State]
|
# format: type_name[: handler_type_name] = update_type[ + State]
|
||||||
# IGNORE as update_type disables filters modification
|
|
||||||
raw: RawUpdate = IGNORE
|
|
||||||
new_message = Message + State
|
new_message = Message + State
|
||||||
edit_message = Message + State
|
edit_message = Message + State
|
||||||
delete_message = DeleteMessageUpdate
|
delete_message = DeleteMessageUpdate
|
|
@ -142,12 +142,12 @@ import { getStickerSet } from './methods/stickers/get-sticker-set'
|
||||||
import { moveStickerInSet } from './methods/stickers/move-sticker-in-set'
|
import { moveStickerInSet } from './methods/stickers/move-sticker-in-set'
|
||||||
import { setStickerSetThumb } from './methods/stickers/set-sticker-set-thumb'
|
import { setStickerSetThumb } from './methods/stickers/set-sticker-set-thumb'
|
||||||
import {
|
import {
|
||||||
|
_dispatchUpdate,
|
||||||
_fetchUpdatesState,
|
_fetchUpdatesState,
|
||||||
_handleUpdate,
|
_handleUpdate,
|
||||||
_loadStorage,
|
_loadStorage,
|
||||||
_saveStorage,
|
_saveStorage,
|
||||||
catchUp,
|
catchUp,
|
||||||
dispatchUpdate,
|
|
||||||
} from './methods/updates'
|
} from './methods/updates'
|
||||||
import { blockUser } from './methods/users/block-user'
|
import { blockUser } from './methods/users/block-user'
|
||||||
import { deleteProfilePhotos } from './methods/users/delete-profile-photos'
|
import { deleteProfilePhotos } from './methods/users/delete-profile-photos'
|
||||||
|
@ -168,17 +168,23 @@ import { Readable } from 'stream'
|
||||||
import {
|
import {
|
||||||
ArrayWithTotal,
|
ArrayWithTotal,
|
||||||
BotCommands,
|
BotCommands,
|
||||||
|
CallbackQuery,
|
||||||
Chat,
|
Chat,
|
||||||
ChatEvent,
|
ChatEvent,
|
||||||
ChatInviteLink,
|
ChatInviteLink,
|
||||||
ChatMember,
|
ChatMember,
|
||||||
|
ChatMemberUpdate,
|
||||||
ChatPreview,
|
ChatPreview,
|
||||||
ChatsIndex,
|
ChatsIndex,
|
||||||
|
ChosenInlineResult,
|
||||||
|
DeleteMessageUpdate,
|
||||||
Dialog,
|
Dialog,
|
||||||
FileDownloadParameters,
|
FileDownloadParameters,
|
||||||
FormattedString,
|
FormattedString,
|
||||||
GameHighScore,
|
GameHighScore,
|
||||||
|
HistoryReadUpdate,
|
||||||
IMessageEntityParser,
|
IMessageEntityParser,
|
||||||
|
InlineQuery,
|
||||||
InputFileLike,
|
InputFileLike,
|
||||||
InputInlineResult,
|
InputInlineResult,
|
||||||
InputMediaLike,
|
InputMediaLike,
|
||||||
|
@ -187,10 +193,13 @@ import {
|
||||||
MaybeDynamic,
|
MaybeDynamic,
|
||||||
Message,
|
Message,
|
||||||
MessageMedia,
|
MessageMedia,
|
||||||
|
ParsedUpdate,
|
||||||
PartialExcept,
|
PartialExcept,
|
||||||
PartialOnly,
|
PartialOnly,
|
||||||
Photo,
|
Photo,
|
||||||
Poll,
|
Poll,
|
||||||
|
PollUpdate,
|
||||||
|
PollVoteUpdate,
|
||||||
RawDocument,
|
RawDocument,
|
||||||
ReplyMarkup,
|
ReplyMarkup,
|
||||||
SentCode,
|
SentCode,
|
||||||
|
@ -201,6 +210,8 @@ import {
|
||||||
UploadFileLike,
|
UploadFileLike,
|
||||||
UploadedFile,
|
UploadedFile,
|
||||||
User,
|
User,
|
||||||
|
UserStatusUpdate,
|
||||||
|
UserTypingUpdate,
|
||||||
UsersIndex,
|
UsersIndex,
|
||||||
} from './types'
|
} from './types'
|
||||||
import {
|
import {
|
||||||
|
@ -212,6 +223,117 @@ import {
|
||||||
import { tdFileId } from '@mtcute/file-id'
|
import { tdFileId } from '@mtcute/file-id'
|
||||||
|
|
||||||
export interface TelegramClient extends BaseTelegramClient {
|
export interface TelegramClient extends BaseTelegramClient {
|
||||||
|
/**
|
||||||
|
* Register a raw update handler
|
||||||
|
*
|
||||||
|
* @param name Event name
|
||||||
|
* @param handler Raw update handler
|
||||||
|
*/
|
||||||
|
on(
|
||||||
|
name: 'raw_update',
|
||||||
|
handler: (
|
||||||
|
upd: tl.TypeUpdate | tl.TypeMessage,
|
||||||
|
users: UsersIndex,
|
||||||
|
chats: ChatsIndex
|
||||||
|
) => void
|
||||||
|
): this
|
||||||
|
/**
|
||||||
|
* Register a parsed update handler
|
||||||
|
*
|
||||||
|
* @param name Event name
|
||||||
|
* @param handler Raw update handler
|
||||||
|
*/
|
||||||
|
on(name: 'update', handler: (upd: ParsedUpdate) => void): this
|
||||||
|
/**
|
||||||
|
* Register a new message handler
|
||||||
|
*
|
||||||
|
* @param name Event name
|
||||||
|
* @param handler New message handler
|
||||||
|
*/
|
||||||
|
on(name: 'new_message', handler: (upd: Message) => void): this
|
||||||
|
/**
|
||||||
|
* Register an edit message handler
|
||||||
|
*
|
||||||
|
* @param name Event name
|
||||||
|
* @param handler Edit message handler
|
||||||
|
*/
|
||||||
|
on(name: 'edit_message', handler: (upd: Message) => void): this
|
||||||
|
/**
|
||||||
|
* Register a delete message handler
|
||||||
|
*
|
||||||
|
* @param name Event name
|
||||||
|
* @param handler Delete message handler
|
||||||
|
*/
|
||||||
|
on(
|
||||||
|
name: 'delete_message',
|
||||||
|
handler: (upd: DeleteMessageUpdate) => void
|
||||||
|
): this
|
||||||
|
/**
|
||||||
|
* Register a chat member update handler
|
||||||
|
*
|
||||||
|
* @param name Event name
|
||||||
|
* @param handler Chat member update handler
|
||||||
|
*/
|
||||||
|
on(name: 'chat_member', handler: (upd: ChatMemberUpdate) => void): this
|
||||||
|
/**
|
||||||
|
* Register an inline query handler
|
||||||
|
*
|
||||||
|
* @param name Event name
|
||||||
|
* @param handler Inline query handler
|
||||||
|
*/
|
||||||
|
on(name: 'inline_query', handler: (upd: InlineQuery) => void): this
|
||||||
|
/**
|
||||||
|
* Register a chosen inline result handler
|
||||||
|
*
|
||||||
|
* @param name Event name
|
||||||
|
* @param handler Chosen inline result handler
|
||||||
|
*/
|
||||||
|
on(
|
||||||
|
name: 'chosen_inline_result',
|
||||||
|
handler: (upd: ChosenInlineResult) => void
|
||||||
|
): this
|
||||||
|
/**
|
||||||
|
* Register a callback query handler
|
||||||
|
*
|
||||||
|
* @param name Event name
|
||||||
|
* @param handler Callback query handler
|
||||||
|
*/
|
||||||
|
on(name: 'callback_query', handler: (upd: CallbackQuery) => void): this
|
||||||
|
/**
|
||||||
|
* Register a poll update handler
|
||||||
|
*
|
||||||
|
* @param name Event name
|
||||||
|
* @param handler Poll update handler
|
||||||
|
*/
|
||||||
|
on(name: 'poll', handler: (upd: PollUpdate) => void): this
|
||||||
|
/**
|
||||||
|
* Register a poll vote handler
|
||||||
|
*
|
||||||
|
* @param name Event name
|
||||||
|
* @param handler Poll vote handler
|
||||||
|
*/
|
||||||
|
on(name: 'poll_vote', handler: (upd: PollVoteUpdate) => void): this
|
||||||
|
/**
|
||||||
|
* Register an user status update handler
|
||||||
|
*
|
||||||
|
* @param name Event name
|
||||||
|
* @param handler User status update handler
|
||||||
|
*/
|
||||||
|
on(name: 'user_status', handler: (upd: UserStatusUpdate) => void): this
|
||||||
|
/**
|
||||||
|
* Register an user typing handler
|
||||||
|
*
|
||||||
|
* @param name Event name
|
||||||
|
* @param handler User typing handler
|
||||||
|
*/
|
||||||
|
on(name: 'user_typing', handler: (upd: UserTypingUpdate) => void): this
|
||||||
|
/**
|
||||||
|
* Register a history read handler
|
||||||
|
*
|
||||||
|
* @param name Event name
|
||||||
|
* @param handler History read handler
|
||||||
|
*/
|
||||||
|
on(name: 'history_read', handler: (upd: HistoryReadUpdate) => void): this
|
||||||
/**
|
/**
|
||||||
* Accept the given TOS
|
* Accept the given TOS
|
||||||
*
|
*
|
||||||
|
@ -3110,29 +3232,6 @@ export interface TelegramClient extends BaseTelegramClient {
|
||||||
progressCallback?: (uploaded: number, total: number) => void
|
progressCallback?: (uploaded: number, total: number) => void
|
||||||
}
|
}
|
||||||
): Promise<StickerSet>
|
): Promise<StickerSet>
|
||||||
/**
|
|
||||||
* Base function for update handling. Replace or override this function
|
|
||||||
* and implement your own update handler, and call this function
|
|
||||||
* to handle externally obtained or manually crafted updates.
|
|
||||||
*
|
|
||||||
* Note that this function is called every time an `Update` is received,
|
|
||||||
* not `Updates`. Low-level updates containers are parsed by the library,
|
|
||||||
* and you receive ready to use updates and related entities.
|
|
||||||
* Also note that entity maps may contain entities that are not
|
|
||||||
* used in this particular update, so do not rely on its contents.
|
|
||||||
*
|
|
||||||
* `update` might contain a Message object - in this case,
|
|
||||||
* it should be interpreted as some kind of `updateNewMessage`.
|
|
||||||
*
|
|
||||||
* @param update Update that has just happened
|
|
||||||
* @param users Map of users in this update
|
|
||||||
* @param chats Map of chats in this update
|
|
||||||
*/
|
|
||||||
dispatchUpdate(
|
|
||||||
update: tl.TypeUpdate | tl.TypeMessage,
|
|
||||||
users: UsersIndex,
|
|
||||||
chats: ChatsIndex
|
|
||||||
): void
|
|
||||||
_handleUpdate(update: tl.TypeUpdates, noDispatch?: boolean): void
|
_handleUpdate(update: tl.TypeUpdates, noDispatch?: boolean): void
|
||||||
/**
|
/**
|
||||||
* Catch up with the server by loading missed updates.
|
* Catch up with the server by loading missed updates.
|
||||||
|
@ -3524,7 +3623,7 @@ export class TelegramClient extends BaseTelegramClient {
|
||||||
protected _fetchUpdatesState = _fetchUpdatesState
|
protected _fetchUpdatesState = _fetchUpdatesState
|
||||||
protected _loadStorage = _loadStorage
|
protected _loadStorage = _loadStorage
|
||||||
protected _saveStorage = _saveStorage
|
protected _saveStorage = _saveStorage
|
||||||
dispatchUpdate = dispatchUpdate
|
protected _dispatchUpdate = _dispatchUpdate
|
||||||
_handleUpdate = _handleUpdate
|
_handleUpdate = _handleUpdate
|
||||||
catchUp = catchUp
|
catchUp = catchUp
|
||||||
blockUser = blockUser
|
blockUser = blockUser
|
||||||
|
|
|
@ -40,7 +40,18 @@ import {
|
||||||
MessageMedia,
|
MessageMedia,
|
||||||
RawDocument,
|
RawDocument,
|
||||||
IMessageEntityParser,
|
IMessageEntityParser,
|
||||||
FormattedString
|
FormattedString,
|
||||||
|
CallbackQuery,
|
||||||
|
ChatMemberUpdate,
|
||||||
|
ChosenInlineResult,
|
||||||
|
DeleteMessageUpdate,
|
||||||
|
HistoryReadUpdate,
|
||||||
|
InlineQuery,
|
||||||
|
ParsedUpdate,
|
||||||
|
PollUpdate,
|
||||||
|
PollVoteUpdate,
|
||||||
|
UserStatusUpdate,
|
||||||
|
UserTypingUpdate,
|
||||||
} from '../types'
|
} from '../types'
|
||||||
|
|
||||||
// @copy
|
// @copy
|
||||||
|
|
|
@ -14,6 +14,7 @@ import {
|
||||||
} from '@mtcute/core'
|
} from '@mtcute/core'
|
||||||
import { isDummyUpdate, isDummyUpdates } from '../utils/updates-utils'
|
import { isDummyUpdate, isDummyUpdates } from '../utils/updates-utils'
|
||||||
import { ChatsIndex, UsersIndex } from '../types'
|
import { ChatsIndex, UsersIndex } from '../types'
|
||||||
|
import { _parseUpdate } from '../utils/parse-update'
|
||||||
|
|
||||||
const debug = require('debug')('mtcute:upds')
|
const debug = require('debug')('mtcute:upds')
|
||||||
|
|
||||||
|
@ -155,31 +156,21 @@ export async function _saveStorage(
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base function for update handling. Replace or override this function
|
|
||||||
* and implement your own update handler, and call this function
|
|
||||||
* to handle externally obtained or manually crafted updates.
|
|
||||||
*
|
|
||||||
* Note that this function is called every time an `Update` is received,
|
|
||||||
* not `Updates`. Low-level updates containers are parsed by the library,
|
|
||||||
* and you receive ready to use updates and related entities.
|
|
||||||
* Also note that entity maps may contain entities that are not
|
|
||||||
* used in this particular update, so do not rely on its contents.
|
|
||||||
*
|
|
||||||
* `update` might contain a Message object - in this case,
|
|
||||||
* it should be interpreted as some kind of `updateNewMessage`.
|
|
||||||
*
|
|
||||||
* @param update Update that has just happened
|
|
||||||
* @param users Map of users in this update
|
|
||||||
* @param chats Map of chats in this update
|
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
export function dispatchUpdate(
|
export function _dispatchUpdate(
|
||||||
this: TelegramClient,
|
this: TelegramClient,
|
||||||
update: tl.TypeUpdate | tl.TypeMessage,
|
update: tl.TypeUpdate | tl.TypeMessage,
|
||||||
users: UsersIndex,
|
users: UsersIndex,
|
||||||
chats: ChatsIndex
|
chats: ChatsIndex
|
||||||
): void {
|
): void {
|
||||||
// no-op //
|
this.emit('raw_update', update, users, chats)
|
||||||
|
|
||||||
|
const parsed = _parseUpdate(this, update, users, chats)
|
||||||
|
if (parsed) {
|
||||||
|
this.emit('update', parsed)
|
||||||
|
this.emit(parsed.name, parsed.data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface NoDispatchIndex {
|
interface NoDispatchIndex {
|
||||||
|
@ -441,7 +432,7 @@ async function _loadDifference(
|
||||||
if (noDispatch.msg[cid]?.[message.id]) return
|
if (noDispatch.msg[cid]?.[message.id]) return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.dispatchUpdate(message, users, chats)
|
this._dispatchUpdate(message, users, chats)
|
||||||
})
|
})
|
||||||
|
|
||||||
for (const upd of diff.otherUpdates) {
|
for (const upd of diff.otherUpdates) {
|
||||||
|
@ -495,7 +486,7 @@ async function _loadDifference(
|
||||||
if (noDispatch.pts[cid ?? 0]?.[pts]) continue
|
if (noDispatch.pts[cid ?? 0]?.[pts]) continue
|
||||||
}
|
}
|
||||||
|
|
||||||
this.dispatchUpdate(upd, users, chats)
|
this._dispatchUpdate(upd, users, chats)
|
||||||
}
|
}
|
||||||
|
|
||||||
this._pts = state.pts
|
this._pts = state.pts
|
||||||
|
@ -556,7 +547,7 @@ async function _loadChannelDifference(
|
||||||
return
|
return
|
||||||
if (message._ === 'messageEmpty') return
|
if (message._ === 'messageEmpty') return
|
||||||
|
|
||||||
this.dispatchUpdate(message, users, chats)
|
this._dispatchUpdate(message, users, chats)
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -565,7 +556,7 @@ async function _loadChannelDifference(
|
||||||
if (noDispatch && noDispatch.msg[channelId]?.[message.id]) return
|
if (noDispatch && noDispatch.msg[channelId]?.[message.id]) return
|
||||||
if (message._ === 'messageEmpty') return
|
if (message._ === 'messageEmpty') return
|
||||||
|
|
||||||
this.dispatchUpdate(message, users, chats)
|
this._dispatchUpdate(message, users, chats)
|
||||||
})
|
})
|
||||||
|
|
||||||
diff.otherUpdates.forEach((upd) => {
|
diff.otherUpdates.forEach((upd) => {
|
||||||
|
@ -582,7 +573,7 @@ async function _loadChannelDifference(
|
||||||
if (upd._ === 'updateNewChannelMessage' && upd.message._ === 'messageEmpty')
|
if (upd._ === 'updateNewChannelMessage' && upd.message._ === 'messageEmpty')
|
||||||
return
|
return
|
||||||
|
|
||||||
this.dispatchUpdate(upd, users, chats)
|
this._dispatchUpdate(upd, users, chats)
|
||||||
})
|
})
|
||||||
|
|
||||||
pts = diff.pts
|
pts = diff.pts
|
||||||
|
@ -728,7 +719,7 @@ export function _handleUpdate(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isDummyUpdate(upd) && !noDispatch) {
|
if (!isDummyUpdate(upd) && !noDispatch) {
|
||||||
this.dispatchUpdate(upd, users, chats)
|
this._dispatchUpdate(upd, users, chats)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (channelId) {
|
if (channelId) {
|
||||||
|
@ -738,7 +729,7 @@ export function _handleUpdate(
|
||||||
this._pts = pts
|
this._pts = pts
|
||||||
}
|
}
|
||||||
} else if (!noDispatch) {
|
} else if (!noDispatch) {
|
||||||
this.dispatchUpdate(upd, users, chats)
|
this._dispatchUpdate(upd, users, chats)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -769,7 +760,7 @@ export function _handleUpdate(
|
||||||
return await _loadDifference.call(this)
|
return await _loadDifference.call(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.dispatchUpdate(upd, peers.users, peers.chats)
|
this._dispatchUpdate(upd, peers.users, peers.chats)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -821,7 +812,7 @@ export function _handleUpdate(
|
||||||
this._date = update.date
|
this._date = update.date
|
||||||
this._pts = update.pts
|
this._pts = update.pts
|
||||||
|
|
||||||
this.dispatchUpdate(message, peers.users, peers.chats)
|
this._dispatchUpdate(message, peers.users, peers.chats)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'updateShortChatMessage': {
|
case 'updateShortChatMessage': {
|
||||||
|
@ -869,7 +860,7 @@ export function _handleUpdate(
|
||||||
this._date = update.date
|
this._date = update.date
|
||||||
this._pts = update.pts
|
this._pts = update.pts
|
||||||
|
|
||||||
this.dispatchUpdate(message, peers.users, peers.chats)
|
this._dispatchUpdate(message, peers.users, peers.chats)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'updateShortSentMessage': {
|
case 'updateShortSentMessage': {
|
||||||
|
|
|
@ -1,104 +1,18 @@
|
||||||
import { Dispatcher } from './dispatcher'
|
import { AsyncLock, getMarkedPeerId, MaybeAsync } from '@mtcute/core'
|
||||||
import {
|
|
||||||
FormattedString,
|
|
||||||
InputMediaLike,
|
|
||||||
InputPeerLike,
|
|
||||||
MaybeAsync,
|
|
||||||
Message,
|
|
||||||
MtCuteArgumentError,
|
|
||||||
TelegramClient,
|
|
||||||
TimeoutError,
|
|
||||||
tl,
|
|
||||||
} from '@mtcute/client'
|
|
||||||
import { AsyncLock, getMarkedPeerId } from '@mtcute/core'
|
|
||||||
import {
|
import {
|
||||||
ControllablePromise,
|
ControllablePromise,
|
||||||
createControllablePromise,
|
createControllablePromise,
|
||||||
} from '@mtcute/core/src/utils/controllable-promise'
|
} from '@mtcute/core/src/utils/controllable-promise'
|
||||||
|
import { TelegramClient } from '../client'
|
||||||
|
import { InputMediaLike } from './media'
|
||||||
|
import { MtCuteArgumentError } from './errors'
|
||||||
|
import { InputPeerLike } from './peers'
|
||||||
import { HistoryReadUpdate } from './updates'
|
import { HistoryReadUpdate } from './updates'
|
||||||
|
import { FormattedString } from './parser'
|
||||||
interface OneWayLinkedListItem<T> {
|
import { Message } from './messages'
|
||||||
v: T
|
import { tl } from '@mtcute/tl'
|
||||||
n?: OneWayLinkedListItem<T>
|
import { TimeoutError } from '@mtcute/tl/errors'
|
||||||
}
|
import { Queue } from '../utils/queue'
|
||||||
|
|
||||||
class Queue<T> {
|
|
||||||
first?: OneWayLinkedListItem<T>
|
|
||||||
last?: OneWayLinkedListItem<T>
|
|
||||||
|
|
||||||
length = 0
|
|
||||||
|
|
||||||
constructor (readonly limit = 0) {
|
|
||||||
}
|
|
||||||
|
|
||||||
push(item: T): void {
|
|
||||||
const it: OneWayLinkedListItem<T> = { v: item }
|
|
||||||
if (!this.first) {
|
|
||||||
this.first = this.last = it
|
|
||||||
} else {
|
|
||||||
this.last!.n = it
|
|
||||||
this.last = it
|
|
||||||
}
|
|
||||||
|
|
||||||
this.length += 1
|
|
||||||
|
|
||||||
if (this.limit) {
|
|
||||||
while (this.first && this.length > this.limit) {
|
|
||||||
this.first = this.first.n
|
|
||||||
this.length -= 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
empty(): boolean {
|
|
||||||
return this.first === undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
peek(): T | undefined {
|
|
||||||
return this.first?.v
|
|
||||||
}
|
|
||||||
|
|
||||||
pop(): T | undefined {
|
|
||||||
if (!this.first) return undefined
|
|
||||||
|
|
||||||
const it = this.first
|
|
||||||
this.first = this.first.n
|
|
||||||
if (!this.first) this.last = undefined
|
|
||||||
|
|
||||||
this.length -= 1
|
|
||||||
return it.v
|
|
||||||
}
|
|
||||||
|
|
||||||
removeBy(pred: (it: T) => boolean): void {
|
|
||||||
if (!this.first) return
|
|
||||||
|
|
||||||
let prev: OneWayLinkedListItem<T> | undefined = undefined
|
|
||||||
let it = this.first
|
|
||||||
while (it && !pred(it.v)) {
|
|
||||||
if (!it.n) return
|
|
||||||
|
|
||||||
prev = it
|
|
||||||
it = it.n
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!it) return
|
|
||||||
|
|
||||||
if (prev) {
|
|
||||||
prev.n = it.n
|
|
||||||
} else {
|
|
||||||
this.first = it.n
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.first) this.last = undefined
|
|
||||||
|
|
||||||
this.length -= 1
|
|
||||||
}
|
|
||||||
|
|
||||||
clear(): void {
|
|
||||||
this.first = this.last = undefined
|
|
||||||
this.length = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface QueuedHandler<T> {
|
interface QueuedHandler<T> {
|
||||||
promise: ControllablePromise<T>
|
promise: ControllablePromise<T>
|
||||||
|
@ -120,7 +34,6 @@ interface QueuedHandler<T> {
|
||||||
export class Conversation {
|
export class Conversation {
|
||||||
private _inputPeer: tl.TypeInputPeer
|
private _inputPeer: tl.TypeInputPeer
|
||||||
private _chatId: number
|
private _chatId: number
|
||||||
private _client: TelegramClient
|
|
||||||
private _started = false
|
private _started = false
|
||||||
|
|
||||||
private _lastMessage: number
|
private _lastMessage: number
|
||||||
|
@ -136,7 +49,7 @@ export class Conversation {
|
||||||
private _pendingRead: Record<number, QueuedHandler<void>> = {}
|
private _pendingRead: Record<number, QueuedHandler<void>> = {}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly dispatcher: Dispatcher<any, any>,
|
readonly client: TelegramClient,
|
||||||
readonly chat: InputPeerLike
|
readonly chat: InputPeerLike
|
||||||
) {
|
) {
|
||||||
this._onNewMessage = this._onNewMessage.bind(this)
|
this._onNewMessage = this._onNewMessage.bind(this)
|
||||||
|
@ -186,24 +99,16 @@ export class Conversation {
|
||||||
async start(): Promise<void> {
|
async start(): Promise<void> {
|
||||||
if (this._started) return
|
if (this._started) return
|
||||||
|
|
||||||
const client = this.dispatcher['_client']
|
|
||||||
if (!client) {
|
|
||||||
throw new MtCuteArgumentError(
|
|
||||||
'Dispatcher is not bound to a client!'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
this._client = client
|
|
||||||
this._started = true
|
this._started = true
|
||||||
this._inputPeer = await client.resolvePeer(this.chat)
|
this._inputPeer = await this.client.resolvePeer(this.chat)
|
||||||
this._chatId = getMarkedPeerId(this._inputPeer)
|
this._chatId = getMarkedPeerId(this._inputPeer)
|
||||||
|
|
||||||
const dialog = await client.getPeerDialogs(this._inputPeer)
|
const dialog = await this.client.getPeerDialogs(this._inputPeer)
|
||||||
this._lastMessage = this._lastReceivedMessage = dialog.lastMessage.id
|
this._lastMessage = this._lastReceivedMessage = dialog.lastMessage.id
|
||||||
|
|
||||||
this.dispatcher.on('new_message', this._onNewMessage)
|
this.client.on('new_message', this._onNewMessage)
|
||||||
this.dispatcher.on('edit_message', this._onEditMessage)
|
this.client.on('edit_message', this._onEditMessage)
|
||||||
this.dispatcher.on('history_read', this._onHistoryRead)
|
this.client.on('history_read', this._onHistoryRead)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -212,9 +117,9 @@ export class Conversation {
|
||||||
stop(): void {
|
stop(): void {
|
||||||
if (!this._started) return
|
if (!this._started) return
|
||||||
|
|
||||||
this.dispatcher.off('new_message', this._onNewMessage)
|
this.client.off('new_message', this._onNewMessage)
|
||||||
this.dispatcher.off('edit_message', this._onEditMessage)
|
this.client.off('edit_message', this._onEditMessage)
|
||||||
this.dispatcher.off('history_read', this._onHistoryRead)
|
this.client.off('history_read', this._onHistoryRead)
|
||||||
|
|
||||||
// reset pending status
|
// reset pending status
|
||||||
this._queuedNewMessage.clear()
|
this._queuedNewMessage.clear()
|
||||||
|
@ -240,7 +145,7 @@ export class Conversation {
|
||||||
throw new MtCuteArgumentError("Conversation hasn't started yet")
|
throw new MtCuteArgumentError("Conversation hasn't started yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await this._client.sendText(this._inputPeer, text, params)
|
const res = await this.client.sendText(this._inputPeer, text, params)
|
||||||
this._lastMessage = res.id
|
this._lastMessage = res.id
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
@ -259,7 +164,7 @@ export class Conversation {
|
||||||
throw new MtCuteArgumentError("Conversation hasn't started yet")
|
throw new MtCuteArgumentError("Conversation hasn't started yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await this._client.sendMedia(this._inputPeer, media, params)
|
const res = await this.client.sendMedia(this._inputPeer, media, params)
|
||||||
this._lastMessage = res.id
|
this._lastMessage = res.id
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
@ -278,7 +183,7 @@ export class Conversation {
|
||||||
throw new MtCuteArgumentError("Conversation hasn't started yet")
|
throw new MtCuteArgumentError("Conversation hasn't started yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await this._client.sendMediaGroup(
|
const res = await this.client.sendMediaGroup(
|
||||||
this._inputPeer,
|
this._inputPeer,
|
||||||
medias,
|
medias,
|
||||||
params
|
params
|
||||||
|
@ -305,7 +210,7 @@ export class Conversation {
|
||||||
message = this._lastMessage ?? 0
|
message = this._lastMessage ?? 0
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._client.readHistory(this._inputPeer, message, clearMentions)
|
return this.client.readHistory(this._inputPeer, message, clearMentions)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -537,7 +442,7 @@ export class Conversation {
|
||||||
)
|
)
|
||||||
|
|
||||||
// check if the message is already read
|
// check if the message is already read
|
||||||
const dialog = await this._client.getPeerDialogs(this._inputPeer)
|
const dialog = await this.client.getPeerDialogs(this._inputPeer)
|
||||||
if (dialog.lastRead >= msgId) return
|
if (dialog.lastRead >= msgId) return
|
||||||
|
|
||||||
const promise = createControllablePromise<void>()
|
const promise = createControllablePromise<void>()
|
||||||
|
@ -578,7 +483,7 @@ export class Conversation {
|
||||||
this._queuedNewMessage.pop()
|
this._queuedNewMessage.pop()
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this._client['_emitError'](e)
|
this.client['_emitError'](e)
|
||||||
}
|
}
|
||||||
|
|
||||||
this._lastMessage = this._lastReceivedMessage = msg.id
|
this._lastMessage = this._lastReceivedMessage = msg.id
|
||||||
|
@ -603,7 +508,7 @@ export class Conversation {
|
||||||
it.promise.resolve(msg)
|
it.promise.resolve(msg)
|
||||||
delete this._pendingEditMessage[msg.id]
|
delete this._pendingEditMessage[msg.id]
|
||||||
}
|
}
|
||||||
})().catch((e) => this._client['_emitError'](e))
|
})().catch((e) => this.client['_emitError'](e))
|
||||||
}
|
}
|
||||||
|
|
||||||
private _onHistoryRead(upd: HistoryReadUpdate) {
|
private _onHistoryRead(upd: HistoryReadUpdate) {
|
|
@ -5,6 +5,8 @@ export * from './media'
|
||||||
export * from './messages'
|
export * from './messages'
|
||||||
export * from './peers'
|
export * from './peers'
|
||||||
export * from './misc'
|
export * from './misc'
|
||||||
|
export * from './updates'
|
||||||
|
export * from './conversation'
|
||||||
|
|
||||||
export * from './errors'
|
export * from './errors'
|
||||||
export * from './parser'
|
export * from './parser'
|
||||||
|
|
|
@ -8,7 +8,7 @@ import {
|
||||||
User,
|
User,
|
||||||
UsersIndex,
|
UsersIndex,
|
||||||
} from '@mtcute/client'
|
} from '@mtcute/client'
|
||||||
import { makeInspectable } from '@mtcute/client/src/types/utils'
|
import { makeInspectable } from '../utils'
|
||||||
|
|
||||||
export namespace ChatMemberUpdate {
|
export namespace ChatMemberUpdate {
|
||||||
/**
|
/**
|
|
@ -1,4 +1,3 @@
|
||||||
import { makeInspectable } from '@mtcute/client/src/types/utils'
|
|
||||||
import { tl } from '@mtcute/tl'
|
import { tl } from '@mtcute/tl'
|
||||||
import {
|
import {
|
||||||
TelegramClient,
|
TelegramClient,
|
||||||
|
@ -7,7 +6,8 @@ import {
|
||||||
MtCuteArgumentError,
|
MtCuteArgumentError,
|
||||||
UsersIndex,
|
UsersIndex,
|
||||||
} from '@mtcute/client'
|
} from '@mtcute/client'
|
||||||
import { encodeInlineMessageId } from '@mtcute/client/src/utils/inline-utils'
|
import { encodeInlineMessageId } from '../../utils/inline-utils'
|
||||||
|
import { makeInspectable } from '../utils'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An inline result was chosen by the user and sent to some chat
|
* An inline result was chosen by the user and sent to some chat
|
|
@ -1,7 +1,7 @@
|
||||||
import { tl } from '@mtcute/tl'
|
import { tl } from '@mtcute/tl'
|
||||||
import { makeInspectable } from '@mtcute/client/src/types/utils'
|
|
||||||
import { MAX_CHANNEL_ID } from '@mtcute/core'
|
import { MAX_CHANNEL_ID } from '@mtcute/core'
|
||||||
import { TelegramClient } from '@mtcute/client'
|
import { TelegramClient } from '@mtcute/client'
|
||||||
|
import { makeInspectable } from '../utils'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* One or more messages were deleted
|
* One or more messages were deleted
|
|
@ -1,7 +1,7 @@
|
||||||
import { tl } from '@mtcute/tl'
|
import { tl } from '@mtcute/tl'
|
||||||
import { TelegramClient } from '@mtcute/client'
|
import { TelegramClient } from '@mtcute/client'
|
||||||
import { getMarkedPeerId, MAX_CHANNEL_ID } from '@mtcute/core'
|
import { getMarkedPeerId, MAX_CHANNEL_ID } from '@mtcute/core'
|
||||||
import { makeInspectable } from '@mtcute/client/src/types/utils'
|
import { makeInspectable } from '../utils'
|
||||||
|
|
||||||
export class HistoryReadUpdate {
|
export class HistoryReadUpdate {
|
||||||
constructor (
|
constructor (
|
38
packages/client/src/types/updates/index.ts
Normal file
38
packages/client/src/types/updates/index.ts
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
import { CallbackQuery, InlineQuery, Message } from '../..'
|
||||||
|
|
||||||
|
import { DeleteMessageUpdate } from './delete-message-update'
|
||||||
|
import { ChatMemberUpdate } from './chat-member-update'
|
||||||
|
import { ChosenInlineResult } from './chosen-inline-result'
|
||||||
|
import { PollUpdate } from './poll-update'
|
||||||
|
import { PollVoteUpdate } from './poll-vote'
|
||||||
|
import { UserStatusUpdate } from './user-status-update'
|
||||||
|
import { UserTypingUpdate } from './user-typing-update'
|
||||||
|
import { HistoryReadUpdate } from './history-read-update'
|
||||||
|
|
||||||
|
export {
|
||||||
|
DeleteMessageUpdate,
|
||||||
|
ChatMemberUpdate,
|
||||||
|
ChosenInlineResult,
|
||||||
|
PollUpdate,
|
||||||
|
PollVoteUpdate,
|
||||||
|
UserStatusUpdate,
|
||||||
|
UserTypingUpdate,
|
||||||
|
HistoryReadUpdate,
|
||||||
|
}
|
||||||
|
|
||||||
|
// begin-codegen
|
||||||
|
export type ParsedUpdate =
|
||||||
|
| { name: 'new_message', data: Message }
|
||||||
|
| { name: 'edit_message', data: Message }
|
||||||
|
| { name: 'delete_message', data: DeleteMessageUpdate }
|
||||||
|
| { name: 'chat_member', data: ChatMemberUpdate }
|
||||||
|
| { name: 'inline_query', data: InlineQuery }
|
||||||
|
| { name: 'chosen_inline_result', data: ChosenInlineResult }
|
||||||
|
| { name: 'callback_query', data: CallbackQuery }
|
||||||
|
| { name: 'poll', data: PollUpdate }
|
||||||
|
| { name: 'poll_vote', data: PollVoteUpdate }
|
||||||
|
| { name: 'user_status', data: UserStatusUpdate }
|
||||||
|
| { name: 'user_typing', data: UserTypingUpdate }
|
||||||
|
| { name: 'history_read', data: HistoryReadUpdate }
|
||||||
|
|
||||||
|
// end-codegen
|
|
@ -1,6 +1,6 @@
|
||||||
import { makeInspectable } from '@mtcute/client/src/types/utils'
|
|
||||||
import { TelegramClient, Poll, UsersIndex } from '@mtcute/client'
|
import { TelegramClient, Poll, UsersIndex } from '@mtcute/client'
|
||||||
import { tl } from '@mtcute/tl'
|
import { tl } from '@mtcute/tl'
|
||||||
|
import { makeInspectable } from '../utils'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Poll state has changed (stopped, somebody
|
* Poll state has changed (stopped, somebody
|
|
@ -5,7 +5,7 @@ import {
|
||||||
UsersIndex,
|
UsersIndex,
|
||||||
} from '@mtcute/client'
|
} from '@mtcute/client'
|
||||||
import { tl } from '@mtcute/tl'
|
import { tl } from '@mtcute/tl'
|
||||||
import { makeInspectable } from '@mtcute/client/src/types/utils'
|
import { makeInspectable } from '../utils'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Some user has voted in a public poll.
|
* Some user has voted in a public poll.
|
|
@ -1,6 +1,6 @@
|
||||||
import { TelegramClient, User } from '@mtcute/client'
|
import { TelegramClient, User } from '@mtcute/client'
|
||||||
import { tl } from '@mtcute/tl'
|
import { tl } from '@mtcute/tl'
|
||||||
import { makeInspectable } from '@mtcute/client/src/types/utils'
|
import { makeInspectable } from '../utils'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User status has changed
|
* User status has changed
|
|
@ -8,7 +8,7 @@ import {
|
||||||
} from '@mtcute/client'
|
} from '@mtcute/client'
|
||||||
import { tl } from '@mtcute/tl'
|
import { tl } from '@mtcute/tl'
|
||||||
import { getBarePeerId, MAX_CHANNEL_ID } from '@mtcute/core'
|
import { getBarePeerId, MAX_CHANNEL_ID } from '@mtcute/core'
|
||||||
import { makeInspectable } from '@mtcute/client/src/types/utils'
|
import { makeInspectable } from '../utils'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User's typing status has changed.
|
* User's typing status has changed.
|
131
packages/client/src/utils/parse-update.ts
Normal file
131
packages/client/src/utils/parse-update.ts
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
import { TelegramClient } from '../client'
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
import {
|
||||||
|
CallbackQuery,
|
||||||
|
ChatMemberUpdate,
|
||||||
|
ChatsIndex,
|
||||||
|
ChosenInlineResult,
|
||||||
|
DeleteMessageUpdate,
|
||||||
|
HistoryReadUpdate,
|
||||||
|
InlineQuery,
|
||||||
|
Message,
|
||||||
|
ParsedUpdate,
|
||||||
|
PollUpdate,
|
||||||
|
PollVoteUpdate,
|
||||||
|
UsersIndex,
|
||||||
|
UserStatusUpdate,
|
||||||
|
UserTypingUpdate,
|
||||||
|
} from '../types'
|
||||||
|
|
||||||
|
type ParserFunction = (
|
||||||
|
client: TelegramClient,
|
||||||
|
upd: tl.TypeUpdate | tl.TypeMessage,
|
||||||
|
users: UsersIndex,
|
||||||
|
chats: ChatsIndex
|
||||||
|
) => any
|
||||||
|
type UpdateParser = [ParsedUpdate['name'], ParserFunction]
|
||||||
|
|
||||||
|
const baseMessageParser: ParserFunction = (
|
||||||
|
client: TelegramClient,
|
||||||
|
upd,
|
||||||
|
users,
|
||||||
|
chats
|
||||||
|
) =>
|
||||||
|
new Message(
|
||||||
|
client,
|
||||||
|
tl.isAnyMessage(upd) ? upd : (upd as any).message,
|
||||||
|
users,
|
||||||
|
chats,
|
||||||
|
upd._ === 'updateNewScheduledMessage'
|
||||||
|
)
|
||||||
|
|
||||||
|
const newMessageParser: UpdateParser = ['new_message', baseMessageParser]
|
||||||
|
const editMessageParser: UpdateParser = ['edit_message', baseMessageParser]
|
||||||
|
const chatMemberParser: UpdateParser = [
|
||||||
|
'chat_member',
|
||||||
|
(client, upd, users, chats) =>
|
||||||
|
new ChatMemberUpdate(client, upd as any, users, chats),
|
||||||
|
]
|
||||||
|
const callbackQueryParser: UpdateParser = [
|
||||||
|
'callback_query',
|
||||||
|
(client, upd, users) => new CallbackQuery(client, upd as any, users),
|
||||||
|
]
|
||||||
|
const userTypingParser: UpdateParser = [
|
||||||
|
'user_typing',
|
||||||
|
(client, upd) => new UserTypingUpdate(client, upd as any),
|
||||||
|
]
|
||||||
|
const deleteMessageParser: UpdateParser = [
|
||||||
|
'delete_message',
|
||||||
|
(client, upd) => new DeleteMessageUpdate(client, upd as any),
|
||||||
|
]
|
||||||
|
const historyReadParser: UpdateParser = [
|
||||||
|
'history_read',
|
||||||
|
(client, upd) => new HistoryReadUpdate(client, upd as any),
|
||||||
|
]
|
||||||
|
|
||||||
|
const PARSERS: Partial<
|
||||||
|
Record<(tl.TypeUpdate | tl.TypeMessage)['_'], UpdateParser>
|
||||||
|
> = {
|
||||||
|
message: newMessageParser,
|
||||||
|
messageEmpty: newMessageParser,
|
||||||
|
messageService: newMessageParser,
|
||||||
|
updateNewMessage: newMessageParser,
|
||||||
|
updateNewChannelMessage: newMessageParser,
|
||||||
|
updateNewScheduledMessage: newMessageParser,
|
||||||
|
updateEditMessage: editMessageParser,
|
||||||
|
updateEditChannelMessage: editMessageParser,
|
||||||
|
updateChatParticipant: chatMemberParser,
|
||||||
|
updateChannelParticipant: chatMemberParser,
|
||||||
|
updateBotInlineQuery: [
|
||||||
|
'inline_query',
|
||||||
|
(client, upd, users) => new InlineQuery(client, upd as any, users),
|
||||||
|
],
|
||||||
|
updateBotInlineSend: [
|
||||||
|
'chosen_inline_result',
|
||||||
|
(client, upd, users) =>
|
||||||
|
new ChosenInlineResult(client, upd as any, users),
|
||||||
|
],
|
||||||
|
updateBotCallbackQuery: callbackQueryParser,
|
||||||
|
updateInlineBotCallbackQuery: callbackQueryParser,
|
||||||
|
updateMessagePoll: [
|
||||||
|
'poll',
|
||||||
|
(client, upd, users) => new PollUpdate(client, upd as any, users),
|
||||||
|
],
|
||||||
|
updateMessagePollVote: [
|
||||||
|
'poll_vote',
|
||||||
|
(client, upd, users) => new PollVoteUpdate(client, upd as any, users),
|
||||||
|
],
|
||||||
|
updateUserStatus: [
|
||||||
|
'user_status',
|
||||||
|
(client, upd) => new UserStatusUpdate(client, upd as any),
|
||||||
|
],
|
||||||
|
updateChannelUserTyping: userTypingParser,
|
||||||
|
updateChatUserTyping: userTypingParser,
|
||||||
|
updateUserTyping: userTypingParser,
|
||||||
|
updateDeleteChannelMessages: deleteMessageParser,
|
||||||
|
updateDeleteMessages: deleteMessageParser,
|
||||||
|
updateReadHistoryInbox: historyReadParser,
|
||||||
|
updateReadHistoryOutbox: historyReadParser,
|
||||||
|
updateReadChannelInbox: historyReadParser,
|
||||||
|
updateReadChannelOutbox: historyReadParser,
|
||||||
|
updateReadChannelDiscussionInbox: historyReadParser,
|
||||||
|
updateReadChannelDiscussionOutbox: historyReadParser,
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
|
export function _parseUpdate(
|
||||||
|
client: TelegramClient,
|
||||||
|
update: tl.TypeUpdate | tl.TypeMessage,
|
||||||
|
users: UsersIndex,
|
||||||
|
chats: ChatsIndex
|
||||||
|
): ParsedUpdate | null {
|
||||||
|
const pair = PARSERS[update._]
|
||||||
|
if (pair) {
|
||||||
|
return {
|
||||||
|
name: pair[0],
|
||||||
|
data: pair[1](client, update, users, chats),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
81
packages/client/src/utils/queue.ts
Normal file
81
packages/client/src/utils/queue.ts
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
interface OneWayLinkedListItem<T> {
|
||||||
|
v: T
|
||||||
|
n?: OneWayLinkedListItem<T>
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Queue<T> {
|
||||||
|
first?: OneWayLinkedListItem<T>
|
||||||
|
last?: OneWayLinkedListItem<T>
|
||||||
|
|
||||||
|
length = 0
|
||||||
|
|
||||||
|
constructor(readonly limit = 0) {}
|
||||||
|
|
||||||
|
push(item: T): void {
|
||||||
|
const it: OneWayLinkedListItem<T> = { v: item }
|
||||||
|
if (!this.first) {
|
||||||
|
this.first = this.last = it
|
||||||
|
} else {
|
||||||
|
this.last!.n = it
|
||||||
|
this.last = it
|
||||||
|
}
|
||||||
|
|
||||||
|
this.length += 1
|
||||||
|
|
||||||
|
if (this.limit) {
|
||||||
|
while (this.first && this.length > this.limit) {
|
||||||
|
this.first = this.first.n
|
||||||
|
this.length -= 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
empty(): boolean {
|
||||||
|
return this.first === undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
peek(): T | undefined {
|
||||||
|
return this.first?.v
|
||||||
|
}
|
||||||
|
|
||||||
|
pop(): T | undefined {
|
||||||
|
if (!this.first) return undefined
|
||||||
|
|
||||||
|
const it = this.first
|
||||||
|
this.first = this.first.n
|
||||||
|
if (!this.first) this.last = undefined
|
||||||
|
|
||||||
|
this.length -= 1
|
||||||
|
return it.v
|
||||||
|
}
|
||||||
|
|
||||||
|
removeBy(pred: (it: T) => boolean): void {
|
||||||
|
if (!this.first) return
|
||||||
|
|
||||||
|
let prev: OneWayLinkedListItem<T> | undefined = undefined
|
||||||
|
let it = this.first
|
||||||
|
while (it && !pred(it.v)) {
|
||||||
|
if (!it.n) return
|
||||||
|
|
||||||
|
prev = it
|
||||||
|
it = it.n
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!it) return
|
||||||
|
|
||||||
|
if (prev) {
|
||||||
|
prev.n = it.n
|
||||||
|
} else {
|
||||||
|
this.first = it.n
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.first) this.last = undefined
|
||||||
|
|
||||||
|
this.length -= 1
|
||||||
|
}
|
||||||
|
|
||||||
|
clear(): void {
|
||||||
|
this.first = this.last = undefined
|
||||||
|
this.length = 0
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,6 +35,7 @@ import bigInt from 'big-integer'
|
||||||
import { BinaryWriter } from './utils/binary/binary-writer'
|
import { BinaryWriter } from './utils/binary/binary-writer'
|
||||||
import { encodeUrlSafeBase64, parseUrlSafeBase64 } from './utils/buffer-utils'
|
import { encodeUrlSafeBase64, parseUrlSafeBase64 } from './utils/buffer-utils'
|
||||||
import { BinaryReader } from './utils/binary/binary-reader'
|
import { BinaryReader } from './utils/binary/binary-reader'
|
||||||
|
import EventEmitter from 'events'
|
||||||
|
|
||||||
const debug = require('debug')('mtcute:base')
|
const debug = require('debug')('mtcute:base')
|
||||||
|
|
||||||
|
@ -148,7 +149,7 @@ export namespace BaseTelegramClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class BaseTelegramClient {
|
export class BaseTelegramClient extends EventEmitter {
|
||||||
/**
|
/**
|
||||||
* `initConnection` params taken from {@link BaseTelegramClient.Options.initConnectionOptions}.
|
* `initConnection` params taken from {@link BaseTelegramClient.Options.initConnectionOptions}.
|
||||||
*/
|
*/
|
||||||
|
@ -242,6 +243,8 @@ export class BaseTelegramClient {
|
||||||
protected _handleUpdate(update: tl.TypeUpdates): void {}
|
protected _handleUpdate(update: tl.TypeUpdates): void {}
|
||||||
|
|
||||||
constructor(opts: BaseTelegramClient.Options) {
|
constructor(opts: BaseTelegramClient.Options) {
|
||||||
|
super()
|
||||||
|
|
||||||
const apiId =
|
const apiId =
|
||||||
typeof opts.apiId === 'string' ? parseInt(opts.apiId) : opts.apiId
|
typeof opts.apiId === 'string' ? parseInt(opts.apiId) : opts.apiId
|
||||||
if (isNaN(apiId))
|
if (isNaN(apiId))
|
||||||
|
|
|
@ -1,87 +1,4 @@
|
||||||
const fs = require('fs')
|
const { types, toSentence, replaceSections, formatFile } = require('../../client/scripts/generate-updates')
|
||||||
const path = require('path')
|
|
||||||
const prettier = require('prettier')
|
|
||||||
const {
|
|
||||||
snakeToCamel,
|
|
||||||
camelToPascal,
|
|
||||||
camelToSnake,
|
|
||||||
} = require('../../tl/scripts/common')
|
|
||||||
|
|
||||||
function parseUpdateTypes() {
|
|
||||||
const lines = fs
|
|
||||||
.readFileSync(path.join(__dirname, 'update-types.txt'), 'utf-8')
|
|
||||||
.split('\n')
|
|
||||||
.map((it) => it.trim())
|
|
||||||
.filter((it) => it && it[0] !== '#')
|
|
||||||
|
|
||||||
const ret = []
|
|
||||||
|
|
||||||
for (const line of lines) {
|
|
||||||
const m = line.match(/^([a-z_]+)(?:: ([a-zA-Z]+))? = ([a-zA-Z]+)( \+ State)?$/)
|
|
||||||
if (!m) throw new Error(`invalid syntax: ${line}`)
|
|
||||||
ret.push({
|
|
||||||
typeName: m[1],
|
|
||||||
handlerTypeName: m[2] || camelToPascal(snakeToCamel(m[1])),
|
|
||||||
updateType: m[3],
|
|
||||||
funcName: m[2]
|
|
||||||
? m[2][0].toLowerCase() + m[2].substr(1)
|
|
||||||
: snakeToCamel(m[1]),
|
|
||||||
state: !!m[4]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
function replaceSections(filename, sections) {
|
|
||||||
let lines = fs
|
|
||||||
.readFileSync(path.join(__dirname, '../src', filename), 'utf-8')
|
|
||||||
.split('\n')
|
|
||||||
|
|
||||||
const findMarker = (marker) => {
|
|
||||||
const idx = lines.findIndex((line) => line.trim() === `// ${marker}`)
|
|
||||||
if (idx === -1) throw new Error(marker + ' not found')
|
|
||||||
return idx
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const [name, content] of Object.entries(sections)) {
|
|
||||||
const start = findMarker(`begin-${name}`)
|
|
||||||
const end = findMarker(`end-${name}`)
|
|
||||||
|
|
||||||
if (start > end) throw new Error('begin is after end')
|
|
||||||
|
|
||||||
lines.splice(start + 1, end - start - 1, content)
|
|
||||||
}
|
|
||||||
|
|
||||||
fs.writeFileSync(path.join(__dirname, '../src', filename), lines.join('\n'))
|
|
||||||
}
|
|
||||||
|
|
||||||
const types = parseUpdateTypes()
|
|
||||||
|
|
||||||
async function formatFile(filename) {
|
|
||||||
const targetFile = path.join(__dirname, '../src/', filename)
|
|
||||||
const prettierConfig = await prettier.resolveConfig(targetFile)
|
|
||||||
let fullSource = await fs.promises.readFile(targetFile, 'utf-8')
|
|
||||||
fullSource = await prettier.format(fullSource, {
|
|
||||||
...(prettierConfig || {}),
|
|
||||||
filepath: targetFile,
|
|
||||||
})
|
|
||||||
await fs.promises.writeFile(targetFile, fullSource)
|
|
||||||
}
|
|
||||||
|
|
||||||
function toSentence(type, stype = 'inline') {
|
|
||||||
const name = camelToSnake(type.handlerTypeName)
|
|
||||||
.toLowerCase()
|
|
||||||
.replace(/_/g, ' ')
|
|
||||||
|
|
||||||
if (stype === 'inline') {
|
|
||||||
return `${name[0].match(/[aeiouy]/i) ? 'an' : 'a'} ${name} handler`
|
|
||||||
} else if (stype === 'plain') {
|
|
||||||
return `${name} handler`
|
|
||||||
} else {
|
|
||||||
return `${name[0].toUpperCase()}${name.substr(1)} handler`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function generateHandler() {
|
function generateHandler() {
|
||||||
const lines = []
|
const lines = []
|
||||||
|
@ -90,8 +7,6 @@ function generateHandler() {
|
||||||
// imports must be added manually because yeah
|
// imports must be added manually because yeah
|
||||||
|
|
||||||
types.forEach((type) => {
|
types.forEach((type) => {
|
||||||
if (type.updateType === 'IGNORE') return
|
|
||||||
|
|
||||||
lines.push(
|
lines.push(
|
||||||
`export type ${type.handlerTypeName}Handler<T = ${type.updateType}` +
|
`export type ${type.handlerTypeName}Handler<T = ${type.updateType}` +
|
||||||
`${type.state ? ', S = never' : ''}> = ParsedUpdateHandler<` +
|
`${type.state ? ', S = never' : ''}> = ParsedUpdateHandler<` +
|
||||||
|
@ -105,147 +20,17 @@ function generateHandler() {
|
||||||
lines.join('\n') +
|
lines.join('\n') +
|
||||||
'\n\nexport type UpdateHandler = \n' +
|
'\n\nexport type UpdateHandler = \n' +
|
||||||
names.map((i) => ` | ${i}\n`).join(''),
|
names.map((i) => ` | ${i}\n`).join(''),
|
||||||
})
|
}, __dirname)
|
||||||
}
|
|
||||||
|
|
||||||
function generateBuilders() {
|
|
||||||
const lines = []
|
|
||||||
const imports = ['UpdateHandler']
|
|
||||||
|
|
||||||
types.forEach((type) => {
|
|
||||||
imports.push(`${type.handlerTypeName}Handler`)
|
|
||||||
|
|
||||||
if (type.updateType === 'IGNORE') {
|
|
||||||
lines.push(`
|
|
||||||
/**
|
|
||||||
* Create ${toSentence(type)}
|
|
||||||
*
|
|
||||||
* @param handler ${toSentence(type, 'full')}
|
|
||||||
*/
|
|
||||||
export function ${type.funcName}(
|
|
||||||
handler: ${type.handlerTypeName}Handler['callback']
|
|
||||||
): ${type.handlerTypeName}Handler
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create ${toSentence(type)} with a filter
|
|
||||||
*
|
|
||||||
* @param filter Predicate to check the update against
|
|
||||||
* @param handler ${toSentence(type, 'full')}
|
|
||||||
*/
|
|
||||||
export function ${type.funcName}(
|
|
||||||
filter: ${type.handlerTypeName}Handler['check'],
|
|
||||||
handler: ${type.handlerTypeName}Handler['callback']
|
|
||||||
): ${type.handlerTypeName}Handler
|
|
||||||
|
|
||||||
/** @internal */
|
|
||||||
export function ${type.funcName}(filter: any, handler?: any): ${
|
|
||||||
type.handlerTypeName
|
|
||||||
}Handler {
|
|
||||||
return _create('${type.typeName}', filter, handler)
|
|
||||||
}
|
|
||||||
`)
|
|
||||||
} else {
|
|
||||||
lines.push(`
|
|
||||||
/**
|
|
||||||
* Create ${toSentence(type)}
|
|
||||||
*
|
|
||||||
* @param handler ${toSentence(type, 'full')}
|
|
||||||
*/
|
|
||||||
export function ${type.funcName}(
|
|
||||||
handler: ${type.handlerTypeName}Handler['callback']
|
|
||||||
): ${type.handlerTypeName}Handler
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create ${toSentence(type)} with a filter
|
|
||||||
*
|
|
||||||
* @param filter Update filter
|
|
||||||
* @param handler ${toSentence(type, 'full')}
|
|
||||||
*/
|
|
||||||
export function ${type.funcName}<Mod>(
|
|
||||||
filter: UpdateFilter<${type.updateType}, Mod>,
|
|
||||||
handler: ${type.handlerTypeName}Handler<
|
|
||||||
filters.Modify<${type.updateType}, Mod>
|
|
||||||
>['callback']
|
|
||||||
): ${type.handlerTypeName}Handler
|
|
||||||
|
|
||||||
/** @internal */
|
|
||||||
export function ${type.funcName}(
|
|
||||||
filter: any,
|
|
||||||
handler?: any
|
|
||||||
): ${type.handlerTypeName}Handler {
|
|
||||||
return _create('${type.typeName}', filter, handler)
|
|
||||||
}
|
|
||||||
`)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
replaceSections('builders.ts', {
|
|
||||||
codegen: lines.join('\n'),
|
|
||||||
'codegen-imports':
|
|
||||||
'import {\n' +
|
|
||||||
imports.map((i) => ` ${i},\n`).join('') +
|
|
||||||
"} from './handler'",
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateDispatcher() {
|
function generateDispatcher() {
|
||||||
const lines = []
|
const lines = []
|
||||||
const declareLines = []
|
const imports = ['UpdateHandler', 'RawUpdateHandler']
|
||||||
const imports = ['UpdateHandler']
|
|
||||||
|
|
||||||
types.forEach((type) => {
|
types.forEach((type) => {
|
||||||
imports.push(`${type.handlerTypeName}Handler`)
|
imports.push(`${type.handlerTypeName}Handler`)
|
||||||
|
|
||||||
if (type.updateType === 'IGNORE') {
|
lines.push(`
|
||||||
declareLines.push(`
|
|
||||||
/**
|
|
||||||
* Register a plain old ${toSentence(type, 'plain')}
|
|
||||||
*
|
|
||||||
* @param name Event name
|
|
||||||
* @param handler ${toSentence(type, 'full')}
|
|
||||||
*/
|
|
||||||
on(name: '${type.typeName}', handler: ${type.handlerTypeName}Handler['callback']): this
|
|
||||||
`)
|
|
||||||
|
|
||||||
lines.push(`
|
|
||||||
/**
|
|
||||||
* Register ${toSentence(type)} without any filters
|
|
||||||
*
|
|
||||||
* @param handler ${toSentence(type, 'full')}
|
|
||||||
* @param group Handler group index
|
|
||||||
*/
|
|
||||||
on${type.handlerTypeName}(handler: ${type.handlerTypeName}Handler['callback'], group?: number): void
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register ${toSentence(type)} with a filter
|
|
||||||
*
|
|
||||||
* @param filter Update filter function
|
|
||||||
* @param handler ${toSentence(type, 'full')}
|
|
||||||
* @param group Handler group index
|
|
||||||
*/
|
|
||||||
on${type.handlerTypeName}(
|
|
||||||
filter: ${type.handlerTypeName}Handler['check'],
|
|
||||||
handler: ${type.handlerTypeName}Handler['callback'],
|
|
||||||
group?: number
|
|
||||||
): void
|
|
||||||
|
|
||||||
/** @internal */
|
|
||||||
on${type.handlerTypeName}(filter: any, handler?: any, group?: number): void {
|
|
||||||
this._addKnownHandler('${type.funcName}', filter, handler, group)
|
|
||||||
}
|
|
||||||
`)
|
|
||||||
} else {
|
|
||||||
declareLines.push(`
|
|
||||||
/**
|
|
||||||
* Register a plain old ${toSentence(type, 'plain')}
|
|
||||||
*
|
|
||||||
* @param name Event name
|
|
||||||
* @param handler ${toSentence(type, 'full')}
|
|
||||||
*/
|
|
||||||
on(name: '${type.typeName}', handler: ${type.handlerTypeName}Handler['callback']): this
|
|
||||||
|
|
||||||
`)
|
|
||||||
lines.push(`
|
|
||||||
/**
|
/**
|
||||||
* Register ${toSentence(type)} without any filters
|
* Register ${toSentence(type)} without any filters
|
||||||
*
|
*
|
||||||
|
@ -284,30 +69,31 @@ ${type.state ? `
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
on${type.handlerTypeName}(filter: any, handler?: any, group?: number): void {
|
on${type.handlerTypeName}(filter: any, handler?: any, group?: number): void {
|
||||||
this._addKnownHandler('${type.funcName}', filter, handler, group)
|
this._addKnownHandler('${type.typeName}', filter, handler, group)
|
||||||
}
|
}
|
||||||
`)
|
`)
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
replaceSections('dispatcher.ts', {
|
replaceSections('dispatcher.ts', {
|
||||||
codegen: lines.join('\n'),
|
codegen: lines.join('\n'),
|
||||||
'codegen-declare': declareLines.join('\n'),
|
|
||||||
'codegen-imports':
|
'codegen-imports':
|
||||||
'import {\n' +
|
'import {\n' +
|
||||||
imports.map((i) => ` ${i},\n`).join('') +
|
imports.map((i) => ` ${i},\n`).join('') +
|
||||||
"} from './handler'",
|
"} from './handler'",
|
||||||
})
|
}, __dirname)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
generateBuilders()
|
|
||||||
generateHandler()
|
generateHandler()
|
||||||
generateDispatcher()
|
generateDispatcher()
|
||||||
|
|
||||||
await formatFile('builders.ts')
|
await formatFile('handler.ts', __dirname)
|
||||||
await formatFile('handler.ts')
|
await formatFile('dispatcher.ts', __dirname)
|
||||||
await formatFile('dispatcher.ts')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main().catch(console.error)
|
module.exports = { types, toSentence }
|
||||||
|
|
||||||
|
if (require.main === module) {
|
||||||
|
main().catch(console.error)
|
||||||
|
}
|
||||||
|
|
|
@ -1,423 +0,0 @@
|
||||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
|
||||||
// begin-codegen-imports
|
|
||||||
import {
|
|
||||||
UpdateHandler,
|
|
||||||
RawUpdateHandler,
|
|
||||||
NewMessageHandler,
|
|
||||||
EditMessageHandler,
|
|
||||||
DeleteMessageHandler,
|
|
||||||
ChatMemberUpdateHandler,
|
|
||||||
InlineQueryHandler,
|
|
||||||
ChosenInlineResultHandler,
|
|
||||||
CallbackQueryHandler,
|
|
||||||
PollUpdateHandler,
|
|
||||||
PollVoteHandler,
|
|
||||||
UserStatusUpdateHandler,
|
|
||||||
UserTypingHandler,
|
|
||||||
HistoryReadHandler,
|
|
||||||
} from './handler'
|
|
||||||
// end-codegen-imports
|
|
||||||
import { filters, UpdateFilter } from './filters'
|
|
||||||
import { CallbackQuery, InlineQuery, Message } from '@mtcute/client'
|
|
||||||
import {
|
|
||||||
ChatMemberUpdate,
|
|
||||||
ChosenInlineResult,
|
|
||||||
PollUpdate,
|
|
||||||
PollVoteUpdate,
|
|
||||||
UserStatusUpdate,
|
|
||||||
UserTypingUpdate,
|
|
||||||
DeleteMessageUpdate,
|
|
||||||
HistoryReadUpdate,
|
|
||||||
} from './updates'
|
|
||||||
|
|
||||||
function _create<T extends UpdateHandler>(
|
|
||||||
type: T['type'],
|
|
||||||
filter: any,
|
|
||||||
handler?: any
|
|
||||||
): T {
|
|
||||||
if (handler) {
|
|
||||||
return {
|
|
||||||
type,
|
|
||||||
check: filter,
|
|
||||||
callback: handler,
|
|
||||||
} as any
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
type,
|
|
||||||
callback: filter,
|
|
||||||
} as any
|
|
||||||
}
|
|
||||||
|
|
||||||
export namespace handlers {
|
|
||||||
// begin-codegen
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a raw update handler
|
|
||||||
*
|
|
||||||
* @param handler Raw update handler
|
|
||||||
*/
|
|
||||||
export function rawUpdate(
|
|
||||||
handler: RawUpdateHandler['callback']
|
|
||||||
): RawUpdateHandler
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a raw update handler with a filter
|
|
||||||
*
|
|
||||||
* @param filter Predicate to check the update against
|
|
||||||
* @param handler Raw update handler
|
|
||||||
*/
|
|
||||||
export function rawUpdate(
|
|
||||||
filter: RawUpdateHandler['check'],
|
|
||||||
handler: RawUpdateHandler['callback']
|
|
||||||
): RawUpdateHandler
|
|
||||||
|
|
||||||
/** @internal */
|
|
||||||
export function rawUpdate(filter: any, handler?: any): RawUpdateHandler {
|
|
||||||
return _create('raw', filter, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new message handler
|
|
||||||
*
|
|
||||||
* @param handler New message handler
|
|
||||||
*/
|
|
||||||
export function newMessage(
|
|
||||||
handler: NewMessageHandler['callback']
|
|
||||||
): NewMessageHandler
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new message handler with a filter
|
|
||||||
*
|
|
||||||
* @param filter Update filter
|
|
||||||
* @param handler New message handler
|
|
||||||
*/
|
|
||||||
export function newMessage<Mod>(
|
|
||||||
filter: UpdateFilter<Message, Mod>,
|
|
||||||
handler: NewMessageHandler<filters.Modify<Message, Mod>>['callback']
|
|
||||||
): NewMessageHandler
|
|
||||||
|
|
||||||
/** @internal */
|
|
||||||
export function newMessage(filter: any, handler?: any): NewMessageHandler {
|
|
||||||
return _create('new_message', filter, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an edit message handler
|
|
||||||
*
|
|
||||||
* @param handler Edit message handler
|
|
||||||
*/
|
|
||||||
export function editMessage(
|
|
||||||
handler: EditMessageHandler['callback']
|
|
||||||
): EditMessageHandler
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an edit message handler with a filter
|
|
||||||
*
|
|
||||||
* @param filter Update filter
|
|
||||||
* @param handler Edit message handler
|
|
||||||
*/
|
|
||||||
export function editMessage<Mod>(
|
|
||||||
filter: UpdateFilter<Message, Mod>,
|
|
||||||
handler: EditMessageHandler<filters.Modify<Message, Mod>>['callback']
|
|
||||||
): EditMessageHandler
|
|
||||||
|
|
||||||
/** @internal */
|
|
||||||
export function editMessage(
|
|
||||||
filter: any,
|
|
||||||
handler?: any
|
|
||||||
): EditMessageHandler {
|
|
||||||
return _create('edit_message', filter, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a delete message handler
|
|
||||||
*
|
|
||||||
* @param handler Delete message handler
|
|
||||||
*/
|
|
||||||
export function deleteMessage(
|
|
||||||
handler: DeleteMessageHandler['callback']
|
|
||||||
): DeleteMessageHandler
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a delete message handler with a filter
|
|
||||||
*
|
|
||||||
* @param filter Update filter
|
|
||||||
* @param handler Delete message handler
|
|
||||||
*/
|
|
||||||
export function deleteMessage<Mod>(
|
|
||||||
filter: UpdateFilter<DeleteMessageUpdate, Mod>,
|
|
||||||
handler: DeleteMessageHandler<
|
|
||||||
filters.Modify<DeleteMessageUpdate, Mod>
|
|
||||||
>['callback']
|
|
||||||
): DeleteMessageHandler
|
|
||||||
|
|
||||||
/** @internal */
|
|
||||||
export function deleteMessage(
|
|
||||||
filter: any,
|
|
||||||
handler?: any
|
|
||||||
): DeleteMessageHandler {
|
|
||||||
return _create('delete_message', filter, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a chat member update handler
|
|
||||||
*
|
|
||||||
* @param handler Chat member update handler
|
|
||||||
*/
|
|
||||||
export function chatMemberUpdate(
|
|
||||||
handler: ChatMemberUpdateHandler['callback']
|
|
||||||
): ChatMemberUpdateHandler
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a chat member update handler with a filter
|
|
||||||
*
|
|
||||||
* @param filter Update filter
|
|
||||||
* @param handler Chat member update handler
|
|
||||||
*/
|
|
||||||
export function chatMemberUpdate<Mod>(
|
|
||||||
filter: UpdateFilter<ChatMemberUpdate, Mod>,
|
|
||||||
handler: ChatMemberUpdateHandler<
|
|
||||||
filters.Modify<ChatMemberUpdate, Mod>
|
|
||||||
>['callback']
|
|
||||||
): ChatMemberUpdateHandler
|
|
||||||
|
|
||||||
/** @internal */
|
|
||||||
export function chatMemberUpdate(
|
|
||||||
filter: any,
|
|
||||||
handler?: any
|
|
||||||
): ChatMemberUpdateHandler {
|
|
||||||
return _create('chat_member', filter, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an inline query handler
|
|
||||||
*
|
|
||||||
* @param handler Inline query handler
|
|
||||||
*/
|
|
||||||
export function inlineQuery(
|
|
||||||
handler: InlineQueryHandler['callback']
|
|
||||||
): InlineQueryHandler
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an inline query handler with a filter
|
|
||||||
*
|
|
||||||
* @param filter Update filter
|
|
||||||
* @param handler Inline query handler
|
|
||||||
*/
|
|
||||||
export function inlineQuery<Mod>(
|
|
||||||
filter: UpdateFilter<InlineQuery, Mod>,
|
|
||||||
handler: InlineQueryHandler<
|
|
||||||
filters.Modify<InlineQuery, Mod>
|
|
||||||
>['callback']
|
|
||||||
): InlineQueryHandler
|
|
||||||
|
|
||||||
/** @internal */
|
|
||||||
export function inlineQuery(
|
|
||||||
filter: any,
|
|
||||||
handler?: any
|
|
||||||
): InlineQueryHandler {
|
|
||||||
return _create('inline_query', filter, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a chosen inline result handler
|
|
||||||
*
|
|
||||||
* @param handler Chosen inline result handler
|
|
||||||
*/
|
|
||||||
export function chosenInlineResult(
|
|
||||||
handler: ChosenInlineResultHandler['callback']
|
|
||||||
): ChosenInlineResultHandler
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a chosen inline result handler with a filter
|
|
||||||
*
|
|
||||||
* @param filter Update filter
|
|
||||||
* @param handler Chosen inline result handler
|
|
||||||
*/
|
|
||||||
export function chosenInlineResult<Mod>(
|
|
||||||
filter: UpdateFilter<ChosenInlineResult, Mod>,
|
|
||||||
handler: ChosenInlineResultHandler<
|
|
||||||
filters.Modify<ChosenInlineResult, Mod>
|
|
||||||
>['callback']
|
|
||||||
): ChosenInlineResultHandler
|
|
||||||
|
|
||||||
/** @internal */
|
|
||||||
export function chosenInlineResult(
|
|
||||||
filter: any,
|
|
||||||
handler?: any
|
|
||||||
): ChosenInlineResultHandler {
|
|
||||||
return _create('chosen_inline_result', filter, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a callback query handler
|
|
||||||
*
|
|
||||||
* @param handler Callback query handler
|
|
||||||
*/
|
|
||||||
export function callbackQuery(
|
|
||||||
handler: CallbackQueryHandler['callback']
|
|
||||||
): CallbackQueryHandler
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a callback query handler with a filter
|
|
||||||
*
|
|
||||||
* @param filter Update filter
|
|
||||||
* @param handler Callback query handler
|
|
||||||
*/
|
|
||||||
export function callbackQuery<Mod>(
|
|
||||||
filter: UpdateFilter<CallbackQuery, Mod>,
|
|
||||||
handler: CallbackQueryHandler<
|
|
||||||
filters.Modify<CallbackQuery, Mod>
|
|
||||||
>['callback']
|
|
||||||
): CallbackQueryHandler
|
|
||||||
|
|
||||||
/** @internal */
|
|
||||||
export function callbackQuery(
|
|
||||||
filter: any,
|
|
||||||
handler?: any
|
|
||||||
): CallbackQueryHandler {
|
|
||||||
return _create('callback_query', filter, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a poll update handler
|
|
||||||
*
|
|
||||||
* @param handler Poll update handler
|
|
||||||
*/
|
|
||||||
export function pollUpdate(
|
|
||||||
handler: PollUpdateHandler['callback']
|
|
||||||
): PollUpdateHandler
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a poll update handler with a filter
|
|
||||||
*
|
|
||||||
* @param filter Update filter
|
|
||||||
* @param handler Poll update handler
|
|
||||||
*/
|
|
||||||
export function pollUpdate<Mod>(
|
|
||||||
filter: UpdateFilter<PollUpdate, Mod>,
|
|
||||||
handler: PollUpdateHandler<filters.Modify<PollUpdate, Mod>>['callback']
|
|
||||||
): PollUpdateHandler
|
|
||||||
|
|
||||||
/** @internal */
|
|
||||||
export function pollUpdate(filter: any, handler?: any): PollUpdateHandler {
|
|
||||||
return _create('poll', filter, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a poll vote handler
|
|
||||||
*
|
|
||||||
* @param handler Poll vote handler
|
|
||||||
*/
|
|
||||||
export function pollVote(
|
|
||||||
handler: PollVoteHandler['callback']
|
|
||||||
): PollVoteHandler
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a poll vote handler with a filter
|
|
||||||
*
|
|
||||||
* @param filter Update filter
|
|
||||||
* @param handler Poll vote handler
|
|
||||||
*/
|
|
||||||
export function pollVote<Mod>(
|
|
||||||
filter: UpdateFilter<PollVoteUpdate, Mod>,
|
|
||||||
handler: PollVoteHandler<
|
|
||||||
filters.Modify<PollVoteUpdate, Mod>
|
|
||||||
>['callback']
|
|
||||||
): PollVoteHandler
|
|
||||||
|
|
||||||
/** @internal */
|
|
||||||
export function pollVote(filter: any, handler?: any): PollVoteHandler {
|
|
||||||
return _create('poll_vote', filter, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an user status update handler
|
|
||||||
*
|
|
||||||
* @param handler User status update handler
|
|
||||||
*/
|
|
||||||
export function userStatusUpdate(
|
|
||||||
handler: UserStatusUpdateHandler['callback']
|
|
||||||
): UserStatusUpdateHandler
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an user status update handler with a filter
|
|
||||||
*
|
|
||||||
* @param filter Update filter
|
|
||||||
* @param handler User status update handler
|
|
||||||
*/
|
|
||||||
export function userStatusUpdate<Mod>(
|
|
||||||
filter: UpdateFilter<UserStatusUpdate, Mod>,
|
|
||||||
handler: UserStatusUpdateHandler<
|
|
||||||
filters.Modify<UserStatusUpdate, Mod>
|
|
||||||
>['callback']
|
|
||||||
): UserStatusUpdateHandler
|
|
||||||
|
|
||||||
/** @internal */
|
|
||||||
export function userStatusUpdate(
|
|
||||||
filter: any,
|
|
||||||
handler?: any
|
|
||||||
): UserStatusUpdateHandler {
|
|
||||||
return _create('user_status', filter, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an user typing handler
|
|
||||||
*
|
|
||||||
* @param handler User typing handler
|
|
||||||
*/
|
|
||||||
export function userTyping(
|
|
||||||
handler: UserTypingHandler['callback']
|
|
||||||
): UserTypingHandler
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an user typing handler with a filter
|
|
||||||
*
|
|
||||||
* @param filter Update filter
|
|
||||||
* @param handler User typing handler
|
|
||||||
*/
|
|
||||||
export function userTyping<Mod>(
|
|
||||||
filter: UpdateFilter<UserTypingUpdate, Mod>,
|
|
||||||
handler: UserTypingHandler<
|
|
||||||
filters.Modify<UserTypingUpdate, Mod>
|
|
||||||
>['callback']
|
|
||||||
): UserTypingHandler
|
|
||||||
|
|
||||||
/** @internal */
|
|
||||||
export function userTyping(filter: any, handler?: any): UserTypingHandler {
|
|
||||||
return _create('user_typing', filter, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a history read handler
|
|
||||||
*
|
|
||||||
* @param handler History read handler
|
|
||||||
*/
|
|
||||||
export function historyRead(
|
|
||||||
handler: HistoryReadHandler['callback']
|
|
||||||
): HistoryReadHandler
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a history read handler with a filter
|
|
||||||
*
|
|
||||||
* @param filter Update filter
|
|
||||||
* @param handler History read handler
|
|
||||||
*/
|
|
||||||
export function historyRead<Mod>(
|
|
||||||
filter: UpdateFilter<HistoryReadUpdate, Mod>,
|
|
||||||
handler: HistoryReadHandler<
|
|
||||||
filters.Modify<HistoryReadUpdate, Mod>
|
|
||||||
>['callback']
|
|
||||||
): HistoryReadHandler
|
|
||||||
|
|
||||||
/** @internal */
|
|
||||||
export function historyRead(
|
|
||||||
filter: any,
|
|
||||||
handler?: any
|
|
||||||
): HistoryReadHandler {
|
|
||||||
return _create('history_read', filter, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
// end-codegen
|
|
||||||
}
|
|
|
@ -8,6 +8,15 @@ import {
|
||||||
MtCuteArgumentError,
|
MtCuteArgumentError,
|
||||||
TelegramClient,
|
TelegramClient,
|
||||||
UsersIndex,
|
UsersIndex,
|
||||||
|
ChatMemberUpdate,
|
||||||
|
ChosenInlineResult,
|
||||||
|
PollUpdate,
|
||||||
|
PollVoteUpdate,
|
||||||
|
UserStatusUpdate,
|
||||||
|
UserTypingUpdate,
|
||||||
|
DeleteMessageUpdate,
|
||||||
|
HistoryReadUpdate,
|
||||||
|
ParsedUpdate,
|
||||||
} from '@mtcute/client'
|
} from '@mtcute/client'
|
||||||
import { tl } from '@mtcute/tl'
|
import { tl } from '@mtcute/tl'
|
||||||
// begin-codegen-imports
|
// begin-codegen-imports
|
||||||
|
@ -28,262 +37,20 @@ import {
|
||||||
HistoryReadHandler,
|
HistoryReadHandler,
|
||||||
} from './handler'
|
} from './handler'
|
||||||
// end-codegen-imports
|
// end-codegen-imports
|
||||||
import { ParsedUpdate } from './handler'
|
|
||||||
import { filters, UpdateFilter } from './filters'
|
import { filters, UpdateFilter } from './filters'
|
||||||
import { handlers } from './builders'
|
|
||||||
import {
|
|
||||||
ChatMemberUpdate,
|
|
||||||
ChosenInlineResult,
|
|
||||||
PollUpdate,
|
|
||||||
PollVoteUpdate,
|
|
||||||
UserStatusUpdate,
|
|
||||||
UserTypingUpdate,
|
|
||||||
DeleteMessageUpdate,
|
|
||||||
HistoryReadUpdate,
|
|
||||||
} from './updates'
|
|
||||||
import { IStateStorage, UpdateState, StateKeyDelegate } from './state'
|
import { IStateStorage, UpdateState, StateKeyDelegate } from './state'
|
||||||
import { defaultStateKeyDelegate } from './state'
|
import { defaultStateKeyDelegate } from './state'
|
||||||
import { PropagationAction } from './propagation'
|
import { PropagationAction } from './propagation'
|
||||||
import EventEmitter from 'events'
|
|
||||||
|
|
||||||
const noop = () => {}
|
const noop = () => {}
|
||||||
|
|
||||||
type ParserFunction = (
|
|
||||||
client: TelegramClient,
|
|
||||||
upd: tl.TypeUpdate | tl.TypeMessage,
|
|
||||||
users: UsersIndex,
|
|
||||||
chats: ChatsIndex
|
|
||||||
) => any
|
|
||||||
type UpdateParser = [Exclude<UpdateHandler['type'], 'raw'>, ParserFunction]
|
|
||||||
|
|
||||||
const baseMessageParser: ParserFunction = (
|
|
||||||
client: TelegramClient,
|
|
||||||
upd,
|
|
||||||
users,
|
|
||||||
chats
|
|
||||||
) =>
|
|
||||||
new Message(
|
|
||||||
client,
|
|
||||||
tl.isAnyMessage(upd) ? upd : (upd as any).message,
|
|
||||||
users,
|
|
||||||
chats,
|
|
||||||
upd._ === 'updateNewScheduledMessage'
|
|
||||||
)
|
|
||||||
|
|
||||||
const newMessageParser: UpdateParser = ['new_message', baseMessageParser]
|
|
||||||
const editMessageParser: UpdateParser = ['edit_message', baseMessageParser]
|
|
||||||
const chatMemberParser: UpdateParser = [
|
|
||||||
'chat_member',
|
|
||||||
(client, upd, users, chats) =>
|
|
||||||
new ChatMemberUpdate(client, upd as any, users, chats),
|
|
||||||
]
|
|
||||||
const callbackQueryParser: UpdateParser = [
|
|
||||||
'callback_query',
|
|
||||||
(client, upd, users) => new CallbackQuery(client, upd as any, users),
|
|
||||||
]
|
|
||||||
const userTypingParser: UpdateParser = [
|
|
||||||
'user_typing',
|
|
||||||
(client, upd) => new UserTypingUpdate(client, upd as any),
|
|
||||||
]
|
|
||||||
const deleteMessageParser: UpdateParser = [
|
|
||||||
'delete_message',
|
|
||||||
(client, upd) => new DeleteMessageUpdate(client, upd as any),
|
|
||||||
]
|
|
||||||
const historyReadParser: UpdateParser = [
|
|
||||||
'history_read',
|
|
||||||
(client, upd) => new HistoryReadUpdate(client, upd as any),
|
|
||||||
]
|
|
||||||
|
|
||||||
const PARSERS: Partial<
|
|
||||||
Record<(tl.TypeUpdate | tl.TypeMessage)['_'], UpdateParser>
|
|
||||||
> = {
|
|
||||||
message: newMessageParser,
|
|
||||||
messageEmpty: newMessageParser,
|
|
||||||
messageService: newMessageParser,
|
|
||||||
updateNewMessage: newMessageParser,
|
|
||||||
updateNewChannelMessage: newMessageParser,
|
|
||||||
updateNewScheduledMessage: newMessageParser,
|
|
||||||
updateEditMessage: editMessageParser,
|
|
||||||
updateEditChannelMessage: editMessageParser,
|
|
||||||
updateChatParticipant: chatMemberParser,
|
|
||||||
updateChannelParticipant: chatMemberParser,
|
|
||||||
updateBotInlineQuery: [
|
|
||||||
'inline_query',
|
|
||||||
(client, upd, users) => new InlineQuery(client, upd as any, users),
|
|
||||||
],
|
|
||||||
updateBotInlineSend: [
|
|
||||||
'chosen_inline_result',
|
|
||||||
(client, upd, users) =>
|
|
||||||
new ChosenInlineResult(client, upd as any, users),
|
|
||||||
],
|
|
||||||
updateBotCallbackQuery: callbackQueryParser,
|
|
||||||
updateInlineBotCallbackQuery: callbackQueryParser,
|
|
||||||
updateMessagePoll: [
|
|
||||||
'poll',
|
|
||||||
(client, upd, users) => new PollUpdate(client, upd as any, users),
|
|
||||||
],
|
|
||||||
updateMessagePollVote: [
|
|
||||||
'poll_vote',
|
|
||||||
(client, upd, users) => new PollVoteUpdate(client, upd as any, users),
|
|
||||||
],
|
|
||||||
updateUserStatus: [
|
|
||||||
'user_status',
|
|
||||||
(client, upd) => new UserStatusUpdate(client, upd as any),
|
|
||||||
],
|
|
||||||
updateChannelUserTyping: userTypingParser,
|
|
||||||
updateChatUserTyping: userTypingParser,
|
|
||||||
updateUserTyping: userTypingParser,
|
|
||||||
updateDeleteChannelMessages: deleteMessageParser,
|
|
||||||
updateDeleteMessages: deleteMessageParser,
|
|
||||||
updateReadHistoryInbox: historyReadParser,
|
|
||||||
updateReadHistoryOutbox: historyReadParser,
|
|
||||||
updateReadChannelInbox: historyReadParser,
|
|
||||||
updateReadChannelOutbox: historyReadParser,
|
|
||||||
updateReadChannelDiscussionInbox: historyReadParser,
|
|
||||||
updateReadChannelDiscussionOutbox: historyReadParser,
|
|
||||||
}
|
|
||||||
|
|
||||||
const HANDLER_TYPE_TO_UPDATE: Record<string, string[]> = {}
|
|
||||||
Object.keys(PARSERS).forEach((upd: keyof typeof PARSERS) => {
|
|
||||||
const handler = PARSERS[upd]![0]
|
|
||||||
if (!(handler in HANDLER_TYPE_TO_UPDATE))
|
|
||||||
HANDLER_TYPE_TO_UPDATE[handler] = []
|
|
||||||
HANDLER_TYPE_TO_UPDATE[handler].push(upd)
|
|
||||||
})
|
|
||||||
|
|
||||||
export declare interface Dispatcher<
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
State = never,
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
SceneName extends string = string
|
|
||||||
> {
|
|
||||||
on<T = {}>(
|
|
||||||
name: 'update',
|
|
||||||
handler: (update: ParsedUpdate & T) => void
|
|
||||||
): this
|
|
||||||
|
|
||||||
// begin-codegen-declare
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a plain old raw update handler
|
|
||||||
*
|
|
||||||
* @param name Event name
|
|
||||||
* @param handler Raw update handler
|
|
||||||
*/
|
|
||||||
on(name: 'raw', handler: RawUpdateHandler['callback']): this
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a plain old new message handler
|
|
||||||
*
|
|
||||||
* @param name Event name
|
|
||||||
* @param handler New message handler
|
|
||||||
*/
|
|
||||||
on(name: 'new_message', handler: NewMessageHandler['callback']): this
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a plain old edit message handler
|
|
||||||
*
|
|
||||||
* @param name Event name
|
|
||||||
* @param handler Edit message handler
|
|
||||||
*/
|
|
||||||
on(name: 'edit_message', handler: EditMessageHandler['callback']): this
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a plain old delete message handler
|
|
||||||
*
|
|
||||||
* @param name Event name
|
|
||||||
* @param handler Delete message handler
|
|
||||||
*/
|
|
||||||
on(name: 'delete_message', handler: DeleteMessageHandler['callback']): this
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a plain old chat member update handler
|
|
||||||
*
|
|
||||||
* @param name Event name
|
|
||||||
* @param handler Chat member update handler
|
|
||||||
*/
|
|
||||||
on(name: 'chat_member', handler: ChatMemberUpdateHandler['callback']): this
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a plain old inline query handler
|
|
||||||
*
|
|
||||||
* @param name Event name
|
|
||||||
* @param handler Inline query handler
|
|
||||||
*/
|
|
||||||
on(name: 'inline_query', handler: InlineQueryHandler['callback']): this
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a plain old chosen inline result handler
|
|
||||||
*
|
|
||||||
* @param name Event name
|
|
||||||
* @param handler Chosen inline result handler
|
|
||||||
*/
|
|
||||||
on(
|
|
||||||
name: 'chosen_inline_result',
|
|
||||||
handler: ChosenInlineResultHandler['callback']
|
|
||||||
): this
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a plain old callback query handler
|
|
||||||
*
|
|
||||||
* @param name Event name
|
|
||||||
* @param handler Callback query handler
|
|
||||||
*/
|
|
||||||
on(name: 'callback_query', handler: CallbackQueryHandler['callback']): this
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a plain old poll update handler
|
|
||||||
*
|
|
||||||
* @param name Event name
|
|
||||||
* @param handler Poll update handler
|
|
||||||
*/
|
|
||||||
on(name: 'poll', handler: PollUpdateHandler['callback']): this
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a plain old poll vote handler
|
|
||||||
*
|
|
||||||
* @param name Event name
|
|
||||||
* @param handler Poll vote handler
|
|
||||||
*/
|
|
||||||
on(name: 'poll_vote', handler: PollVoteHandler['callback']): this
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a plain old user status update handler
|
|
||||||
*
|
|
||||||
* @param name Event name
|
|
||||||
* @param handler User status update handler
|
|
||||||
*/
|
|
||||||
on(name: 'user_status', handler: UserStatusUpdateHandler['callback']): this
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a plain old user typing handler
|
|
||||||
*
|
|
||||||
* @param name Event name
|
|
||||||
* @param handler User typing handler
|
|
||||||
*/
|
|
||||||
on(name: 'user_typing', handler: UserTypingHandler['callback']): this
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a plain old history read handler
|
|
||||||
*
|
|
||||||
* @param name Event name
|
|
||||||
* @param handler History read handler
|
|
||||||
*/
|
|
||||||
on(name: 'history_read', handler: HistoryReadHandler['callback']): this
|
|
||||||
|
|
||||||
// end-codegen-declare
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates dispatcher
|
* Updates dispatcher
|
||||||
*/
|
*/
|
||||||
export class Dispatcher<
|
export class Dispatcher<State = never, SceneName extends string = string> {
|
||||||
State = never,
|
|
||||||
SceneName extends string = string
|
|
||||||
> extends EventEmitter {
|
|
||||||
private _groups: Record<
|
private _groups: Record<
|
||||||
number,
|
number,
|
||||||
Record<UpdateHandler['type'], UpdateHandler[]>
|
Record<UpdateHandler['name'], UpdateHandler[]>
|
||||||
> = {}
|
> = {}
|
||||||
private _groupsOrder: number[] = []
|
private _groupsOrder: number[] = []
|
||||||
|
|
||||||
|
@ -304,8 +71,6 @@ export class Dispatcher<
|
||||||
private _customStateKeyDelegate?: StateKeyDelegate
|
private _customStateKeyDelegate?: StateKeyDelegate
|
||||||
private _customStorage?: IStateStorage
|
private _customStorage?: IStateStorage
|
||||||
|
|
||||||
private _handlersCount: Record<string, number> = {}
|
|
||||||
|
|
||||||
private _errorHandler?: <T = {}>(
|
private _errorHandler?: <T = {}>(
|
||||||
err: Error,
|
err: Error,
|
||||||
update: ParsedUpdate & T,
|
update: ParsedUpdate & T,
|
||||||
|
@ -346,7 +111,8 @@ export class Dispatcher<
|
||||||
storage?: IStateStorage | StateKeyDelegate,
|
storage?: IStateStorage | StateKeyDelegate,
|
||||||
key?: StateKeyDelegate
|
key?: StateKeyDelegate
|
||||||
) {
|
) {
|
||||||
super()
|
this.dispatchRawUpdate = this.dispatchRawUpdate.bind(this)
|
||||||
|
this.dispatchUpdate = this.dispatchUpdate.bind(this)
|
||||||
|
|
||||||
if (client) {
|
if (client) {
|
||||||
if (client instanceof TelegramClient) {
|
if (client instanceof TelegramClient) {
|
||||||
|
@ -383,7 +149,9 @@ export class Dispatcher<
|
||||||
* Dispatcher also uses bound client to throw errors
|
* Dispatcher also uses bound client to throw errors
|
||||||
*/
|
*/
|
||||||
bindToClient(client: TelegramClient): void {
|
bindToClient(client: TelegramClient): void {
|
||||||
client['dispatchUpdate'] = this.dispatchUpdate.bind(this)
|
client.on('update', this.dispatchUpdate)
|
||||||
|
client.on('raw_update', this.dispatchRawUpdate)
|
||||||
|
|
||||||
this._client = client
|
this._client = client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,11 +163,103 @@ export class Dispatcher<
|
||||||
*/
|
*/
|
||||||
unbind(): void {
|
unbind(): void {
|
||||||
if (this._client) {
|
if (this._client) {
|
||||||
this._client['dispatchUpdate'] = noop
|
this._client.off('update', this.dispatchUpdate)
|
||||||
|
this._client.off('raw_update', this.dispatchRawUpdate)
|
||||||
|
|
||||||
this._client = undefined
|
this._client = undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process a raw update with this dispatcher.
|
||||||
|
* Calling this method without bound client will not work.
|
||||||
|
*
|
||||||
|
* Under the hood asynchronously calls {@link dispatchRawUpdateNow}
|
||||||
|
* with error handler set to client's one.
|
||||||
|
*
|
||||||
|
* @param update Update to process
|
||||||
|
* @param users Users map
|
||||||
|
* @param chats Chats map
|
||||||
|
*/
|
||||||
|
dispatchRawUpdate(
|
||||||
|
update: tl.TypeUpdate | tl.TypeMessage,
|
||||||
|
users: UsersIndex,
|
||||||
|
chats: ChatsIndex
|
||||||
|
): void {
|
||||||
|
if (!this._client) return
|
||||||
|
|
||||||
|
// order does not matter in the dispatcher,
|
||||||
|
// so we can handle each update in its own task
|
||||||
|
this.dispatchRawUpdateNow(update, users, chats).catch((err) =>
|
||||||
|
this._client!['_emitError'](err)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process a raw update right now in the current stack.
|
||||||
|
*
|
||||||
|
* Unlike {@link dispatchRawUpdate}, this does not schedule
|
||||||
|
* the update to be dispatched, but dispatches it immediately,
|
||||||
|
* and after `await`ing this method you can be certain that the update
|
||||||
|
* was fully processed by all the registered handlers, including children.
|
||||||
|
*
|
||||||
|
* @param update Update to process
|
||||||
|
* @param users Users map
|
||||||
|
* @param chats Chats map
|
||||||
|
* @returns Whether the update was handled
|
||||||
|
*/
|
||||||
|
async dispatchRawUpdateNow(
|
||||||
|
update: tl.TypeUpdate | tl.TypeMessage,
|
||||||
|
users: UsersIndex,
|
||||||
|
chats: ChatsIndex
|
||||||
|
): Promise<boolean> {
|
||||||
|
if (!this._client) return false
|
||||||
|
|
||||||
|
let handled = false
|
||||||
|
|
||||||
|
outer: for (const grp of this._groupsOrder) {
|
||||||
|
const group = this._groups[grp]
|
||||||
|
|
||||||
|
if ('raw' in group) {
|
||||||
|
const handlers = group['raw'] as RawUpdateHandler[]
|
||||||
|
|
||||||
|
for (const h of handlers) {
|
||||||
|
let result: void | PropagationAction
|
||||||
|
|
||||||
|
if (
|
||||||
|
!h.check ||
|
||||||
|
(await h.check(this._client, update, users, chats))
|
||||||
|
) {
|
||||||
|
result = await h.callback(
|
||||||
|
this._client,
|
||||||
|
update,
|
||||||
|
users,
|
||||||
|
chats
|
||||||
|
)
|
||||||
|
handled = true
|
||||||
|
} else continue
|
||||||
|
|
||||||
|
switch (result) {
|
||||||
|
case 'continue':
|
||||||
|
continue
|
||||||
|
case 'stop':
|
||||||
|
break outer
|
||||||
|
case 'stop-children':
|
||||||
|
return handled
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const child of this._children) {
|
||||||
|
handled ||= await child.dispatchRawUpdateNow(update, users, chats)
|
||||||
|
}
|
||||||
|
|
||||||
|
return handled
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process an update with this dispatcher.
|
* Process an update with this dispatcher.
|
||||||
* Calling this method without bound client will not work.
|
* Calling this method without bound client will not work.
|
||||||
|
@ -408,19 +268,13 @@ export class Dispatcher<
|
||||||
* with error handler set to client's one.
|
* with error handler set to client's one.
|
||||||
*
|
*
|
||||||
* @param update Update to process
|
* @param update Update to process
|
||||||
* @param users Map of users
|
|
||||||
* @param chats Map of chats
|
|
||||||
*/
|
*/
|
||||||
dispatchUpdate(
|
dispatchUpdate(update: ParsedUpdate): void {
|
||||||
update: tl.TypeUpdate | tl.TypeMessage,
|
|
||||||
users: UsersIndex,
|
|
||||||
chats: ChatsIndex
|
|
||||||
): void {
|
|
||||||
if (!this._client) return
|
if (!this._client) return
|
||||||
|
|
||||||
// order does not matter in the dispatcher,
|
// order does not matter in the dispatcher,
|
||||||
// so we can handle each update in its own task
|
// so we can handle each update in its own task
|
||||||
this.dispatchUpdateNow(update, users, chats).catch((err) =>
|
this.dispatchUpdateNow(update).catch((err) =>
|
||||||
this._client!['_emitError'](err)
|
this._client!['_emitError'](err)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -434,58 +288,31 @@ export class Dispatcher<
|
||||||
* was fully processed by all the registered handlers, including children.
|
* was fully processed by all the registered handlers, including children.
|
||||||
*
|
*
|
||||||
* @param update Update to process
|
* @param update Update to process
|
||||||
* @param users Map of users
|
|
||||||
* @param chats Map of chats
|
|
||||||
* @returns Whether the update was handled
|
* @returns Whether the update was handled
|
||||||
*/
|
*/
|
||||||
async dispatchUpdateNow(
|
async dispatchUpdateNow(update: ParsedUpdate): Promise<boolean> {
|
||||||
update: tl.TypeUpdate | tl.TypeMessage,
|
return this._dispatchUpdateNowImpl(update)
|
||||||
users: UsersIndex,
|
|
||||||
chats: ChatsIndex
|
|
||||||
): Promise<boolean> {
|
|
||||||
return this._dispatchUpdateNowImpl(update, users, chats)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _dispatchUpdateNowImpl(
|
private async _dispatchUpdateNowImpl(
|
||||||
update: tl.TypeUpdate | tl.TypeMessage | null,
|
update: ParsedUpdate,
|
||||||
users: UsersIndex | null,
|
|
||||||
chats: ChatsIndex | null,
|
|
||||||
// this is getting a bit crazy lol
|
// this is getting a bit crazy lol
|
||||||
parsed?: any,
|
|
||||||
parsedType?: Exclude<UpdateHandler['type'], 'raw'> | null,
|
|
||||||
parsedState?: UpdateState<State, SceneName> | null,
|
parsedState?: UpdateState<State, SceneName> | null,
|
||||||
parsedScene?: string | null,
|
parsedScene?: string | null,
|
||||||
forceScene?: true
|
forceScene?: true
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
if (!this._client) return false
|
if (!this._client) return false
|
||||||
|
|
||||||
const isRawMessage = update && tl.isAnyMessage(update)
|
|
||||||
|
|
||||||
if (parsed === undefined) {
|
|
||||||
const pair = PARSERS[update!._]
|
|
||||||
if (pair) {
|
|
||||||
if (
|
|
||||||
this._handlersCount[update!._] ||
|
|
||||||
this.listenerCount(pair[0])
|
|
||||||
) {
|
|
||||||
parsed = pair[1](this._client, update!, users!, chats!)
|
|
||||||
parsedType = pair[0]
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
parsed = parsedType = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parsedScene === undefined) {
|
if (parsedScene === undefined) {
|
||||||
if (
|
if (
|
||||||
this._storage &&
|
this._storage &&
|
||||||
this._scenes &&
|
this._scenes &&
|
||||||
(parsedType === 'new_message' ||
|
(update.name === 'new_message' ||
|
||||||
parsedType === 'edit_message' ||
|
update.name === 'edit_message' ||
|
||||||
parsedType === 'callback_query')
|
update.name === 'callback_query')
|
||||||
) {
|
) {
|
||||||
// no need to fetch scene if there are no registered scenes
|
// no need to fetch scene if there are no registered scenes
|
||||||
const key = await this._stateKeyDelegate!(parsed)
|
const key = await this._stateKeyDelegate!(update.data)
|
||||||
if (key) {
|
if (key) {
|
||||||
parsedScene = await this._storage.getCurrentScene(key)
|
parsedScene = await this._storage.getCurrentScene(key)
|
||||||
} else {
|
} else {
|
||||||
|
@ -508,10 +335,6 @@ export class Dispatcher<
|
||||||
|
|
||||||
return this._scenes[parsedScene]._dispatchUpdateNowImpl(
|
return this._scenes[parsedScene]._dispatchUpdateNowImpl(
|
||||||
update,
|
update,
|
||||||
users,
|
|
||||||
chats,
|
|
||||||
parsed,
|
|
||||||
parsedType,
|
|
||||||
parsedState,
|
parsedState,
|
||||||
parsedScene,
|
parsedScene,
|
||||||
true
|
true
|
||||||
|
@ -522,16 +345,18 @@ export class Dispatcher<
|
||||||
if (parsedState === undefined) {
|
if (parsedState === undefined) {
|
||||||
if (
|
if (
|
||||||
this._storage &&
|
this._storage &&
|
||||||
(parsedType === 'new_message' ||
|
(update.name === 'new_message' ||
|
||||||
parsedType === 'edit_message' ||
|
update.name === 'edit_message' ||
|
||||||
parsedType === 'callback_query')
|
update.name === 'callback_query')
|
||||||
) {
|
) {
|
||||||
const key = await this._stateKeyDelegate!(parsed)
|
const key = await this._stateKeyDelegate!(update.data)
|
||||||
if (key) {
|
if (key) {
|
||||||
let customKey
|
let customKey
|
||||||
if (
|
if (
|
||||||
!this._customStateKeyDelegate ||
|
!this._customStateKeyDelegate ||
|
||||||
(customKey = await this._customStateKeyDelegate(parsed))
|
(customKey = await this._customStateKeyDelegate(
|
||||||
|
update.data
|
||||||
|
))
|
||||||
) {
|
) {
|
||||||
parsedState = new UpdateState(
|
parsedState = new UpdateState(
|
||||||
this._storage!,
|
this._storage!,
|
||||||
|
@ -552,79 +377,23 @@ export class Dispatcher<
|
||||||
|
|
||||||
let shouldDispatch = true
|
let shouldDispatch = true
|
||||||
let shouldDispatchChildren = true
|
let shouldDispatchChildren = true
|
||||||
let wasHandled = false
|
let handled = false
|
||||||
let updateInfo: any = null
|
|
||||||
|
|
||||||
if (parsed) {
|
switch (await this._preUpdateHandler?.(update, parsedState as any)) {
|
||||||
updateInfo = { type: parsedType, data: parsed }
|
case 'stop':
|
||||||
switch (
|
shouldDispatch = false
|
||||||
await this._preUpdateHandler?.(
|
break
|
||||||
updateInfo as any,
|
case 'stop-children':
|
||||||
parsedState as any
|
return false
|
||||||
)
|
|
||||||
) {
|
|
||||||
case 'stop':
|
|
||||||
shouldDispatch = false
|
|
||||||
break
|
|
||||||
case 'stop-children':
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldDispatch) {
|
if (shouldDispatch) {
|
||||||
if (update && !isRawMessage) {
|
|
||||||
this.emit('raw', update, users, chats)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parsedType) {
|
|
||||||
this.emit('update', updateInfo)
|
|
||||||
this.emit(parsedType, parsed)
|
|
||||||
}
|
|
||||||
|
|
||||||
outer: for (const grp of this._groupsOrder) {
|
outer: for (const grp of this._groupsOrder) {
|
||||||
const group = this._groups[grp]
|
const group = this._groups[grp]
|
||||||
|
|
||||||
if (update && !isRawMessage && 'raw' in group) {
|
if (update.name in group) {
|
||||||
const handlers = group['raw'] as RawUpdateHandler[]
|
|
||||||
|
|
||||||
for (const h of handlers) {
|
|
||||||
let result: void | PropagationAction
|
|
||||||
|
|
||||||
if (
|
|
||||||
!h.check ||
|
|
||||||
(await h.check(
|
|
||||||
this._client,
|
|
||||||
update as any,
|
|
||||||
users!,
|
|
||||||
chats!
|
|
||||||
))
|
|
||||||
) {
|
|
||||||
result = await h.callback(
|
|
||||||
this._client,
|
|
||||||
update as any,
|
|
||||||
users!,
|
|
||||||
chats!
|
|
||||||
)
|
|
||||||
wasHandled = true
|
|
||||||
} else continue
|
|
||||||
|
|
||||||
switch (result) {
|
|
||||||
case 'continue':
|
|
||||||
continue
|
|
||||||
case 'stop':
|
|
||||||
break outer
|
|
||||||
case 'stop-children':
|
|
||||||
shouldDispatchChildren = false
|
|
||||||
break outer
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parsedType && parsedType in group) {
|
|
||||||
// raw is not handled here, so we can safely assume this
|
// raw is not handled here, so we can safely assume this
|
||||||
const handlers = group[parsedType] as Exclude<
|
const handlers = group[update.name] as Exclude<
|
||||||
UpdateHandler,
|
UpdateHandler,
|
||||||
RawUpdateHandler
|
RawUpdateHandler
|
||||||
>[]
|
>[]
|
||||||
|
@ -635,13 +404,16 @@ export class Dispatcher<
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!h.check ||
|
!h.check ||
|
||||||
(await h.check(parsed, parsedState as never))
|
(await h.check(
|
||||||
|
update.data as any,
|
||||||
|
parsedState as never
|
||||||
|
))
|
||||||
) {
|
) {
|
||||||
result = await h.callback(
|
result = await h.callback(
|
||||||
parsed,
|
update.data as any,
|
||||||
parsedState as never
|
parsedState as never
|
||||||
)
|
)
|
||||||
wasHandled = true
|
handled = true
|
||||||
} else continue
|
} else continue
|
||||||
|
|
||||||
switch (result) {
|
switch (result) {
|
||||||
|
@ -669,10 +441,6 @@ export class Dispatcher<
|
||||||
scene
|
scene
|
||||||
]._dispatchUpdateNowImpl(
|
]._dispatchUpdateNowImpl(
|
||||||
update,
|
update,
|
||||||
users,
|
|
||||||
chats,
|
|
||||||
parsed,
|
|
||||||
parsedType,
|
|
||||||
undefined,
|
undefined,
|
||||||
scene,
|
scene,
|
||||||
true
|
true
|
||||||
|
@ -686,7 +454,7 @@ export class Dispatcher<
|
||||||
if (this._errorHandler) {
|
if (this._errorHandler) {
|
||||||
const handled = await this._errorHandler(
|
const handled = await this._errorHandler(
|
||||||
e,
|
e,
|
||||||
updateInfo as any,
|
update,
|
||||||
parsedState as never
|
parsedState as never
|
||||||
)
|
)
|
||||||
if (!handled) throw e
|
if (!handled) throw e
|
||||||
|
@ -700,25 +468,13 @@ export class Dispatcher<
|
||||||
|
|
||||||
if (shouldDispatchChildren) {
|
if (shouldDispatchChildren) {
|
||||||
for (const child of this._children) {
|
for (const child of this._children) {
|
||||||
wasHandled ||= await child._dispatchUpdateNowImpl(
|
handled ||= await child._dispatchUpdateNowImpl(update)
|
||||||
update,
|
|
||||||
users,
|
|
||||||
chats,
|
|
||||||
parsed,
|
|
||||||
parsedType
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updateInfo) {
|
this._postUpdateHandler?.(handled, update, parsedState as any)
|
||||||
this._postUpdateHandler?.(
|
|
||||||
wasHandled,
|
|
||||||
updateInfo,
|
|
||||||
parsedState as any
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return wasHandled
|
return handled
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -734,28 +490,23 @@ export class Dispatcher<
|
||||||
this._groupsOrder.sort((a, b) => a - b)
|
this._groupsOrder.sort((a, b) => a - b)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(handler.type in this._groups[group])) {
|
if (!(handler.name in this._groups[group])) {
|
||||||
this._groups[group][handler.type] = []
|
this._groups[group][handler.name] = []
|
||||||
}
|
}
|
||||||
|
|
||||||
HANDLER_TYPE_TO_UPDATE[handler.type].forEach((upd) => {
|
this._groups[group][handler.name].push(handler)
|
||||||
if (!(upd in this._handlersCount)) this._handlersCount[upd] = 0
|
|
||||||
this._handlersCount[upd] += 1
|
|
||||||
})
|
|
||||||
|
|
||||||
this._groups[group][handler.type].push(handler)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove an update handler (or handlers) from a given
|
* Remove an update handler (or handlers) from a given
|
||||||
* handler group.
|
* handler group.
|
||||||
*
|
*
|
||||||
* @param handler Update handler to remove, its type or `'all'` to remove all
|
* @param handler Update handler to remove, its name or `'all'` to remove all
|
||||||
* @param group Handler group index (-1 to affect all groups)
|
* @param group Handler group index (-1 to affect all groups)
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
removeUpdateHandler(
|
removeUpdateHandler(
|
||||||
handler: UpdateHandler | UpdateHandler['type'] | 'all',
|
handler: UpdateHandler | UpdateHandler['name'] | 'all',
|
||||||
group = 0
|
group = 0
|
||||||
): void {
|
): void {
|
||||||
if (group !== -1 && !(group in this._groups)) {
|
if (group !== -1 && !(group in this._groups)) {
|
||||||
|
@ -766,38 +517,22 @@ export class Dispatcher<
|
||||||
if (handler === 'all') {
|
if (handler === 'all') {
|
||||||
if (group === -1) {
|
if (group === -1) {
|
||||||
this._groups = {}
|
this._groups = {}
|
||||||
this._handlersCount = {}
|
|
||||||
} else {
|
} else {
|
||||||
const grp = this._groups[group] as any
|
|
||||||
Object.keys(grp).forEach((handler) => {
|
|
||||||
HANDLER_TYPE_TO_UPDATE[handler].forEach((upd) => {
|
|
||||||
this._handlersCount[upd] -= grp[handler].length
|
|
||||||
})
|
|
||||||
})
|
|
||||||
delete this._groups[group]
|
delete this._groups[group]
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
HANDLER_TYPE_TO_UPDATE[handler].forEach((upd) => {
|
|
||||||
this._handlersCount[upd] -= this._groups[group][
|
|
||||||
handler
|
|
||||||
].length
|
|
||||||
})
|
|
||||||
delete this._groups[group][handler]
|
delete this._groups[group][handler]
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(handler.type in this._groups[group])) {
|
if (!(handler.name in this._groups[group])) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const idx = this._groups[group][handler.type].indexOf(handler)
|
const idx = this._groups[group][handler.name].indexOf(handler)
|
||||||
if (idx > 0) {
|
if (idx > -1) {
|
||||||
this._groups[group][handler.type].splice(idx, 1)
|
this._groups[group][handler.name].splice(idx, 1)
|
||||||
|
|
||||||
HANDLER_TYPE_TO_UPDATE[handler.type].forEach((upd) => {
|
|
||||||
this._handlersCount[upd] -= 1
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1071,10 +806,6 @@ export class Dispatcher<
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
Object.keys(other._handlersCount).forEach((typ) => {
|
|
||||||
this._handlersCount[typ] += other._handlersCount[typ]
|
|
||||||
})
|
|
||||||
|
|
||||||
other._children.forEach((it) => {
|
other._children.forEach((it) => {
|
||||||
it._unparent()
|
it._unparent()
|
||||||
this.addChild(it as any)
|
this.addChild(it as any)
|
||||||
|
@ -1121,14 +852,13 @@ export class Dispatcher<
|
||||||
dp._groups[idx] = {} as any
|
dp._groups[idx] = {} as any
|
||||||
|
|
||||||
Object.keys(this._groups[idx]).forEach(
|
Object.keys(this._groups[idx]).forEach(
|
||||||
(type: UpdateHandler['type']) => {
|
(type: UpdateHandler['name']) => {
|
||||||
dp._groups[idx][type] = [...this._groups[idx][type]]
|
dp._groups[idx][type] = [...this._groups[idx][type]]
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
dp._groupsOrder = [...this._groupsOrder]
|
dp._groupsOrder = [...this._groupsOrder]
|
||||||
dp._handlersCount = { ...this._handlersCount }
|
|
||||||
dp._errorHandler = this._errorHandler
|
dp._errorHandler = this._errorHandler
|
||||||
dp._customStateKeyDelegate = this._customStateKeyDelegate
|
dp._customStateKeyDelegate = this._customStateKeyDelegate
|
||||||
dp._customStorage = this._customStorage
|
dp._customStorage = this._customStorage
|
||||||
|
@ -1268,16 +998,23 @@ export class Dispatcher<
|
||||||
// addUpdateHandler convenience wrappers //
|
// addUpdateHandler convenience wrappers //
|
||||||
|
|
||||||
private _addKnownHandler(
|
private _addKnownHandler(
|
||||||
name: keyof typeof handlers,
|
name: UpdateHandler['name'],
|
||||||
filter: any,
|
filter: any,
|
||||||
handler?: any,
|
handler?: any,
|
||||||
group?: number
|
group?: number
|
||||||
): void {
|
): void {
|
||||||
if (typeof handler === 'number') {
|
if (typeof handler === 'number') {
|
||||||
this.addUpdateHandler((handlers as any)[name](filter), handler)
|
this.addUpdateHandler({
|
||||||
|
name,
|
||||||
|
callback: filter
|
||||||
|
}, handler)
|
||||||
} else {
|
} else {
|
||||||
this.addUpdateHandler(
|
this.addUpdateHandler(
|
||||||
(handlers as any)[name](filter, handler),
|
{
|
||||||
|
name,
|
||||||
|
callback: handler,
|
||||||
|
check: filter
|
||||||
|
},
|
||||||
group
|
group
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1285,32 +1022,6 @@ export class Dispatcher<
|
||||||
|
|
||||||
// begin-codegen
|
// begin-codegen
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a raw update handler without any filters
|
|
||||||
*
|
|
||||||
* @param handler Raw update handler
|
|
||||||
* @param group Handler group index
|
|
||||||
*/
|
|
||||||
onRawUpdate(handler: RawUpdateHandler['callback'], group?: number): void
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a raw update handler with a filter
|
|
||||||
*
|
|
||||||
* @param filter Update filter function
|
|
||||||
* @param handler Raw update handler
|
|
||||||
* @param group Handler group index
|
|
||||||
*/
|
|
||||||
onRawUpdate(
|
|
||||||
filter: RawUpdateHandler['check'],
|
|
||||||
handler: RawUpdateHandler['callback'],
|
|
||||||
group?: number
|
|
||||||
): void
|
|
||||||
|
|
||||||
/** @internal */
|
|
||||||
onRawUpdate(filter: any, handler?: any, group?: number): void {
|
|
||||||
this._addKnownHandler('rawUpdate', filter, handler, group)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a new message handler without any filters
|
* Register a new message handler without any filters
|
||||||
*
|
*
|
||||||
|
@ -1359,7 +1070,7 @@ export class Dispatcher<
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
onNewMessage(filter: any, handler?: any, group?: number): void {
|
onNewMessage(filter: any, handler?: any, group?: number): void {
|
||||||
this._addKnownHandler('newMessage', filter, handler, group)
|
this._addKnownHandler('new_message', filter, handler, group)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1410,7 +1121,7 @@ export class Dispatcher<
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
onEditMessage(filter: any, handler?: any, group?: number): void {
|
onEditMessage(filter: any, handler?: any, group?: number): void {
|
||||||
this._addKnownHandler('editMessage', filter, handler, group)
|
this._addKnownHandler('edit_message', filter, handler, group)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1441,7 +1152,7 @@ export class Dispatcher<
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
onDeleteMessage(filter: any, handler?: any, group?: number): void {
|
onDeleteMessage(filter: any, handler?: any, group?: number): void {
|
||||||
this._addKnownHandler('deleteMessage', filter, handler, group)
|
this._addKnownHandler('delete_message', filter, handler, group)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1472,7 +1183,7 @@ export class Dispatcher<
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
onChatMemberUpdate(filter: any, handler?: any, group?: number): void {
|
onChatMemberUpdate(filter: any, handler?: any, group?: number): void {
|
||||||
this._addKnownHandler('chatMemberUpdate', filter, handler, group)
|
this._addKnownHandler('chat_member', filter, handler, group)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1500,7 +1211,7 @@ export class Dispatcher<
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
onInlineQuery(filter: any, handler?: any, group?: number): void {
|
onInlineQuery(filter: any, handler?: any, group?: number): void {
|
||||||
this._addKnownHandler('inlineQuery', filter, handler, group)
|
this._addKnownHandler('inline_query', filter, handler, group)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1531,7 +1242,7 @@ export class Dispatcher<
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
onChosenInlineResult(filter: any, handler?: any, group?: number): void {
|
onChosenInlineResult(filter: any, handler?: any, group?: number): void {
|
||||||
this._addKnownHandler('chosenInlineResult', filter, handler, group)
|
this._addKnownHandler('chosen_inline_result', filter, handler, group)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1582,7 +1293,7 @@ export class Dispatcher<
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
onCallbackQuery(filter: any, handler?: any, group?: number): void {
|
onCallbackQuery(filter: any, handler?: any, group?: number): void {
|
||||||
this._addKnownHandler('callbackQuery', filter, handler, group)
|
this._addKnownHandler('callback_query', filter, handler, group)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1608,7 +1319,7 @@ export class Dispatcher<
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
onPollUpdate(filter: any, handler?: any, group?: number): void {
|
onPollUpdate(filter: any, handler?: any, group?: number): void {
|
||||||
this._addKnownHandler('pollUpdate', filter, handler, group)
|
this._addKnownHandler('poll', filter, handler, group)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1636,7 +1347,7 @@ export class Dispatcher<
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
onPollVote(filter: any, handler?: any, group?: number): void {
|
onPollVote(filter: any, handler?: any, group?: number): void {
|
||||||
this._addKnownHandler('pollVote', filter, handler, group)
|
this._addKnownHandler('poll_vote', filter, handler, group)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1667,7 +1378,7 @@ export class Dispatcher<
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
onUserStatusUpdate(filter: any, handler?: any, group?: number): void {
|
onUserStatusUpdate(filter: any, handler?: any, group?: number): void {
|
||||||
this._addKnownHandler('userStatusUpdate', filter, handler, group)
|
this._addKnownHandler('user_status', filter, handler, group)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1695,7 +1406,7 @@ export class Dispatcher<
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
onUserTyping(filter: any, handler?: any, group?: number): void {
|
onUserTyping(filter: any, handler?: any, group?: number): void {
|
||||||
this._addKnownHandler('userTyping', filter, handler, group)
|
this._addKnownHandler('user_typing', filter, handler, group)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1723,7 +1434,7 @@ export class Dispatcher<
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
onHistoryRead(filter: any, handler?: any, group?: number): void {
|
onHistoryRead(filter: any, handler?: any, group?: number): void {
|
||||||
this._addKnownHandler('historyRead', filter, handler, group)
|
this._addKnownHandler('history_read', filter, handler, group)
|
||||||
}
|
}
|
||||||
|
|
||||||
// end-codegen
|
// end-codegen
|
||||||
|
|
|
@ -23,14 +23,14 @@ import {
|
||||||
WebPage,
|
WebPage,
|
||||||
MessageAction,
|
MessageAction,
|
||||||
RawLocation,
|
RawLocation,
|
||||||
|
ChatMemberUpdate,
|
||||||
|
ChosenInlineResult,
|
||||||
|
UserStatusUpdate,
|
||||||
|
PollVoteUpdate,
|
||||||
|
UserTypingUpdate,
|
||||||
} from '@mtcute/client'
|
} from '@mtcute/client'
|
||||||
import { MaybeArray } from '@mtcute/core'
|
import { MaybeArray } from '@mtcute/core'
|
||||||
import { ChatMemberUpdate } from './updates'
|
|
||||||
import { ChosenInlineResult } from './updates/chosen-inline-result'
|
|
||||||
import { UpdateState } from './state'
|
import { UpdateState } from './state'
|
||||||
import { UserStatusUpdate } from './updates/user-status-update'
|
|
||||||
import { PollVoteUpdate } from './updates/poll-vote'
|
|
||||||
import { UserTypingUpdate } from './updates/user-typing-update'
|
|
||||||
|
|
||||||
function extractText(
|
function extractText(
|
||||||
obj: Message | InlineQuery | ChosenInlineResult | CallbackQuery
|
obj: Message | InlineQuery | ChosenInlineResult | CallbackQuery
|
||||||
|
|
|
@ -6,52 +6,42 @@ import {
|
||||||
CallbackQuery,
|
CallbackQuery,
|
||||||
UsersIndex,
|
UsersIndex,
|
||||||
ChatsIndex,
|
ChatsIndex,
|
||||||
|
ChatMemberUpdate,
|
||||||
|
PollVoteUpdate,
|
||||||
|
UserStatusUpdate,
|
||||||
|
ChosenInlineResult,
|
||||||
|
HistoryReadUpdate,
|
||||||
|
DeleteMessageUpdate,
|
||||||
|
PollUpdate,
|
||||||
|
UserTypingUpdate,
|
||||||
} from '@mtcute/client'
|
} from '@mtcute/client'
|
||||||
import { tl } from '@mtcute/tl'
|
import { tl } from '@mtcute/tl'
|
||||||
import { PropagationAction } from './propagation'
|
import { PropagationAction } from './propagation'
|
||||||
import {
|
|
||||||
ChatMemberUpdate,
|
|
||||||
ChosenInlineResult,
|
|
||||||
PollUpdate,
|
|
||||||
PollVoteUpdate,
|
|
||||||
UserStatusUpdate,
|
|
||||||
UserTypingUpdate,
|
|
||||||
DeleteMessageUpdate,
|
|
||||||
HistoryReadUpdate,
|
|
||||||
} from './updates'
|
|
||||||
|
|
||||||
interface BaseUpdateHandler<Type, Handler, Checker> {
|
interface BaseUpdateHandler<Name, Handler, Checker> {
|
||||||
type: Type
|
name: Name
|
||||||
callback: Handler
|
callback: Handler
|
||||||
|
|
||||||
check?: Checker
|
check?: Checker
|
||||||
}
|
}
|
||||||
|
|
||||||
type ParsedUpdateHandler<Type, Update, State = never> = BaseUpdateHandler<
|
type ParsedUpdateHandler<Name, Update, State = never> = BaseUpdateHandler<
|
||||||
Type,
|
Name,
|
||||||
(update: Update, state: State) => MaybeAsync<void | PropagationAction>,
|
(update: Update, state: State) => MaybeAsync<void | PropagationAction>,
|
||||||
(update: Update, state: State) => MaybeAsync<boolean>
|
(update: Update, state: State) => MaybeAsync<boolean>
|
||||||
>
|
>
|
||||||
|
|
||||||
type _ParsedUpdate<T> = T extends ParsedUpdateHandler<infer K, infer Q>
|
|
||||||
? {
|
|
||||||
readonly type: K
|
|
||||||
readonly data: Q
|
|
||||||
}
|
|
||||||
: never
|
|
||||||
export type ParsedUpdate = _ParsedUpdate<UpdateHandler>
|
|
||||||
|
|
||||||
export type RawUpdateHandler = BaseUpdateHandler<
|
export type RawUpdateHandler = BaseUpdateHandler<
|
||||||
'raw',
|
'raw',
|
||||||
(
|
(
|
||||||
client: TelegramClient,
|
client: TelegramClient,
|
||||||
update: tl.TypeUpdate,
|
update: tl.TypeUpdate | tl.TypeMessage,
|
||||||
users: UsersIndex,
|
users: UsersIndex,
|
||||||
chats: ChatsIndex
|
chats: ChatsIndex
|
||||||
) => MaybeAsync<void | PropagationAction>,
|
) => MaybeAsync<void | PropagationAction>,
|
||||||
(
|
(
|
||||||
client: TelegramClient,
|
client: TelegramClient,
|
||||||
update: tl.TypeUpdate,
|
update: tl.TypeUpdate | tl.TypeMessage,
|
||||||
users: UsersIndex,
|
users: UsersIndex,
|
||||||
chats: ChatsIndex
|
chats: ChatsIndex
|
||||||
) => MaybeAsync<boolean>
|
) => MaybeAsync<boolean>
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
export * from './builders'
|
|
||||||
export * from './dispatcher'
|
export * from './dispatcher'
|
||||||
export * from './filters'
|
export * from './filters'
|
||||||
export * from './handler'
|
export * from './handler'
|
||||||
export * from './propagation'
|
export * from './propagation'
|
||||||
export * from './updates'
|
|
||||||
export * from './wizard'
|
export * from './wizard'
|
||||||
export * from './callback-data-builder'
|
export * from './callback-data-builder'
|
||||||
export * from './conversation'
|
|
||||||
|
|
||||||
export { UpdateState, IStateStorage } from './state'
|
export { UpdateState, IStateStorage } from './state'
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
export * from './chat-member-update'
|
|
||||||
export * from './chosen-inline-result'
|
|
||||||
export * from './delete-message-update'
|
|
||||||
export * from './poll-update'
|
|
||||||
export * from './poll-vote'
|
|
||||||
export * from './user-status-update'
|
|
||||||
export * from './user-typing-update'
|
|
||||||
export * from './history-read-update'
|
|
Loading…
Reference in a new issue