feat(dispatcher): dependency injection
This commit is contained in:
parent
229c49c817
commit
8baacc701c
4 changed files with 71 additions and 4 deletions
|
@ -90,6 +90,10 @@ export interface DispatcherParams {
|
|||
key?: StateKeyDelegate
|
||||
}
|
||||
|
||||
export interface DispatcherDependencies {
|
||||
// intentionally empty, to be extended by consumers
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates dispatcher
|
||||
*/
|
||||
|
@ -112,6 +116,8 @@ export class Dispatcher<State extends object = never> {
|
|||
private _customStateKeyDelegate?: StateKeyDelegate
|
||||
private _customStorage?: StateService
|
||||
|
||||
private _deps: DispatcherDependencies = {}
|
||||
|
||||
private _errorHandler?: <T = {}>(
|
||||
err: Error,
|
||||
update: ParsedUpdate & T,
|
||||
|
@ -193,6 +199,26 @@ export class Dispatcher<State extends object = never> {
|
|||
return this._scene
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject a dependency to be available in this dispatcher and all its children.
|
||||
*
|
||||
* **Note**: This is only available for the root dispatcher.
|
||||
*/
|
||||
inject<Name extends keyof DispatcherDependencies>(name: Name, value: DispatcherDependencies[Name]): void {
|
||||
if (this._parent) {
|
||||
throw new MtArgumentError('Cannot inject dependencies to child dispatchers')
|
||||
}
|
||||
|
||||
this._deps[name] = value
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the dependencies injected into this dispatcher.
|
||||
*/
|
||||
get deps(): DispatcherDependencies {
|
||||
return this._deps
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind the dispatcher to the client.
|
||||
* Called by the constructor automatically if
|
||||
|
@ -678,6 +704,7 @@ export class Dispatcher<State extends object = never> {
|
|||
child._parent = this as any
|
||||
child._client = this._client
|
||||
child._storage = this._storage
|
||||
child._deps = this._deps
|
||||
child._stateKeyDelegate = this._stateKeyDelegate
|
||||
child._customStorage ??= this._customStorage
|
||||
child._customStateKeyDelegate ??= this._customStateKeyDelegate
|
||||
|
@ -773,8 +800,9 @@ export class Dispatcher<State extends object = never> {
|
|||
|
||||
private _unparent(): void {
|
||||
this._parent = this._client = undefined
|
||||
;(this as any)._stateKeyDelegate = undefined
|
||||
;(this as any)._storage = undefined
|
||||
this._deps = {} // to avoid dangling references
|
||||
this._stateKeyDelegate = undefined
|
||||
this._storage = undefined
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -12,6 +12,7 @@ peers.chats.set(1, createStub('channel', { id: 1 }))
|
|||
const createMessageContext = (partial: Partial<tl.RawMessage>) =>
|
||||
new MessageContext(
|
||||
StubTelegramClient.full(), // eslint-disable-line
|
||||
{},
|
||||
new Message(createStub('message', partial), peers, false),
|
||||
)
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import { PeersIndex } from '@mtcute/core'
|
||||
import { Message, PeersIndex } from '@mtcute/core'
|
||||
import { TelegramClient } from '@mtcute/core/client.js'
|
||||
import { StubTelegramClient } from '@mtcute/test'
|
||||
import { createStub, StubTelegramClient } from '@mtcute/test'
|
||||
|
||||
import { Dispatcher, PropagationAction } from '../src/index.js'
|
||||
|
||||
|
@ -237,4 +237,41 @@ describe('Dispatcher', () => {
|
|||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe('Dependency injection', () => {
|
||||
it('should inject dependencies into update contexts', async () => {
|
||||
const dp = Dispatcher.for(client)
|
||||
|
||||
dp.inject('foo' as never, 'foo' as never)
|
||||
|
||||
const log: string[] = []
|
||||
|
||||
dp.onNewMessage(() => {
|
||||
// eslint-disable-next-line
|
||||
log.push(`received ${(dp.deps as any).foo}`)
|
||||
})
|
||||
|
||||
const dp2 = Dispatcher.child()
|
||||
|
||||
dp2.onNewMessage(() => {
|
||||
// eslint-disable-next-line
|
||||
log.push(`received ${(dp.deps as any).foo} (child)`)
|
||||
})
|
||||
|
||||
dp.addChild(dp2)
|
||||
|
||||
await dp.dispatchUpdateNow({
|
||||
name: 'new_message',
|
||||
data: new Message(
|
||||
createStub('message'),
|
||||
emptyPeers,
|
||||
),
|
||||
})
|
||||
|
||||
expect(log).eql([
|
||||
'received foo',
|
||||
'received foo (child)',
|
||||
])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -85,6 +85,7 @@ describe('i18n', () => {
|
|||
it('should parse language from a message', () => {
|
||||
const message = new MessageContext(
|
||||
null as never,
|
||||
{},
|
||||
new Message(
|
||||
{ _: 'message', peerId: { _: 'peerUser', userId: 1 } } as never,
|
||||
PeersIndex.from({
|
||||
|
|
Loading…
Reference in a new issue