From cbba0903a08d8cca88a0842eae010751d27ac587 Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Fri, 10 Feb 2023 14:38:47 +0000 Subject: [PATCH] Use interface instead of @grpc/grpc-js Client class in public API Since the gRPC Client is a concrete class, changes to private members can cause version-to-version type incompatibilities if the caller has a dependency on a different version of @grpc/grpc-js. Requiring an interface containing only public methods of the gRPC Client class avoids these issues, provided there are no breaking changes in the gRPC Client API. Signed-off-by: Mark S. Lewis --- node/src/gateway.test.ts | 2 +- node/src/gateway.ts | 25 +++++++++++++++++++++++-- node/src/index.ts | 2 +- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/node/src/gateway.test.ts b/node/src/gateway.test.ts index 1b3cbed6f..a5975bed2 100644 --- a/node/src/gateway.test.ts +++ b/node/src/gateway.test.ts @@ -31,7 +31,7 @@ describe('Gateway', () => { it('throws if no identity supplied', () => { const options = { client, - } as ConnectOptions; + } as unknown as ConnectOptions; expect(() => connect(options)).toThrow(); }); }); diff --git a/node/src/gateway.ts b/node/src/gateway.ts index 6f1dec82f..ae36dc1e7 100644 --- a/node/src/gateway.ts +++ b/node/src/gateway.ts @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { CallOptions, Client } from '@grpc/grpc-js'; +import { CallOptions, ChannelInterface, ClientDuplexStream, ClientReadableStream, ClientUnaryCall, ClientWritableStream, Deadline, Metadata, requestCallback } from '@grpc/grpc-js'; import { common, gateway, peer } from '@hyperledger/fabric-protos'; import { ChaincodeEventsRequest, Commit, Proposal, Transaction } from '.'; import { BlockAndPrivateDataEventsRequest, BlockAndPrivateDataEventsRequestImpl, BlockEventsRequest, BlockEventsRequestImpl, FilteredBlockEventsRequest, FilteredBlockEventsRequestImpl } from './blockeventsrequest'; @@ -19,6 +19,27 @@ import { ProposalImpl } from './proposal'; import { SigningIdentity } from './signingidentity'; import { TransactionImpl } from './transaction'; +/** + * Interface describing the public API of the gRPC Client class. + */ +export interface GrpcClient { + close(): void; + getChannel(): ChannelInterface; + waitForReady(deadline: Deadline, callback: (error?: Error) => void): void; + makeUnaryRequest(method: string, serialize: (value: RequestType) => Buffer, deserialize: (value: Buffer) => ResponseType, argument: RequestType, metadata: Metadata, options: CallOptions, callback: requestCallback): ClientUnaryCall; + makeUnaryRequest(method: string, serialize: (value: RequestType) => Buffer, deserialize: (value: Buffer) => ResponseType, argument: RequestType, metadata: Metadata, callback: requestCallback): ClientUnaryCall; + makeUnaryRequest(method: string, serialize: (value: RequestType) => Buffer, deserialize: (value: Buffer) => ResponseType, argument: RequestType, options: CallOptions, callback: requestCallback): ClientUnaryCall; + makeUnaryRequest(method: string, serialize: (value: RequestType) => Buffer, deserialize: (value: Buffer) => ResponseType, argument: RequestType, callback: requestCallback): ClientUnaryCall; + makeClientStreamRequest(method: string, serialize: (value: RequestType) => Buffer, deserialize: (value: Buffer) => ResponseType, metadata: Metadata, options: CallOptions, callback: requestCallback): ClientWritableStream; + makeClientStreamRequest(method: string, serialize: (value: RequestType) => Buffer, deserialize: (value: Buffer) => ResponseType, metadata: Metadata, callback: requestCallback): ClientWritableStream; + makeClientStreamRequest(method: string, serialize: (value: RequestType) => Buffer, deserialize: (value: Buffer) => ResponseType, options: CallOptions, callback: requestCallback): ClientWritableStream; + makeClientStreamRequest(method: string, serialize: (value: RequestType) => Buffer, deserialize: (value: Buffer) => ResponseType, callback: requestCallback): ClientWritableStream; + makeServerStreamRequest(method: string, serialize: (value: RequestType) => Buffer, deserialize: (value: Buffer) => ResponseType, argument: RequestType, metadata: Metadata, options?: CallOptions): ClientReadableStream; + makeServerStreamRequest(method: string, serialize: (value: RequestType) => Buffer, deserialize: (value: Buffer) => ResponseType, argument: RequestType, options?: CallOptions): ClientReadableStream; + makeBidiStreamRequest(method: string, serialize: (value: RequestType) => Buffer, deserialize: (value: Buffer) => ResponseType, metadata: Metadata, options?: CallOptions): ClientDuplexStream; + makeBidiStreamRequest(method: string, serialize: (value: RequestType) => Buffer, deserialize: (value: Buffer) => ResponseType, options?: CallOptions): ClientDuplexStream; +} + /** * Options used when connecting to a Fabric Gateway. * @example @@ -47,7 +68,7 @@ export interface ConnectOptions { * A gRPC client connection to a Fabric Gateway. This should be shared by all gateway instances connecting to the * same Fabric Gateway. The client connection will not be closed when the gateway is closed. */ - client: Client; + client: GrpcClient; /** * Client identity used by the gateway. diff --git a/node/src/index.ts b/node/src/index.ts index 3285f17d1..8ac9d7bb1 100644 --- a/node/src/index.ts +++ b/node/src/index.ts @@ -18,7 +18,7 @@ export { CommitStatusError } from './commitstatuserror'; export { Contract } from './contract'; export { EndorseError } from './endorseerror'; export { EventsOptions } from './eventsbuilder'; -export { connect, ConnectOptions, Gateway } from './gateway'; +export { connect, ConnectOptions, Gateway, GrpcClient } from './gateway'; export { ErrorDetail, GatewayError } from './gatewayerror'; export { Hash } from './hash/hash'; export * as hash from './hash/hashes';