Compare commits
63 Commits
Author | SHA1 | Date |
---|---|---|
|
8a5568de77 | |
|
57cd21060b | |
|
7fa34ff6a6 | |
|
22c0e57947 | |
|
cdea9a26b1 | |
|
50ac48e026 | |
|
3c6840bdd7 | |
|
4c9af68899 | |
|
cc6667c5b1 | |
|
d6ee163a36 | |
|
41e3965870 | |
|
a3feb781a7 | |
|
910f7e4bfe | |
|
7f1870778e | |
|
d044e6cef4 | |
|
005134d725 | |
|
e3cb1d5955 | |
|
6df7ece0a8 | |
|
27a8fa7651 | |
|
a3f33bd901 | |
|
194629a25b | |
|
34055b4117 | |
|
9ae37cef32 | |
|
a9a7fe64d8 | |
|
3940268149 | |
|
2b703c0621 | |
|
01affdbb51 | |
|
643dd12ab8 | |
|
c9f5808675 | |
|
3e9670d9cf | |
|
d5e2dd8ae0 | |
|
61a415ec6f | |
|
17ea984a61 | |
|
180dcf72fe | |
|
8c06bda57f | |
|
b219a870bd | |
|
e5c1359509 | |
|
744fc56f29 | |
|
1a63399df0 | |
|
f1bfe2d065 | |
|
371f2dbc82 | |
|
84f6032f44 | |
|
133550f482 | |
|
edb996043e | |
|
688ca8f38d | |
|
614623577b | |
|
2ea1abb9b0 | |
|
4182e142bf | |
|
f6d5a7462a | |
|
989eba2dc9 | |
|
34368536f9 | |
|
f7b9ce72ba | |
|
b06340b757 | |
|
8caaf2504c | |
|
7793dd5a73 | |
|
dfde567b25 | |
|
06cad6fa4e | |
|
d81a4ab8e9 | |
|
93c3559a05 | |
|
2942e19b90 | |
|
3b4f7e6b80 | |
|
e88d81bf16 | |
|
26f8ceebae |
10
.travis.yml
10
.travis.yml
|
@ -3,18 +3,20 @@ language: node_js
|
||||||
node_js:
|
node_js:
|
||||||
- '8'
|
- '8'
|
||||||
- '10'
|
- '10'
|
||||||
|
- '12'
|
||||||
jdk: oraclejdk8
|
jdk: oraclejdk8
|
||||||
before_install:
|
before_install:
|
||||||
- echo $JAVA_HOME
|
- echo $JAVA_HOME
|
||||||
- java -version
|
- java -version
|
||||||
- 'wget https://github.com/alibaba/nacos/releases/download/0.5.0/nacos-server-0.5.0.tar.gz'
|
- 'wget https://github.com/alibaba/nacos/releases/download/1.0.0/nacos-server-1.0.0.tar.gz'
|
||||||
- 'wget https://github.com/gxcsoccer/PDisk/releases/download/1.0.0/startup.sh'
|
- 'wget https://github.com/gxcsoccer/PDisk/releases/download/1.0.1/startup.sh'
|
||||||
- 'tar xf nacos-server-0.5.0.tar.gz'
|
- 'tar xf nacos-server-1.0.0.tar.gz'
|
||||||
- 'mv ./startup.sh ./nacos/bin/startup.sh'
|
- 'mv ./startup.sh ./nacos/bin/startup.sh'
|
||||||
- 'chmod 755 ./nacos/bin/startup.sh'
|
- 'chmod 755 ./nacos/bin/startup.sh'
|
||||||
- 'nohup ./nacos/bin/startup.sh -m standalone 2>&1 &'
|
- 'nohup ./nacos/bin/startup.sh -m standalone 2>&1 &'
|
||||||
- 'sleep 30'
|
- 'sleep 30'
|
||||||
- 'curl "127.0.0.1:8848/nacos/v1/ns/api/hello"'
|
- 'cat nohup.out'
|
||||||
|
- 'curl "127.0.0.1:8848/nacos/v1/ns/operator/metrics"'
|
||||||
install:
|
install:
|
||||||
- npm i npminstall && npminstall
|
- npm i npminstall && npminstall
|
||||||
- npm run bootstrap
|
- npm run bootstrap
|
||||||
|
|
6
AUTHORS
6
AUTHORS
|
@ -1,7 +1,9 @@
|
||||||
# Ordered by date of first contribution.
|
# Ordered by date of first contribution.
|
||||||
# Auto-generated by 'contributors' on Wed, 12 Dec 2018 06:57:02 GMT.
|
# Auto-generated by 'contributors' on Tue, 26 Jan 2021 05:30:11 GMT.
|
||||||
# https://github.com/xingrz/node-contributors
|
# https://github.com/xingrz/node-contributors
|
||||||
|
|
||||||
yanlinly <yan.lin2009@163.com> (https://github.com/yanlinly)
|
yanlinly <yan.lin2009@163.com>
|
||||||
zōng yǔ <gxcsoccer@126.com> (https://github.com/gxcsoccer)
|
zōng yǔ <gxcsoccer@126.com> (https://github.com/gxcsoccer)
|
||||||
Harry Chen <czy88840616@gmail.com> (https://github.com/czy88840616)
|
Harry Chen <czy88840616@gmail.com> (https://github.com/czy88840616)
|
||||||
|
zōng yǔ <gxcsoccer@users.noreply.github.com>
|
||||||
|
netfoxor <netfoxor@qq.com>
|
||||||
|
|
34
CHANGELOG.md
34
CHANGELOG.md
|
@ -3,6 +3,40 @@
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [2.0.1](https://github.com/nacos-group/nacos-sdk-nodejs/compare/v2.0.0...v2.0.1) (2021-01-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix the request address is undefined after SSL is enabled ([#42](https://github.com/nacos-group/nacos-sdk-nodejs/issues/42)) ([6146235](https://github.com/nacos-group/nacos-sdk-nodejs/commit/614623577baa510fefc575f875e2ff3076f8a781))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.1.2](https://github.com/nacos-group/nacos-sdk-nodejs/compare/v1.1.1...v1.1.2) (2019-03-31)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix gbk text ([93c3559](https://github.com/nacos-group/nacos-sdk-nodejs/commit/93c3559))
|
||||||
|
* fix options in direct mode ([2942e19](https://github.com/nacos-group/nacos-sdk-nodejs/commit/2942e19))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.1.1](https://github.com/nacos-group/nacos-sdk-nodejs/compare/v1.1.0...v1.1.1) (2019-01-17)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* beatinfo is wrong ([26f8cee](https://github.com/nacos-group/nacos-sdk-nodejs/commit/26f8cee))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [1.1.0](https://github.com/nacos-group/nacos-sdk-nodejs/compare/v1.0.2...v1.1.0) (2019-01-15)
|
# [1.1.0](https://github.com/nacos-group/nacos-sdk-nodejs/compare/v1.0.2...v1.1.0) (2019-01-15)
|
||||||
|
|
||||||
|
|
||||||
|
|
72
README.md
72
README.md
|
@ -21,6 +21,13 @@
|
||||||
npm install nacos --save
|
npm install nacos --save
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Version Mapping
|
||||||
|
|
||||||
|
Node.js SDK \ Nacos Server | 0.x.0 | 1.0.0 |
|
||||||
|
--- | --- | --- |
|
||||||
|
1.x | √ | |
|
||||||
|
2.x | | √ |
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
### Service Discovery
|
### Service Discovery
|
||||||
|
@ -34,14 +41,21 @@ const logger = console;
|
||||||
const client = new NacosNamingClient({
|
const client = new NacosNamingClient({
|
||||||
logger,
|
logger,
|
||||||
serverList: '127.0.0.1:8848', // replace to real nacos serverList
|
serverList: '127.0.0.1:8848', // replace to real nacos serverList
|
||||||
|
namespace: 'public',
|
||||||
});
|
});
|
||||||
await client.ready();
|
await client.ready();
|
||||||
|
|
||||||
const serviceName = 'nodejs.test.domain';
|
const serviceName = 'nodejs.test.domain';
|
||||||
|
|
||||||
// registry instance
|
// registry instance
|
||||||
await client.registerInstance(serviceName, '1.1.1.1', 8080, 'NODEJS');
|
await client.registerInstance(serviceName, {
|
||||||
await client.registerInstance(serviceName, '2.2.2.2', 8080, 'NODEJS');
|
ip: '1.1.1.1',
|
||||||
|
port: 8080,
|
||||||
|
});
|
||||||
|
await client.registerInstance(serviceName, {
|
||||||
|
ip: '2.2.2.2',
|
||||||
|
port: 8080,
|
||||||
|
});
|
||||||
|
|
||||||
// subscribe instance
|
// subscribe instance
|
||||||
client.subscribe(serviceName, hosts => {
|
client.subscribe(serviceName, hosts => {
|
||||||
|
@ -49,7 +63,10 @@ client.subscribe(serviceName, hosts => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// deregister instance
|
// deregister instance
|
||||||
await client.deregisterInstance(serviceName, '1.1.1.1', 8080, 'NODEJS');
|
await client.deregisterInstance(serviceName, {
|
||||||
|
ip: '1.1.1.1',
|
||||||
|
port: 8080,
|
||||||
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
### Config Service
|
### Config Service
|
||||||
|
@ -100,27 +117,36 @@ default value: [ClientOptions default value](https://github.com/nacos-group/naco
|
||||||
|
|
||||||
### Service Discovery
|
### Service Discovery
|
||||||
|
|
||||||
- `registerInstance(serviceName, ip, port, [cluster])` Register an instance to service.
|
- `registerInstance(serviceName, instance, [groupName])` Register an instance to service.
|
||||||
- serviceName <String> Service name
|
- serviceName {String} Service name
|
||||||
- ip <String> IP of instance
|
- instance {Instance}
|
||||||
- port <Number> Port of instance
|
- ip {String} IP of instance
|
||||||
- cluster <String> Virtual cluster name
|
- port {Number} Port of instance
|
||||||
|
- [weight] {Number} weight of the instance, default is 1.0
|
||||||
|
- [ephemeral] {Boolean} active until the client is alive, default is true
|
||||||
|
- [clusterName] {String} Virtual cluster name
|
||||||
|
- [groupName] {String} group name, default is `DEFAULT_GROUP`
|
||||||
- `deregisterInstance(serviceName, ip, port, [cluster])` Delete instance from service.
|
- `deregisterInstance(serviceName, ip, port, [cluster])` Delete instance from service.
|
||||||
- serviceName <String> Service name
|
- serviceName {String} Service name
|
||||||
- ip <String> IP of instance
|
- instance {Instance}
|
||||||
- port <Number> Port of instance
|
- ip {String} IP of instance
|
||||||
- cluster <String> Virtual cluster name
|
- port {Number} Port of instance
|
||||||
- `getAllInstances(serviceName, [clusters])` Query instance list of service.
|
- [weight] {Number} weight of the instance, default is 1.0
|
||||||
- serviceName <String> Service name
|
- [ephemeral] {Boolean} active until the client is alive, default is true
|
||||||
- clusters <Array> Cluster names
|
- [clusterName] {String} Virtual cluster name
|
||||||
|
- [groupName] {String} group name, default is `DEFAULT_GROUP`
|
||||||
|
- `getAllInstances(serviceName, [groupName], [clusters], [subscribe])` Query instance list of service.
|
||||||
|
- serviceName {String} Service name
|
||||||
|
- [groupName] {String} group name, default is `DEFAULT_GROUP`
|
||||||
|
- [clusters] {String} Cluster names
|
||||||
|
- [subscribe] {Boolean} whether subscribe the service, default is true
|
||||||
- `getServerStatus()` Get the status of nacos server, 'UP' or 'DOWN'.
|
- `getServerStatus()` Get the status of nacos server, 'UP' or 'DOWN'.
|
||||||
- `subscribe(info, listener)` Subscribe the instances of the service
|
- `subscribe(info, listener)` Subscribe the instances of the service
|
||||||
- info <Object | String> service info, if type is string, it's the serviceName
|
- info {Object}|{String} service info, if type is string, it's the serviceName
|
||||||
- listener <Function> the listener function
|
- listener {Function} the listener function
|
||||||
- unSubscribe(info, [listener]) Unsubscribe the instances of the service
|
- `unSubscribe(info, [listener])` Unsubscribe the instances of the service
|
||||||
- info <Object | String> service info, if type is string, it's the serviceName
|
- info {Object}|{String} service info, if type is string, it's the serviceName
|
||||||
- listener <Function> the listener function, if not provide, will unSubscribe all listeners under this service
|
- listener {Function} the listener function, if not provide, will unSubscribe all listeners under this service
|
||||||
|
|
||||||
|
|
||||||
### Config Service
|
### Config Service
|
||||||
|
|
||||||
|
@ -151,6 +177,10 @@ Please let us know how can we help. Do check out [issues](https://github.com/nac
|
||||||
|
|
||||||
PR is welcome.
|
PR is welcome.
|
||||||
|
|
||||||
|
nacos-sdk-nodejs ding group : 44654232
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
[Apache License V2](LICENSE)
|
[Apache License V2](LICENSE)
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const NacosConfigClient = require('nacos').NacosConfigClient;
|
||||||
|
|
||||||
|
const configClient = new NacosConfigClient({
|
||||||
|
serverAddr: 'aliyun.nacos.net:80',
|
||||||
|
namespace: '',
|
||||||
|
// 如果nacos开启了认证鉴权,需要在此处填写用户名密码
|
||||||
|
// username: 'xxx',
|
||||||
|
// password: 'xxx'
|
||||||
|
});
|
||||||
|
|
||||||
|
function sleep(time){
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve();
|
||||||
|
}, time);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
await configClient.ready();
|
||||||
|
|
||||||
|
const dataId = 'nacos.test.22';
|
||||||
|
const group = 'DEFAULT_GROUP';
|
||||||
|
const str = `example_test_${Math.random()}_${Date.now()}`;
|
||||||
|
|
||||||
|
console.log('---------ready to publish------------');
|
||||||
|
await configClient.publishSingle(dataId, group, str);
|
||||||
|
await sleep(2000);
|
||||||
|
console.log('---------publish complete------------');
|
||||||
|
await sleep(2000);
|
||||||
|
console.log('---------ready to getConfig----------');
|
||||||
|
await sleep(2000);
|
||||||
|
let content = await configClient.getConfig(dataId, group);
|
||||||
|
console.log('---------getConfig complete----------');
|
||||||
|
console.log('current content => ' + content);
|
||||||
|
await sleep(2000);
|
||||||
|
console.log('---------ready to remove config------');
|
||||||
|
await configClient.remove(dataId, group);
|
||||||
|
console.log('---------remove config complete------');
|
||||||
|
await sleep(2000);
|
||||||
|
content = await configClient.getConfig(dataId, group);
|
||||||
|
console.log('---------getConfig complete----------');
|
||||||
|
console.log('current content => ' + content);
|
||||||
|
await sleep(2000);
|
||||||
|
console.log('---------remove config success-------');
|
||||||
|
configClient.close();
|
||||||
|
process.exit(0);
|
||||||
|
})();
|
|
@ -2,6 +2,6 @@
|
||||||
"name": "nacos-example",
|
"name": "nacos-example",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nacos": "^1.0.0"
|
"nacos": "^2.5.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
16
lerna.json
16
lerna.json
|
@ -2,5 +2,19 @@
|
||||||
"packages": [
|
"packages": [
|
||||||
"packages/*"
|
"packages/*"
|
||||||
],
|
],
|
||||||
"version": "1.1.0"
|
"command": {
|
||||||
|
"bootstrap": {
|
||||||
|
"hoist": true,
|
||||||
|
"noCi": true,
|
||||||
|
"npmClientArgs": [
|
||||||
|
"--no-package-lock"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"publish": {
|
||||||
|
"ignoreChanges": [
|
||||||
|
"*.md"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"version": "2.6.0"
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,14 +6,14 @@
|
||||||
"contributors": "contributors -f plain -o AUTHORS",
|
"contributors": "contributors -f plain -o AUTHORS",
|
||||||
"clean": "lerna clean --yes; rm -rf ./packages/**/package-lock.json",
|
"clean": "lerna clean --yes; rm -rf ./packages/**/package-lock.json",
|
||||||
"bootstrap": "rm -f ./packages/.DS*; lerna bootstrap --no-ci",
|
"bootstrap": "rm -f ./packages/.DS*; lerna bootstrap --no-ci",
|
||||||
"publish": "rm -f ./packages/.DS*; sh scripts/publish.sh",
|
"release": "rm -f ./packages/.DS*; sh scripts/publish.sh",
|
||||||
"next": "sh scripts/publish.sh --npm-tag next",
|
"next": "sh scripts/publish.sh --npm-tag next",
|
||||||
"test": "lerna run test",
|
"test": "lerna run test",
|
||||||
"cov": "sh scripts/cov.sh",
|
"cov": "sh scripts/cov.sh",
|
||||||
"ci": "npm run cov",
|
"ci": "npm run cov",
|
||||||
"build": "lerna run build && cp ./README.md ./packages/nacos/README.md"
|
"build": "lerna run build && cp ./README.md ./packages/nacos/README.md"
|
||||||
},
|
},
|
||||||
"license": "Apache",
|
"license": "Apache-2.0",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/nacos-group/nacos-sdk-nodejs/issues"
|
"url": "https://github.com/nacos-group/nacos-sdk-nodejs/issues"
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,6 +3,29 @@
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [2.0.1](https://github.com/nacos-group/nacos-sdk-nodejs/compare/v2.0.0...v2.0.1) (2021-01-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix the request address is undefined after SSL is enabled ([#42](https://github.com/nacos-group/nacos-sdk-nodejs/issues/42)) ([6146235](https://github.com/nacos-group/nacos-sdk-nodejs/commit/614623577baa510fefc575f875e2ff3076f8a781))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.1.2](https://github.com/nacos-group/nacos-sdk-nodejs/compare/v1.1.1...v1.1.2) (2019-03-31)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix gbk text ([93c3559](https://github.com/nacos-group/nacos-sdk-nodejs/commit/93c3559))
|
||||||
|
* fix options in direct mode ([2942e19](https://github.com/nacos-group/nacos-sdk-nodejs/commit/2942e19))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [1.1.0](https://github.com/nacos-group/nacos-sdk-nodejs/compare/v1.0.2...v1.1.0) (2019-01-15)
|
# [1.1.0](https://github.com/nacos-group/nacos-sdk-nodejs/compare/v1.0.2...v1.1.0) (2019-01-15)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "nacos-config",
|
"name": "nacos-config",
|
||||||
"version": "1.1.0",
|
"version": "2.6.0",
|
||||||
"description": "nacos config client",
|
"description": "nacos config client",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"nacos-config",
|
"nacos-config",
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
"@types/mocha": "^5.2.5",
|
"@types/mocha": "^5.2.5",
|
||||||
"@types/node": "^10.9.4",
|
"@types/node": "^10.9.4",
|
||||||
"contributors": "^0.5.1",
|
"contributors": "^0.5.1",
|
||||||
"midway-bin": "^0.3.2",
|
"midway-bin": "1",
|
||||||
"mm": "^2.4.1",
|
"mm": "^2.4.1",
|
||||||
"pedding": "^1.1.0",
|
"pedding": "^1.1.0",
|
||||||
"tslint": "^5.11.0",
|
"tslint": "^5.11.0",
|
||||||
|
|
|
@ -44,7 +44,9 @@ export class DataClient extends Base implements BaseClient {
|
||||||
protected httpAgent;
|
protected httpAgent;
|
||||||
|
|
||||||
constructor(options: ClientOptions) {
|
constructor(options: ClientOptions) {
|
||||||
assert(options.endpoint, '[Client] options.endpoint is required');
|
if(!options.endpoint && !options.serverAddr) {
|
||||||
|
assert(options.endpoint, '[Client] options.endpoint or options.serverAddr is required');
|
||||||
|
}
|
||||||
|
|
||||||
options = Object.assign({}, DEFAULT_OPTIONS, options);
|
options = Object.assign({}, DEFAULT_OPTIONS, options);
|
||||||
super(options);
|
super(options);
|
||||||
|
@ -52,7 +54,8 @@ export class DataClient extends Base implements BaseClient {
|
||||||
|
|
||||||
this.snapshot = this.getSnapshot();
|
this.snapshot = this.getSnapshot();
|
||||||
this.serverMgr = this.getServerListManager();
|
this.serverMgr = this.getServerListManager();
|
||||||
this.httpAgent = new HttpAgent({ configuration: this.configuration });
|
const CustomHttpAgent = this.configuration.get(ClientOptionKeys.HTTP_AGENT);
|
||||||
|
this.httpAgent = CustomHttpAgent ? new CustomHttpAgent({ configuration: this.configuration }) : new HttpAgent({ configuration: this.configuration });
|
||||||
|
|
||||||
this.configuration.merge({
|
this.configuration.merge({
|
||||||
snapshot: this.snapshot,
|
snapshot: this.snapshot,
|
||||||
|
@ -160,7 +163,7 @@ export class DataClient extends Base implements BaseClient {
|
||||||
async publishSingle(dataId, group, content, options) {
|
async publishSingle(dataId, group, content, options) {
|
||||||
checkParameters(dataId, group);
|
checkParameters(dataId, group);
|
||||||
const client = this.getClient(options);
|
const client = this.getClient(options);
|
||||||
return await client.publishSingle(dataId, group, content);
|
return await client.publishSingle(dataId, group, content, options && options.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -217,6 +217,10 @@ export class ClientWorker extends Base implements IClientWorker {
|
||||||
}
|
}
|
||||||
|
|
||||||
const postData = {};
|
const postData = {};
|
||||||
|
// 开启权限验证后需要携带租户,否则没有权限
|
||||||
|
if (tenant) {
|
||||||
|
Object.assign(postData, { tenant })
|
||||||
|
}
|
||||||
postData[ this.listenerDataKey ] = probeUpdate.join('');
|
postData[ this.listenerDataKey ] = probeUpdate.join('');
|
||||||
const content = await this.httpAgent.request(this.apiRoutePath.LISTENER, {
|
const content = await this.httpAgent.request(this.apiRoutePath.LISTENER, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
@ -345,9 +349,10 @@ export class ClientWorker extends Base implements IClientWorker {
|
||||||
* @param {String} dataId - id of the data
|
* @param {String} dataId - id of the data
|
||||||
* @param {String} group - group name of the data
|
* @param {String} group - group name of the data
|
||||||
* @param {String} content - config value
|
* @param {String} content - config value
|
||||||
|
* @param {String} type - type of the data
|
||||||
* @return {Boolean} success
|
* @return {Boolean} success
|
||||||
*/
|
*/
|
||||||
async publishSingle(dataId, group, content) {
|
async publishSingle(dataId, group, content, type) {
|
||||||
await this.httpAgent.request(this.apiRoutePath.PUBLISH, {
|
await this.httpAgent.request(this.apiRoutePath.PUBLISH, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
encode: true,
|
encode: true,
|
||||||
|
@ -356,6 +361,8 @@ export class ClientWorker extends Base implements IClientWorker {
|
||||||
group,
|
group,
|
||||||
content,
|
content,
|
||||||
tenant: this.namespace,
|
tenant: this.namespace,
|
||||||
|
type,
|
||||||
|
appName: this.appName
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -18,12 +18,12 @@ import { HTTP_CONFLICT, HTTP_NOT_FOUND, HTTP_OK, VERSION } from './const';
|
||||||
import { ClientOptionKeys, IConfiguration, IServerListManager } from './interface';
|
import { ClientOptionKeys, IConfiguration, IServerListManager } from './interface';
|
||||||
import * as urllib from 'urllib';
|
import * as urllib from 'urllib';
|
||||||
import * as crypto from 'crypto';
|
import * as crypto from 'crypto';
|
||||||
import { encodingParams } from './utils';
|
import { encodingParams, transformGBKToUTF8 } from './utils';
|
||||||
|
import * as dns from 'dns';
|
||||||
|
|
||||||
export class HttpAgent {
|
export class HttpAgent {
|
||||||
|
|
||||||
options;
|
options;
|
||||||
currentServer: string;
|
|
||||||
protected loggerDomain = 'Nacos';
|
protected loggerDomain = 'Nacos';
|
||||||
private debugPrefix = this.loggerDomain.toLowerCase();
|
private debugPrefix = this.loggerDomain.toLowerCase();
|
||||||
private debug = require('debug')(`${this.debugPrefix}:${process.pid}:http_agent`);
|
private debug = require('debug')(`${this.debugPrefix}:${process.pid}:http_agent`);
|
||||||
|
@ -83,6 +83,22 @@ export class HttpAgent {
|
||||||
return this.configuration.get(ClientOptionKeys.DEFAULT_ENCODING) || 'utf8';
|
return this.configuration.get(ClientOptionKeys.DEFAULT_ENCODING) || 'utf8';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get identityKey() {
|
||||||
|
return this.configuration.get(ClientOptionKeys.IDENTITY_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
get identityValue() {
|
||||||
|
return this.configuration.get(ClientOptionKeys.IDENTITY_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
get endpointQueryParams() {
|
||||||
|
return this.configuration.get(ClientOptionKeys.ENDPOINT_QUERY_PARAMS)
|
||||||
|
}
|
||||||
|
|
||||||
|
get decodeRes() {
|
||||||
|
return this.configuration.get(ClientOptionKeys.DECODE_RES);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 请求
|
* 请求
|
||||||
|
@ -107,6 +123,11 @@ export class HttpAgent {
|
||||||
const endTime = Date.now() + timeout;
|
const endTime = Date.now() + timeout;
|
||||||
let lastErr;
|
let lastErr;
|
||||||
|
|
||||||
|
if (this.options?.configuration?.innerConfig?.username &&
|
||||||
|
this.options?.configuration?.innerConfig?.password) {
|
||||||
|
data.username = this.options.configuration.innerConfig.username;
|
||||||
|
data.password = this.options.configuration.innerConfig.password;
|
||||||
|
}
|
||||||
let signStr = data.tenant;
|
let signStr = data.tenant;
|
||||||
if (data.group && data.tenant) {
|
if (data.group && data.tenant) {
|
||||||
signStr = data.tenant + '+' + data.group;
|
signStr = data.tenant + '+' + data.group;
|
||||||
|
@ -126,6 +147,7 @@ export class HttpAgent {
|
||||||
timeStamp: ts,
|
timeStamp: ts,
|
||||||
exConfigInfo: 'true',
|
exConfigInfo: 'true',
|
||||||
'Spas-Signature': signature,
|
'Spas-Signature': signature,
|
||||||
|
...this.identityKey ? {[this.identityKey]: this.identityValue} : {}
|
||||||
});
|
});
|
||||||
|
|
||||||
let requestData = data;
|
let requestData = data;
|
||||||
|
@ -153,7 +175,10 @@ export class HttpAgent {
|
||||||
this.debug('%s %s, got %s, body: %j', method, url, res.status, res.data);
|
this.debug('%s %s, got %s, body: %j', method, url, res.status, res.data);
|
||||||
switch (res.status) {
|
switch (res.status) {
|
||||||
case HTTP_OK:
|
case HTTP_OK:
|
||||||
return res.data;
|
if (this.decodeRes) {
|
||||||
|
return this.decodeRes(res, method, this.defaultEncoding)
|
||||||
|
}
|
||||||
|
return this.decodeResData(res, method);
|
||||||
case HTTP_NOT_FOUND:
|
case HTTP_NOT_FOUND:
|
||||||
return null;
|
return null;
|
||||||
case HTTP_CONFLICT:
|
case HTTP_CONFLICT:
|
||||||
|
@ -171,6 +196,9 @@ export class HttpAgent {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
if (err.code === dns.NOTFOUND) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
err.url = `${method} ${url}`;
|
err.url = `${method} ${url}`;
|
||||||
err.data = data;
|
err.data = data;
|
||||||
err.headers = headers;
|
err.headers = headers;
|
||||||
|
@ -188,15 +216,28 @@ export class HttpAgent {
|
||||||
if (/:/.test(currentServer)) {
|
if (/:/.test(currentServer)) {
|
||||||
url = `http://${currentServer}`;
|
url = `http://${currentServer}`;
|
||||||
if (this.ssl) {
|
if (this.ssl) {
|
||||||
url = `https://${this.currentServer}`;
|
url = `https://${currentServer}`;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
url = `http://${currentServer}:${this.serverPort}`;
|
url = `http://${currentServer}:${this.serverPort}`;
|
||||||
if (this.ssl) {
|
if (this.ssl) {
|
||||||
url = `https://${this.currentServer}:${this.serverPort}`;
|
url = `https://${currentServer}:${this.serverPort}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return `${url}/${this.contextPath}`;
|
return `${url}/${this.contextPath}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
decodeResData(res, method = 'GET') {
|
||||||
|
if (method === 'GET' && /charset=GBK/.test(res.headers[ 'content-type' ]) && this.defaultEncoding === 'utf8') {
|
||||||
|
try {
|
||||||
|
return transformGBKToUTF8(res.data);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`transform gbk data to utf8 error, msg=${err.messager}`);
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ export { DataClient } from './client';
|
||||||
export { ClientWorker } from './client_worker';
|
export { ClientWorker } from './client_worker';
|
||||||
export { ServerListManager } from './server_list_mgr';
|
export { ServerListManager } from './server_list_mgr';
|
||||||
export { Snapshot } from './snapshot';
|
export { Snapshot } from './snapshot';
|
||||||
|
export { HttpAgent } from './http_agent'
|
||||||
|
|
||||||
const APIClientBase = require('cluster-client').APIClientBase;
|
const APIClientBase = require('cluster-client').APIClientBase;
|
||||||
|
|
||||||
|
|
|
@ -251,9 +251,10 @@ export interface ClientOptions {
|
||||||
accessKey?: string; // 阿里云的 accessKey
|
accessKey?: string; // 阿里云的 accessKey
|
||||||
secretKey?: string; // 阿里云的 secretKey
|
secretKey?: string; // 阿里云的 secretKey
|
||||||
httpclient?: any; // http 请求客户端,默认为 urllib
|
httpclient?: any; // http 请求客户端,默认为 urllib
|
||||||
|
httpAgent?: any; // httpAgent
|
||||||
appName?: string; // 应用名,可选
|
appName?: string; // 应用名,可选
|
||||||
ssl?: boolean; // 是否为 https 请求
|
ssl?: boolean; // 是否为 https 请求
|
||||||
refreshInterval?: number; // 重新拉去地址列表的间隔时间
|
refreshInterval?: number; // 重新拉取地址列表的间隔时间
|
||||||
contextPath?: string; // 请求的 contextPath
|
contextPath?: string; // 请求的 contextPath
|
||||||
clusterName?: string; // 请求的 path
|
clusterName?: string; // 请求的 path
|
||||||
requestTimeout?: number; // 请求超时时间
|
requestTimeout?: number; // 请求超时时间
|
||||||
|
@ -261,7 +262,13 @@ export interface ClientOptions {
|
||||||
serverAddr?: string; // 用于直连,包含端口
|
serverAddr?: string; // 用于直连,包含端口
|
||||||
unit?: string; // 内部单元化用
|
unit?: string; // 内部单元化用
|
||||||
nameServerAddr?: string; // 老的兼容参数,逐步废弃,同 endpoint
|
nameServerAddr?: string; // 老的兼容参数,逐步废弃,同 endpoint
|
||||||
|
username?: string; // 认证的用户名
|
||||||
|
password?: string; // 认证的密码
|
||||||
cacheDir?: string; // 缓存文件的路径
|
cacheDir?: string; // 缓存文件的路径
|
||||||
|
identityKey?: string; // Identity Key
|
||||||
|
identityValue?: string; // Identity Value
|
||||||
|
endpointQueryParams?: string; // endPoint 查询参数 e.g: param_1=1¶m_2=2
|
||||||
|
decodeRes?: (res: any, method?: string, encoding?: string) => any
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ClientOptionKeys {
|
export enum ClientOptionKeys {
|
||||||
|
@ -285,6 +292,10 @@ export enum ClientOptionKeys {
|
||||||
HTTP_AGENT = 'httpAgent',
|
HTTP_AGENT = 'httpAgent',
|
||||||
SERVER_MGR = 'serverMgr',
|
SERVER_MGR = 'serverMgr',
|
||||||
DEFAULT_ENCODING = 'defaultEncoding',
|
DEFAULT_ENCODING = 'defaultEncoding',
|
||||||
|
IDENTITY_KEY = 'identityKey',
|
||||||
|
IDENTITY_VALUE = 'identityValue',
|
||||||
|
DECODE_RES = 'decodeRes',
|
||||||
|
ENDPOINT_QUERY_PARAMS = 'endpointQueryParams'
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IConfiguration {
|
export interface IConfiguration {
|
||||||
|
|
|
@ -108,6 +108,10 @@ export class ServerListManager extends Base implements IServerListManager {
|
||||||
return this.configuration.get(ClientOptionKeys.CLUSTER_NAME) || 'serverlist';
|
return this.configuration.get(ClientOptionKeys.CLUSTER_NAME) || 'serverlist';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get endpointQueryParams() {
|
||||||
|
return this.configuration.get(ClientOptionKeys.ENDPOINT_QUERY_PARAMS)
|
||||||
|
}
|
||||||
|
|
||||||
get requestTimeout(): number {
|
get requestTimeout(): number {
|
||||||
return this.configuration.get(ClientOptionKeys.REQUEST_TIMEOUT);
|
return this.configuration.get(ClientOptionKeys.REQUEST_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
@ -226,7 +230,8 @@ export class ServerListManager extends Base implements IServerListManager {
|
||||||
|
|
||||||
// 获取请求 url
|
// 获取请求 url
|
||||||
protected getRequestUrl(unit) {
|
protected getRequestUrl(unit) {
|
||||||
return `http://${this.nameServerAddr}/${this.contextPath}/${this.clusterName}`;
|
const endpointQueryParams = !!this.endpointQueryParams ? `?${this.endpointQueryParams}` : '';
|
||||||
|
return `http://${this.nameServerAddr}/${this.contextPath}/${this.clusterName}${endpointQueryParams}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -74,3 +74,8 @@ export function checkParameters(dataIds, group, datumId?) {
|
||||||
assert(exports.isValid(datumId), `[datumId] only allow digital, letter and symbols in [ "_", "-", ".", ":" ], but got ${datumId}`);
|
assert(exports.isValid(datumId), `[datumId] only allow digital, letter and symbols in [ "_", "-", ".", ":" ], but got ${datumId}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function transformGBKToUTF8(text) {
|
||||||
|
return iconv.decode(iconv.encode(text, 'gbk'), 'utf8');
|
||||||
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import { DataClient } from '../src/client';
|
import { DataClient } from '../src/client';
|
||||||
|
import { HttpAgent } from '../src/http_agent'
|
||||||
|
|
||||||
const mm = require('mm');
|
const mm = require('mm');
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
@ -117,4 +118,20 @@ describe('test/client.test.ts', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('support custom httpAgent', () => {
|
||||||
|
class CustomHttpAgent {};
|
||||||
|
assert(client.httpAgent instanceof HttpAgent);
|
||||||
|
client = new DataClient({
|
||||||
|
appName: 'test',
|
||||||
|
endpoint: 'acm.aliyun.com',
|
||||||
|
namespace: '81597370-5076-4216-9df5-538a2b55bac3',
|
||||||
|
accessKey: '4c796a4dcd0d4f5895d4ba83a296b489',
|
||||||
|
secretKey: 'UjLemP8inirhjMg1NZyY0faOk1E=',
|
||||||
|
httpclient,
|
||||||
|
httpAgent: CustomHttpAgent,
|
||||||
|
ssl: false
|
||||||
|
});
|
||||||
|
assert(client.httpAgent instanceof CustomHttpAgent);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -497,5 +497,32 @@ describe('test/client_worker.test.ts', () => {
|
||||||
assert(error && error.name === 'NacosServerConflictError');
|
assert(error && error.name === 'NacosServerConflictError');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('custom decode res data', () => {
|
||||||
|
before(async () => {
|
||||||
|
configuration.merge({ decodeRes(res) {
|
||||||
|
if (/^\d+\.\d+\.\d+\.\d+\:\d+$/.test(res.data)) {
|
||||||
|
return 'customDecode' + res.data
|
||||||
|
}
|
||||||
|
return res.data;
|
||||||
|
}});
|
||||||
|
client = getClient(configuration);
|
||||||
|
await client.publishSingle('com.taobao.hsf.redis', 'DEFAULT_GROUP', '10.123.32.1:8080');
|
||||||
|
await sleep(1000);
|
||||||
|
await client.ready();
|
||||||
|
});
|
||||||
|
afterEach(mm.restore);
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
client.close();
|
||||||
|
await client.remove('com.taobao.hsf.redis', 'DEFAULT_GROUP');
|
||||||
|
await rimraf(cacheDir);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be handled by decodeRes', async () => {
|
||||||
|
const content = await client.getConfig('com.taobao.hsf.redis', 'DEFAULT_GROUP');
|
||||||
|
assert(/^customDecode\d+\.\d+\.\d+\.\d+\:\d+$/.test(content));
|
||||||
|
});
|
||||||
|
})
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -18,14 +18,6 @@
|
||||||
import { Configuration } from '../src/configuration';
|
import { Configuration } from '../src/configuration';
|
||||||
import { DEFAULT_OPTIONS } from '../src/const';
|
import { DEFAULT_OPTIONS } from '../src/const';
|
||||||
|
|
||||||
export function delay(timeout) {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
setTimeout(() => {
|
|
||||||
resolve();
|
|
||||||
}, timeout);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createDefaultConfiguration(config: any) {
|
export function createDefaultConfiguration(config: any) {
|
||||||
return new Configuration(Object.assign({}, DEFAULT_OPTIONS)).merge(config);
|
return new Configuration(Object.assign({}, DEFAULT_OPTIONS)).merge(config);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
|
||||||
|
language: node_js
|
||||||
|
node_js:
|
||||||
|
- '8'
|
||||||
|
- '10'
|
||||||
|
- '12'
|
||||||
|
before_install:
|
||||||
|
- npm i npminstall -g
|
||||||
|
install:
|
||||||
|
- npminstall
|
||||||
|
script:
|
||||||
|
- npm run ci
|
||||||
|
after_script:
|
||||||
|
- npminstall codecov && codecov
|
|
@ -3,6 +3,33 @@
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [2.0.1](https://github.com/nacos-group/nacos-sdk-nodejs/compare/v2.0.0...v2.0.1) (2021-01-26)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package nacos-naming
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.1.2](https://github.com/nacos-group/nacos-sdk-nodejs/compare/v1.1.1...v1.1.2) (2019-03-31)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package nacos-naming
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.1.1](https://github.com/nacos-group/nacos-sdk-nodejs/compare/v1.1.0...v1.1.1) (2019-01-17)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* beatinfo is wrong ([26f8cee](https://github.com/nacos-group/nacos-sdk-nodejs/commit/26f8cee))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [1.1.0](https://github.com/nacos-group/nacos-sdk-nodejs/compare/v1.0.2...v1.1.0) (2019-01-15)
|
# [1.1.0](https://github.com/nacos-group/nacos-sdk-nodejs/compare/v1.0.2...v1.1.0) (2019-01-15)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -34,14 +34,21 @@ const logger = console;
|
||||||
const client = new NacosNamingClient({
|
const client = new NacosNamingClient({
|
||||||
logger,
|
logger,
|
||||||
serverList: '127.0.0.1:8848', // replace to real nacos serverList
|
serverList: '127.0.0.1:8848', // replace to real nacos serverList
|
||||||
|
namespace: 'public',
|
||||||
});
|
});
|
||||||
await client.ready();
|
await client.ready();
|
||||||
|
|
||||||
const serviceName = 'nodejs.test.domain';
|
const serviceName = 'nodejs.test.domain';
|
||||||
|
|
||||||
// registry instance
|
// registry instance
|
||||||
await client.registerInstance(serviceName, '1.1.1.1', 8080, 'NODEJS');
|
await client.registerInstance(serviceName, {
|
||||||
await client.registerInstance(serviceName, '2.2.2.2', 8080, 'NODEJS');
|
ip: '1.1.1.1',
|
||||||
|
port: 8080,
|
||||||
|
});
|
||||||
|
await client.registerInstance(serviceName, {
|
||||||
|
ip: '2.2.2.2',
|
||||||
|
port: 8080,
|
||||||
|
});
|
||||||
|
|
||||||
// subscribe instance
|
// subscribe instance
|
||||||
client.subscribe(serviceName, hosts => {
|
client.subscribe(serviceName, hosts => {
|
||||||
|
@ -49,33 +56,46 @@ client.subscribe(serviceName, hosts => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// deregister instance
|
// deregister instance
|
||||||
await client.deregisterInstance(serviceName, '1.1.1.1', 8080, 'NODEJS');
|
await client.deregisterInstance(serviceName, {
|
||||||
|
ip: '1.1.1.1',
|
||||||
|
port: 8080,
|
||||||
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
## APIs
|
## APIs
|
||||||
|
|
||||||
### Service Discovery
|
### Service Discovery
|
||||||
|
|
||||||
- `registerInstance(serviceName, ip, port, [cluster])` Register an instance to service.
|
- `registerInstance(serviceName, instance, [groupName])` Register an instance to service.
|
||||||
- serviceName <String> Service name
|
- serviceName {String} Service name
|
||||||
- ip <String> IP of instance
|
- instance {Instance}
|
||||||
- port <Number> Port of instance
|
- ip {String} IP of instance
|
||||||
- cluster <String> Virtual cluster name
|
- port {Number} Port of instance
|
||||||
|
- [weight] {Number} weight of the instance, default is 1.0
|
||||||
|
- [ephemeral] {Boolean} active until the client is alive, default is true
|
||||||
|
- [clusterName] {String} Virtual cluster name
|
||||||
|
- [groupName] {String} group name, default is `DEFAULT_GROUP`
|
||||||
- `deregisterInstance(serviceName, ip, port, [cluster])` Delete instance from service.
|
- `deregisterInstance(serviceName, ip, port, [cluster])` Delete instance from service.
|
||||||
- serviceName <String> Service name
|
- serviceName {String} Service name
|
||||||
- ip <String> IP of instance
|
- instance {Instance}
|
||||||
- port <Number> Port of instance
|
- ip {String} IP of instance
|
||||||
- cluster <String> Virtual cluster name
|
- port {Number} Port of instance
|
||||||
- `getAllInstances(serviceName, [clusters])` Query instance list of service.
|
- [weight] {Number} weight of the instance, default is 1.0
|
||||||
- serviceName <String> Service name
|
- [ephemeral] {Boolean} active until the client is alive, default is true
|
||||||
- clusters <Array> Cluster names
|
- [clusterName] {String} Virtual cluster name
|
||||||
|
- [groupName] {String} group name, default is `DEFAULT_GROUP`
|
||||||
|
- `getAllInstances(serviceName, [groupName], [clusters], [subscribe])` Query instance list of service.
|
||||||
|
- serviceName {String} Service name
|
||||||
|
- [groupName] {String} group name, default is `DEFAULT_GROUP`
|
||||||
|
- [clusters] {String} Cluster names
|
||||||
|
- [subscribe] {Boolean} whether subscribe the service, default is true
|
||||||
- `getServerStatus()` Get the status of nacos server, 'UP' or 'DOWN'.
|
- `getServerStatus()` Get the status of nacos server, 'UP' or 'DOWN'.
|
||||||
- `subscribe(info, listener)` Subscribe the instances of the service
|
- `subscribe(info, listener)` Subscribe the instances of the service
|
||||||
- info <Object>|<String> service info, if type is string, it's the serviceName
|
- info {Object}|{String} service info, if type is string, it's the serviceName
|
||||||
- listener <Function> the listener function
|
- listener {Function} the listener function
|
||||||
- `unSubscribe(info, [listener])` Unsubscribe the instances of the service
|
- `unSubscribe(info, [listener])` Unsubscribe the instances of the service
|
||||||
- info <Object>|<String> service info, if type is string, it's the serviceName
|
- info {Object}|{String} service info, if type is string, it's the serviceName
|
||||||
- listener <Function> the listener function, if not provide, will unSubscribe all listeners under this service
|
- listener {Function} the listener function, if not provide, will unSubscribe all listeners under this service
|
||||||
|
|
||||||
## Questions & Suggestions
|
## Questions & Suggestions
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ async function test() {
|
||||||
const client = new NacosNamingClient({
|
const client = new NacosNamingClient({
|
||||||
logger,
|
logger,
|
||||||
serverList: '127.0.0.1:8848',
|
serverList: '127.0.0.1:8848',
|
||||||
|
namespace: 'public',
|
||||||
});
|
});
|
||||||
await client.ready();
|
await client.ready();
|
||||||
|
|
||||||
|
@ -38,8 +39,14 @@ async function test() {
|
||||||
console.log(hosts);
|
console.log(hosts);
|
||||||
});
|
});
|
||||||
|
|
||||||
await client.registerInstance(serviceName, '1.1.1.1', 8080, 'NODEJS');
|
await client.registerInstance(serviceName, {
|
||||||
await client.registerInstance(serviceName, '2.2.2.2', 8080, 'NODEJS');
|
ip: '1.1.1.1',
|
||||||
|
port: 8080,
|
||||||
|
});
|
||||||
|
await client.registerInstance(serviceName, {
|
||||||
|
ip: '2.2.2.2',
|
||||||
|
port: 8080,
|
||||||
|
});
|
||||||
|
|
||||||
// const hosts = await client.getAllInstances(serviceName);
|
// const hosts = await client.getAllInstances(serviceName);
|
||||||
// console.log();
|
// console.log();
|
||||||
|
@ -48,7 +55,10 @@ async function test() {
|
||||||
|
|
||||||
await sleep(5000);
|
await sleep(5000);
|
||||||
|
|
||||||
await client.deregisterInstance(serviceName, '1.1.1.1', 8080, 'NODEJS');
|
await client.deregisterInstance(serviceName, {
|
||||||
|
ip: '1.1.1.1',
|
||||||
|
port: 8080,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
test().catch(err => {
|
test().catch(err => {
|
||||||
|
|
|
@ -1,64 +0,0 @@
|
||||||
/**
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright ownership.
|
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
||||||
* (the "License"); you may not use this file except in compliance with
|
|
||||||
* the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const net = require('net');
|
|
||||||
const NameProxy = require('../lib/naming/proxy');
|
|
||||||
const HostReactor = require('../lib/naming/host_reactor');
|
|
||||||
const logger = console;
|
|
||||||
|
|
||||||
const server = net.createServer();
|
|
||||||
server.listen(8080);
|
|
||||||
|
|
||||||
const serverProxy = new NameProxy({
|
|
||||||
logger,
|
|
||||||
serverList: '127.0.0.1:8848',
|
|
||||||
});
|
|
||||||
const hostReactor = new HostReactor({
|
|
||||||
logger,
|
|
||||||
serverProxy,
|
|
||||||
});
|
|
||||||
|
|
||||||
async function test() {
|
|
||||||
await hostReactor.ready();
|
|
||||||
|
|
||||||
const serviceName = 'nodejs.test.nodejs.1';
|
|
||||||
let result = await serverProxy.registerService(serviceName, {
|
|
||||||
ip: '30.23.176.112',
|
|
||||||
port: 8080,
|
|
||||||
cluster: {
|
|
||||||
name: 'NODEJS',
|
|
||||||
serviceName,
|
|
||||||
},
|
|
||||||
weight: 1.0,
|
|
||||||
healthy: true,
|
|
||||||
});
|
|
||||||
console.log(result);
|
|
||||||
|
|
||||||
const doms = await hostReactor.getServiceInfo({
|
|
||||||
serviceName,
|
|
||||||
cluster: [ 'NODEJS' ],
|
|
||||||
allIPs: true,
|
|
||||||
});
|
|
||||||
console.log(doms);
|
|
||||||
|
|
||||||
result = await serverProxy.deregisterService(serviceName, '30.23.176.112', 8080, 'NODEJS');
|
|
||||||
console.log(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
test();
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
* Author: ugrg
|
||||||
|
* Create Time: 2021/8/20 9:12
|
||||||
|
*/
|
||||||
|
interface Instance {
|
||||||
|
instanceId: string,
|
||||||
|
ip: string, //IP of instance
|
||||||
|
port: number, //Port of instance
|
||||||
|
healthy: boolean,
|
||||||
|
enabled: boolean,
|
||||||
|
serviceName?: string,
|
||||||
|
weight?: number,
|
||||||
|
ephemeral?: boolean,
|
||||||
|
clusterName?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Host {
|
||||||
|
instanceId: string;
|
||||||
|
ip: string;
|
||||||
|
port: number;
|
||||||
|
weight: number;
|
||||||
|
healthy: boolean;
|
||||||
|
enabled: boolean;
|
||||||
|
ephemeral: boolean;
|
||||||
|
clusterName: string;
|
||||||
|
serviceName: string;
|
||||||
|
metadata: any;
|
||||||
|
instanceHeartBeatInterval: number;
|
||||||
|
instanceIdGenerator: string;
|
||||||
|
instanceHeartBeatTimeOut: number;
|
||||||
|
ipDeleteTimeout: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Hosts = Host[];
|
||||||
|
|
||||||
|
interface SubscribeInfo {
|
||||||
|
serviceName: string,
|
||||||
|
groupName?: string,
|
||||||
|
clusters?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface NacosNamingClientConfig {
|
||||||
|
logger: typeof console,
|
||||||
|
serverList: string | string[],
|
||||||
|
namespace?: string,
|
||||||
|
username?: string,
|
||||||
|
password?: string,
|
||||||
|
endpoint?: string,
|
||||||
|
vipSrvRefInterMillis?: number,
|
||||||
|
ssl?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nacos服务发现组件
|
||||||
|
*/
|
||||||
|
export class NacosNamingClient {
|
||||||
|
constructor (config: NacosNamingClientConfig);
|
||||||
|
|
||||||
|
ready: () => Promise<void>;
|
||||||
|
// Register an instance to service
|
||||||
|
registerInstance: (
|
||||||
|
serviceName: string, //Service name
|
||||||
|
instance: Instance, //Instance
|
||||||
|
groupName?: string // group name, default is DEFAULT_GROUP
|
||||||
|
) => Promise<void>;
|
||||||
|
// Delete instance from service.
|
||||||
|
deregisterInstance: (
|
||||||
|
serviceName: string, //Service name
|
||||||
|
instance: Instance, //Instance
|
||||||
|
groupName?: string // group name, default is DEFAULT_GROUP
|
||||||
|
) => Promise<void>;
|
||||||
|
// Query instance list of service.
|
||||||
|
getAllInstances: (
|
||||||
|
serviceName: string, //Service name
|
||||||
|
groupName?: string, //group name, default is DEFAULT_GROUP
|
||||||
|
clusters?: string, //Cluster names
|
||||||
|
subscribe?: boolean //whether subscribe the service, default is true
|
||||||
|
) => Promise<Hosts>;
|
||||||
|
// Select instance list of service.
|
||||||
|
selectInstances: (
|
||||||
|
serviceName: string,
|
||||||
|
groupName?: string,
|
||||||
|
clusters?: string,
|
||||||
|
healthy?: boolean,
|
||||||
|
subscribe?: boolean
|
||||||
|
) => Promise<Hosts>;
|
||||||
|
// Get the status of nacos server, 'UP' or 'DOWN'.
|
||||||
|
getServerStatus: () => 'UP' | 'DOWN';
|
||||||
|
subscribe: (
|
||||||
|
info: SubscribeInfo | string, //service info, if type is string, it's the serviceName
|
||||||
|
listener: (host: Hosts) => void //the listener function
|
||||||
|
) => void;
|
||||||
|
unSubscribe: (
|
||||||
|
info: SubscribeInfo | string, //service info, if type is string, it's the serviceName
|
||||||
|
listener: (host: Hosts) => void //the listener function
|
||||||
|
) => void;
|
||||||
|
}
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
exports.VERSION = 'Nacos-Java-Client:v0.1.0';
|
exports.VERSION = 'Nacos-Java-Client:v1.0.0';
|
||||||
|
|
||||||
exports.ENCODING = 'UTF-8';
|
exports.ENCODING = 'UTF-8';
|
||||||
|
|
||||||
|
@ -46,3 +46,9 @@ exports.SERVER_ADDR_IP_SPLITER = ':';
|
||||||
exports.NAMING_INSTANCE_ID_SPLITTER = '#';
|
exports.NAMING_INSTANCE_ID_SPLITTER = '#';
|
||||||
|
|
||||||
exports.NAMING_DEFAULT_CLUSTER_NAME = 'DEFAULT';
|
exports.NAMING_DEFAULT_CLUSTER_NAME = 'DEFAULT';
|
||||||
|
|
||||||
|
exports.SERVICE_INFO_SPLITER = '@@';
|
||||||
|
|
||||||
|
exports.DEFAULT_GROUP = 'DEFAULT_GROUP';
|
||||||
|
|
||||||
|
exports.DEFAULT_DELAY = 5000;
|
||||||
|
|
|
@ -24,7 +24,6 @@ const sleep = require('mz-modules/sleep');
|
||||||
|
|
||||||
class BeatReactor extends Base {
|
class BeatReactor extends Base {
|
||||||
constructor(options = {}) {
|
constructor(options = {}) {
|
||||||
assert(options.logger, '[BeatReactor] options.logger is required');
|
|
||||||
assert(options.serverProxy, '[BeatReactor] options.serverProxy is required');
|
assert(options.serverProxy, '[BeatReactor] options.serverProxy is required');
|
||||||
super(options);
|
super(options);
|
||||||
|
|
||||||
|
@ -36,10 +35,6 @@ class BeatReactor extends Base {
|
||||||
this.ready(true);
|
this.ready(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
get logger() {
|
|
||||||
return this.options.logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
get serverProxy() {
|
get serverProxy() {
|
||||||
return this.options.serverProxy;
|
return this.options.serverProxy;
|
||||||
}
|
}
|
||||||
|
@ -57,20 +52,11 @@ class BeatReactor extends Base {
|
||||||
}
|
}
|
||||||
|
|
||||||
async _beat(beatInfo) {
|
async _beat(beatInfo) {
|
||||||
const params = {
|
if (beatInfo.scheduled) return;
|
||||||
beat: JSON.stringify(beatInfo),
|
|
||||||
dom: beatInfo.dom,
|
beatInfo.scheduled = true;
|
||||||
};
|
this._clientBeatInterval = await this.serverProxy.sendBeat(beatInfo);
|
||||||
try {
|
beatInfo.scheduled = false;
|
||||||
const result = await this.serverProxy.reqAPI(Constants.NACOS_URL_BASE + '/api/clientBeat', params);
|
|
||||||
const jsonObject = JSON.parse(result);
|
|
||||||
if (jsonObject) {
|
|
||||||
this._clientBeatInterval = jsonObject.clientBeatInterval;
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
err.message = '[CLIENT-BEAT] failed to send beat: ' + JSON.stringify(beatInfo) + ', caused by ' + err.message;
|
|
||||||
this.emit('error', err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async _startBeat() {
|
async _startBeat() {
|
||||||
|
@ -78,15 +64,14 @@ class BeatReactor extends Base {
|
||||||
|
|
||||||
this._isRunning = true;
|
this._isRunning = true;
|
||||||
while (!this._isClosed) {
|
while (!this._isClosed) {
|
||||||
for (const beatInfo of this._dom2Beat.values()) {
|
await Promise.all(Array.from(this._dom2Beat.values())
|
||||||
this._beat(beatInfo);
|
.map(beatInfo => this._beat(beatInfo)));
|
||||||
}
|
|
||||||
await sleep(this._clientBeatInterval);
|
await sleep(this._clientBeatInterval);
|
||||||
}
|
}
|
||||||
this._isRunning = false;
|
this._isRunning = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
close() {
|
async _close() {
|
||||||
this._isClosed = true;
|
this._isClosed = true;
|
||||||
this._isRunning = false;
|
this._isRunning = false;
|
||||||
this._dom2Beat.clear();
|
this._dom2Beat.clear();
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const utils = require('../util');
|
||||||
const Base = require('sdk-base');
|
const Base = require('sdk-base');
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const Instance = require('./instance');
|
const Instance = require('./instance');
|
||||||
|
@ -34,10 +35,7 @@ class NacosNamingClient extends Base {
|
||||||
assert(options.logger, '');
|
assert(options.logger, '');
|
||||||
super(Object.assign({}, defaultOptions, options, { initMethod: '_init' }));
|
super(Object.assign({}, defaultOptions, options, { initMethod: '_init' }));
|
||||||
|
|
||||||
this._serverProxy = new NamingProxy({
|
this._serverProxy = new NamingProxy(this.options);
|
||||||
logger: this.logger,
|
|
||||||
serverList: this.options.serverList,
|
|
||||||
});
|
|
||||||
this._beatReactor = new BeatReactor({
|
this._beatReactor = new BeatReactor({
|
||||||
serverProxy: this._serverProxy,
|
serverProxy: this._serverProxy,
|
||||||
logger: this.logger,
|
logger: this.logger,
|
||||||
|
@ -56,45 +54,63 @@ class NacosNamingClient extends Base {
|
||||||
return this.options.logger;
|
return this.options.logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
async registerInstance(serviceName, ip, port, clusterName = Constants.NAMING_DEFAULT_CLUSTER_NAME) {
|
async registerInstance(serviceName, instance, groupName = Constants.DEFAULT_GROUP) {
|
||||||
let instance = null;
|
if (!(instance instanceof Instance)) {
|
||||||
if (typeof ip === 'object') {
|
instance = new Instance(instance);
|
||||||
instance = new Instance(ip);
|
|
||||||
} else {
|
|
||||||
instance = new Instance({
|
|
||||||
ip,
|
|
||||||
port,
|
|
||||||
weight: 1,
|
|
||||||
clusterName,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
const beatInfo = {
|
const serviceNameWithGroup = utils.getGroupedName(serviceName, groupName);
|
||||||
port,
|
if (instance.ephemeral) {
|
||||||
ip,
|
const beatInfo = {
|
||||||
weight: instance.weight,
|
serviceName: serviceNameWithGroup,
|
||||||
metadata: instance.metadata,
|
ip: instance.ip,
|
||||||
dom: serviceName,
|
port: instance.port,
|
||||||
};
|
cluster: instance.clusterName,
|
||||||
this._beatReactor.addBeatInfo(serviceName, beatInfo);
|
weight: instance.weight,
|
||||||
await this._serverProxy.registerService(serviceName, instance);
|
metadata: instance.metadata,
|
||||||
|
scheduled: false,
|
||||||
|
};
|
||||||
|
this._beatReactor.addBeatInfo(serviceNameWithGroup, beatInfo);
|
||||||
|
}
|
||||||
|
await this._serverProxy.registerService(serviceNameWithGroup, groupName, instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
async deregisterInstance(serviceName, ip, port, clusterName = Constants.NAMING_DEFAULT_CLUSTER_NAME) {
|
async deregisterInstance(serviceName, instance, groupName = Constants.DEFAULT_GROUP) {
|
||||||
this._beatReactor.removeBeatInfo(serviceName, ip, port);
|
if (!(instance instanceof Instance)) {
|
||||||
await this._serverProxy.deregisterService(serviceName, ip, port, clusterName);
|
instance = new Instance(instance);
|
||||||
|
}
|
||||||
|
const serviceNameWithGroup = utils.getGroupedName(serviceName, groupName);
|
||||||
|
this._beatReactor.removeBeatInfo(serviceNameWithGroup, instance.ip, instance.port);
|
||||||
|
await this._serverProxy.deregisterService(serviceName, instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAllInstances(serviceName, clusters = []) {
|
async getAllInstances(serviceName, groupName = Constants.DEFAULT_GROUP, clusters = '', subscribe = true) {
|
||||||
const serviceInfo = await this._hostReactor.getServiceInfo({
|
let serviceInfo;
|
||||||
serviceName,
|
const serviceNameWithGroup = utils.getGroupedName(serviceName, groupName);
|
||||||
clusters,
|
if (subscribe) {
|
||||||
allIPs: false,
|
serviceInfo = await this._hostReactor.getServiceInfo(serviceNameWithGroup, clusters);
|
||||||
env: '',
|
} else {
|
||||||
});
|
serviceInfo = await this._hostReactor.getServiceInfoDirectlyFromServer(serviceNameWithGroup, clusters);
|
||||||
|
}
|
||||||
if (!serviceInfo) return [];
|
if (!serviceInfo) return [];
|
||||||
return serviceInfo.hosts;
|
return serviceInfo.hosts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async selectInstances(serviceName, groupName = Constants.DEFAULT_GROUP, clusters = '', healthy = true, subscribe = true) {
|
||||||
|
let serviceInfo;
|
||||||
|
const serviceNameWithGroup = utils.getGroupedName(serviceName, groupName);
|
||||||
|
if (subscribe) {
|
||||||
|
serviceInfo = await this._hostReactor.getServiceInfo(serviceNameWithGroup, clusters);
|
||||||
|
} else {
|
||||||
|
serviceInfo = await this._hostReactor.getServiceInfoDirectlyFromServer(serviceNameWithGroup, clusters);
|
||||||
|
}
|
||||||
|
if (!serviceInfo || !serviceInfo.hosts || !serviceInfo.hosts.length) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return serviceInfo.hosts.filter(host => {
|
||||||
|
return host.healthy === healthy && host.enabled && host.weight > 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async getServerStatus() {
|
async getServerStatus() {
|
||||||
const isHealthy = await this._serverProxy.serverHealthy();
|
const isHealthy = await this._serverProxy.serverHealthy();
|
||||||
return isHealthy ? 'UP' : 'DOWN';
|
return isHealthy ? 'UP' : 'DOWN';
|
||||||
|
@ -106,7 +122,12 @@ class NacosNamingClient extends Base {
|
||||||
serviceName: info,
|
serviceName: info,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
this._hostReactor.subscribe(info, listener);
|
const groupName = info.groupName || Constants.DEFAULT_GROUP;
|
||||||
|
const serviceNameWithGroup = utils.getGroupedName(info.serviceName, groupName);
|
||||||
|
this._hostReactor.subscribe({
|
||||||
|
serviceName: serviceNameWithGroup,
|
||||||
|
clusters: info.clusters || '',
|
||||||
|
}, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
unSubscribe(info, listener) {
|
unSubscribe(info, listener) {
|
||||||
|
@ -115,12 +136,17 @@ class NacosNamingClient extends Base {
|
||||||
serviceName: info,
|
serviceName: info,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
this._hostReactor.unSubscribe(info, listener);
|
const groupName = info.groupName || Constants.DEFAULT_GROUP;
|
||||||
|
const serviceNameWithGroup = utils.getGroupedName(info.serviceName, groupName);
|
||||||
|
this._hostReactor.unSubscribe({
|
||||||
|
serviceName: serviceNameWithGroup,
|
||||||
|
clusters: info.clusters || '',
|
||||||
|
}, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
close() {
|
async _close() {
|
||||||
this._beatReactor.close();
|
await this._beatReactor.close();
|
||||||
this._hostReactor.close();
|
await this._hostReactor.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ const Base = require('sdk-base');
|
||||||
const Constants = require('../const');
|
const Constants = require('../const');
|
||||||
const ServiceInfo = require('./service_info');
|
const ServiceInfo = require('./service_info');
|
||||||
const PushReceiver = require('./push_receiver');
|
const PushReceiver = require('./push_receiver');
|
||||||
const localIp = require('address').ip();
|
const equals = require('equals');
|
||||||
|
|
||||||
class HostReactor extends Base {
|
class HostReactor extends Base {
|
||||||
constructor(options = {}) {
|
constructor(options = {}) {
|
||||||
|
@ -30,6 +30,9 @@ class HostReactor extends Base {
|
||||||
assert(options.serverProxy, '[HostReactor] options.serverProxy is required');
|
assert(options.serverProxy, '[HostReactor] options.serverProxy is required');
|
||||||
super(Object.assign({}, options, { initMethod: '_init' }));
|
super(Object.assign({}, options, { initMethod: '_init' }));
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// cacheDir
|
||||||
|
|
||||||
this._serviceInfoMap = new Map();
|
this._serviceInfoMap = new Map();
|
||||||
this._updatingSet = new Set();
|
this._updatingSet = new Set();
|
||||||
this._futureMap = new Map();
|
this._futureMap = new Map();
|
||||||
|
@ -53,7 +56,10 @@ class HostReactor extends Base {
|
||||||
}
|
}
|
||||||
|
|
||||||
async _init() {
|
async _init() {
|
||||||
await this._pushReceiver.ready();
|
await Promise.all([
|
||||||
|
this.serverProxy.ready(),
|
||||||
|
this._pushReceiver.ready(),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
processServiceJSON(json) {
|
processServiceJSON(json) {
|
||||||
|
@ -87,7 +93,7 @@ class HostReactor extends Base {
|
||||||
const key = host.ip + ':' + host.port;
|
const key = host.ip + ':' + host.port;
|
||||||
newHostMap.set(key, host);
|
newHostMap.set(key, host);
|
||||||
|
|
||||||
if (oldHostMap.has(key) && JSON.stringify(host) !== JSON.stringify(oldHostMap.get(key))) {
|
if (oldHostMap.has(key) && !equals(host, oldHostMap.get(key))) {
|
||||||
modHosts.push(host);
|
modHosts.push(host);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -128,16 +134,13 @@ class HostReactor extends Base {
|
||||||
this.emit(`${serviceInfo.getKey()}_changed`, serviceInfo.hosts, serviceInfo);
|
this.emit(`${serviceInfo.getKey()}_changed`, serviceInfo.hosts, serviceInfo);
|
||||||
// TODO: 本地缓存
|
// TODO: 本地缓存
|
||||||
}
|
}
|
||||||
this.logger.info('[HostReactor] current ips(%d) service: %s -> %s', serviceInfo.ipCount, serviceInfo.name, JSON.stringify(serviceInfo.hosts));
|
|
||||||
return serviceInfo;
|
return serviceInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
_getKey(param) {
|
_getKey(param) {
|
||||||
const serviceName = param.serviceName;
|
const serviceName = param.serviceName;
|
||||||
const clusters = (param.clusters || []).join(',');
|
const clusters = param.clusters || Constants.NAMING_DEFAULT_CLUSTER_NAME;
|
||||||
const env = param.env || '';
|
return ServiceInfo.getKey(serviceName, clusters);
|
||||||
const allIPs = param.allIPs || false;
|
|
||||||
return ServiceInfo.getKey(serviceName, clusters, env, allIPs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
subscribe(param, listener) {
|
subscribe(param, listener) {
|
||||||
|
@ -146,7 +149,7 @@ class HostReactor extends Base {
|
||||||
if (serviceInfo) {
|
if (serviceInfo) {
|
||||||
setImmediate(() => { listener(serviceInfo.hosts); });
|
setImmediate(() => { listener(serviceInfo.hosts); });
|
||||||
} else {
|
} else {
|
||||||
this.getServiceInfo(param);
|
this.getServiceInfo(param.serviceName, param.clusters || Constants.NAMING_DEFAULT_CLUSTER_NAME);
|
||||||
}
|
}
|
||||||
this.on(key + '_changed', listener);
|
this.on(key + '_changed', listener);
|
||||||
}
|
}
|
||||||
|
@ -160,12 +163,16 @@ class HostReactor extends Base {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getServiceInfo(param) {
|
async getServiceInfoDirectlyFromServer(serviceName, clusters = Constants.NAMING_DEFAULT_CLUSTER_NAME) {
|
||||||
const serviceName = param.serviceName;
|
const result = await this.serverProxy.queryList(serviceName, clusters, 0, false);
|
||||||
const clusters = (param.clusters || []).join(',');
|
if (result) {
|
||||||
const env = param.env || '';
|
return this.processServiceJSON(result);
|
||||||
const allIPs = param.allIPs || false;
|
}
|
||||||
const key = ServiceInfo.getKey(serviceName, clusters, env, allIPs);
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getServiceInfo(serviceName, clusters = Constants.NAMING_DEFAULT_CLUSTER_NAME) {
|
||||||
|
const key = ServiceInfo.getKey(serviceName, clusters);
|
||||||
// TODO: failover
|
// TODO: failover
|
||||||
|
|
||||||
let serviceInfo = this._serviceInfoMap.get(key);
|
let serviceInfo = this._serviceInfoMap.get(key);
|
||||||
|
@ -173,121 +180,54 @@ class HostReactor extends Base {
|
||||||
serviceInfo = new ServiceInfo({
|
serviceInfo = new ServiceInfo({
|
||||||
name: serviceName,
|
name: serviceName,
|
||||||
clusters,
|
clusters,
|
||||||
env,
|
|
||||||
allIPs,
|
|
||||||
hosts: [],
|
hosts: [],
|
||||||
});
|
});
|
||||||
this._serviceInfoMap.set(key, serviceInfo);
|
this._serviceInfoMap.set(key, serviceInfo);
|
||||||
this._updatingSet.add(key);
|
this._updatingSet.add(key);
|
||||||
|
await this.updateServiceNow(serviceName, clusters);
|
||||||
if (allIPs) {
|
|
||||||
await this.updateService4AllIPNow(serviceName, clusters, env);
|
|
||||||
} else {
|
|
||||||
await this.updateServiceNow(serviceName, clusters, env);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._updatingSet.delete(key);
|
this._updatingSet.delete(key);
|
||||||
} else if (this._updatingSet.has(key)) {
|
} else if (this._updatingSet.has(key)) {
|
||||||
// await updating
|
// await updating
|
||||||
await this.await(`${key}_changed`);
|
await this.await(`${key}_changed`);
|
||||||
}
|
}
|
||||||
this._scheduleUpdateIfAbsent(serviceName, clusters, env, allIPs);
|
this._scheduleUpdateIfAbsent(serviceName, clusters);
|
||||||
return this._serviceInfoMap.get(key);
|
return this._serviceInfoMap.get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateService4AllIPNow(serviceName, clusters, env) {
|
async updateServiceNow(serviceName, clusters) {
|
||||||
try {
|
try {
|
||||||
const params = {
|
const result = await this.serverProxy.queryList(serviceName, clusters, this._pushReceiver.udpPort, false);
|
||||||
dom: serviceName,
|
|
||||||
clusters,
|
|
||||||
udpPort: this._pushReceiver.udpPort + '',
|
|
||||||
};
|
|
||||||
const key = ServiceInfo.getKey(serviceName, clusters, env, true);
|
|
||||||
const oldService = this._serviceInfoMap.get(key);
|
|
||||||
if (oldService) {
|
|
||||||
params.checksum = oldService.checksum;
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await this.serverProxy.reqAPI(Constants.NACOS_URL_BASE + '/api/srvAllIP', params);
|
|
||||||
if (result) {
|
|
||||||
const serviceInfo = this.processServiceJSON(result);
|
|
||||||
serviceInfo.isAllIPs = true;
|
|
||||||
}
|
|
||||||
this.logger.debug('[HostReactor] updateService4AllIPNow() serviceName: %s, clusters: %s, env: %s, result: %s',
|
|
||||||
serviceName, clusters, env, result);
|
|
||||||
} catch (err) {
|
|
||||||
err.message = 'failed to update serviceName: ' + serviceName + ', caused by: ' + err.message;
|
|
||||||
this.emit('error', err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateServiceNow(serviceName, clusters, env) {
|
|
||||||
const key = ServiceInfo.getKey(serviceName, clusters, env, false);
|
|
||||||
const oldService = this._serviceInfoMap.get(key);
|
|
||||||
try {
|
|
||||||
const params = {
|
|
||||||
dom: serviceName,
|
|
||||||
clusters,
|
|
||||||
udpPort: this._pushReceiver.udpPort + '',
|
|
||||||
env,
|
|
||||||
clientIP: localIp,
|
|
||||||
unconsistentDom: '', // TODO:
|
|
||||||
};
|
|
||||||
|
|
||||||
const envSpliter = ',';
|
|
||||||
if (env && !env.includes(envSpliter)) {
|
|
||||||
params.useEnvId = 'true';
|
|
||||||
}
|
|
||||||
if (oldService) {
|
|
||||||
params.checksum = oldService.checksum;
|
|
||||||
}
|
|
||||||
const result = await this.serverProxy.reqAPI(Constants.NACOS_URL_BASE + '/api/srvIPXT', params);
|
|
||||||
if (result) {
|
if (result) {
|
||||||
this.processServiceJSON(result);
|
this.processServiceJSON(result);
|
||||||
}
|
}
|
||||||
this.logger.debug('[HostReactor] updateServiceNow() serviceName: %s, clusters: %s, env: %s, result: %s',
|
this.logger.debug('[HostReactor] updateServiceNow() serviceName: %s, clusters: %s, result: %s', serviceName, clusters, result);
|
||||||
serviceName, clusters, env, result);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
err.message = 'failed to update serviceName: ' + serviceName + ', caused by: ' + err.message;
|
err.message = 'failed to update serviceName: ' + serviceName + ', caused by: ' + err.message;
|
||||||
this.emit('error', err);
|
if (err.status === 404) {
|
||||||
}
|
this.logger.warn(err.message);
|
||||||
}
|
|
||||||
|
|
||||||
async refreshOnly(serviceName, clusters, env, allIPs) {
|
|
||||||
try {
|
|
||||||
const params = {
|
|
||||||
dom: serviceName,
|
|
||||||
clusters,
|
|
||||||
udpPort: this._pushReceiver.udpPort + '',
|
|
||||||
unit: env,
|
|
||||||
clientIP: localIp,
|
|
||||||
unconsistentDom: '', // TODO:
|
|
||||||
};
|
|
||||||
|
|
||||||
const envSpliter = ',';
|
|
||||||
if (env && !env.includes(envSpliter)) {
|
|
||||||
params.useEnvId = 'true';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allIPs) {
|
|
||||||
await this.serverProxy.reqAPI(Constants.NACOS_URL_BASE + '/api/srvAllIP', params);
|
|
||||||
} else {
|
} else {
|
||||||
await this.serverProxy.reqAPI(Constants.NACOS_URL_BASE + '/api/srvIPXT', params);
|
this.emit('error', err);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async refreshOnly(serviceName, clusters) {
|
||||||
|
try {
|
||||||
|
await this.serverProxy.queryList(serviceName, clusters, this._pushReceiver.udpPort, false);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
err.message = 'failed to update serviceName: ' + serviceName + ', caused by: ' + err.message;
|
err.message = 'failed to update serviceName: ' + serviceName + ', caused by: ' + err.message;
|
||||||
this.emit('error', err);
|
this.emit('error', err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_scheduleUpdateIfAbsent(serviceName, clusters, env, allIPs) {
|
_scheduleUpdateIfAbsent(serviceName, clusters) {
|
||||||
const key = ServiceInfo.getKey(serviceName, clusters, env, allIPs);
|
const key = ServiceInfo.getKey(serviceName, clusters);
|
||||||
if (this._futureMap.has(key)) {
|
if (this._futureMap.has(key)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 第一次延迟 1s 更新
|
// 第一次延迟 1s 更新
|
||||||
const timer = setTimeout(() => {
|
const timer = setTimeout(() => {
|
||||||
this._doUpdate(serviceName, clusters, env, allIPs)
|
this._doUpdate(serviceName, clusters)
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
this.emit('error', err);
|
this.emit('error', err);
|
||||||
});
|
});
|
||||||
|
@ -299,35 +239,31 @@ class HostReactor extends Base {
|
||||||
this._futureMap.set(key, task);
|
this._futureMap.set(key, task);
|
||||||
}
|
}
|
||||||
|
|
||||||
async _doUpdate(serviceName, clusters, env, allIPs) {
|
async _doUpdate(serviceName, clusters) {
|
||||||
const key = ServiceInfo.getKey(serviceName, clusters, env, allIPs);
|
const key = ServiceInfo.getKey(serviceName, clusters);
|
||||||
const task = this._futureMap.get(key);
|
const task = this._futureMap.get(key);
|
||||||
if (!task) return;
|
if (!task) return;
|
||||||
|
|
||||||
const serviceInfo = this._serviceInfoMap.get(key);
|
const serviceInfo = this._serviceInfoMap.get(key);
|
||||||
if (!serviceInfo || serviceInfo.lastRefTime <= task.lastRefTime) {
|
if (!serviceInfo || serviceInfo.lastRefTime <= task.lastRefTime) {
|
||||||
if (allIPs) {
|
await this.updateServiceNow(serviceName, clusters);
|
||||||
await this.updateService4AllIPNow(serviceName, clusters, env);
|
|
||||||
} else {
|
|
||||||
await this.updateServiceNow(serviceName, clusters, env);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
this.logger.debug('[HostReactor] refreshOnly, serviceInfo.lastRefTime: %s, task.lastRefTime: %s, serviceName: %s, clusters: %s, env: %s',
|
this.logger.debug('[HostReactor] refreshOnly, serviceInfo.lastRefTime: %s, task.lastRefTime: %s, serviceName: %s, clusters: %s',
|
||||||
serviceInfo.lastRefTime, task.lastRefTime, serviceName, clusters, env);
|
serviceInfo.lastRefTime, task.lastRefTime, serviceName, clusters);
|
||||||
// if serviceName already updated by push, we should not override it
|
// if serviceName already updated by push, we should not override it
|
||||||
// since the push data may be different from pull through force push
|
// since the push data may be different from pull through force push
|
||||||
await this.refreshOnly(serviceName, clusters, env, allIPs);
|
await this.refreshOnly(serviceName, clusters);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._futureMap.has(key)) {
|
if (this._futureMap.has(key)) {
|
||||||
const serviceInfo = this._serviceInfoMap.get(key);
|
const serviceInfo = this._serviceInfoMap.get(key);
|
||||||
let delay = 1000;
|
let delay = Constants.DEFAULT_DELAY;
|
||||||
if (serviceInfo) {
|
if (serviceInfo) {
|
||||||
delay = serviceInfo.cacheMillis;
|
delay = serviceInfo.cacheMillis;
|
||||||
task.lastRefTime = serviceInfo.lastRefTime;
|
task.lastRefTime = serviceInfo.lastRefTime;
|
||||||
}
|
}
|
||||||
const timer = setTimeout(() => {
|
const timer = setTimeout(() => {
|
||||||
this._doUpdate(serviceName, clusters, env, allIPs)
|
this._doUpdate(serviceName, clusters)
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
this.emit('error', err);
|
this.emit('error', err);
|
||||||
});
|
});
|
||||||
|
@ -337,7 +273,7 @@ class HostReactor extends Base {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
close() {
|
async _close() {
|
||||||
this._pushReceiver.close();
|
this._pushReceiver.close();
|
||||||
this._updatingSet.clear();
|
this._updatingSet.clear();
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ class Instance {
|
||||||
this.healthy = true;
|
this.healthy = true;
|
||||||
}
|
}
|
||||||
this.enabled = typeof data.enabled === 'boolean' ? data.enabled : true;
|
this.enabled = typeof data.enabled === 'boolean' ? data.enabled : true;
|
||||||
|
this.ephemeral = typeof data.ephemeral === 'boolean' ? data.ephemeral : true;
|
||||||
this.clusterName = data.clusterName || Constants.NAMING_DEFAULT_CLUSTER_NAME; // Cluster information of instance
|
this.clusterName = data.clusterName || Constants.NAMING_DEFAULT_CLUSTER_NAME; // Cluster information of instance
|
||||||
this.serviceName = data.serviceName;
|
this.serviceName = data.serviceName;
|
||||||
this.metadata = data.metadata || {};
|
this.metadata = data.metadata || {};
|
||||||
|
|
|
@ -19,14 +19,22 @@
|
||||||
|
|
||||||
const uuid = require('uuid/v4');
|
const uuid = require('uuid/v4');
|
||||||
const Base = require('sdk-base');
|
const Base = require('sdk-base');
|
||||||
|
const utils = require('../util');
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const utility = require('utility');
|
const utility = require('utility');
|
||||||
const Constants = require('../const');
|
const Constants = require('../const');
|
||||||
|
const localIp = require('address').ip();
|
||||||
|
const sleep = require('mz-modules/sleep');
|
||||||
|
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
namespace: 'default',
|
namespace: 'default',
|
||||||
httpclient: require('urllib'),
|
httpclient: require('urllib'),
|
||||||
ssl: false,
|
ssl: false,
|
||||||
|
ak: null,
|
||||||
|
sk: null,
|
||||||
|
appName: '',
|
||||||
|
endpoint: null,
|
||||||
|
vipSrvRefInterMillis: 30000,
|
||||||
};
|
};
|
||||||
const DEFAULT_SERVER_PORT = 8848;
|
const DEFAULT_SERVER_PORT = 8848;
|
||||||
|
|
||||||
|
@ -36,19 +44,25 @@ class NameProxy extends Base {
|
||||||
if (typeof options.serverList === 'string' && options.serverList) {
|
if (typeof options.serverList === 'string' && options.serverList) {
|
||||||
options.serverList = options.serverList.split(',');
|
options.serverList = options.serverList.split(',');
|
||||||
}
|
}
|
||||||
super(Object.assign({}, defaultOptions, options));
|
super(Object.assign({}, defaultOptions, options, { initMethod: '_init' }));
|
||||||
// 硬负载域名
|
|
||||||
if (options.serverList.length === 1) {
|
|
||||||
this.nacosDomain = options.serverList[0];
|
|
||||||
}
|
|
||||||
this.serverList = options.serverList || [];
|
this.serverList = options.serverList || [];
|
||||||
this.ready(true);
|
// 硬负载域名
|
||||||
|
if (this.serverList.length === 1) {
|
||||||
|
this.nacosDomain = this.serverList[0];
|
||||||
|
}
|
||||||
|
this.serversFromEndpoint = [];
|
||||||
|
this.lastSrvRefTime = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
get logger() {
|
get logger() {
|
||||||
return this.options.logger;
|
return this.options.logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get endpoint() {
|
||||||
|
return this.options.endpoint;
|
||||||
|
}
|
||||||
|
|
||||||
get namespace() {
|
get namespace() {
|
||||||
return this.options.namespace;
|
return this.options.namespace;
|
||||||
}
|
}
|
||||||
|
@ -57,20 +71,99 @@ class NameProxy extends Base {
|
||||||
return this.options.httpclient;
|
return this.options.httpclient;
|
||||||
}
|
}
|
||||||
|
|
||||||
async _callServer(serverAddr, method, api, params) {
|
async _getServerListFromEndpoint() {
|
||||||
const headers = {
|
const urlString = 'http://' + this.endpoint + '/nacos/serverlist';
|
||||||
|
const headers = this._builderHeaders();
|
||||||
|
|
||||||
|
const result = await this.httpclient.request(urlString, {
|
||||||
|
method: 'GET',
|
||||||
|
headers,
|
||||||
|
dataType: 'text',
|
||||||
|
});
|
||||||
|
if (result.status !== 200) {
|
||||||
|
throw new Error('Error while requesting: ' + urlString + ', Server returned: ' + result.status);
|
||||||
|
}
|
||||||
|
const content = result.data;
|
||||||
|
return content.split('\r\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
async _refreshSrvIfNeed() {
|
||||||
|
if (this.serverList.length !== 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Date.now() - this.lastSrvRefTime < this.options.vipSrvRefInterMillis) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const list = await this._getServerListFromEndpoint();
|
||||||
|
if (!list || !list.length) {
|
||||||
|
throw new Error('Can not acquire Nacos list');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.serversFromEndpoint = list;
|
||||||
|
this.lastSrvRefTime = Date.now();
|
||||||
|
} catch (err) {
|
||||||
|
this.logger.warn(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async _init() {
|
||||||
|
if (!this.endpoint) return;
|
||||||
|
|
||||||
|
await this._refreshSrvIfNeed();
|
||||||
|
this._refreshLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
async _refreshLoop() {
|
||||||
|
while (!this._closed) {
|
||||||
|
await sleep(this.options.vipSrvRefInterMillis);
|
||||||
|
await this._refreshSrvIfNeed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_getSignData(serviceName) {
|
||||||
|
return serviceName ? Date.now() + '@@' + serviceName : Date.now() + '';
|
||||||
|
}
|
||||||
|
|
||||||
|
_checkSignature(params) {
|
||||||
|
const { ak, sk, appName } = this.options;
|
||||||
|
if (!ak && !sk) return;
|
||||||
|
|
||||||
|
const signData = this._getSignData(params.serviceName);
|
||||||
|
const signature = utils.sign(signData, sk);
|
||||||
|
params.signature = signature;
|
||||||
|
params.data = signData;
|
||||||
|
params.ak = ak;
|
||||||
|
params.app = appName;
|
||||||
|
}
|
||||||
|
|
||||||
|
_builderHeaders() {
|
||||||
|
return {
|
||||||
|
'User-Agent': Constants.VERSION,
|
||||||
'Client-Version': Constants.VERSION,
|
'Client-Version': Constants.VERSION,
|
||||||
'Accept-Encoding': 'gzip,deflate,sdch',
|
'Accept-Encoding': 'gzip,deflate,sdch',
|
||||||
|
'Request-Module': 'Naming',
|
||||||
Connection: 'Keep-Alive',
|
Connection: 'Keep-Alive',
|
||||||
RequestId: uuid(),
|
RequestId: uuid(),
|
||||||
'User-Agent': 'Nacos-Java-Client',
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async _callServer(serverAddr, method, api, params = {}) {
|
||||||
|
this._checkSignature(params);
|
||||||
|
params.namespaceId = this.namespace;
|
||||||
|
const headers = this._builderHeaders();
|
||||||
|
|
||||||
if (!serverAddr.includes(Constants.SERVER_ADDR_IP_SPLITER)) {
|
if (!serverAddr.includes(Constants.SERVER_ADDR_IP_SPLITER)) {
|
||||||
serverAddr = serverAddr + Constants.SERVER_ADDR_IP_SPLITER + DEFAULT_SERVER_PORT;
|
serverAddr = serverAddr + Constants.SERVER_ADDR_IP_SPLITER + DEFAULT_SERVER_PORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = (this.options.ssl ? 'https://' : 'http://') + serverAddr + api;
|
const url = (this.options.ssl ? 'https://' : 'http://') + serverAddr + api;
|
||||||
|
if (this.options.username && this.options.password) {
|
||||||
|
params.username = this.options.username;
|
||||||
|
params.password = this.options.password;
|
||||||
|
}
|
||||||
const result = await this.httpclient.request(url, {
|
const result = await this.httpclient.request(url, {
|
||||||
method,
|
method,
|
||||||
headers,
|
headers,
|
||||||
|
@ -87,12 +180,13 @@ class NameProxy extends Base {
|
||||||
}
|
}
|
||||||
const err = new Error('failed to req API: ' + url + '. code: ' + result.status + ' msg: ' + result.data);
|
const err = new Error('failed to req API: ' + url + '. code: ' + result.status + ' msg: ' + result.data);
|
||||||
err.name = 'NacosException';
|
err.name = 'NacosException';
|
||||||
|
err.status = result.status;
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
async reqAPI(api, params, method) {
|
async _reqAPI(api, params, method) {
|
||||||
// TODO:
|
// TODO:
|
||||||
const servers = this.serverList;
|
const servers = this.serverList.length ? this.serverList : this.serversFromEndpoint;
|
||||||
const size = servers.length;
|
const size = servers.length;
|
||||||
|
|
||||||
if (size === 0 && !this.nacosDomain) {
|
if (size === 0 && !this.nacosDomain) {
|
||||||
|
@ -123,41 +217,94 @@ class NameProxy extends Base {
|
||||||
throw new Error('failed to req API: ' + api + ' after all servers(' + this.nacosDomain + ') tried');
|
throw new Error('failed to req API: ' + api + ' after all servers(' + this.nacosDomain + ') tried');
|
||||||
}
|
}
|
||||||
|
|
||||||
async registerService(serviceName, instance) {
|
async registerService(serviceName, groupName, instance) {
|
||||||
this.logger.info('[NameProxy][REGISTER-SERVICE] registering service: %s with instance:%j', serviceName, instance);
|
this.logger.info('[NameProxy][REGISTER-SERVICE] %s registering service: %s with instance:%j', this.namespace, serviceName, instance);
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
tenant: this.namespace,
|
namespaceId: this.namespace,
|
||||||
|
serviceName,
|
||||||
|
groupName,
|
||||||
|
clusterName: instance.clusterName,
|
||||||
ip: instance.ip,
|
ip: instance.ip,
|
||||||
port: instance.port + '',
|
port: instance.port + '',
|
||||||
weight: instance.weight + '',
|
weight: instance.weight + '',
|
||||||
enable: instance.enabled ? 'true' : 'false',
|
enable: instance.enabled ? 'true' : 'false',
|
||||||
healthy: instance.healthy ? 'true' : 'false',
|
healthy: instance.healthy ? 'true' : 'false',
|
||||||
|
ephemeral: instance.ephemeral ? 'true' : 'false',
|
||||||
metadata: JSON.stringify(instance.metadata),
|
metadata: JSON.stringify(instance.metadata),
|
||||||
clusterName: instance.clusterName,
|
|
||||||
serviceName,
|
|
||||||
};
|
};
|
||||||
return await this.reqAPI(Constants.NACOS_URL_INSTANCE, params, 'PUT');
|
return await this._reqAPI(Constants.NACOS_URL_INSTANCE, params, 'POST');
|
||||||
}
|
}
|
||||||
|
|
||||||
async deregisterService(serviceName, ip, port, cluster) {
|
async deregisterService(serviceName, instance) {
|
||||||
|
this.logger.info('[NameProxy][DEREGISTER-SERVICE] %s deregistering service: %s with instance:%j', this.namespace, serviceName, instance);
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
tenant: this.namespace,
|
namespaceId: this.namespace,
|
||||||
ip,
|
|
||||||
port: port + '',
|
|
||||||
serviceName,
|
serviceName,
|
||||||
cluster,
|
clusterName: instance.clusterName,
|
||||||
|
ip: instance.ip,
|
||||||
|
port: instance.port + '',
|
||||||
|
ephemeral: instance.ephemeral !== false ? 'true' : 'false',
|
||||||
};
|
};
|
||||||
return await this.reqAPI(Constants.NACOS_URL_INSTANCE, params, 'DELETE');
|
return await this._reqAPI(Constants.NACOS_URL_INSTANCE, params, 'DELETE');
|
||||||
|
}
|
||||||
|
|
||||||
|
async queryList(serviceName, clusters, udpPort, healthyOnly) {
|
||||||
|
const params = {
|
||||||
|
namespaceId: this.namespace,
|
||||||
|
serviceName,
|
||||||
|
clusters,
|
||||||
|
udpPort: udpPort + '',
|
||||||
|
clientIP: localIp,
|
||||||
|
healthyOnly: healthyOnly ? 'true' : 'false',
|
||||||
|
};
|
||||||
|
return await this._reqAPI(Constants.NACOS_URL_BASE + '/instance/list', params, 'GET');
|
||||||
}
|
}
|
||||||
|
|
||||||
async serverHealthy() {
|
async serverHealthy() {
|
||||||
try {
|
try {
|
||||||
await this.reqAPI(Constants.NACOS_URL_BASE + '/api/hello', {}, 'GET');
|
const str = await this._reqAPI(Constants.NACOS_URL_BASE + '/operator/metrics', {}, 'GET');
|
||||||
|
const result = JSON.parse(str);
|
||||||
|
return result && result.status === 'UP';
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
}
|
||||||
|
|
||||||
|
async sendBeat(beatInfo) {
|
||||||
|
try {
|
||||||
|
const params = {
|
||||||
|
beat: JSON.stringify(beatInfo),
|
||||||
|
namespaceId: this.namespace,
|
||||||
|
serviceName: beatInfo.serviceName,
|
||||||
|
};
|
||||||
|
const jsonStr = await this._reqAPI(Constants.NACOS_URL_BASE + '/instance/beat', params, 'PUT');
|
||||||
|
const result = JSON.parse(jsonStr);
|
||||||
|
if (result && result.clientBeatInterval) {
|
||||||
|
return Number(result.clientBeatInterval);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
err.message = `[CLIENT-BEAT] failed to send beat: ${JSON.stringify(beatInfo)}, caused by ${err.message}`;
|
||||||
|
this.logger.error(err);
|
||||||
|
}
|
||||||
|
return Constants.DEFAULT_DELAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getServiceList(pageNo, pageSize, groupName) {
|
||||||
|
const params = {
|
||||||
|
pageNo: pageNo + '',
|
||||||
|
pageSize: pageSize + '',
|
||||||
|
namespaceId: this.namespace,
|
||||||
|
groupName,
|
||||||
|
};
|
||||||
|
// TODO: selector
|
||||||
|
const result = await this._reqAPI(Constants.NACOS_URL_BASE + '/service/list', params, 'GET');
|
||||||
|
const json = JSON.parse(result);
|
||||||
|
return {
|
||||||
|
count: Number(json.count),
|
||||||
|
data: json.doms,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ class PushReceiver extends Base {
|
||||||
});
|
});
|
||||||
this._server.on('message', (msg, rinfo) => this._handlePushMessage(msg, rinfo));
|
this._server.on('message', (msg, rinfo) => this._handlePushMessage(msg, rinfo));
|
||||||
// 随机绑定一个端口
|
// 随机绑定一个端口
|
||||||
this._server.bind();
|
this._server.bind({port: 0, exclusive: true}, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
_handlePushMessage(msg, rinfo) {
|
_handlePushMessage(msg, rinfo) {
|
||||||
|
@ -104,7 +104,13 @@ class PushReceiver extends Base {
|
||||||
}
|
}
|
||||||
|
|
||||||
close() {
|
close() {
|
||||||
this._isClosed = true;
|
return new Promise((resolve) => {
|
||||||
|
this._isClosed = true;
|
||||||
|
if (this._server) {
|
||||||
|
this._server.close(resolve)
|
||||||
|
this._server = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,20 +17,21 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const Constants = require('../const');
|
||||||
const EMPTY = '';
|
const EMPTY = '';
|
||||||
const SPLITER = '@@';
|
const SPLITER = '@@';
|
||||||
const ALL_IPS = '000--00-ALL_IPS--00--000';
|
// const ALL_IPS = '000--00-ALL_IPS--00--000';
|
||||||
|
|
||||||
class ServiceInfo {
|
class ServiceInfo {
|
||||||
constructor(data) {
|
constructor(data) {
|
||||||
this.name = data.name || data.dom;
|
this.name = data.name || data.dom;
|
||||||
|
this.groupName = data.groupName;
|
||||||
this.clusters = data.clusters;
|
this.clusters = data.clusters;
|
||||||
this.isAllIPs = data.allIPs || false;
|
this.isAllIPs = data.allIPs || false;
|
||||||
this.cacheMillis = data.cacheMillis || 1000;
|
this.cacheMillis = data.cacheMillis || Constants.DEFAULT_DELAY;
|
||||||
this.hosts = data.hosts;
|
this.hosts = data.hosts;
|
||||||
this.lastRefTime = data.lastRefTime || 0;
|
this.lastRefTime = data.lastRefTime || 0;
|
||||||
this.checksum = data.checksum || '';
|
this.checksum = data.checksum || '';
|
||||||
this.env = data.env || '';
|
|
||||||
this.jsonFromServer = EMPTY;
|
this.jsonFromServer = EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,81 +40,47 @@ class ServiceInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
get isValid() {
|
get isValid() {
|
||||||
return !!this.hosts;
|
const valid = !!this.hosts;
|
||||||
|
// 如果 this.hosts 是空数组要返回 false
|
||||||
|
if (valid && Array.isArray(this.hosts)) {
|
||||||
|
return this.hosts.length > 0;
|
||||||
|
}
|
||||||
|
return valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
getKey() {
|
getKey() {
|
||||||
const name = this.name;
|
return ServiceInfo.getKey(this.name, this.clusters);
|
||||||
const clusters = this.clusters;
|
|
||||||
const unit = this.env;
|
|
||||||
const isAllIPs = this.isAllIPs;
|
|
||||||
return ServiceInfo.getKey(name, clusters, unit, isAllIPs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toString() {
|
toString() {
|
||||||
return this.getKey();
|
return this.getKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
static getKey(name, clusters, unit, isAllIPs) {
|
static getKey(name, clusters) {
|
||||||
if (!unit) {
|
|
||||||
unit = EMPTY;
|
|
||||||
}
|
|
||||||
if (clusters && unit) {
|
|
||||||
return isAllIPs ? name + SPLITER + clusters + SPLITER + unit + SPLITER + ALL_IPS :
|
|
||||||
name + SPLITER + clusters + SPLITER + unit;
|
|
||||||
}
|
|
||||||
if (clusters) {
|
if (clusters) {
|
||||||
return isAllIPs ? name + SPLITER + clusters + SPLITER + ALL_IPS : name + SPLITER + clusters;
|
return name + SPLITER + clusters;
|
||||||
}
|
}
|
||||||
if (unit) {
|
return name;
|
||||||
return isAllIPs ? name + SPLITER + EMPTY + SPLITER + unit + SPLITER + ALL_IPS :
|
|
||||||
name + SPLITER + EMPTY + SPLITER + unit;
|
|
||||||
}
|
|
||||||
return isAllIPs ? name + SPLITER + ALL_IPS : name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static parse(key) {
|
static fromKey(key) {
|
||||||
const maxKeySectionCount = 4;
|
|
||||||
const allIpFlagIndex = 3;
|
|
||||||
const envIndex = 2;
|
|
||||||
const clusterIndex = 1;
|
|
||||||
const serviceNameIndex = 0;
|
|
||||||
|
|
||||||
let name;
|
let name;
|
||||||
let clusters;
|
let clusters;
|
||||||
let env;
|
let groupName;
|
||||||
let allIPs = false;
|
|
||||||
|
|
||||||
const keys = key.split(SPLITER);
|
const segs = key.split(SPLITER);
|
||||||
if (keys.length >= maxKeySectionCount) {
|
if (segs.length === 2) {
|
||||||
name = keys[serviceNameIndex];
|
groupName = segs[0];
|
||||||
clusters = keys[clusterIndex];
|
name = segs[1];
|
||||||
env = keys[envIndex];
|
} else if (segs.length === 3) {
|
||||||
if (keys[allIpFlagIndex] === ALL_IPS) {
|
groupName = segs[0];
|
||||||
allIPs = true;
|
name = segs[1];
|
||||||
}
|
clusters = segs[2];
|
||||||
} else if (keys.length >= allIpFlagIndex) {
|
|
||||||
name = keys[serviceNameIndex];
|
|
||||||
clusters = keys[clusterIndex];
|
|
||||||
if (keys[envIndex] === ALL_IPS) {
|
|
||||||
allIPs = true;
|
|
||||||
} else {
|
|
||||||
env = keys[envIndex];
|
|
||||||
}
|
|
||||||
} else if (keys.length >= envIndex) {
|
|
||||||
name = keys[serviceNameIndex];
|
|
||||||
if (keys[clusterIndex] === ALL_IPS) {
|
|
||||||
allIPs = true;
|
|
||||||
} else {
|
|
||||||
clusters = keys[clusterIndex];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ServiceInfo({
|
return new ServiceInfo({
|
||||||
name,
|
name,
|
||||||
clusters,
|
clusters,
|
||||||
env,
|
groupName,
|
||||||
allIPs,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const zlib = require('zlib');
|
const zlib = require('zlib');
|
||||||
|
const crypto = require('crypto');
|
||||||
|
const Constants = require('../const');
|
||||||
|
|
||||||
const GZIP_MAGIC = 35615;
|
const GZIP_MAGIC = 35615;
|
||||||
|
|
||||||
|
@ -36,3 +38,25 @@ exports.tryDecompress = buf => {
|
||||||
}
|
}
|
||||||
return zlib.gunzipSync(buf);
|
return zlib.gunzipSync(buf);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports.sign = (data, key) => {
|
||||||
|
return crypto.createHmac('sha1', key).update(data).digest('base64');
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.getGroupedName = (serviceName, groupName) => {
|
||||||
|
return groupName + Constants.SERVICE_INFO_SPLITER + serviceName;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.getServiceName = serviceNameWithGroup => {
|
||||||
|
if (!serviceNameWithGroup.includes(Constants.SERVICE_INFO_SPLITER)) {
|
||||||
|
return serviceNameWithGroup;
|
||||||
|
}
|
||||||
|
return serviceNameWithGroup.split(Constants.SERVICE_INFO_SPLITER)[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.getGroupName = serviceNameWithGroup => {
|
||||||
|
if (!serviceNameWithGroup.includes(Constants.SERVICE_INFO_SPLITER)) {
|
||||||
|
return Constants.DEFAULT_GROUP;
|
||||||
|
}
|
||||||
|
return serviceNameWithGroup.split(Constants.SERVICE_INFO_SPLITER)[0];
|
||||||
|
};
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "nacos-naming",
|
"name": "nacos-naming",
|
||||||
"version": "1.1.0",
|
"version": "2.6.0",
|
||||||
"description": "nacos (https://nacos.io/en-us/) nodejs sdk",
|
"description": "nacos (https://nacos.io/en-us/) nodejs sdk",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"files": [
|
"files": [
|
||||||
"lib",
|
"lib",
|
||||||
"index.js"
|
"index.js",
|
||||||
|
"index.d.ts"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"autod": "autod",
|
"autod": "autod",
|
||||||
|
@ -38,25 +39,26 @@
|
||||||
},
|
},
|
||||||
"ci": {
|
"ci": {
|
||||||
"type": "travis",
|
"type": "travis",
|
||||||
"version": "8, 10"
|
"version": "8, 10, 12"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"address": "^1.0.3",
|
"address": "^1.1.0",
|
||||||
|
"equals": "^1.0.5",
|
||||||
"mz-modules": "^2.1.0",
|
"mz-modules": "^2.1.0",
|
||||||
"sdk-base": "^3.5.1",
|
"sdk-base": "^3.6.0",
|
||||||
"urllib": "^2.33.0",
|
"urllib": "^2.33.3",
|
||||||
"utility": "^1.15.0",
|
"utility": "^1.16.1",
|
||||||
"uuid": "^3.3.2"
|
"uuid": "^3.3.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"autod": "^3.0.1",
|
"autod": "^3.1.0",
|
||||||
"await-event": "^2.1.0",
|
"await-event": "^2.1.0",
|
||||||
"contributors": "^0.5.1",
|
"contributors": "^0.5.1",
|
||||||
"egg-bin": "^4.10.0",
|
"egg-bin": "^4.13.1",
|
||||||
"egg-ci": "^1.11.0",
|
"egg-ci": "^1.11.0",
|
||||||
"eslint": "^5.12.0",
|
"eslint": "^5.16.0",
|
||||||
"eslint-config-egg": "^7.1.0",
|
"eslint-config-egg": "^7.3.1",
|
||||||
"mm": "^2.4.1",
|
"mm": "^2.5.0",
|
||||||
"mz-modules": "^2.1.0"
|
"mz-modules": "^2.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,18 +36,32 @@ describe('test/naming/client.test.js', () => {
|
||||||
await client.ready();
|
await client.ready();
|
||||||
});
|
});
|
||||||
afterEach(mm.restore);
|
afterEach(mm.restore);
|
||||||
after(() => {
|
after(async () => {
|
||||||
client.close();
|
await client.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should registerInstance & deregisterInstance ok', async function() {
|
it('should registerInstance & deregisterInstance ok', async function() {
|
||||||
client.subscribe(serviceName, hosts => {
|
client.subscribe({
|
||||||
|
serviceName,
|
||||||
|
clusters: 'NODEJS',
|
||||||
|
}, hosts => {
|
||||||
console.log(hosts);
|
console.log(hosts);
|
||||||
client.emit('update', hosts);
|
client.emit('update', hosts);
|
||||||
});
|
});
|
||||||
|
|
||||||
client.registerInstance(serviceName, '1.1.1.1', 8080, 'NODEJS');
|
const instance_1 = {
|
||||||
client.registerInstance(serviceName, '2.2.2.2', 8080, 'NODEJS');
|
ip: '1.1.1.1',
|
||||||
|
port: 8080,
|
||||||
|
clusterName: 'NODEJS',
|
||||||
|
};
|
||||||
|
const instance_2 = {
|
||||||
|
ip: '2.2.2.2',
|
||||||
|
port: 8080,
|
||||||
|
clusterName: 'NODEJS',
|
||||||
|
};
|
||||||
|
|
||||||
|
client.registerInstance(serviceName, instance_1);
|
||||||
|
client.registerInstance(serviceName, instance_2);
|
||||||
|
|
||||||
let hosts = [];
|
let hosts = [];
|
||||||
|
|
||||||
|
@ -58,7 +72,7 @@ describe('test/naming/client.test.js', () => {
|
||||||
assert(hosts.find(host => host.ip === '1.1.1.1' && host.port === 8080));
|
assert(hosts.find(host => host.ip === '1.1.1.1' && host.port === 8080));
|
||||||
assert(hosts.find(host => host.ip === '2.2.2.2' && host.port === 8080));
|
assert(hosts.find(host => host.ip === '2.2.2.2' && host.port === 8080));
|
||||||
|
|
||||||
client.deregisterInstance(serviceName, '1.1.1.1', 8080, 'NODEJS');
|
client.deregisterInstance(serviceName, instance_1);
|
||||||
|
|
||||||
while (hosts.length !== 1) {
|
while (hosts.length !== 1) {
|
||||||
hosts = await client.await('update');
|
hosts = await client.await('update');
|
||||||
|
@ -66,7 +80,54 @@ describe('test/naming/client.test.js', () => {
|
||||||
|
|
||||||
assert(hosts.find(host => host.ip === '2.2.2.2' && host.port === 8080));
|
assert(hosts.find(host => host.ip === '2.2.2.2' && host.port === 8080));
|
||||||
|
|
||||||
client.deregisterInstance(serviceName, '2.2.2.2', 8080, 'NODEJS');
|
client.deregisterInstance(serviceName, instance_2);
|
||||||
|
|
||||||
|
while (hosts.length !== 0) {
|
||||||
|
hosts = await client.await('update');
|
||||||
|
}
|
||||||
|
|
||||||
|
client.unSubscribe({
|
||||||
|
serviceName,
|
||||||
|
clusters: 'NODEJS',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should registerInstance & deregisterInstance with default cluster ok', async function() {
|
||||||
|
client.subscribe(serviceName, hosts => {
|
||||||
|
console.log(hosts);
|
||||||
|
client.emit('update', hosts);
|
||||||
|
});
|
||||||
|
|
||||||
|
const instance_1 = {
|
||||||
|
ip: '1.1.1.1',
|
||||||
|
port: 8080,
|
||||||
|
};
|
||||||
|
const instance_2 = {
|
||||||
|
ip: '2.2.2.2',
|
||||||
|
port: 8080,
|
||||||
|
};
|
||||||
|
|
||||||
|
client.registerInstance(serviceName, instance_1);
|
||||||
|
client.registerInstance(serviceName, instance_2);
|
||||||
|
|
||||||
|
let hosts = [];
|
||||||
|
|
||||||
|
while (hosts.length !== 2) {
|
||||||
|
hosts = await client.await('update');
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(hosts.find(host => host.ip === '1.1.1.1' && host.port === 8080));
|
||||||
|
assert(hosts.find(host => host.ip === '2.2.2.2' && host.port === 8080));
|
||||||
|
|
||||||
|
client.deregisterInstance(serviceName, instance_1);
|
||||||
|
|
||||||
|
while (hosts.length !== 1) {
|
||||||
|
hosts = await client.await('update');
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(hosts.find(host => host.ip === '2.2.2.2' && host.port === 8080));
|
||||||
|
|
||||||
|
client.deregisterInstance(serviceName, instance_2);
|
||||||
|
|
||||||
while (hosts.length !== 0) {
|
while (hosts.length !== 0) {
|
||||||
hosts = await client.await('update');
|
hosts = await client.await('update');
|
||||||
|
@ -86,18 +147,37 @@ describe('test/naming/client.test.js', () => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
await sleep(2000);
|
await sleep(2000);
|
||||||
const hosts = await client.getAllInstances(serviceName);
|
let hosts = await client.getAllInstances(serviceName);
|
||||||
console.log(hosts);
|
console.log(hosts);
|
||||||
const host = hosts.find(host => {
|
const host = hosts.find(host => {
|
||||||
return host.ip === '1.1.1.1' && host.port === 8888;
|
return host.ip === '1.1.1.1' && host.port === 8888;
|
||||||
});
|
});
|
||||||
assert.deepEqual(host.metadata, { foo: 'bar', xxx: 'yyy' });
|
assert.deepEqual(host.metadata, { foo: 'bar', xxx: 'yyy' });
|
||||||
|
|
||||||
|
hosts = null;
|
||||||
|
client.subscribe(serviceName, val => {
|
||||||
|
hosts = val;
|
||||||
|
});
|
||||||
|
|
||||||
|
await sleep(10000);
|
||||||
|
assert(hosts && hosts.length === 1);
|
||||||
|
assert(hosts[0].ip === '1.1.1.1');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should getAllInstances ok', async function() {
|
it('should getAllInstances ok', async function() {
|
||||||
await client.registerInstance(serviceName, '1.1.1.1', 8080, 'NODEJS');
|
const serviceName = 'nodejs.test.getAllInstances' + process.versions.node;
|
||||||
await client.registerInstance(serviceName, '2.2.2.2', 8080, 'OTHERS');
|
const instance_1 = {
|
||||||
|
ip: '1.1.1.1',
|
||||||
|
port: 8080,
|
||||||
|
clusterName: 'NODEJS',
|
||||||
|
};
|
||||||
|
const instance_2 = {
|
||||||
|
ip: '2.2.2.2',
|
||||||
|
port: 8080,
|
||||||
|
clusterName: 'OTHERS',
|
||||||
|
};
|
||||||
|
await client.registerInstance(serviceName, instance_1);
|
||||||
|
await client.registerInstance(serviceName, instance_2);
|
||||||
await sleep(2000);
|
await sleep(2000);
|
||||||
|
|
||||||
let hosts = await client.getAllInstances(serviceName);
|
let hosts = await client.getAllInstances(serviceName);
|
||||||
|
@ -105,12 +185,22 @@ describe('test/naming/client.test.js', () => {
|
||||||
assert(hosts.find(host => host.ip === '1.1.1.1' && host.port === 8080));
|
assert(hosts.find(host => host.ip === '1.1.1.1' && host.port === 8080));
|
||||||
assert(hosts.find(host => host.ip === '2.2.2.2' && host.port === 8080));
|
assert(hosts.find(host => host.ip === '2.2.2.2' && host.port === 8080));
|
||||||
|
|
||||||
hosts = await client.getAllInstances(serviceName, [ 'NODEJS' ]);
|
hosts = await client.getAllInstances(serviceName, 'DEFAULT_GROUP', 'NODEJS,OTHERS');
|
||||||
|
assert(hosts.length === 2);
|
||||||
|
assert(hosts.find(host => host.ip === '1.1.1.1' && host.port === 8080));
|
||||||
|
assert(hosts.find(host => host.ip === '2.2.2.2' && host.port === 8080));
|
||||||
|
|
||||||
|
hosts = await client.getAllInstances(serviceName, 'DEFAULT_GROUP', 'NODEJS,OTHERS', false);
|
||||||
|
assert(hosts.length === 2);
|
||||||
|
assert(hosts.find(host => host.ip === '1.1.1.1' && host.port === 8080));
|
||||||
|
assert(hosts.find(host => host.ip === '2.2.2.2' && host.port === 8080));
|
||||||
|
|
||||||
|
hosts = await client.getAllInstances(serviceName, 'DEFAULT_GROUP', 'NODEJS');
|
||||||
assert(hosts.length === 1);
|
assert(hosts.length === 1);
|
||||||
assert(hosts.find(host => host.ip === '1.1.1.1' && host.port === 8080));
|
assert(hosts.find(host => host.ip === '1.1.1.1' && host.port === 8080));
|
||||||
|
|
||||||
await client.deregisterInstance(serviceName, '1.1.1.1', 8080, 'NODEJS');
|
await client.deregisterInstance(serviceName, instance_1);
|
||||||
await client.deregisterInstance(serviceName, '2.2.2.2', 8080, 'OTHERS');
|
await client.deregisterInstance(serviceName, instance_2);
|
||||||
|
|
||||||
await sleep(2000);
|
await sleep(2000);
|
||||||
|
|
||||||
|
@ -118,6 +208,67 @@ describe('test/naming/client.test.js', () => {
|
||||||
assert(hosts.length === 0);
|
assert(hosts.length === 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should selectInstances ok', async function() {
|
||||||
|
const serviceName = 'nodejs.test.selectInstance' + process.versions.node;
|
||||||
|
const instance_1 = {
|
||||||
|
ip: '11.11.11.11',
|
||||||
|
port: 8080,
|
||||||
|
healthy: true,
|
||||||
|
clusterName: 'NODEJS',
|
||||||
|
ephemeral: false,
|
||||||
|
};
|
||||||
|
const instance_2 = {
|
||||||
|
ip: '22.22.22.22',
|
||||||
|
port: 8080,
|
||||||
|
healthy: false,
|
||||||
|
clusterName: 'OTHERS',
|
||||||
|
ephemeral: false,
|
||||||
|
};
|
||||||
|
const instance_3 = {
|
||||||
|
ip: '33.33.33.33',
|
||||||
|
port: 8080,
|
||||||
|
healthy: true,
|
||||||
|
clusterName: 'OTHERS',
|
||||||
|
ephemeral: false,
|
||||||
|
};
|
||||||
|
await client.registerInstance(serviceName, instance_1);
|
||||||
|
await client.registerInstance(serviceName, instance_2);
|
||||||
|
await client.registerInstance(serviceName, instance_3);
|
||||||
|
await sleep(2000);
|
||||||
|
|
||||||
|
let hosts = await client.selectInstances(serviceName);
|
||||||
|
assert(hosts.length === 2);
|
||||||
|
assert(hosts.find(host => host.ip === '11.11.11.11' && host.port === 8080));
|
||||||
|
assert(hosts.find(host => host.ip === '33.33.33.33' && host.port === 8080));
|
||||||
|
|
||||||
|
hosts = await client.selectInstances(serviceName, 'DEFAULT_GROUP', 'NODEJS,OTHERS');
|
||||||
|
assert(hosts.length === 2);
|
||||||
|
assert(hosts.find(host => host.ip === '11.11.11.11' && host.port === 8080));
|
||||||
|
assert(hosts.find(host => host.ip === '33.33.33.33' && host.port === 8080));
|
||||||
|
|
||||||
|
hosts = await client.selectInstances(serviceName, 'DEFAULT_GROUP', 'NODEJS,OTHERS', false, false);
|
||||||
|
assert(hosts.length === 1);
|
||||||
|
// assert(hosts.find(host => host.ip === '1.1.1.1' && host.port === 8080));
|
||||||
|
assert(hosts.find(host => host.ip === '22.22.22.22' && host.port === 8080));
|
||||||
|
|
||||||
|
hosts = await client.selectInstances(serviceName, 'DEFAULT_GROUP', 'OTHERS');
|
||||||
|
assert(hosts.length === 1);
|
||||||
|
assert(hosts.find(host => host.ip === '33.33.33.33' && host.port === 8080));
|
||||||
|
|
||||||
|
hosts = await client.selectInstances(serviceName, 'DEFAULT_GROUP', 'OTHERS', false);
|
||||||
|
assert(hosts.length === 1);
|
||||||
|
assert(hosts.find(host => host.ip === '22.22.22.22' && host.port === 8080));
|
||||||
|
|
||||||
|
await client.deregisterInstance(serviceName, instance_1);
|
||||||
|
await client.deregisterInstance(serviceName, instance_2);
|
||||||
|
await client.deregisterInstance(serviceName, instance_3);
|
||||||
|
|
||||||
|
await sleep(2000);
|
||||||
|
|
||||||
|
hosts = await client.selectInstances(serviceName);
|
||||||
|
assert(hosts.length === 0);
|
||||||
|
});
|
||||||
|
|
||||||
it('should getServerStatus ok', async function() {
|
it('should getServerStatus ok', async function() {
|
||||||
let status = await client.getServerStatus();
|
let status = await client.getServerStatus();
|
||||||
assert(status === 'UP');
|
assert(status === 'UP');
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const mm = require('mm');
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const NameProxy = require('../../lib/naming/proxy');
|
const NameProxy = require('../../lib/naming/proxy');
|
||||||
const Instance = require('../../lib/naming/instance');
|
const Instance = require('../../lib/naming/instance');
|
||||||
|
@ -24,13 +25,24 @@ const HostReactor = require('../../lib/naming/host_reactor');
|
||||||
|
|
||||||
const logger = console;
|
const logger = console;
|
||||||
const serviceName = 'nodejs.test.' + process.versions.node;
|
const serviceName = 'nodejs.test.' + process.versions.node;
|
||||||
|
const groupName = 'DEFAULT_GROUP';
|
||||||
|
const serviceNameWithGroup = groupName + '@@' + serviceName;
|
||||||
|
|
||||||
describe('test/naming/host_reactor.test.js', () => {
|
describe('test/naming/host_reactor.test.js', () => {
|
||||||
it('should ok', async function() {
|
let serverProxy;
|
||||||
const serverProxy = new NameProxy({
|
before(async () => {
|
||||||
|
serverProxy = new NameProxy({
|
||||||
logger,
|
logger,
|
||||||
serverList: '127.0.0.1:8848',
|
serverList: '127.0.0.1:8848',
|
||||||
});
|
});
|
||||||
|
await serverProxy.ready();
|
||||||
|
});
|
||||||
|
after(async () => {
|
||||||
|
await serverProxy.close();
|
||||||
|
});
|
||||||
|
afterEach(mm.restore);
|
||||||
|
|
||||||
|
it('should ok', async function() {
|
||||||
const hostReactor = new HostReactor({
|
const hostReactor = new HostReactor({
|
||||||
logger,
|
logger,
|
||||||
serverProxy,
|
serverProxy,
|
||||||
|
@ -38,7 +50,8 @@ describe('test/naming/host_reactor.test.js', () => {
|
||||||
await hostReactor.ready();
|
await hostReactor.ready();
|
||||||
|
|
||||||
hostReactor.subscribe({
|
hostReactor.subscribe({
|
||||||
serviceName,
|
serviceName: serviceNameWithGroup,
|
||||||
|
clusters: 'NODEJS',
|
||||||
}, hosts => {
|
}, hosts => {
|
||||||
hostReactor.emit('update', hosts);
|
hostReactor.emit('update', hosts);
|
||||||
});
|
});
|
||||||
|
@ -52,70 +65,79 @@ describe('test/naming/host_reactor.test.js', () => {
|
||||||
valid: true,
|
valid: true,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
});
|
});
|
||||||
serverProxy.registerService(serviceName, instance);
|
serverProxy.registerService(serviceNameWithGroup, groupName, instance);
|
||||||
|
|
||||||
let hosts = [];
|
let hosts = [];
|
||||||
|
|
||||||
while (hosts.length !== 1) {
|
while (hosts.length !== 1) {
|
||||||
hosts = await hostReactor.await('update');
|
hosts = await hostReactor.await('update');
|
||||||
}
|
}
|
||||||
assert(hosts.find(host => host.ip === '1.1.1.1' && host.port === 8080));
|
assert(hosts.some(host => host.ip === '1.1.1.1' && host.port === 8080));
|
||||||
|
|
||||||
|
const key = serviceNameWithGroup + '@@NODEJS';
|
||||||
console.log(hostReactor.getServiceInfoMap);
|
console.log(hostReactor.getServiceInfoMap);
|
||||||
assert(hostReactor.getServiceInfoMap && hostReactor.getServiceInfoMap[serviceName]);
|
assert(hostReactor.getServiceInfoMap && hostReactor.getServiceInfoMap[key]);
|
||||||
|
|
||||||
hostReactor.processServiceJSON(JSON.stringify({
|
hostReactor.processServiceJSON(JSON.stringify({
|
||||||
dom: serviceName,
|
metadata: {},
|
||||||
clusters: '',
|
dom: serviceNameWithGroup,
|
||||||
isAllIPs: false,
|
|
||||||
cacheMillis: 10000,
|
cacheMillis: 10000,
|
||||||
|
useSpecifiedURL: false,
|
||||||
hosts: null,
|
hosts: null,
|
||||||
lastRefTime: 1542806333263,
|
name: serviceNameWithGroup,
|
||||||
checksum: 'c1762ddd16f512ae13bcf2c5a07e2e221542806333263',
|
checksum: 'cc4e0ff13773c6d443d9ba0532b32810',
|
||||||
|
lastRefTime: 1556603044852,
|
||||||
env: '',
|
env: '',
|
||||||
|
clusters: 'NODEJS',
|
||||||
}));
|
}));
|
||||||
assert(hostReactor.getServiceInfoMap[serviceName].hosts.length === 1);
|
assert(hostReactor.getServiceInfoMap[key].hosts.length === 1);
|
||||||
|
|
||||||
hostReactor.processServiceJSON(JSON.stringify({
|
hostReactor.processServiceJSON(JSON.stringify({
|
||||||
dom: serviceName,
|
metadata: {},
|
||||||
clusters: '',
|
dom: serviceNameWithGroup,
|
||||||
isAllIPs: false,
|
|
||||||
cacheMillis: 10000,
|
cacheMillis: 10000,
|
||||||
hosts: hostReactor.getServiceInfoMap[serviceName].hosts,
|
useSpecifiedURL: false,
|
||||||
lastRefTime: 1542806333262,
|
hosts: hostReactor.getServiceInfoMap[key].hosts,
|
||||||
checksum: 'c1762ddd16f512ae13bcf2c5a07e2e221542806333263',
|
name: serviceNameWithGroup,
|
||||||
|
checksum: 'cc4e0ff13773c6d443d9ba0532b32811',
|
||||||
|
lastRefTime: 1556603044852,
|
||||||
env: '',
|
env: '',
|
||||||
|
clusters: 'NODEJS',
|
||||||
}));
|
}));
|
||||||
assert(hostReactor.getServiceInfoMap[serviceName].hosts.length === 1);
|
assert(hostReactor.getServiceInfoMap[key].hosts.length === 1);
|
||||||
|
|
||||||
hostReactor.processServiceJSON(JSON.stringify({
|
hostReactor.processServiceJSON(JSON.stringify({
|
||||||
dom: serviceName,
|
metadata: {},
|
||||||
clusters: '',
|
dom: serviceNameWithGroup,
|
||||||
isAllIPs: false,
|
|
||||||
cacheMillis: 10000,
|
cacheMillis: 10000,
|
||||||
hosts: hostReactor.getServiceInfoMap[serviceName].hosts.map(host => {
|
useSpecifiedURL: false,
|
||||||
|
hosts: hostReactor.getServiceInfoMap[key].hosts.map(host => {
|
||||||
return Object.assign({}, host, { enabled: false });
|
return Object.assign({}, host, { enabled: false });
|
||||||
}),
|
}),
|
||||||
lastRefTime: 1542806333262,
|
name: serviceNameWithGroup,
|
||||||
checksum: 'c1762ddd16f512ae13bcf2c5a07e2e221542806333263',
|
checksum: 'cc4e0ff13773c6d443d9ba0532b32812',
|
||||||
|
lastRefTime: 1556603044852,
|
||||||
env: '',
|
env: '',
|
||||||
|
clusters: 'NODEJS',
|
||||||
}));
|
}));
|
||||||
assert(hostReactor.getServiceInfoMap[serviceName].hosts.length === 1);
|
assert(hostReactor.getServiceInfoMap[key].hosts.length === 1);
|
||||||
assert(!hostReactor.getServiceInfoMap[serviceName].hosts[0].enabled);
|
assert(!hostReactor.getServiceInfoMap[key].hosts[0].enabled);
|
||||||
|
|
||||||
hostReactor.processServiceJSON(JSON.stringify({
|
hostReactor.processServiceJSON(JSON.stringify({
|
||||||
dom: serviceName + '_1',
|
metadata: {},
|
||||||
clusters: '',
|
dom: 'mock_dom',
|
||||||
isAllIPs: false,
|
|
||||||
cacheMillis: 10000,
|
cacheMillis: 10000,
|
||||||
hosts: hostReactor.getServiceInfoMap[serviceName].hosts,
|
useSpecifiedURL: false,
|
||||||
lastRefTime: 1542806333263,
|
hosts: hostReactor.getServiceInfoMap[key].hosts,
|
||||||
checksum: 'c1762ddd16f512ae13bcf2c5a07e2e221542806333263',
|
name: 'mock_dom',
|
||||||
|
checksum: 'cc4e0ff13773c6d443d9ba0532b32813',
|
||||||
|
lastRefTime: 1556603044852,
|
||||||
env: '',
|
env: '',
|
||||||
|
clusters: 'NODEJS',
|
||||||
}));
|
}));
|
||||||
assert(hostReactor.getServiceInfoMap[serviceName + '_1']);
|
assert(hostReactor.getServiceInfoMap['mock_dom@@NODEJS']);
|
||||||
|
|
||||||
serverProxy.deregisterService(serviceName, instance.ip, instance.port, instance.clusterName);
|
serverProxy.deregisterService(serviceName, instance);
|
||||||
|
|
||||||
while (hosts.length !== 0) {
|
while (hosts.length !== 0) {
|
||||||
hosts = await hostReactor.await('update');
|
hosts = await hostReactor.await('update');
|
||||||
|
@ -125,20 +147,18 @@ describe('test/naming/host_reactor.test.js', () => {
|
||||||
assert(hosts.length === 0);
|
assert(hosts.length === 0);
|
||||||
};
|
};
|
||||||
hostReactor.subscribe({
|
hostReactor.subscribe({
|
||||||
serviceName,
|
serviceName: serviceNameWithGroup,
|
||||||
|
clusters: 'NODEJS',
|
||||||
}, listener);
|
}, listener);
|
||||||
hostReactor.unSubscribe({
|
hostReactor.unSubscribe({
|
||||||
serviceName,
|
serviceName: serviceNameWithGroup,
|
||||||
|
clusters: 'NODEJS',
|
||||||
}, listener);
|
}, listener);
|
||||||
|
|
||||||
hostReactor.close();
|
await hostReactor.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should updateService4AllIPNow ok', async function() {
|
it('should updateServiceNow ok', async () => {
|
||||||
const serverProxy = new NameProxy({
|
|
||||||
logger,
|
|
||||||
serverList: '127.0.0.1:8848',
|
|
||||||
});
|
|
||||||
const hostReactor = new HostReactor({
|
const hostReactor = new HostReactor({
|
||||||
logger,
|
logger,
|
||||||
serverProxy,
|
serverProxy,
|
||||||
|
@ -146,17 +166,36 @@ describe('test/naming/host_reactor.test.js', () => {
|
||||||
await hostReactor.ready();
|
await hostReactor.ready();
|
||||||
|
|
||||||
const arr = await Promise.all([
|
const arr = await Promise.all([
|
||||||
hostReactor.getServiceInfo({
|
hostReactor.getServiceInfo(serviceNameWithGroup, 'NODEJS'),
|
||||||
serviceName,
|
hostReactor.getServiceInfo(serviceNameWithGroup, 'NODEJS'),
|
||||||
allIPs: true,
|
|
||||||
}),
|
|
||||||
hostReactor.getServiceInfo({
|
|
||||||
serviceName,
|
|
||||||
allIPs: true,
|
|
||||||
}),
|
|
||||||
]);
|
]);
|
||||||
console.log(arr);
|
assert(arr && arr.length === 2);
|
||||||
|
assert(arr.every(item => !!item));
|
||||||
|
|
||||||
hostReactor.close();
|
await hostReactor.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should emit error if serverProxy.queryList failed', async () => {
|
||||||
|
mm.error(serverProxy, 'queryList', 'mock error');
|
||||||
|
|
||||||
|
const hostReactor = new HostReactor({
|
||||||
|
logger,
|
||||||
|
serverProxy,
|
||||||
|
});
|
||||||
|
await hostReactor.ready();
|
||||||
|
|
||||||
|
hostReactor.updateServiceNow(serviceNameWithGroup, 'NODEJS');
|
||||||
|
|
||||||
|
await assert.rejects(async () => {
|
||||||
|
await hostReactor.await('error');
|
||||||
|
}, /failed to update serviceName/);
|
||||||
|
|
||||||
|
hostReactor.refreshOnly(serviceNameWithGroup, 'NODEJS');
|
||||||
|
|
||||||
|
await assert.rejects(async () => {
|
||||||
|
await hostReactor.await('error');
|
||||||
|
}, /failed to update serviceName/);
|
||||||
|
|
||||||
|
await hostReactor.close();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -28,7 +28,7 @@ describe('test/naming/instance.test.js', () => {
|
||||||
valid: true,
|
valid: true,
|
||||||
enabled: false,
|
enabled: false,
|
||||||
});
|
});
|
||||||
assert(instance1.toString() === '{"ip":"1.1.1.1","port":8888,"weight":1,"healthy":true,"enabled":false,"clusterName":"DEFAULT","metadata":{}}');
|
assert(instance1.toString() === '{"ip":"1.1.1.1","port":8888,"weight":1,"healthy":true,"enabled":false,"ephemeral":true,"clusterName":"DEFAULT","metadata":{}}');
|
||||||
assert(instance1.toInetAddr() === '1.1.1.1:8888');
|
assert(instance1.toInetAddr() === '1.1.1.1:8888');
|
||||||
|
|
||||||
const instance2 = new Instance({
|
const instance2 = new Instance({
|
||||||
|
@ -37,7 +37,7 @@ describe('test/naming/instance.test.js', () => {
|
||||||
healthy: true,
|
healthy: true,
|
||||||
enabled: false,
|
enabled: false,
|
||||||
});
|
});
|
||||||
assert(instance2.toString() === '{"ip":"1.1.1.1","port":8888,"weight":1,"healthy":true,"enabled":false,"clusterName":"DEFAULT","metadata":{}}');
|
assert(instance2.toString() === '{"ip":"1.1.1.1","port":8888,"weight":1,"healthy":true,"enabled":false,"ephemeral":true,"clusterName":"DEFAULT","metadata":{}}');
|
||||||
assert(instance2.toInetAddr() === '1.1.1.1:8888');
|
assert(instance2.toInetAddr() === '1.1.1.1:8888');
|
||||||
|
|
||||||
assert(instance1.equal(instance2));
|
assert(instance1.equal(instance2));
|
||||||
|
@ -46,7 +46,7 @@ describe('test/naming/instance.test.js', () => {
|
||||||
ip: '1.1.1.1',
|
ip: '1.1.1.1',
|
||||||
port: 8888,
|
port: 8888,
|
||||||
});
|
});
|
||||||
assert(instance3.toString() === '{"ip":"1.1.1.1","port":8888,"weight":1,"healthy":true,"enabled":true,"clusterName":"DEFAULT","metadata":{}}');
|
assert(instance3.toString() === '{"ip":"1.1.1.1","port":8888,"weight":1,"healthy":true,"enabled":true,"ephemeral":true,"clusterName":"DEFAULT","metadata":{}}');
|
||||||
assert(instance3.toInetAddr() === '1.1.1.1:8888');
|
assert(instance3.toInetAddr() === '1.1.1.1:8888');
|
||||||
|
|
||||||
assert(!instance1.equal(instance3));
|
assert(!instance1.equal(instance3));
|
||||||
|
|
|
@ -18,8 +18,11 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const mm = require('mm');
|
const mm = require('mm');
|
||||||
|
const http = require('http');
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
const sleep = require('mz-modules/sleep');
|
||||||
const NameProxy = require('../../lib/naming/proxy');
|
const NameProxy = require('../../lib/naming/proxy');
|
||||||
|
const Instance = require('../../lib/naming/instance');
|
||||||
|
|
||||||
const logger = console;
|
const logger = console;
|
||||||
const serviceName = 'nodejs.test.' + process.versions.node;
|
const serviceName = 'nodejs.test.' + process.versions.node;
|
||||||
|
@ -33,40 +36,43 @@ describe('test/naming/proxy.test.js', () => {
|
||||||
serverList: '127.0.0.1',
|
serverList: '127.0.0.1',
|
||||||
});
|
});
|
||||||
await proxy.ready();
|
await proxy.ready();
|
||||||
let result = await proxy.registerService(serviceName, {
|
const groupName = 'DEFAULT_GROUP';
|
||||||
|
const instance = new Instance({
|
||||||
ip: '1.1.1.1',
|
ip: '1.1.1.1',
|
||||||
port: 8080,
|
port: 8080,
|
||||||
clusterName: 'NODEJS',
|
clusterName: 'NODEJS',
|
||||||
weight: 1.0,
|
weight: 1.0,
|
||||||
metadata: {},
|
metadata: {},
|
||||||
});
|
|
||||||
assert(result === 'ok');
|
|
||||||
|
|
||||||
let jsonStr = await proxy.reqAPI('/nacos/v1/ns/instances', {
|
|
||||||
serviceName,
|
serviceName,
|
||||||
}, 'GET');
|
});
|
||||||
|
let result = await proxy.registerService(serviceName, groupName, instance);
|
||||||
|
assert(result === 'ok');
|
||||||
|
await sleep(1000);
|
||||||
|
|
||||||
|
let jsonStr = await proxy.queryList(serviceName, 'NODEJS', '', 'false');
|
||||||
let serviceInfo = JSON.parse(jsonStr);
|
let serviceInfo = JSON.parse(jsonStr);
|
||||||
|
|
||||||
assert(serviceInfo && serviceInfo.dom === serviceName);
|
assert(serviceInfo && serviceInfo.dom === 'DEFAULT_GROUP@@' + serviceName);
|
||||||
assert(serviceInfo.hosts && serviceInfo.hosts.length === 1);
|
assert(serviceInfo.hosts && serviceInfo.hosts.length === 1);
|
||||||
assert(serviceInfo.hosts[0].ip === '1.1.1.1');
|
assert(serviceInfo.hosts[0].ip === '1.1.1.1');
|
||||||
assert(serviceInfo.hosts[0].port === 8080);
|
assert(serviceInfo.hosts[0].port === 8080);
|
||||||
|
|
||||||
result = await proxy.deregisterService(serviceName, '1.1.1.1', 8080, 'NODEJS');
|
result = await proxy.deregisterService(serviceName, instance);
|
||||||
assert(result === 'ok');
|
assert(result === 'ok');
|
||||||
|
|
||||||
jsonStr = await proxy.reqAPI('/nacos/v1/ns/instances', {
|
jsonStr = await proxy.queryList(serviceName, 'NODEJS', '', 'false');
|
||||||
serviceName,
|
|
||||||
}, 'GET');
|
|
||||||
serviceInfo = JSON.parse(jsonStr);
|
serviceInfo = JSON.parse(jsonStr);
|
||||||
|
|
||||||
assert(serviceInfo && serviceInfo.dom === serviceName);
|
assert(serviceInfo && serviceInfo.dom === 'DEFAULT_GROUP@@' + serviceName);
|
||||||
assert(serviceInfo.hosts && serviceInfo.hosts.length === 0);
|
assert(serviceInfo.hosts && serviceInfo.hosts.length === 0);
|
||||||
|
|
||||||
|
await proxy.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should serverHealthy ok', async function() {
|
it('should serverHealthy ok', async function() {
|
||||||
const proxy = new NameProxy({
|
const proxy = new NameProxy({
|
||||||
logger,
|
logger,
|
||||||
|
endpoint: '127.0.0.1:8849',
|
||||||
serverList: '127.0.0.1:8848',
|
serverList: '127.0.0.1:8848',
|
||||||
});
|
});
|
||||||
await proxy.ready();
|
await proxy.ready();
|
||||||
|
@ -74,19 +80,28 @@ describe('test/naming/proxy.test.js', () => {
|
||||||
let isHealthy = await proxy.serverHealthy();
|
let isHealthy = await proxy.serverHealthy();
|
||||||
assert(isHealthy);
|
assert(isHealthy);
|
||||||
|
|
||||||
mm.http.request(/\/nacos\/v1\/ns\/api\/hello/, '', {
|
mm.http.request(/\/nacos\/v1\/ns\/operator\/metrics/, '{"status": "DOWN"}', {
|
||||||
|
statusCode: 200,
|
||||||
|
});
|
||||||
|
|
||||||
|
isHealthy = await proxy.serverHealthy();
|
||||||
|
assert(!isHealthy);
|
||||||
|
|
||||||
|
mm.http.request(/\/nacos\/v1\/ns\/operator\/metrics/, '', {
|
||||||
statusCode: 304,
|
statusCode: 304,
|
||||||
});
|
});
|
||||||
|
|
||||||
isHealthy = await proxy.serverHealthy();
|
isHealthy = await proxy.serverHealthy();
|
||||||
assert(isHealthy);
|
assert(!isHealthy);
|
||||||
|
|
||||||
mm.http.request(/\/nacos\/v1\/ns\/api\/hello/, '', {
|
mm.http.request(/\/nacos\/v1\/ns\/operator\/metrics/, '', {
|
||||||
statusCode: 500,
|
statusCode: 500,
|
||||||
});
|
});
|
||||||
|
|
||||||
isHealthy = await proxy.serverHealthy();
|
isHealthy = await proxy.serverHealthy();
|
||||||
assert(!isHealthy);
|
assert(!isHealthy);
|
||||||
|
|
||||||
|
await proxy.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should failed if no server available', async function() {
|
it('should failed if no server available', async function() {
|
||||||
|
@ -98,6 +113,8 @@ describe('test/naming/proxy.test.js', () => {
|
||||||
|
|
||||||
const isHealthy = await proxy.serverHealthy();
|
const isHealthy = await proxy.serverHealthy();
|
||||||
assert(!isHealthy);
|
assert(!isHealthy);
|
||||||
|
|
||||||
|
await proxy.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support naocsDomain', async function() {
|
it('should support naocsDomain', async function() {
|
||||||
|
@ -111,11 +128,127 @@ describe('test/naming/proxy.test.js', () => {
|
||||||
let isHealthy = await proxy.serverHealthy();
|
let isHealthy = await proxy.serverHealthy();
|
||||||
assert(isHealthy);
|
assert(isHealthy);
|
||||||
|
|
||||||
mm.http.request(/\/nacos\/v1\/ns\/api\/hello/, '', {
|
mm.http.request(/\/nacos\/v1\/ns\/operator\/metrics/, '', {
|
||||||
statusCode: 500,
|
statusCode: 500,
|
||||||
});
|
});
|
||||||
|
|
||||||
isHealthy = await proxy.serverHealthy();
|
isHealthy = await proxy.serverHealthy();
|
||||||
assert(!isHealthy);
|
assert(!isHealthy);
|
||||||
|
|
||||||
|
await proxy.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should sendBeat ok', async () => {
|
||||||
|
const proxy = new NameProxy({
|
||||||
|
logger,
|
||||||
|
serverList: '127.0.0.1:8848',
|
||||||
|
});
|
||||||
|
await proxy.ready();
|
||||||
|
|
||||||
|
const beatInfo = {
|
||||||
|
serviceName: 'DEFAULT_GROUP@@' + serviceName,
|
||||||
|
ip: '1.1.1.1',
|
||||||
|
port: 8080,
|
||||||
|
cluster: 'NODEJS',
|
||||||
|
weight: 1,
|
||||||
|
metadata: {},
|
||||||
|
scheduled: false,
|
||||||
|
};
|
||||||
|
let result = await proxy.sendBeat(beatInfo);
|
||||||
|
console.log(result);
|
||||||
|
assert(typeof result === 'number' && result > 0);
|
||||||
|
|
||||||
|
mm.error(proxy, '_reqAPI', 'mock error');
|
||||||
|
|
||||||
|
result = await proxy.sendBeat(beatInfo);
|
||||||
|
assert(result === 0);
|
||||||
|
|
||||||
|
await proxy.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should getServiceList ok', async () => {
|
||||||
|
const proxy = new NameProxy({
|
||||||
|
logger,
|
||||||
|
serverList: '127.0.0.1:8848',
|
||||||
|
});
|
||||||
|
await proxy.ready();
|
||||||
|
|
||||||
|
let data = await proxy.getServiceList(0, 10, 'DEFAULT_GROUP');
|
||||||
|
console.log(data);
|
||||||
|
|
||||||
|
const groupName = 'DEFAULT_GROUP';
|
||||||
|
const instance = new Instance({
|
||||||
|
ip: '1.1.1.1',
|
||||||
|
port: 8080,
|
||||||
|
clusterName: 'NODEJS',
|
||||||
|
weight: 1.0,
|
||||||
|
metadata: {},
|
||||||
|
serviceName,
|
||||||
|
});
|
||||||
|
let result = await proxy.registerService(serviceName, groupName, instance);
|
||||||
|
assert(result === 'ok');
|
||||||
|
await sleep(1000);
|
||||||
|
|
||||||
|
data = await proxy.getServiceList(0, 10, 'DEFAULT_GROUP');
|
||||||
|
console.log(data);
|
||||||
|
|
||||||
|
result = await proxy.deregisterService(serviceName, instance);
|
||||||
|
assert(result === 'ok');
|
||||||
|
|
||||||
|
await proxy.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('endpoint', () => {
|
||||||
|
let server;
|
||||||
|
before(done => {
|
||||||
|
server = http.createServer((req, res) => {
|
||||||
|
res.writeHead(200, { 'Content-Type': 'application/text' });
|
||||||
|
res.end('127.0.0.1:8848');
|
||||||
|
});
|
||||||
|
server.listen(8849, done);
|
||||||
|
});
|
||||||
|
after(done => {
|
||||||
|
server.once('close', done);
|
||||||
|
server.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get serverList from endpoint', async () => {
|
||||||
|
const proxy = new NameProxy({
|
||||||
|
logger,
|
||||||
|
endpoint: '127.0.0.1:8849',
|
||||||
|
vipSrvRefInterMillis: 5000,
|
||||||
|
});
|
||||||
|
await proxy.ready();
|
||||||
|
|
||||||
|
assert(proxy.serverList && proxy.serverList.length === 0);
|
||||||
|
assert(proxy.serversFromEndpoint && proxy.serversFromEndpoint.length === 1);
|
||||||
|
|
||||||
|
assert(proxy.lastSrvRefTime > 0);
|
||||||
|
|
||||||
|
const isHealthy = await proxy.serverHealthy();
|
||||||
|
assert(isHealthy);
|
||||||
|
|
||||||
|
await sleep(6000);
|
||||||
|
|
||||||
|
const lastSrvRefTime = proxy.lastSrvRefTime;
|
||||||
|
assert(Date.now() - lastSrvRefTime < 5000);
|
||||||
|
await proxy._refreshSrvIfNeed();
|
||||||
|
assert(proxy.lastSrvRefTime === lastSrvRefTime);
|
||||||
|
|
||||||
|
await proxy.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not healthy', async () => {
|
||||||
|
const proxy = new NameProxy({
|
||||||
|
logger,
|
||||||
|
endpoint: 'unknown.com',
|
||||||
|
});
|
||||||
|
await proxy.ready();
|
||||||
|
|
||||||
|
const isHealthy = await proxy.serverHealthy();
|
||||||
|
assert(!isHealthy);
|
||||||
|
|
||||||
|
await proxy.close();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -36,63 +36,51 @@ describe('test/naming/service_info.test.js', () => {
|
||||||
weight: 1.0,
|
weight: 1.0,
|
||||||
valid: true,
|
valid: true,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
ephemeral: true,
|
||||||
metadata: {},
|
metadata: {},
|
||||||
}],
|
}],
|
||||||
});
|
});
|
||||||
assert(serviceInfo.ipCount === 1);
|
assert(serviceInfo.ipCount === 1);
|
||||||
assert(serviceInfo.isValid);
|
assert(serviceInfo.isValid);
|
||||||
assert(serviceInfo.getKey() === 'xxx@@clusters@@000--00-ALL_IPS--00--000');
|
assert(serviceInfo.getKey() === 'xxx@@clusters');
|
||||||
|
|
||||||
mm(serviceInfo, 'isAllIPs', false);
|
mm(serviceInfo, 'isAllIPs', false);
|
||||||
assert(serviceInfo.getKey() === 'xxx@@clusters');
|
assert(serviceInfo.getKey() === 'xxx@@clusters');
|
||||||
|
|
||||||
mm(serviceInfo, 'env', 'test');
|
mm(serviceInfo, 'env', 'test');
|
||||||
assert(serviceInfo.getKey() === 'xxx@@clusters@@test');
|
assert(serviceInfo.getKey() === 'xxx@@clusters');
|
||||||
|
|
||||||
mm(serviceInfo, 'isAllIPs', true);
|
mm(serviceInfo, 'isAllIPs', true);
|
||||||
assert(serviceInfo.getKey() === 'xxx@@clusters@@test@@000--00-ALL_IPS--00--000');
|
assert(serviceInfo.getKey() === 'xxx@@clusters');
|
||||||
|
|
||||||
mm(serviceInfo, 'clusters', null);
|
mm(serviceInfo, 'clusters', null);
|
||||||
assert(serviceInfo.getKey() === 'xxx@@@@test@@000--00-ALL_IPS--00--000');
|
assert(serviceInfo.getKey() === 'xxx');
|
||||||
|
|
||||||
mm(serviceInfo, 'isAllIPs', false);
|
mm(serviceInfo, 'isAllIPs', false);
|
||||||
assert(serviceInfo.getKey() === 'xxx@@@@test');
|
|
||||||
|
|
||||||
mm(serviceInfo, 'env', null);
|
|
||||||
assert(serviceInfo.getKey() === 'xxx');
|
assert(serviceInfo.getKey() === 'xxx');
|
||||||
|
|
||||||
mm(serviceInfo, 'isAllIPs', true);
|
mm(serviceInfo, 'isAllIPs', true);
|
||||||
assert(serviceInfo.getKey() === 'xxx@@000--00-ALL_IPS--00--000');
|
assert(serviceInfo.getKey() === 'xxx');
|
||||||
assert(serviceInfo.toString() === 'xxx@@000--00-ALL_IPS--00--000');
|
assert(serviceInfo.toString() === 'xxx');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should parse from string', () => {
|
it('should parse from string', () => {
|
||||||
let data = ServiceInfo.parse('xxx@@clusters@@000--00-ALL_IPS--00--000');
|
let data = ServiceInfo.fromKey('DEFAULT_GROUP@@xxx');
|
||||||
assert(data.name === 'xxx');
|
|
||||||
assert(data.clusters === 'clusters');
|
|
||||||
assert(data.isAllIPs);
|
|
||||||
|
|
||||||
data = ServiceInfo.parse('xxx@@clusters@@test@@000--00-ALL_IPS--00--000');
|
|
||||||
assert(data.name === 'xxx');
|
|
||||||
assert(data.clusters === 'clusters');
|
|
||||||
assert(data.isAllIPs);
|
|
||||||
assert(data.env === 'test');
|
|
||||||
|
|
||||||
data = ServiceInfo.parse('xxx@@clusters');
|
|
||||||
assert(data.name === 'xxx');
|
|
||||||
assert(data.clusters === 'clusters');
|
|
||||||
assert(!data.isAllIPs);
|
|
||||||
|
|
||||||
data = ServiceInfo.parse('xxx@@clusters@@test');
|
|
||||||
assert(data.name === 'xxx');
|
|
||||||
assert(data.clusters === 'clusters');
|
|
||||||
assert(data.env === 'test');
|
|
||||||
assert(!data.isAllIPs);
|
|
||||||
|
|
||||||
data = ServiceInfo.parse('xxx@@000--00-ALL_IPS--00--000');
|
|
||||||
assert(data.name === 'xxx');
|
assert(data.name === 'xxx');
|
||||||
|
assert(data.groupName === 'DEFAULT_GROUP');
|
||||||
assert(!data.clusters);
|
assert(!data.clusters);
|
||||||
assert(!data.env);
|
assert(!data.isAllIPs);
|
||||||
assert(data.isAllIPs);
|
|
||||||
|
data = ServiceInfo.fromKey('DEFAULT_GROUP@@xxx@@clusters');
|
||||||
|
assert(data.name === 'xxx');
|
||||||
|
assert(data.clusters === 'clusters');
|
||||||
|
assert(!data.isAllIPs);
|
||||||
|
assert(data.groupName === 'DEFAULT_GROUP');
|
||||||
|
|
||||||
|
data = ServiceInfo.fromKey('xxx');
|
||||||
|
assert(!data.name);
|
||||||
|
assert(!data.clusters);
|
||||||
|
assert(!data.isAllIPs);
|
||||||
|
assert(!data.groupName);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -29,4 +29,24 @@ describe('test/util/index.test.js', () => {
|
||||||
const zipped = zlib.gzipSync(buf);
|
const zipped = zlib.gzipSync(buf);
|
||||||
assert.deepEqual(util.tryDecompress(zipped), buf);
|
assert.deepEqual(util.tryDecompress(zipped), buf);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should getGroupedName ok', () => {
|
||||||
|
const serviceWithGroupName = util.getGroupedName('serviceName', 'groupName');
|
||||||
|
assert(serviceWithGroupName === 'groupName@@serviceName');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should getServiceName ok', () => {
|
||||||
|
assert(util.getServiceName('groupName@@serviceName') === 'serviceName');
|
||||||
|
assert(util.getServiceName('serviceName') === 'serviceName');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should getGroupName ok', () => {
|
||||||
|
assert(util.getGroupName('groupName@@serviceName') === 'groupName');
|
||||||
|
assert(util.getGroupName('serviceName') === 'DEFAULT_GROUP');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should sign ok', () => {
|
||||||
|
const result = util.sign('1556606455782@@nodejs.test', 'xxxxxx');
|
||||||
|
assert(result === 'hhmW6gWCqR0g8dctGZXQclYomYg=');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,6 +3,30 @@
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [2.0.1](https://github.com/nacos-group/nacos-sdk-nodejs/compare/v2.0.0...v2.0.1) (2021-01-26)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package nacos
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.1.2](https://github.com/nacos-group/nacos-sdk-nodejs/compare/v1.1.1...v1.1.2) (2019-03-31)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package nacos
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.1.1](https://github.com/nacos-group/nacos-sdk-nodejs/compare/v1.1.0...v1.1.1) (2019-01-17)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package nacos
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [1.1.0](https://github.com/nacos-group/nacos-sdk-nodejs/compare/v1.0.2...v1.1.0) (2019-01-15)
|
# [1.1.0](https://github.com/nacos-group/nacos-sdk-nodejs/compare/v1.0.2...v1.1.0) (2019-01-15)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,13 @@
|
||||||
npm install nacos --save
|
npm install nacos --save
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Version Mapping
|
||||||
|
|
||||||
|
Node.js SDK \ Nacos Server | 0.x.0 | 1.0.0 |
|
||||||
|
--- | --- | --- |
|
||||||
|
1.x | √ | |
|
||||||
|
2.x | | √ |
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
### Service Discovery
|
### Service Discovery
|
||||||
|
@ -34,14 +41,21 @@ const logger = console;
|
||||||
const client = new NacosNamingClient({
|
const client = new NacosNamingClient({
|
||||||
logger,
|
logger,
|
||||||
serverList: '127.0.0.1:8848', // replace to real nacos serverList
|
serverList: '127.0.0.1:8848', // replace to real nacos serverList
|
||||||
|
namespace: 'public',
|
||||||
});
|
});
|
||||||
await client.ready();
|
await client.ready();
|
||||||
|
|
||||||
const serviceName = 'nodejs.test.domain';
|
const serviceName = 'nodejs.test.domain';
|
||||||
|
|
||||||
// registry instance
|
// registry instance
|
||||||
await client.registerInstance(serviceName, '1.1.1.1', 8080, 'NODEJS');
|
await client.registerInstance(serviceName, {
|
||||||
await client.registerInstance(serviceName, '2.2.2.2', 8080, 'NODEJS');
|
ip: '1.1.1.1',
|
||||||
|
port: 8080,
|
||||||
|
});
|
||||||
|
await client.registerInstance(serviceName, {
|
||||||
|
ip: '2.2.2.2',
|
||||||
|
port: 8080,
|
||||||
|
});
|
||||||
|
|
||||||
// subscribe instance
|
// subscribe instance
|
||||||
client.subscribe(serviceName, hosts => {
|
client.subscribe(serviceName, hosts => {
|
||||||
|
@ -49,7 +63,10 @@ client.subscribe(serviceName, hosts => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// deregister instance
|
// deregister instance
|
||||||
await client.deregisterInstance(serviceName, '1.1.1.1', 8080, 'NODEJS');
|
await client.deregisterInstance(serviceName, {
|
||||||
|
ip: '1.1.1.1',
|
||||||
|
port: 8080,
|
||||||
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
### Config Service
|
### Config Service
|
||||||
|
@ -100,27 +117,36 @@ default value: [ClientOptions default value](https://github.com/nacos-group/naco
|
||||||
|
|
||||||
### Service Discovery
|
### Service Discovery
|
||||||
|
|
||||||
- `registerInstance(serviceName, ip, port, [cluster])` Register an instance to service.
|
- `registerInstance(serviceName, instance, [groupName])` Register an instance to service.
|
||||||
- serviceName <String> Service name
|
- serviceName {String} Service name
|
||||||
- ip <String> IP of instance
|
- instance {Instance}
|
||||||
- port <Number> Port of instance
|
- ip {String} IP of instance
|
||||||
- cluster <String> Virtual cluster name
|
- port {Number} Port of instance
|
||||||
|
- [weight] {Number} weight of the instance, default is 1.0
|
||||||
|
- [ephemeral] {Boolean} active until the client is alive, default is true
|
||||||
|
- [clusterName] {String} Virtual cluster name
|
||||||
|
- [groupName] {String} group name, default is `DEFAULT_GROUP`
|
||||||
- `deregisterInstance(serviceName, ip, port, [cluster])` Delete instance from service.
|
- `deregisterInstance(serviceName, ip, port, [cluster])` Delete instance from service.
|
||||||
- serviceName <String> Service name
|
- serviceName {String} Service name
|
||||||
- ip <String> IP of instance
|
- instance {Instance}
|
||||||
- port <Number> Port of instance
|
- ip {String} IP of instance
|
||||||
- cluster <String> Virtual cluster name
|
- port {Number} Port of instance
|
||||||
- `getAllInstances(serviceName, [clusters])` Query instance list of service.
|
- [weight] {Number} weight of the instance, default is 1.0
|
||||||
- serviceName <String> Service name
|
- [ephemeral] {Boolean} active until the client is alive, default is true
|
||||||
- clusters <Array> Cluster names
|
- [clusterName] {String} Virtual cluster name
|
||||||
|
- [groupName] {String} group name, default is `DEFAULT_GROUP`
|
||||||
|
- `getAllInstances(serviceName, [groupName], [clusters], [subscribe])` Query instance list of service.
|
||||||
|
- serviceName {String} Service name
|
||||||
|
- [groupName] {String} group name, default is `DEFAULT_GROUP`
|
||||||
|
- [clusters] {String} Cluster names
|
||||||
|
- [subscribe] {Boolean} whether subscribe the service, default is true
|
||||||
- `getServerStatus()` Get the status of nacos server, 'UP' or 'DOWN'.
|
- `getServerStatus()` Get the status of nacos server, 'UP' or 'DOWN'.
|
||||||
- `subscribe(info, listener)` Subscribe the instances of the service
|
- `subscribe(info, listener)` Subscribe the instances of the service
|
||||||
- info <Object | String> service info, if type is string, it's the serviceName
|
- info {Object}|{String} service info, if type is string, it's the serviceName
|
||||||
- listener <Function> the listener function
|
- listener {Function} the listener function
|
||||||
- unSubscribe(info, [listener]) Unsubscribe the instances of the service
|
- `unSubscribe(info, [listener])` Unsubscribe the instances of the service
|
||||||
- info <Object | String> service info, if type is string, it's the serviceName
|
- info {Object}|{String} service info, if type is string, it's the serviceName
|
||||||
- listener <Function> the listener function, if not provide, will unSubscribe all listeners under this service
|
- listener {Function} the listener function, if not provide, will unSubscribe all listeners under this service
|
||||||
|
|
||||||
|
|
||||||
### Config Service
|
### Config Service
|
||||||
|
|
||||||
|
@ -151,6 +177,10 @@ Please let us know how can we help. Do check out [issues](https://github.com/nac
|
||||||
|
|
||||||
PR is welcome.
|
PR is welcome.
|
||||||
|
|
||||||
|
nacos-sdk-nodejs ding group : 44654232
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
[Apache License V2](LICENSE)
|
[Apache License V2](LICENSE)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "nacos",
|
"name": "nacos",
|
||||||
"version": "1.1.0",
|
"version": "2.6.0",
|
||||||
"description": "nacos client main package",
|
"description": "nacos client main package",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"nacos",
|
"nacos",
|
||||||
|
@ -12,8 +12,8 @@
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"author": "czy88840616@gmail.com",
|
"author": "czy88840616@gmail.com",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nacos-config": "^1.1.0",
|
"nacos-config": "^2.6.0",
|
||||||
"nacos-naming": "^1.1.0"
|
"nacos-naming": "^2.6.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/mocha": "^5.2.5",
|
"@types/mocha": "^5.2.5",
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
npm run contributors
|
|
||||||
npm run build
|
npm run build
|
||||||
git add .
|
lerna publish $*
|
||||||
git commit -m "chore: ready for publish"
|
|
||||||
lerna publish $* --conventional-commits
|
|
||||||
|
|
Loading…
Reference in New Issue