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,
|
* Send this message as a copy (i.e. send the same message,
|
||||||
* but do not forward it).
|
* but do not forward it).
|
||||||
|
|
|
@ -31,6 +31,7 @@ import {
|
||||||
PollVoteHandler,
|
PollVoteHandler,
|
||||||
UserStatusUpdateHandler,
|
UserStatusUpdateHandler,
|
||||||
UserTypingHandler,
|
UserTypingHandler,
|
||||||
|
UpdateInfoForError,
|
||||||
} from './handler'
|
} from './handler'
|
||||||
// end-codegen-imports
|
// end-codegen-imports
|
||||||
import { filters, UpdateFilter } from './filters'
|
import { filters, UpdateFilter } from './filters'
|
||||||
|
@ -169,6 +170,14 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
||||||
|
|
||||||
private _handlersCount: Record<string, number> = {}
|
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,
|
* Create a new dispatcher, that will be used as a child,
|
||||||
* optionally providing a custom key delegate
|
* optionally providing a custom key delegate
|
||||||
|
@ -400,6 +409,7 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
||||||
RawUpdateHandler
|
RawUpdateHandler
|
||||||
>[]
|
>[]
|
||||||
|
|
||||||
|
try {
|
||||||
for (const h of handlers) {
|
for (const h of handlers) {
|
||||||
let result: void | PropagationSymbol
|
let result: void | PropagationSymbol
|
||||||
|
|
||||||
|
@ -407,7 +417,10 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
||||||
!h.check ||
|
!h.check ||
|
||||||
(await h.check(parsed, parsedState as never))
|
(await h.check(parsed, parsedState as never))
|
||||||
) {
|
) {
|
||||||
result = await h.callback(parsed, parsedState as never)
|
result = await h.callback(
|
||||||
|
parsed,
|
||||||
|
parsedState as never
|
||||||
|
)
|
||||||
} else continue
|
} else continue
|
||||||
|
|
||||||
if (result === ContinuePropagation) continue
|
if (result === ContinuePropagation) continue
|
||||||
|
@ -417,6 +430,17 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
||||||
tryRaw = false
|
tryRaw = false
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (this._errorHandler) {
|
||||||
|
await this._errorHandler(
|
||||||
|
e,
|
||||||
|
{ type: parsedType, data: parsed },
|
||||||
|
parsedState as never
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tryRaw && 'raw' in group) {
|
if (tryRaw && 'raw' in group) {
|
||||||
|
@ -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 //
|
// children //
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -30,6 +30,16 @@ type ParsedUpdateHandler<Type, Update, State = never> = BaseUpdateHandler<
|
||||||
(update: Update, state: State) => MaybeAsync<boolean>
|
(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<
|
export type RawUpdateHandler = BaseUpdateHandler<
|
||||||
'raw',
|
'raw',
|
||||||
(
|
(
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { TelegramClient, User } from '@mtcute/client'
|
import { TelegramClient, User } from '@mtcute/client'
|
||||||
import { BaseTelegramClient } from '@mtcute/core'
|
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 { HtmlMessageEntityParser } from '@mtcute/html-parser'
|
||||||
import { MarkdownMessageEntityParser } from '@mtcute/markdown-parser'
|
import { MarkdownMessageEntityParser } from '@mtcute/markdown-parser'
|
||||||
import { SqliteStorage } from '@mtcute/sqlite'
|
import { SqliteStorage } from '@mtcute/sqlite'
|
||||||
|
@ -9,6 +9,11 @@ import { createInterface, Interface as RlInterface } from 'readline'
|
||||||
export * from '@mtcute/dispatcher'
|
export * from '@mtcute/dispatcher'
|
||||||
export { SqliteStorage }
|
export { SqliteStorage }
|
||||||
|
|
||||||
|
let nativeCrypto: typeof NodeNativeCryptoProvider | null
|
||||||
|
try {
|
||||||
|
nativeCrypto = require('@mtcute/crypto-node').NodeNativeCryptoProvider
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
export namespace NodeTelegramClient {
|
export namespace NodeTelegramClient {
|
||||||
export interface Options
|
export interface Options
|
||||||
extends Omit<BaseTelegramClient.Options, 'storage'> {
|
extends Omit<BaseTelegramClient.Options, 'storage'> {
|
||||||
|
@ -63,7 +68,7 @@ export const input = (text: string): Promise<string> => {
|
||||||
export class NodeTelegramClient extends TelegramClient {
|
export class NodeTelegramClient extends TelegramClient {
|
||||||
constructor(opts: NodeTelegramClient.Options) {
|
constructor(opts: NodeTelegramClient.Options) {
|
||||||
super({
|
super({
|
||||||
crypto: () => new NodeNativeCryptoProvider(),
|
crypto: nativeCrypto ? () => new nativeCrypto!() : undefined,
|
||||||
...opts,
|
...opts,
|
||||||
storage:
|
storage:
|
||||||
typeof opts.storage === 'string'
|
typeof opts.storage === 'string'
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
"@mtcute/sqlite": "^1.0.0",
|
"@mtcute/sqlite": "^1.0.0",
|
||||||
"@mtcute/markdown-parser": "^1.0.0",
|
"@mtcute/markdown-parser": "^1.0.0",
|
||||||
"@mtcute/html-parser": "^1.0.0",
|
"@mtcute/html-parser": "^1.0.0",
|
||||||
"@mtcute/dispatcher": "^1.0.0",
|
"@mtcute/dispatcher": "^1.0.0"
|
||||||
"@mtcute/crypto-node": "^1.0.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue