diff --git a/.cspell.json b/.cspell.json index b45f60df1f..1aecf659be 100644 --- a/.cspell.json +++ b/.cspell.json @@ -38,12 +38,14 @@ "clsx", "commenceack", "configtx", + "connectrpc", "Corda", "Cordapp", "couchdb", "COUCHDBADDRESS", "COUCHDBCONFIG", "Creds", + "Crpc", "data", "davecgh", "dclm", @@ -59,6 +61,7 @@ "escc", "execa", "faio", + "fastify", "fidm", "flowdb", "fsouza", diff --git a/packages/cactus-core-api/package.json b/packages/cactus-core-api/package.json index c77d7a3bd9..90733979d1 100644 --- a/packages/cactus-core-api/package.json +++ b/packages/cactus-core-api/package.json @@ -63,6 +63,8 @@ "axios": "1.6.0" }, "devDependencies": { + "@bufbuild/protobuf": "1.8.0", + "@connectrpc/connect": "1.4.0", "@grpc/grpc-js": "1.10.3", "@grpc/proto-loader": "0.7.8", "@types/express": "4.17.19", diff --git a/packages/cactus-core-api/src/main/typescript/plugin/crpc-service/i-plugin-crpc-service.ts b/packages/cactus-core-api/src/main/typescript/plugin/crpc-service/i-plugin-crpc-service.ts new file mode 100644 index 0000000000..fea7c5c8fe --- /dev/null +++ b/packages/cactus-core-api/src/main/typescript/plugin/crpc-service/i-plugin-crpc-service.ts @@ -0,0 +1,68 @@ +import type { ServiceType } from "@bufbuild/protobuf"; +import type { ServiceImpl } from "@connectrpc/connect"; +import type { UniversalHandlerOptions } from "@connectrpc/connect/protocol"; + +/** + * Implementers of this interface are responsible for providing a Crpc service + * that can be dynamically registered at runtime by the API server. + * + * It describes what methods a class (plugin) needs to implement + * in order to be able to operate as a Cacti Crpc service (e.g. expose its + * functionality through Crpc not just HTTP or SocketIO) + * + * @see {IPluginWebService} + * @see {IPluginGrpcService} + * @see {ApiServer} + */ +export interface IPluginCrpcService { + /** + * Used by the API server and/or automated test cases when hooking up this + * plugin instance into a crpc Server object. + * + * The returned pair of service + * definition and implementation objects are passed in to the `.addService()` + * method of the `Server` object of the `@connectrpc/connect` library. + * + * @see {ServiceDefinition} + * @see {ServiceType} + * @see {ICrpcSvcRegistration} + */ + createCrpcSvcRegistrations( + opts: unknown, + ): Promise>>; +} + +/** + * A wrapper object that contains both the the definition and the implementation + * objects of a crpc service that a plugin can implement to expose it's functionality + * over crpc. + * + * @see {IPluginGrpcService} + * @see {IGrpcSvcDefAndImplPair} + */ +export interface ICrpcSvcRegistration { + readonly definition: T; + readonly implementation: Partial>; + readonly serviceName: string; + readonly options?: Partial; +} + +/** + * Custom (user-defined) Typescript type-guard that verifies at runtime whether + * `x` is an implementation of {IPluginCrpcService} or not. + * + * @param x Literally any object or value that you'd want to verify for having + * the right method(s) implemented in-order to qualify as an implementer of the + * {IPluginCrpcService} interface. + * + * The {ApiServer} uses this to filter the total list of plugins down to the ones + * that have crpc services of their own and then hook those up at runtime. + * + * @returns `true` if `x` does implement {IPluginCrpcService} `false` otherwise. + */ +export function isIPluginCrpcService(x: unknown): x is IPluginCrpcService { + return ( + !!x && + typeof (x as IPluginCrpcService).createCrpcSvcRegistrations === "function" + ); +} diff --git a/packages/cactus-core-api/src/main/typescript/public-api.ts b/packages/cactus-core-api/src/main/typescript/public-api.ts index 97ad96a597..7221bf1a6c 100755 --- a/packages/cactus-core-api/src/main/typescript/public-api.ts +++ b/packages/cactus-core-api/src/main/typescript/public-api.ts @@ -48,3 +48,7 @@ export { ISendRequestResultV1 } from "./plugin/ledger-connector/i-send-request-r export { IPluginGrpcService } from "./plugin/grpc-service/i-plugin-grpc-service"; export { IGrpcSvcDefAndImplPair } from "./plugin/grpc-service/i-plugin-grpc-service"; export { isIPluginGrpcService } from "./plugin/grpc-service/i-plugin-grpc-service"; + +export { ICrpcSvcRegistration } from "./plugin/crpc-service/i-plugin-crpc-service"; +export { IPluginCrpcService } from "./plugin/crpc-service/i-plugin-crpc-service"; +export { isIPluginCrpcService } from "./plugin/crpc-service/i-plugin-crpc-service"; diff --git a/yarn.lock b/yarn.lock index f239e4ea79..ce4116c7b0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4341,6 +4341,13 @@ __metadata: languageName: node linkType: hard +"@bufbuild/protobuf@npm:1.8.0": + version: 1.8.0 + resolution: "@bufbuild/protobuf@npm:1.8.0" + checksum: 10/f91d60ff1609c023466500e99312d2e92ac09c163d615c315fa25d9e50f1e9b76a3a9cac776786a3dd5c5065bb7061bf29388587e2a1d27306f68ed98e57a892 + languageName: node + linkType: hard + "@chainsafe/as-sha256@npm:^0.3.1": version: 0.3.1 resolution: "@chainsafe/as-sha256@npm:0.3.1" @@ -4607,6 +4614,15 @@ __metadata: languageName: node linkType: hard +"@connectrpc/connect@npm:1.4.0": + version: 1.4.0 + resolution: "@connectrpc/connect@npm:1.4.0" + peerDependencies: + "@bufbuild/protobuf": ^1.4.2 + checksum: 10/5e84fbba544f7e52533bdd0058caaa6d5c89903f522fbd9551c6bad0cd2fea2d3f14c7396696609d1787a5e2018054dd53db40b2d08c55975ff81334074eeeae + languageName: node + linkType: hard + "@cspell/cspell-bundled-dicts@npm:^5.21.2": version: 5.21.2 resolution: "@cspell/cspell-bundled-dicts@npm:5.21.2" @@ -7672,6 +7688,8 @@ __metadata: version: 0.0.0-use.local resolution: "@hyperledger/cactus-core-api@workspace:packages/cactus-core-api" dependencies: + "@bufbuild/protobuf": "npm:1.8.0" + "@connectrpc/connect": "npm:1.4.0" "@grpc/grpc-js": "npm:1.10.3" "@grpc/proto-loader": "npm:0.7.8" "@hyperledger/cactus-common": "npm:2.0.0-alpha.2"