Skip to content

Commit 62ff577

Browse files
author
暴雨也要吃麻辣烫
committed
style: 修改函数封装,优化加载
1 parent f23e243 commit 62ff577

File tree

9 files changed

+199
-146
lines changed

9 files changed

+199
-146
lines changed

README.md

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,40 @@
11
## @142vip/egg-grpc-client
22

3-
### 支持的功能
3+
4+
#### 可能有用
5+
6+
- 客户端插件:[egg-grpc-client](https://github.com/142vip/egg-grpc-client)
7+
- 服务端插件:[egg-grpc-server](https://github.com/142vip/egg-grpc-server)
8+
9+
10+
#### 支持的功能
411

512
- [x] 支持单个grpc-server服务端连接实例
613
- [x] 支持多个grpc-server服务端连接实例
7-
- [x] 灵活配置app、agent挂载
8-
- [x] 详细的日志报警机制
14+
- [x] 灵活配置app、agent挂载,灵活使用egg.js全局对象
15+
- [x] 详细的日志报警机制,支持日志切割与划分
916

10-
### 安装
17+
#### 安装
1118

1219
```bash
1320
## 安装最新版grpc-client插件
14-
npm i @142vipegg-grpc-client --save
15-
21+
npm i @142vip/egg-grpc-client --save
1622
## 安装制定版本grpc-client插件
17-
npm i @142vipegg-grpc-client@xxx --save
23+
npm i @142vip/egg-grpc-client@xxx --save
1824
```
1925

20-
### 快速使用
26+
#### 快速使用
2127

2228
在plugin.js插件配置文件中配置egg-grpc-client
2329
```js
2430
// {app_root}/config/plugin.js
2531
exports.grpcClient = {
2632
enable: true,
27-
package: '@142vipegg-grpc-client',
33+
package: '@142vip/egg-grpc-client',
2834
};
2935
```
3036

31-
### 默认配置
37+
#### 默认配置
3238

3339
```js
3440
// {app_root}/config/config.default.js
@@ -84,7 +90,7 @@ exports.grpcClient = {
8490

8591
更多默认配置,请查看[config/config.default.js](config/config.default.js)
8692

87-
### 使用示例
93+
#### 使用示例
8894

8995
```js
9096
// 连接单个grpc server时
@@ -96,9 +102,9 @@ ctx.grpcClient.get('xxx').xxxx
96102

97103
```
98104

99-
完整grpc客户端、服务端插件使用示例,可以参考[142vip/egg-grpc-demo](https://github.com/142vip/egg-grpc-demo)
105+
完整grpc客户端、服务端插件使用示例,可以参考[egg-grpc-client/example](https://github.com/142vip/egg-grpc-client/example)
100106

101-
### 证书
107+
#### 证书
102108

103109
```text
104110
MIT License
@@ -122,6 +128,4 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
122128
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
123129
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
124130
SOFTWARE.
125-
126-
127131
```

agent.js

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,29 @@ const { creatGRPClientInstance } = require('./libs');
33
const assert = require('assert');
44
module.exports = agent => {
55
const now = new Date().getTime();
6-
76
const config = agent.config.grpcClient;
87

9-
assert(typeof config.agent === 'boolean', `[egg-grpc-client] app just is true or false , but now agent is ${config.agent}`);
10-
assert(!(config.client == null && config.clients == null) || (config.client != null && config.clients != null), '[egg-grpc-client] only one can exist between client and clients in config.js file');
8+
assert(
9+
typeof config.agent === 'boolean',
10+
`[egg-grpc-client] app just is true or false , but now agent is ${config.agent}`
11+
);
12+
assert(
13+
!(config.client == null && config.clients == null) ||
14+
(config.client != null && config.clients != null),
15+
'[egg-grpc-client] only one can exist between client and clients in config.js file'
16+
);
17+
1118
// 启动之前
19+
1220
agent.beforeStart(async () => {
1321
if (config.agent) {
1422
// 加载到agent对象上,创建一个实例
1523
agent.addSingleton('grpcClient', await creatGRPClientInstance);
16-
agent.logger.info(`[egg-grpc-client] load grpc client to agent.js (${new Date().getTime() - now}ms)`);
24+
agent.logger.info(
25+
`[egg-grpc-client] load grpc client to agent.js (${
26+
new Date().getTime() - now
27+
}ms)`
28+
);
1729
}
1830
});
19-
20-
2131
};

app.js

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,26 @@ const assert = require('assert');
44
module.exports = app => {
55
const now = new Date().getTime();
66
const config = app.config.grpcClient;
7-
assert(typeof config.app === 'boolean', `[egg-grpc-client] app just is true or false , but now agent is ${config.agent}`);
8-
assert(!(config.client == null && config.clients == null) || (config.client != null && config.clients != null), '[egg-grpc-client] only one can exist between client and clients in config.js file');
7+
8+
assert(
9+
typeof config.app === 'boolean',
10+
`[egg-grpc-client] app just is true or false , but now agent is ${config.agent}`
11+
);
12+
assert(
13+
!(config.client == null && config.clients == null) ||
14+
(config.client != null && config.clients != null),
15+
'[egg-grpc-client] only one can exist between client and clients in config.js file'
16+
);
917
// 启动之前
1018
app.beforeStart(async () => {
1119
if (config.app) {
1220
// 加载到agent对象上,创建一个实例
1321
app.addSingleton('grpcClient', await creatGRPClientInstance);
14-
app.logger.info(`[egg-grpc-client] load grpc client to app.js (${new Date().getTime() - now}ms)`);
22+
app.logger.info(
23+
`[egg-grpc-client] load grpc client to app.js (${
24+
new Date().getTime() - now
25+
}ms)`
26+
);
1527
}
1628
});
1729
};
18-

app/extend/context.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
const GrpcClient = Symbol('Context#grpcClient');
44

55
module.exports = {
6-
// 新增grpcClient属性,ctx.grpcServer.xxx
6+
/**
7+
* 新增grpcClient属性,ctx.grpcServer.xxx
8+
* @return {*}
9+
*/
710
get grpcClient() {
811
if (!this[GrpcClient]) {
912
this[GrpcClient] = this.app.grpcClient;

config/config.default.js

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
11
'use strict';
22

3-
// 配置选项:
4-
// keepCase –保留字段名称。 默认设置是将它们更改为驼峰式。
5-
// longs –应该用于表示long值的类型。 有效选项是Number和String 。 默认为库中的Long对象类型。
6-
// enums –应该用于表示enum值的类型。 唯一有效的选项是String 。 默认为数值。
7-
// bytes –应该用于表示bytes值的类型。 有效选项是Array和String 。 默认是使用Buffer 。
8-
// defaults –在输出对象上设置默认值。 默认为false 。
9-
// arrays –为空数组设置缺少的数组值,即使defaults值为false 。 默认为false 。
10-
// objects –即使defaults值为false也为缺少的对象值设置空对象。 默认为false 。
11-
// oneofs –将虚拟的oneof属性设置为当前字段的名称
12-
13-
143
/**
15-
* egg-grpc-client default config
4+
* 配置选项:
5+
* keepCase –保留字段名称。 默认设置是将它们更改为驼峰式。
6+
* longs –应该用于表示long值的类型。 有效选项是Number和String 。 默认为库中的Long对象类型。
7+
* enums –应该用于表示enum值的类型。 唯一有效的选项是String 。 默认为数值。
8+
* bytes –应该用于表示bytes值的类型。 有效选项是Array和String 。 默认是使用Buffer 。
9+
* defaults –在输出对象上设置默认值。 默认为false 。
10+
* arrays –为空数组设置缺少的数组值,即使defaults值为false 。 默认为false 。
11+
* objects –即使defaults值为false也为缺少的对象值设置空对象。 默认为false 。
12+
* oneofs –将虚拟的oneof属性设置为当前字段的名称
1613
*/
1714
exports.grpcClient = {
1815
// protoDir: 'app/grpc',
@@ -70,6 +67,4 @@ exports.grpcClient = {
7067
// },
7168
app: true,
7269
agent: false,
73-
74-
7570
};

libs/index.js

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use strict';
22

33
const path = require('path');
4-
const loadProto = require('./loadProto');
4+
const loadGrpcProto = require('./loadGrpcProto');
55
const assert = require('assert');
66

77
/**
@@ -10,15 +10,28 @@ const assert = require('assert');
1010
* @param app
1111
*/
1212
async function creatGRPClientInstance(config, app) {
13+
assert(
14+
config.protoDir != null,
15+
'[egg-grpc-client] protoDir is not exist in config.js file , default protoDir: app/grpc'
16+
);
17+
assert(
18+
config.serviceDir != null,
19+
'[egg-grpc-client] serviceDir is not exist in config.js file , default serviceDir: app/grpc'
20+
);
21+
assert(
22+
config.host != null,
23+
'[egg-grpc-client] host is not exist in config.js file , default host: app/grpc'
24+
);
25+
assert(
26+
config.port != null,
27+
'[egg-grpc-client] port is not exist in config.js file , default port: app/grpc'
28+
);
29+
assert(
30+
config.loaderOptions != null,
31+
'[egg-grpc-client] loaderOptions is not exist in config.js file , please see https://github.com/142vip/egg-grpc-client/blob/master/config/config.default.js'
32+
);
1333

14-
15-
assert(config.protoDir != null, '[egg-grpc-client] protoDir is not exist in config.js file , default protoDir: app/grpc');
16-
assert(config.serviceDir != null, '[egg-grpc-client] serviceDir is not exist in config.js file , default serviceDir: app/grpc');
17-
assert(config.host != null, '[egg-grpc-client] host is not exist in config.js file , default host: app/grpc');
18-
assert(config.port != null, '[egg-grpc-client] port is not exist in config.js file , default port: app/grpc');
19-
assert(config.loaderOptions != null, '[egg-grpc-client] loaderOptions is not exist in config.js file , please see https://github.com/142vip/egg-grpc-client/blob/master/config/config.default.js');
20-
21-
const loadProtoInstance = new loadProto(app);
34+
const loadProtoInstance = new loadGrpcProto(app);
2235
const protoFileDir = path.join(app.baseDir, config.protoDir);
2336
return await loadProtoInstance.getGrpcClient(protoFileDir, config);
2437
}

libs/loadGrpcProto.js

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
'use strict';
2+
const fs = require('fs');
3+
const path = require('path');
4+
const protoLoader = require('@grpc/proto-loader');
5+
const grpc = require('@grpc/grpc-js');
6+
7+
class loadGrpcProto {
8+
constructor(app) {
9+
this.app = app;
10+
this.config = app.config;
11+
this.logger = app.logger;
12+
}
13+
14+
/**
15+
* 获取proto文件路径列表
16+
* @param protoDir
17+
*/
18+
async getProtoFileList(protoDir) {
19+
const fileStat = fs.statSync(protoDir);
20+
if (!fileStat.isDirectory()) {
21+
this.logger.error(`[egg-grpc-client] isn't dir: ${protoDir} `);
22+
return;
23+
}
24+
const filePathNameList = fs.readdirSync(protoDir);
25+
// 过滤
26+
return filePathNameList
27+
.filter(name => name.endsWith('.proto'))
28+
.map(filePathName => path.join(protoDir, filePathName));
29+
}
30+
31+
/**
32+
* 获取grpc client实例
33+
* @param protoDir
34+
* @param config
35+
*/
36+
async getGrpcClient(protoDir, config) {
37+
const { host, port, loaderOptions } = config;
38+
const protoList = await this.getProtoFileList(protoDir);
39+
const grpcClient = {};
40+
for (const protoTargetPath of protoList) {
41+
const packageDefinition = protoLoader.loadSync(
42+
protoTargetPath,
43+
loaderOptions
44+
);
45+
const grpcObject = grpc.loadPackageDefinition(packageDefinition);
46+
// grpc对象遍历处理
47+
Object.values(grpcObject).forEach(packageObj => {
48+
for (const serviceClass of Object.values(packageObj)) {
49+
if (serviceClass.service != null) {
50+
const grpcClientInstance = new serviceClass(
51+
`${host}:${port}`,
52+
grpc.credentials.createInsecure()
53+
);
54+
// console.log(Object.getOwnPropertyNames(serviceClass.prototype));
55+
// 遍历方法 serviceClass.prototype 替换 grpcClientInstance.__proto__
56+
Object.getOwnPropertyNames(serviceClass.prototype).forEach(
57+
name => {
58+
if (name !== 'constructor') {
59+
grpcClient[name] = async requestData =>
60+
await this.handleGrpcClientMethod(
61+
grpcClientInstance,
62+
name,
63+
requestData
64+
);
65+
}
66+
}
67+
);
68+
}
69+
}
70+
});
71+
}
72+
return grpcClient;
73+
}
74+
75+
/**
76+
*
77+
* 对grpcClient客户端方法,进行封装处理
78+
* 支持async/await调用
79+
* @param clientInStance grpc客户端对象实例
80+
* @param name 方法名
81+
* @param requestData 请求数据
82+
*/
83+
async handleGrpcClientMethod(clientInStance, name, requestData) {
84+
const { app } = this;
85+
if (typeof requestData !== 'object') {
86+
app.logger.error(
87+
'[egg-grpc-client] grpc client method params error ,please look at docs'
88+
);
89+
return;
90+
}
91+
return new Promise((resolve, reject) => {
92+
// todo 支持grpc传输字段 自定义 ,默认 data
93+
clientInStance[name](
94+
{ data: JSON.stringify(requestData) },
95+
(err, result) => {
96+
// 将结果反序列化,
97+
if (err == null) {
98+
const { data } = result;
99+
if (data == null) {
100+
app.logger.info(
101+
'[egg-grpc-client] no key-word data in rpc message struct ,please check .proto file'
102+
);
103+
return;
104+
}
105+
resolve(JSON.parse(data));
106+
}
107+
reject(err, result);
108+
}
109+
);
110+
});
111+
}
112+
}
113+
114+
module.exports = loadGrpcProto;

0 commit comments

Comments
 (0)