Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
{
"name": "@loopback/grpc",
"version": "1.0.0-alpha.2",
"version": "1.0.7",
"description": "A gRPC extencion for LoopBack Next",
"main": "index.js",
"engines": {
"node": ">=8"
},
"scripts": {
"build": "lb-tsc es2017",
"build": "lb-tsc es2017 --outDir dist",
"build:apidocs": "lb-apidocs",
"build:watch": "lb-tsc es2017 --watch",
"build:watch": "lb-tsc es2017 --outDir dist --watch",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please fix the test script to be:

"test": "lb-mocha \"dist/test/unit/**/*.js\" \"dist/test/acceptance/**/*.js\"",

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@raymondfeng Just fixed.

"clean": "lb-clean loopback-grpc*.tgz dist package api-docs",
"prepublishOnly": "npm run build && npm run build:apidocs",
"pretest": "npm run lint:fix && npm run clean && npm run build",
"test": "lb-mocha \"DIST/test/unit/**/*.js\" \"DIST/test/acceptance/**/*.js\"",
"test": "lb-mocha \"dist/test/unit/**/*.js\" \"dist/test/acceptance/**/*.js\"",
"lint": "npm run prettier:check && npm run tslint",
"lint:fix": "npm run prettier:fix && npm run tslint:fix",
"tslint": "lb-tslint --project tsconfig.json",
Expand Down Expand Up @@ -47,19 +47,19 @@
"compilers"
],
"dependencies": {
"@loopback/context": "^4.0.0-alpha.30",
"@loopback/core": "^4.0.0-alpha.32",
"@loopback/metadata": "^4.0.0-alpha.9",
"@loopback/repository": "^4.0.0-alpha.28",
"@loopback/rest": "^4.0.0-alpha.24",
"@mean-expert/protoc-ts": "0.0.2",
"@loopback/context": "^1.0.0",
"@loopback/core": "^1.0.0",
"@loopback/metadata": "^1.0.0",
"@loopback/repository": "^1.0.0",
"@loopback/rest": "^1.0.0",
"@xanthous/protoc-ts": "^0.1.0",
"glob": "^7.1.2",
"grpc": "^1.6.6",
"protobufjs": "^6.8.0"
},
"devDependencies": {
"@loopback/build": "^4.0.0-alpha.13",
"@loopback/testlab": "^4.0.0-alpha.23",
"@loopback/build": "^1.0.0",
"@loopback/testlab": "^1.0.0",
"@types/glob": "^5.0.35"
}
}
16 changes: 16 additions & 0 deletions src/grpc.sequence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,20 @@ export class GrpcSequence implements GrpcSequenceInterface {
// Do something after call
return reply;
}

// tslint:disable-next-line:no-any
async clientStreamingCall(clientStream: grpc.ServerReadableStream<any>): Promise<any> {
const reply = await this.controller[this.method](clientStream);
return reply;
}

// tslint:disable-next-line:no-any
processServerStream(stream: grpc.ServerWriteableStream<any>): void {
this.controller[this.method](stream);
}

// tslint:disable-next-line:no-any
processBidiStream(stream: grpc.ServerDuplexStream<any, any>): void {
this.controller[this.method](stream);
}
}
106 changes: 75 additions & 31 deletions src/grpc.server.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import {
Application,
CoreBindings,
BindingKey,
Server,
ControllerClass,
} from '@loopback/core';
import {MetadataInspector} from '@loopback/metadata';
import {Context, inject, Constructor} from '@loopback/context';
import {Context, inject} from '@loopback/context';
import {GRPC_METHODS} from './decorators/grpc.decorator';
import {GrpcBindings} from './keys';
import {GrpcSequence} from './grpc.sequence';
import {Config} from './types';
import * as grpc from 'grpc';
import {Service} from 'protobufjs';
import {GrpcGenerator} from './grpc.generator';
import {BindingScope} from '@loopback/context/dist/src/binding';
const debug = require('debug')('loopback:grpc:server');
Expand All @@ -35,6 +35,9 @@ export class GrpcServer extends Context implements Server {
* GRPCBindings.CONFIG).
*
*/

listening: boolean = true;

