Skip to content
This repository has been archived by the owner on Mar 5, 2024. It is now read-only.

Commit

Permalink
Merge pull request #110 from finos-plexus/db-contrib/develop
Browse files Browse the repository at this point in the history
Cancel Request for Point to Point invocation in Generated JS Client
  • Loading branch information
Mikhail Udalov committed Oct 29, 2019
2 parents 8d223ed + 92d0a3d commit af9c989
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 18 deletions.
Expand Up @@ -53,16 +53,23 @@ class TypescriptApplicationApiGenerator extends ApplicationCodeGenerator {
'''
«imports(genConfig)»
export interface CancellableUnaryResponse<T> {
invocation: InvocationClient;
response: Promise<T>;
}
«FOR consumedService : consumedServices SEPARATOR "\n
/**
* Proxy interface of «consumedService.aliasOrName.toFirstUpper» service, to be consumed by Client API
*/
export abstract class «consumedService.aliasOrName.toFirstUpper»Proxy {
«FOR method : consumedService.methods SEPARATOR "\n
public abstract «clientMethodSignature(method, genConfig)»;
«FOR consumedMethod : consumedService.methods SEPARATOR "\n
public abstract «clientMethodSignature(consumedMethod, genConfig)»;
«IF consumedMethod.method.isPointToPoint»
public abstract «cancellableUnaryMethodSignature(consumedMethod.method, genConfig)»;
«ENDIF»
«ENDFOR»
}
«ENDFOR»
Expand All @@ -78,6 +85,11 @@ class TypescriptApplicationApiGenerator extends ApplicationCodeGenerator {
public «clientMethodSignature(consumedMethod, genConfig)» {
«clientMethodImpl(consumedMethod, consumedService, genConfig)»
}
«IF consumedMethod.method.isPointToPoint»
public «cancellableUnaryMethodSignature(consumedMethod.method, genConfig)» {
«clientCancellablePointToPointImpl(consumedMethod, consumedService, genConfig)»
}
«ENDIF»
«ENDFOR»
}
Expand Down Expand Up @@ -242,6 +254,8 @@ import * as «genConfig.namespace» from '«genConfig.getExternalDependencies().
clientMethodSignature(methodLink.method, genConfig)
}
def cancellableUnaryMethodSignature(Method rpcMethod, PlexusGenConfig genConfig) '''«rpcMethod.name.toFirstLower»WithCancellation(request: «requestType(rpcMethod, genConfig)»): Promise<CancellableUnaryResponse<«responseType(rpcMethod, genConfig)»>>'''
def clientMethodSignature(Method rpcMethod, PlexusGenConfig genConfig) {
switch (rpcMethod) {
case rpcMethod.isPointToPoint: '''«rpcMethod.name.toFirstLower»(request: «requestType(rpcMethod, genConfig)»): Promise<«responseType(rpcMethod, genConfig)»>'''
Expand Down Expand Up @@ -286,6 +300,23 @@ import * as «genConfig.namespace» from '«genConfig.getExternalDependencies().
'''
}
def clientCancellablePointToPointImpl(ConsumedMethod consumed, ConsumedService consumedService, PlexusGenConfig genConfig) {
val rpcMethod = consumed.method
return '''
«clientInvocationInfo(consumed, consumedService, genConfig)»
return new Promise<CancellableUnaryResponse<«responseType(rpcMethod, genConfig)»>>((resolveInvocation, rejectInvocation) => {
const responsePromise = new Promise<«responseType(rpcMethod, genConfig)»>((resolveResponse, rejectResponse) => {
this.genericClient.sendUnaryRequest(invocationInfo, request, {
value: responsePayload => resolveResponse(responsePayload),
error: e => rejectResponse(e)
}, «requestTypeImpl(rpcMethod, genConfig)», «responseTypeImpl(rpcMethod, genConfig)»)
.then(invocationClient => resolveInvocation({ invocation: invocationClient, response: responsePromise }))
.catch(rejectInvocation);
});
});
'''
}
def clientBidiStreamingImpl(ConsumedMethod consumed, ConsumedService consumedService, PlexusGenConfig genConfig) {
val rpcMethod = consumed.method
return '''
Expand Down
Expand Up @@ -6,19 +6,24 @@ import { InvocationObserver, InvocationObserverConverter, ContainerAwareClientAP

import * as plexus from './plexus-messages';

export interface CancellableUnaryResponse<T> {
invocation: InvocationClient;
response: Promise<T>;
}

/**
* Proxy interface of ExampleService service, to be consumed by Client API
*/
export abstract class ExampleServiceProxy {

public abstract pointToPoint(request: plexus.com.db.plexus.interop.dsl.gen.test.model.IRequest): Promise<plexus.com.db.plexus.interop.dsl.gen.test.model.IResponse>;

public abstract pointToPointWithCancellation(request: plexus.com.db.plexus.interop.dsl.gen.test.model.IRequest): Promise<CancellableUnaryResponse<plexus.com.db.plexus.interop.dsl.gen.test.model.IResponse>>;

public abstract serverStreaming(request: plexus.com.db.plexus.interop.dsl.gen.test.model.IRequest, responseObserver: InvocationObserver<plexus.com.db.plexus.interop.dsl.gen.test.model.IResponse>): Promise<InvocationClient>;

public abstract clientToServer(responseObserver: InvocationObserver<plexus.com.db.plexus.interop.dsl.gen.test.model.IResponse>): Promise<StreamingInvocationClient<plexus.com.db.plexus.interop.dsl.gen.test.model.IRequest>>;

public abstract bidiStreaming(responseObserver: InvocationObserver<plexus.com.db.plexus.interop.dsl.gen.test.model.IResponse>): Promise<StreamingInvocationClient<plexus.com.db.plexus.interop.dsl.gen.test.model.IRequest>>;

}

/**
Expand All @@ -27,7 +32,7 @@ export abstract class ExampleServiceProxy {
export abstract class NoLaunchExampleServiceProxy {

public abstract pointToPoint(request: plexus.com.db.plexus.interop.dsl.gen.test.model.IRequest): Promise<plexus.com.db.plexus.interop.dsl.gen.test.model.IResponse>;

public abstract pointToPointWithCancellation(request: plexus.com.db.plexus.interop.dsl.gen.test.model.IRequest): Promise<CancellableUnaryResponse<plexus.com.db.plexus.interop.dsl.gen.test.model.IResponse>>;
}

/**
Expand All @@ -49,7 +54,23 @@ export class ExampleServiceProxyImpl implements ExampleServiceProxy {
}, plexus.com.db.plexus.interop.dsl.gen.test.model.Request, plexus.com.db.plexus.interop.dsl.gen.test.model.Response);
});
}

public pointToPointWithCancellation(request: plexus.com.db.plexus.interop.dsl.gen.test.model.IRequest): Promise<CancellableUnaryResponse<plexus.com.db.plexus.interop.dsl.gen.test.model.IResponse>> {
const invocationInfo: InvocationRequestInfo = {
methodId: 'PointToPoint',
serviceId: 'com.db.plexus.interop.dsl.gen.test.services.ExampleService'
};
return new Promise<CancellableUnaryResponse<plexus.com.db.plexus.interop.dsl.gen.test.model.IResponse>>((resolveInvocation, rejectInvocation) => {
const responsePromise = new Promise<plexus.com.db.plexus.interop.dsl.gen.test.model.IResponse>((resolveResponse, rejectResponse) => {
this.genericClient.sendUnaryRequest(invocationInfo, request, {
value: responsePayload => resolveResponse(responsePayload),
error: e => rejectResponse(e)
}, plexus.com.db.plexus.interop.dsl.gen.test.model.Request, plexus.com.db.plexus.interop.dsl.gen.test.model.Response)
.then(invocationClient => resolveInvocation({ invocation: invocationClient, response: responsePromise }))
.catch(rejectInvocation);
});
});
}

public serverStreaming(request: plexus.com.db.plexus.interop.dsl.gen.test.model.IRequest, responseObserver: InvocationObserver<plexus.com.db.plexus.interop.dsl.gen.test.model.IResponse>): Promise<InvocationClient> {
const invocationInfo: InvocationRequestInfo = {
methodId: 'ServerStreaming',
Expand All @@ -62,7 +83,7 @@ export class ExampleServiceProxyImpl implements ExampleServiceProxy {
plexus.com.db.plexus.interop.dsl.gen.test.model.Request, plexus.com.db.plexus.interop.dsl.gen.test.model.Response
);
}

public clientToServer(responseObserver: InvocationObserver<plexus.com.db.plexus.interop.dsl.gen.test.model.IResponse>): Promise<StreamingInvocationClient<plexus.com.db.plexus.interop.dsl.gen.test.model.IRequest>> {
const invocationInfo: InvocationRequestInfo = {
methodId: 'ClientToServer',
Expand All @@ -73,7 +94,7 @@ export class ExampleServiceProxyImpl implements ExampleServiceProxy {
responseObserver,
plexus.com.db.plexus.interop.dsl.gen.test.model.Request, plexus.com.db.plexus.interop.dsl.gen.test.model.Response);
}

public bidiStreaming(responseObserver: InvocationObserver<plexus.com.db.plexus.interop.dsl.gen.test.model.IResponse>): Promise<StreamingInvocationClient<plexus.com.db.plexus.interop.dsl.gen.test.model.IRequest>> {
const invocationInfo: InvocationRequestInfo = {
methodId: 'BidiStreaming',
Expand Down Expand Up @@ -107,6 +128,23 @@ export class NoLaunchExampleServiceProxyImpl implements NoLaunchExampleServicePr
}, plexus.com.db.plexus.interop.dsl.gen.test.model.Request, plexus.com.db.plexus.interop.dsl.gen.test.model.Response);
});
}
public pointToPointWithCancellation(request: plexus.com.db.plexus.interop.dsl.gen.test.model.IRequest): Promise<CancellableUnaryResponse<plexus.com.db.plexus.interop.dsl.gen.test.model.IResponse>> {
const invocationInfo: InvocationRequestInfo = {
methodId: 'PointToPoint',
serviceId: 'com.db.plexus.interop.dsl.gen.test.services.ExampleService',
serviceAlias: 'NoLaunchExampleService'
};
return new Promise<CancellableUnaryResponse<plexus.com.db.plexus.interop.dsl.gen.test.model.IResponse>>((resolveInvocation, rejectInvocation) => {
const responsePromise = new Promise<plexus.com.db.plexus.interop.dsl.gen.test.model.IResponse>((resolveResponse, rejectResponse) => {
this.genericClient.sendUnaryRequest(invocationInfo, request, {
value: responsePayload => resolveResponse(responsePayload),
error: e => rejectResponse(e)
}, plexus.com.db.plexus.interop.dsl.gen.test.model.Request, plexus.com.db.plexus.interop.dsl.gen.test.model.Response)
.then(invocationClient => resolveInvocation({ invocation: invocationClient, response: responsePromise }))
.catch(rejectInvocation);
});
});
}

}

Expand All @@ -116,7 +154,7 @@ export class NoLaunchExampleServiceProxyImpl implements NoLaunchExampleServicePr
export interface ComponentAClient extends GenericClientApi {

getExampleServiceProxy(): ExampleServiceProxy;

getNoLaunchExampleServiceProxy(): NoLaunchExampleServiceProxy;

}
Expand All @@ -137,7 +175,7 @@ class ComponentAClientImpl extends GenericClientApiBase implements ComponentACli
public getExampleServiceProxy(): ExampleServiceProxy {
return this.exampleServiceProxy;
}

public getNoLaunchExampleServiceProxy(): NoLaunchExampleServiceProxy {
return this.noLaunchExampleServiceProxy;
}
Expand All @@ -158,11 +196,11 @@ export abstract class NoLaunchExampleServiceInvocationHandler {
export abstract class ExampleServiceInvocationHandler {

public abstract onPointToPoint(invocationContext: MethodInvocationContext, request: plexus.com.db.plexus.interop.dsl.gen.test.model.IRequest): Promise<plexus.com.db.plexus.interop.dsl.gen.test.model.IResponse>;

public abstract onServerStreaming(invocationContext: MethodInvocationContext, request: plexus.com.db.plexus.interop.dsl.gen.test.model.IRequest, hostClient: StreamingInvocationClient<plexus.com.db.plexus.interop.dsl.gen.test.model.IResponse>): void;

public abstract onClientToServer(invocationContext: MethodInvocationContext, hostClient: StreamingInvocationClient<plexus.com.db.plexus.interop.dsl.gen.test.model.IResponse>): InvocationObserver<plexus.com.db.plexus.interop.dsl.gen.test.model.IRequest>;

public abstract onBidiStreaming(invocationContext: MethodInvocationContext, hostClient: StreamingInvocationClient<plexus.com.db.plexus.interop.dsl.gen.test.model.IResponse>): InvocationObserver<plexus.com.db.plexus.interop.dsl.gen.test.model.IRequest>;
}

Expand All @@ -176,14 +214,14 @@ export class ComponentAClientBuilder implements ClientApiBuilder<ComponentAClien
.withApplicationId('com.db.plexus.interop.dsl.gen.test.components.ComponentA');

private noLaunchExampleServiceHandler: NoLaunchExampleServiceInvocationHandler;

private exampleServiceHandler: ExampleServiceInvocationHandler;

public withNoLaunchExampleServiceInvocationsHandler(invocationsHandler: NoLaunchExampleServiceInvocationHandler): ComponentAClientBuilder {
this.noLaunchExampleServiceHandler = invocationsHandler;
return this;
}

public withExampleServiceInvocationsHandler(invocationsHandler: ExampleServiceInvocationHandler): ComponentAClientBuilder {
this.exampleServiceHandler = invocationsHandler;
return this;
Expand Down
24 changes: 24 additions & 0 deletions web/packages/e2e/src/echo/client/EchoClientGeneratedClient.ts
Expand Up @@ -22,12 +22,19 @@ import { InvocationObserver, InvocationObserverConverter, ContainerAwareClientAP

import * as plexus from '../gen/plexus-messages';

export interface CancellableUnaryResponse<T> {
invocation: InvocationClient;
response: Promise<T>;
}

/**
* Proxy interface of EchoService service, to be consumed by Client API
*/
export abstract class EchoServiceProxy {

public abstract unary(request: plexus.plexus.interop.testing.IEchoRequest): Promise<plexus.plexus.interop.testing.IEchoRequest>;

public abstract unaryWithCancellation(request: plexus.plexus.interop.testing.IEchoRequest): Promise<CancellableUnaryResponse<plexus.plexus.interop.testing.IEchoRequest>>;

public abstract serverStreaming(request: plexus.plexus.interop.testing.IEchoRequest, responseObserver: InvocationObserver<plexus.plexus.interop.testing.IEchoRequest>): Promise<InvocationClient>;

Expand All @@ -53,6 +60,23 @@ export class EchoServiceProxyImpl implements EchoServiceProxy {

constructor(private readonly genericClient: GenericClientApi) { }

public unaryWithCancellation(request: plexus.plexus.interop.testing.IEchoRequest): Promise<CancellableUnaryResponse<plexus.plexus.interop.testing.IEchoRequest>> {
const invocationInfo: InvocationRequestInfo = {
methodId: 'Unary',
serviceId: 'plexus.interop.testing.EchoService'
};
return new Promise<CancellableUnaryResponse<plexus.plexus.interop.testing.IEchoRequest>>((resolveInvocation, rejectInvocation) => {
const responsePromise = new Promise<plexus.plexus.interop.testing.IEchoRequest>((resolveResponse, rejectResponse) => {
this.genericClient.sendUnaryRequest(invocationInfo, request, {
value: responsePayload => resolveResponse(responsePayload),
error: e => rejectResponse(e)
}, plexus.plexus.interop.testing.EchoRequest, plexus.plexus.interop.testing.EchoRequest)
.then(invocationClient => resolveInvocation({ invocation: invocationClient, response: responsePromise }))
.catch(rejectInvocation);
});
});
}

public unary(request: plexus.plexus.interop.testing.IEchoRequest): Promise<plexus.plexus.interop.testing.IEchoRequest> {
const invocationInfo: InvocationRequestInfo = {
methodId: 'Unary',
Expand Down
28 changes: 28 additions & 0 deletions web/packages/e2e/tests/echo/PointToPointInvocationTests.ts
Expand Up @@ -23,6 +23,7 @@ import { ClientError } from '@plexus-interop/protocol';
import { expect } from 'chai';
import { MethodInvocationContext } from '@plexus-interop/client';
import { NopServiceHandler } from './NopServiceHandler';
import { AsyncHelper } from '@plexus-interop/common';

export class PointToPointInvocationTests extends BaseEchoTest {

Expand Down Expand Up @@ -85,6 +86,33 @@ export class PointToPointInvocationTests extends BaseEchoTest {
return this.testHostsExecutionErrorReceivedInternal(errorText, errorText);
}

public async testGeneratedClientCanCancelUnaryInvocation(): Promise<void> {
const echoRequest = this.clientsSetup.createRequestDto();
let serverReceivedCancel = false;
const handler = new UnaryServiceHandler(context => {
return new Promise<plexus.plexus.interop.testing.IEchoRequest>(() => {
context.cancellationToken.onCancel(() => serverReceivedCancel = true);
// "long running operation" do not return any result
});
});
const [echoClient, echoServer] = await this.clientsSetup.createEchoClients(this.connectionProvider, handler);
const cancellableResponse = await echoClient.getEchoServiceProxy().unaryWithCancellation(echoRequest);
await cancellableResponse.invocation.cancel();
await this.clientsSetup.disconnect(echoClient, echoServer);
// tslint:disable-next-line: no-unused-expression
await AsyncHelper.waitFor(() => serverReceivedCancel === true, undefined, 10, 500);
}

public async testGeneratedClientCanGetResponseFromCancellableUnaryInvocation(): Promise<void> {
const echoRequest = this.clientsSetup.createRequestDto();
const handler = new UnaryServiceHandler(async () => echoRequest);
const [echoClient, echoServer] = await this.clientsSetup.createEchoClients(this.connectionProvider, handler);
const cancellableResponse = await echoClient.getEchoServiceProxy().unaryWithCancellation(echoRequest);
const echoResponse = await cancellableResponse.response;
await this.clientsSetup.disconnect(echoClient, echoServer);
this.assertEqual(echoRequest, echoResponse);
}

public testFewMessagesSent(): Promise<void> {
const echoRequest = this.clientsSetup.createRequestDto();
return new Promise<void>((resolve, reject) => {
Expand Down
8 changes: 8 additions & 0 deletions web/packages/e2e/tests/native/WebSocketPointToPoint.spec.ts
Expand Up @@ -66,4 +66,12 @@ describe('Client: Web Socket Point to Point invocation', () => {
return pointToPointTests.testHostExecutionExceptionReceived();
});

it('Supports cancel of Unary Invocation by Generated Client', () => {
return pointToPointTests.testGeneratedClientCanCancelUnaryInvocation();
});

it('Supports receiving of result from cancellable Unary Invocation by Generated Client', () => {
return pointToPointTests.testGeneratedClientCanGetResponseFromCancellableUnaryInvocation();
});

});

0 comments on commit af9c989

Please sign in to comment.