diff --git a/__tests__/unit/core-database/database-service.test.ts b/__tests__/unit/core-database/database-service.test.ts index 965310bf00..0466591cc2 100644 --- a/__tests__/unit/core-database/database-service.test.ts +++ b/__tests__/unit/core-database/database-service.test.ts @@ -91,6 +91,11 @@ const triggers = { call: jest.fn(), }; +const events = { + call: jest.fn(), + dispatch: jest.fn(), +}; + const logger = { error: jest.fn(), warning: jest.fn(), @@ -98,11 +103,6 @@ const logger = { debug: jest.fn(), }; -const emitter = { - call: jest.fn(), - dispatch: jest.fn(), -}; - const container = new Container.Container(); container.bind(Container.Identifiers.Application).toConstantValue(app); container.bind(Container.Identifiers.DatabaseConnection).toConstantValue(connection); @@ -118,8 +118,8 @@ container.bind(Container.Identifiers.BlockState).toConstantValue(blockState); container.bind(Container.Identifiers.DposState).toConstantValue(dposState); container.bind(Container.Identifiers.DposPreviousRoundStateProvider).toConstantValue(getDposPreviousRoundState); container.bind(Container.Identifiers.TriggerService).toConstantValue(triggers); +container.bind(Container.Identifiers.EventDispatcherService).toConstantValue(events); container.bind(Container.Identifiers.LogService).toConstantValue(logger); -container.bind(Container.Identifiers.EventDispatcherService).toConstantValue(emitter); beforeEach(() => { app.get.mockReset(); @@ -183,15 +183,15 @@ beforeEach(() => { logger.info.mockReset(); logger.debug.mockReset(); - emitter.call.mockReset(); - emitter.dispatch.mockReset(); + events.call.mockReset(); + events.dispatch.mockReset(); }); describe("DatabaseService.initialize", () => { it("should dispatch starting event", async () => { const databaseService = container.resolve(DatabaseService); await databaseService.initialize(); - expect(emitter.dispatch).toBeCalledWith(Enums.StateEvent.Starting); + expect(events.dispatch).toBeCalledWith(Enums.StateEvent.Starting); }); it("should reset database when CORE_RESET_DATABASE variable is set", async () => { @@ -292,8 +292,8 @@ describe("DatabaseService.disconnect", () => { it("should emit disconnect events", async () => { const databaseService = container.resolve(DatabaseService); await databaseService.disconnect(); - expect(emitter.dispatch).toBeCalledWith("database.preDisconnect"); - expect(emitter.dispatch).toBeCalledWith("database.postDisconnect"); + expect(events.dispatch).toBeCalledWith("database.preDisconnect"); + expect(events.dispatch).toBeCalledWith("database.postDisconnect"); }); }); @@ -325,7 +325,10 @@ describe("DatabaseService.restoreCurrentRound", () => { expect(getDposPreviousRoundState).not.toBeCalled(); // restoring current round should not need previous round state // important: getActiveDelegates should be called with only roundInfo (restoreCurrentRound does *not* provide delegates to it) - expect(triggers.call).toHaveBeenLastCalledWith("getActiveDelegates", { roundInfo: expect.anything(), delegates: undefined }); + expect(triggers.call).toHaveBeenLastCalledWith("getActiveDelegates", { + roundInfo: expect.anything(), + delegates: undefined, + }); expect(databaseService.forgingDelegates).toEqual(forgingDelegates); }); }); @@ -371,9 +374,9 @@ describe("DatabaseService.applyBlock", () => { expect(stateStore.getLastBlock).toBeCalledTimes(1); expect(blockState.applyBlock).toBeCalledWith(block); expect(databaseService.blocksInCurrentRound).toEqual([block]); - expect(emitter.dispatch).toBeCalledWith("forger.missing", { delegate: delegateWallet }); - expect(handler.emitEvents).toBeCalledWith(transaction, emitter); - expect(emitter.dispatch).toBeCalledWith("block.applied", block.data); + expect(events.dispatch).toBeCalledWith("forger.missing", { delegate: delegateWallet }); + expect(handler.emitEvents).toBeCalledWith(transaction, events); + expect(events.dispatch).toBeCalledWith("block.applied", block.data); }); it("should apply block, not apply round, and not detect missed blocks when last block height is 1", async () => { @@ -393,8 +396,8 @@ describe("DatabaseService.applyBlock", () => { await databaseService.applyBlock(block as any); expect(stateStore.getLastBlock).toBeCalledTimes(1); - expect(handler.emitEvents).toBeCalledWith(transaction, emitter); - expect(emitter.dispatch).toBeCalledWith("block.applied", block.data); + expect(handler.emitEvents).toBeCalledWith(transaction, events); + expect(events.dispatch).toBeCalledWith("block.applied", block.data); }); }); @@ -433,7 +436,7 @@ describe("DatabaseService.applyRound", () => { maxDelegates: 51, }); expect(roundRepository.save).toBeCalledWith(dposStateRoundDelegates); - expect(emitter.dispatch).toBeCalledWith("round.applied"); + expect(events.dispatch).toBeCalledWith("round.applied"); }); it("should build delegates, save round, dispatch events when height is 1", async () => { @@ -470,7 +473,7 @@ describe("DatabaseService.applyRound", () => { maxDelegates: 51, }); expect(roundRepository.save).toBeCalledWith(dposStateRoundDelegates); - expect(emitter.dispatch).toBeCalledWith("round.applied"); + expect(events.dispatch).toBeCalledWith("round.applied"); }); it("should build delegates, save round, dispatch events, and skip missing round checks when first round has genesis block only", async () => { @@ -507,7 +510,7 @@ describe("DatabaseService.applyRound", () => { maxDelegates: 51, }); expect(roundRepository.save).toBeCalledWith(dposStateRoundDelegates); - expect(emitter.dispatch).toBeCalledWith("round.applied"); + expect(events.dispatch).toBeCalledWith("round.applied"); }); it("should delete round and rethrow error when error was thrown", async () => { @@ -957,9 +960,9 @@ describe("DatabaseService.revertBlock", () => { await databaseService.revertBlock(block as any); expect(blockState.revertBlock).toBeCalledWith(block); - expect(emitter.dispatch).toBeCalledWith("transaction.reverted", transaction1.data); - expect(emitter.dispatch).toBeCalledWith("transaction.reverted", transaction2.data); - expect(emitter.dispatch).toBeCalledWith("block.reverted", block.data); + expect(events.dispatch).toBeCalledWith("transaction.reverted", transaction1.data); + expect(events.dispatch).toBeCalledWith("transaction.reverted", transaction2.data); + expect(events.dispatch).toBeCalledWith("block.reverted", block.data); }); }); @@ -1022,7 +1025,7 @@ describe("DatabaseService.saveRound", () => { expect(delegate1.getAttribute).toBeCalledWith("delegate.round"); expect(roundRepository.save).toBeCalledWith(activeDelegates); - expect(emitter.dispatch).toBeCalledWith("round.created", activeDelegates); + expect(events.dispatch).toBeCalledWith("round.created", activeDelegates); }); }); diff --git a/__tests__/unit/core-kernel/services/queue/service-provider.test.ts b/__tests__/unit/core-kernel/services/queue/service-provider.test.ts index d78197031f..915acf1df5 100644 --- a/__tests__/unit/core-kernel/services/queue/service-provider.test.ts +++ b/__tests__/unit/core-kernel/services/queue/service-provider.test.ts @@ -2,13 +2,17 @@ import "jest-extended"; import { Application } from "@packages/core-kernel/src/application"; import { Container, Identifiers } from "@packages/core-kernel/src/ioc"; +import { MemoryEventDispatcher } from "@packages/core-kernel/src/services/events/drivers/memory"; import { ServiceProvider } from "@packages/core-kernel/src/services/queue"; import { MemoryQueue } from "@packages/core-kernel/src/services/queue/drivers/memory"; import { QueueFactory } from "@packages/core-kernel/src/types"; let app: Application; -beforeEach(() => (app = new Application(new Container()))); +beforeEach(() => { + app = new Application(new Container()); + app.bind(Identifiers.EventDispatcherService).to(MemoryEventDispatcher); +}); describe("QueueServiceProvider", () => { it("should register the service", async () => { diff --git a/__tests__/unit/core-kernel/services/schedule/schedule.test.ts b/__tests__/unit/core-kernel/services/schedule/schedule.test.ts index 19b1137f7a..3eec4c69b6 100644 --- a/__tests__/unit/core-kernel/services/schedule/schedule.test.ts +++ b/__tests__/unit/core-kernel/services/schedule/schedule.test.ts @@ -16,6 +16,7 @@ beforeEach(() => { container.snapshot(); app = new Application(container); + app.bind(Identifiers.EventDispatcherService).to(MemoryEventDispatcher); scheduleService = app.resolve(Schedule); }); @@ -26,10 +27,6 @@ describe("Schedule", () => { }); it("should return a block job instance", () => { - app.bind(Identifiers.EventDispatcherService).toConstantValue( - app.resolve(MemoryEventDispatcher), - ); - expect(scheduleService.block()).toBeInstanceOf(BlockJob); }); }); diff --git a/__tests__/unit/core-manager/watcher-wallet.test.ts b/__tests__/unit/core-manager/watcher-wallet.test.ts index 29f2937fe0..c9d8ca8b13 100644 --- a/__tests__/unit/core-manager/watcher-wallet.test.ts +++ b/__tests__/unit/core-manager/watcher-wallet.test.ts @@ -1,24 +1,19 @@ import "jest-extended"; -import { Container, Services } from "@arkecosystem/core-kernel"; +import { Services } from "@arkecosystem/core-kernel"; import { WatcherWallet } from "@arkecosystem/core-manager/src/watcher-wallet"; import { Utils } from "@arkecosystem/crypto"; -import { Sandbox } from "@packages/core-test-framework"; import { getWalletAttributeSet } from "@packages/core-test-framework/src/internal/wallet-attributes"; -let sandbox: Sandbox; let wallet: WatcherWallet; const mockEventDispatcher = { dispatchSync: jest.fn(), }; beforeEach(() => { - sandbox = new Sandbox(); - sandbox.app.bind(Container.Identifiers.EventDispatcherService).toConstantValue(mockEventDispatcher); - const attributeMap = new Services.Attributes.AttributeMap(getWalletAttributeSet()); - wallet = new WatcherWallet(sandbox.app, "123", attributeMap); + wallet = new WatcherWallet(mockEventDispatcher as any, "123", attributeMap); }); afterEach(() => { diff --git a/packages/core-blockchain/src/blockchain.ts b/packages/core-blockchain/src/blockchain.ts index 14836c85a5..0597ecce94 100644 --- a/packages/core-blockchain/src/blockchain.ts +++ b/packages/core-blockchain/src/blockchain.ts @@ -28,7 +28,7 @@ export class Blockchain implements Contracts.Blockchain.Blockchain { private readonly stateMachine!: StateMachine; @Container.inject(Container.Identifiers.EventDispatcherService) - private readonly emitter!: Contracts.Kernel.EventDispatcher; + private readonly events!: Contracts.Kernel.EventDispatcher; @Container.inject(Container.Identifiers.LogService) private readonly logger!: Contracts.Kernel.Logger; @@ -115,9 +115,9 @@ export class Blockchain implements Contracts.Blockchain.Blockchain { peerCount: 10, }); - this.emitter.listen(Enums.ForgerEvent.Missing, { handle: this.checkMissingBlocks }); + this.events.listen(Enums.ForgerEvent.Missing, { handle: this.checkMissingBlocks }); - this.emitter.listen(Enums.RoundEvent.Applied, { handle: this.resetMissedBlocks }); + this.events.listen(Enums.RoundEvent.Applied, { handle: this.resetMissedBlocks }); return true; } @@ -202,11 +202,11 @@ export class Blockchain implements Contracts.Blockchain.Blockchain { this.dispatch("NEWBLOCK"); this.enqueueBlocks([block]); - this.app.events.dispatch(Enums.BlockEvent.Received, block); + this.events.dispatch(Enums.BlockEvent.Received, block); } else { this.logger.info(`Block disregarded because blockchain is not ready`); - this.app.events.dispatch(Enums.BlockEvent.Disregarded, block); + this.events.dispatch(Enums.BlockEvent.Disregarded, block); } } diff --git a/packages/core-blockchain/src/state-machine/actions/blockchain-ready.ts b/packages/core-blockchain/src/state-machine/actions/blockchain-ready.ts index ac0ed3f5dd..287f4ce63c 100644 --- a/packages/core-blockchain/src/state-machine/actions/blockchain-ready.ts +++ b/packages/core-blockchain/src/state-machine/actions/blockchain-ready.ts @@ -11,13 +11,13 @@ export class BlockchainReady implements Action { private readonly stateStore!: Contracts.State.StateStore; @Container.inject(Container.Identifiers.EventDispatcherService) - private readonly eventDispatcher!: Contracts.Kernel.EventDispatcher; + private readonly events!: Contracts.Kernel.EventDispatcher; public async handle(): Promise { if (!this.stateStore.started) { this.stateStore.started = true; - this.eventDispatcher.dispatch(Enums.StateEvent.Started, true); + this.events.dispatch(Enums.StateEvent.Started, true); } } } diff --git a/packages/core-database/src/database-service.ts b/packages/core-database/src/database-service.ts index 42ebc93052..d4cf6a8a38 100644 --- a/packages/core-database/src/database-service.ts +++ b/packages/core-database/src/database-service.ts @@ -64,7 +64,7 @@ export class DatabaseService { private readonly logger!: Contracts.Kernel.Logger; @Container.inject(Container.Identifiers.EventDispatcherService) - private readonly emitter!: Contracts.Kernel.EventDispatcher; + private readonly events!: Contracts.Kernel.EventDispatcher; // TODO: make private readonly public blocksInCurrentRound: Interfaces.IBlock[] | undefined = undefined; @@ -75,7 +75,7 @@ export class DatabaseService { public async initialize(): Promise { try { - this.emitter.dispatch(Enums.StateEvent.Starting); + this.events.dispatch(Enums.StateEvent.Starting); const genesisBlockJson = Managers.configManager.get("genesisBlock"); const blockTimeLookup = await AppUtils.forgingInfoCalculator.getBlockTimeLookup( @@ -100,11 +100,11 @@ export class DatabaseService { public async disconnect(): Promise { this.logger.debug("Disconnecting from database"); - this.emitter.dispatch(DatabaseEvent.PRE_DISCONNECT); + this.events.dispatch(DatabaseEvent.PRE_DISCONNECT); await this.connection.close(); - this.emitter.dispatch(DatabaseEvent.POST_DISCONNECT); + this.events.dispatch(DatabaseEvent.POST_DISCONNECT); this.logger.debug("Disconnected from database"); } @@ -134,7 +134,7 @@ export class DatabaseService { await this.emitTransactionEvents(transaction); } - this.emitter.dispatch(Enums.BlockEvent.Applied, block.data); + this.events.dispatch(Enums.BlockEvent.Applied, block.data); } // TODO: move out of core-database to get rid of WalletState dependency @@ -169,7 +169,7 @@ export class DatabaseService { // ! set it to empty array and why it can be undefined at all? this.blocksInCurrentRound!.length = 0; - this.emitter.dispatch(Enums.RoundEvent.Applied); + this.events.dispatch(Enums.RoundEvent.Applied); } catch (error) { // trying to leave database state has it was // ! this.saveRound may not have been called @@ -479,10 +479,10 @@ export class DatabaseService { assert(this.blocksInCurrentRound!.pop()!.data.id === block.data.id); for (let i = block.transactions.length - 1; i >= 0; i--) { - this.emitter.dispatch(Enums.TransactionEvent.Reverted, block.transactions[i].data); + this.events.dispatch(Enums.TransactionEvent.Reverted, block.transactions[i].data); } - this.emitter.dispatch(Enums.BlockEvent.Reverted, block.data); + this.events.dispatch(Enums.BlockEvent.Reverted, block.data); } public async revertRound(height: number): Promise { @@ -510,7 +510,7 @@ export class DatabaseService { await this.roundRepository.save(activeDelegates); - this.emitter.dispatch(Enums.RoundEvent.Created, activeDelegates); + this.events.dispatch(Enums.RoundEvent.Created, activeDelegates); } public async deleteRound(round: number): Promise { @@ -605,7 +605,7 @@ export class DatabaseService { `Delegate ${delegate.getAttribute("delegate.username")} (${delegate.publicKey}) just missed a block.`, ); - this.emitter.dispatch(Enums.ForgerEvent.Missing, { + this.events.dispatch(Enums.ForgerEvent.Missing, { delegate, }); } @@ -732,7 +732,7 @@ export class DatabaseService { `Delegate ${wallet.getAttribute("delegate.username")} (${wallet.publicKey}) just missed a round.`, ); - this.emitter.dispatch(Enums.RoundEvent.Missed, { + this.events.dispatch(Enums.RoundEvent.Missed, { delegate: wallet, }); } @@ -778,9 +778,9 @@ export class DatabaseService { } private async emitTransactionEvents(transaction: Interfaces.ITransaction): Promise { - this.emitter.dispatch(Enums.TransactionEvent.Applied, transaction.data); + this.events.dispatch(Enums.TransactionEvent.Applied, transaction.data); const handler = await this.handlerRegistry.getActivatedHandlerForData(transaction.data); // ! no reason to pass this.emitter - handler.emitEvents(transaction, this.emitter); + handler.emitEvents(transaction, this.events); } } diff --git a/packages/core-kernel/src/application.ts b/packages/core-kernel/src/application.ts index eef1261ca1..519bdf09d1 100644 --- a/packages/core-kernel/src/application.ts +++ b/packages/core-kernel/src/application.ts @@ -295,7 +295,10 @@ export class Application implements Contracts.Kernel.Application { this.get(Identifiers.LogService).notice("Application is now in maintenance mode."); - this.events.dispatch("kernel.maintenance", true); + this.get(Identifiers.EventDispatcherService).dispatch( + "kernel.maintenance", + true, + ); } /** @@ -306,7 +309,10 @@ export class Application implements Contracts.Kernel.Application { this.get(Identifiers.LogService).notice("Application is now live."); - this.events.dispatch("kernel.maintenance", false); + this.get(Identifiers.EventDispatcherService).dispatch( + "kernel.maintenance", + false, + ); } /** @@ -337,17 +343,6 @@ export class Application implements Contracts.Kernel.Application { await this.disposeServiceProviders(); } - /** - * todo: remove after initial migration - ioc/injection should be used to access those - * - * @readonly - * @type {Contracts.Kernel.EventDispatcher} - * @memberof Application - */ - public get events(): Contracts.Kernel.EventDispatcher { - return this.get(Identifiers.EventDispatcherService); - } - /** * @template T * @param {Contracts.Kernel.Container.ServiceIdentifier} serviceIdentifier @@ -441,13 +436,14 @@ export class Application implements Contracts.Kernel.Application { */ private async bootstrapWith(type: string): Promise { const bootstrappers: Array> = Object.values(Bootstrappers[type]); + const events: Contracts.Kernel.EventDispatcher = this.get(Identifiers.EventDispatcherService); for (const bootstrapper of bootstrappers) { - this.events.dispatch(KernelEvent.Bootstrapping, { bootstrapper: bootstrapper.name }); + events.dispatch(KernelEvent.Bootstrapping, { bootstrapper: bootstrapper.name }); await this.resolve(bootstrapper).bootstrap(); - this.events.dispatch(KernelEvent.Bootstrapped, { bootstrapper: bootstrapper.name }); + events.dispatch(KernelEvent.Bootstrapped, { bootstrapper: bootstrapper.name }); } } diff --git a/packages/core-kernel/src/bootstrap/service-providers/boot-service-providers.ts b/packages/core-kernel/src/bootstrap/service-providers/boot-service-providers.ts index 71c9f025fe..e050c61069 100644 --- a/packages/core-kernel/src/bootstrap/service-providers/boot-service-providers.ts +++ b/packages/core-kernel/src/bootstrap/service-providers/boot-service-providers.ts @@ -36,6 +36,14 @@ export class BootServiceProviders implements Bootstrapper { @inject(Identifiers.ServiceProviderRepository) private readonly serviceProviders!: ServiceProviderRepository; + /** + * @private + * @type {Contracts.Kernel.EventDispatcher} + * @memberof BootServiceProviders + */ + @inject(Identifiers.EventDispatcherService) + private readonly events!: Contracts.Kernel.EventDispatcher; + /** * @private * @type {Contracts.Kernel.Logger} @@ -76,10 +84,10 @@ export class BootServiceProviders implements Bootstrapper { .initialize(serviceProviderName, serviceProvider); // Register the "enable/disposeWhen" listeners to be triggered on every block. Use with care! - this.app.events.listen(BlockEvent.Applied, eventListener); + this.events.listen(BlockEvent.Applied, eventListener); // We only want to trigger this if another service provider has been booted to avoid an infinite loop. - this.app.events.listen(KernelEvent.ServiceProviderBooted, eventListener); + this.events.listen(KernelEvent.ServiceProviderBooted, eventListener); } } } diff --git a/packages/core-kernel/src/contracts/kernel/application.ts b/packages/core-kernel/src/contracts/kernel/application.ts index a5ebecf3dd..13e63a5e06 100644 --- a/packages/core-kernel/src/contracts/kernel/application.ts +++ b/packages/core-kernel/src/contracts/kernel/application.ts @@ -1,7 +1,6 @@ import { Exception } from "../../exceptions/base"; import { JsonObject } from "../../types"; import { Container } from "./container"; -import { EventDispatcher } from "./events"; // todo: remove this interface as it serves no purpose. Every package depends on core-kernel so it can import the application directly. export interface Application { @@ -10,11 +9,6 @@ export interface Application { */ readonly container: Container.Container; - /** - * Get an instance of the application event dispatcher. - */ - readonly events: EventDispatcher; - /** * Bootstrap the application with the given configuration. */ diff --git a/packages/core-kernel/src/services/queue/drivers/memory.ts b/packages/core-kernel/src/services/queue/drivers/memory.ts index 59ef92beaf..31c583056c 100644 --- a/packages/core-kernel/src/services/queue/drivers/memory.ts +++ b/packages/core-kernel/src/services/queue/drivers/memory.ts @@ -1,6 +1,6 @@ import { performance } from "perf_hooks"; -import { Application } from "../../../contracts/kernel/application"; +import { EventDispatcher } from "../../../contracts/kernel/events"; import { Queue, QueueJob } from "../../../contracts/kernel/queue"; import { QueueEvent } from "../../../enums"; import { Identifiers, inject, injectable } from "../../../ioc"; @@ -12,8 +12,8 @@ import { Identifiers, inject, injectable } from "../../../ioc"; */ @injectable() export class MemoryQueue implements Queue { - @inject(Identifiers.Application) - protected readonly app!: Application; + @inject(Identifiers.EventDispatcherService) + private readonly events!: EventDispatcher; /** * @private @@ -185,7 +185,7 @@ export class MemoryQueue implements Queue { try { lastResults.push(await this.jobs[from].handle()); - await this.app.events.dispatch(QueueEvent.Finished, { + await this.events.dispatch(QueueEvent.Finished, { driver: "memory", executionTime: performance.now() - start, }); @@ -194,7 +194,7 @@ export class MemoryQueue implements Queue { } catch (error) { this.isRunning = false; - await this.app.events.dispatch(QueueEvent.Failed, { + await this.events.dispatch(QueueEvent.Failed, { driver: "memory", executionTime: performance.now() - start, error: error, diff --git a/packages/core-kernel/src/services/schedule/block-job.ts b/packages/core-kernel/src/services/schedule/block-job.ts index 6e37b4eed9..db52d68a2a 100644 --- a/packages/core-kernel/src/services/schedule/block-job.ts +++ b/packages/core-kernel/src/services/schedule/block-job.ts @@ -1,7 +1,6 @@ import { Managers } from "@arkecosystem/crypto"; import { performance } from "perf_hooks"; -import { Application } from "../../contracts/kernel"; import { EventDispatcher } from "../../contracts/kernel/events"; import { BlockEvent, ScheduleEvent } from "../../enums"; import { Identifiers, inject, injectable } from "../../ioc"; @@ -15,9 +14,6 @@ import { ExecuteCallbackWhenReady } from "./listeners"; */ @injectable() export class BlockJob implements Job { - @inject(Identifiers.Application) - protected readonly app!: Application; - /** * @private * @type {EventDispatcher} @@ -43,7 +39,7 @@ export class BlockJob implements Job { await callback(); - await this.app.events.dispatch(ScheduleEvent.BlockJobFinished, { + await this.events.dispatch(ScheduleEvent.BlockJobFinished, { executionTime: performance.now() - start, blockCount: this.blockCount, }); diff --git a/packages/core-kernel/src/services/schedule/cron-job.ts b/packages/core-kernel/src/services/schedule/cron-job.ts index c7f44d7690..3a656d54b7 100644 --- a/packages/core-kernel/src/services/schedule/cron-job.ts +++ b/packages/core-kernel/src/services/schedule/cron-job.ts @@ -1,7 +1,7 @@ import { CronCommand, CronJob as Cron } from "cron"; import { performance } from "perf_hooks"; -import { Application } from "../../contracts/kernel"; +import { EventDispatcher } from "../../contracts/kernel/events"; import { ScheduleEvent } from "../../enums"; import { Identifiers, inject, injectable } from "../../ioc"; import { Job } from "./interfaces"; @@ -17,8 +17,13 @@ import { Job } from "./interfaces"; */ @injectable() export class CronJob implements Job { - @inject(Identifiers.Application) - protected readonly app!: Application; + /** + * @private + * @type {EventDispatcher} + * @memberof CronJob + */ + @inject(Identifiers.EventDispatcherService) + private readonly events!: EventDispatcher; /** * @private @@ -37,7 +42,7 @@ export class CronJob implements Job { // @ts-ignore callback(); - this.app.events.dispatch(ScheduleEvent.CronJobFinished, { + this.events.dispatch(ScheduleEvent.CronJobFinished, { executionTime: performance.now() - start, expression: this.expression, }); diff --git a/packages/core-manager/src/listener.ts b/packages/core-manager/src/listener.ts index 2adc5e1f88..9822904da4 100644 --- a/packages/core-manager/src/listener.ts +++ b/packages/core-manager/src/listener.ts @@ -8,14 +8,14 @@ export class Listener { @Container.tagged("plugin", "@arkecosystem/core-manager") private readonly configuration!: Providers.PluginConfiguration; - @Container.inject(Container.Identifiers.EventDispatcherService) - private readonly eventDispatcher!: Contracts.Kernel.EventDispatcher; - @Container.inject(Container.Identifiers.WatcherDatabaseService) private readonly databaseService!: DatabaseService; - public boot() { - this.eventDispatcher.listen("*", { + @Container.inject(Container.Identifiers.EventDispatcherService) + private readonly events!: Contracts.Kernel.EventDispatcher; + + public boot(): void { + this.events.listen("*", { handle: (data: any) => { this.handleEvents(data); }, diff --git a/packages/core-manager/src/service-provider.ts b/packages/core-manager/src/service-provider.ts index 718273e330..b96bf3a973 100644 --- a/packages/core-manager/src/service-provider.ts +++ b/packages/core-manager/src/service-provider.ts @@ -43,7 +43,7 @@ export class ServiceProvider extends Providers.ServiceProvider { .bind(Container.Identifiers.WalletFactory) .toFactory((context: Container.interfaces.Context) => (address: string) => new WatcherWallet( - context.container.get(Container.Identifiers.Application), + context.container.get(Container.Identifiers.EventDispatcherService), address, new Services.Attributes.AttributeMap( context.container.get( diff --git a/packages/core-manager/src/watcher-wallet.ts b/packages/core-manager/src/watcher-wallet.ts index 74d9db9b9f..9faec58b21 100644 --- a/packages/core-manager/src/watcher-wallet.ts +++ b/packages/core-manager/src/watcher-wallet.ts @@ -6,15 +6,15 @@ import { WalletEvent } from "./events"; export class WatcherWallet extends Wallets.Wallet { public constructor( - private app: Contracts.Kernel.Application, + private readonly events: Contracts.Kernel.EventDispatcher, address: string, attributes: Services.Attributes.AttributeMap, ) { super(address, attributes); const handler: ProxyHandler = { - set(target, key, value) { - target.app.events.dispatchSync(WalletEvent.PropertySet, { + set: (target, key, value) => { + this.events.dispatchSync(WalletEvent.PropertySet, { publicKey: target.publicKey, key: key, value: value, @@ -33,7 +33,7 @@ export class WatcherWallet extends Wallets.Wallet { public setAttribute(key: string, value: T): boolean { const isSet = super.setAttribute(key, value); - this.app.events.dispatchSync(WalletEvent.AttributeSet, { + this.events.dispatchSync(WalletEvent.AttributeSet, { publicKey: this.publicKey, isSet: isSet, key: key, @@ -48,7 +48,7 @@ export class WatcherWallet extends Wallets.Wallet { const previousValue = super.getAttribute(key); const isForget = super.forgetAttribute(key); - this.app.events.dispatchSync(WalletEvent.AttributeForget, { + this.events.dispatchSync(WalletEvent.AttributeForget, { publicKey: this.publicKey, isForget: isForget, key: key, @@ -60,10 +60,10 @@ export class WatcherWallet extends Wallets.Wallet { } public clone(): WatcherWallet { - const clone = new WatcherWallet(this.app, this.address, cloneDeep(this.attributes)); + const clone = new WatcherWallet(this.events, this.address, cloneDeep(this.attributes)); for (const key of Object.keys(this)) { - if (key === "app") { + if (key === "events") { continue; } diff --git a/packages/core-p2p/src/event-listener.ts b/packages/core-p2p/src/event-listener.ts index 5f1c5acc6f..8b206707fc 100644 --- a/packages/core-p2p/src/event-listener.ts +++ b/packages/core-p2p/src/event-listener.ts @@ -9,9 +9,9 @@ export class EventListener { protected readonly app!: Contracts.Kernel.Application; @Container.inject(Container.Identifiers.EventDispatcherService) - private readonly emitter!: Contracts.Kernel.EventDispatcher; + private readonly events!: Contracts.Kernel.EventDispatcher; - public initialize() { - this.emitter.listen(Enums.PeerEvent.Disconnect, this.app.resolve(DisconnectPeer)); + public initialize(): void { + this.events.listen(Enums.PeerEvent.Disconnect, this.app.resolve(DisconnectPeer)); } } diff --git a/packages/core-p2p/src/listeners.ts b/packages/core-p2p/src/listeners.ts index 1a48b03679..87c9ef3701 100644 --- a/packages/core-p2p/src/listeners.ts +++ b/packages/core-p2p/src/listeners.ts @@ -19,19 +19,19 @@ export class DisconnectInvalidPeers implements Contracts.Kernel.EventListener { /** * @private - * @type {Contracts.Kernel.EventDispatcher} + * @type {Contracts.P2P.PeerStorage} * @memberof DisconnectInvalidPeers */ - @Container.inject(Container.Identifiers.EventDispatcherService) - private readonly emitter!: Contracts.Kernel.EventDispatcher; + @Container.inject(Container.Identifiers.PeerStorage) + private readonly storage!: Contracts.P2P.PeerStorage; /** * @private - * @type {Contracts.P2P.PeerStorage} + * @type {Contracts.Kernel.EventDispatcher} * @memberof DisconnectInvalidPeers */ - @Container.inject(Container.Identifiers.PeerStorage) - private readonly storage!: Contracts.P2P.PeerStorage; + @Container.inject(Container.Identifiers.EventDispatcherService) + private readonly events!: Contracts.Kernel.EventDispatcher; /** * @returns {Promise} @@ -42,7 +42,7 @@ export class DisconnectInvalidPeers implements Contracts.Kernel.EventListener { for (const peer of peers) { if (!isValidVersion(this.app, peer)) { - this.emitter.dispatch("internal.p2p.disconnectPeer", { peer }); + this.events.dispatch("internal.p2p.disconnectPeer", { peer }); } } } diff --git a/packages/core-p2p/src/network-monitor.ts b/packages/core-p2p/src/network-monitor.ts index 6d31de8b6a..e25a6ece1c 100644 --- a/packages/core-p2p/src/network-monitor.ts +++ b/packages/core-p2p/src/network-monitor.ts @@ -17,18 +17,18 @@ export class NetworkMonitor implements Contracts.P2P.NetworkMonitor { @Container.tagged("plugin", "@arkecosystem/core-p2p") private readonly configuration!: Providers.PluginConfiguration; - @Container.inject(Container.Identifiers.LogService) - private readonly logger!: Contracts.Kernel.Logger; - - @Container.inject(Container.Identifiers.EventDispatcherService) - private readonly emitter!: Contracts.Kernel.EventDispatcher; - @Container.inject(Container.Identifiers.PeerCommunicator) private readonly communicator!: PeerCommunicator; @Container.inject(Container.Identifiers.PeerStorage) private readonly storage!: Contracts.P2P.PeerStorage; + @Container.inject(Container.Identifiers.EventDispatcherService) + private readonly events!: Contracts.Kernel.EventDispatcher; + + @Container.inject(Container.Identifiers.LogService) + private readonly logger!: Contracts.Kernel.Logger; + public config: any; public nextUpdateNetworkStatusScheduled: boolean | undefined; private coldStart: boolean = false; @@ -141,8 +141,8 @@ export class NetworkMonitor implements Contracts.P2P.NetworkMonitor { peerErrors[error] = peerErrors[error] || []; peerErrors[error].push(peer); - this.emitter.dispatch("internal.p2p.disconnectPeer", { peer }); - this.emitter.dispatch(Enums.PeerEvent.Removed, peer); + this.events.dispatch("internal.p2p.disconnectPeer", { peer }); + this.events.dispatch(Enums.PeerEvent.Removed, peer); return undefined; } diff --git a/packages/core-p2p/src/peer-communicator.ts b/packages/core-p2p/src/peer-communicator.ts index c6b0afc6c7..46fc145a69 100644 --- a/packages/core-p2p/src/peer-communicator.ts +++ b/packages/core-p2p/src/peer-communicator.ts @@ -21,18 +21,18 @@ export class PeerCommunicator implements Contracts.P2P.PeerCommunicator { @Container.tagged("plugin", "@arkecosystem/core-p2p") private readonly configuration!: Providers.PluginConfiguration; - @Container.inject(Container.Identifiers.LogService) - private readonly logger!: Contracts.Kernel.Logger; + @Container.inject(Container.Identifiers.PeerConnector) + private readonly connector!: Contracts.P2P.PeerConnector; @Container.inject(Container.Identifiers.EventDispatcherService) - private readonly emitter!: Contracts.Kernel.EventDispatcher; + private readonly events!: Contracts.Kernel.EventDispatcher; - @Container.inject(Container.Identifiers.PeerConnector) - private readonly connector!: Contracts.P2P.PeerConnector; + @Container.inject(Container.Identifiers.LogService) + private readonly logger!: Contracts.Kernel.Logger; private outgoingRateLimiter!: RateLimiter; - public initialize() { + public initialize(): void { this.outgoingRateLimiter = buildRateLimiter({ // White listing anybody here means we would not throttle ourselves when sending // them requests, ie we could spam them. @@ -129,7 +129,7 @@ export class PeerCommunicator implements Contracts.P2P.PeerCommunicator { `Disconnecting from ${peerHostPort}: ` + `nethash mismatch: our=${ourNethash}, his=${hisNethash}.`, ); - this.emitter.dispatch("internal.p2p.disconnectPeer", { peer }); + this.events.dispatch("internal.p2p.disconnectPeer", { peer }); } } } else { @@ -311,7 +311,7 @@ export class PeerCommunicator implements Contracts.P2P.PeerCommunicator { if (process.env.CORE_P2P_PEER_VERIFIER_DEBUG_EXTRA) { this.logger.debug(`Socket error (peer ${peer.ip}) : ${error.message}`); } - this.emitter.dispatch(Enums.PeerEvent.Disconnect, { peer }); + this.events.dispatch(Enums.PeerEvent.Disconnect, { peer }); } } } diff --git a/packages/core-p2p/src/peer-processor.ts b/packages/core-p2p/src/peer-processor.ts index 64a59fb0e5..05301de271 100644 --- a/packages/core-p2p/src/peer-processor.ts +++ b/packages/core-p2p/src/peer-processor.ts @@ -14,12 +14,6 @@ export class PeerProcessor implements Contracts.P2P.PeerProcessor { @Container.tagged("plugin", "@arkecosystem/core-p2p") private readonly configuration!: Providers.PluginConfiguration; - @Container.inject(Container.Identifiers.LogService) - private readonly logger!: Contracts.Kernel.Logger; - - @Container.inject(Container.Identifiers.EventDispatcherService) - private readonly emitter!: Contracts.Kernel.EventDispatcher; - @Container.inject(Container.Identifiers.PeerCommunicator) private readonly communicator!: Contracts.P2P.PeerCommunicator; @@ -29,11 +23,17 @@ export class PeerProcessor implements Contracts.P2P.PeerProcessor { @Container.inject(Container.Identifiers.PeerStorage) private readonly storage!: Contracts.P2P.PeerStorage; + @Container.inject(Container.Identifiers.EventDispatcherService) + private readonly events!: Contracts.Kernel.EventDispatcher; + + @Container.inject(Container.Identifiers.LogService) + private readonly logger!: Contracts.Kernel.Logger; + public server: any; public nextUpdateNetworkStatusScheduled: boolean = false; public initialize() { - this.emitter.listen(Enums.CryptoEvent.MilestoneChanged, this.app.resolve(DisconnectInvalidPeers)); + this.events.listen(Enums.CryptoEvent.MilestoneChanged, this.app.resolve(DisconnectInvalidPeers)); } public async validateAndAcceptPeer( @@ -94,7 +94,7 @@ export class PeerProcessor implements Contracts.P2P.PeerProcessor { this.logger.debug(`Accepted new peer ${newPeer.ip}:${newPeer.port} (v${newPeer.version})`); } - this.emitter.dispatch(Enums.PeerEvent.Added, newPeer); + this.events.dispatch(Enums.PeerEvent.Added, newPeer); } catch (error) { this.connector.disconnect(newPeer); } finally { diff --git a/packages/core-p2p/src/socket-server/controllers/internal.ts b/packages/core-p2p/src/socket-server/controllers/internal.ts index eed1628a9a..4aff78dc6a 100644 --- a/packages/core-p2p/src/socket-server/controllers/internal.ts +++ b/packages/core-p2p/src/socket-server/controllers/internal.ts @@ -12,18 +12,18 @@ export class InternalController extends Controller { @Container.inject(Container.Identifiers.PeerNetworkMonitor) private readonly peerNetworkMonitor!: Contracts.P2P.NetworkMonitor; - @Container.inject(Container.Identifiers.EventDispatcherService) - private readonly eventDispatcher!: Contracts.Kernel.EventDispatcher; - @Container.inject(Container.Identifiers.DatabaseService) private readonly database!: DatabaseService; + @Container.inject(Container.Identifiers.EventDispatcherService) + private readonly events!: Contracts.Kernel.EventDispatcher; + public async acceptNewPeer(request: Hapi.Request, h: Hapi.ResponseToolkit): Promise { return this.peerProcessor.validateAndAcceptPeer({ ip: (request.payload as any).ip } as Contracts.P2P.Peer); } public emitEvent(request: Hapi.Request, h: Hapi.ResponseToolkit): boolean { - this.eventDispatcher.dispatch((request.payload as any).event, (request.payload as any).body); + this.events.dispatch((request.payload as any).event, (request.payload as any).body); return true; } diff --git a/packages/core-snapshots/src/progress-dispatcher.ts b/packages/core-snapshots/src/progress-dispatcher.ts index 46adb64c1b..e1d940895c 100644 --- a/packages/core-snapshots/src/progress-dispatcher.ts +++ b/packages/core-snapshots/src/progress-dispatcher.ts @@ -5,7 +5,7 @@ import { SnapshotApplicationEvents } from "./events"; @Container.injectable() export class ProgressDispatcher { @Container.inject(Container.Identifiers.EventDispatcherService) - private readonly emitter!: Contracts.Kernel.EventDispatcher; + private readonly events!: Contracts.Kernel.EventDispatcher; private table: string = ""; private count: number = 0; @@ -14,21 +14,21 @@ export class ProgressDispatcher { this.table = table; this.count = count; - await this.emitter.dispatch(SnapshotApplicationEvents.SnapshotStart, { + await this.events.dispatch(SnapshotApplicationEvents.SnapshotStart, { table: this.table, count: this.count, }); } public async update(count: number): Promise { - await this.emitter.dispatch(SnapshotApplicationEvents.SnapshotProgress, { + await this.events.dispatch(SnapshotApplicationEvents.SnapshotProgress, { table: this.table, value: count, }); } public async end(): Promise { - await this.emitter.dispatch(SnapshotApplicationEvents.SnapshotComplete, { + await this.events.dispatch(SnapshotApplicationEvents.SnapshotComplete, { table: this.table, }); } diff --git a/packages/core-state/src/state-builder.ts b/packages/core-state/src/state-builder.ts index 6fae7a4005..082968f704 100644 --- a/packages/core-state/src/state-builder.ts +++ b/packages/core-state/src/state-builder.ts @@ -23,17 +23,17 @@ export class StateBuilder { @Container.tagged("state", "blockchain") private dposState!: Contracts.State.DposState; + @Container.inject(Container.Identifiers.EventDispatcherService) + private events!: Contracts.Kernel.EventDispatcher; + @Container.inject(Container.Identifiers.LogService) private logger!: Contracts.Kernel.Logger; - @Container.inject(Container.Identifiers.EventDispatcherService) - private emitter!: Contracts.Kernel.EventDispatcher; - @Container.inject(Container.Identifiers.ConfigRepository) private readonly configRepository!: Services.Config.ConfigRepository; public async run(): Promise { - this.emitter = this.app.get(Container.Identifiers.EventDispatcherService); + this.events = this.app.get(Container.Identifiers.EventDispatcherService); const registeredHandlers = this.app .getTagged(Container.Identifiers.TransactionHandlerRegistry, "state", "blockchain") @@ -68,7 +68,7 @@ export class StateBuilder { this.verifyWalletsConsistency(); - this.emitter.dispatch(Enums.StateEvent.BuilderFinished); + this.events.dispatch(Enums.StateEvent.BuilderFinished); } catch (ex) { this.logger.error(ex.stack); } diff --git a/packages/core-transaction-pool/src/sender-state.ts b/packages/core-transaction-pool/src/sender-state.ts index a28ba96f21..49ce07007d 100644 --- a/packages/core-transaction-pool/src/sender-state.ts +++ b/packages/core-transaction-pool/src/sender-state.ts @@ -29,7 +29,7 @@ export class SenderState implements Contracts.TransactionPool.SenderState { private readonly triggers!: Services.Triggers.Triggers; @Container.inject(Container.Identifiers.EventDispatcherService) - private readonly emitter!: Contracts.Kernel.EventDispatcher; + private readonly events!: Contracts.Kernel.EventDispatcher; private corrupt = false; @@ -51,7 +51,7 @@ export class SenderState implements Contracts.TransactionPool.SenderState { } if (await this.expirationService.isExpired(transaction)) { - this.emitter.dispatch(Enums.TransactionEvent.Expired, transaction.data); + this.events.dispatch(Enums.TransactionEvent.Expired, transaction.data); const expirationHeight: number = await this.expirationService.getExpirationHeight(transaction); throw new TransactionHasExpiredError(transaction, expirationHeight); } diff --git a/packages/core-transaction-pool/src/service.ts b/packages/core-transaction-pool/src/service.ts index 61f61a167e..d517160941 100644 --- a/packages/core-transaction-pool/src/service.ts +++ b/packages/core-transaction-pool/src/service.ts @@ -5,12 +5,6 @@ import { TransactionAlreadyInPoolError, TransactionPoolFullError } from "./error @Container.injectable() export class Service implements Contracts.TransactionPool.Service { - @Container.inject(Container.Identifiers.LogService) - private readonly logger!: Contracts.Kernel.Logger; - - @Container.inject(Container.Identifiers.EventDispatcherService) - private readonly emitter!: Contracts.Kernel.EventDispatcher; - @Container.inject(Container.Identifiers.PluginConfiguration) @Container.tagged("plugin", "@arkecosystem/core-transaction-pool") private readonly configuration!: Providers.PluginConfiguration; @@ -27,10 +21,16 @@ export class Service implements Contracts.TransactionPool.Service { @Container.inject(Container.Identifiers.TransactionPoolExpirationService) private readonly expirationService!: Contracts.TransactionPool.ExpirationService; + @Container.inject(Container.Identifiers.EventDispatcherService) + private readonly events!: Contracts.Kernel.EventDispatcher; + + @Container.inject(Container.Identifiers.LogService) + private readonly logger!: Contracts.Kernel.Logger; + private readonly lock: AppUtils.Lock = new AppUtils.Lock(); public async boot(): Promise { - this.emitter.listen(Enums.CryptoEvent.MilestoneChanged, { + this.events.listen(Enums.CryptoEvent.MilestoneChanged, { handle: () => this.readdTransactions(), }); @@ -56,11 +56,11 @@ export class Service implements Contracts.TransactionPool.Service { try { await this.addTransactionToMempool(transaction); this.logger.debug(`${transaction} added to pool`); - this.emitter.dispatch(Enums.TransactionEvent.AddedToPool, transaction.data); + this.events.dispatch(Enums.TransactionEvent.AddedToPool, transaction.data); } catch (error) { this.storage.removeTransaction(transaction.id); this.logger.warning(`${transaction} failed to enter pool: ${error.message}`); - this.emitter.dispatch(Enums.TransactionEvent.RejectedByPool, transaction.data); + this.events.dispatch(Enums.TransactionEvent.RejectedByPool, transaction.data); throw error; } }); @@ -86,7 +86,7 @@ export class Service implements Contracts.TransactionPool.Service { this.logger.error(`${transaction} removed from pool (wasn't in mempool)`); } - this.emitter.dispatch(Enums.TransactionEvent.RemovedFromPool, transaction.data); + this.events.dispatch(Enums.TransactionEvent.RemovedFromPool, transaction.data); }); } @@ -218,7 +218,7 @@ export class Service implements Contracts.TransactionPool.Service { this.logger.warning(`${transaction} expired`); await this.removeTransaction(transaction); - this.emitter.dispatch(Enums.TransactionEvent.Expired, transaction.data); + this.events.dispatch(Enums.TransactionEvent.Expired, transaction.data); } } } diff --git a/packages/core-webhooks/src/listener.ts b/packages/core-webhooks/src/listener.ts index 633114b83a..707b67d9e0 100644 --- a/packages/core-webhooks/src/listener.ts +++ b/packages/core-webhooks/src/listener.ts @@ -16,14 +16,23 @@ export class Listener { /** * @private * @type {Contracts.Kernel.Application} - * @memberof Server + * @memberof Listener */ @Container.inject(Container.Identifiers.Application) private readonly app!: Contracts.Kernel.Application; + + /** + * @private + * @type {Contracts.Kernel.EventDispatcher} + * @memberof Listener + */ + @Container.inject(Container.Identifiers.EventDispatcherService) + private readonly events!: Contracts.Kernel.EventDispatcher; + /** * @private * @type {Contracts.Kernel.Logger} - * @memberof Broadcaster + * @memberof Listener */ @Container.inject(Container.Identifiers.LogService) private readonly logger!: Contracts.Kernel.Logger; @@ -81,14 +90,14 @@ export class Listener { private async dispatchWebhookEvent(start: number, webhook: Webhook, payload: object, err?: Error) { if (err) { - this.app.events.dispatch(WebhookEvent.Failed, { + this.events.dispatch(WebhookEvent.Failed, { executionTime: performance.now() - start, webhook: webhook, payload: payload, error: err, }); } else { - this.app.events.dispatch(WebhookEvent.Broadcasted, { + this.events.dispatch(WebhookEvent.Broadcasted, { executionTime: performance.now() - start, webhook: webhook, payload: payload, diff --git a/packages/core-webhooks/src/service-provider.ts b/packages/core-webhooks/src/service-provider.ts index 450fdff467..002a7b9f2d 100644 --- a/packages/core-webhooks/src/service-provider.ts +++ b/packages/core-webhooks/src/service-provider.ts @@ -1,4 +1,4 @@ -import { Providers, Types } from "@arkecosystem/core-kernel"; +import { Container, Contracts, Providers, Types } from "@arkecosystem/core-kernel"; import { Database } from "./database"; import { Identifiers } from "./identifiers"; @@ -59,6 +59,8 @@ export class ServiceProvider extends Providers.ServiceProvider { * @memberof ServiceProvider */ private startListeners(): void { - this.app.events.listen("*", this.app.resolve(Listener)); + this.app + .get(Container.Identifiers.EventDispatcherService) + .listen("*", this.app.resolve(Listener)); } } diff --git a/packages/core/src/utils/snapshot-progress-renderer.ts b/packages/core/src/utils/snapshot-progress-renderer.ts index 0ef3645ca8..5a0098190b 100644 --- a/packages/core/src/utils/snapshot-progress-renderer.ts +++ b/packages/core/src/utils/snapshot-progress-renderer.ts @@ -22,21 +22,21 @@ export class ProgressRenderer { public constructor(spinner: Ora, app: Contracts.Kernel.Application) { this.spinner = spinner; - const emitter = app.get(Container.Identifiers.EventDispatcherService); + const events = app.get(Container.Identifiers.EventDispatcherService); - emitter.listen(SnapshotApplicationEvents.SnapshotStart, { + events.listen(SnapshotApplicationEvents.SnapshotStart, { handle: (data) => { this.handleStart(data.data); }, }); - emitter.listen(SnapshotApplicationEvents.SnapshotProgress, { + events.listen(SnapshotApplicationEvents.SnapshotProgress, { handle: (data) => { this.handleUpdate(data.data); }, }); - emitter.listen(SnapshotApplicationEvents.SnapshotComplete, { + events.listen(SnapshotApplicationEvents.SnapshotComplete, { handle: (data) => { this.handleComplete(data.data); },