grpc-server-ts
Version:
a grpc server side module built by typescrpt
161 lines (141 loc) • 4.29 kB
text/typescript
/**
* @author Xuezi
* @email xzj15859722542@hotmail.com
* @create date 2018-06-14 06:11:20
* @modify date 2018-06-14 06:11:20
* @desc [description]
*/
import * as GRPC from 'grpc';
import * as protoLoader from '@grpc/proto-loader';
export class ServiceContainer {
static services: { service: any, target: Function }[] = [];
static routes: { target: Function, route: Function, func?: Function }[] = [];
/**
* @description registry grpc service
* @author Xuezi
* @static
* @param {Function} target service constructor
* @param {string} path proto file path
* @memberof ServiceContainer
*/
static registryService(target: Function, path: string) {
let packageDefinition = protoLoader.loadSync(path, {
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true
});
let protoDescriptor = GRPC.loadPackageDefinition(packageDefinition);
const packages = Object.keys(protoDescriptor);
for (let packageKey of packages) {
for (let key in protoDescriptor[packageKey]) {
this._setServiceClient(protoDescriptor[packageKey][key], target);
// if (protoDescriptor[packageKey][key].hasOwnProperty('service')) {
// this.services.push({ service: protoDescriptor[packageKey][key]['service'], target });
// }
}
}
}
private static _setServiceClient(service: any, target: Function) {
if(!service) {
return;
}
if(service.name === 'ServiceClient') {
this.services.push({service: service['service'], target});
} else {
for(const key in service) {
this._setServiceClient(service[key], target);
}
}
}
static registryRoute(target: Function, route: Function) {
if (this.routes.find(r => (r.target === target && r.route === route))) {
return;
}
this.routes.push({ target, route });
}
static generateRouteFunc(...args) {
return this._generateRouteFunc.apply(this, args);
}
private static _generateRouteFunc(service: any, route: Function): Function {
let key = route.name;
let rawFunc = service[key];
let {requestStream, responseStream} = rawFunc;
let func;
if (requestStream && responseStream) {
// requestStream: true
// responseStream: true
func = async function(call) {
call.on('data', async function(chunk) {
try {
let result = await route(chunk);
call.write(result);
} catch (e) {
call.emit('error', e);
}
});
call.on('error', error => {
console.error(error);
});
call.on('end', () => {
call.end && call.end();
});
};
} else if (requestStream && !responseStream) {
// requestStream: true
// responseStream: false
func = async function(call) {
let callback = arguments[1];
call.on('data', async chunk => {
try {
let result = await route(chunk);
callback(null, result);
} catch (e) {
callback(e);
}
});
call.on('error', error => {
console.error(error);
});
call.on('end', () => {
call.end && call.end();
});
};
} else if (!requestStream && responseStream) {
// requestStream: false
// responseStream: true
func = async function(call) {
try {
let result = await route(call.request);
call.write(result);
} catch (e) {
call.emit('error', e);
}
call.on('error', error => {
console.error(error);
});
call.on('end', () => {
call.end && call.end();
});
};
} else {
// requestStream: false
// responseStream: false
func = async function(call) {
let callback = arguments[1];
try {
let result = await route(call.request);
callback(null,result);
} catch (e) {
callback(e);
}
};
}
return func;
}
static getService(target: Function): any[] {
let services = this.services.filter(service => service.target === target);
return services;
}
}