From b2809e9e7df3128fbdafc7914d274238dd006017 Mon Sep 17 00:00:00 2001 From: dostrikov Date: Thu, 20 Jun 2024 12:33:38 +0700 Subject: [PATCH] feat(bus): get rid of amqp event bus (#198) 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 761e46b6..e94f9075 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", @@ -6695,7 +6628,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", @@ -7079,11 +7013,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", @@ -12302,11 +12231,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", @@ -12357,7 +12281,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", @@ -12556,17 +12481,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", @@ -12655,7 +12569,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", @@ -13686,11 +13601,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", @@ -14645,6 +14555,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" @@ -15183,18 +15094,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", @@ -15213,7 +15112,6 @@ "npm": ">=8" }, "peerDependencies": { - "@sectester/bus": ">=0.16.0 <1.0.0", "@sectester/core": ">=0.16.0 <1.0.0" } }, @@ -15238,7 +15136,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", @@ -15254,29 +15151,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", @@ -16892,10 +16771,6 @@ } } }, - "@sectester/bus": { - "version": "file:packages/bus", - "requires": {} - }, "@sectester/core": { "version": "file:packages/core" }, @@ -17117,15 +16992,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", @@ -17770,25 +17636,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", @@ -18147,11 +17994,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", @@ -18608,7 +18450,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", @@ -20391,7 +20234,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", @@ -20646,11 +20490,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", @@ -24421,11 +24260,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", @@ -24463,7 +24297,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", @@ -24612,17 +24447,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", @@ -24690,7 +24514,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", @@ -25504,11 +25329,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", @@ -26209,6 +26029,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",