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
29 changes: 21 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@
## Install

```bash
$ npm i egg-grpc --save
$ npm i egg-grpc-ssl --save
```

```js
// {app_root}/config/plugin.js
exports.grpc = {
enable: true,
package: 'egg-grpc',
package: 'egg-grpc-ssl',
};
```

Expand All @@ -41,10 +41,23 @@ exports.grpc = {
```js
// {app_root}/config/config.default.js
exports.grpc = {
endpoint: 'localhost:50051',
// dir: 'app/proto', // proto files dir, relative path
// property: 'grpc', // default attach to `ctx.grpc.**`
// loadOpts: { convertFieldsToCamelCase: true, }, // message field case: `string user_name` -> `userName`
clients: {
grpc1: {
property: 'grpc1', // default attach to `ctx.grpc.**`
endpoint: 'localhost:50051',
// dir: 'app/proto', // proto files dir, relative path
// loadOpts: { convertFieldsToCamelCase: true }, // message field case: `string user_name` -> `userName`
clientSsl: {
enable: false,
// grpc.credentials.createSsl
rootCerts: 'config/cert/server.crt',
options: {
'grpc.ssl_target_name_override': 'example.server',
'grpc.default_authority': 'example.server',
},
},
},
},
};
```

Expand Down Expand Up @@ -211,11 +224,11 @@ stream.end(data3);

## Example

see [grpc.tests.js](test/grpc.tests.js).
see [test/grpc.tests.js](test/grpc.tests.js).

## Questions & Suggestions

Please open an issue [here](https://github.com/eggjs/egg/issues).
Please open an issue [here](https://github.com/xdxiaodong/egg-grpc/issues).

## License

Expand Down
29 changes: 21 additions & 8 deletions README.zh_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@
## 安装

```bash
$ npm i egg-grpc --save
$ npm i egg-grpc-ssl --save
```

```js
// {app_root}/config/plugin.js
exports.grpc = {
enable: true,
package: 'egg-grpc',
package: 'egg-grpc-ssl',
};
```

Expand All @@ -41,10 +41,23 @@ exports.grpc = {
```js
// {app_root}/config/config.default.js
exports.grpc = {
endpoint: 'localhost:50051',
// dir: 'app/proto', // proto 文件目录,相对路径
// property: 'grpc', // 默认挂载到 `ctx.grpc.**`
// loadOpts: { convertFieldsToCamelCase: true, }, // message field case: `string user_name` -> `userName`
clients: {
grpc1: {
property: 'grpc1', // default attach to `ctx.grpc.**`
endpoint: 'localhost:50051',
// dir: 'app/proto', // proto files dir, relative path
// loadOpts: { convertFieldsToCamelCase: true }, // message field case: `string user_name` -> `userName`
clientSsl: {
enable: false,
// grpc.credentials.createSsl
rootCerts: 'config/cert/server.crt',
options: {
'grpc.ssl_target_name_override': 'example.server',
'grpc.default_authority': 'example.server',
},
},
},
},
};
```

Expand Down Expand Up @@ -211,11 +224,11 @@ stream.end(data3);

## 示例

参见 [grpc.tests.js](test/grpc.tests.js).
参见 [test/grpc.tests.js](test/grpc.tests.js).

## 问题反馈

访问并发起 [issue](https://github.com/eggjs/egg/issues).
访问并发起 [issue](https://github.com/xdxiaodong/egg-grpc/issues).

## License

Expand Down
3 changes: 1 addition & 2 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,5 @@ const loader = require('./lib/grpc_loader');

module.exports = app => {
// grpc.setLogger(app.coreLogger);
const GrpcLoader = app.loader.GrpcLoader = loader(app);
new GrpcLoader({}).load();
loader(app);
};
59 changes: 51 additions & 8 deletions config/config.default.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,63 @@
* grpc config
* @member Config#grpc
* @property {String} dir - proto files dir, relative path
* @property {String} property - default attach to `ctx.grpc.**`
* @property {String} property - default attach to `ctx.grpc.**`,与object.key同名,存在多个实例时需要配置该项
* @property {Object} loadOpts - options pass to `grpc.load(file, type, opts)`
* @property {Boolean} loadOpts.convertFieldsToCamelCase - default to true, `string user_name` -> `userName`
* @property {Object} clientOpts - options pass to `new Client(host, credentials, opts)`
* @property {String} endpoint - default andress to connect, for debug or showcase purpose
* @property {Number} timeout - default 5000ms
* @property {Boolean} clientSsl.enable - enable client ssl
* @property {Buffer} clientSsl.rootCerts - The root certificate data file path,作为grpc client时仅提供该项作为证书即可
* @property {Buffer} clientSsl.privateKey - The client certificate private key file path, if applicable
* @property {Buffer} clientSsl.certChain - The client certificate cert chain file path, if applicable
* @property {Object} clientSsl.verifyOptions - Additional peer verification options, if desired
* @property {Object} clientSsl.options - 主要用于grpc.ssl_target_name_override和grpc.default_authority的配置
*/
exports.grpc = {
dir: 'app/proto',
property: 'grpc',
loadOpts: {
convertFieldsToCamelCase: true,
default: {
dir: 'app/proto',
property: 'grpc',
loadOpts: {
convertFieldsToCamelCase: true,
},
clientOpts: {},
endpoint: 'localhost:50051',
timeout: 5000,
/**
* 2019-12-03 by 张晓东
* 通过扩展原有配置的形式,使其支持tls/ssl安全
*/
clientSsl: {
enable: false,
// grpc.credentials.createSsl
// config/grpc/cert.server.crt
rootCerts: '', //
privateKey: '', // 作为grpc client时无需填写
certChain: '', // 作为grpc client时无需填写
verifyOptions: {},
options: {
'grpc.ssl_target_name_override': 'example.server',
'grpc.default_authority': 'example.server',
},
},
},
clientOpts: {},
endpoint: 'localhost:50051',
timeout: 5000,
// clients: {
// // this.ctx.grpc1
// grpc1: {
// property: 'grpc1',
// dir: 'grpc',
// // 服务端地址
// endpoint: 'localhost:8090',
// clientSsl: {
// enable: true,
// // grpc.credentials.createSsl
// rootCerts: 'grpc/cert/server.crt',
// options: {
// "grpc.ssl_target_name_override": 'example.server',
// "grpc.default_authority": 'example.server'
// }
// }
// },
// }
};
16 changes: 11 additions & 5 deletions lib/base_grpc.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ module.exports = class BaseGrpc {
constructor(ctx, ProtoClass) {
this.ctx = ctx;
this.app = ctx.app;
this.config = this.app.config.grpc;
// this.config = this.app.config.grpc;
const key = ProtoClass.grpcconfig; // 获取对应的config的key值
this.config = this.app.config.grpc.clients[key]; // 获取对应的key值的config对象
this.ProtoClass = ProtoClass;

// delegate client rpc to this
for (const key of Object.keys(this.ProtoClass.service)) {
this[key] = function(...args) {
this[key] = function (...args) {
return this._invokeRPC(key, ...args);
};
}
Expand All @@ -40,9 +42,13 @@ module.exports = class BaseGrpc {
if (!this[CLIENT]) {
// options should NOT reuse, otherwise the user-agent will oom you!
// https://github.com/grpc/grpc/blob/master/src/node/src/client.js#L464
this[CLIENT] = new this.ProtoClass(this.config.endpoint, grpc.credentials.createInsecure(), Object.assign({}, this.config.clientOpts));
if (!this.config.clientSsl.enable) {
this[CLIENT] = new this.ProtoClass(this.config.endpoint, grpc.credentials.createInsecure(), Object.assign({}, this.config.clientOpts));
} else {
const ssl_creds = grpc.credentials.createSsl(this.config.clientSsl.rootCertsData, this.config.clientSsl.privateKeyData, this.config.clientSsl.certChainData, this.config.clientSsl.verifyOptions);
this[CLIENT] = new this.ProtoClass(this.config.endpoint, ssl_creds, Object.assign({}, this.config.clientOpts, this.config.clientSsl.options));
}
}
// TODO: config.ssl
return this[CLIENT];
}

Expand Down Expand Up @@ -83,7 +89,7 @@ module.exports = class BaseGrpc {
metadata = args[0];
options = undefined;
} else {
[ metadata, options, callback ] = args;
[metadata, options, callback] = args;
}
const invokeArgs = this._beforeRequest({ client, rpc, metadata, options, attrs, callback });
return this._invokeClientStreamRequest(invokeArgs);
Expand Down
56 changes: 53 additions & 3 deletions lib/grpc_loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,57 @@ const grpc = require('grpc');
const traverse = require('traverse');
const extend = require('extend2');
const debug = require('debug')('grpc');
const fs = require('fs');

module.exports = app => {
const config = app.config.grpc;
// 获取多个配置
const multiConfig = app.config.grpc.clients;
// 获取所有配置的对象键值
const keys = Object.keys(multiConfig);
// 循环获取多个配置,进行加载,采用类官方插件多实例实现方案
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
// 合并默认配置
const config = Object.assign({}, app.config.grpc.default);
Object.assign(config, multiConfig[key]);
const config_clientSsl = Object.assign({}, config.clientSsl);
Object.assign(config.clientSsl, app.config.grpc.default.clientSsl);
Object.assign(config.clientSsl, config_clientSsl);
const GrpcLoader = createGrpc(config, app);
new GrpcLoader({}).load();
}
};

/**
* @param {Object} config 框架处理之后的配置项,如果应用配置了多个实例,会将每一个配置项分别传入并调用多次该函数
* @param {Application} app 当前的应用
* @return {Object} 返回创建的实例
*/
function createGrpc(config, app) {
// grpc ssl
if (config.clientSsl.enable) {
config.clientSsl.rootCertsData = undefined;
config.clientSsl.privateKeyData = undefined;
config.clientSsl.certChainData = undefined;
if (config.clientSsl.rootCerts !== '') {
const rootCerts = path.join(app.baseDir, config.clientSsl.rootCerts);
if (fs.existsSync(rootCerts)) {
config.clientSsl.rootCertsData = fs.readFileSync(rootCerts);
}
}
if (config.clientSsl.privateKey !== '') {
const privateKey = path.join(app.baseDir, config.clientSsl.privateKey);
if (fs.existsSync(privateKey)) {
config.clientSsl.privateKeyData = fs.readFileSync(privateKey);
}
}
if (config.clientSsl.certChain !== '') {
const certChain = path.join(app.baseDir, config.clientSsl.certChain);
if (fs.existsSync(certChain)) {
config.clientSsl.certChainData = fs.readFileSync(certChain);
}
}
}

const defaults = {
call: true,
Expand Down Expand Up @@ -44,13 +92,14 @@ module.exports = app => {

// traverse origin grpc proto to extract rpc service
// `/example.Test/Echo` -> `app.grpcClasses.example.test` -> `yield ctx.grpc.example.test.echo()`
traverse(exports).forEach(function(proto) {
traverse(exports).forEach(function (proto) {
/* istanbul ignore next */
if (this.circular) this.remove();

if (proto.name === 'Client' || proto.name === 'ServiceClient') {
const properties = this.path.map(camelize);
proto.paths = properties;
proto.grpcconfig = config.property; // key
const item = {
fullpath,
properties,
Expand Down Expand Up @@ -83,4 +132,5 @@ module.exports = app => {
}

return GrpcLoader;
};
}

12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "egg-grpc",
"version": "1.0.3",
"name": "egg-grpc-ssl",
"version": "1.0.6",
"description": "grpc plugin for egg",
"eggPlugin": {
"name": "grpc"
Expand Down Expand Up @@ -50,12 +50,12 @@
},
"repository": {
"type": "git",
"url": "git+https://github.com/eggjs/egg-grpc.git"
"url": "git+https://github.com/xdxiaodong/egg-grpc.git"
},
"bugs": {
"url": "https://github.com/eggjs/egg/issues"
"url": "https://github.com/xdxiaodong/egg-grpc/issues"
},
"homepage": "https://github.com/eggjs/egg-grpc#readme",
"author": "TZ <atian25@qq.com>",
"homepage": "https://github.com/xdxiaodong/egg-grpc#readme",
"author": "xiaodong <yunfei_vip@qq.com>",
"license": "MIT"
}