feat(dispatcher): local error handling
This commit is contained in:
parent
8cbd6e14c8
commit
7a0de134ba
5 changed files with 98 additions and 17 deletions
|
@ -786,6 +786,20 @@ export class Message {
|
|||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward this message to some chat
|
||||
*
|
||||
* @param peer Chat where to forward this message
|
||||
* @param params
|
||||
* @returns Forwarded message
|
||||
*/
|
||||
forwardTo(
|
||||
peer: InputPeerLike,
|
||||
params?: Parameters<TelegramClient['forwardMessages']>[3]
|
||||
): Promise<Message> {
|
||||
return this.client.forwardMessages(peer, this.chat.inputPeer, this.id, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* Send this message as a copy (i.e. send the same message,
|
||||
* but do not forward it).
|
||||
|
|
|
@ -31,6 +31,7 @@ import {
|
|||
PollVoteHandler,
|
||||
UserStatusUpdateHandler,
|
||||
UserTypingHandler,
|
||||
UpdateInfoForError,
|
||||
} from './handler'
|
||||
// end-codegen-imports
|
||||
import { filters, UpdateFilter } from './filters'
|
||||
|
@ -169,6 +170,14 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
|
||||
private _handlersCount: Record<string, number> = {}
|
||||
|
||||
private _errorHandler?: <
|
||||
T extends Exclude<UpdateHandler, RawUpdateHandler>
|
||||
>(
|
||||
err: Error,
|
||||
update: UpdateInfoForError<T>,
|
||||
state?: UpdateState<State, SceneName>
|
||||
) => MaybeAsync<void>
|
||||
|
||||
/**
|
||||
* Create a new dispatcher, that will be used as a child,
|
||||
* optionally providing a custom key delegate
|
||||
|
@ -400,22 +409,37 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
RawUpdateHandler
|
||||
>[]
|
||||
|
||||
for (const h of handlers) {
|
||||
let result: void | PropagationSymbol
|
||||
try {
|
||||
for (const h of handlers) {
|
||||
let result: void | PropagationSymbol
|
||||
|
||||
if (
|
||||
!h.check ||
|
||||
(await h.check(parsed, parsedState as never))
|
||||
) {
|
||||
result = await h.callback(parsed, parsedState as never)
|
||||
} else continue
|
||||
if (
|
||||
!h.check ||
|
||||
(await h.check(parsed, parsedState as never))
|
||||
) {
|
||||
result = await h.callback(
|
||||
parsed,
|
||||
parsedState as never
|
||||
)
|
||||
} else continue
|
||||
|
||||
if (result === ContinuePropagation) continue
|
||||
if (result === StopPropagation) break outer
|
||||
if (result === StopChildrenPropagation) return
|
||||
if (result === ContinuePropagation) continue
|
||||
if (result === StopPropagation) break outer
|
||||
if (result === StopChildrenPropagation) return
|
||||
|
||||
tryRaw = false
|
||||
break
|
||||
tryRaw = false
|
||||
break
|
||||
}
|
||||
} catch (e) {
|
||||
if (this._errorHandler) {
|
||||
await this._errorHandler(
|
||||
e,
|
||||
{ type: parsedType, data: parsed },
|
||||
parsedState as never
|
||||
)
|
||||
} else {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -542,6 +566,35 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an error handler.
|
||||
*
|
||||
* This is used locally within this dispatcher
|
||||
* (does not affect children/parent) whenever
|
||||
* an error is thrown inside an update handler.
|
||||
* Not used for raw update handlers
|
||||
*
|
||||
* When an error is thrown, but there is no error
|
||||
* handler, it is propagated to `TelegramClient`.
|
||||
*
|
||||
* There can be at most one error handler.
|
||||
* Pass `null` to remove it.
|
||||
*
|
||||
* @param handler Error handler
|
||||
*/
|
||||
onError(
|
||||
handler:
|
||||
| ((
|
||||
err: Error,
|
||||
update: UpdateInfoForError<UpdateHandler>,
|
||||
state?: UpdateState<State, SceneName>
|
||||
) => MaybeAsync<void>)
|
||||
| null
|
||||
): void {
|
||||
if (handler) this._errorHandler = handler
|
||||
else this._errorHandler = undefined
|
||||
}
|
||||
|
||||
// children //
|
||||
|
||||
/**
|
||||
|
|
|
@ -30,6 +30,16 @@ type ParsedUpdateHandler<Type, Update, State = never> = BaseUpdateHandler<
|
|||
(update: Update, state: State) => MaybeAsync<boolean>
|
||||
>
|
||||
|
||||
export type UpdateInfoForError<T> = T extends ParsedUpdateHandler<
|
||||
infer K,
|
||||
infer Q
|
||||
>
|
||||
? {
|
||||
type: K
|
||||
data: Q
|
||||
}
|
||||
: never
|
||||
|
||||
export type RawUpdateHandler = BaseUpdateHandler<
|
||||
'raw',
|
||||
(
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { TelegramClient, User } from '@mtcute/client'
|
||||
import { BaseTelegramClient } from '@mtcute/core'
|
||||
import { NodeNativeCryptoProvider } from '@mtcute/crypto-node'
|
||||
import type { NodeNativeCryptoProvider } from '@mtcute/crypto-node'
|
||||
import { HtmlMessageEntityParser } from '@mtcute/html-parser'
|
||||
import { MarkdownMessageEntityParser } from '@mtcute/markdown-parser'
|
||||
import { SqliteStorage } from '@mtcute/sqlite'
|
||||
|
@ -9,6 +9,11 @@ import { createInterface, Interface as RlInterface } from 'readline'
|
|||
export * from '@mtcute/dispatcher'
|
||||
export { SqliteStorage }
|
||||
|
||||
let nativeCrypto: typeof NodeNativeCryptoProvider | null
|
||||
try {
|
||||
nativeCrypto = require('@mtcute/crypto-node').NodeNativeCryptoProvider
|
||||
} catch (e) {}
|
||||
|
||||
export namespace NodeTelegramClient {
|
||||
export interface Options
|
||||
extends Omit<BaseTelegramClient.Options, 'storage'> {
|
||||
|
@ -63,7 +68,7 @@ export const input = (text: string): Promise<string> => {
|
|||
export class NodeTelegramClient extends TelegramClient {
|
||||
constructor(opts: NodeTelegramClient.Options) {
|
||||
super({
|
||||
crypto: () => new NodeNativeCryptoProvider(),
|
||||
crypto: nativeCrypto ? () => new nativeCrypto!() : undefined,
|
||||
...opts,
|
||||
storage:
|
||||
typeof opts.storage === 'string'
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
"@mtcute/sqlite": "^1.0.0",
|
||||
"@mtcute/markdown-parser": "^1.0.0",
|
||||
"@mtcute/html-parser": "^1.0.0",
|
||||
"@mtcute/dispatcher": "^1.0.0",
|
||||
"@mtcute/crypto-node": "^1.0.0"
|
||||
"@mtcute/dispatcher": "^1.0.0"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue