Skip to content

Commit

Permalink
feat: support nacos registry
Browse files Browse the repository at this point in the history
  • Loading branch information
gxcsoccer committed Jan 17, 2019
1 parent fc891ee commit bf51da2
Show file tree
Hide file tree
Showing 16 changed files with 487 additions and 21 deletions.
13 changes: 12 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,24 @@ language: node_js
node_js:
- '8'
- '10'
jdk: oraclejdk8
before_install:
- 'wget https://archive.apache.org/dist/zookeeper/zookeeper-3.4.6/zookeeper-3.4.6.tar.gz'
- 'tar xf zookeeper-3.4.6.tar.gz'
- 'mv zookeeper-3.4.6/conf/zoo_sample.cfg zookeeper-3.4.6/conf/zoo.cfg'
- './zookeeper-3.4.6/bin/zkServer.sh start'
- echo $JAVA_HOME
- java -version
- 'wget https://github.com/alibaba/nacos/releases/download/0.5.0/nacos-server-0.5.0.tar.gz'
- 'wget https://github.com/gxcsoccer/PDisk/releases/download/1.0.0/startup.sh'
- 'tar xf nacos-server-0.5.0.tar.gz'
- 'mv ./startup.sh ./nacos/bin/startup.sh'
- 'chmod 755 ./nacos/bin/startup.sh'
- 'nohup ./nacos/bin/startup.sh -m standalone 2>&1 &'
- 'sleep 30'
- 'curl "127.0.0.1:8848/nacos/v1/ns/api/hello"'
install:
- npm i npminstall && npminstall --registry=https://registry.npm.taobao.org
- npm i
script:
- npm run ci
after_script:
Expand Down
40 changes: 28 additions & 12 deletions config/config.default.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,34 @@

'use strict';

const assert = require('assert');
const protocol = require('dubbo-remoting');
const DubboZookeeperRegistry = require('../lib/zk_registry');
const DubboNacosRegistry = require('../lib/registry/nacos');
const DubboZookeeperRegistry = require('../lib/registry/zk');