constructor(
@inject(CoreBindings.APPLICATION_INSTANCE) protected app: Application,
@inject(GrpcBindings.GRPC_SERVER) protected server: grpc.Server,
Expand Down Expand Up @@ -97,51 +100,92 @@ export class GrpcServer extends Context implements Server {
// tslint:disable-next-line:no-any
const serviceMeta = pkgMeta[config.SERVICE_NAME] as any;
// tslint:disable-next-line:no-any
const serviceDef: grpc.ServiceDefinition<any> = serviceMeta.service;
const serviceDef: grpc.ServiceDefinition<any> =
{ [methodName]: serviceMeta.service[methodName] };
this.server.addService(serviceDef, {
[config.METHOD_NAME]: this.setupGrpcCall(ctor, methodName),
[config.METHOD_NAME]: this.setupGrpcCall(ctor, methodName, config),
});
}
}
/**
* @method setupGrpcCall
* @author Miroslav Bajtos
* @author Jonathan Casarrubias
* @author Simon Liang
* @license MIT
* @param prototype
* @param ctor
* @param methodName
*/
private setupGrpcCall<T>(
ctor: ControllerClass,
methodName: string,
config: Config.Method
// tslint:disable-next-line:no-any
): grpc.handleUnaryCall<grpc.ServerUnaryCall<any>, any> {
): grpc.handleCall<any, any> {
const context: Context = this;
return function(
// tslint:disable-next-line:no-any
call: grpc.ServerUnaryCall<any>,
// tslint:disable-next-line:no-any
callback: (err: any, value?: T) => void,
) {
handleUnary().then(
result => callback(null, result),
error => {
debugger;
callback(error);
},
);
async function handleUnary(): Promise<T> {
context.bind(GrpcBindings.CONTEXT).to(context);
context
.bind(GrpcBindings.GRPC_CONTROLLER)
.toClass(ctor)
.inScope(BindingScope.CONTEXT);
context.bind(GrpcBindings.GRPC_METHOD_NAME).to(methodName);
const sequence: GrpcSequence = await context.get(
GrpcBindings.GRPC_SEQUENCE,
);
return sequence.unaryCall(call);

context.bind(GrpcBindings.CONTEXT).to(context);
context
.bind(GrpcBindings.GRPC_CONTROLLER)
.toClass(ctor)
.inScope(BindingScope.CONTEXT);
context.bind(GrpcBindings.GRPC_METHOD_NAME).to(methodName);
const bindingKey: BindingKey<GrpcSequence> = BindingKey.create<GrpcSequence>(GrpcBindings.GRPC_SEQUENCE);

if (config.REQUEST_STREAM) {
if (config.RESPONSE_STREAM) {
// bidi stream
return function(
// tslint:disable-next-line:no-any
bidiStream: grpc.ServerDuplexStream<any, any>
) {
context.get(bindingKey).then((sequence: GrpcSequence) => sequence.processBidiStream(bidiStream));
};
} else {
// client streaming
return function(
// tslint:disable-next-line:no-any
clientStream: grpc.ServerReadableStream<any>,
// tslint:disable-next-line:no-any
callback: grpc.sendUnaryData<any>
) {
handleClientStream().then(
result => callback(null, result),
error => callback(error, null),
);
async function handleClientStream(): Promise<T> {
const sequence: GrpcSequence = await context.get(bindingKey);
return sequence.clientStreamingCall(clientStream);
}
}
}
};
} else {
if (config.RESPONSE_STREAM) {
// server streaming
return function(
// tslint:disable-next-line:no-any
serverStream: grpc.ServerWriteableStream<any>
) {
context.get(bindingKey).then((sequence: GrpcSequence) => sequence.processServerStream(serverStream));
}
} else {
// unary call
return function(
// tslint:disable-next-line:no-any
call: grpc.ServerUnaryCall<any>,
// tslint:disable-next-line:no-any
callback: grpc.sendUnaryData<any>,
) {
handleUnary().then(
result => callback(null, result),
error => callback(error, null),
);
async function handleUnary(): Promise<T> {
const sequence: GrpcSequence = await context.get(bindingKey);
return sequence.unaryCall(call);
}
};
}
}
}
}