Compare commits

...

40 Commits

Author SHA1 Message Date
Harry Chen 8a5568de77 v2.6.0 2023-12-14 10:43:15 +08:00
Bob 57cd21060b
chore: nacos-naming add more types (#105)
Co-authored-by: Harry Chen <czy88840616@gmail.com>
2023-12-14 10:41:52 +08:00
Nolan Zhang 7fa34ff6a6
chore: add Hosts typings (#97)
I have deployed NACOS version 2.1.1. Has the type changed here because of the version upgrade? I have fixed it
2023-12-13 19:56:09 +08:00
Marc SUN 22c0e57947
chore: add nacos auth supportt typings (#114)
* Update index.d.ts

add nacos auth support

* Update interface.ts

add nacos auth support
2023-12-13 19:54:50 +08:00
陈浩 Nineteen cdea9a26b1
chore: support nacos-sdk-nodejs(2.5.0) example and add auth example (#100) 2023-12-13 19:52:01 +08:00
唯然 50ac48e026
chore: update pkg.license => Apache-2.0 (#101)
rome reports "✖ Unknown license Apache".

refs: https://rome.tools/
2023-03-10 11:23:25 +08:00
Harry Chen 3c6840bdd7 v2.5.1 2022-12-08 16:14:07 +08:00
Jack Hu 4c9af68899
fix: no retry with dns.NOTFOUND (#102)
Co-authored-by: hujingkang <hujingkang@joyy.com>
2022-12-08 16:04:08 +08:00
Harry Chen cc6667c5b1 v2.5.0 2022-08-22 00:05:23 +08:00
Darcy d6ee163a36
fix: comparing the host information using an unstable JSON string (#95) 2022-08-22 00:03:21 +08:00
Harry Chen 41e3965870 v2.4.2 2022-08-09 19:35:21 +08:00
Harry Chen a3feb781a7 chore: update 2022-08-09 19:33:46 +08:00
恒遥 910f7e4bfe
fix: ignore empty hosts array (#94)
Co-authored-by: hengyao.zhy <hengyao.zhy@antgroup.com>
2022-08-09 19:30:03 +08:00
yanlinly 7f1870778e
Update README.md
update ding group info
2022-06-08 17:25:34 +08:00
Harry Chen d044e6cef4 v2.4.1 2022-05-09 14:40:09 +08:00
Evanhahaha 005134d725
feat: config add appName (#87)
* feat: clientOptions增加endPoint查询的url参数选项

* feat: add example of endPointQueryParam

* fixed query param example

* feat: 增加appName可配置

* fixed merge conflict

Co-authored-by: 黑糖 <heitang.zlw@alibaba-inc.com>
2022-05-09 14:38:56 +08:00
Harry Chen e3cb1d5955 v2.4.0 2022-05-05 20:15:14 +08:00
Evanhahaha 6df7ece0a8 feat: clientOptions add endPoint url query params (#84)
Co-authored-by: 黑糖 <heitang.zlw@alibaba-inc.com>
2022-05-05 20:15:14 +08:00
Harry Chen 27a8fa7651 v2.3.1 2022-05-05 20:15:14 +08:00
Harry Chen a3f33bd901 fix: missing typings 2022-05-05 20:15:14 +08:00
Harry Chen 194629a25b v2.3.0 2022-05-05 20:15:14 +08:00
ugrg 34055b4117 feat: add nacos-naming typings (#77)
Co-authored-by: ugrg <ugrg@163.com>
2022-05-05 20:13:49 +08:00
Vinlic科技 9ae37cef32
feat: add configuration type support (#82) 2022-04-25 19:33:54 +08:00
沈赟杰 a9a7fe64d8
fix: update interface.ts (#80) 2022-04-25 19:33:23 +08:00
zhanheng 3940268149
fix: window10,node use clutser (#57)
Co-authored-by: zhanheng <zhanheng@guahao.com>
2021-12-30 12:54:09 +08:00
Harry Chen 2b703c0621 v2.2.1 2021-11-25 12:10:05 +08:00
恒遥 01affdbb51
fix: listener add tenant (#71)
Co-authored-by: hengyao.zhy <hengyao.zhy@antgroup.com>
2021-11-25 12:05:35 +08:00
Harry Chen 643dd12ab8 v2.2.0 2021-09-29 18:37:15 +08:00
恒遥 c9f5808675
feat: support custom decode res data (#66)
Co-authored-by: hengyao.zhy <hengyao.zhy@antgroup.com>
2021-09-29 18:29:34 +08:00
恒遥 3e9670d9cf
feat: support custom httpAgent (#60)
Co-authored-by: hengyao.zhy <hengyao.zhy@antgroup.com>
2021-08-06 15:35:19 +08:00
gxcsoccer d5e2dd8ae0 v2.1.1 2021-05-11 13:39:15 +08:00
zōng yǔ 61a415ec6f
Merge pull request #49 from zhanghengyao/fix/delay-default
fix: the delay default value is too short
2021-05-11 13:33:00 +08:00
陈高原 17ea984a61
fix: close process after push_receiver (#30) 2021-05-09 11:33:49 +08:00
zhangchen 180dcf72fe
feat: identity header (#50) 2021-05-09 11:24:31 +08:00
hengyao.zhy 8c06bda57f fix: the delay default value is too short 2021-05-08 14:09:22 +08:00
Harry Chen b219a870bd v2.1.0 2021-02-19 15:30:52 +08:00
Harry Chen e5c1359509 chore: add optional 2021-02-19 15:29:51 +08:00
Harry Chen 744fc56f29 Merge branch 'master' of github.com:nacos-group/nacos-sdk-nodejs 2021-02-19 15:26:00 +08:00
silverera 1a63399df0
feat: support new authentication mode (#39) 2021-02-19 15:18:08 +08:00
Harry Chen f1bfe2d065 chore: update 2021-01-26 13:35:28 +08:00
24 changed files with 250 additions and 36 deletions

View File

@ -177,6 +177,10 @@ Please let us know how can we help. Do check out [issues](https://github.com/nac
PR is welcome.
nacos-sdk-nodejs ding group 44654232
![image](https://user-images.githubusercontent.com/17695352/172582005-c661e2a0-49fa-425c-bf99-785bb7cd4dc1.png)
## License
[Apache License V2](LICENSE)

View File

@ -3,8 +3,11 @@
const NacosConfigClient = require('nacos').NacosConfigClient;
const configClient = new NacosConfigClient({
serverAddr: '106.14.43.196:8848',
serverAddr: 'aliyun.nacos.net:80',
namespace: '',
// 如果nacos开启了认证鉴权需要在此处填写用户名密码
// username: 'xxx',
// password: 'xxx'
});
function sleep(time){
@ -18,7 +21,7 @@ function sleep(time){
(async () => {
await configClient.ready();
const dataId = 'nacos.test.1';
const dataId = 'nacos.test.22';
const group = 'DEFAULT_GROUP';
const str = `example_test_${Math.random()}_${Date.now()}`;

View File

@ -2,6 +2,6 @@
"name": "nacos-example",
"version": "1.0.0",
"dependencies": {
"nacos": "^1.0.0"
"nacos": "^2.5.0"
}
}

View File

@ -14,11 +14,7 @@
"ignoreChanges": [
"*.md"
]
},
"version": {
"conventionalCommits": true,
"createRelease": "github"
}
},
"version": "2.0.1"
"version": "2.6.0"
}

View File

@ -13,7 +13,7 @@
"ci": "npm run cov",
"build": "lerna run build && cp ./README.md ./packages/nacos/README.md"
},
"license": "Apache",
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/nacos-group/nacos-sdk-nodejs/issues"
},

View File

@ -1,6 +1,6 @@
{
"name": "nacos-config",
"version": "2.0.1",
"version": "2.6.0",
"description": "nacos config client",
"keywords": [
"nacos-config",

View File

@ -54,7 +54,8 @@ export class DataClient extends Base implements BaseClient {
this.snapshot = this.getSnapshot();
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({
snapshot: this.snapshot,
@ -162,7 +163,7 @@ export class DataClient extends Base implements BaseClient {
async publishSingle(dataId, group, content, options) {
checkParameters(dataId, group);
const client = this.getClient(options);
return await client.publishSingle(dataId, group, content);
return await client.publishSingle(dataId, group, content, options && options.type);
}
/**

View File

@ -217,6 +217,10 @@ export class ClientWorker extends Base implements IClientWorker {
}
const postData = {};
// 开启权限验证后需要携带租户,否则没有权限
if (tenant) {
Object.assign(postData, { tenant })
}
postData[ this.listenerDataKey ] = probeUpdate.join('');
const content = await this.httpAgent.request(this.apiRoutePath.LISTENER, {
method: 'POST',
@ -345,9 +349,10 @@ export class ClientWorker extends Base implements IClientWorker {
* @param {String} dataId - id of the data
* @param {String} group - group name of the data
* @param {String} content - config value
* @param {String} type - type of the data
* @return {Boolean} success
*/
async publishSingle(dataId, group, content) {
async publishSingle(dataId, group, content, type) {
await this.httpAgent.request(this.apiRoutePath.PUBLISH, {
method: 'POST',
encode: true,
@ -356,6 +361,8 @@ export class ClientWorker extends Base implements IClientWorker {
group,
content,
tenant: this.namespace,
type,
appName: this.appName
},
});
return true;

View File

@ -19,6 +19,7 @@ import { ClientOptionKeys, IConfiguration, IServerListManager } from './interfac
import * as urllib from 'urllib';
import * as crypto from 'crypto';
import { encodingParams, transformGBKToUTF8 } from './utils';
import * as dns from 'dns';
export class HttpAgent {
@ -82,6 +83,22 @@ export class HttpAgent {
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);
}
/**
*
@ -106,6 +123,11 @@ export class HttpAgent {
const endTime = Date.now() + timeout;
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;
if (data.group && data.tenant) {
signStr = data.tenant + '+' + data.group;
@ -125,6 +147,7 @@ export class HttpAgent {
timeStamp: ts,
exConfigInfo: 'true',
'Spas-Signature': signature,
...this.identityKey ? {[this.identityKey]: this.identityValue} : {}
});
let requestData = data;
@ -152,6 +175,9 @@ export class HttpAgent {
this.debug('%s %s, got %s, body: %j', method, url, res.status, res.data);
switch (res.status) {
case HTTP_OK:
if (this.decodeRes) {
return this.decodeRes(res, method, this.defaultEncoding)
}
return this.decodeResData(res, method);
case HTTP_NOT_FOUND:
return null;
@ -170,6 +196,9 @@ export class HttpAgent {
break;
}
} catch (err) {
if (err.code === dns.NOTFOUND) {
throw err;
}
err.url = `${method} ${url}`;
err.data = data;
err.headers = headers;

View File

@ -24,6 +24,7 @@ export { DataClient } from './client';
export { ClientWorker } from './client_worker';
export { ServerListManager } from './server_list_mgr';
export { Snapshot } from './snapshot';
export { HttpAgent } from './http_agent'
const APIClientBase = require('cluster-client').APIClientBase;

View File

@ -251,9 +251,10 @@ export interface ClientOptions {
accessKey?: string; // 阿里云的 accessKey
secretKey?: string; // 阿里云的 secretKey
httpclient?: any; // http 请求客户端,默认为 urllib
httpAgent?: any; // httpAgent
appName?: string; // 应用名,可选
ssl?: boolean; // 是否为 https 请求
refreshInterval?: number; // 重新拉地址列表的间隔时间
refreshInterval?: number; // 重新拉地址列表的间隔时间
contextPath?: string; // 请求的 contextPath
clusterName?: string; // 请求的 path
requestTimeout?: number; // 请求超时时间
@ -261,7 +262,13 @@ export interface ClientOptions {
serverAddr?: string; // 用于直连,包含端口
unit?: string; // 内部单元化用
nameServerAddr?: string; // 老的兼容参数,逐步废弃,同 endpoint
username?: string; // 认证的用户名
password?: string; // 认证的密码
cacheDir?: string; // 缓存文件的路径
identityKey?: string; // Identity Key
identityValue?: string; // Identity Value
endpointQueryParams?: string; // endPoint 查询参数 e.g: param_1=1&param_2=2
decodeRes?: (res: any, method?: string, encoding?: string) => any
}
export enum ClientOptionKeys {
@ -285,6 +292,10 @@ export enum ClientOptionKeys {
HTTP_AGENT = 'httpAgent',
SERVER_MGR = 'serverMgr',
DEFAULT_ENCODING = 'defaultEncoding',
IDENTITY_KEY = 'identityKey',
IDENTITY_VALUE = 'identityValue',
DECODE_RES = 'decodeRes',
ENDPOINT_QUERY_PARAMS = 'endpointQueryParams'
}
export interface IConfiguration {

View File

@ -108,6 +108,10 @@ export class ServerListManager extends Base implements IServerListManager {
return this.configuration.get(ClientOptionKeys.CLUSTER_NAME) || 'serverlist';
}
get endpointQueryParams() {
return this.configuration.get(ClientOptionKeys.ENDPOINT_QUERY_PARAMS)
}
get requestTimeout(): number {
return this.configuration.get(ClientOptionKeys.REQUEST_TIMEOUT);
}
@ -226,7 +230,8 @@ export class ServerListManager extends Base implements IServerListManager {
// 获取请求 url
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}`;
}
/**

View File

@ -15,6 +15,7 @@
* limitations under the License.
*/
import { DataClient } from '../src/client';
import { HttpAgent } from '../src/http_agent'
const mm = require('mm');
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);
});
});

View File

@ -497,5 +497,32 @@ describe('test/client_worker.test.ts', () => {
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));
});
})
});
});

View File

@ -18,14 +18,6 @@
import { Configuration } from '../src/configuration';
import { DEFAULT_OPTIONS } from '../src/const';
export function delay(timeout) {
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, timeout);
});
}
export function createDefaultConfiguration(config: any) {
return new Configuration(Object.assign({}, DEFAULT_OPTIONS)).merge(config);
}

97
packages/nacos-naming/index.d.ts vendored Normal file
View File

@ -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;
}

View File

@ -50,3 +50,5 @@ exports.NAMING_DEFAULT_CLUSTER_NAME = 'DEFAULT';
exports.SERVICE_INFO_SPLITER = '@@';
exports.DEFAULT_GROUP = 'DEFAULT_GROUP';
exports.DEFAULT_DELAY = 5000;

View File

@ -22,6 +22,7 @@ const Base = require('sdk-base');
const Constants = require('../const');
const ServiceInfo = require('./service_info');
const PushReceiver = require('./push_receiver');
const equals = require('equals');
class HostReactor extends Base {
constructor(options = {}) {
@ -92,7 +93,7 @@ class HostReactor extends Base {
const key = host.ip + ':' + host.port;
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);
continue;
}
@ -133,7 +134,6 @@ class HostReactor extends Base {
this.emit(`${serviceInfo.getKey()}_changed`, serviceInfo.hosts, serviceInfo);
// TODO: 本地缓存
}
this.logger.info('[HostReactor] current ips(%d) service: %s -> %s', serviceInfo.ipCount, serviceInfo.name, JSON.stringify(serviceInfo.hosts));
return serviceInfo;
}
@ -257,7 +257,7 @@ class HostReactor extends Base {
if (this._futureMap.has(key)) {
const serviceInfo = this._serviceInfoMap.get(key);
let delay = 1000;
let delay = Constants.DEFAULT_DELAY;
if (serviceInfo) {
delay = serviceInfo.cacheMillis;
task.lastRefTime = serviceInfo.lastRefTime;

View File

@ -160,6 +160,10 @@ class NameProxy extends Base {
}
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, {
method,
headers,
@ -284,7 +288,7 @@ class NameProxy extends Base {
err.message = `[CLIENT-BEAT] failed to send beat: ${JSON.stringify(beatInfo)}, caused by ${err.message}`;
this.logger.error(err);
}
return 0;
return Constants.DEFAULT_DELAY;
}
async getServiceList(pageNo, pageSize, groupName) {

View File

@ -66,7 +66,7 @@ class PushReceiver extends Base {
});
this._server.on('message', (msg, rinfo) => this._handlePushMessage(msg, rinfo));
// 随机绑定一个端口
this._server.bind();
this._server.bind({port: 0, exclusive: true}, null);
}
_handlePushMessage(msg, rinfo) {
@ -104,7 +104,13 @@ class PushReceiver extends Base {
}
close() {
this._isClosed = true;
return new Promise((resolve) => {
this._isClosed = true;
if (this._server) {
this._server.close(resolve)
this._server = null;
}
});
}
}

View File

@ -17,6 +17,7 @@
'use strict';
const Constants = require('../const');
const EMPTY = '';
const SPLITER = '@@';
// const ALL_IPS = '000--00-ALL_IPS--00--000';
@ -27,7 +28,7 @@ class ServiceInfo {
this.groupName = data.groupName;
this.clusters = data.clusters;
this.isAllIPs = data.allIPs || false;
this.cacheMillis = data.cacheMillis || 1000;
this.cacheMillis = data.cacheMillis || Constants.DEFAULT_DELAY;
this.hosts = data.hosts;
this.lastRefTime = data.lastRefTime || 0;
this.checksum = data.checksum || '';
@ -39,7 +40,12 @@ class ServiceInfo {
}
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() {

View File

@ -1,11 +1,12 @@
{
"name": "nacos-naming",
"version": "2.0.1",
"version": "2.6.0",
"description": "nacos (https://nacos.io/en-us/) nodejs sdk",
"main": "index.js",
"files": [
"lib",
"index.js"
"index.js",
"index.d.ts"
],
"scripts": {
"autod": "autod",
@ -42,6 +43,7 @@
},
"dependencies": {
"address": "^1.1.0",
"equals": "^1.0.5",
"mz-modules": "^2.1.0",
"sdk-base": "^3.6.0",
"urllib": "^2.33.3",

View File

@ -177,6 +177,10 @@ Please let us know how can we help. Do check out [issues](https://github.com/nac
PR is welcome.
nacos-sdk-nodejs ding group 44654232
![image](https://user-images.githubusercontent.com/17695352/172582005-c661e2a0-49fa-425c-bf99-785bb7cd4dc1.png)
## License
[Apache License V2](LICENSE)

View File

@ -1,6 +1,6 @@
{
"name": "nacos",
"version": "2.0.1",
"version": "2.6.0",
"description": "nacos client main package",
"keywords": [
"nacos",
@ -12,8 +12,8 @@
"main": "dist/index.js",
"author": "czy88840616@gmail.com",
"dependencies": {
"nacos-config": "^2.0.1",
"nacos-naming": "^2.0.1"
"nacos-config": "^2.6.0",
"nacos-naming": "^2.6.0"
},
"devDependencies": {
"@types/mocha": "^5.2.5",