exports.rpc = {
registryClass: DubboZookeeperRegistry,
client: {
protocol,
},
server: {
version: '1.0.0',
group: '',
protocol,
codecType: 'hessian2',
},
const buildinRegistryMap = {
zk: DubboZookeeperRegistry,
nacos: DubboNacosRegistry,
};

module.exports = (appInfo, appConfig) => {
let registryClass = DubboZookeeperRegistry;
if (appConfig.rpc && appConfig.rpc.registry && appConfig.rpc.registry.type) {
registryClass = buildinRegistryMap[appConfig.rpc.registry.type];
assert(registryClass, `config.rpc.registry.type should be in [ ${Object.keys(buildinRegistryMap).map(k => '"' + k + '"')} ]`);
}
return {
rpc: {
registryClass,
client: {
protocol,
},
server: {
version: '1.0.0',
group: '',
protocol,
codecType: 'hessian2',
},
},
};
};
164 changes: 164 additions & 0 deletions lib/registry/nacos.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
/**
* 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 assert = require('assert');
const SdkBase = require('sdk-base');
const { URL, URLSearchParams } = require('url');
const NacosNamingClient = require('nacos').NacosNamingClient;
const RegistryBase = require('sofa-rpc-node/lib/registry/base');

const localIp = require('address').ip();

class NacosRegistryClient extends SdkBase {
constructor(options = {}) {
assert(options.logger, '[NacosRegistryClient] options.logger is required');
assert(options.address, '[NacosRegistryClient] options.address is required');
super({ initMethod: '_init' });
this.options = options;
this._client = null;
this._subscribeMap = new Map(); // <serviceKey, addressList>
}

get logger() {
return this.options.logger;
}

async _init() {
let serverList = this.options.address;
if (typeof serverList === 'string') {
serverList = serverList.split(',');
}
this._client = new NacosNamingClient({
logger: this.logger,
serverList,
});
await this._client.ready();
}

async register(config) {
assert(config && config.interfaceName, '[NacosRegistry] register(config) config.interfaceName is required');
assert(config.url, '[NacosRegistry] register(config) config.url is required');
const serviceName = this._buildProviderPath(config);
const url = new URL(config.url);
const searchParams = url.searchParams;
const metadata = {};
for (const key of searchParams.keys()) {
metadata[key] = searchParams.get(key);
}
await this._client.registerInstance(serviceName, {
ip: url.hostname,
port: Number(url.port),
metadata,
});
}

async unRegister(config) {
assert(config && config.interfaceName, '[NacosRegistry] register(config) config.interfaceName is required');
assert(config.url, '[NacosRegistry] register(config) config.url is required');
const serviceName = this._buildProviderPath(config);
const url = new URL(config.url);
await this._client.deregisterInstance(serviceName, url.hostname, Number(url.port));
}

async _doSubscribe(consumerKey, config) {
this._subscribeMap.set(consumerKey, null);
await this._client.registerInstance(consumerKey, localIp, 0);
const providerKey = this._buildProviderPath(config);
this._client.subscribe(providerKey, hosts => {
const addressList = hosts.filter(host => host.enabled).map(host => {
const params = new URLSearchParams();
const metadata = host.metadata || {};
for (const key in metadata) {
params.append(key, metadata[key]);
}
return `dubbo://${host.ip}:${host.port}?${params.toString()}`;
});
this._subscribeMap.set(consumerKey, addressList);
this.emit(consumerKey, addressList);
});
}

subscribe(config, listener) {
assert(config && config.interfaceName, '[NacosRegistry] subscribe(config, listener) config.interfaceName is required');
const consumerKey = this._buildConsumerPath(config);

if (!this._subscribeMap.has(consumerKey)) {
this._doSubscribe(consumerKey, config)
.catch(err => { this.emit('error', err); });
} else {
const addressList = this._subscribeMap.get(consumerKey);
if (addressList) {
setImmediate(() => { listener(addressList); });
}
}
this.on(consumerKey, listener);
}

unSubscribe(config, listener) {
assert(config && config.interfaceName, '[NacosRegistry] unSubscribe(config, listener) config.interfaceName is required');
const consumerKey = this._buildConsumerPath(config);

if (listener) {
this.removeListener(consumerKey, listener);
} else {
this.removeAllListeners(consumerKey);
}
if (this.listenerCount(consumerKey) === 0) {
const providerKey = this._buildProviderPath(config);
this._client.unSubscribe(providerKey);
this._subscribeMap.delete(consumerKey);
}
}

_buildProviderPath(config) {
return this._getServiceName(config, 'providers');
}

_buildConsumerPath(config) {
return this._getServiceName(config, 'consumers');
}

_getServiceName(config, category = 'providers') {
let serviceName = category + ':' + config.interfaceName;
if (config.version) {
serviceName += ':' + config.version;
}
if (config.group) {
serviceName += ':' + config.group;
}
return serviceName;
}

close() {
this._client.close();
this._subscribeMap.clear();
}
}

class DubboNacosRegistry extends RegistryBase {
get DataClient() {
return NacosRegistryClient;
}

static get DataClient() {
return NacosRegistryClient;
}
}

module.exports = DubboNacosRegistry;
File renamed without changes.
17 changes: 10 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,21 @@
"egg-plugin"
],
"dependencies": {
"address": "^1.0.3",
"dubbo-remoting": "^2.1.3",
"sofa-rpc-node": "^1.6.0"
"nacos": "^1.1.0",
"sdk-base": "^3.5.1",
"sofa-rpc-node": "^1.6.2"
},
"devDependencies": {
"autod": "^3.0.1",
"autod-egg": "^1.1.0",
"egg": "^2.14.0",
"egg-bin": "^4.9.0",
"egg-mock": "^3.20.1",
"egg-rpc-base": "^1.3.0",
"egg-rpc-generator": "^1.1.1",
"eslint": "^5.9.0",
"egg": "^2.14.2",
"egg-bin": "^4.10.0",
"egg-mock": "^3.21.0",
"egg-rpc-base": "^1.3.1",
"egg-rpc-generator": "^1.2.0",
"eslint": "^5.12.0",
"eslint-config-egg": "^7.1.0",
"mz-modules": "^2.1.0",
"webstorm-disable-index": "^1.2.0",
Expand Down
28 changes: 28 additions & 0 deletions test/fixtures/apps/dubbo-nacos/app/controller/home.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* 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 Controller = require('egg').Controller;

class HomeController extends Controller {
async index() {
this.ctx.body = await this.ctx.proxy.demoService.sayHello('gxcsoccer');
}
}

module.exports = HomeController;
24 changes: 24 additions & 0 deletions test/fixtures/apps/dubbo-nacos/app/router.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* 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';

module.exports = app => {
const { router, controller } = app;

router.get('/', controller.home.index);
};
29 changes: 29 additions & 0 deletions test/fixtures/apps/dubbo-nacos/app/rpc/DemoService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* 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';

exports.sayHello = async function(name) {
return 'hello ' + name;
};

exports.echoPerson = async function(p) {
return {
$class: 'eggjs.demo.Person',
$: p,
};
};
Binary file not shown.
Binary file not shown.
33 changes: 33 additions & 0 deletions test/fixtures/apps/dubbo-nacos/config/config.default.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* 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';

exports.keys = '123456';

exports.rpc = {
registry: {
type: 'nacos',
address: '127.0.0.1:8848',
},
server: {
version: '1.0.0',
group: 'HSF',
codecType: 'hessian2',
namespace: 'eggjs.demo',
},
};
Loading

0 comments on commit bf51da2

Please sign in to comment.