refactor(dispatcher): store and lookup handlers by their type
avoids redundant loops over all registered handlers
This commit is contained in:
parent
2d335af78e
commit
b926178b9d
1 changed files with 89 additions and 43 deletions
|
@ -82,7 +82,7 @@ const userTypingParser: UpdateParser = [
|
||||||
]
|
]
|
||||||
const deleteMessageParser: UpdateParser = [
|
const deleteMessageParser: UpdateParser = [
|
||||||
'delete_message',
|
'delete_message',
|
||||||
(client, upd) => new DeleteMessageUpdate(client, upd as any)
|
(client, upd) => new DeleteMessageUpdate(client, upd as any),
|
||||||
]
|
]
|
||||||
|
|
||||||
const PARSERS: Partial<
|
const PARSERS: Partial<
|
||||||
|
@ -132,7 +132,10 @@ const PARSERS: Partial<
|
||||||
* Updates dispatcher
|
* Updates dispatcher
|
||||||
*/
|
*/
|
||||||
export class Dispatcher {
|
export class Dispatcher {
|
||||||
private _groups: Record<number, UpdateHandler[]> = {}
|
private _groups: Record<
|
||||||
|
number,
|
||||||
|
Record<UpdateHandler['type'], UpdateHandler[]>
|
||||||
|
> = {}
|
||||||
private _groupsOrder: number[] = []
|
private _groupsOrder: number[] = []
|
||||||
|
|
||||||
private _client?: TelegramClient
|
private _client?: TelegramClient
|
||||||
|
@ -220,7 +223,7 @@ export class Dispatcher {
|
||||||
async dispatchUpdateNow(
|
async dispatchUpdateNow(
|
||||||
update: tl.TypeUpdate | tl.TypeMessage,
|
update: tl.TypeUpdate | tl.TypeMessage,
|
||||||
users: UsersIndex,
|
users: UsersIndex,
|
||||||
chats: ChatsIndex,
|
chats: ChatsIndex
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
return this._dispatchUpdateNowImpl(update, users, chats)
|
return this._dispatchUpdateNowImpl(update, users, chats)
|
||||||
}
|
}
|
||||||
|
@ -246,33 +249,54 @@ export class Dispatcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
outer: for (const grp of this._groupsOrder) {
|
outer: for (const grp of this._groupsOrder) {
|
||||||
for (const handler of this._groups[grp]) {
|
const group = this._groups[grp]
|
||||||
|
|
||||||
|
let tryRaw = !isRawMessage
|
||||||
|
|
||||||
|
if (parsedType && parsedType in group) {
|
||||||
|
// raw is not handled here, so we can safely assume this
|
||||||
|
const handlers = group[parsedType] as Exclude<
|
||||||
|
UpdateHandler,
|
||||||
|
RawUpdateHandler
|
||||||
|
>[]
|
||||||
|
|
||||||
|
for (const h of handlers) {
|
||||||
|
let result: void | PropagationSymbol
|
||||||
|
|
||||||
|
if (!h.check || (await h.check(parsed, this._client))) {
|
||||||
|
result = await h.callback(parsed, this._client)
|
||||||
|
} else continue
|
||||||
|
|
||||||
|
if (result === ContinuePropagation) continue
|
||||||
|
if (result === StopPropagation) break outer
|
||||||
|
if (result === StopChildrenPropagation) return
|
||||||
|
|
||||||
|
tryRaw = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tryRaw && 'raw' in group) {
|
||||||
|
const handlers = group['raw'] as RawUpdateHandler[]
|
||||||
|
|
||||||
|
for (const h of handlers) {
|
||||||
let result: void | PropagationSymbol
|
let result: void | PropagationSymbol
|
||||||
|
|
||||||
if (
|
if (
|
||||||
handler.type === 'raw' &&
|
!h.check ||
|
||||||
!isRawMessage &&
|
(await h.check(
|
||||||
(!handler.check ||
|
|
||||||
(await handler.check(
|
|
||||||
this._client,
|
this._client,
|
||||||
update as any,
|
update as any,
|
||||||
users,
|
users,
|
||||||
chats
|
chats
|
||||||
)))
|
))
|
||||||
) {
|
) {
|
||||||
result = await handler.callback(
|
result = await h.callback(
|
||||||
this._client,
|
this._client,
|
||||||
update as any,
|
update as any,
|
||||||
users,
|
users,
|
||||||
chats
|
chats
|
||||||
)
|
)
|
||||||
} else if (
|
|
||||||
parsedType &&
|
|
||||||
handler.type === parsedType &&
|
|
||||||
(!handler.check ||
|
|
||||||
(await handler.check(parsed, this._client)))
|
|
||||||
) {
|
|
||||||
result = await handler.callback(parsed, this._client)
|
|
||||||
} else continue
|
} else continue
|
||||||
|
|
||||||
if (result === ContinuePropagation) continue
|
if (result === ContinuePropagation) continue
|
||||||
|
@ -282,9 +306,16 @@ export class Dispatcher {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (const child of this._children) {
|
for (const child of this._children) {
|
||||||
await child._dispatchUpdateNowImpl(update, users, chats, parsed, parsedType)
|
await child._dispatchUpdateNowImpl(
|
||||||
|
update,
|
||||||
|
users,
|
||||||
|
chats,
|
||||||
|
parsed,
|
||||||
|
parsedType
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -296,12 +327,16 @@ export class Dispatcher {
|
||||||
*/
|
*/
|
||||||
addUpdateHandler(handler: UpdateHandler, group = 0): void {
|
addUpdateHandler(handler: UpdateHandler, group = 0): void {
|
||||||
if (!(group in this._groups)) {
|
if (!(group in this._groups)) {
|
||||||
this._groups[group] = []
|
this._groups[group] = {} as any
|
||||||
this._groupsOrder.push(group)
|
this._groupsOrder.push(group)
|
||||||
this._groupsOrder.sort((a, b) => a - b)
|
this._groupsOrder.sort((a, b) => a - b)
|
||||||
}
|
}
|
||||||
|
|
||||||
this._groups[group].push(handler)
|
if (!(handler.type in this._groups[group])) {
|
||||||
|
this._groups[group][handler.type] = []
|
||||||
|
}
|
||||||
|
|
||||||
|
this._groups[group][handler.type].push(handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -309,24 +344,26 @@ export class Dispatcher {
|
||||||
* handler group.
|
* handler group.
|
||||||
*
|
*
|
||||||
* @param handler Update handler to remove, its type or `'all'` to remove all
|
* @param handler Update handler to remove, its type or `'all'` to remove all
|
||||||
* @param group Handler group index
|
* @param group Handler group index (-1 to affect all groups)
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
removeUpdateHandler(
|
removeUpdateHandler(
|
||||||
handler: UpdateHandler | UpdateHandler['type'] | 'all',
|
handler: UpdateHandler | UpdateHandler['type'] | 'all',
|
||||||
group = 0
|
group = 0
|
||||||
): void {
|
): void {
|
||||||
if (!(group in this._groups)) {
|
if (group !== -1 && !(group in this._groups)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof handler === 'string') {
|
if (typeof handler === 'string') {
|
||||||
if (handler === 'all') {
|
if (handler === 'all') {
|
||||||
delete this._groups[group]
|
if (group === -1) {
|
||||||
|
this._groups = {}
|
||||||
} else {
|
} else {
|
||||||
this._groups[group] = this._groups[group].filter(
|
delete this._groups[group]
|
||||||
(h) => h.type !== handler
|
}
|
||||||
)
|
} else {
|
||||||
|
delete this._groups[group][handler]
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -335,9 +372,9 @@ export class Dispatcher {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const idx = this._groups[group].indexOf(handler)
|
const idx = this._groups[group][handler.type].indexOf(handler)
|
||||||
if (idx > 0) {
|
if (idx > 0) {
|
||||||
this._groups[group].splice(idx, 1)
|
this._groups[group][handler.type].splice(idx, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -418,10 +455,19 @@ export class Dispatcher {
|
||||||
extend(other: Dispatcher): void {
|
extend(other: Dispatcher): void {
|
||||||
other._groupsOrder.forEach((group) => {
|
other._groupsOrder.forEach((group) => {
|
||||||
if (!(group in this._groups)) {
|
if (!(group in this._groups)) {
|
||||||
this._groups[group] = []
|
this._groups[group] = other._groups[group]
|
||||||
this._groupsOrder.push(group)
|
this._groupsOrder.push(group)
|
||||||
|
} else {
|
||||||
|
const otherGrp = other._groups[group] as any
|
||||||
|
const selfGrp = this._groups[group] as any
|
||||||
|
Object.keys(otherGrp).forEach((typ) => {
|
||||||
|
if (!(typ in selfGrp)) {
|
||||||
|
selfGrp[typ] = otherGrp[typ]
|
||||||
|
} else {
|
||||||
|
selfGrp[typ].push(...otherGrp[typ])
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
this._groups[group].push(...other._groups[group])
|
|
||||||
})
|
})
|
||||||
|
|
||||||
this._groupsOrder.sort((a, b) => a - b)
|
this._groupsOrder.sort((a, b) => a - b)
|
||||||
|
|
Loading…
Reference in a new issue