Skip to content

Commit

Permalink
新增 grpc client 多实例
Browse files Browse the repository at this point in the history
  • Loading branch information
xdxiaodong committed Dec 5, 2019
1 parent ee585f5 commit eafb8b7
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 93 deletions.
30 changes: 17 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +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`
// clientSsl: {
// enable: false,
// grpc.credentials.createSsl
// rootCerts: 'config/cert/server.crt',
// options: {
// "grpc.ssl_target_name_override": 'example.server',
// "grpc.default_authority": 'example.server'
// }
// }
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
30 changes: 17 additions & 13 deletions README.zh_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +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`
// clientSsl: {
// enable: false,
// grpc.credentials.createSsl
// rootCerts: 'config/cert/server.crt',
// options: {
// "grpc.ssl_target_name_override": 'example.server',
// "grpc.default_authority": 'example.server'
// }
// }
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
27 changes: 1 addition & 26 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,8 @@
'use strict';

const loader = require('./lib/grpc_loader');
const fs = require('fs');
const path = require('path');


module.exports = app => {
// grpc.setLogger(app.coreLogger);
const GrpcLoader = app.loader.GrpcLoader = loader(app);
new GrpcLoader({}).load();
// grpc ssl
if (app.config.grpc.clientSsl.enable) {
if (app.config.grpc.clientSsl.rootCerts.trim() !== '') {
const rootCerts = path.join(app.baseDir, app.config.grpc.clientSsl.rootCerts)
if (fs.existsSync(rootCerts)) {
app.grpc.clientSsl.rootCerts = fs.readFileSync(rootCerts);
}
}
if (app.config.grpc.clientSsl.privateKey.trim() != '') {
const privateKey = path.join(app.baseDir, app.config.grpc.clientSsl.privateKey)
if (fs.existsSync(privateKey)) {
app.grpc.clientSsl.privateKey = fs.readFileSync(privateKey);
}
}
if (app.config.grpc.clientSsl.certChain.trim() != '') {
const certChain = path.join(app.baseDir, app.config.grpc.clientSsl.certChain)
if (fs.existsSync(certChain)) {
app.grpc.clientSsl.certChain = fs.readFileSync(certChain);
}
}
}
loader(app);
};
8 changes: 0 additions & 8 deletions app/extend/application.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
'use strict';

const GrpcBaseClass = require('../../lib/base_grpc');
const GRPC = Symbol('Application#grpc');

module.exports = {

Expand Down Expand Up @@ -37,11 +36,4 @@ module.exports = {
get GrpcBaseClass() {
return GrpcBaseClass;
},
get grpc() {
// this 就是 app 对象,在其中可以调用 app 上的其他方法,或访问属性
if (!this[GRPC]) {
this[GRPC] = { clientSsl: { rootCerts: null, privateKey: null, certChain: null } }
}
return this[GRPC];
}
};
70 changes: 45 additions & 25 deletions config/config.default.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* 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)`
Expand All @@ -18,29 +18,49 @@
* @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,
/**
* 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'
}
}
// 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'
// }
// }
// },
// }
};
8 changes: 4 additions & 4 deletions lib/base_grpc.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ 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
Expand All @@ -43,12 +45,10 @@ module.exports = class BaseGrpc {
if (!this.config.clientSsl.enable) {
this[CLIENT] = new this.ProtoClass(this.config.endpoint, grpc.credentials.createInsecure(), Object.assign({}, this.config.clientOpts));
} else {
// TODO: 多个grpc实例
const ssl_creds = grpc.credentials.createSsl(this.app.grpc.clientSsl.rootCerts, this.app.grpc.clientSsl.privateKey, this.app.grpc.clientSsl.certChain, this.config.clientSsl.verifyOptions)
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
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;
};
}

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "egg-grpc-ssl",
"version": "1.0.4",
"version": "1.0.6",
"description": "grpc plugin for egg",
"eggPlugin": {
"name": "grpc"
Expand Down

0 comments on commit eafb8b7

Please sign in to comment.