From a307ed1fb5ccb0358060dedf6bdee47e3cb90d38 Mon Sep 17 00:00:00 2001 From: Dmitry Ostrikov Date: Tue, 18 Jun 2024 20:52:02 +0700 Subject: [PATCH] feat(bus): get rid of amqp event bus BREAKING CHANGE: The `sectester/bus` package, which was intended to provide support of communication via the AMQP transport is removed. This change simplifies the codebase by removing deprecated options and encourages the use of more modern and supported transport methods. closes #196 --- package-lock.json | 215 +---- package.json | 3 - packages/bus/.babelrc | 3 - packages/bus/.eslintrc.js | 45 -- packages/bus/README.md | 293 ------- packages/bus/jest.config.ts | 16 - packages/bus/package.json | 41 - packages/bus/project.json | 48 -- packages/bus/src/commands/index.ts | 1 - .../DefaultRMQConnectionManager.spec.ts | 175 ---- .../DefaultRMQConnectionManager.ts | 122 --- .../src/dispatchers/RMQConnectionConfig.ts | 13 - .../src/dispatchers/RMQConnectionManager.ts | 15 - .../bus/src/dispatchers/RMQEventBus.spec.ts | 754 ------------------ packages/bus/src/dispatchers/RMQEventBus.ts | 442 ---------- .../bus/src/dispatchers/RMQEventBusConfig.ts | 8 - packages/bus/src/dispatchers/index.ts | 7 - packages/bus/src/exceptions/index.ts | 1 - packages/bus/src/index.ts | 5 - packages/bus/src/register.ts | 53 -- packages/bus/src/retry-strategies/index.ts | 11 - packages/bus/tsconfig.json | 13 - packages/bus/tsconfig.lib.json | 10 - packages/bus/tsconfig.spec.json | 20 - packages/core/README.md | 75 +- packages/core/src/bus/Event.spec.ts | 35 - packages/core/src/bus/Event.ts | 21 - packages/core/src/bus/EventBus.ts | 15 - packages/core/src/bus/EventDispatcher.ts | 8 - packages/core/src/bus/EventHandler.ts | 7 - packages/core/src/bus/decorators/bind.spec.ts | 55 -- packages/core/src/bus/decorators/bind.ts | 23 - packages/core/src/bus/decorators/index.ts | 1 - .../bus/exceptions/EventHandlerNotFound.ts | 11 - .../src/bus/exceptions/IllegalOperation.ts | 14 - .../core/src/bus/exceptions/NoResponse.ts | 7 - .../bus/exceptions/NoSubscriptionsFound.ts | 13 - .../bus/exceptions/UnsupportedEventType.ts | 8 - packages/core/src/bus/exceptions/index.ts | 5 - packages/core/src/bus/index.ts | 10 - .../src/{bus => commands}/Command.spec.ts | 0 .../core/src/{bus => commands}/Command.ts | 0 .../{bus => commands}/CommandDispatcher.ts | 0 .../src/commands/HttpRequest.spec.ts | 0 .../{bus => core}/src/commands/HttpRequest.ts | 2 +- .../src/{bus => commands}/Message.spec.ts | 0 .../core/src/{bus => commands}/Message.ts | 0 .../src/{bus => commands}/RetryStartegy.ts | 0 packages/core/src/commands/index.ts | 5 + .../src/configuration/Configuration.spec.ts | 20 +- .../core/src/configuration/Configuration.ts | 8 - .../ExponentialBackoffRetryStrategy.spec.ts | 1 + .../ExponentialBackoffRetryStrategy.ts | 3 +- .../dispatchers/HttpCommandDispatcher.spec.ts | 5 +- .../src/dispatchers/HttpCommandDispatcher.ts | 4 +- .../HttpCommandDispatcherConfig.ts | 0 packages/core/src/dispatchers/index.ts | 3 + .../src/exceptions/HttpCommandError.spec.ts | 0 .../src/exceptions/HttpCommandError.ts | 3 +- packages/core/src/exceptions/index.ts | 1 + packages/core/src/index.ts | 3 +- packages/core/src/register.ts | 32 + packages/repeater/package.json | 1 - .../src/api/DefaultRepeatersManager.ts | 2 +- .../api/ExecuteRequestEventHandler.spec.ts | 69 -- .../src/api/ExecuteRequestEventHandler.ts | 58 -- .../src/api/commands/CreateRepeaterRequest.ts | 2 +- .../src/api/commands/DeleteRepeaterRequest.ts | 2 +- .../src/api/commands/GetRepeaterRequest.ts | 2 +- packages/repeater/src/register.ts | 48 +- packages/runner/package.json | 1 - packages/scan/package.json | 1 - packages/scan/src/commands/CreateScan.ts | 2 +- packages/scan/src/commands/DeleteScan.ts | 2 +- packages/scan/src/commands/GetScan.ts | 2 +- packages/scan/src/commands/ListIssues.ts | 2 +- packages/scan/src/commands/StopScan.ts | 2 +- packages/scan/src/commands/UploadHar.ts | 2 +- workspace.json | 1 - 79 files changed, 93 insertions(+), 2818 deletions(-) delete mode 100644 packages/bus/.babelrc delete mode 100644 packages/bus/.eslintrc.js delete mode 100644 packages/bus/README.md delete mode 100644 packages/bus/jest.config.ts delete mode 100644 packages/bus/package.json delete mode 100644 packages/bus/project.json delete mode 100644 packages/bus/src/commands/index.ts delete mode 100644 packages/bus/src/dispatchers/DefaultRMQConnectionManager.spec.ts delete mode 100644 packages/bus/src/dispatchers/DefaultRMQConnectionManager.ts delete mode 100644 packages/bus/src/dispatchers/RMQConnectionConfig.ts delete mode 100644 packages/bus/src/dispatchers/RMQConnectionManager.ts delete mode 100644 packages/bus/src/dispatchers/RMQEventBus.spec.ts delete mode 100644 packages/bus/src/dispatchers/RMQEventBus.ts delete mode 100644 packages/bus/src/dispatchers/RMQEventBusConfig.ts delete mode 100644 packages/bus/src/dispatchers/index.ts delete mode 100644 packages/bus/src/exceptions/index.ts delete mode 100644 packages/bus/src/index.ts delete mode 100644 packages/bus/src/register.ts delete mode 100644 packages/bus/src/retry-strategies/index.ts delete mode 100644 packages/bus/tsconfig.json delete mode 100644 packages/bus/tsconfig.lib.json delete mode 100644 packages/bus/tsconfig.spec.json delete mode 100644 packages/core/src/bus/Event.spec.ts delete mode 100644 packages/core/src/bus/Event.ts delete mode 100644 packages/core/src/bus/EventBus.ts delete mode 100644 packages/core/src/bus/EventDispatcher.ts delete mode 100644 packages/core/src/bus/EventHandler.ts delete mode 100644 packages/core/src/bus/decorators/bind.spec.ts delete mode 100644 packages/core/src/bus/decorators/bind.ts delete mode 100644 packages/core/src/bus/decorators/index.ts delete mode 100644 packages/core/src/bus/exceptions/EventHandlerNotFound.ts delete mode 100644 packages/core/src/bus/exceptions/IllegalOperation.ts delete mode 100644 packages/core/src/bus/exceptions/NoResponse.ts delete mode 100644 packages/core/src/bus/exceptions/NoSubscriptionsFound.ts delete mode 100644 packages/core/src/bus/exceptions/UnsupportedEventType.ts delete mode 100644 packages/core/src/bus/exceptions/index.ts delete mode 100644 packages/core/src/bus/index.ts rename packages/core/src/{bus => commands}/Command.spec.ts (100%) rename packages/core/src/{bus => commands}/Command.ts (100%) rename packages/core/src/{bus => commands}/CommandDispatcher.ts (100%) rename packages/{bus => core}/src/commands/HttpRequest.spec.ts (100%) rename packages/{bus => core}/src/commands/HttpRequest.ts (96%) rename packages/core/src/{bus => commands}/Message.spec.ts (100%) rename packages/core/src/{bus => commands}/Message.ts (100%) rename packages/core/src/{bus => commands}/RetryStartegy.ts (100%) create mode 100644 packages/core/src/commands/index.ts rename packages/{bus/src/retry-strategies => core/src/dispatchers}/ExponentialBackoffRetryStrategy.spec.ts (99%) rename packages/{bus/src/retry-strategies => core/src/dispatchers}/ExponentialBackoffRetryStrategy.ts (95%) rename packages/{bus => core}/src/dispatchers/HttpCommandDispatcher.spec.ts (98%) rename packages/{bus => core}/src/dispatchers/HttpCommandDispatcher.ts (96%) rename packages/{bus => core}/src/dispatchers/HttpCommandDispatcherConfig.ts (100%) create mode 100644 packages/core/src/dispatchers/index.ts rename packages/{bus => core}/src/exceptions/HttpCommandError.spec.ts (100%) rename packages/{bus => core}/src/exceptions/HttpCommandError.ts (85%) delete mode 100644 packages/repeater/src/api/ExecuteRequestEventHandler.spec.ts delete mode 100644 packages/repeater/src/api/ExecuteRequestEventHandler.ts diff --git a/package-lock.json b/package-lock.json index 61705998..c1a3fda7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,8 +13,6 @@ ], "dependencies": { "@har-sdk/core": "^1.4.3", - "amqp-connection-manager": "^4.1.13", - "amqplib": "^0.10.3", "axios": "^0.26.1", "axios-rate-limit": "^1.3.0", "chalk": "^4.1.2", @@ -48,7 +46,6 @@ "@nrwl/workspace": "14.5.6", "@semantic-release/exec": "^6.0.3", "@semantic-release/git": "^10.0.1", - "@types/amqplib": "^0.10.1", "@types/content-type": "^1.1.5", "@types/jest": "27.4.1", "@types/node": "18.7.1", @@ -80,24 +77,6 @@ "npm": ">=8" } }, - "node_modules/@acuminous/bitsyntax": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@acuminous/bitsyntax/-/bitsyntax-0.1.2.tgz", - "integrity": "sha512-29lUK80d1muEQqiUsSo+3A0yP6CdspgC95EnKBMi22Xlwt79i/En4Vr67+cXhU+cZjbti3TgGGC5wy1stIywVQ==", - "dependencies": { - "buffer-more-ints": "~1.0.0", - "debug": "^4.3.4", - "safe-buffer": "~5.1.2" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/@acuminous/bitsyntax/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, "node_modules/@ampproject/remapping": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", @@ -2137,10 +2116,6 @@ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", "dev": true }, - "node_modules/@sectester/bus": { - "resolved": "packages/bus", - "link": true - }, "node_modules/@sectester/core": { "resolved": "packages/core", "link": true @@ -2412,15 +2387,6 @@ "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", "dev": true }, - "node_modules/@types/amqplib": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@types/amqplib/-/amqplib-0.10.1.tgz", - "integrity": "sha512-j6ANKT79ncUDnAs/+9r9eDujxbeJoTjoVu33gHHcaPfmLQaMhvfbH2GqSe8KUM444epAp1Vl3peVOQfZk3UIqA==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/babel__core": { "version": "7.1.19", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", @@ -3197,35 +3163,6 @@ "ajv": "^6.9.1" } }, - "node_modules/amqp-connection-manager": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/amqp-connection-manager/-/amqp-connection-manager-4.1.13.tgz", - "integrity": "sha512-riL5EOlXDlBY4VTTfi6lgy4lwrDbtncQQ9C4SdgxGV6PZ8vgBsNmiKnkxGLvbppDRZ70522glxIc1ep+9Xd/Xw==", - "dependencies": { - "promise-breaker": "^6.0.0" - }, - "engines": { - "node": ">=10.0.0", - "npm": ">5.0.0" - }, - "peerDependencies": { - "amqplib": "*" - } - }, - "node_modules/amqplib": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.10.3.tgz", - "integrity": "sha512-UHmuSa7n8vVW/a5HGh2nFPqAEr8+cD4dEZ6u9GjP91nHfr1a54RyAKyra7Sb5NH7NBKOUlyQSMXIp0qAixKexw==", - "dependencies": { - "@acuminous/bitsyntax": "^0.1.2", - "buffer-more-ints": "~1.0.0", - "readable-stream": "1.x >=1.1.9", - "url-parse": "~1.5.10" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/ansi-colors": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", @@ -3706,11 +3643,6 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, - "node_modules/buffer-more-ints": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-1.0.0.tgz", - "integrity": "sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg==" - }, "node_modules/cacheable-lookup": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-6.0.4.tgz", @@ -4333,7 +4265,8 @@ "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true }, "node_modules/cors": { "version": "2.8.5", @@ -6736,7 +6669,8 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true }, "node_modules/ini": { "version": "1.3.8", @@ -7120,11 +7054,6 @@ "node": ">=8" } }, - "node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -12343,11 +12272,6 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, - "node_modules/promise-breaker": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/promise-breaker/-/promise-breaker-6.0.0.tgz", - "integrity": "sha512-BthzO9yTPswGf7etOBiHCVuugs2N01/Q/94dIPls48z2zCmrnDptUUZzfIb+41xq0MnYZ/BzmOd6ikDR4ibNZA==" - }, "node_modules/prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -12398,7 +12322,8 @@ "node_modules/querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true }, "node_modules/queue-microtask": { "version": "1.2.3", @@ -12597,17 +12522,6 @@ "node": ">=8" } }, - "node_modules/readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -12696,7 +12610,8 @@ "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true }, "node_modules/resolve": { "version": "1.22.0", @@ -13748,11 +13663,6 @@ "mixme": "^0.5.1" } }, - "node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - }, "node_modules/string-argv": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", @@ -14707,6 +14617,7 @@ "version": "1.5.10", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, "dependencies": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" @@ -15225,18 +15136,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "packages/bus": { - "name": "@sectester/bus", - "version": "0.28.0", - "license": "MIT", - "engines": { - "node": ">=16", - "npm": ">=8" - }, - "peerDependencies": { - "@sectester/core": ">=0.16.0 <1.0.0" - } - }, "packages/core": { "name": "@sectester/core", "version": "0.28.0", @@ -15255,7 +15154,6 @@ "npm": ">=8" }, "peerDependencies": { - "@sectester/bus": ">=0.16.0 <1.0.0", "@sectester/core": ">=0.16.0 <1.0.0" } }, @@ -15280,7 +15178,6 @@ "npm": ">=8" }, "peerDependencies": { - "@sectester/bus": ">=0.16.0 <1.0.0", "@sectester/core": ">=0.16.0 <1.0.0", "@sectester/repeater": ">=0.16.0 <1.0.0", "@sectester/reporter": ">=0.16.0 <1.0.0", @@ -15296,29 +15193,11 @@ "npm": ">=8" }, "peerDependencies": { - "@sectester/bus": ">=0.16.0 <1.0.0", "@sectester/core": ">=0.16.0 <1.0.0" } } }, "dependencies": { - "@acuminous/bitsyntax": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@acuminous/bitsyntax/-/bitsyntax-0.1.2.tgz", - "integrity": "sha512-29lUK80d1muEQqiUsSo+3A0yP6CdspgC95EnKBMi22Xlwt79i/En4Vr67+cXhU+cZjbti3TgGGC5wy1stIywVQ==", - "requires": { - "buffer-more-ints": "~1.0.0", - "debug": "^4.3.4", - "safe-buffer": "~5.1.2" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - } - } - }, "@ampproject/remapping": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", @@ -16934,10 +16813,6 @@ } } }, - "@sectester/bus": { - "version": "file:packages/bus", - "requires": {} - }, "@sectester/core": { "version": "file:packages/core" }, @@ -17159,15 +17034,6 @@ "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", "dev": true }, - "@types/amqplib": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@types/amqplib/-/amqplib-0.10.1.tgz", - "integrity": "sha512-j6ANKT79ncUDnAs/+9r9eDujxbeJoTjoVu33gHHcaPfmLQaMhvfbH2GqSe8KUM444epAp1Vl3peVOQfZk3UIqA==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, "@types/babel__core": { "version": "7.1.19", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", @@ -17812,25 +17678,6 @@ "dev": true, "requires": {} }, - "amqp-connection-manager": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/amqp-connection-manager/-/amqp-connection-manager-4.1.13.tgz", - "integrity": "sha512-riL5EOlXDlBY4VTTfi6lgy4lwrDbtncQQ9C4SdgxGV6PZ8vgBsNmiKnkxGLvbppDRZ70522glxIc1ep+9Xd/Xw==", - "requires": { - "promise-breaker": "^6.0.0" - } - }, - "amqplib": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.10.3.tgz", - "integrity": "sha512-UHmuSa7n8vVW/a5HGh2nFPqAEr8+cD4dEZ6u9GjP91nHfr1a54RyAKyra7Sb5NH7NBKOUlyQSMXIp0qAixKexw==", - "requires": { - "@acuminous/bitsyntax": "^0.1.2", - "buffer-more-ints": "~1.0.0", - "readable-stream": "1.x >=1.1.9", - "url-parse": "~1.5.10" - } - }, "ansi-colors": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", @@ -18189,11 +18036,6 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, - "buffer-more-ints": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-1.0.0.tgz", - "integrity": "sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg==" - }, "cacheable-lookup": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-6.0.4.tgz", @@ -18650,7 +18492,8 @@ "core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true }, "cors": { "version": "2.8.5", @@ -20450,7 +20293,8 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true }, "ini": { "version": "1.3.8", @@ -20705,11 +20549,6 @@ "is-docker": "^2.0.0" } }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -24480,11 +24319,6 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, - "promise-breaker": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/promise-breaker/-/promise-breaker-6.0.0.tgz", - "integrity": "sha512-BthzO9yTPswGf7etOBiHCVuugs2N01/Q/94dIPls48z2zCmrnDptUUZzfIb+41xq0MnYZ/BzmOd6ikDR4ibNZA==" - }, "prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -24522,7 +24356,8 @@ "querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true }, "queue-microtask": { "version": "1.2.3", @@ -24671,17 +24506,6 @@ } } }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, "readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -24749,7 +24573,8 @@ "requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true }, "resolve": { "version": "1.22.0", @@ -25572,11 +25397,6 @@ "mixme": "^0.5.1" } }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - }, "string-argv": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", @@ -26277,6 +26097,7 @@ "version": "1.5.10", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, "requires": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" diff --git a/package.json b/package.json index 3433ee00..019bd158 100644 --- a/package.json +++ b/package.json @@ -76,8 +76,6 @@ "homepage": "https://github.com/NeuraLegion/sectester-js#readme", "dependencies": { "@har-sdk/core": "^1.4.3", - "amqp-connection-manager": "^4.1.13", - "amqplib": "^0.10.3", "axios": "^0.26.1", "axios-rate-limit": "^1.3.0", "chalk": "^4.1.2", @@ -111,7 +109,6 @@ "@nrwl/workspace": "14.5.6", "@semantic-release/exec": "^6.0.3", "@semantic-release/git": "^10.0.1", - "@types/amqplib": "^0.10.1", "@types/content-type": "^1.1.5", "@types/jest": "27.4.1", "@types/node": "18.7.1", diff --git a/packages/bus/.babelrc b/packages/bus/.babelrc deleted file mode 100644 index cf7ddd99..00000000 --- a/packages/bus/.babelrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "presets": [["@nrwl/web/babel", { "useBuiltIns": "usage" }]] -} diff --git a/packages/bus/.eslintrc.js b/packages/bus/.eslintrc.js deleted file mode 100644 index 5ed78223..00000000 --- a/packages/bus/.eslintrc.js +++ /dev/null @@ -1,45 +0,0 @@ -module.exports = { - extends: ['../../.eslintrc.json'], - ignorePatterns: ['!**/*'], - overrides: [ - { - files: ['*.ts', '*.tsx', '*.js', '*.jsx'], - parserOptions: { - project: ['packages/bus/tsconfig.*?.json'] - }, - rules: {} - }, - { - files: ['*.ts', '*.tsx'], - rules: { - 'import/no-extraneous-dependencies': [ - 'error', - { - packageDir: [__dirname, `${__dirname}/../..`], - devDependencies: false, - optionalDependencies: false, - peerDependencies: true - } - ] - } - }, - { - files: ['*.js', '*.jsx'], - rules: {} - }, - { - files: ['*.spec.ts'], - rules: { - 'import/no-extraneous-dependencies': [ - 'error', - { - packageDir: [__dirname, `${__dirname}/../..`], - devDependencies: true, - optionalDependencies: false, - peerDependencies: true - } - ] - } - } - ] -}; diff --git a/packages/bus/README.md b/packages/bus/README.md deleted file mode 100644 index 30214ff9..00000000 --- a/packages/bus/README.md +++ /dev/null @@ -1,293 +0,0 @@ -# @sectester/bus - -[![Maintainability](https://api.codeclimate.com/v1/badges/a5f72ececc9b0f402802/maintainability)](https://codeclimate.com/github/NeuraLegion/sectester-js/maintainability) -[![Test Coverage](https://api.codeclimate.com/v1/badges/a5f72ececc9b0f402802/test_coverage)](https://codeclimate.com/github/NeuraLegion/sectester-js/test_coverage) -![Build Status](https://github.com/NeuraLegion/sectester-js/actions/workflows/coverage.yml/badge.svg?branch=master&event=push) -![NPM Downloads](https://img.shields.io/npm/dw/@sectester/core) - -The package includes a simplified implementation of the `EventBus`, one based on `RabbitMQ`, to establish synchronous and asynchronous communication between services and agents. - -## Setup - -```bash -npm i -s @sectester/bus -``` - -## Usage - -### Overview - -To use the RabbitMQ Event Bus, pass the following options object to the constructor method: - -```ts -import { Configuration } from '@sectester/core'; -import { RMQEventBus, ExponentialBackoffRetryStrategy } from '@sectester/bus'; - -const config = new Configuration({ - hostname: 'app.neuralegion.com' -}); - -const repeaterId = 'your Repeater ID'; - -const bus = new RMQEventBus( - config.container, - new ExponentialBackoffRetryStrategy({ maxDepth: 5 }), - { - url: config.bus, - exchange: 'EventBus', - clientQueue: `agent:${repeaterId}`, - appQueue: 'app', - credentials: { - username: 'bot', - password: config.credentials!.token - } - } -); -``` - -The options are specific to the chosen transporter. The `RabbitMQ` implementation exposes the properties described below: - -| Option | Description | -| :------------------ | ------------------------------------------------------------------------------------ | -| `url` | EventBus address. | -| `exchange` | Exchange name which routes a message to a particular queue. | -| `clientQueue` | Queue name which your bus will listen to. | -| `appQueue` | Queue name which application will listen to. | -| `prefetchCount` | Sets the prefetch count for the channel. By default, `1` | -| `connectTimeout` | Time to wait for initial connect. If not specified, defaults to `heartbeatInterval`. | -| `reconnectTime` | The time to wait before trying to reconnect. By default, `20` seconds. | -| `heartbeatInterval` | The interval, in seconds, to send heartbeats. By default, `30` seconds. | -| `credentials` | The `username` and `password` to perform authentication. | - -Finally, to establish a connection with `RabbitMQ`, you have to the `init()` method. - -```ts -await bus.init(); -``` - -In case of unrecoverable or operational errors, you will get an exception while initial connecting. - -### Subscribing to events - -To subscribe an event handler to the particular event, you should use the `@bind()` decorator as follows: - -```ts -import { bind, Event, EventHandler } from '@sectester/core'; -import { injectable } from 'tsyringe'; - -interface Issue { - name: string; - details: string; - type: string; - cvss?: string; - cwe?: string; -} - -class IssueDetected extends Event { - constructor(payload: Issue) { - super(payload); - } -} - -@bind(IssueDetected) -@injectable() -class IssueDetectedHandler implements EventHandler { - public handle(payload: Issue): Promise { - // implementation - } -} -``` - -> ⚡ Make sure that you use `@injectable()` decorator to register the corresponding provider in the IoC. Otherwise, you get an error while trying to register a handler in the `EventBus`. - -Then you just need to register the handler in the `EventBus`: - -```ts -await bus.register(IssueDetectedHandler); -``` - -Now the `IssueDetectedHandler` event handler listens for the `IssueDetected` event. As soon as the `IssueDetected` event appers, -the `EventBus` will call the `handle()` method with the payload passed from the application. - -To remove subscription, and removes the event handler, you have to call the `unregister()` method: - -```ts -await bus.unregister(IssueDetectedHandler); -``` - -#### Publishing events through the event bus - -The `EventBus` exposes a `publish()` method. This method publishes an event to the message broker. - -```ts -interface Payload { - status: 'connected' | 'disconnected'; -} - -class StatusChanged extends Event { - constructor(payload: Payload) { - super(payload); - } -} - -const event = new StatusChanged({ status: 'connected' }); - -await bus.publish(event); -``` - -The `publish()` method takes just a single argument, an instance of the derived class of the `Event`. - -> ⚡ The class name should match one defined event in the application. Otherwise, you should override it by passing the expected name via the constructor. - -For more information, please see `@sectester/core`. - -#### Executing RPC methods - -The `EventBus` exposes a `execute()` method. This method is intended to perform a command to the application and returns an `Promise` with its response. - -```ts -interface Payload { - version: string; -} - -interface Response { - lastVersion: string; -} - -class CheckVersion extends Command { - constructor(payload: Payload) { - super(payload); - } -} - -const command = new CheckVersion({ version: '0.0.1' }); - -const response = await bus.execute(command); -``` - -This method returns a `Promise` which will eventually be resolved as a response message. - -For instance, if you do not expect any response, you can easily make the `EventBus` resolve a `Promise` immediately to undefined: - -```ts -class Record extends Command { - public readonly expectReply = false; - - constructor(payload: Payload) { - super(payload); - } -} - -const command = new Record({ version: '0.0.1' }); - -await bus.execute(command); -``` - -The `HttpCommandDispatcher` is an alternative way to execute the commands over HTTP. To start, you should create an `HttpCommandDispatcher` instance by passing the following options to the constructor: - -```ts -import { - HttpCommandDispatcher, - HttpCommandDispatcherConfig -} from '@sectester/bus'; -import { container } from 'tsyringe'; - -const options: HttpCommandDispatcherConfig = { - baseUrl: 'https://app.neuralegion.com', - token: 'weobbz5.nexa.vennegtzr2h7urpxgtksetz2kwppdgj0' -}; -const logger = container.resolve(Logger); -const retryStrategy = container.resolve(RetryStrategy); - -const httpDispatcher = new HttpCommandDispatcher( - logger, - retryStrategy, - options -); -``` - -The command dispatcher can be customized using the following options: - -| Option | Description | -| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `baseUrl` | Base URL for your application instance, e.g. `https://app.neuralegion.com` | -| `token` | API key to access the API. Find out how to obtain [personal](https://docs.brightsec.com/docs/manage-your-personal-account#manage-your-personal-api-keys-authentication-tokens) and [organization](https://docs.brightsec.com/docs/manage-your-organization#manage-organization-apicli-authentication-tokens) API keys in the knowledgebase | -| `timeout` | Time to wait for a server to send response headers (and start the response body) before aborting the request. Default 10000 ms | -| `rate` | Set how many requests per interval should perform immediately, others will be delayed automatically. By default, 10 requests per 1 minute | - -Then you have to create an instance of `HttpRequest` instead of a custom command, specifying the `url` and `method` in addition to the `payload` that a command accepts by default: - -```ts -const command = new HttpCommand({ - url: '/api/v1/repeaters', - method: 'POST', - payload: { name: 'test' } -}); -``` - -Once it is done, you can perform a request using `HttpComandDispatcher` as follows: - -```ts -const response: { id: string } = await httpDispatcher.execute(command); -``` - -Below you will find a list of parameters that can be used to configure a command: - -| Option | Description | -| --------------- | ------------------------------------------------------------------------------------------ | -| `url` | Absolute URL or path that will be used for the request. By default, `/` | -| `method` | HTTP method that is going to be used when making the request. By default, `GET` | -| `params` | Use to set query parameters. | -| `payload` | Message that we want to transmit to the remote service. | -| `expectReply` | Indicates whether to wait for a reply. By default true. | -| `ttl` | Period of time that command should be handled before being discarded. By default 10000 ms. | -| `type` | The name of a command. By default, it is the name of specific class. | -| `correlationId` | Used to ensure atomicity while working with EventBus. By default, random UUID. | -| `createdAt` | The exact date and time the command was created. | - -For more information, please see `@sectester/core`. - -#### Retry Strategy - -For some noncritical operations, it is better to fail as soon as possible rather than retry a coupe of times. -For example, it is better to fail right after a smaller number of retries with only a short delay between retry attempts, and display a message to the user. - -By default, you can use the [Exponential backoff](https://en.wikipedia.org/wiki/Exponential_backoff) retry strategy to retry an action when errors like `ETIMEDOUT` appear. - -You can implement your own to match the business requirements and the nature of the failure: - -```ts -export class CustomRetryStrategy implements RetryStrategy { - public async acquire unknown>( - task: T - ): Promise> { - let times = 0; - - for (;;) { - try { - return await task(); - } catch { - times++; - - if (times === 3) { - throw e; - } - } - } - } -} -``` - -Once a retry strategy is implemented, you can use it like that: - -```ts -const retryStrategy = new CustomRetryStrategy(); - -const bus = new RMQEventBus(container, retryStrategy, options); -``` - -## License - -Copyright © 2022 [Bright Security](https://brightsec.com/). - -This project is licensed under the MIT License - see the [LICENSE file](LICENSE) for details. diff --git a/packages/bus/jest.config.ts b/packages/bus/jest.config.ts deleted file mode 100644 index 4f5f18f0..00000000 --- a/packages/bus/jest.config.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* eslint-disable */ -export default { - displayName: 'bus', - preset: '../../jest.preset.js', - globals: { - 'ts-jest': { - tsconfig: '/tsconfig.spec.json' - } - }, - testEnvironment: 'node', - transform: { - '^.+\\.[tj]sx?$': 'ts-jest' - }, - moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], - coverageDirectory: '../../coverage/packages/bus' -}; diff --git a/packages/bus/package.json b/packages/bus/package.json deleted file mode 100644 index 50af550f..00000000 --- a/packages/bus/package.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "name": "@sectester/bus", - "version": "0.28.0", - "description": "The package includes a simplified implementation of the `EventBus`, one based on `RabbitMQ`, to establish synchronous and asynchronous communication between services and agents.", - "repository": { - "type": "git", - "url": "git+https://github.com/NeuraLegion/sectester-js.git" - }, - "engines": { - "node": ">=16", - "npm": ">=8" - }, - "author": { - "name": "Artem Derevnjuk", - "email": "artem.derevnjuk@brightsec.com" - }, - "license": "MIT", - "bugs": { - "url": "https://github.com/NeuraLegion/sectester-js/issues" - }, - "publishConfig": { - "access": "public" - }, - "keywords": [ - "security", - "testing", - "e2e", - "test", - "typescript", - "appsec", - "pentesting", - "qa", - "brightsec", - "rmq", - "rabbitmq", - "bus" - ], - "peerDependencies": { - "@sectester/core": ">=0.16.0 <1.0.0" - } -} diff --git a/packages/bus/project.json b/packages/bus/project.json deleted file mode 100644 index 27390b3b..00000000 --- a/packages/bus/project.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "$schema": "../../node_modules/nx/schemas/project-schema.json", - "sourceRoot": "packages/bus/src", - "projectType": "library", - "targets": { - "build": { - "executor": "@nrwl/js:tsc", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/packages/bus", - "tsConfig": "packages/bus/tsconfig.lib.json", - "packageJson": "packages/bus/package.json", - "main": "packages/bus/src/index.ts", - "assets": [ - "packages/bus/*.md", - { - "glob": "LICENSE", - "input": "", - "output": "" - } - ], - "buildableProjectDepsInPackageJsonType": "dependencies" - } - }, - "lint": { - "executor": "@nrwl/linter:eslint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": ["packages/bus/**/*.ts"] - } - }, - "test": { - "executor": "@nrwl/jest:jest", - "outputs": ["coverage/packages/bus"], - "options": { - "jestConfig": "packages/bus/jest.config.ts", - "passWithNoTests": true - } - }, - "publish": { - "executor": "./tools/executors:publish", - "options": { - "dist": "dist/packages/bus" - } - } - }, - "tags": [] -} diff --git a/packages/bus/src/commands/index.ts b/packages/bus/src/commands/index.ts deleted file mode 100644 index a768a9c1..00000000 --- a/packages/bus/src/commands/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './HttpRequest'; diff --git a/packages/bus/src/dispatchers/DefaultRMQConnectionManager.spec.ts b/packages/bus/src/dispatchers/DefaultRMQConnectionManager.spec.ts deleted file mode 100644 index fbee9572..00000000 --- a/packages/bus/src/dispatchers/DefaultRMQConnectionManager.spec.ts +++ /dev/null @@ -1,175 +0,0 @@ -import 'reflect-metadata'; -import { DefaultRMQConnectionManager } from './DefaultRMQConnectionManager'; -import { RMQConnectionConfig } from './RMQConnectionConfig'; -import { Logger } from '@sectester/core'; -import { - anything, - deepEqual, - instance, - mock, - objectContaining, - reset, - resetCalls, - spy, - verify, - when -} from 'ts-mockito'; -import { AmqpConnectionManager, ChannelWrapper } from 'amqp-connection-manager'; - -describe('DefaultRMQConnectionManager', () => { - const mockedConnectionManagerConstructor = jest.fn(); - const mockedAmqpConnectionManager = mock(); - const mockedChannelWrapper = mock(); - const mockedLogger = mock(); - const options: RMQConnectionConfig = { - url: 'amqp://localhost:5672' - }; - const spiedOptions = spy(options); - - let sut!: DefaultRMQConnectionManager; - - beforeEach(() => { - jest.mock('amqp-connection-manager', () => ({ - // eslint-disable-next-line @typescript-eslint/naming-convention - AmqpConnectionManagerClass: - mockedConnectionManagerConstructor.mockImplementation(() => - instance(mockedAmqpConnectionManager) - ) - })); - when(mockedAmqpConnectionManager.createChannel(anything())).thenReturn( - instance(mockedChannelWrapper) - ); - - sut = new DefaultRMQConnectionManager(instance(mockedLogger), options); - }); - - afterEach(() => { - reset< - ChannelWrapper | AmqpConnectionManager | RMQConnectionConfig | Logger - >( - mockedAmqpConnectionManager, - mockedChannelWrapper, - spiedOptions, - mockedLogger - ); - jest.resetModules(); - jest.resetAllMocks(); - }); - - describe('connect', () => { - afterEach(() => jest.useRealTimers()); - - it('should skip initialization if client is already initialized', async () => { - // arrange - await sut.connect(); - - // act - await sut.connect(); - - // assert - verify(mockedAmqpConnectionManager.connect(anything())).once(); - }); - - it('should set credentials', async () => { - // arrange - when(spiedOptions.credentials).thenReturn({ - username: 'user', - password: 'pa$$word' - }); - - // act - await sut.connect(); - - // assert - expect(mockedConnectionManagerConstructor).toHaveBeenCalledWith( - 'amqp://localhost:5672', - expect.objectContaining({ - connectionOptions: { - credentials: { - mechanism: 'PLAIN', - username: 'user', - password: 'pa$$word', - response: expect.any(Function) - } - } - }) - ); - }); - - it('should set max frame as URL query param', async () => { - // arrange - when(spiedOptions.frameMax).thenReturn(1); - - // act - await sut.connect(); - - // assert - expect(mockedConnectionManagerConstructor).toHaveBeenCalledWith( - 'amqp://localhost:5672?frameMax=1', - expect.anything() - ); - }); - - it('should be disposed if connect timeout is passed', async () => { - // arrange - when(spiedOptions.connectTimeout).thenReturn(10); - - // act - await sut.connect(); - - // assert - verify( - mockedAmqpConnectionManager.connect( - objectContaining({ timeout: 10000 }) - ) - ).once(); - }); - }); - - describe('destroy', () => { - beforeEach(() => sut.connect()); - - afterEach(() => resetCalls(mockedChannelWrapper)); - - it('should remove client', async () => { - // act - await sut.disconnect(); - - // assert - verify(mockedAmqpConnectionManager.close()).once(); - expect(sut).not.toMatchObject({ - channel: expect.anything(), - client: expect.anything() - }); - }); - }); - - describe('createChannel', () => { - it('should create a channel', async () => { - // arrange - await sut.connect(); - when(mockedAmqpConnectionManager.isConnected()).thenReturn(true); - - // act - const result = sut.createChannel(); - - // assert - verify( - mockedAmqpConnectionManager.createChannel(deepEqual({ json: false })) - ).once(); - expect(result).not.toBeNull(); - expect(result).not.toBeUndefined(); - }); - - it('should throw an error when connection is lost', () => { - // act - const act = () => sut.createChannel(); - - // assert - verify( - mockedAmqpConnectionManager.createChannel(deepEqual({ json: true })) - ).never(); - expect(act).toThrow(); - }); - }); -}); diff --git a/packages/bus/src/dispatchers/DefaultRMQConnectionManager.ts b/packages/bus/src/dispatchers/DefaultRMQConnectionManager.ts deleted file mode 100644 index 992f0dd5..00000000 --- a/packages/bus/src/dispatchers/DefaultRMQConnectionManager.ts +++ /dev/null @@ -1,122 +0,0 @@ -import { RMQConnectionManager } from './RMQConnectionManager'; -import { RMQConnectionConfig } from './RMQConnectionConfig'; -import { - type AmqpConnectionManager, - type AmqpConnectionManagerOptions, - type ChannelWrapper -} from 'amqp-connection-manager'; -import { inject, injectable } from 'tsyringe'; -import { Logger } from '@sectester/core'; - -@injectable() -export class DefaultRMQConnectionManager implements RMQConnectionManager { - private readonly DEFAULT_RECONNECT_TIME = 20; - private readonly DEFAULT_HEARTBEAT_INTERVAL = 30; - - private client?: AmqpConnectionManager; - - constructor( - private readonly logger: Logger, - @inject(RMQConnectionConfig) private readonly config: RMQConnectionConfig - ) {} - - get connected(): boolean { - return !!this.client?.isConnected(); - } - - public async connect(): Promise { - if (!this.client) { - const url = this.buildUrl(); - const options = this.buildOptions(); - - this.client = new ( - await import('amqp-connection-manager') - ).AmqpConnectionManagerClass(url, options); - - await this.client.connect({ - timeout: - (this.config.connectTimeout ?? this.DEFAULT_RECONNECT_TIME) * 1000 - }); - - this.logger.debug('Connected to %s', this.config.url); - } - } - - public async disconnect(): Promise { - try { - if (this.client) { - await this.client.close(); - } - - delete this.client; - - this.logger.debug('Disconnected from %s', this.config.url); - } catch (e) { - this.logger.error('Cannot terminate a connection to bus gracefully'); - this.logger.debug('Connection to the event bus terminated'); - this.logger.debug('Error on disconnect: %s', e.message); - } - } - - public createChannel(): ChannelWrapper { - this.throwIfNotConnected(); - - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - return this.client!.createChannel({ - json: false - }); - } - - private throwIfNotConnected(): void { - if (!this.connected) { - throw new Error( - 'Please make sure that client established a connection with host.' - ); - } - } - - private buildUrl(): string { - const url = new URL(this.config.url); - - const { frameMax } = this.config; - - if (frameMax !== null && frameMax !== undefined) { - url.searchParams.append('frameMax', frameMax.toString(10)); - } - - return url.toString(); - } - - private buildOptions(): AmqpConnectionManagerOptions { - const { reconnectTime, heartbeatInterval, credentials } = this.config; - - return { - heartbeatIntervalInSeconds: - heartbeatInterval ?? this.DEFAULT_HEARTBEAT_INTERVAL, - reconnectTimeInSeconds: reconnectTime ?? this.DEFAULT_RECONNECT_TIME, - connectionOptions: { - ...(credentials - ? { credentials: this.createAuthRequest(credentials) } - : {}) - } - }; - } - - private createAuthRequest(plain: { username: string; password: string }): { - password: string; - response(): Buffer; - mechanism: 'PLAIN'; - username: string; - } { - return { - ...plain, - mechanism: 'PLAIN', - /* istanbul ignore next */ - response(): Buffer { - return Buffer.from( - ['', plain.username, plain.password].join(String.fromCharCode(0)) - ); - } - }; - } -} diff --git a/packages/bus/src/dispatchers/RMQConnectionConfig.ts b/packages/bus/src/dispatchers/RMQConnectionConfig.ts deleted file mode 100644 index b50e406f..00000000 --- a/packages/bus/src/dispatchers/RMQConnectionConfig.ts +++ /dev/null @@ -1,13 +0,0 @@ -export interface RMQConnectionConfig { - url: string; - connectTimeout?: number; - heartbeatInterval?: number; - reconnectTime?: number; - frameMax?: number; - credentials?: { - username: string; - password: string; - }; -} - -export const RMQConnectionConfig: unique symbol = Symbol('RMQConnectionConfig'); diff --git a/packages/bus/src/dispatchers/RMQConnectionManager.ts b/packages/bus/src/dispatchers/RMQConnectionManager.ts deleted file mode 100644 index c2e34e86..00000000 --- a/packages/bus/src/dispatchers/RMQConnectionManager.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { ChannelWrapper } from 'amqp-connection-manager'; - -export interface RMQConnectionManager { - connected: boolean; - - connect(): Promise; - - disconnect(): Promise; - - createChannel(): ChannelWrapper; -} - -export const RMQConnectionManager: unique symbol = Symbol( - 'RMQConnectionManager' -); diff --git a/packages/bus/src/dispatchers/RMQEventBus.spec.ts b/packages/bus/src/dispatchers/RMQEventBus.spec.ts deleted file mode 100644 index 8f67d9ae..00000000 --- a/packages/bus/src/dispatchers/RMQEventBus.spec.ts +++ /dev/null @@ -1,754 +0,0 @@ -/* eslint-disable max-classes-per-file */ -import { RMQEventBus } from './RMQEventBus'; -import { RMQEventBusConfig } from './RMQEventBusConfig'; -import { RMQConnectionManager } from './RMQConnectionManager'; -import { - bind, - Command, - Event, - EventHandler, - EventHandlerNotFound, - Logger, - NoResponse, - RetryStrategy -} from '@sectester/core'; -import { - anyFunction, - anyOfClass, - anyString, - anything, - deepEqual, - instance, - mock, - objectContaining, - reset, - resetCalls, - spy, - verify, - when -} from 'ts-mockito'; -import { ChannelWrapper } from 'amqp-connection-manager'; -import { Channel, ConsumeMessage } from 'amqplib'; -import { DependencyContainer } from 'tsyringe'; - -class ConcreteCommand extends Command { - constructor( - payload: string, - expectReply?: boolean, - ttl?: number, - type?: string, - correlationId?: string, - createdAt?: Date - ) { - super(payload, { expectReply, ttl, type, correlationId, createdAt }); - } -} - -class ConcreteEvent extends Event<{ foo: string }> { - constructor( - payload: { foo: string }, - type?: string, - correlationId?: string, - createdAt?: Date - ) { - super(payload, type, correlationId, createdAt); - } -} - -@bind(ConcreteEvent) -class ConcreteFirstHandler - implements EventHandler<{ foo: string }, { bar: string }> -{ - public handle(_: { foo: string }): Promise<{ bar: string } | undefined> { - return Promise.resolve(undefined); - } -} - -@bind(ConcreteEvent) -class ConcreteSecondHandler implements EventHandler<{ foo: string }> { - public async handle(_: { foo: string }): Promise { - // noop - } -} - -class ConcreteThirdHandler implements EventHandler<{ foo: string }> { - public async handle(_: { foo: string }): Promise { - // noop - } -} - -describe('RMQEventBus', () => { - const mockedChannelWrapper = mock(); - const mockedChannel = mock(); - const mockedLogger = mock(); - const mockedConnectionManager = mock(); - const mockedDependencyContainer = mock(); - const mockedRetryStrategy = mock(); - const options: RMQEventBusConfig = { - exchange: 'event-bus', - clientQueue: 'Agent', - appQueue: 'App' - }; - const spiedOptions = spy(options); - - let rmq!: RMQEventBus; - - beforeEach(() => { - when(mockedConnectionManager.createChannel()).thenReturn( - instance(mockedChannelWrapper) - ); - when(mockedChannelWrapper.addSetup(anyFunction())).thenCall( - (callback: (...args: unknown[]) => unknown) => - callback(instance(mockedChannel)) - ); - when( - mockedChannel.consume(anyString(), anyFunction(), anything()) - ).thenResolve({ consumerTag: 'tag' } as any); - when(mockedRetryStrategy.acquire(anyFunction())).thenCall( - (callback: (...args: unknown[]) => unknown) => callback() - ); - when(mockedDependencyContainer.resolve(Logger)).thenReturn( - instance(mockedLogger) - ); - rmq = new RMQEventBus( - instance(mockedDependencyContainer), - instance(mockedLogger), - instance(mockedRetryStrategy), - options, - instance(mockedConnectionManager) - ); - }); - - afterEach(() => { - reset< - | ChannelWrapper - | RMQConnectionManager - | Channel - | RMQEventBusConfig - | Logger - | DependencyContainer - | RetryStrategy - >( - mockedChannelWrapper, - mockedConnectionManager, - mockedChannel, - spiedOptions, - mockedDependencyContainer, - mockedLogger, - mockedRetryStrategy - ); - jest.resetModules(); - jest.resetAllMocks(); - }); - - describe('execute', () => { - it('should throw an error if client is not initialized yet', async () => { - // arrange - const command = new ConcreteCommand('test'); - - // act - const result = rmq.execute(command); - - // assert - await expect(result).rejects.toThrow( - 'established a connection with host' - ); - }); - - it('should send a message to queue', async () => { - // arrange - const command = new ConcreteCommand('test', false); - when( - mockedChannelWrapper.sendToQueue( - anyString(), - anyOfClass(Buffer), - anything() - ) - ).thenResolve(); - - await rmq.init(); - - // act - const result = await rmq.execute(command); - - // assert - expect(result).toBeUndefined(); - verify( - mockedChannelWrapper.publish( - '', - options.appQueue, - anyOfClass(Buffer), - deepEqual({ - type: command.type, - mandatory: true, - persistent: true, - contentType: 'application/json', - timestamp: command.createdAt.getTime(), - correlationId: command.correlationId, - replyTo: 'amq.rabbitmq.reply-to' - }) - ) - ).once(); - }); - - it('should send a message to queue and get a reply', async () => { - // arrange - const command = new ConcreteCommand('test'); - when( - mockedChannelWrapper.sendToQueue( - anyString(), - anyOfClass(Buffer), - anything() - ) - ).thenResolve(); - let processMessage!: (msg: ConsumeMessage | null) => Promise; - when( - mockedChannel.consume( - 'amq.rabbitmq.reply-to', - anyFunction(), - anything() - ) - ).thenCall( - ( - _: string, - callback: (msg: ConsumeMessage | null) => Promise - ) => (processMessage = callback) - ); - - const payload = { foo: 'bar' }; - const message = { - content: Buffer.from(JSON.stringify(payload)), - fields: { - redelivered: false, - routingKey: ConcreteEvent.name - }, - properties: { - type: ConcreteEvent.name, - correlationId: command.correlationId - } - } as ConsumeMessage; - - await rmq.init(); - - process.nextTick(() => processMessage(message)); - - // act - const result = await rmq.execute(command); - - // assert - expect(result).toEqual(payload); - verify( - mockedChannelWrapper.publish( - '', - options.appQueue, - anyOfClass(Buffer), - deepEqual({ - type: command.type, - mandatory: true, - persistent: true, - contentType: 'application/json', - timestamp: command.createdAt.getTime(), - correlationId: command.correlationId, - replyTo: 'amq.rabbitmq.reply-to' - }) - ) - ).once(); - }); - - it('should throw a error if no response', async () => { - // arrange - const command = new ConcreteCommand('test', true, 1); - when( - mockedChannelWrapper.sendToQueue( - anyString(), - anyOfClass(Buffer), - anything() - ) - ).thenResolve(); - - await rmq.init(); - - // act - const result = rmq.execute(command); - - // assert - verify( - mockedChannelWrapper.publish( - '', - options.appQueue, - anyOfClass(Buffer), - deepEqual({ - type: command.type, - mandatory: true, - persistent: true, - contentType: 'application/json', - timestamp: command.createdAt.getTime(), - correlationId: command.correlationId, - replyTo: 'amq.rabbitmq.reply-to' - }) - ) - ).once(); - await expect(result).rejects.toThrow(NoResponse); - }); - }); - - describe('init', () => { - afterEach(() => jest.useRealTimers()); - - it('should skip initialization if channel is already initialized', async () => { - // arrange - await rmq.init(); - - // act - await rmq.init(); - - // assert - verify(mockedConnectionManager.createChannel()).once(); - }); - - it('should create a channel', async () => { - // act - await rmq.init(); - - // assert - verify(mockedConnectionManager.createChannel()).once(); - }); - - it('should consume regular messages', async () => { - // arrange - when( - mockedChannel.consume(anyString(), anyFunction(), anything()) - ).thenResolve({ consumerTag: 'tag' } as any); - - // act - await rmq.init(); - - // assert - verify( - mockedChannel.consume( - options.clientQueue, - anyFunction(), - deepEqual({ - noAck: true - }) - ) - ).once(); - }); - - it('should consume reply messages', async () => { - // arrange - when( - mockedChannel.consume(anyString(), anyFunction(), anything()) - ).thenResolve({ consumerTag: 'tag' } as any); - - // act - await rmq.init(); - - // assert - verify( - mockedChannel.consume( - 'amq.rabbitmq.reply-to', - anyFunction(), - deepEqual({ - noAck: true - }) - ) - ).once(); - }); - - it('should bind exchanges to queue', async () => { - // act - await rmq.init(); - - // assert - verify( - mockedChannel.assertExchange( - options.exchange, - 'direct', - deepEqual({ - durable: true - }) - ) - ).once(); - verify( - mockedChannel.assertQueue( - options.clientQueue, - deepEqual({ - durable: true, - exclusive: false, - autoDelete: true - }) - ) - ).once(); - verify(mockedChannel.prefetch(1)).once(); - }); - }); - - describe('destroy', () => { - beforeEach(() => rmq.init()); - - afterEach(() => resetCalls(mockedChannelWrapper)); - - it('should remove channel', async () => { - // act - await rmq.destroy(); - - // assert - verify(mockedChannelWrapper.close()).once(); - expect(rmq).not.toMatchObject({ - channel: expect.anything() - }); - }); - }); - - describe('publish', () => { - it('should throw an error if client is not initialized yet', async () => { - // arrange - const message = new ConcreteEvent({ foo: 'bar' }); - - // act - const result = rmq.publish(message); - - // assert - await expect(result).rejects.toThrow( - 'established a connection with host' - ); - }); - - it('should publish an message', async () => { - // arrange - const message = new ConcreteEvent({ foo: 'bar' }); - - await rmq.init(); - - // act - await rmq.publish(message); - - // assert - verify( - mockedChannelWrapper.publish( - options.exchange, - message.type, - anyOfClass(Buffer), - objectContaining({ - type: message.type, - mandatory: true, - persistent: true, - contentType: 'application/json', - timestamp: message.createdAt.getTime(), - correlationId: message.correlationId - }) - ) - ).once(); - }); - - it('should apply a retry strategy', async () => { - // arrange - const message = new ConcreteEvent({ foo: 'bar' }); - - await rmq.init(); - - // act - await rmq.publish(message); - - // assert - verify(mockedRetryStrategy.acquire(anyFunction())).once(); - }); - }); - - describe('subscribe', () => { - beforeEach(async () => { - await rmq.init(); - - resetCalls(mockedChannelWrapper); - }); - - it('should throw an error if no such handler', async () => { - // arrange - when(mockedDependencyContainer.isRegistered(anything())).thenReturn( - false - ); - - // act / assert - await expect(rmq.register(ConcreteFirstHandler)).rejects.toThrow( - 'Event handler not found' - ); - verify(mockedChannelWrapper.addSetup(anyFunction())).never(); - }); - - it('should throw an error if no subscriptions', async () => { - // arrange - when(mockedDependencyContainer.isRegistered(anything())).thenReturn(true); - when( - mockedDependencyContainer.resolve(anything()) - ).thenReturn(new ConcreteThirdHandler()); - - // act / assert - await expect(rmq.register(ConcreteThirdHandler)).rejects.toThrow( - 'No subscriptions found' - ); - verify(mockedChannelWrapper.addSetup(anyFunction())).never(); - }); - - it('should add handler for event', async () => { - // arrange - when(mockedDependencyContainer.isRegistered(anything())).thenReturn(true); - when( - mockedDependencyContainer.resolve(anything()) - ).thenReturn(new ConcreteFirstHandler()); - - // act - await rmq.register(ConcreteFirstHandler); - - // assert - verify(mockedChannelWrapper.addSetup(anyFunction())).once(); - verify( - mockedChannel.bindQueue( - options.clientQueue, - options.exchange, - ConcreteEvent.name - ) - ).once(); - }); - - it('should add multiple handlers for the same event', async () => { - // arrange - when(mockedDependencyContainer.isRegistered(anything())).thenReturn(true); - when( - mockedDependencyContainer.resolve(anything()) - ).thenReturn(new ConcreteFirstHandler()); - - // act - await rmq.register(ConcreteFirstHandler); - await rmq.register(ConcreteSecondHandler); - - // assert - verify(mockedChannelWrapper.addSetup(anyFunction())).once(); - verify( - mockedChannel.bindQueue( - options.clientQueue, - options.exchange, - ConcreteEvent.name - ) - ).once(); - }); - }); - - describe('processMessage', () => { - const handler = new ConcreteFirstHandler(); - let spiedHandler!: ConcreteFirstHandler; - let processMessage!: (msg: ConsumeMessage | null) => Promise; - - beforeEach(async () => { - when(mockedDependencyContainer.isRegistered(anything())).thenReturn(true); - when( - mockedDependencyContainer.resolve(anything()) - ).thenReturn(handler); - when( - mockedChannel.consume(options.clientQueue, anyFunction(), anything()) - ).thenCall( - ( - _: string, - callback: (msg: ConsumeMessage | null) => Promise - ) => (processMessage = callback) - ); - spiedHandler = spy(handler); - - await rmq.init(); - await rmq.register(ConcreteFirstHandler); - }); - - afterEach(() => reset(spiedHandler)); - - it('should handle a consumed event', async () => { - // arrange - const payload = { foo: 'bar' }; - const message = { - content: Buffer.from(JSON.stringify(payload)), - fields: { - redelivered: false, - routingKey: ConcreteEvent.name - }, - properties: { - type: ConcreteEvent.name, - correlationId: '1' - } - } as ConsumeMessage; - - // act - await processMessage(message); - - // assert - verify(spiedHandler.handle(deepEqual(payload))).once(); - }); - - it('should send a reply', async () => { - // arrange - const payload = { foo: 'bar' }; - const reply = { bar: 'foo' }; - const replyTo = 'reply-queue'; - const message = { - content: Buffer.from(JSON.stringify(payload)), - fields: { - redelivered: false, - routingKey: ConcreteEvent.name - }, - properties: { - replyTo, - correlationId: '1', - type: ConcreteEvent.name - } - } as ConsumeMessage; - when(spiedHandler.handle(anything())).thenResolve(reply); - - // act - await processMessage(message); - - // assert - verify(spiedHandler.handle(deepEqual(payload))).once(); - verify( - mockedChannelWrapper.publish( - '', - replyTo, - anyOfClass(Buffer), - anything() - ) - ).once(); - }); - - it('should log an error if no active subscriptions', async () => { - // arrange - const payload = { foo: 'bar' }; - const message = { - content: Buffer.from(JSON.stringify(payload)), - fields: { - redelivered: false, - routingKey: 'test' - }, - properties: { - type: 'test', - correlationId: '1' - } - } as ConsumeMessage; - - // act - await processMessage(message); - // assert - verify(spiedHandler.handle(anything())).never(); - verify( - mockedLogger.error(anyString(), anyOfClass(EventHandlerNotFound)) - ).once(); - }); - - it('should skip a redelivered event', async () => { - // arrange - const payload = { foo: 'bar' }; - const message = { - content: Buffer.from(JSON.stringify(payload)), - fields: { - redelivered: true, - routingKey: ConcreteEvent.name - }, - properties: { - type: ConcreteEvent.name, - correlationId: '1' - } - } as ConsumeMessage; - - // act - await processMessage(message); - - // assert - verify(spiedHandler.handle(anything())).never(); - }); - }); - - describe('unsubscribe', () => { - beforeEach(async () => { - await rmq.init(); - - resetCalls(mockedChannelWrapper); - }); - - it('should remove handler for event', async () => { - // arrange - when(mockedChannelWrapper.removeSetup(anyFunction())).thenCall( - (callback: (...args: unknown[]) => unknown) => - callback(instance(mockedChannel)) - ); - when( - mockedChannel.unbindQueue(anyString(), anyString(), anyString()) - ).thenResolve(); - when(mockedDependencyContainer.isRegistered(anything())).thenReturn(true); - when( - mockedDependencyContainer.resolve(anything()) - ).thenReturn(new ConcreteFirstHandler()); - - await rmq.register(ConcreteFirstHandler); - - // act - await rmq.unregister(ConcreteFirstHandler); - - // assert - verify(mockedChannelWrapper.removeSetup(anyFunction())).once(); - verify( - mockedChannel.unbindQueue( - options.clientQueue, - options.exchange, - ConcreteEvent.name - ) - ).once(); - }); - - it('should throw an error if no such handler', async () => { - // arrange - when(mockedDependencyContainer.isRegistered(anything())).thenReturn( - false - ); - - // act / assert - await expect(rmq.unregister(ConcreteFirstHandler)).rejects.toThrow( - 'Event handler not found' - ); - verify(mockedChannelWrapper.removeSetup(anyFunction())).never(); - }); - - it('should throw an error if no subscriptions', async () => { - // arrange - when(mockedDependencyContainer.isRegistered(anything())).thenReturn(true); - when( - mockedDependencyContainer.resolve(anything()) - ).thenReturn(new ConcreteThirdHandler()); - - // act / assert - await expect(rmq.unregister(ConcreteThirdHandler)).rejects.toThrow( - 'No subscriptions found' - ); - verify(mockedChannelWrapper.addSetup(anyFunction())).never(); - }); - - it('should remove multiple handlers for the same event', async () => { - // arrange - when(mockedDependencyContainer.isRegistered(anything())).thenReturn(true); - when( - mockedDependencyContainer.resolve(anything()) - ).thenReturn(new ConcreteFirstHandler()); - - await rmq.register(ConcreteFirstHandler); - await rmq.register(ConcreteSecondHandler); - - // act - await rmq.unregister(ConcreteFirstHandler); - - // assert - verify(mockedChannelWrapper.removeSetup(anyFunction())).never(); - verify( - mockedChannel.unbindQueue( - options.clientQueue, - options.exchange, - ConcreteEvent.name - ) - ).never(); - }); - }); -}); diff --git a/packages/bus/src/dispatchers/RMQEventBus.ts b/packages/bus/src/dispatchers/RMQEventBus.ts deleted file mode 100644 index d258fa8a..00000000 --- a/packages/bus/src/dispatchers/RMQEventBus.ts +++ /dev/null @@ -1,442 +0,0 @@ -import { RMQEventBusConfig } from './RMQEventBusConfig'; -import { RMQConnectionManager } from './RMQConnectionManager'; -import { - Command, - Event, - EventBus, - EventHandler, - EventHandlerConstructor, - EventHandlerNotFound, - IllegalOperation, - Logger, - NoResponse, - NoSubscriptionsFound, - RetryStrategy -} from '@sectester/core'; -import type { Channel, ConsumeMessage } from 'amqplib'; -import { DependencyContainer, inject, injectable } from 'tsyringe'; -import type { ChannelWrapper } from 'amqp-connection-manager'; -import { EventEmitter, once } from 'events'; - -interface ParsedConsumeMessage { - payload: T; - name: string; - replyTo?: string; - correlationId?: string; -} - -interface RawMessage { - payload: T; - routingKey: string; - exchange?: string; - type?: string; - correlationId?: string; - replyTo?: string; - timestamp?: Date; -} - -interface Binding { - handler: EventHandler; - eventNames: string[]; -} - -@injectable() -export class RMQEventBus implements EventBus { - private channel: ChannelWrapper | undefined; - - private readonly subject = new EventEmitter({ captureRejections: true }); - private readonly handlers = new Map< - string, - EventHandler[] - >(); - private readonly REPLY_QUEUE_NAME = 'amq.rabbitmq.reply-to'; - - constructor( - private readonly container: DependencyContainer, - private readonly logger: Logger, - @inject(RetryStrategy) - private readonly retryStrategy: RetryStrategy, - @inject(RMQEventBusConfig) private readonly options: RMQEventBusConfig, - @inject(RMQConnectionManager) - private readonly connectionManager: RMQConnectionManager - ) { - this.subject.setMaxListeners(Infinity); - } - - public async init(): Promise { - await this.connectionManager.connect(); - - if (!this.channel) { - this.channel = this.connectionManager.createChannel(); - - await this.channel.addSetup(async (channel: Channel) => { - await this.bindExchangesToQueue(channel); - await this.startBasicConsume(channel); - await this.startReplyQueueConsume(channel); - }); - } - } - - public async register( - type: EventHandlerConstructor - ): Promise { - const { handler, eventNames } = this.discoverEventBinding(type); - - await Promise.all( - eventNames.map(eventName => this.subscribe(eventName, handler)) - ); - } - - public async unregister( - type: EventHandlerConstructor - ): Promise { - const { handler, eventNames } = this.discoverEventBinding(type); - - await Promise.all( - eventNames.map(eventName => this.unsubscribe(eventName, handler)) - ); - } - - public async publish(event: Event): Promise { - const { type, payload, correlationId, createdAt } = event; - - await this.tryToSendMessage({ - type, - payload, - correlationId, - routingKey: type, - timestamp: createdAt, - exchange: this.options.exchange - }); - } - - public async execute({ - type, - payload, - correlationId, - createdAt, - expectReply, - ttl - }: Command): Promise { - const waiter = expectReply - ? this.expectReply(correlationId, ttl) - : Promise.resolve(undefined); - - try { - await this.tryToSendMessage({ - type, - payload, - correlationId, - timestamp: createdAt, - routingKey: this.options.appQueue, - replyTo: this.REPLY_QUEUE_NAME - }); - - return await waiter; - } finally { - this.subject.removeAllListeners(correlationId); - } - } - - public async destroy(): Promise { - await this.connectionManager.disconnect(); - - try { - if (this.channel) { - await this.channel.cancelAll(); - await this.channel.close(); - } - - delete this.channel; - - this.subject.removeAllListeners(); - } catch (e) { - this.logger.error('Cannot terminate event bus gracefully'); - this.logger.debug('Error on terminating event bus: %s', e.message); - } - } - - private async subscribe( - eventName: string, - handler: EventHandler - ): Promise { - const handlers = this.handlers.get(eventName); - - if (Array.isArray(handlers)) { - handlers.push(handler); - } else { - this.handlers.set(eventName, [handler]); - await this.bindQueue(eventName); - } - } - - private async bindQueue(eventName: string): Promise { - this.logger.debug( - 'Bind the queue (%s) to the exchange (%s) by the routing key (%s).', - this.options.clientQueue, - this.options.exchange, - eventName - ); - await this.getChannel().addSetup((channel: Channel) => - channel.bindQueue( - this.options.clientQueue, - this.options.exchange, - eventName - ) - ); - } - - private async unsubscribe( - eventName: string, - handler: EventHandler - ): Promise { - const handlers = this.handlers.get(eventName); - - if (Array.isArray(handlers)) { - const idx = handlers.indexOf(handler); - - if (idx !== -1) { - handlers.splice(idx, 1); - } - - if (!handlers.length) { - this.handlers.delete(eventName); - await this.unbindQueue(eventName); - } - } - } - - private async unbindQueue(eventName: string) { - this.logger.debug( - 'Unbind the queue (%s) to the exchange (%s) by the routing key (%s).', - this.options.clientQueue, - this.options.exchange, - eventName - ); - await this.getChannel().removeSetup((channel: Channel) => - channel.unbindQueue( - this.options.clientQueue, - this.options.exchange, - eventName - ) - ); - } - - private discoverEventBinding( - type: EventHandlerConstructor - ): Binding { - const handler = this.resolveHandler(type); - const eventNames = this.reflectEventsNames(type); - - if (!eventNames.length) { - throw new NoSubscriptionsFound(handler); - } - - return { handler, eventNames }; - } - - private resolveHandler( - type: EventHandlerConstructor - ): EventHandler { - const eventHandler = this.container.resolve(type); - - if (!eventHandler) { - throw new EventHandlerNotFound(type.name); - } - - return eventHandler; - } - - private async expectReply( - correlationId: string, - ttl: number = 5000 - ): Promise { - const result = await Promise.race([ - once(this.subject, correlationId) as Promise<[R]>, - new Promise((_, reject) => - setTimeout(reject, ttl, new NoResponse(ttl)).unref() - ) - ]); - - const [response]: [R] = result; - - return response; - } - - private reflectEventsNames(handlerType: EventHandlerConstructor): string[] { - return Reflect.getMetadata(Event, handlerType) ?? []; - } - - private async startReplyQueueConsume(channel: Channel): Promise { - await channel.consume( - this.REPLY_QUEUE_NAME, - (msg: ConsumeMessage | null) => (msg ? this.processReply(msg) : void 0), - { - noAck: true - } - ); - } - - private async startBasicConsume(channel: Channel): Promise { - await channel.consume( - this.options.clientQueue, - async (msg: ConsumeMessage | null) => { - try { - if (msg) { - await this.processMessage(msg); - } - } catch (e) { - this.logger.error( - 'Error while processing a message due to error occurred: ', - e - ); - } - }, - { - noAck: true - } - ); - } - - private async bindExchangesToQueue(channel: Channel): Promise { - await channel.assertExchange(this.options.exchange, 'direct', { - durable: true - }); - await channel.assertQueue(this.options.clientQueue, { - durable: true, - exclusive: false, - autoDelete: true - }); - await channel.prefetch(this.options.prefetchCount ?? 1); - } - - private processReply(message: ConsumeMessage | null): void { - const event: ParsedConsumeMessage | undefined = - this.parseConsumeMessage(message); - - if (event?.correlationId) { - this.logger.debug( - 'Received a reply (%s) with following payload: %j', - event.correlationId, - event.payload - ); - - this.subject.emit(event.correlationId, event.payload); - } else { - this.logger.debug( - 'Error while processing a reply. The correlation ID not found. Reply: %j', - event - ); - } - } - - private async processMessage(message: ConsumeMessage | null): Promise { - const event: ParsedConsumeMessage | undefined = - this.parseConsumeMessage(message); - - if (event) { - this.logger.debug( - 'Received a event (%s) with following payload: %j', - event.name, - event.payload - ); - - const handlers = this.handlers.get(event.name); - - if (!handlers) { - throw new EventHandlerNotFound(event.name); - } - - await Promise.all( - handlers.map(handler => this.handleEvent(handler, event)) - ); - } - } - - private async handleEvent( - handler: EventHandler, - event: ParsedConsumeMessage - ): Promise { - try { - const response = await handler.handle(event.payload); - - if (response && event.replyTo) { - this.logger.debug( - 'Sending a reply (%s) back with following payload: %j', - event.name, - event.payload - ); - - await this.tryToSendMessage({ - payload: response, - routingKey: event.replyTo, - correlationId: event.correlationId - }); - } - } catch (e) { - this.logger.error( - 'Error occurred while precessing a message (%s)', - event.correlationId, - e - ); - this.logger.debug('Failed message (%s): %j', event.correlationId, event); - } - } - - private async tryToSendMessage(options: RawMessage): Promise { - await this.retryStrategy.acquire(() => this.sendMessage(options)); - } - - private async sendMessage(options: RawMessage): Promise { - const { - type, - payload, - replyTo, - routingKey, - correlationId, - exchange = '', - timestamp = new Date() - } = options; - - this.logger.debug('Send a message with following parameters: %j', options); - - await this.getChannel().publish( - exchange ?? '', - routingKey, - Buffer.from(JSON.stringify(payload)), - { - type, - replyTo, - correlationId, - mandatory: true, - persistent: true, - contentType: 'application/json', - timestamp: timestamp?.getTime() - } - ); - } - - private parseConsumeMessage( - message: ConsumeMessage | null - ): ParsedConsumeMessage | undefined { - if (message && !message.fields.redelivered) { - const { content, fields, properties } = message; - const { type, correlationId, replyTo } = properties; - const { routingKey } = fields; - - const name = type ?? routingKey; - - const payload = JSON.parse(content.toString()); - - return { payload, name, correlationId, replyTo }; - } - } - - private getChannel(): NonNullable { - if (!this.channel) { - throw new IllegalOperation(this); - } - - return this.channel; - } -} diff --git a/packages/bus/src/dispatchers/RMQEventBusConfig.ts b/packages/bus/src/dispatchers/RMQEventBusConfig.ts deleted file mode 100644 index 146b16db..00000000 --- a/packages/bus/src/dispatchers/RMQEventBusConfig.ts +++ /dev/null @@ -1,8 +0,0 @@ -export interface RMQEventBusConfig { - exchange: string; - clientQueue: string; - appQueue: string; - prefetchCount?: number; -} - -export const RMQEventBusConfig: unique symbol = Symbol('RMQEventBusConfig'); diff --git a/packages/bus/src/dispatchers/index.ts b/packages/bus/src/dispatchers/index.ts deleted file mode 100644 index 964cb043..00000000 --- a/packages/bus/src/dispatchers/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export * from './HttpCommandDispatcher'; -export * from './RMQConnectionManager'; -export * from './DefaultRMQConnectionManager'; -export * from './HttpCommandDispatcherConfig'; -export * from './RMQEventBus'; -export * from './RMQEventBusConfig'; -export * from './RMQConnectionConfig'; diff --git a/packages/bus/src/exceptions/index.ts b/packages/bus/src/exceptions/index.ts deleted file mode 100644 index 89f6414c..00000000 --- a/packages/bus/src/exceptions/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './HttpCommandError'; diff --git a/packages/bus/src/index.ts b/packages/bus/src/index.ts deleted file mode 100644 index 1360e980..00000000 --- a/packages/bus/src/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './register'; - -export * from './dispatchers'; -export * from './commands'; -export * from './retry-strategies'; diff --git a/packages/bus/src/register.ts b/packages/bus/src/register.ts deleted file mode 100644 index f95e0f48..00000000 --- a/packages/bus/src/register.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { - DefaultRMQConnectionManager, - HttpCommandDispatcher, - HttpCommandDispatcherConfig, - RMQConnectionConfig, - RMQConnectionManager -} from './dispatchers'; -import { container, DependencyContainer } from 'tsyringe'; -import { CommandDispatcher, Configuration } from '@sectester/core'; - -container.register(CommandDispatcher, { useClass: HttpCommandDispatcher }); - -container.register(RMQConnectionManager, { - useClass: DefaultRMQConnectionManager -}); - -container.register(RMQConnectionConfig, { - useFactory(childContainer: DependencyContainer) { - const configuration = childContainer.resolve(Configuration); - - if (!configuration.credentials) { - throw new Error( - 'Please provide credentials to establish a connection with the dispatcher.' - ); - } - - return { - url: configuration.bus, - credentials: { - username: 'bot', - password: configuration.credentials.token ?? '' - } - }; - } -}); - -container.register(HttpCommandDispatcherConfig, { - useFactory(childContainer: DependencyContainer) { - const configuration = childContainer.resolve(Configuration); - - if (!configuration.credentials) { - throw new Error( - 'Please provide credentials to establish a connection with the dispatcher.' - ); - } - - return { - timeout: 10000, - baseUrl: configuration.api, - token: configuration.credentials.token - }; - } -}); diff --git a/packages/bus/src/retry-strategies/index.ts b/packages/bus/src/retry-strategies/index.ts deleted file mode 100644 index efab5561..00000000 --- a/packages/bus/src/retry-strategies/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { ExponentialBackoffRetryStrategy } from './ExponentialBackoffRetryStrategy'; -import { container } from 'tsyringe'; -import { RetryStrategy } from '@sectester/core'; - -container.register(RetryStrategy, { - useFactory() { - return new ExponentialBackoffRetryStrategy({ maxDepth: 5 }); - } -}); - -export * from './ExponentialBackoffRetryStrategy'; diff --git a/packages/bus/tsconfig.json b/packages/bus/tsconfig.json deleted file mode 100644 index 62ebbd94..00000000 --- a/packages/bus/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.lib.json" - }, - { - "path": "./tsconfig.spec.json" - } - ] -} diff --git a/packages/bus/tsconfig.lib.json b/packages/bus/tsconfig.lib.json deleted file mode 100644 index 0e68bec1..00000000 --- a/packages/bus/tsconfig.lib.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../dist/out-tsc", - "declaration": true, - "types": ["node"] - }, - "exclude": ["**/*.spec.ts", "**/*.test.ts", "jest.config.ts"], - "include": ["**/*.ts"] -} diff --git a/packages/bus/tsconfig.spec.json b/packages/bus/tsconfig.spec.json deleted file mode 100644 index a85d573f..00000000 --- a/packages/bus/tsconfig.spec.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../dist/out-tsc", - "module": "commonjs", - "types": ["jest", "node"] - }, - "include": [ - "**/*.test.ts", - "**/*.spec.ts", - "**/*.test.tsx", - "**/*.spec.tsx", - "**/*.test.js", - "**/*.spec.js", - "**/*.test.jsx", - "**/*.spec.jsx", - "**/*.d.ts", - "jest.config.ts" - ] -} diff --git a/packages/core/README.md b/packages/core/README.md index 2539b0d6..dd98b6b7 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -164,8 +164,6 @@ await new Ping({ status: 'connected' }).execute(dispatcher); await dispatcher.execute(new Ping({ status: 'disconnected' })); ``` -The same is applicable for the `Event`. You just need to use the `EventDispatcher` instead of `CommandDispatcher`. - Each message have a correlation ID to ensure atomicity. The regular UUID is used, but you might also want to consider other options. ### Request-response @@ -200,80 +198,9 @@ To adjust its behavior you can use next options: | `expectReply` | Indicates whether to wait for a reply. By default `true`. | | `ttl` | Period of time that command should be handled before being discarded. By default `10000` ms. | | `type` | The name of a command. By default, it is the name of specific class. | -| `corelationId` | Used to ensure atomicity while working with EventBus. By default, random UUID. | +| `corelationId` | Used to ensure atomicity. By default, random UUID. | | `createdAt` | The exact date and time the command was created. | -### Publish-subscribe - -When you just want to publish events without waiting for a response, it is better to use the `Event`. -The ideal use case for the publish-subscribe model is when you want to simply notify another service that a certain condition has occurred. - -To create an instance of `Event` use the abstract class as follows: - -```ts -import { Event } from '@sectester/core'; - -interface Issue { - name: string; - details: string; - type: string; - cvss?: string; - cwe?: string; -} - -class IssueDetected extends Event { - constructor(payload: Issue) { - super(payload); - } -} -``` - -To adjust its behavior you can use next options: - -| Option | Description | -| :------------- | ------------------------------------------------------------------------------ | -| `payload` | Message that we want to transmit to the remote service. | -| `type` | The name of a command. By default, it is the name of specific class. | -| `corelationId` | Used to ensure atomicity while working with EventBus. By default, random UUID. | -| `createdAt` | The exact date and time the event was created. | - -To create an event handler, you should implement the `Handler` interface and use the `@bind()` decorator to subscribe a handler to an event: - -```ts -@bind(IssueDetected) -class IssueDetectedHandler implements EventHandler { - public handle(payload: Issue): Promise { - // implementation - } -} -``` - -You can register multiple event handlers for a single event pattern and all of them will be automatically triggered in parallel. - -```ts -@bind(IssueDetected, IssueReopened) -class IssueDetectedHandler implements EventHandler { - public handle(payload: Issue): Promise { - // implementation - } -} -``` - -You can also use a string and symbol to subscribe a handler to events: - -```ts -const IssueReopened = Symbol('IssueReopened'); - -@bind('IssueDetected', IssueReopened) -class IssueDetectedHandler implements EventHandler { - public handle(payload: Issue): Promise { - // implementation - } -} -``` - -As soon as the `IssueDetected` event appears, the event handler takes a single argument, the data passed from the client (in this case, an event payload which has been sent over the network). - ## License Copyright © 2022 [Bright Security](https://brightsec.com/). diff --git a/packages/core/src/bus/Event.spec.ts b/packages/core/src/bus/Event.spec.ts deleted file mode 100644 index 12b7d68e..00000000 --- a/packages/core/src/bus/Event.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { EventDispatcher } from './EventDispatcher'; -import { Event } from './Event'; -import { instance, mock, reset, verify, when } from 'ts-mockito'; - -class TestEvent extends Event { - constructor(payload: string) { - super(payload); - } -} - -describe('Event', () => { - const mockDispatcher = mock(); - - afterEach(() => reset(mockDispatcher)); - - describe('publish', () => { - it('should publish event', async () => { - const event = new TestEvent('Test'); - when(mockDispatcher.publish(event)).thenResolve(); - - await event.publish(instance(mockDispatcher)); - - verify(mockDispatcher.publish(event)).once(); - }); - - it('should rethrow an exception', async () => { - const event = new TestEvent('Test'); - when(mockDispatcher.publish(event)).thenReject(); - - const result = event.publish(instance(mockDispatcher)); - - await expect(result).rejects.toThrow(); - }); - }); -}); diff --git a/packages/core/src/bus/Event.ts b/packages/core/src/bus/Event.ts deleted file mode 100644 index 897f64d2..00000000 --- a/packages/core/src/bus/Event.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { EventDispatcher } from './EventDispatcher'; -import { Message } from './Message'; - -export abstract class Event extends Message { - protected constructor( - payload: T, - type?: string, - correlationId?: string, - createdAt?: Date - ) { - super(payload, type, correlationId, createdAt); - } - - public publish(dispatcher: EventDispatcher): Promise { - return dispatcher.publish(this); - } -} - -export type EventConstructor = abstract new ( - ...args: any[] -) => Event; diff --git a/packages/core/src/bus/EventBus.ts b/packages/core/src/bus/EventBus.ts deleted file mode 100644 index c4688b8c..00000000 --- a/packages/core/src/bus/EventBus.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { CommandDispatcher } from './CommandDispatcher'; -import { EventDispatcher } from './EventDispatcher'; -import { EventHandlerConstructor } from './EventHandler'; - -export interface EventBus extends EventDispatcher, CommandDispatcher { - register(type: EventHandlerConstructor): Promise; - - unregister(type: EventHandlerConstructor): Promise; - - init?(): Promise; - - destroy?(): Promise; -} - -export const EventBus: unique symbol = Symbol('EventBus'); diff --git a/packages/core/src/bus/EventDispatcher.ts b/packages/core/src/bus/EventDispatcher.ts deleted file mode 100644 index 7aa08bf1..00000000 --- a/packages/core/src/bus/EventDispatcher.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Event } from './Event'; - -export interface EventDispatcher { - publish(event: Event): Promise; -} - -export const EventDispatcher: unique symbol = Symbol('EventDispatcher'); - diff --git a/packages/core/src/bus/EventHandler.ts b/packages/core/src/bus/EventHandler.ts deleted file mode 100644 index ec5ab2ea..00000000 --- a/packages/core/src/bus/EventHandler.ts +++ /dev/null @@ -1,7 +0,0 @@ -export interface EventHandler { - handle(payload: T): Promise; -} - -export type EventHandlerConstructor = new ( - ...args: any -) => EventHandler; diff --git a/packages/core/src/bus/decorators/bind.spec.ts b/packages/core/src/bus/decorators/bind.spec.ts deleted file mode 100644 index c5318be2..00000000 --- a/packages/core/src/bus/decorators/bind.spec.ts +++ /dev/null @@ -1,55 +0,0 @@ -// eslint-disable-next-line max-classes-per-file -import 'reflect-metadata'; -import { EventHandler } from '../EventHandler'; -import { Event } from '../Event'; -import { bind, EventName } from './bind'; - -describe('bind', () => { - class ConcreteEvent extends Event { - constructor(payload: string) { - super(payload); - } - } - - it.each([ - { - input: ConcreteEvent, - expected: 'ConcreteEvent' - }, - { - input: 'ConcreteEvent', - expected: 'ConcreteEvent' - }, - { - input: Symbol('ConcreteEvent'), - expected: 'ConcreteEvent' - } - ])('should discover event name from $input', ({ input, expected }) => { - // arrange - class ConcreteHandler implements EventHandler { - public async handle(_: string): Promise { - // noop - } - } - - // act - bind(input)(ConcreteHandler); - - // assert - expect(Reflect.getMetadata(Event, ConcreteHandler)).toEqual([expected]); - }); - - it('should throw an error if wrong argument is passed', () => { - // arrange - class ConcreteHandler implements EventHandler { - public async handle(_: string): Promise { - // noop - } - } - - // act/ assert - expect(() => - bind(undefined as unknown as EventName)(ConcreteHandler) - ).toThrow('undefined cannot be used with the @bind decorator'); - }); -}); diff --git a/packages/core/src/bus/decorators/bind.ts b/packages/core/src/bus/decorators/bind.ts deleted file mode 100644 index ba8629a4..00000000 --- a/packages/core/src/bus/decorators/bind.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Event, EventConstructor } from '../Event'; -import { UnsupportedEventType } from '../exceptions'; - -export type EventName = EventConstructor | string | symbol; - -export const bind = - (...events: EventName[]): ClassDecorator => - target => { - const eventNames = events.map(event => { - switch (typeof event) { - case 'string': - return event; - case 'function': - return event.name; - case 'symbol': - return event.description; - default: - throw new UnsupportedEventType(event); - } - }); - - Reflect.defineMetadata(Event, eventNames, target); - }; diff --git a/packages/core/src/bus/decorators/index.ts b/packages/core/src/bus/decorators/index.ts deleted file mode 100644 index 4921a486..00000000 --- a/packages/core/src/bus/decorators/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './bind'; diff --git a/packages/core/src/bus/exceptions/EventHandlerNotFound.ts b/packages/core/src/bus/exceptions/EventHandlerNotFound.ts deleted file mode 100644 index f3288aee..00000000 --- a/packages/core/src/bus/exceptions/EventHandlerNotFound.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { SecTesterError } from '../../exceptions'; - -export class EventHandlerNotFound extends SecTesterError { - constructor(...eventNames: string[]) { - super( - `Event handler not found. Please register a handler for the following events: ${eventNames.join( - ', ' - )}` - ); - } -} diff --git a/packages/core/src/bus/exceptions/IllegalOperation.ts b/packages/core/src/bus/exceptions/IllegalOperation.ts deleted file mode 100644 index 99d95231..00000000 --- a/packages/core/src/bus/exceptions/IllegalOperation.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { CommandDispatcher } from '../CommandDispatcher'; -import { EventDispatcher } from '../EventDispatcher'; -import { SecTesterError } from '../../exceptions'; -import { getTypeName } from '../../utils'; - -export class IllegalOperation extends SecTesterError { - constructor(instance: EventDispatcher | CommandDispatcher) { - super( - `Please make sure that ${getTypeName( - instance - )} established a connection with host.` - ); - } -} diff --git a/packages/core/src/bus/exceptions/NoResponse.ts b/packages/core/src/bus/exceptions/NoResponse.ts deleted file mode 100644 index 8e6c3bd1..00000000 --- a/packages/core/src/bus/exceptions/NoResponse.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { SecTesterError } from '../../exceptions'; - -export class NoResponse extends SecTesterError { - constructor(duration: number) { - super(`No response for ${duration} seconds.`); - } -} diff --git a/packages/core/src/bus/exceptions/NoSubscriptionsFound.ts b/packages/core/src/bus/exceptions/NoSubscriptionsFound.ts deleted file mode 100644 index a54b3fa2..00000000 --- a/packages/core/src/bus/exceptions/NoSubscriptionsFound.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { EventHandler } from '../EventHandler'; -import { SecTesterError } from '../../exceptions'; -import { getTypeName } from '../../utils'; - -export class NoSubscriptionsFound extends SecTesterError { - constructor(handler: EventHandler) { - super( - `No subscriptions found. Please use '@bind()' decorator to subscribe ${getTypeName( - handler - )} to events.` - ); - } -} diff --git a/packages/core/src/bus/exceptions/UnsupportedEventType.ts b/packages/core/src/bus/exceptions/UnsupportedEventType.ts deleted file mode 100644 index 6482ec25..00000000 --- a/packages/core/src/bus/exceptions/UnsupportedEventType.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { SecTesterError } from '../../exceptions'; -import { getTypeName } from '../../utils'; - -export class UnsupportedEventType extends SecTesterError { - constructor(event: unknown) { - super(`${getTypeName(event)} cannot be used with the @bind decorator.`); - } -} diff --git a/packages/core/src/bus/exceptions/index.ts b/packages/core/src/bus/exceptions/index.ts deleted file mode 100644 index 5d876832..00000000 --- a/packages/core/src/bus/exceptions/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './NoResponse'; -export * from './IllegalOperation'; -export * from './EventHandlerNotFound'; -export * from './NoSubscriptionsFound'; -export * from './UnsupportedEventType'; diff --git a/packages/core/src/bus/index.ts b/packages/core/src/bus/index.ts deleted file mode 100644 index b5652467..00000000 --- a/packages/core/src/bus/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -export * from './Command'; -export * from './CommandDispatcher'; -export * from './Event'; -export * from './Message'; -export * from './EventDispatcher'; -export * from './EventBus'; -export * from './RetryStartegy'; -export * from './EventHandler'; -export * from './exceptions'; -export * from './decorators'; diff --git a/packages/core/src/bus/Command.spec.ts b/packages/core/src/commands/Command.spec.ts similarity index 100% rename from packages/core/src/bus/Command.spec.ts rename to packages/core/src/commands/Command.spec.ts diff --git a/packages/core/src/bus/Command.ts b/packages/core/src/commands/Command.ts similarity index 100% rename from packages/core/src/bus/Command.ts rename to packages/core/src/commands/Command.ts diff --git a/packages/core/src/bus/CommandDispatcher.ts b/packages/core/src/commands/CommandDispatcher.ts similarity index 100% rename from packages/core/src/bus/CommandDispatcher.ts rename to packages/core/src/commands/CommandDispatcher.ts diff --git a/packages/bus/src/commands/HttpRequest.spec.ts b/packages/core/src/commands/HttpRequest.spec.ts similarity index 100% rename from packages/bus/src/commands/HttpRequest.spec.ts rename to packages/core/src/commands/HttpRequest.spec.ts diff --git a/packages/bus/src/commands/HttpRequest.ts b/packages/core/src/commands/HttpRequest.ts similarity index 96% rename from packages/bus/src/commands/HttpRequest.ts rename to packages/core/src/commands/HttpRequest.ts index 71ce8871..8e815700 100644 --- a/packages/bus/src/commands/HttpRequest.ts +++ b/packages/core/src/commands/HttpRequest.ts @@ -1,4 +1,4 @@ -import { Command } from '@sectester/core'; +import { Command } from './Command'; import { Method } from 'axios'; export interface HttpOptions { diff --git a/packages/core/src/bus/Message.spec.ts b/packages/core/src/commands/Message.spec.ts similarity index 100% rename from packages/core/src/bus/Message.spec.ts rename to packages/core/src/commands/Message.spec.ts diff --git a/packages/core/src/bus/Message.ts b/packages/core/src/commands/Message.ts similarity index 100% rename from packages/core/src/bus/Message.ts rename to packages/core/src/commands/Message.ts diff --git a/packages/core/src/bus/RetryStartegy.ts b/packages/core/src/commands/RetryStartegy.ts similarity index 100% rename from packages/core/src/bus/RetryStartegy.ts rename to packages/core/src/commands/RetryStartegy.ts diff --git a/packages/core/src/commands/index.ts b/packages/core/src/commands/index.ts new file mode 100644 index 00000000..120e351c --- /dev/null +++ b/packages/core/src/commands/index.ts @@ -0,0 +1,5 @@ +export * from './Command'; +export * from './CommandDispatcher'; +export * from './HttpRequest'; +export * from './Message'; +export * from './RetryStartegy'; diff --git a/packages/core/src/configuration/Configuration.spec.ts b/packages/core/src/configuration/Configuration.spec.ts index 0b38c331..01aa5c7e 100644 --- a/packages/core/src/configuration/Configuration.spec.ts +++ b/packages/core/src/configuration/Configuration.spec.ts @@ -94,61 +94,57 @@ describe('Configuration', () => { it.each([ { input: 'localhost', - expected: { bus: 'amqp://localhost:5672', api: 'http://localhost:8000' } + expected: { api: 'http://localhost:8000' } }, { input: 'localhost:8080', - expected: { bus: 'amqp://localhost:5672', api: 'http://localhost:8000' } + expected: { api: 'http://localhost:8000' } }, { input: 'http://localhost', - expected: { bus: 'amqp://localhost:5672', api: 'http://localhost:8000' } + expected: { api: 'http://localhost:8000' } }, { input: 'http://localhost:8080', - expected: { bus: 'amqp://localhost:5672', api: 'http://localhost:8000' } + expected: { api: 'http://localhost:8000' } }, { input: '127.0.0.1', - expected: { bus: 'amqp://127.0.0.1:5672', api: 'http://127.0.0.1:8000' } + expected: { api: 'http://127.0.0.1:8000' } }, { input: '127.0.0.1:8080', - expected: { bus: 'amqp://127.0.0.1:5672', api: 'http://127.0.0.1:8000' } + expected: { api: 'http://127.0.0.1:8000' } }, { input: 'http://127.0.0.1', - expected: { bus: 'amqp://127.0.0.1:5672', api: 'http://127.0.0.1:8000' } + expected: { api: 'http://127.0.0.1:8000' } }, { input: 'http://127.0.0.1:8080', - expected: { bus: 'amqp://127.0.0.1:5672', api: 'http://127.0.0.1:8000' } + expected: { api: 'http://127.0.0.1:8000' } }, { input: 'example.com', expected: { - bus: 'amqps://amq.example.com:5672', api: 'https://example.com' } }, { input: 'example.com:443', expected: { - bus: 'amqps://amq.example.com:5672', api: 'https://example.com' } }, { input: 'http://example.com', expected: { - bus: 'amqps://amq.example.com:5672', api: 'https://example.com' } }, { input: 'http://example.com:443', expected: { - bus: 'amqps://amq.example.com:5672', api: 'https://example.com' } } diff --git a/packages/core/src/configuration/Configuration.ts b/packages/core/src/configuration/Configuration.ts index e350dc00..05b9cb6a 100644 --- a/packages/core/src/configuration/Configuration.ts +++ b/packages/core/src/configuration/Configuration.ts @@ -38,12 +38,6 @@ export class Configuration { return this._credentials; } - private _bus!: string; - - get bus() { - return this._bus; - } - private _api!: string; get api() { @@ -132,10 +126,8 @@ export class Configuration { } if (['localhost', '127.0.0.1'].includes(hostname)) { - this._bus = `amqp://${hostname}:5672`; this._api = `http://${hostname}:8000`; } else { - this._bus = `amqps://amq.${hostname}:5672`; this._api = `https://${hostname}`; } } diff --git a/packages/bus/src/retry-strategies/ExponentialBackoffRetryStrategy.spec.ts b/packages/core/src/dispatchers/ExponentialBackoffRetryStrategy.spec.ts similarity index 99% rename from packages/bus/src/retry-strategies/ExponentialBackoffRetryStrategy.spec.ts rename to packages/core/src/dispatchers/ExponentialBackoffRetryStrategy.spec.ts index 6639d981..68c4f3b7 100644 --- a/packages/bus/src/retry-strategies/ExponentialBackoffRetryStrategy.spec.ts +++ b/packages/core/src/dispatchers/ExponentialBackoffRetryStrategy.spec.ts @@ -1,3 +1,4 @@ +import 'reflect-metadata'; import { ExponentialBackoffRetryStrategy } from './ExponentialBackoffRetryStrategy'; import { HttpCommandError } from '../exceptions'; import { AxiosRequestConfig } from 'axios'; diff --git a/packages/bus/src/retry-strategies/ExponentialBackoffRetryStrategy.ts b/packages/core/src/dispatchers/ExponentialBackoffRetryStrategy.ts similarity index 95% rename from packages/bus/src/retry-strategies/ExponentialBackoffRetryStrategy.ts rename to packages/core/src/dispatchers/ExponentialBackoffRetryStrategy.ts index 209c3220..ff054e21 100644 --- a/packages/bus/src/retry-strategies/ExponentialBackoffRetryStrategy.ts +++ b/packages/core/src/dispatchers/ExponentialBackoffRetryStrategy.ts @@ -1,5 +1,6 @@ import { HttpCommandError } from '../exceptions'; -import { delay, RetryStrategy } from '@sectester/core'; +import { RetryStrategy } from '../commands'; +import { delay } from '../utils'; import { injectable } from 'tsyringe'; import ErrnoException = NodeJS.ErrnoException; diff --git a/packages/bus/src/dispatchers/HttpCommandDispatcher.spec.ts b/packages/core/src/dispatchers/HttpCommandDispatcher.spec.ts similarity index 98% rename from packages/bus/src/dispatchers/HttpCommandDispatcher.spec.ts rename to packages/core/src/dispatchers/HttpCommandDispatcher.spec.ts index 02b94aa8..7ddde649 100644 --- a/packages/bus/src/dispatchers/HttpCommandDispatcher.spec.ts +++ b/packages/core/src/dispatchers/HttpCommandDispatcher.spec.ts @@ -1,8 +1,9 @@ -import { HttpRequest } from '../commands'; +import 'reflect-metadata'; +import { HttpRequest, RetryStrategy } from '../commands'; import { HttpCommandDispatcher } from './HttpCommandDispatcher'; import { HttpCommandDispatcherConfig } from './HttpCommandDispatcherConfig'; import { HttpCommandError } from '../exceptions'; -import { Logger, RetryStrategy } from '@sectester/core'; +import { Logger } from '../logger'; import { anyFunction, instance, diff --git a/packages/bus/src/dispatchers/HttpCommandDispatcher.ts b/packages/core/src/dispatchers/HttpCommandDispatcher.ts similarity index 96% rename from packages/bus/src/dispatchers/HttpCommandDispatcher.ts rename to packages/core/src/dispatchers/HttpCommandDispatcher.ts index 8db552be..c091c713 100644 --- a/packages/bus/src/dispatchers/HttpCommandDispatcher.ts +++ b/packages/core/src/dispatchers/HttpCommandDispatcher.ts @@ -1,7 +1,7 @@ import { HttpCommandDispatcherConfig } from './HttpCommandDispatcherConfig'; -import { HttpRequest } from '../commands'; +import { CommandDispatcher, RetryStrategy, HttpRequest } from '../commands'; import { HttpCommandError } from '../exceptions'; -import { CommandDispatcher, Logger, RetryStrategy } from '@sectester/core'; +import { Logger } from '../logger'; import { inject, injectable } from 'tsyringe'; import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'; import rateLimit from 'axios-rate-limit'; diff --git a/packages/bus/src/dispatchers/HttpCommandDispatcherConfig.ts b/packages/core/src/dispatchers/HttpCommandDispatcherConfig.ts similarity index 100% rename from packages/bus/src/dispatchers/HttpCommandDispatcherConfig.ts rename to packages/core/src/dispatchers/HttpCommandDispatcherConfig.ts diff --git a/packages/core/src/dispatchers/index.ts b/packages/core/src/dispatchers/index.ts new file mode 100644 index 00000000..b7147548 --- /dev/null +++ b/packages/core/src/dispatchers/index.ts @@ -0,0 +1,3 @@ +export * from './HttpCommandDispatcher'; +export * from './HttpCommandDispatcherConfig'; +export * from './ExponentialBackoffRetryStrategy'; diff --git a/packages/bus/src/exceptions/HttpCommandError.spec.ts b/packages/core/src/exceptions/HttpCommandError.spec.ts similarity index 100% rename from packages/bus/src/exceptions/HttpCommandError.spec.ts rename to packages/core/src/exceptions/HttpCommandError.spec.ts diff --git a/packages/bus/src/exceptions/HttpCommandError.ts b/packages/core/src/exceptions/HttpCommandError.ts similarity index 85% rename from packages/bus/src/exceptions/HttpCommandError.ts rename to packages/core/src/exceptions/HttpCommandError.ts index c40d795b..c869787b 100644 --- a/packages/bus/src/exceptions/HttpCommandError.ts +++ b/packages/core/src/exceptions/HttpCommandError.ts @@ -1,5 +1,6 @@ +import { SecTesterError } from './SecTesterError'; +import { isStream, isPresent } from '../utils'; import { AxiosError } from 'axios'; -import { SecTesterError, isStream, isPresent } from '@sectester/core'; export class HttpCommandError extends SecTesterError { public readonly status: number | undefined; diff --git a/packages/core/src/exceptions/index.ts b/packages/core/src/exceptions/index.ts index bc6e9e8b..a8a9cf6b 100644 --- a/packages/core/src/exceptions/index.ts +++ b/packages/core/src/exceptions/index.ts @@ -1 +1,2 @@ export * from './SecTesterError'; +export * from './HttpCommandError'; diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 7323b48b..bb5171d1 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,9 +1,10 @@ import 'reflect-metadata'; import './register'; -export * from './bus'; +export * from './commands'; export * from './configuration'; export * from './credentials-provider'; +export * from './dispatchers'; export * from './exceptions'; export * from './logger'; export { diff --git a/packages/core/src/register.ts b/packages/core/src/register.ts index 344e2e65..ccdb1046 100644 --- a/packages/core/src/register.ts +++ b/packages/core/src/register.ts @@ -1,4 +1,10 @@ +import { CommandDispatcher, RetryStrategy } from './commands'; import { Configuration } from './configuration'; +import { + ExponentialBackoffRetryStrategy, + HttpCommandDispatcher, + HttpCommandDispatcherConfig +} from './dispatchers'; import { Logger } from './logger'; import { container, @@ -6,6 +12,12 @@ import { instancePerContainerCachingFactory } from 'tsyringe'; +container.register(RetryStrategy, { + useFactory() { + return new ExponentialBackoffRetryStrategy({ maxDepth: 5 }); + } +}); + container.register(Logger, { useFactory: instancePerContainerCachingFactory((child: DependencyContainer) => child.isRegistered(Configuration, true) @@ -13,3 +25,23 @@ container.register(Logger, { : new Logger() ) }); + +container.register(CommandDispatcher, { useClass: HttpCommandDispatcher }); + +container.register(HttpCommandDispatcherConfig, { + useFactory(childContainer: DependencyContainer) { + const configuration = childContainer.resolve(Configuration); + + if (!configuration.credentials) { + throw new Error( + 'Please provide credentials to establish a connection with the dispatcher.' + ); + } + + return { + timeout: 10000, + baseUrl: configuration.api, + token: configuration.credentials.token + }; + } +}); diff --git a/packages/repeater/package.json b/packages/repeater/package.json index a8dd4c65..52402707 100644 --- a/packages/repeater/package.json +++ b/packages/repeater/package.json @@ -35,7 +35,6 @@ "onprem" ], "peerDependencies": { - "@sectester/bus": ">=0.16.0 <1.0.0", "@sectester/core": ">=0.16.0 <1.0.0" } } diff --git a/packages/repeater/src/api/DefaultRepeatersManager.ts b/packages/repeater/src/api/DefaultRepeatersManager.ts index 7b199b36..c891ebc3 100644 --- a/packages/repeater/src/api/DefaultRepeatersManager.ts +++ b/packages/repeater/src/api/DefaultRepeatersManager.ts @@ -49,7 +49,7 @@ export class DefaultRepeatersManager implements RepeatersManager { return { repeaterId: repeater.id }; } - public async deleteRepeater(repeaterId: string): Promise { + public deleteRepeater(repeaterId: string): Promise { return this.commandDispatcher.execute( new DeleteRepeaterRequest({ repeaterId }) ); diff --git a/packages/repeater/src/api/ExecuteRequestEventHandler.spec.ts b/packages/repeater/src/api/ExecuteRequestEventHandler.spec.ts deleted file mode 100644 index 6897eb9a..00000000 --- a/packages/repeater/src/api/ExecuteRequestEventHandler.spec.ts +++ /dev/null @@ -1,69 +0,0 @@ -import 'reflect-metadata'; -import { ExecuteRequestEventHandler } from './ExecuteRequestEventHandler'; -import { Protocol } from '../models'; -import { RequestRunner } from '../request-runner'; -import { anything, instance, mock, reset, when } from 'ts-mockito'; - -describe('ExecuteRequestEventHandler', () => { - const requestRunnerResponse = { - protocol: Protocol.HTTP, - statusCode: 200, - errorCode: '', - body: 'text' - }; - - const objectKeysTransformer = - (transform: (x: string) => string) => (obj: Record) => - Object.fromEntries( - Object.entries(obj).map(([key, value]: [string, unknown]) => [ - transform(key), - value - ]) - ); - - const toSnakeCaseKeys = objectKeysTransformer(key => - key.replace(/([a-z])([A-Z])/g, `$1_$2`).toLowerCase() - ); - - const responsePayload = toSnakeCaseKeys(requestRunnerResponse); - - const mockedRequestRunner = mock(); - - beforeEach(() => { - when(mockedRequestRunner.protocol).thenReturn(Protocol.HTTP); - when(mockedRequestRunner.run(anything())).thenResolve( - requestRunnerResponse - ); - }); - - afterEach(() => reset(mockedRequestRunner)); - - describe('handle', () => { - it('should run request having corresponding runner', async () => { - const requestPayload = { - protocol: Protocol.HTTP, - url: 'http://foo.bar', - headers: {} - }; - const handler = new ExecuteRequestEventHandler([ - instance(mockedRequestRunner) - ]); - - const res = await handler.handle(requestPayload); - - expect(res).toEqual(responsePayload); - }); - - it('should throw an error if cannot find corresponding runner', async () => { - const handler = new ExecuteRequestEventHandler([]); - - const res = handler.handle({ - protocol: Protocol.HTTP, - url: 'http://foo.bar', - headers: {} - }); - - await expect(res).rejects.toThrow(`Unsupported protocol "http"`); - }); - }); -}); diff --git a/packages/repeater/src/api/ExecuteRequestEventHandler.ts b/packages/repeater/src/api/ExecuteRequestEventHandler.ts deleted file mode 100644 index f8dd43d1..00000000 --- a/packages/repeater/src/api/ExecuteRequestEventHandler.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { Protocol } from '../models'; -import { Request, RequestRunner, Response } from '../request-runner'; -import { bind, EventHandler } from '@sectester/core'; -import { injectAll, Lifecycle, scoped } from 'tsyringe'; - -export interface ExecuteRequestPayload { - readonly protocol: Protocol; - readonly url: string; - readonly headers: Record; - readonly method?: string; - readonly body?: string; - readonly correlation_id_regex?: string; -} - -export interface ExecuteRequestResult { - readonly protocol: Protocol; - readonly body?: string; - readonly headers?: Record; - readonly status_code?: number; - readonly error_code?: string; - readonly message?: string; -} - -@scoped(Lifecycle.ContainerScoped) -@bind('ExecuteScript') -export class ExecuteRequestEventHandler - implements EventHandler -{ - constructor( - @injectAll(RequestRunner) - private readonly requestRunners: RequestRunner[] - ) {} - - public async handle( - event: ExecuteRequestPayload - ): Promise { - const { protocol } = event; - - const runner = this.requestRunners.find(x => x.protocol === protocol); - - if (!runner) { - throw new Error(`Unsupported protocol "${protocol}"`); - } - - const response: Response = await runner.run(new Request({ ...event })); - - const { statusCode, message, errorCode, body, headers } = response; - - return { - protocol, - body, - headers, - message, - status_code: statusCode, - error_code: errorCode - }; - } -} diff --git a/packages/repeater/src/api/commands/CreateRepeaterRequest.ts b/packages/repeater/src/api/commands/CreateRepeaterRequest.ts index 7a493d3f..9f093046 100644 --- a/packages/repeater/src/api/commands/CreateRepeaterRequest.ts +++ b/packages/repeater/src/api/commands/CreateRepeaterRequest.ts @@ -1,4 +1,4 @@ -import { HttpRequest } from '@sectester/bus'; +import { HttpRequest } from '@sectester/core'; export interface CreateRepeaterRequestPayload { name: string; diff --git a/packages/repeater/src/api/commands/DeleteRepeaterRequest.ts b/packages/repeater/src/api/commands/DeleteRepeaterRequest.ts index e6b26620..85bf9bda 100644 --- a/packages/repeater/src/api/commands/DeleteRepeaterRequest.ts +++ b/packages/repeater/src/api/commands/DeleteRepeaterRequest.ts @@ -1,4 +1,4 @@ -import { HttpRequest } from '@sectester/bus'; +import { HttpRequest } from '@sectester/core'; export class DeleteRepeaterRequest extends HttpRequest { constructor(payload: { repeaterId: string }) { diff --git a/packages/repeater/src/api/commands/GetRepeaterRequest.ts b/packages/repeater/src/api/commands/GetRepeaterRequest.ts index 05882ff5..8f72d18e 100644 --- a/packages/repeater/src/api/commands/GetRepeaterRequest.ts +++ b/packages/repeater/src/api/commands/GetRepeaterRequest.ts @@ -1,4 +1,4 @@ -import { HttpRequest } from '@sectester/bus'; +import { HttpRequest } from '@sectester/core'; export interface GetRepeaterResponsePayload { id: string; diff --git a/packages/repeater/src/register.ts b/packages/repeater/src/register.ts index 84752d1f..5096263b 100644 --- a/packages/repeater/src/register.ts +++ b/packages/repeater/src/register.ts @@ -1,6 +1,5 @@ import { RepeaterFactory, - RepeaterId, DefaultRepeaterCommands, DefaultRepeaterServer, DefaultRepeaterServerOptions, @@ -14,22 +13,8 @@ import { } from './request-runner'; import { DefaultRepeatersManager, RepeatersManager } from './api'; import { DefaultProxyFactory, ProxyFactory } from './utils'; -import { - container, - DependencyContainer, - instancePerContainerCachingFactory -} from 'tsyringe'; -import { - Configuration, - EventBus, - Logger, - RetryStrategy -} from '@sectester/core'; -import { - RMQConnectionManager, - RMQEventBus, - RMQEventBusConfig -} from '@sectester/bus'; +import { container, DependencyContainer } from 'tsyringe'; +import { Configuration } from '@sectester/core'; container.register(RequestRunner, { useClass: HttpRequestRunner @@ -65,35 +50,6 @@ container.register(RepeaterFactory, { } }); -container.register(RMQEventBusConfig, { - useFactory: instancePerContainerCachingFactory( - (childContainer: DependencyContainer) => ({ - exchange: 'EventBus', - appQueue: 'app', - clientQueue: `agent:${childContainer.resolve(RepeaterId)}` - }) - ) -}); - -container.register(EventBus, { - useFactory: (childContainer: DependencyContainer) => { - const connectionManager = - childContainer.resolve(RMQConnectionManager); - const logger = childContainer.resolve(Logger); - const retryStrategy = childContainer.resolve(RetryStrategy); - const eventBusConfig = - childContainer.resolve(RMQEventBusConfig); - - return new RMQEventBus( - childContainer, - logger, - retryStrategy, - eventBusConfig, - connectionManager - ); - } -}); - container.register(DefaultRepeaterServerOptions, { useFactory: (childContainer: DependencyContainer) => { const configuration = childContainer.resolve(Configuration); diff --git a/packages/runner/package.json b/packages/runner/package.json index 00831908..3e949594 100644 --- a/packages/runner/package.json +++ b/packages/runner/package.json @@ -33,7 +33,6 @@ "brightsec" ], "peerDependencies": { - "@sectester/bus": ">=0.16.0 <1.0.0", "@sectester/core": ">=0.16.0 <1.0.0", "@sectester/repeater": ">=0.16.0 <1.0.0", "@sectester/reporter": ">=0.16.0 <1.0.0", diff --git a/packages/scan/package.json b/packages/scan/package.json index 0acd6d49..1c3c3d95 100644 --- a/packages/scan/package.json +++ b/packages/scan/package.json @@ -35,7 +35,6 @@ "dast" ], "peerDependencies": { - "@sectester/bus": ">=0.16.0 <1.0.0", "@sectester/core": ">=0.16.0 <1.0.0" } } diff --git a/packages/scan/src/commands/CreateScan.ts b/packages/scan/src/commands/CreateScan.ts index f2468cbf..9115346e 100644 --- a/packages/scan/src/commands/CreateScan.ts +++ b/packages/scan/src/commands/CreateScan.ts @@ -1,5 +1,5 @@ import { ScanConfig } from '../models'; -import { HttpRequest } from '@sectester/bus'; +import { HttpRequest } from '@sectester/core'; export type CreateScanPayload = ScanConfig & { info: { diff --git a/packages/scan/src/commands/DeleteScan.ts b/packages/scan/src/commands/DeleteScan.ts index 6e4a1bd9..0e48e32b 100644 --- a/packages/scan/src/commands/DeleteScan.ts +++ b/packages/scan/src/commands/DeleteScan.ts @@ -1,4 +1,4 @@ -import { HttpRequest } from '@sectester/bus'; +import { HttpRequest } from '@sectester/core'; export class DeleteScan extends HttpRequest { constructor(id: string) { diff --git a/packages/scan/src/commands/GetScan.ts b/packages/scan/src/commands/GetScan.ts index b4c0b3ff..b641114d 100644 --- a/packages/scan/src/commands/GetScan.ts +++ b/packages/scan/src/commands/GetScan.ts @@ -1,5 +1,5 @@ import { ScanState } from '../models'; -import { HttpRequest } from '@sectester/bus'; +import { HttpRequest } from '@sectester/core'; export class GetScan extends HttpRequest { constructor(id: string) { diff --git a/packages/scan/src/commands/ListIssues.ts b/packages/scan/src/commands/ListIssues.ts index e26787f3..1c13b724 100644 --- a/packages/scan/src/commands/ListIssues.ts +++ b/packages/scan/src/commands/ListIssues.ts @@ -1,5 +1,5 @@ import { Issue } from '../models'; -import { HttpRequest } from '@sectester/bus'; +import { HttpRequest } from '@sectester/core'; export class ListIssues extends HttpRequest[]> { constructor(id: string) { diff --git a/packages/scan/src/commands/StopScan.ts b/packages/scan/src/commands/StopScan.ts index d1ea734f..c68e0f19 100644 --- a/packages/scan/src/commands/StopScan.ts +++ b/packages/scan/src/commands/StopScan.ts @@ -1,4 +1,4 @@ -import { HttpRequest } from '@sectester/bus'; +import { HttpRequest } from '@sectester/core'; export class StopScan extends HttpRequest { constructor(id: string) { diff --git a/packages/scan/src/commands/UploadHar.ts b/packages/scan/src/commands/UploadHar.ts index d2f83f82..7ad5d5a2 100644 --- a/packages/scan/src/commands/UploadHar.ts +++ b/packages/scan/src/commands/UploadHar.ts @@ -1,6 +1,6 @@ import { UploadHarOptions } from '../Scans'; import FormData from 'form-data'; -import { HttpRequest } from '@sectester/bus'; +import { HttpRequest } from '@sectester/core'; export class UploadHar extends HttpRequest { constructor({ filename, har, discard = false }: UploadHarOptions) { diff --git a/workspace.json b/workspace.json index d4fb06e1..020fae72 100644 --- a/workspace.json +++ b/workspace.json @@ -1,7 +1,6 @@ { "version": 2, "projects": { - "bus": "packages/bus", "core": "packages/core", "repeater": "packages/repeater", "reporter": "packages/reporter",