From 437cf5fc0e488b4dae343eee94eaeb778d3040ad Mon Sep 17 00:00:00 2001 From: Peter Somogyvari Date: Tue, 31 Aug 2021 07:55:23 -0700 Subject: [PATCH] feat(consortium-indy): support consortium database indy backend #675 WORK IN PROGRESS Fixes #675 Signed-off-by: Peter Somogyvari --- .../cactus-plugin-consortium-indy/.gitignore | 2 + .../cactus-plugin-consortium-indy/README.md | 19 + .../openapitools.json | 7 + .../package.json | 92 +++++ .../src/main/json/openapi.json | 173 ++++++++++ .../get-consortium-jws-endpoint-v1.ts | 117 +++++++ .../consortium/get-node-jws-endpoint-v1.ts | 115 ++++++ ...prometheus-exporter-metrics-endpoint-v1.ts | 95 +++++ .../openapi/typescript-axios/.gitignore | 4 + .../.openapi-generator-ignore | 26 ++ .../typescript-axios/.openapi-generator/FILES | 6 + .../.openapi-generator/VERSION | 1 + .../generated/openapi/typescript-axios/api.ts | 326 ++++++++++++++++++ .../openapi/typescript-axios/base.ts | 71 ++++ .../openapi/typescript-axios/common.ts | 138 ++++++++ .../openapi/typescript-axios/configuration.ts | 101 ++++++ .../openapi/typescript-axios/index.ts | 18 + .../src/main/typescript/index.ts | 1 + .../src/main/typescript/index.web.ts | 1 + .../main/typescript/plugin-consortium-indy.ts | 283 +++++++++++++++ .../plugin-factory-consortium-indy.ts | 20 ++ .../prometheus-exporter/data-fetcher.ts | 12 + .../typescript/prometheus-exporter/metrics.ts | 11 + .../prometheus-exporter.ts | 43 +++ .../prometheus-exporter/response.type.ts | 3 + .../src/main/typescript/public-api.ts | 28 ++ .../integration/api-surface.test.ts | 8 + .../test/typescript/unit/api-surface.test.ts | 8 + .../get-node-jws-endpoint-v1.test.ts | 165 +++++++++ .../tsconfig.json | 25 ++ 30 files changed, 1919 insertions(+) create mode 100644 packages/cactus-plugin-consortium-indy/.gitignore create mode 100644 packages/cactus-plugin-consortium-indy/README.md create mode 100644 packages/cactus-plugin-consortium-indy/openapitools.json create mode 100644 packages/cactus-plugin-consortium-indy/package.json create mode 100644 packages/cactus-plugin-consortium-indy/src/main/json/openapi.json create mode 100644 packages/cactus-plugin-consortium-indy/src/main/typescript/consortium/get-consortium-jws-endpoint-v1.ts create mode 100644 packages/cactus-plugin-consortium-indy/src/main/typescript/consortium/get-node-jws-endpoint-v1.ts create mode 100644 packages/cactus-plugin-consortium-indy/src/main/typescript/consortium/get-prometheus-exporter-metrics-endpoint-v1.ts create mode 100644 packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/.gitignore create mode 100644 packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator-ignore create mode 100644 packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator/FILES create mode 100644 packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator/VERSION create mode 100644 packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/api.ts create mode 100644 packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/base.ts create mode 100644 packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/common.ts create mode 100644 packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/configuration.ts create mode 100644 packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/index.ts create mode 100755 packages/cactus-plugin-consortium-indy/src/main/typescript/index.ts create mode 100755 packages/cactus-plugin-consortium-indy/src/main/typescript/index.web.ts create mode 100644 packages/cactus-plugin-consortium-indy/src/main/typescript/plugin-consortium-indy.ts create mode 100644 packages/cactus-plugin-consortium-indy/src/main/typescript/plugin-factory-consortium-indy.ts create mode 100644 packages/cactus-plugin-consortium-indy/src/main/typescript/prometheus-exporter/data-fetcher.ts create mode 100644 packages/cactus-plugin-consortium-indy/src/main/typescript/prometheus-exporter/metrics.ts create mode 100644 packages/cactus-plugin-consortium-indy/src/main/typescript/prometheus-exporter/prometheus-exporter.ts create mode 100644 packages/cactus-plugin-consortium-indy/src/main/typescript/prometheus-exporter/response.type.ts create mode 100755 packages/cactus-plugin-consortium-indy/src/main/typescript/public-api.ts create mode 100644 packages/cactus-plugin-consortium-indy/src/test/typescript/integration/api-surface.test.ts create mode 100644 packages/cactus-plugin-consortium-indy/src/test/typescript/unit/api-surface.test.ts create mode 100644 packages/cactus-plugin-consortium-indy/src/test/typescript/unit/consortium/get-node-jws-endpoint-v1.test.ts create mode 100644 packages/cactus-plugin-consortium-indy/tsconfig.json diff --git a/packages/cactus-plugin-consortium-indy/.gitignore b/packages/cactus-plugin-consortium-indy/.gitignore new file mode 100644 index 0000000000..8daeeed434 --- /dev/null +++ b/packages/cactus-plugin-consortium-indy/.gitignore @@ -0,0 +1,2 @@ +cactus-openapi-spec-plugin-consortium-indy.json +src/main/typescript/generated/openapi/typescript-axios/.npmignore \ No newline at end of file diff --git a/packages/cactus-plugin-consortium-indy/README.md b/packages/cactus-plugin-consortium-indy/README.md new file mode 100644 index 0000000000..abf2e03f48 --- /dev/null +++ b/packages/cactus-plugin-consortium-indy/README.md @@ -0,0 +1,19 @@ +# `@hyperledger/cactus-plugin-consortium-indy` + +TODO + +Items: + +1. Create an Indy all-in-one test ledger, similar to all the other test ledgers that are located under packages/cactus-test-tooling/src/main/typescript which are classes that are pulling up containers which are mostly defined in the Dockerfiles under `tools/docker/*all-in-one` +2. Then select an Indy client library (Javascript/Typescript based, one that has Typescript types is preferred but not mandatory) +3. Create a test case where the pristine Indy ledger gets pulled up, +4. Populate Indy ledger with some test data that defines a dummy consortium +5. Instantiate the consortium plugin within the test case with the connection details of the Indy ledger +6. Instantiate an API client of the consortium plugin (packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios => `DefaultApi` class) +7. Use API client to invoke `getNodeJws()` and `getConsortiumJws()` methods of the plugin via HTTP +8. Assert that the data has been retrieved successfully. +9. Test case passed. +10. Open Pull request. + + +A good example of a containerized ledger is in this Dockerfile: tools/docker/iroha-all-in-one/Dockerfile \ No newline at end of file diff --git a/packages/cactus-plugin-consortium-indy/openapitools.json b/packages/cactus-plugin-consortium-indy/openapitools.json new file mode 100644 index 0000000000..d2fdbae832 --- /dev/null +++ b/packages/cactus-plugin-consortium-indy/openapitools.json @@ -0,0 +1,7 @@ +{ + "$schema": "node_modules/@openapitools/openapi-generator-cli/config.schema.json", + "spaces": 2, + "generator-cli": { + "version": "5.1.1" + } +} diff --git a/packages/cactus-plugin-consortium-indy/package.json b/packages/cactus-plugin-consortium-indy/package.json new file mode 100644 index 0000000000..9d1d5db018 --- /dev/null +++ b/packages/cactus-plugin-consortium-indy/package.json @@ -0,0 +1,92 @@ +{ + "name": "@hyperledger/cactus-plugin-consortium-indy", + "version": "0.8.0", + "description": "A web service plugin that provides management capabilities on a Cactus consortium as a whole for administrative purposes.", + "main": "dist/lib/main/typescript/index.js", + "mainMinified": "dist/cactus-plugin-consortium-indy.node.umd.min.js", + "browser": "dist/cactus-plugin-consortium-indy.web.umd.js", + "browserMinified": "dist/cactus-plugin-consortium-indy.web.umd.min.js", + "module": "dist/lib/main/typescript/index.js", + "types": "dist/lib/main/typescript/index.d.ts", + "files": [ + "dist/*" + ], + "scripts": { + "generate-sdk": "openapi-generator-cli generate -i ./src/main/json/openapi.json -g typescript-axios -o ./src/main/typescript/generated/openapi/typescript-axios/ --reserved-words-mappings protected=protected", + "codegen:openapi": "npm run generate-sdk", + "codegen": "run-p 'codegen:*'", + "watch": "npm-watch", + "webpack": "npm-run-all webpack:dev webpack:prod", + "webpack:dev": "npm-run-all webpack:dev:node webpack:dev:web", + "webpack:dev:web": "webpack --env=dev --target=web --config ../../webpack.config.js", + "webpack:dev:node": "webpack --env=dev --target=node --config ../../webpack.config.js", + "webpack:prod": "npm-run-all webpack:prod:node webpack:prod:web", + "webpack:prod:web": "webpack --env=prod --target=web --config ../../webpack.config.js", + "webpack:prod:node": "webpack --env=prod --target=node --config ../../webpack.config.js" + }, + "watch": { + "codegen:openapi": { + "patterns": [ + "./src/main/json/openapi.json" + ] + } + }, + "publishConfig": { + "access": "public" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/hyperledger/cactus.git" + }, + "keywords": [ + "Hyperledger", + "Cactus", + "Integration", + "Blockchain", + "Distributed Ledger Technology" + ], + "author": { + "name": "Hyperledger Cactus Contributors", + "email": "cactus@lists.hyperledger.org", + "url": "https://www.hyperledger.org/use/cactus" + }, + "contributors": [ + { + "name": "Please add yourself to the list of contributors", + "email": "your.name@example.com", + "url": "https://example.com" + }, + { + "name": "Peter Somogyvari", + "email": "peter.somogyvari@accenture.com", + "url": "https://accenture.com" + } + ], + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/hyperledger/cactus/issues" + }, + "homepage": "https://github.com/hyperledger/cactus#readme", + "dependencies": { + "@hyperledger/cactus-common": "0.8.0", + "@hyperledger/cactus-core": "0.8.0", + "@hyperledger/cactus-core-api": "0.8.0", + "axios": "0.21.1", + "body-parser": "1.19.0", + "express": "4.17.1", + "jose": "1.28.1", + "json-stable-stringify": "1.0.1", + "prom-client": "13.2.0", + "typescript-optional": "2.0.1", + "uuid": "8.3.2" + }, + "devDependencies": { + "@types/express": "4.17.13", + "@types/json-stable-stringify": "1.0.33", + "@types/uuid": "8.3.1" + } +} diff --git a/packages/cactus-plugin-consortium-indy/src/main/json/openapi.json b/packages/cactus-plugin-consortium-indy/src/main/json/openapi.json new file mode 100644 index 0000000000..46e741cf79 --- /dev/null +++ b/packages/cactus-plugin-consortium-indy/src/main/json/openapi.json @@ -0,0 +1,173 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "Hyperledger Cactus Plugin - Consortium Web Service", + "description": "Manage a Cactus consortium through the APIs. Needs administrative privileges.", + "version": "0.0.1", + "license": { + "name": "Apache 2.0", + "url": "https://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "servers": [ + { + "url": "https://www.cactus.stream/{basePath}", + "description": "Public test instance", + "variables": { + "basePath": { + "default": "" + } + } + }, + { + "url": "http://localhost:4000/{basePath}", + "description": "Local test instance", + "variables": { + "basePath": { + "default": "" + } + } + } + ], + "components": { + "schemas": { + "GetNodeJwsResponse": { + "type": "object", + "required": [ + "jws" + ], + "properties": { + "jws": { + "description": "The JSON Web Signature of the Cactus node.", + "$ref": "../../../../cactus-core-api/src/main/json/openapi.json#/components/schemas/JWSGeneral", + "nullable": false + } + } + }, + "GetConsortiumJwsResponse": { + "type": "object", + "required": [ + "jws" + ], + "properties": { + "jws": { + "description": "The JSON Web Signature of the Cactus consortium.", + "$ref": "../../../../cactus-core-api/src/main/json/openapi.json#/components/schemas/JWSGeneral", + "nullable": false, + "format": "The general format which is a JSON object, not a string." + } + } + }, + "PrometheusExporterMetricsResponse": { + "type": "string", + "nullable": false + }, + "GetNodeJwsRequest": { + "type": "object", + "properties": { + } + }, + "GetConsortiumJwsRequest": { + "type": "object", + "properties": { + } + } + } + }, + "paths": { + "/api/v1/plugins/@hyperledger/cactus-plugin-consortium-indy/consortium/jws": { + "post": { + "x-hyperledger-cactus": { + "http": { + "verbLowerCase": "post", + "path": "/api/v1/plugins/@hyperledger/cactus-plugin-consortium-indy/consortium/jws" + } + }, + "operationId": "getConsortiumJwsV1", + "summary": "Retrieves a consortium JWS", + "description": "The JWS asserting the consortium metadata (pub keys and hosts of nodes)", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetConsortiumJwsRequest" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetConsortiumJwsResponse" + } + } + } + } + } + } + }, + "/api/v1/plugins/@hyperledger/cactus-plugin-consortium-indy/node/jws": { + "post": { + "x-hyperledger-cactus": { + "http": { + "verbLowerCase": "post", + "path": "/api/v1/plugins/@hyperledger/cactus-plugin-consortium-indy/node/jws" + } + }, + "operationId": "getNodeJwsV1", + "summary": "Retrieves the JWT of a Cactus Node", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetNodeJwsRequest" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetNodeJwsResponse" + } + } + } + } + } + } + }, + "/api/v1/plugins/@hyperledger/cactus-plugin-consortium-indy/get-prometheus-exporter-metrics": { + "get": { + "x-hyperledger-cactus": { + "http": { + "verbLowerCase": "get", + "path": "/api/v1/plugins/@hyperledger/cactus-plugin-consortium-indy/get-prometheus-exporter-metrics" + } + }, + "operationId": "getPrometheusMetricsV1", + "summary": "Get the Prometheus Metrics", + "parameters": [], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/PrometheusExporterMetricsResponse" + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/packages/cactus-plugin-consortium-indy/src/main/typescript/consortium/get-consortium-jws-endpoint-v1.ts b/packages/cactus-plugin-consortium-indy/src/main/typescript/consortium/get-consortium-jws-endpoint-v1.ts new file mode 100644 index 0000000000..e7fb33e225 --- /dev/null +++ b/packages/cactus-plugin-consortium-indy/src/main/typescript/consortium/get-consortium-jws-endpoint-v1.ts @@ -0,0 +1,117 @@ +import { Express, Request, Response } from "express"; + +import { + IWebServiceEndpoint, + IExpressRequestHandler, + IEndpointAuthzOptions, +} from "@hyperledger/cactus-core-api"; + +import { GetConsortiumJwsResponse } from "../generated/openapi/typescript-axios"; + +import { + LogLevelDesc, + Logger, + LoggerProvider, + IAsyncProvider, + Checks, +} from "@hyperledger/cactus-common"; + +import { + registerWebServiceEndpoint, + ConsortiumRepository, +} from "@hyperledger/cactus-core"; + +import OAS from "../../json/openapi.json"; +import { PluginConsortiumIndy } from "../plugin-consortium-indy"; + +export interface IGetConsortiumJwsEndpointOptions { + plugin: PluginConsortiumIndy; + keyPairPem: string; + consortiumRepo: ConsortiumRepository; + logLevel?: LogLevelDesc; +} + +export class GetConsortiumEndpointV1 implements IWebServiceEndpoint { + private readonly log: Logger; + private readonly plugin: PluginConsortiumIndy; + + constructor(public readonly options: IGetConsortiumJwsEndpointOptions) { + const fnTag = "GetConsortiumJwsEndpoint#constructor()"; + if (!options) { + throw new Error(`${fnTag} options falsy.`); + } + if (!options.keyPairPem) { + throw new Error(`${fnTag} options.keyPairPem falsy.`); + } + if (!options.consortiumRepo) { + throw new Error(`${fnTag} options.consortium falsy.`); + } + Checks.truthy(options.plugin, `${fnTag} options.plugin`); + Checks.truthy( + options.plugin instanceof PluginConsortiumIndy, + `${fnTag} options.plugin instanceof PluginConsortiumIndy`, + ); + this.plugin = options.plugin; + + const label = "get-consortium-jws-endpoint"; + const level = options.logLevel || "INFO"; + this.log = LoggerProvider.getOrCreate({ label, level }); + } + + getAuthorizationOptionsProvider(): IAsyncProvider { + // TODO: make this an injectable dependency in the constructor + return { + get: async () => ({ + isProtected: true, + requiredRoles: [], + }), + }; + } + + public getExpressRequestHandler(): IExpressRequestHandler { + return this.handleRequest.bind(this); + } + + public getOperationId(): string { + return OAS.paths[ + "/api/v1/plugins/@hyperledger/cactus-plugin-consortium-indy/consortium/jws" + ].post.operationId; + } + + public getPath(): string { + return OAS.paths[ + "/api/v1/plugins/@hyperledger/cactus-plugin-consortium-indy/consortium/jws" + ].post["x-hyperledger-cactus"].http.path; + } + + public getVerbLowerCase(): string { + return OAS.paths[ + "/api/v1/plugins/@hyperledger/cactus-plugin-consortium-indy/consortium/jws" + ].post["x-hyperledger-cactus"].http.verbLowerCase; + } + + public async registerExpress( + expressApp: Express, + ): Promise { + await registerWebServiceEndpoint(expressApp, this); + return this; + } + + async handleRequest(req: Request, res: Response): Promise { + const fnTag = "GetConsortiumJwsEndpointV1#handleRequest()"; + this.log.debug(`POST ${this.getPath()}`); + + try { + const jws = await this.options.plugin.getConsortiumJws(); + + const body: GetConsortiumJwsResponse = { jws }; + res.status(200); + res.json(body); + } catch (ex) { + this.log.error(`${fnTag} failed to serve request`, ex); + res.status(500); + res.statusMessage = ex.message; + res.json({ error: ex.stack }); + } + } +} diff --git a/packages/cactus-plugin-consortium-indy/src/main/typescript/consortium/get-node-jws-endpoint-v1.ts b/packages/cactus-plugin-consortium-indy/src/main/typescript/consortium/get-node-jws-endpoint-v1.ts new file mode 100644 index 0000000000..c92545d991 --- /dev/null +++ b/packages/cactus-plugin-consortium-indy/src/main/typescript/consortium/get-node-jws-endpoint-v1.ts @@ -0,0 +1,115 @@ +import { Express, Request, Response } from "express"; + +import { + IWebServiceEndpoint, + IExpressRequestHandler, + IEndpointAuthzOptions, +} from "@hyperledger/cactus-core-api"; + +import { GetNodeJwsResponse } from "../generated/openapi/typescript-axios"; + +import { + Logger, + LogLevelDesc, + LoggerProvider, + Checks, + IAsyncProvider, +} from "@hyperledger/cactus-common"; + +import { + registerWebServiceEndpoint, + ConsortiumRepository, +} from "@hyperledger/cactus-core"; + +import OAS from "../../json/openapi.json"; +import { PluginConsortiumIndy } from "../plugin-consortium-indy"; + +export interface IGetNodeJwsEndpointOptions { + plugin: PluginConsortiumIndy; + keyPairPem: string; + consortiumRepo: ConsortiumRepository; + logLevel?: LogLevelDesc; +} + +export class GetNodeJwsEndpoint implements IWebServiceEndpoint { + private readonly log: Logger; + private readonly plugin: PluginConsortiumIndy; + + constructor(public readonly options: IGetNodeJwsEndpointOptions) { + const fnTag = "GetNodeJwsEndpoint#constructor()"; + if (!options) { + throw new Error(`${fnTag} options falsy.`); + } + if (!options.keyPairPem) { + throw new Error(`${fnTag} options.keyPairPem falsy.`); + } + Checks.truthy(options.consortiumRepo, `${fnTag} options.consortiumRepo`); + Checks.truthy(options.plugin, `${fnTag} options.plugin`); + Checks.truthy( + options.plugin instanceof PluginConsortiumIndy, + `${fnTag} options.plugin instanceof PluginConsortiumIndy`, + ); + this.plugin = options.plugin; + + const level = options.logLevel || "INFO"; + const label = "get-node-jws-endpoint-v1"; + this.log = LoggerProvider.getOrCreate({ level, label }); + } + + getAuthorizationOptionsProvider(): IAsyncProvider { + // TODO: make this an injectable dependency in the constructor + return { + get: async () => ({ + isProtected: true, + requiredRoles: [], + }), + }; + } + + public getExpressRequestHandler(): IExpressRequestHandler { + return this.handleRequest.bind(this); + } + + public getOasPath() { + return OAS.paths[ + "/api/v1/plugins/@hyperledger/cactus-plugin-consortium-indy/node/jws" + ]; + } + + public getOperationId(): string { + return this.getOasPath().post.operationId; + } + + public getPath(): string { + const oasPath = this.getOasPath(); + return oasPath.post["x-hyperledger-cactus"].http.path; + } + + public getVerbLowerCase(): string { + const oasPath = this.getOasPath(); + return oasPath.post["x-hyperledger-cactus"].http.verbLowerCase; + } + + public async registerExpress( + expressApp: Express, + ): Promise { + await registerWebServiceEndpoint(expressApp, this); + return this; + } + + async handleRequest(req: Request, res: Response): Promise { + const fnTag = "GetNodeJwsEndpoint#createJws()"; + this.log.debug(`GET ${this.getPath()}`); + try { + const jws = await this.options.plugin.getNodeJws(); + const body: GetNodeJwsResponse = { jws }; + res.status(200); + res.json(body); + } catch (ex) { + this.log.error(`${fnTag} failed to serve request`, ex); + res.status(500); + res.statusMessage = ex.message; + res.json({ error: ex.stack }); + } + } +} diff --git a/packages/cactus-plugin-consortium-indy/src/main/typescript/consortium/get-prometheus-exporter-metrics-endpoint-v1.ts b/packages/cactus-plugin-consortium-indy/src/main/typescript/consortium/get-prometheus-exporter-metrics-endpoint-v1.ts new file mode 100644 index 0000000000..5b9065fb64 --- /dev/null +++ b/packages/cactus-plugin-consortium-indy/src/main/typescript/consortium/get-prometheus-exporter-metrics-endpoint-v1.ts @@ -0,0 +1,95 @@ +import { Express, Request, Response } from "express"; + +import { + Logger, + LoggerProvider, + LogLevelDesc, + Checks, + IAsyncProvider, +} from "@hyperledger/cactus-common"; + +import { + IWebServiceEndpoint, + IExpressRequestHandler, + IEndpointAuthzOptions, +} from "@hyperledger/cactus-core-api"; + +import OAS from "../../json/openapi.json"; + +import { registerWebServiceEndpoint } from "@hyperledger/cactus-core"; + +import { PluginConsortiumIndy } from "../plugin-consortium-indy"; + +export interface IGetPrometheusExporterMetricsEndpointV1Options { + logLevel?: LogLevelDesc; + plugin: PluginConsortiumIndy; +} + +export class GetPrometheusExporterMetricsEndpointV1 + implements IWebServiceEndpoint { + private readonly log: Logger; + + constructor( + public readonly opts: IGetPrometheusExporterMetricsEndpointV1Options, + ) { + const fnTag = "GetPrometheusExporterMetricsEndpointV1#constructor()"; + + Checks.truthy(opts, `${fnTag} options`); + Checks.truthy(opts.plugin, `${fnTag} options.plugin`); + + this.log = LoggerProvider.getOrCreate({ + label: "get-prometheus-exporter-metrics-v1", + level: opts.logLevel || "INFO", + }); + } + + getAuthorizationOptionsProvider(): IAsyncProvider { + // TODO: make this an injectable dependency in the constructor + return { + get: async () => ({ + isProtected: true, + requiredRoles: [], + }), + }; + } + + public getExpressRequestHandler(): IExpressRequestHandler { + return this.handleRequest.bind(this); + } + + public getPath(): string { + return OAS.paths[ + "/api/v1/plugins/@hyperledger/cactus-plugin-consortium-indy/get-prometheus-exporter-metrics" + ].get["x-hyperledger-cactus"].http.path; + } + + public getVerbLowerCase(): string { + return OAS.paths[ + "/api/v1/plugins/@hyperledger/cactus-plugin-consortium-indy/get-prometheus-exporter-metrics" + ].get["x-hyperledger-cactus"].http.verbLowerCase; + } + + public async registerExpress( + expressApp: Express, + ): Promise { + await registerWebServiceEndpoint(expressApp, this); + return this; + } + + async handleRequest(req: Request, res: Response): Promise { + const fnTag = "GetPrometheusExporterMetrics#handleRequest()"; + const verbUpper = this.getVerbLowerCase().toUpperCase(); + this.log.debug(`${verbUpper} ${this.getPath()}`); + + try { + const resBody = await this.opts.plugin.getPrometheusExporterMetrics(); + res.status(200); + res.send(resBody); + } catch (ex) { + this.log.error(`${fnTag} failed to serve request`, ex); + res.status(500); + res.statusMessage = ex.message; + res.json({ error: ex.stack }); + } + } +} diff --git a/packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/.gitignore b/packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/.gitignore new file mode 100644 index 0000000000..149b576547 --- /dev/null +++ b/packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/.gitignore @@ -0,0 +1,4 @@ +wwwroot/*.js +node_modules +typings +dist diff --git a/packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator-ignore b/packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator-ignore new file mode 100644 index 0000000000..6a6325b75c --- /dev/null +++ b/packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator-ignore @@ -0,0 +1,26 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md + +git_push.sh +.npmignore diff --git a/packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator/FILES b/packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator/FILES new file mode 100644 index 0000000000..d5e35beea1 --- /dev/null +++ b/packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator/FILES @@ -0,0 +1,6 @@ +.gitignore +api.ts +base.ts +common.ts +configuration.ts +index.ts diff --git a/packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator/VERSION b/packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator/VERSION new file mode 100644 index 0000000000..3bff059174 --- /dev/null +++ b/packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator/VERSION @@ -0,0 +1 @@ +5.1.1 \ No newline at end of file diff --git a/packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/api.ts b/packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/api.ts new file mode 100644 index 0000000000..41b24e0408 --- /dev/null +++ b/packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/api.ts @@ -0,0 +1,326 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Hyperledger Cactus Plugin - Consortium Web Service + * Manage a Cactus consortium through the APIs. Needs administrative privileges. + * + * The version of the OpenAPI document: 0.0.1 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +import { Configuration } from './configuration'; +import globalAxios, { AxiosPromise, AxiosInstance } from 'axios'; +// Some imports not used depending on template conditions +// @ts-ignore +import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObject, setBearerAuthToObject, setOAuthToObject, setSearchParams, serializeDataIfNeeded, toPathString, createRequestFunction } from './common'; +// @ts-ignore +import { BASE_PATH, COLLECTION_FORMATS, RequestArgs, BaseAPI, RequiredError } from './base'; + +/** + * + * @export + * @interface GetConsortiumJwsResponse + */ +export interface GetConsortiumJwsResponse { + /** + * + * @type {JWSGeneral} + * @memberof GetConsortiumJwsResponse + */ + jws: JWSGeneral; +} +/** + * + * @export + * @interface GetNodeJwsResponse + */ +export interface GetNodeJwsResponse { + /** + * + * @type {JWSGeneral} + * @memberof GetNodeJwsResponse + */ + jws: JWSGeneral; +} +/** + * + * @export + * @interface JWSGeneral + */ +export interface JWSGeneral { + /** + * + * @type {string} + * @memberof JWSGeneral + */ + payload: string; + /** + * + * @type {Array} + * @memberof JWSGeneral + */ + signatures: Array; +} +/** + * A JSON Web Signature. See: https://tools.ietf.org/html/rfc7515 for info about standard. + * @export + * @interface JWSRecipient + */ +export interface JWSRecipient { + /** + * + * @type {string} + * @memberof JWSRecipient + */ + signature: string; + /** + * + * @type {string} + * @memberof JWSRecipient + */ + protected?: string; + /** + * + * @type {{ [key: string]: object; }} + * @memberof JWSRecipient + */ + header?: { [key: string]: object; }; +} + +/** + * DefaultApi - axios parameter creator + * @export + */ +export const DefaultApiAxiosParamCreator = function (configuration?: Configuration) { + return { + /** + * The JWS asserting the consortium metadata (pub keys and hosts of nodes) + * @summary Retrieves a consortium JWS + * @param {object} [body] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getConsortiumJwsV1: async (body?: object, options: any = {}): Promise => { + const localVarPath = `/api/v1/plugins/@hyperledger/cactus-plugin-consortium-indy/consortium/jws`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter, options.query); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(body, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @summary Retrieves the JWT of a Cactus Node + * @param {object} [body] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getNodeJwsV1: async (body?: object, options: any = {}): Promise => { + const localVarPath = `/api/v1/plugins/@hyperledger/cactus-plugin-consortium-indy/node/jws`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter, options.query); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(body, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @summary Get the Prometheus Metrics + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getPrometheusMetricsV1: async (options: any = {}): Promise => { + const localVarPath = `/api/v1/plugins/@hyperledger/cactus-plugin-consortium-indy/get-prometheus-exporter-metrics`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + + + setSearchParams(localVarUrlObj, localVarQueryParameter, options.query); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + } +}; + +/** + * DefaultApi - functional programming interface + * @export + */ +export const DefaultApiFp = function(configuration?: Configuration) { + const localVarAxiosParamCreator = DefaultApiAxiosParamCreator(configuration) + return { + /** + * The JWS asserting the consortium metadata (pub keys and hosts of nodes) + * @summary Retrieves a consortium JWS + * @param {object} [body] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getConsortiumJwsV1(body?: object, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getConsortiumJwsV1(body, options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, + /** + * + * @summary Retrieves the JWT of a Cactus Node + * @param {object} [body] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getNodeJwsV1(body?: object, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getNodeJwsV1(body, options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, + /** + * + * @summary Get the Prometheus Metrics + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getPrometheusMetricsV1(options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getPrometheusMetricsV1(options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, + } +}; + +/** + * DefaultApi - factory interface + * @export + */ +export const DefaultApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) { + const localVarFp = DefaultApiFp(configuration) + return { + /** + * The JWS asserting the consortium metadata (pub keys and hosts of nodes) + * @summary Retrieves a consortium JWS + * @param {object} [body] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getConsortiumJwsV1(body?: object, options?: any): AxiosPromise { + return localVarFp.getConsortiumJwsV1(body, options).then((request) => request(axios, basePath)); + }, + /** + * + * @summary Retrieves the JWT of a Cactus Node + * @param {object} [body] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getNodeJwsV1(body?: object, options?: any): AxiosPromise { + return localVarFp.getNodeJwsV1(body, options).then((request) => request(axios, basePath)); + }, + /** + * + * @summary Get the Prometheus Metrics + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getPrometheusMetricsV1(options?: any): AxiosPromise { + return localVarFp.getPrometheusMetricsV1(options).then((request) => request(axios, basePath)); + }, + }; +}; + +/** + * DefaultApi - object-oriented interface + * @export + * @class DefaultApi + * @extends {BaseAPI} + */ +export class DefaultApi extends BaseAPI { + /** + * The JWS asserting the consortium metadata (pub keys and hosts of nodes) + * @summary Retrieves a consortium JWS + * @param {object} [body] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof DefaultApi + */ + public getConsortiumJwsV1(body?: object, options?: any) { + return DefaultApiFp(this.configuration).getConsortiumJwsV1(body, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * + * @summary Retrieves the JWT of a Cactus Node + * @param {object} [body] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof DefaultApi + */ + public getNodeJwsV1(body?: object, options?: any) { + return DefaultApiFp(this.configuration).getNodeJwsV1(body, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * + * @summary Get the Prometheus Metrics + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof DefaultApi + */ + public getPrometheusMetricsV1(options?: any) { + return DefaultApiFp(this.configuration).getPrometheusMetricsV1(options).then((request) => request(this.axios, this.basePath)); + } +} + + diff --git a/packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/base.ts b/packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/base.ts new file mode 100644 index 0000000000..a4e481ed14 --- /dev/null +++ b/packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/base.ts @@ -0,0 +1,71 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Hyperledger Cactus Plugin - Consortium Web Service + * Manage a Cactus consortium through the APIs. Needs administrative privileges. + * + * The version of the OpenAPI document: 0.0.1 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +import { Configuration } from "./configuration"; +// Some imports not used depending on template conditions +// @ts-ignore +import globalAxios, { AxiosPromise, AxiosInstance } from 'axios'; + +export const BASE_PATH = "https://www.cactus.stream".replace(/\/+$/, ""); + +/** + * + * @export + */ +export const COLLECTION_FORMATS = { + csv: ",", + ssv: " ", + tsv: "\t", + pipes: "|", +}; + +/** + * + * @export + * @interface RequestArgs + */ +export interface RequestArgs { + url: string; + options: any; +} + +/** + * + * @export + * @class BaseAPI + */ +export class BaseAPI { + protected configuration: Configuration | undefined; + + constructor(configuration?: Configuration, protected basePath: string = BASE_PATH, protected axios: AxiosInstance = globalAxios) { + if (configuration) { + this.configuration = configuration; + this.basePath = configuration.basePath || this.basePath; + } + } +}; + +/** + * + * @export + * @class RequiredError + * @extends {Error} + */ +export class RequiredError extends Error { + name: "RequiredError" = "RequiredError"; + constructor(public field: string, msg?: string) { + super(msg); + } +} diff --git a/packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/common.ts b/packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/common.ts new file mode 100644 index 0000000000..a44fb71d29 --- /dev/null +++ b/packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/common.ts @@ -0,0 +1,138 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Hyperledger Cactus Plugin - Consortium Web Service + * Manage a Cactus consortium through the APIs. Needs administrative privileges. + * + * The version of the OpenAPI document: 0.0.1 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +import { Configuration } from "./configuration"; +import { RequiredError, RequestArgs } from "./base"; +import { AxiosInstance } from 'axios'; + +/** + * + * @export + */ +export const DUMMY_BASE_URL = 'https://example.com' + +/** + * + * @throws {RequiredError} + * @export + */ +export const assertParamExists = function (functionName: string, paramName: string, paramValue: unknown) { + if (paramValue === null || paramValue === undefined) { + throw new RequiredError(paramName, `Required parameter ${paramName} was null or undefined when calling ${functionName}.`); + } +} + +/** + * + * @export + */ +export const setApiKeyToObject = async function (object: any, keyParamName: string, configuration?: Configuration) { + if (configuration && configuration.apiKey) { + const localVarApiKeyValue = typeof configuration.apiKey === 'function' + ? await configuration.apiKey(keyParamName) + : await configuration.apiKey; + object[keyParamName] = localVarApiKeyValue; + } +} + +/** + * + * @export + */ +export const setBasicAuthToObject = function (object: any, configuration?: Configuration) { + if (configuration && (configuration.username || configuration.password)) { + object["auth"] = { username: configuration.username, password: configuration.password }; + } +} + +/** + * + * @export + */ +export const setBearerAuthToObject = async function (object: any, configuration?: Configuration) { + if (configuration && configuration.accessToken) { + const accessToken = typeof configuration.accessToken === 'function' + ? await configuration.accessToken() + : await configuration.accessToken; + object["Authorization"] = "Bearer " + accessToken; + } +} + +/** + * + * @export + */ +export const setOAuthToObject = async function (object: any, name: string, scopes: string[], configuration?: Configuration) { + if (configuration && configuration.accessToken) { + const localVarAccessTokenValue = typeof configuration.accessToken === 'function' + ? await configuration.accessToken(name, scopes) + : await configuration.accessToken; + object["Authorization"] = "Bearer " + localVarAccessTokenValue; + } +} + +/** + * + * @export + */ +export const setSearchParams = function (url: URL, ...objects: any[]) { + const searchParams = new URLSearchParams(url.search); + for (const object of objects) { + for (const key in object) { + if (Array.isArray(object[key])) { + searchParams.delete(key); + for (const item of object[key]) { + searchParams.append(key, item); + } + } else { + searchParams.set(key, object[key]); + } + } + } + url.search = searchParams.toString(); +} + +/** + * + * @export + */ +export const serializeDataIfNeeded = function (value: any, requestOptions: any, configuration?: Configuration) { + const nonString = typeof value !== 'string'; + const needsSerialization = nonString && configuration && configuration.isJsonMime + ? configuration.isJsonMime(requestOptions.headers['Content-Type']) + : nonString; + return needsSerialization + ? JSON.stringify(value !== undefined ? value : {}) + : (value || ""); +} + +/** + * + * @export + */ +export const toPathString = function (url: URL) { + return url.pathname + url.search + url.hash +} + +/** + * + * @export + */ +export const createRequestFunction = function (axiosArgs: RequestArgs, globalAxios: AxiosInstance, BASE_PATH: string, configuration?: Configuration) { + return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => { + const axiosRequestArgs = {...axiosArgs.options, url: (configuration?.basePath || basePath) + axiosArgs.url}; + return axios.request(axiosRequestArgs); + }; +} diff --git a/packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/configuration.ts b/packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/configuration.ts new file mode 100644 index 0000000000..fc7ebd2565 --- /dev/null +++ b/packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/configuration.ts @@ -0,0 +1,101 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Hyperledger Cactus Plugin - Consortium Web Service + * Manage a Cactus consortium through the APIs. Needs administrative privileges. + * + * The version of the OpenAPI document: 0.0.1 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +export interface ConfigurationParameters { + apiKey?: string | Promise | ((name: string) => string) | ((name: string) => Promise); + username?: string; + password?: string; + accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise); + basePath?: string; + baseOptions?: any; + formDataCtor?: new () => any; +} + +export class Configuration { + /** + * parameter for apiKey security + * @param name security name + * @memberof Configuration + */ + apiKey?: string | Promise | ((name: string) => string) | ((name: string) => Promise); + /** + * parameter for basic security + * + * @type {string} + * @memberof Configuration + */ + username?: string; + /** + * parameter for basic security + * + * @type {string} + * @memberof Configuration + */ + password?: string; + /** + * parameter for oauth2 security + * @param name security name + * @param scopes oauth2 scope + * @memberof Configuration + */ + accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise); + /** + * override base path + * + * @type {string} + * @memberof Configuration + */ + basePath?: string; + /** + * base options for axios calls + * + * @type {any} + * @memberof Configuration + */ + baseOptions?: any; + /** + * The FormData constructor that will be used to create multipart form data + * requests. You can inject this here so that execution environments that + * do not support the FormData class can still run the generated client. + * + * @type {new () => FormData} + */ + formDataCtor?: new () => any; + + constructor(param: ConfigurationParameters = {}) { + this.apiKey = param.apiKey; + this.username = param.username; + this.password = param.password; + this.accessToken = param.accessToken; + this.basePath = param.basePath; + this.baseOptions = param.baseOptions; + this.formDataCtor = param.formDataCtor; + } + + /** + * Check if the given MIME is a JSON MIME. + * JSON MIME examples: + * application/json + * application/json; charset=UTF8 + * APPLICATION/JSON + * application/vnd.company+json + * @param mime - MIME (Multipurpose Internet Mail Extensions) + * @return True if the given MIME is JSON, false otherwise. + */ + public isJsonMime(mime: string): boolean { + const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i'); + return mime !== null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); + } +} diff --git a/packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/index.ts b/packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/index.ts new file mode 100644 index 0000000000..15276d7356 --- /dev/null +++ b/packages/cactus-plugin-consortium-indy/src/main/typescript/generated/openapi/typescript-axios/index.ts @@ -0,0 +1,18 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Hyperledger Cactus Plugin - Consortium Web Service + * Manage a Cactus consortium through the APIs. Needs administrative privileges. + * + * The version of the OpenAPI document: 0.0.1 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +export * from "./api"; +export * from "./configuration"; + diff --git a/packages/cactus-plugin-consortium-indy/src/main/typescript/index.ts b/packages/cactus-plugin-consortium-indy/src/main/typescript/index.ts new file mode 100755 index 0000000000..87cb558397 --- /dev/null +++ b/packages/cactus-plugin-consortium-indy/src/main/typescript/index.ts @@ -0,0 +1 @@ +export * from "./public-api"; diff --git a/packages/cactus-plugin-consortium-indy/src/main/typescript/index.web.ts b/packages/cactus-plugin-consortium-indy/src/main/typescript/index.web.ts new file mode 100755 index 0000000000..bdf54028d2 --- /dev/null +++ b/packages/cactus-plugin-consortium-indy/src/main/typescript/index.web.ts @@ -0,0 +1 @@ +export * from "./generated/openapi/typescript-axios/index"; diff --git a/packages/cactus-plugin-consortium-indy/src/main/typescript/plugin-consortium-indy.ts b/packages/cactus-plugin-consortium-indy/src/main/typescript/plugin-consortium-indy.ts new file mode 100644 index 0000000000..56f0ceacf1 --- /dev/null +++ b/packages/cactus-plugin-consortium-indy/src/main/typescript/plugin-consortium-indy.ts @@ -0,0 +1,283 @@ +import { Server } from "http"; +import { Server as SecureServer } from "https"; +import { Optional } from "typescript-optional"; +import { promisify } from "util"; +import express, { Express } from "express"; +import bodyParser from "body-parser"; +import { JWS, JWK } from "jose"; +import jsonStableStringify from "json-stable-stringify"; +import { v4 as uuidv4 } from "uuid"; + +import { + ConsortiumDatabase, + IPluginWebService, + IWebServiceEndpoint, + ICactusPlugin, + ICactusPluginOptions, + JWSGeneral, + JWSRecipient, +} from "@hyperledger/cactus-core-api"; + +import { PluginRegistry, ConsortiumRepository } from "@hyperledger/cactus-core"; + +import { + Checks, + Logger, + LoggerProvider, + LogLevelDesc, +} from "@hyperledger/cactus-common"; +import { GetConsortiumEndpointV1 } from "./consortium/get-consortium-jws-endpoint-v1"; +import { GetNodeJwsEndpoint } from "./consortium/get-node-jws-endpoint-v1"; + +import { PrometheusExporter } from "./prometheus-exporter/prometheus-exporter"; + +import { + IGetPrometheusExporterMetricsEndpointV1Options, + GetPrometheusExporterMetricsEndpointV1, +} from "./consortium/get-prometheus-exporter-metrics-endpoint-v1"; + +import { + Configuration, + DefaultApi, +} from "./generated/openapi/typescript-axios"; +export interface IWebAppOptions { + port: number; + hostname: string; +} + +export interface IPluginConsortiumIndyOptions extends ICactusPluginOptions { + keyPairPem: string; + // Indy connection details here (TODO) + consortiumDatabase: ConsortiumDatabase; + prometheusExporter?: PrometheusExporter; + pluginRegistry?: PluginRegistry; + logLevel?: LogLevelDesc; + webAppOptions?: IWebAppOptions; +} + +export class PluginConsortiumIndy implements ICactusPlugin, IPluginWebService { + public static readonly CLASS_NAME = "PluginConsortiumIndy"; + public prometheusExporter: PrometheusExporter; + private readonly log: Logger; + private readonly instanceId: string; + private readonly repo: ConsortiumRepository; + private endpoints: IWebServiceEndpoint[] | undefined; + private httpServer: Server | SecureServer | null = null; + + public get className(): string { + return PluginConsortiumIndy.CLASS_NAME; + } + + constructor(public readonly options: IPluginConsortiumIndyOptions) { + const fnTag = `PluginConsortiumIndy#constructor()`; + if (!options) { + throw new Error(`${fnTag} options falsy.`); + } + Checks.truthy(options.instanceId, `${fnTag} options.instanceId`); + Checks.truthy( + options.consortiumDatabase, + `${fnTag} options.consortiumDatabase`, + ); + + this.log = LoggerProvider.getOrCreate({ + label: "plugin-consortium-indy", + }); + + this.instanceId = this.options.instanceId; + this.repo = new ConsortiumRepository({ db: options.consortiumDatabase }); + + this.prometheusExporter = + options.prometheusExporter || + new PrometheusExporter({ pollingIntervalInMin: 1 }); + + Checks.truthy( + this.prometheusExporter, + `${fnTag} options.prometheusExporter`, + ); + this.prometheusExporter.startMetricsCollection(); + this.prometheusExporter.setNodeCount(this.getNodeCount()); + } + + public getInstanceId(): string { + return this.instanceId; + } + + public async onPluginInit(): Promise { + return; + } + + public getPrometheusExporter(): PrometheusExporter { + return this.prometheusExporter; + } + + public async getPrometheusExporterMetrics(): Promise { + const res: string = await this.prometheusExporter.getPrometheusMetrics(); + this.log.debug(`getPrometheusExporterMetrics() response: %o`, res); + return res; + } + + public getNodeCount(): number { + Checks.truthy(this.repo, `${this.className}.this.repo`); + return this.repo.allNodes.length; + } + + /** + * Updates the Node count Prometheus metric of the plugin. + * Note: This does not change the underlying consortium database at all, + * only affects **the metrics**. + */ + public updateMetricNodeCount(): void { + const nodeCount = this.getNodeCount(); + this.prometheusExporter.setNodeCount(nodeCount); + } + + public async shutdown(): Promise { + this.log.info(`Shutting down...`); + const serverMaybe = this.getHttpServer(); + if (serverMaybe.isPresent()) { + this.log.info(`Awaiting server.close() ...`); + const server = serverMaybe.get(); + await promisify(server.close.bind(server))(); + this.log.info(`server.close() OK`); + } else { + this.log.info(`No HTTP server found, skipping...`); + } + } + + public async registerWebServices( + app: Express, + ): Promise { + const webApp: Express = this.options.webAppOptions ? express() : app; + + if (this.options.webAppOptions) { + this.log.info(`Creating dedicated HTTP server...`); + const { port, hostname } = this.options.webAppOptions; + + webApp.use(bodyParser.json({ limit: "50mb" })); + + const address = await new Promise((resolve, reject) => { + const httpServer = webApp.listen(port, hostname, (err?: any) => { + if (err) { + reject(err); + this.log.error(`Failed to create dedicated HTTP server`, err); + } else { + this.httpServer = httpServer; + const theAddress = this.httpServer.address(); + resolve(theAddress); + } + }); + }); + 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 { keyPairPem } = this.options; + const consortiumRepo = this.repo; + + const endpoints: IWebServiceEndpoint[] = []; + { + const options = { keyPairPem, consortiumRepo, plugin: this }; + const endpoint = new GetConsortiumEndpointV1(options); + endpoints.push(endpoint); + 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(); + endpoints.push(endpoint); + this.log.info(`Instantiated GetNodeJwsEndpoint at ${path}`); + } + { + const opts: IGetPrometheusExporterMetricsEndpointV1Options = { + plugin: this, + logLevel: this.options.logLevel, + }; + const endpoint = new GetPrometheusExporterMetricsEndpointV1(opts); + const path = endpoint.getPath(); + endpoints.push(endpoint); + this.log.info(`Instantiated GetNodeJwsEndpoint at ${path}`); + } + this.endpoints = endpoints; + + log.info(`Instantiated web svcs for plugin ${pkgName} OK`, { endpoints }); + return endpoints; + } + + public getHttpServer(): Optional { + return Optional.ofNullable(this.httpServer); + } + + public getPackageName(): string { + return `@hyperledger/cactus-plugin-consortium-indy`; + } + + public async getNodeJws(): Promise { + // here you connect to the indy ledger and obtain + // the consortium database information to substitute + // the data that the manual consortium plugin has + // in it's static configuration (which is what makes it + // "manual") + Checks.truthy(this.repo, `${this.className}.this.repo`); + const { keyPairPem } = this.options; + + this.updateMetricNodeCount(); + const keyPair = JWK.asKey(keyPairPem); + const payloadObject = { consortiumDatabase: this.repo.consortiumDatabase }; + const payloadJson = jsonStableStringify(payloadObject); + const _protected = { + iat: Date.now(), + jti: uuidv4(), + iss: "Hyperledger Cactus", + }; + // TODO: double check if this casting is safe (it is supposed to be) + return JWS.sign.general(payloadJson, keyPair, _protected) as JWSGeneral; + } + + public async getConsortiumJws(): Promise { + // here you connect to the indy ledger and obtain + // the consortium database information to substitute + // the data that the manual consortium plugin has + // in it's static configuration (which is what makes it + // "manual") + const nodes = this.repo.allNodes; + + const requests = nodes + .map((cnm) => cnm.nodeApiHost) + .map((host) => new Configuration({ basePath: host })) + .map((configuration) => new DefaultApi(configuration)) + .map((apiClient) => apiClient.getNodeJwsV1()); + + const responses = await Promise.all(requests); + + const signatures: JWSRecipient[] = []; + + responses + .map((apiResponse) => apiResponse.data) + .map((getNodeJwsResponse) => getNodeJwsResponse.jws) + .forEach((aJws: JWSGeneral) => + aJws.signatures.forEach((signature) => signatures.push(signature)), + ); + + const [response] = responses; + const jws = response.data.jws; + jws.signatures = signatures; + return jws; + } +} diff --git a/packages/cactus-plugin-consortium-indy/src/main/typescript/plugin-factory-consortium-indy.ts b/packages/cactus-plugin-consortium-indy/src/main/typescript/plugin-factory-consortium-indy.ts new file mode 100644 index 0000000000..4a493ede33 --- /dev/null +++ b/packages/cactus-plugin-consortium-indy/src/main/typescript/plugin-factory-consortium-indy.ts @@ -0,0 +1,20 @@ +import { + IPluginFactoryOptions, + PluginFactory, +} from "@hyperledger/cactus-core-api"; +import { + IPluginConsortiumIndyOptions, + PluginConsortiumIndy, +} from "./plugin-consortium-indy"; + +export class PluginFactoryWebService extends PluginFactory< + PluginConsortiumIndy, + IPluginConsortiumIndyOptions, + IPluginFactoryOptions +> { + async create( + pluginOptions: IPluginConsortiumIndyOptions, + ): Promise { + return new PluginConsortiumIndy(pluginOptions); + } +} diff --git a/packages/cactus-plugin-consortium-indy/src/main/typescript/prometheus-exporter/data-fetcher.ts b/packages/cactus-plugin-consortium-indy/src/main/typescript/prometheus-exporter/data-fetcher.ts new file mode 100644 index 0000000000..55869bf1cf --- /dev/null +++ b/packages/cactus-plugin-consortium-indy/src/main/typescript/prometheus-exporter/data-fetcher.ts @@ -0,0 +1,12 @@ +import { NodeCount } from "./response.type"; + +import { + totalTxCount, + K_CACTUS_CONSORTIUM_MANUAL_TOTAL_NODE_COUNT, +} from "./metrics"; + +export async function collectMetrics(nodeCount: NodeCount): Promise { + totalTxCount + .labels(K_CACTUS_CONSORTIUM_MANUAL_TOTAL_NODE_COUNT) + .set(nodeCount.counter); +} diff --git a/packages/cactus-plugin-consortium-indy/src/main/typescript/prometheus-exporter/metrics.ts b/packages/cactus-plugin-consortium-indy/src/main/typescript/prometheus-exporter/metrics.ts new file mode 100644 index 0000000000..b965dd39f4 --- /dev/null +++ b/packages/cactus-plugin-consortium-indy/src/main/typescript/prometheus-exporter/metrics.ts @@ -0,0 +1,11 @@ +import { Gauge } from "prom-client"; + +export const K_CACTUS_CONSORTIUM_MANUAL_TOTAL_NODE_COUNT = + "cactus_consortium_manual_total_node_count"; + +export const totalTxCount = new Gauge({ + registers: [], + name: K_CACTUS_CONSORTIUM_MANUAL_TOTAL_NODE_COUNT, + help: "Total cactus node count", + labelNames: ["type"], +}); diff --git a/packages/cactus-plugin-consortium-indy/src/main/typescript/prometheus-exporter/prometheus-exporter.ts b/packages/cactus-plugin-consortium-indy/src/main/typescript/prometheus-exporter/prometheus-exporter.ts new file mode 100644 index 0000000000..6c07c56008 --- /dev/null +++ b/packages/cactus-plugin-consortium-indy/src/main/typescript/prometheus-exporter/prometheus-exporter.ts @@ -0,0 +1,43 @@ +import promClient, { Registry } from "prom-client"; +import { NodeCount } from "./response.type"; +import { + totalTxCount, + K_CACTUS_CONSORTIUM_MANUAL_TOTAL_NODE_COUNT, +} from "./metrics"; + +export interface IPrometheusExporterOptions { + pollingIntervalInMin?: number; +} + +export class PrometheusExporter { + public readonly metricsPollingIntervalInMin: number; + public readonly nodeCount: NodeCount = { counter: 0 }; + public readonly registry: Registry; + + constructor( + public readonly prometheusExporterOptions: IPrometheusExporterOptions, + ) { + this.metricsPollingIntervalInMin = + prometheusExporterOptions.pollingIntervalInMin || 1; + this.registry = new Registry(); + } + + public setNodeCount(nodeCount: number): void { + this.nodeCount.counter = nodeCount; + totalTxCount + .labels(K_CACTUS_CONSORTIUM_MANUAL_TOTAL_NODE_COUNT) + .set(this.nodeCount.counter); + } + + public async getPrometheusMetrics(): Promise { + const result = await this.registry.getSingleMetricAsString( + K_CACTUS_CONSORTIUM_MANUAL_TOTAL_NODE_COUNT, + ); + return result; + } + + public startMetricsCollection(): void { + this.registry.registerMetric(totalTxCount); + promClient.collectDefaultMetrics({ register: this.registry }); + } +} diff --git a/packages/cactus-plugin-consortium-indy/src/main/typescript/prometheus-exporter/response.type.ts b/packages/cactus-plugin-consortium-indy/src/main/typescript/prometheus-exporter/response.type.ts new file mode 100644 index 0000000000..4f2cf2ac0c --- /dev/null +++ b/packages/cactus-plugin-consortium-indy/src/main/typescript/prometheus-exporter/response.type.ts @@ -0,0 +1,3 @@ +export type NodeCount = { + counter: number; +}; diff --git a/packages/cactus-plugin-consortium-indy/src/main/typescript/public-api.ts b/packages/cactus-plugin-consortium-indy/src/main/typescript/public-api.ts new file mode 100755 index 0000000000..7851016987 --- /dev/null +++ b/packages/cactus-plugin-consortium-indy/src/main/typescript/public-api.ts @@ -0,0 +1,28 @@ +export { + GetConsortiumEndpointV1, + IGetConsortiumJwsEndpointOptions, +} from "./consortium/get-consortium-jws-endpoint-v1"; + +export { + GetNodeJwsEndpoint, + IGetNodeJwsEndpointOptions, +} from "./consortium/get-node-jws-endpoint-v1"; + +export { + PluginConsortiumIndy, + IPluginConsortiumIndyOptions, + IWebAppOptions, +} from "./plugin-consortium-indy"; + +export * from "./generated/openapi/typescript-axios/index"; + +export { PluginFactoryWebService } from "./plugin-factory-consortium-indy"; + +import { IPluginFactoryOptions } from "@hyperledger/cactus-core-api"; +import { PluginFactoryWebService } from "./plugin-factory-consortium-indy"; + +export async function createPluginFactory( + pluginFactoryOptions: IPluginFactoryOptions, +): Promise { + return new PluginFactoryWebService(pluginFactoryOptions); +} diff --git a/packages/cactus-plugin-consortium-indy/src/test/typescript/integration/api-surface.test.ts b/packages/cactus-plugin-consortium-indy/src/test/typescript/integration/api-surface.test.ts new file mode 100644 index 0000000000..a77b09a829 --- /dev/null +++ b/packages/cactus-plugin-consortium-indy/src/test/typescript/integration/api-surface.test.ts @@ -0,0 +1,8 @@ +import test, { Test } from "tape-promise/tape"; + +import * as apiSurface from "../../../main/typescript/public-api"; + +test("Library can be loaded", (t: Test) => { + t.ok(apiSurface, "apiSurface truthy OK"); + t.end(); +}); diff --git a/packages/cactus-plugin-consortium-indy/src/test/typescript/unit/api-surface.test.ts b/packages/cactus-plugin-consortium-indy/src/test/typescript/unit/api-surface.test.ts new file mode 100644 index 0000000000..a77b09a829 --- /dev/null +++ b/packages/cactus-plugin-consortium-indy/src/test/typescript/unit/api-surface.test.ts @@ -0,0 +1,8 @@ +import test, { Test } from "tape-promise/tape"; + +import * as apiSurface from "../../../main/typescript/public-api"; + +test("Library can be loaded", (t: Test) => { + t.ok(apiSurface, "apiSurface truthy OK"); + t.end(); +}); diff --git a/packages/cactus-plugin-consortium-indy/src/test/typescript/unit/consortium/get-node-jws-endpoint-v1.test.ts b/packages/cactus-plugin-consortium-indy/src/test/typescript/unit/consortium/get-node-jws-endpoint-v1.test.ts new file mode 100644 index 0000000000..2077c4f08a --- /dev/null +++ b/packages/cactus-plugin-consortium-indy/src/test/typescript/unit/consortium/get-node-jws-endpoint-v1.test.ts @@ -0,0 +1,165 @@ +import test, { Test } from "tape"; +import { JWS, JWK } from "jose"; +import express from "express"; +import bodyParser from "body-parser"; +import http from "http"; +import { AddressInfo } from "net"; + +import { IListenOptions, Servers } from "@hyperledger/cactus-common"; + +import { + ConsortiumDatabase, + CactusNode, + Configuration, +} from "@hyperledger/cactus-core-api"; + +import { + PluginConsortiumIndy, + IPluginConsortiumIndyOptions, +} from "../../../../main/typescript/public-api"; + +import { GetNodeJwsEndpoint } from "../../../../main/typescript/public-api"; + +import { v4 as uuidv4 } from "uuid"; + +import { DefaultApi as ConsortiumManualApi } from "../../../../main/typescript/public-api"; + +import { K_CACTUS_CONSORTIUM_MANUAL_TOTAL_NODE_COUNT } from "../../../../main/typescript/prometheus-exporter/metrics"; + +test("Can provide JWS", async (t: Test) => { + t.ok(GetNodeJwsEndpoint); + + const keyPair = await JWK.generate("EC", "secp256k1", { use: "sig" }, true); + const keyPairPem = keyPair.toPEM(true); + + const db: ConsortiumDatabase = { + cactusNode: [], + consortium: [], + consortiumMember: [], + ledger: [], + pluginInstance: [], + }; + + // Creating the PluginConsortiumIndy object to observe the prometheus metrics. + const options: IPluginConsortiumIndyOptions = { + instanceId: uuidv4(), + keyPairPem: keyPairPem, + consortiumDatabase: db, + }; + + const PluginConsortiumIndy: PluginConsortiumIndy = new PluginConsortiumIndy( + options, + ); + + // Setting up of the api-server for hosting the endpoints defined in the openapi specs + // of the plugin + const expressApp = express(); + expressApp.use(bodyParser.json({ limit: "250mb" })); + const server = http.createServer(expressApp); + const listenOptions: IListenOptions = { + hostname: "0.0.0.0", + port: 0, + server, + }; + const addressInfo = (await Servers.listen(listenOptions)) as AddressInfo; + test.onFinish(async () => await Servers.shutdown(server)); + const { address, port } = addressInfo; + const apiHost = `http://${address}:${port}`; + t.comment( + `Metrics URL: ${apiHost}/api/v1/plugins/@hyperledger/cactus-plugin-consortium-indy/get-prometheus-exporter-metrics`, + ); + + const config = new Configuration({ basePath: apiHost }); + const apiClient = new ConsortiumManualApi(config); + + await PluginConsortiumIndy.getOrCreateWebServices(); + await PluginConsortiumIndy.registerWebServices(expressApp); + + const pubKeyPem = keyPair.toPEM(false); + + const jws = await PluginConsortiumIndy.getNodeJws(); + t.ok(jws, "created JWS is truthy"); + t.ok(typeof jws === "object", "created JWS is an object"); + + t.doesNotThrow(() => JWS.verify(jws, pubKeyPem), "JWS verified OK"); + t.doesNotThrow(() => JWS.verify(jws, keyPair), "JWS verified OK"); + + const payload = JWS.verify(jws, pubKeyPem) as { + consortiumDatabase: ConsortiumDatabase; + }; + t.ok(payload, "JWS verified payload truthy"); + if (typeof payload === "string") { + t.fail(`JWS Verification result: ${payload}`); + } else { + t.ok(payload.consortiumDatabase, "JWS payload.consortiumDatabase truthy"); + } + + { + // The first check shall observe the cactus_consortium_manual_total_node_count metrics + // to be valued at zero, as the ConsortiumRepo object is initialized with an empty array of + // Cactus nodes. + const res = await apiClient.getPrometheusMetricsV1(); + const promMetricsOutput = + "# HELP " + + K_CACTUS_CONSORTIUM_MANUAL_TOTAL_NODE_COUNT + + " Total cactus node count\n" + + "# TYPE " + + K_CACTUS_CONSORTIUM_MANUAL_TOTAL_NODE_COUNT + + " gauge\n" + + K_CACTUS_CONSORTIUM_MANUAL_TOTAL_NODE_COUNT + + '{type="' + + K_CACTUS_CONSORTIUM_MANUAL_TOTAL_NODE_COUNT + + '"} 0'; + t.ok(res); + t.ok(res.data); + t.equal(res.status, 200); + t.true( + res.data.includes(promMetricsOutput), + "Total Cactus Node Count of 0 recorded as expected. RESULT OK", + ); + } + + // Creating a dummy cactus node for adding it to the cactus node array + // and thus observing the change in prometheus exporter metrics (should increment by 1) + const dummyCactusNode: CactusNode = { + consortiumId: "", + id: "", + ledgerIds: [], + memberId: "", + nodeApiHost: "", + pluginInstanceIds: [], + publicKeyPem: "", + }; + + db.cactusNode.push(dummyCactusNode); + // The invocation of the node JWS endpoint internally triggers the update + // of the metrics so after it has executed we can expect the metrics to + // show the new values for our assertions below + await apiClient.getNodeJwsV1(); + + { + // The second check shall observe the cactus_consortium_manual_total_node_count metrics + // to be valued at One, as the Cactus node array is pushed with a dummy cactus node. + const res = await apiClient.getPrometheusMetricsV1(); + const promMetricsOutput = + "# HELP " + + K_CACTUS_CONSORTIUM_MANUAL_TOTAL_NODE_COUNT + + " Total cactus node count\n" + + "# TYPE " + + K_CACTUS_CONSORTIUM_MANUAL_TOTAL_NODE_COUNT + + " gauge\n" + + K_CACTUS_CONSORTIUM_MANUAL_TOTAL_NODE_COUNT + + '{type="' + + K_CACTUS_CONSORTIUM_MANUAL_TOTAL_NODE_COUNT + + '"} 1'; + t.ok(res); + t.ok(res.data); + t.equal(res.status, 200); + t.true( + res.data.includes(promMetricsOutput), + "Total Cactus Node Count of 1 recorded as expected. RESULT OK", + ); + } + + t.end(); +}); diff --git a/packages/cactus-plugin-consortium-indy/tsconfig.json b/packages/cactus-plugin-consortium-indy/tsconfig.json new file mode 100644 index 0000000000..ffc2db9efa --- /dev/null +++ b/packages/cactus-plugin-consortium-indy/tsconfig.json @@ -0,0 +1,25 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "composite": true, + "outDir": "./dist/lib/", + "declarationDir": "dist/lib", + "rootDir": "./src", + "tsBuildInfoFile": "../../.build-cache/cactus-plugin-consortium-indy.tsbuildinfo" + }, + "include": [ + "./src", + "**/openapi.json" + ], + "references": [ + { + "path": "../cactus-common/tsconfig.json" + }, + { + "path": "../cactus-core/tsconfig.json" + }, + { + "path": "../cactus-core-api/tsconfig.json" + } + ] +} \ No newline at end of file