diff --git a/examples/cactus-example-supply-chain-business-logic-plugin/src/main/typescript/business-logic-plugin/supply-chain-cactus-plugin.ts b/examples/cactus-example-supply-chain-business-logic-plugin/src/main/typescript/business-logic-plugin/supply-chain-cactus-plugin.ts index 615d570b18..8bf704a33e 100644 --- a/examples/cactus-example-supply-chain-business-logic-plugin/src/main/typescript/business-logic-plugin/supply-chain-cactus-plugin.ts +++ b/examples/cactus-example-supply-chain-business-logic-plugin/src/main/typescript/business-logic-plugin/supply-chain-cactus-plugin.ts @@ -1,4 +1,6 @@ import { Optional } from "typescript-optional"; +import { Express } from "express"; + import { Logger, Checks, @@ -18,6 +20,7 @@ import { import { DefaultApi as BesuApi } from "@hyperledger/cactus-plugin-ledger-connector-besu"; import { InsertBambooHarvestEndpoint } from "./web-services/insert-bamboo-harvest-endpoint"; import { DefaultApi as FabricApi } from "@hyperledger/cactus-plugin-ledger-connector-fabric"; + import { ListBambooHarvestEndpoint } from "./web-services/list-bamboo-harvest-endpoint"; import { ISupplyChainContractDeploymentInfo } from "../i-supply-chain-contract-deployment-info"; import { InsertBookshelfEndpoint } from "./web-services/insert-bookshelf-endpoint"; @@ -51,6 +54,8 @@ export class SupplyChainCactusPlugin private readonly log: Logger; private readonly instanceId: string; + private endpoints: IWebServiceEndpoint[] | undefined; + public get className(): string { return SupplyChainCactusPlugin.CLASS_NAME; } @@ -73,9 +78,16 @@ export class SupplyChainCactusPlugin this.instanceId = options.instanceId; } - public async installWebServices( - expressApp: any, - ): Promise { + async registerWebServices(app: Express): Promise { + const webServices = await this.getOrCreateWebServices(); + webServices.forEach((ws) => ws.registerExpress(app)); + return webServices; + } + + public async getOrCreateWebServices(): Promise { + if (Array.isArray(this.endpoints)) { + return this.endpoints; + } const insertBambooHarvest = new InsertBambooHarvestEndpoint({ contractAddress: this.options.contracts.bambooHarvestRepository.address, contractAbi: this.options.contracts.bambooHarvestRepository.abi, @@ -84,7 +96,6 @@ export class SupplyChainCactusPlugin .web3SigningCredential as Web3SigningCredential, logLevel: this.options.logLevel, }); - insertBambooHarvest.registerExpress(expressApp); const listBambooHarvest = new ListBambooHarvestEndpoint({ contractAddress: this.options.contracts.bambooHarvestRepository.address, @@ -92,7 +103,6 @@ export class SupplyChainCactusPlugin apiClient: this.options.quorumApiClient, logLevel: this.options.logLevel, }); - listBambooHarvest.registerExpress(expressApp); const insertBookshelf = new InsertBookshelfEndpoint({ contractAddress: this.options.contracts.bookshelfRepository.address, @@ -102,7 +112,6 @@ export class SupplyChainCactusPlugin .web3SigningCredential as Web3SigningCredential, logLevel: this.options.logLevel, }); - insertBookshelf.registerExpress(expressApp); const listBookshelf = new ListBookshelfEndpoint({ contractAddress: this.options.contracts.bookshelfRepository.address, @@ -110,21 +119,18 @@ export class SupplyChainCactusPlugin besuApi: this.options.besuApiClient, logLevel: this.options.logLevel, }); - listBookshelf.registerExpress(expressApp); const insertShipment = new InsertShipmentEndpoint({ logLevel: this.options.logLevel, fabricApi: this.options.fabricApiClient, }); - insertShipment.registerExpress(expressApp); const listShipment = new ListShipmentEndpoint({ logLevel: this.options.logLevel, fabricApi: this.options.fabricApiClient, }); - listShipment.registerExpress(expressApp); - return [ + this.endpoints = [ insertBambooHarvest, listBambooHarvest, insertBookshelf, @@ -132,6 +138,7 @@ export class SupplyChainCactusPlugin insertShipment, listShipment, ]; + return this.endpoints; } public getHttpServer(): Optional { diff --git a/packages/cactus-cmd-api-server/package-lock.json b/packages/cactus-cmd-api-server/package-lock.json index 2e87a7d7f6..771887ac3b 100644 --- a/packages/cactus-cmd-api-server/package-lock.json +++ b/packages/cactus-cmd-api-server/package-lock.json @@ -178,6 +178,15 @@ "integrity": "sha512-8Ly3zIPTnT0/8RCU6Kg/G3uTICf9sRwYOpUzSIM3503tLIKcnJPRuinHhXngJUy2MntrEf6dlpOHXJju90Qh5w==", "dev": true }, + "@types/xml2js": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.8.tgz", + "integrity": "sha512-EyvT83ezOdec7BhDaEcsklWy7RSIdi6CNe95tmOAK0yx/Lm30C9K75snT3fYayK59ApC2oyW+rcHErdG05FHJA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "accepts": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", diff --git a/packages/cactus-cmd-api-server/package.json b/packages/cactus-cmd-api-server/package.json index c9668e19f1..cb47429d6d 100644 --- a/packages/cactus-cmd-api-server/package.json +++ b/packages/cactus-cmd-api-server/package.json @@ -118,6 +118,7 @@ "@types/node-forge": "0.9.3", "@types/npm": "2.0.31", "@types/semver": "7.3.1", - "@types/uuid": "7.0.2" + "@types/uuid": "7.0.2", + "@types/xml2js": "0.4.8" } } diff --git a/packages/cactus-cmd-api-server/src/main/typescript/api-server.ts b/packages/cactus-cmd-api-server/src/main/typescript/api-server.ts index 4f2a13472b..009ddb981d 100644 --- a/packages/cactus-cmd-api-server/src/main/typescript/api-server.ts +++ b/packages/cactus-cmd-api-server/src/main/typescript/api-server.ts @@ -372,20 +372,12 @@ export class ApiServer { return addressInfo; } - async startApiServer(): Promise { - const app: Application = express(); - app.use(compression()); - - const apiCorsDomainCsv = this.options.config.apiCorsDomainCsv; - const allowedDomains = apiCorsDomainCsv.split(","); - const corsMiddleware = this.createCorsMiddleware(allowedDomains); - app.use(corsMiddleware); - - app.use(bodyParser.json({ limit: "50mb" })); - - const openApiValidator = this.createOpenApiValidator(); - await openApiValidator.install(app); - + /** + * Installs the own endpoints of the API server such as the ones providing + * healthcheck and monitoring information. + * @param app + */ + async getOrCreateWebServices(app: express.Application): Promise { const healthcheckHandler = (req: Request, res: Response) => { res.json({ success: true, @@ -420,16 +412,34 @@ export class ApiServer { httpPathPrometheus, prometheusExporterHandler, ); + } - const registry = await this.getOrInitPluginRegistry(); + async startApiServer(): Promise { + const pluginRegistry = await this.getOrInitPluginRegistry(); + + const app: Application = express(); + app.use(compression()); + + const apiCorsDomainCsv = this.options.config.apiCorsDomainCsv; + const allowedDomains = apiCorsDomainCsv.split(","); + const corsMiddleware = this.createCorsMiddleware(allowedDomains); + app.use(corsMiddleware); + + app.use(bodyParser.json({ limit: "50mb" })); + + const openApiValidator = this.createOpenApiValidator(); + await openApiValidator.install(app); + + this.getOrCreateWebServices(app); // The API server's own endpoints this.log.info(`Starting to install web services...`); - const webServicesInstalled = registry + const webServicesInstalled = pluginRegistry .getPlugins() .filter((pluginInstance) => isIPluginWebService(pluginInstance)) - .map((pluginInstance: ICactusPlugin) => { - return (pluginInstance as IPluginWebService).installWebServices(app); + .map(async (plugin: ICactusPlugin) => { + await (plugin as IPluginWebService).getOrCreateWebServices(); + return (plugin as IPluginWebService).registerWebServices(app); }); const endpoints2D = await Promise.all(webServicesInstalled); diff --git a/packages/cactus-core-api/src/main/typescript/plugin/web-service/i-plugin-web-service.ts b/packages/cactus-core-api/src/main/typescript/plugin/web-service/i-plugin-web-service.ts index dba765d300..8e90bb64bd 100644 --- a/packages/cactus-core-api/src/main/typescript/plugin/web-service/i-plugin-web-service.ts +++ b/packages/cactus-core-api/src/main/typescript/plugin/web-service/i-plugin-web-service.ts @@ -1,11 +1,13 @@ -import { IWebServiceEndpoint } from "./i-web-service-endpoint"; -import { ICactusPlugin } from "../i-cactus-plugin"; import { Server } from "http"; import { Server as SecureServer } from "https"; import { Optional } from "typescript-optional"; +import { Application } from "express"; +import { IWebServiceEndpoint } from "./i-web-service-endpoint"; +import { ICactusPlugin } from "../i-cactus-plugin"; export interface IPluginWebService extends ICactusPlugin { - installWebServices(expressApp: any): Promise; + getOrCreateWebServices(): Promise; + registerWebServices(expressApp: Application): Promise; getHttpServer(): Optional; shutdown(): Promise; } @@ -15,7 +17,9 @@ export function isIPluginWebService( ): pluginInstance is IPluginWebService { return ( pluginInstance && - typeof (pluginInstance as IPluginWebService).installWebServices === + typeof (pluginInstance as IPluginWebService).registerWebServices === + "function" && + typeof (pluginInstance as IPluginWebService).getOrCreateWebServices === "function" && typeof (pluginInstance as IPluginWebService).getHttpServer === "function" && typeof (pluginInstance as IPluginWebService).getPackageName === diff --git a/packages/cactus-plugin-consortium-manual/src/main/typescript/plugin-consortium-manual.ts b/packages/cactus-plugin-consortium-manual/src/main/typescript/plugin-consortium-manual.ts index 1caf6097fc..0b245a3bc4 100644 --- a/packages/cactus-plugin-consortium-manual/src/main/typescript/plugin-consortium-manual.ts +++ b/packages/cactus-plugin-consortium-manual/src/main/typescript/plugin-consortium-manual.ts @@ -50,6 +50,7 @@ export class PluginConsortiumManual public prometheusExporter: PrometheusExporter; private readonly log: Logger; private readonly instanceId: string; + private endpoints: IWebServiceEndpoint[] | undefined; private httpServer: Server | SecureServer | null = null; constructor(public readonly options: IPluginConsortiumManualOptions) { @@ -126,16 +127,11 @@ export class PluginConsortiumManual } } - public async installWebServices( - expressApp: Express, + public async registerWebServices( + app: Express, ): Promise { - const { log } = this; - - log.info(`Installing web services for plugin ${this.getPackageName()}...`); - const webApp: Express = this.options.webAppOptions ? express() : expressApp; + const webApp: Express = this.options.webAppOptions ? express() : app; - // presence of webAppOptions implies that caller wants the plugin to configure it's own express instance on a custom - // host/port to listen on if (this.options.webAppOptions) { this.log.info(`Creating dedicated HTTP server...`); const { port, hostname } = this.options.webAppOptions; @@ -157,6 +153,22 @@ export class PluginConsortiumManual this.log.info(`Creation of HTTP server OK`, { address }); } + const webServices = await this.getOrCreateWebServices(); + webServices.forEach((ws) => ws.registerExpress(webApp)); + return webServices; + } + + public async getOrCreateWebServices(): Promise { + const { log } = this; + const pkgName = this.getPackageName(); + + if (this.endpoints) { + return this.endpoints; + } + log.info(`Creating web services for plugin ${pkgName}...`); + // presence of webAppOptions implies that caller wants the plugin to configure it's own express instance on a custom + // host/port to listen on + const { consortiumDatabase, keyPairPem } = this.options; const consortiumRepo = new ConsortiumRepository({ db: consortiumDatabase, @@ -166,18 +178,16 @@ export class PluginConsortiumManual { const options = { keyPairPem, consortiumRepo }; const endpoint = new GetConsortiumEndpointV1(options); - const path = endpoint.getPath(); - webApp.get(path, endpoint.getExpressRequestHandler()); endpoints.push(endpoint); - this.log.info(`Registered GetConsortiumEndpointV1 at ${path}`); + const path = endpoint.getPath(); + this.log.info(`Instantiated GetConsortiumEndpointV1 at ${path}`); } { const options = { keyPairPem, consortiumRepo, plugin: this }; const endpoint = new GetNodeJwsEndpoint(options); const path = endpoint.getPath(); - webApp.get(path, endpoint.getExpressRequestHandler()); endpoints.push(endpoint); - this.log.info(`Registered GetNodeJwsEndpoint at ${path}`); + this.log.info(`Instantiated GetNodeJwsEndpoint at ${path}`); } { const opts: IGetPrometheusExporterMetricsEndpointV1Options = { @@ -185,13 +195,13 @@ export class PluginConsortiumManual logLevel: this.options.logLevel, }; const endpoint = new GetPrometheusExporterMetricsEndpointV1(opts); - endpoint.registerExpress(expressApp); + const path = endpoint.getPath(); endpoints.push(endpoint); + this.log.info(`Instantiated GetNodeJwsEndpoint at ${path}`); } + this.endpoints = endpoints; - log.info(`Installed web svcs for plugin ${this.getPackageName()} OK`, { - endpoints, - }); + log.info(`Instantiated web svcs for plugin ${pkgName} OK`, { endpoints }); return endpoints; } diff --git a/packages/cactus-plugin-consortium-manual/src/test/typescript/unit/consortium/get-node-jws-endpoint-v1.test.ts b/packages/cactus-plugin-consortium-manual/src/test/typescript/unit/consortium/get-node-jws-endpoint-v1.test.ts index 280c5a6dd7..9b2423b7d5 100644 --- a/packages/cactus-plugin-consortium-manual/src/test/typescript/unit/consortium/get-node-jws-endpoint-v1.test.ts +++ b/packages/cactus-plugin-consortium-manual/src/test/typescript/unit/consortium/get-node-jws-endpoint-v1.test.ts @@ -72,7 +72,8 @@ test("Can provide JWS", async (t: Test) => { ); const apiClient = new ConsortiumManualApi({ basePath: apiHost }); - await pluginConsortiumManual.installWebServices(expressApp); + await pluginConsortiumManual.getOrCreateWebServices(); + await pluginConsortiumManual.registerWebServices(expressApp); const epOpts: IGetNodeJwsEndpointOptions = { plugin: pluginConsortiumManual, diff --git a/packages/cactus-plugin-keychain-memory/src/main/typescript/plugin-keychain-memory.ts b/packages/cactus-plugin-keychain-memory/src/main/typescript/plugin-keychain-memory.ts index 9ee54f69be..8749add556 100644 --- a/packages/cactus-plugin-keychain-memory/src/main/typescript/plugin-keychain-memory.ts +++ b/packages/cactus-plugin-keychain-memory/src/main/typescript/plugin-keychain-memory.ts @@ -77,7 +77,7 @@ export class PluginKeychainMemory { return res; } - public async installWebServices( + public async getOrCreateWebServices( expressApp: Express, ): Promise { const { log } = this; diff --git a/packages/cactus-plugin-keychain-memory/src/test/typescript/unit/plugin-keychain-memory.test.ts b/packages/cactus-plugin-keychain-memory/src/test/typescript/unit/plugin-keychain-memory.test.ts index 6f091dfbce..550dbd5922 100644 --- a/packages/cactus-plugin-keychain-memory/src/test/typescript/unit/plugin-keychain-memory.test.ts +++ b/packages/cactus-plugin-keychain-memory/src/test/typescript/unit/plugin-keychain-memory.test.ts @@ -82,7 +82,7 @@ test("PluginKeychainMemory", (t1: Test) => { ); const apiClient = new KeychainMemoryApi({ basePath: apiHost }); - await plugin.installWebServices(expressApp); + await plugin.getOrCreateWebServices(expressApp); t.equal(plugin.getKeychainId(), options.keychainId, "Keychain ID set OK"); t.equal(plugin.getInstanceId(), options.instanceId, "Instance ID set OK"); diff --git a/packages/cactus-plugin-keychain-vault/src/main/typescript/plugin-keychain-vault-remote-adapter.ts b/packages/cactus-plugin-keychain-vault/src/main/typescript/plugin-keychain-vault-remote-adapter.ts index df3dcca627..e864783901 100644 --- a/packages/cactus-plugin-keychain-vault/src/main/typescript/plugin-keychain-vault-remote-adapter.ts +++ b/packages/cactus-plugin-keychain-vault/src/main/typescript/plugin-keychain-vault-remote-adapter.ts @@ -1,6 +1,7 @@ import { Server } from "http"; import { Server as SecureServer } from "https"; +import { Express } from "express"; import { Optional } from "typescript-optional"; import { @@ -79,10 +80,15 @@ export class PluginKeychainVaultRemoteAdapter * * @param _expressApp */ - public async installWebServices(): Promise { + public async getOrCreateWebServices(): Promise { return []; } + /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ + public registerWebServices(app: Express): Promise { + return this.getOrCreateWebServices(); + } + public getHttpServer(): Optional { return Optional.empty(); } diff --git a/packages/cactus-plugin-keychain-vault/src/main/typescript/plugin-keychain-vault.ts b/packages/cactus-plugin-keychain-vault/src/main/typescript/plugin-keychain-vault.ts index 20c1e1d63c..ec4ebaf695 100644 --- a/packages/cactus-plugin-keychain-vault/src/main/typescript/plugin-keychain-vault.ts +++ b/packages/cactus-plugin-keychain-vault/src/main/typescript/plugin-keychain-vault.ts @@ -73,6 +73,7 @@ export class PluginKeychainVault implements ICactusPlugin, IPluginWebService { private readonly instanceId: string; private readonly kvSecretsMountPath: string; private readonly backend: Vault.client; + private endpoints: IWebServiceEndpoint[] | undefined; public prometheusExporter: PrometheusExporter; public get className() { @@ -131,9 +132,16 @@ export class PluginKeychainVault implements ICactusPlugin, IPluginWebService { return res; } - public async installWebServices( - expressApp: Express, - ): Promise { + async registerWebServices(app: Express): Promise { + const webServices = await this.getOrCreateWebServices(); + webServices.forEach((ws) => ws.registerExpress(app)); + return webServices; + } + + public async getOrCreateWebServices(): Promise { + if (Array.isArray(this.endpoints)) { + return this.endpoints; + } const endpoints: IWebServiceEndpoint[] = []; // TODO: Writing the getExpressRequestHandler() method for @@ -159,10 +167,11 @@ export class PluginKeychainVault implements ICactusPlugin, IPluginWebService { logLevel: this.opts.logLevel, }; const ep = new GetPrometheusExporterMetricsEndpointV1(opts); - ep.registerExpress(expressApp); endpoints.push(ep); } + this.endpoints = endpoints; + return endpoints; } diff --git a/packages/cactus-plugin-keychain-vault/src/test/typescript/integration/plugin-keychain-vault.test.ts b/packages/cactus-plugin-keychain-vault/src/test/typescript/integration/plugin-keychain-vault.test.ts index 402a0d2d64..32bc4186b7 100644 --- a/packages/cactus-plugin-keychain-vault/src/test/typescript/integration/plugin-keychain-vault.test.ts +++ b/packages/cactus-plugin-keychain-vault/src/test/typescript/integration/plugin-keychain-vault.test.ts @@ -77,7 +77,8 @@ test("get,set,has,delete alters state as expected", async (t: Test) => { ); const apiClient = new KeychainVaultApi({ basePath: apiHost }); - await plugin.installWebServices(expressApp); + await plugin.getOrCreateWebServices(); + await plugin.registerWebServices(expressApp); t.equal(plugin.getKeychainId(), options.keychainId, "Keychain ID set OK"); t.equal(plugin.getInstanceId(), options.instanceId, "Instance ID set OK"); diff --git a/packages/cactus-plugin-ledger-connector-besu/src/main/typescript/plugin-ledger-connector-besu.ts b/packages/cactus-plugin-ledger-connector-besu/src/main/typescript/plugin-ledger-connector-besu.ts index e1ab9bd783..c97a7f93f7 100644 --- a/packages/cactus-plugin-ledger-connector-besu/src/main/typescript/plugin-ledger-connector-besu.ts +++ b/packages/cactus-plugin-ledger-connector-besu/src/main/typescript/plugin-ledger-connector-besu.ts @@ -97,6 +97,7 @@ export class PluginLedgerConnectorBesu [name: string]: Contract; } = {}; + private endpoints: IWebServiceEndpoint[] | undefined; private httpServer: Server | SecureServer | null = null; private contractsPath?: string; public static readonly CLASS_NAME = "PluginLedgerConnectorBesu"; @@ -160,16 +161,23 @@ export class PluginLedgerConnectorBesu } } - public async installWebServices( - expressApp: Express, - ): Promise { + async registerWebServices(app: Express): Promise { + const webServices = await this.getOrCreateWebServices(); + webServices.forEach((ws) => ws.registerExpress(app)); + return webServices; + } + + public async getOrCreateWebServices(): Promise { + if (Array.isArray(this.endpoints)) { + return this.endpoints; + } + const endpoints: IWebServiceEndpoint[] = []; { const endpoint = new DeployContractSolidityBytecodeEndpoint({ connector: this, logLevel: this.options.logLevel, }); - endpoint.registerExpress(expressApp); endpoints.push(endpoint); } { @@ -177,7 +185,6 @@ export class PluginLedgerConnectorBesu connector: this, logLevel: this.options.logLevel, }); - endpoint.registerExpress(expressApp); endpoints.push(endpoint); } { @@ -185,7 +192,6 @@ export class PluginLedgerConnectorBesu connector: this, logLevel: this.options.logLevel, }); - endpoint.registerExpress(expressApp); endpoints.push(endpoint); } { @@ -193,7 +199,6 @@ export class PluginLedgerConnectorBesu connector: this, logLevel: this.options.logLevel, }); - endpoint.registerExpress(expressApp); endpoints.push(endpoint); } { @@ -201,7 +206,6 @@ export class PluginLedgerConnectorBesu connector: this, logLevel: this.options.logLevel, }); - endpoint.registerExpress(expressApp); endpoints.push(endpoint); } { @@ -210,9 +214,9 @@ export class PluginLedgerConnectorBesu logLevel: this.options.logLevel, }; const endpoint = new GetPrometheusExporterMetricsEndpointV1(opts); - endpoint.registerExpress(expressApp); endpoints.push(endpoint); } + this.endpoints = endpoints; return endpoints; } diff --git a/packages/cactus-plugin-ledger-connector-besu/src/test/typescript/integration/plugin-ledger-connector-besu/deploy-contract/deploy-contract-from-json.test.ts b/packages/cactus-plugin-ledger-connector-besu/src/test/typescript/integration/plugin-ledger-connector-besu/deploy-contract/deploy-contract-from-json.test.ts index 3277afb6bb..9159f8ce22 100644 --- a/packages/cactus-plugin-ledger-connector-besu/src/test/typescript/integration/plugin-ledger-connector-besu/deploy-contract/deploy-contract-from-json.test.ts +++ b/packages/cactus-plugin-ledger-connector-besu/src/test/typescript/integration/plugin-ledger-connector-besu/deploy-contract/deploy-contract-from-json.test.ts @@ -102,7 +102,8 @@ test(testCase, async (t: Test) => { ); const apiClient = new BesuApi({ basePath: apiHost }); - await connector.installWebServices(expressApp); + await connector.getOrCreateWebServices(); + await connector.registerWebServices(expressApp); await connector.transact({ web3SigningCredential: { diff --git a/packages/cactus-plugin-ledger-connector-corda/src/main/typescript/plugin-ledger-connector-corda.ts b/packages/cactus-plugin-ledger-connector-corda/src/main/typescript/plugin-ledger-connector-corda.ts index 4378a93be9..8152ff8ff1 100644 --- a/packages/cactus-plugin-ledger-connector-corda/src/main/typescript/plugin-ledger-connector-corda.ts +++ b/packages/cactus-plugin-ledger-connector-corda/src/main/typescript/plugin-ledger-connector-corda.ts @@ -39,6 +39,8 @@ export class PluginLedgerConnectorCorda private readonly instanceId: string; private readonly log: Logger; + private endpoints: IWebServiceEndpoint[] | undefined; + public get className(): string { return DeployContractJarsEndpoint.CLASS_NAME; } @@ -84,10 +86,18 @@ export class PluginLedgerConnectorCorda throw new Error("Method not implemented."); } - public async installWebServices( - expressApp: Express, - ): Promise { - this.log.info(`Installing web services for ${this.getPackageName()}...`); + async registerWebServices(app: Express): Promise { + const webServices = await this.getOrCreateWebServices(); + webServices.forEach((ws) => ws.registerExpress(app)); + return webServices; + } + + public async getOrCreateWebServices(): Promise { + if (Array.isArray(this.endpoints)) { + return this.endpoints; + } + const pkgName = this.getPackageName(); + this.log.info(`Instantiating web services for ${pkgName}...`); const endpoints: IWebServiceEndpoint[] = []; { const endpoint = new DeployContractJarsEndpoint({ @@ -98,12 +108,9 @@ export class PluginLedgerConnectorCorda cordaStopCmd: this.options.cordaStopCmd, }); - endpoint.registerExpress(expressApp); - endpoints.push(endpoint); - - this.log.info(`Registered endpoint at ${endpoint.getPath()}`); } + this.log.info(`Instantiated endpoints of ${pkgName}`); return endpoints; } diff --git a/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/plugin-ledger-connector-fabric.ts b/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/plugin-ledger-connector-fabric.ts index c3c0f9cf00..6717392947 100644 --- a/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/plugin-ledger-connector-fabric.ts +++ b/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/plugin-ledger-connector-fabric.ts @@ -113,6 +113,7 @@ export class PluginLedgerConnectorFabric private readonly dockerBinary: string; private readonly cliContainerGoPath: string; public prometheusExporter: PrometheusExporter; + private endpoints: IWebServiceEndpoint[] | undefined; public get className(): string { return PluginLedgerConnectorFabric.CLASS_NAME; @@ -387,9 +388,17 @@ export class PluginLedgerConnectorFabric } } - public async installWebServices( - expressApp: Express, - ): Promise { + async registerWebServices(app: Express): Promise { + const webServices = await this.getOrCreateWebServices(); + webServices.forEach((ws) => ws.registerExpress(app)); + return webServices; + } + + public async getOrCreateWebServices(): Promise { + if (Array.isArray(this.endpoints)) { + return this.endpoints; + } + const { log } = this; log.info(`Installing web services for plugin ${this.getPackageName()}...`); @@ -402,7 +411,6 @@ export class PluginLedgerConnectorFabric logLevel: this.opts.logLevel, }; const endpoint = new DeployContractGoSourceEndpointV1(opts); - endpoint.registerExpress(expressApp); endpoints.push(endpoint); } @@ -412,7 +420,6 @@ export class PluginLedgerConnectorFabric logLevel: this.opts.logLevel, }; const endpoint = new RunTransactionEndpointV1(opts); - endpoint.registerExpress(expressApp); endpoints.push(endpoint); } @@ -422,7 +429,6 @@ export class PluginLedgerConnectorFabric logLevel: this.opts.logLevel, }; const endpoint = new GetPrometheusExporterMetricsEndpointV1(opts); - endpoint.registerExpress(expressApp); endpoints.push(endpoint); } diff --git a/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/deploy-contract-go-bin-endpoint-v1/deploy-contract/deploy-cc-from-golang-source.test.ts b/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/deploy-contract-go-bin-endpoint-v1/deploy-contract/deploy-cc-from-golang-source.test.ts index ccd3d734b0..88613bcb0f 100644 --- a/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/deploy-contract-go-bin-endpoint-v1/deploy-contract/deploy-cc-from-golang-source.test.ts +++ b/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/deploy-contract-go-bin-endpoint-v1/deploy-contract/deploy-cc-from-golang-source.test.ts @@ -147,7 +147,8 @@ test(testCase, async (t: Test) => { const { port } = addressInfo; test.onFinish(async () => await Servers.shutdown(server)); - await plugin.installWebServices(expressApp); + await plugin.getOrCreateWebServices(); + await plugin.registerWebServices(expressApp); const apiUrl = `http://localhost:${port}`; const apiClient = new FabricApi({ basePath: apiUrl }); diff --git a/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v1-4-x/run-transaction-endpoint-v1.test.ts b/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v1-4-x/run-transaction-endpoint-v1.test.ts index 2d1441798c..199f2282a3 100644 --- a/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v1-4-x/run-transaction-endpoint-v1.test.ts +++ b/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v1-4-x/run-transaction-endpoint-v1.test.ts @@ -132,7 +132,8 @@ test(testCase, async (t: Test) => { ); const apiClient = new FabricApi({ basePath: apiHost }); - await plugin.installWebServices(expressApp); + await plugin.getOrCreateWebServices(); + await plugin.registerWebServices(expressApp); const carId = "CAR277"; const carOwner = uuidv4(); diff --git a/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v2-2-x/run-transaction-endpoint-v1.test.ts b/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v2-2-x/run-transaction-endpoint-v1.test.ts index 639b811d36..3fc6374ae1 100644 --- a/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v2-2-x/run-transaction-endpoint-v1.test.ts +++ b/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v2-2-x/run-transaction-endpoint-v1.test.ts @@ -136,7 +136,8 @@ test(testCase, async (t: Test) => { ); const apiClient = new FabricApi({ basePath: apiHost }); - await plugin.installWebServices(expressApp); + await plugin.getOrCreateWebServices(); + await plugin.registerWebServices(expressApp); const assetId = "asset277"; const assetOwner = uuidv4(); diff --git a/packages/cactus-plugin-ledger-connector-quorum/src/main/typescript/plugin-ledger-connector-quorum.ts b/packages/cactus-plugin-ledger-connector-quorum/src/main/typescript/plugin-ledger-connector-quorum.ts index 87fd4841d4..7a2594c2dd 100644 --- a/packages/cactus-plugin-ledger-connector-quorum/src/main/typescript/plugin-ledger-connector-quorum.ts +++ b/packages/cactus-plugin-ledger-connector-quorum/src/main/typescript/plugin-ledger-connector-quorum.ts @@ -89,6 +89,7 @@ export class PluginLedgerConnectorQuorum [name: string]: Contract; } = {}; + private endpoints: IWebServiceEndpoint[] | undefined; public static readonly CLASS_NAME = "PluginLedgerConnectorQuorum"; public get className(): string { @@ -151,16 +152,22 @@ export class PluginLedgerConnectorQuorum } } - public async installWebServices( - expressApp: Express, - ): Promise { + async registerWebServices(app: Express): Promise { + const webServices = await this.getOrCreateWebServices(); + webServices.forEach((ws) => ws.registerExpress(app)); + return webServices; + } + + public async getOrCreateWebServices(): Promise { + if (Array.isArray(this.endpoints)) { + return this.endpoints; + } const endpoints: IWebServiceEndpoint[] = []; { const endpoint = new DeployContractSolidityBytecodeEndpoint({ connector: this, logLevel: this.options.logLevel, }); - endpoint.registerExpress(expressApp); endpoints.push(endpoint); } { @@ -168,7 +175,6 @@ export class PluginLedgerConnectorQuorum connector: this, logLevel: this.options.logLevel, }); - endpoint.registerExpress(expressApp); endpoints.push(endpoint); } { @@ -176,7 +182,6 @@ export class PluginLedgerConnectorQuorum connector: this, logLevel: this.options.logLevel, }); - endpoint.registerExpress(expressApp); endpoints.push(endpoint); } { @@ -184,7 +189,6 @@ export class PluginLedgerConnectorQuorum connector: this, logLevel: this.options.logLevel, }); - endpoint.registerExpress(expressApp); endpoints.push(endpoint); } { @@ -193,9 +197,9 @@ export class PluginLedgerConnectorQuorum logLevel: this.options.logLevel, }; const endpoint = new GetPrometheusExporterMetricsEndpointV1(opts); - endpoint.registerExpress(expressApp); endpoints.push(endpoint); } + this.endpoints = endpoints; return endpoints; } diff --git a/packages/cactus-plugin-ledger-connector-quorum/src/test/typescript/integration/plugin-ledger-connector-quorum/deploy-contract/deploy-contract-from-json.test.ts b/packages/cactus-plugin-ledger-connector-quorum/src/test/typescript/integration/plugin-ledger-connector-quorum/deploy-contract/deploy-contract-from-json.test.ts index af9728d48c..68c25c9443 100644 --- a/packages/cactus-plugin-ledger-connector-quorum/src/test/typescript/integration/plugin-ledger-connector-quorum/deploy-contract/deploy-contract-from-json.test.ts +++ b/packages/cactus-plugin-ledger-connector-quorum/src/test/typescript/integration/plugin-ledger-connector-quorum/deploy-contract/deploy-contract-from-json.test.ts @@ -110,7 +110,8 @@ test(testCase, async (t: Test) => { ); const apiClient = new QuorumApi({ basePath: apiHost }); - await connector.installWebServices(expressApp); + await connector.getOrCreateWebServices(); + await connector.registerWebServices(expressApp); await connector.transact({ web3SigningCredential: {