├── .gitignore ├── .npmignore ├── README.MD ├── agent.ts ├── app.ts ├── appveyor.yml ├── config └── config.default.ts ├── index.d.ts ├── lib ├── nacosClient.ts ├── nacosConfig.ts └── nacosNaming.ts ├── package.json ├── tsconfig.json ├── typings ├── interface.d.ts └── interface.ts └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | archive 2 | node_modules 3 | .idea 4 | bower_components 5 | explorations 6 | .DS_Store 7 | coverage 8 | perf 9 | *.map 10 | npm-debug.log 11 | .vscode 12 | tsconfig.tsbuildinfo 13 | *.js 14 | *.d.ts 15 | !typings/*.d.ts 16 | !index.d.ts -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | 2 | logs/ 3 | npm-debug.log 4 | node_modules/ 5 | coverage/ 6 | .idea/ 7 | run/ 8 | logs/ 9 | .DS_Store 10 | .vscode 11 | *.swp 12 | *.lock 13 | *.ts 14 | !*.d.ts 15 | example/ 16 | !.autod.conf.js 17 | !dependency/**/*.js 18 | test/**/*.ts 19 | app/**/*.mapq 20 | test/**/*.map 21 | config/**/*.map 22 | yarn-error.log 23 | tsconfig.json -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | # egg-nacos-ts 2 | 3 | 基于nacos-sdk-nodejs开发的nacos插件。cluster模式下支持单实例注册,以及通过配置自动注册和监听服务。 4 | 5 | #### 安装步骤: 6 | ``` 7 | npm install egg-nacos-ts 8 | yarn add egg-nacos-ts 9 | ``` 10 | 11 | #### 配置方式: 12 | 13 | 修改eggjs项目中config/plugin.ts文件,开启egg-nacos-ts插件。 14 | 15 | ```typescript 16 | // 示例代码 17 | import { EggPlugin } from 'egg'; 18 | 19 | const plugin: EggPlugin = { 20 | nacos: { 21 | enable: true, 22 | package: 'egg-nacos-ts', 23 | }, 24 | }; 25 | export default plugin; 26 | ``` 27 | 28 | 配置config/config.default.ts文件 29 | 30 | ```typescript 31 | // 示例代码,具体配置项参考ts声明文件 32 | config.nacos = { 33 | serverList: ['127.0.0.1:8848'], 34 | namespace: 'public', 35 | subscribers: { // 需要监听的服务,不配置不监听 36 | messageService: { 37 | serviceName: 'message-service', 38 | }, 39 | }, 40 | configCenter: { // 配置中心相关配置 41 | clientOptions: {}, 42 | configList: { 43 | baseConfig: { 44 | dataId: 'test-config.yml', 45 | groupName: 'DEFAULT_GROUP', 46 | }, 47 | }, 48 | }, 49 | providers: { 50 | accountService: { 51 | serviceName: 'account-service', 52 | instance: { 53 | ip: '127.0.0.1', 54 | port: 8874, 55 | }, 56 | groupName: 'DEFAULT_GROUP', 57 | }, 58 | }, 59 | }; 60 | ``` 61 | 62 | #### 使用方式: 63 | 64 | 从nacos配置中心远程读取配置示例: 65 | 66 | ```typescript 67 | // agent.ts 68 | import { Agent } from 'egg'; 69 | import { saveNacosRemoteConfig } from './lib/configHandler'; 70 | 71 | export default class AgentBootHook { 72 | constructor(private readonly agent: Agent) {} 73 | 74 | async didReady() { 75 | // 把nacos远程配置保存到临时文件,供appWorker调用。 76 | await saveNacosRemoteConfig(this.agent); 77 | } 78 | } 79 | ``` 80 | 81 | ```typescript 82 | // app.ts 83 | import { Application, IBoot } from 'egg'; 84 | import { initNacosConfig } from './lib/configHandler'; 85 | 86 | export default class AppBoot implements IBoot { 87 | constructor(private app: Application) {} 88 | 89 | configWillLoad() { 90 | initNacosConfig(this.app); 91 | } 92 | 93 | async didReady() {} 94 | async beforeClose() {} 95 | } 96 | ``` 97 | 98 | ```typescript 99 | // lib/configHandler.ts 100 | import { Agent, EggApplication } from 'egg'; 101 | import * as fs from 'fs'; 102 | import * as path from 'path'; 103 | import * as assert from 'assert'; 104 | import * as YAML from 'yamljs'; 105 | import * as is from 'is-type-of'; 106 | 107 | // 临时写入的远程配置文件 108 | export const nacosRuntimeFile = './run/nacos-remote-config.json'; 109 | 110 | /** 111 | * 使用字符串深度获取对象属性 112 | * @param object 113 | * @param path 114 | * @param defaultValue 115 | */ 116 | export const deepGet = (object, path, defaultValue?) => { 117 | return ( 118 | (!Array.isArray(path) 119 | ? path 120 | .replace(/\[/g, '.') 121 | .replace(/\]/g, '') 122 | .split('.') 123 | : path 124 | ).reduce((o, k) => (o || {})[k], object) || defaultValue 125 | ); 126 | }; 127 | 128 | /** 129 | * 深度遍历配置文件,检查模板字段,并替换。 130 | * @param obj 131 | * @param cb 132 | */ 133 | export const depthSearch = (obj, config) => { 134 | const regular = /^\$\{(.*)+\}$/; 135 | for (const index in obj) { 136 | const item = obj[index]; 137 | if (is.object(item)) { 138 | depthSearch(item, config); 139 | } else if (is.string(item) && regular.test(item)) { 140 | // console.log(item, deepGet(config, temp[1], '')); 141 | const temp = item.match(regular); 142 | obj[index] = deepGet(config, temp[1], ''); 143 | } 144 | } 145 | }; 146 | 147 | /** 148 | * agentWorker获取nacos配置数据, 149 | * 写入到运行时文件中,供appWorker调用。 150 | * @param agent 151 | */ 152 | export const saveNacosRemoteConfig = async (agent: Agent) => { 153 | const { nacosConfig, config } = agent; 154 | try { 155 | const configs = await nacosConfig.getAllConfigs(); 156 | if (configs.length < 1) { 157 | throw new Error('Nacos配置信息未找到'); 158 | } 159 | const configData = YAML.parse(Object.values(configs[0])[0]); 160 | const tempConfigFile = path.join(agent.baseDir, nacosRuntimeFile); 161 | fs.writeFileSync(tempConfigFile, JSON.stringify(configData)); 162 | } catch (err) { 163 | agent.logger.error(err); 164 | throw new Error('Nacos配置信息获取失败!'); 165 | } 166 | }; 167 | 168 | /** 169 | * 从临时文件中读取agentWorker保存的远程配置文件, 170 | * 并修改当前项目中的config文件。 171 | * @param app 172 | */ 173 | export const initNacosConfig = (app: EggApplication) => { 174 | const tempConfigFile = path.join(app.baseDir, nacosRuntimeFile); 175 | try { 176 | const content = fs.readFileSync(tempConfigFile); 177 | const remoteConfig = JSON.parse(content.toString()); 178 | depthSearch(app.config, remoteConfig); 179 | } catch (err) { 180 | app.logger.error('nacos配置文件读取失败!'); 181 | throw err; 182 | } 183 | }; 184 | ``` 185 | 186 | ```typescript 187 | // 示例配置 config.default.ts 188 | config.typeorm = { 189 | clients: { 190 | accountDB: { 191 | type: 'postgres', 192 | host: '${database.host}', // 这里会用远程拿到的配置信息替换 193 | port: '${database.port}', // 这里会用远程拿到的配置信息替换 194 | username: '${database.username}', // 这里会用远程拿到的配置信息替换 195 | password: '${database.password}', // 这里会用远程拿到的配置信息替换 196 | }, 197 | }, 198 | }; 199 | ``` 200 | -------------------------------------------------------------------------------- /agent.ts: -------------------------------------------------------------------------------- 1 | import 'reflect-metadata'; 2 | import { Agent, IBoot } from 'egg'; 3 | import NacosNaming from './lib/nacosNaming'; 4 | import NacosConfig from './lib/nacosConfig'; 5 | 6 | export default class AgentBoot implements IBoot { 7 | private nacosNaming: NacosNaming; 8 | private nacosConfig: NacosConfig; 9 | 10 | constructor(private agent: Agent) {} 11 | 12 | configWillLoad() {} 13 | 14 | async didLoad() { 15 | this.nacosConfig = (this.agent.nacosConfig = new NacosConfig(this.agent)); 16 | await this.nacosConfig.createClient(); 17 | } 18 | 19 | async willReady() { 20 | this.nacosNaming = (this.agent.nacosNaming = new NacosNaming(this.agent)); 21 | await this.nacosNaming.createClient(); 22 | } 23 | 24 | async didReady() {} 25 | 26 | async serverDidReady() { 27 | // @ts-ignore 28 | process.on('SIGINT', () => { 29 | this.beforeClose(); 30 | }); 31 | await this.nacosNaming.registerSubscribers(); 32 | await this.nacosNaming.registerProviders(); 33 | } 34 | 35 | async beforeClose() { 36 | await this.nacosNaming.deregisterProviders(); 37 | await this.nacosNaming.deregisterSubscribers(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app.ts: -------------------------------------------------------------------------------- 1 | import { Application, IBoot } from 'egg'; 2 | import NacosClient from './lib/nacosClient'; 3 | import NacosConfig from './lib/nacosConfig'; 4 | 5 | export default class AppBoot implements IBoot { 6 | constructor(private app: Application) {} 7 | 8 | configWillLoad() {} 9 | 10 | async didLoad() { 11 | if (this.app.config.nacos?.serverList) { 12 | this.app.nacosNaming = new NacosClient(this.app); 13 | } 14 | if (this.app.config.nacos?.configCenter) { 15 | this.app.nacosConfig = new NacosConfig(this.app); 16 | await this.app.nacosConfig.createClient(); 17 | // @ts-ignore 18 | process.on('SIGINT', () => { 19 | this.beforeClose(); 20 | }); 21 | } 22 | } 23 | 24 | async willReady() {} 25 | 26 | async didReady() {} 27 | 28 | async serverDidReady() {} 29 | 30 | async beforeClose() { 31 | this.app.nacosConfig.close(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | matrix: 3 | - nodejs_version: '8' 4 | - nodejs_version: '10' 5 | - nodejs_version: '12' 6 | 7 | install: 8 | - ps: Install-Product node $env:nodejs_version 9 | - npm i npminstall && node_modules\.bin\npminstall 10 | 11 | test_script: 12 | - node --version 13 | - npm --version 14 | - npm run test 15 | 16 | build: off 17 | -------------------------------------------------------------------------------- /config/config.default.ts: -------------------------------------------------------------------------------- 1 | import { address } from 'ip'; 2 | import { EggAppConfig, PowerPartial } from 'egg'; 3 | import { NacosConfig } from '../typings/interface'; 4 | 5 | export default () => { 6 | const config = {} as PowerPartial; 7 | 8 | config.nacos = { 9 | namespace: 'public', 10 | subscribers: {}, 11 | configCenter: {}, 12 | providers: {}, 13 | } as NacosConfig; 14 | 15 | return config; 16 | }; 17 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | import { ForgedNacos } from './typings/interface'; 2 | import NacosNaming from './lib/nacosNaming'; 3 | import NacosConfig from './lib/nacosConfig' 4 | 5 | declare module 'egg' { 6 | interface Agent { 7 | nacosNaming: NacosNaming; 8 | nacosConfig: NacosConfig; 9 | } 10 | interface Application { 11 | nacosNaming: ForgedNacos; 12 | nacosConfig: NacosConfig; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lib/nacosClient.ts: -------------------------------------------------------------------------------- 1 | import uuidV1 = require('uuid/v1'); 2 | import { Application } from 'egg'; 3 | import { ForgedNacos, NacosHost } from '../typings/interface'; 4 | 5 | export default class NacosClient implements ForgedNacos { 6 | constructor(private _app: Application) {} 7 | 8 | private getServerStatusProxy(cb: (err: Error | null, status: 'UP' | 'DOWN') => void) { 9 | const uuid = uuidV1(); 10 | this._app.messenger.sendToAgent('getServerStatus', { 11 | eventId: uuid, 12 | }); 13 | // 超时处理 14 | const timeout = setTimeout(() => { 15 | this._app.messenger.removeAllListeners(uuid); 16 | cb(new Error('Nacos getAllInstances failed!'), 'DOWN'); 17 | }, 5000); 18 | this._app.messenger.once(uuid, ({ status, error }) => { 19 | clearTimeout(timeout); 20 | cb(error, status); 21 | }); 22 | } 23 | 24 | private getAllInstancesProxy( 25 | serviceName: string, 26 | groupName: string, 27 | clusters: string, 28 | subscribe: boolean, 29 | cb: (err: Error | null, hosts: NacosHost[]) => void, 30 | ) { 31 | const uuid = uuidV1(); 32 | this._app.messenger.sendToAgent('getAllInstances', { 33 | params: { 34 | serviceName, 35 | groupName, 36 | clusters, 37 | subscribe, 38 | }, 39 | eventId: uuid, 40 | }); 41 | // 超时处理 42 | const timeout = setTimeout(() => { 43 | this._app.messenger.removeAllListeners(uuid); 44 | cb(new Error('Nacos getAllInstances failed!'), []); 45 | }, 5000); 46 | this._app.messenger.once(uuid, ({ hosts, error }) => { 47 | clearTimeout(timeout); 48 | cb(error, hosts); 49 | }); 50 | } 51 | 52 | private selectInstancesProxy( 53 | serviceName: string, 54 | groupName: string, 55 | clusters: string, 56 | healthy: boolean, 57 | subscribe: boolean, 58 | cb: (err: Error | null, hosts: NacosHost[]) => void, 59 | ) { 60 | const uuid = uuidV1(); 61 | this._app.messenger.sendToAgent('selectInstances', { 62 | params: { 63 | serviceName, 64 | groupName, 65 | clusters, 66 | healthy, 67 | subscribe, 68 | }, 69 | eventId: uuid, 70 | }); 71 | // 超时处理 72 | const timeout = setTimeout(() => { 73 | this._app.messenger.removeAllListeners(uuid); 74 | cb(new Error('Nacos getAllInstances failed!'), []); 75 | }, 5000); 76 | this._app.messenger.once(uuid, ({ hosts, error }) => { 77 | clearTimeout(timeout); 78 | cb(error, hosts); 79 | }); 80 | } 81 | 82 | async getServerStatus(): Promise<'UP' | 'DOWN'> { 83 | return await new Promise((resolve, reject) => { 84 | this.getServerStatusProxy((error: Error | null, status: 'UP' | 'DOWN') => { 85 | if (error) { 86 | this._app.logger.error(error); 87 | reject(error); 88 | } else { 89 | if (!status) { 90 | const err = new Error('Nacos服务状态查询失败'); 91 | this._app.logger.error(err); 92 | reject(err); 93 | } else { 94 | resolve(status); 95 | } 96 | } 97 | }); 98 | }); 99 | } 100 | 101 | async getAllInstances( 102 | serviceName: string, 103 | groupName = 'DEFAULT_GROUP', 104 | clusters = '', 105 | subscribe = true, 106 | ): Promise { 107 | return await new Promise((resolve, reject) => { 108 | this.getAllInstancesProxy( 109 | serviceName, 110 | groupName, 111 | clusters, 112 | subscribe, 113 | (error: Error | null, hosts: NacosHost[]) => { 114 | if (error) { 115 | this._app.logger.error(error); 116 | reject(error); 117 | } else { 118 | if (!hosts || hosts.length === 0) { 119 | const err = new Error(`服务[${serviceName}]未找到,请重试`); 120 | this._app.logger.error(err); 121 | reject(err); 122 | } else { 123 | resolve(hosts); 124 | } 125 | } 126 | }, 127 | ); 128 | }); 129 | } 130 | 131 | async selectInstances( 132 | serviceName: string, 133 | groupName = 'DEFAULT_GROUP', 134 | clusters = '', 135 | healthy = true, 136 | subscribe = true, 137 | ): Promise { 138 | return await new Promise((resolve, reject) => { 139 | this.selectInstancesProxy( 140 | serviceName, 141 | groupName, 142 | clusters, 143 | healthy, 144 | subscribe, 145 | (error: Error | null, hosts: NacosHost[]) => { 146 | if (error) { 147 | this._app.logger.error(error); 148 | reject(error); 149 | } else { 150 | if (!hosts || hosts.length === 0) { 151 | const err = new Error(`服务[${serviceName}]未找到,请重试`); 152 | this._app.logger.error(err); 153 | reject(err); 154 | } else { 155 | resolve(hosts); 156 | } 157 | } 158 | }, 159 | ); 160 | }); 161 | } 162 | 163 | async selectRandomInstance( 164 | serviceName: string, 165 | groupName = 'DEFAULT_GROUP', 166 | clusters = '', 167 | healthy = true, 168 | subscribe = true, 169 | ) { 170 | const hosts = await this.selectInstances(serviceName, groupName, clusters, healthy, subscribe); 171 | return this.weightRandom(hosts); 172 | } 173 | 174 | async getRandomInstance(serviceName: string, groupName = 'DEFAULT_GROUP', clusters = '', subscribe = true) { 175 | const hosts = await this.getAllInstances(serviceName, groupName, clusters, subscribe); 176 | return this.weightRandom(hosts); 177 | } 178 | 179 | private weightRandom(list: NacosHost[]) { 180 | const randomList: NacosHost[] = []; 181 | for (const i in list) { 182 | const item = list[i]; 183 | if (!item.weight) { 184 | item.weight = 1; 185 | } 186 | for (let j = 0; j < item.weight; j++) { 187 | randomList.push(item); 188 | } 189 | } 190 | return randomList[Math.floor(Math.random() * randomList.length)]; 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /lib/nacosConfig.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | import { Agent, Application } from 'egg'; 3 | import { NacosConfigClient } from 'nacos'; 4 | import { ConfigEntity } from '../typings/interface'; 5 | 6 | export default class NacosConfig { 7 | private _nacosConfigClient: NacosConfigClient; 8 | 9 | constructor(private worker: Agent | Application) {} 10 | 11 | get nacosConfigClient() { 12 | return this._nacosConfigClient; 13 | } 14 | 15 | public async createClient() { 16 | const { nacos } = this.worker.config; 17 | assert(nacos.serverList && nacos.serverList.length > 0, 'Nacos serverList不能为空'); 18 | 19 | this._nacosConfigClient = new NacosConfigClient({ 20 | serverAddr: nacos.serverList[0], 21 | namespace: nacos.namespace, 22 | ...nacos.configCenter.clientOptions, 23 | }); 24 | await this._nacosConfigClient.ready(); 25 | return this._nacosConfigClient; 26 | } 27 | 28 | public async getAllConfigs() { 29 | const { configCenter } = this.worker.config.nacos; 30 | if (!configCenter.configList) { 31 | return []; 32 | } 33 | const configList: ConfigEntity[] = Object.values(configCenter.configList); 34 | if (configList.length < 1) { 35 | return []; 36 | } 37 | const configNames: string[] = []; 38 | const asyncQueue: Array> = []; 39 | for (const key in configCenter.configList) { 40 | configNames.push(key); 41 | const { dataId, groupName, options = {} } = configCenter.configList[key]; 42 | asyncQueue.push(this._nacosConfigClient.getConfig(dataId, groupName, { ...options })); 43 | } 44 | const result: string[] = await Promise.all(asyncQueue); 45 | return configNames.map((name, index) => ({ [name]: result[index] })); 46 | } 47 | 48 | public close() { 49 | this._nacosConfigClient.close(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /lib/nacosNaming.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | import { Agent } from 'egg'; 3 | import { ProviderConfig, SubscriberConfig } from '../typings/interface'; 4 | const { NacosNamingClient } = require('nacos'); 5 | 6 | export default class NacosNaming { 7 | private _nacosNamingClient; 8 | 9 | constructor(private agent: Agent) {} 10 | 11 | get nacosNamingClient() { 12 | return this._nacosNamingClient; 13 | } 14 | 15 | public async createClient() { 16 | const { nacos } = this.agent.config; 17 | assert(nacos.serverList && nacos.serverList.length > 0, 'Nacos serverList不能为空'); 18 | 19 | this._nacosNamingClient = new NacosNamingClient({ 20 | ...nacos, 21 | logger: this.agent.logger, 22 | }); 23 | await this._nacosNamingClient.ready(); 24 | this.registerEvents(); 25 | return this._nacosNamingClient; 26 | } 27 | 28 | public async registerProviders() { 29 | const { nacos } = this.agent.config; 30 | // 注册服务 31 | if (nacos.providers) { 32 | const providers = Object.values(nacos.providers) as ProviderConfig[]; 33 | providers.forEach(async service => { 34 | await this._nacosNamingClient.registerInstance( 35 | service.serviceName, 36 | { 37 | ...service.instance, 38 | }, 39 | service.groupName, 40 | ); 41 | }); 42 | } 43 | } 44 | 45 | public async registerSubscribers() { 46 | const { nacos } = this.agent.config; 47 | // 订阅服务 48 | if (nacos.subscribers) { 49 | const subscribers = Object.values(nacos.subscribers) as SubscriberConfig[]; 50 | subscribers.forEach(service => { 51 | this._nacosNamingClient.subscribe(service, hosts => { 52 | this.agent.logger.info(`[egg-nacos] New service detected: ${JSON.stringify(hosts)}`); 53 | }); 54 | }); 55 | } 56 | } 57 | 58 | public async deregisterProviders() { 59 | const { nacos } = this.agent.config; 60 | if (nacos.providers) { 61 | const providers = Object.values(nacos.providers) as ProviderConfig[]; 62 | providers.forEach(async service => { 63 | await this._nacosNamingClient.deregisterInstance( 64 | service, 65 | { 66 | ...service.instance, 67 | }, 68 | service.groupName, 69 | ); 70 | }); 71 | } 72 | } 73 | 74 | public async deregisterSubscribers() { 75 | const { nacos } = this.agent.config; 76 | if (nacos.subscribers) { 77 | const subscribers = Object.values(nacos.subscribers) as SubscriberConfig[]; 78 | subscribers.forEach(service => { 79 | this._nacosNamingClient.unSubscribe(service, () => {}); 80 | }); 81 | } 82 | } 83 | 84 | private registerEvents() { 85 | this.agent.messenger.on('getServerStatus', async ({ eventId }) => { 86 | let error = null; 87 | let status = 'DOWN'; 88 | try { 89 | status = await this._nacosNamingClient.getServerStatus(); 90 | } catch (err) { 91 | error = err; 92 | } 93 | this.agent.messenger.sendToApp(eventId, { 94 | error, 95 | status, 96 | }); 97 | }); 98 | 99 | this.agent.messenger.on( 100 | 'getAllInstances', 101 | async ({ 102 | eventId, 103 | params, 104 | }) => { 105 | let error = null; 106 | let hosts = []; 107 | const { serviceName, groupName, clusters, subscribe } = params; 108 | try { 109 | hosts = await this._nacosNamingClient.getAllInstances(serviceName, groupName, clusters, subscribe); 110 | } catch (err) { 111 | error = err; 112 | } 113 | this.agent.messenger.sendToApp(eventId, { 114 | error, 115 | hosts, 116 | }); 117 | }, 118 | ); 119 | 120 | this.agent.messenger.on( 121 | 'selectInstances', 122 | async ({ 123 | eventId, 124 | params, 125 | }) => { 126 | let error = null; 127 | let hosts = []; 128 | const { serviceName, groupName, clusters, healthy, subscribe } = params; 129 | try { 130 | hosts = await this._nacosNamingClient.selectInstances( 131 | serviceName, 132 | groupName, 133 | clusters, 134 | healthy, 135 | subscribe, 136 | ); 137 | } catch (err) { 138 | error = err; 139 | } 140 | this.agent.messenger.sendToApp(eventId, { 141 | error, 142 | hosts, 143 | }); 144 | }, 145 | ); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "egg-nacos-ts", 3 | "version": "1.0.2", 4 | "description": "Nacos plugin for egg", 5 | "eggPlugin": { 6 | "name": "nacos" 7 | }, 8 | "keywords": [ 9 | "egg", 10 | "eggPlugin", 11 | "egg-plugin", 12 | "nacos" 13 | ], 14 | "scripts": { 15 | "build": "tsc -d" 16 | }, 17 | "dependencies": { 18 | "egg": "^2.26.0", 19 | "nacos": "^2.0.0", 20 | "uuid": "^3.3.3" 21 | }, 22 | "devDependencies": { 23 | "@types/node": "^7.10.5", 24 | "autod": "^3.0.1", 25 | "autod-egg": "^1.1.0", 26 | "egg-bin": "^4.13.1", 27 | "egg-ci": "^1.8.0", 28 | "egg-mock": "^3.16.0", 29 | "egg-ts-helper": "^1.25.5", 30 | "tsconfig-paths": "^3.8.0", 31 | "tslib": "^1.9.0", 32 | "tslint": "^5.0.0", 33 | "tslint-config-egg": "^1.0.0", 34 | "typescript": "^3.7.3" 35 | }, 36 | "engines": { 37 | "node": ">=8.9.0" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": true, 3 | "compilerOptions": { 4 | /* Basic Options */ 5 | "target": "es2017" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */, 6 | "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */, 7 | // "lib": [], /* Specify library files to be included in the compilation. */ 8 | // "allowJs": true, /* Allow javascript files to be compiled. */ 9 | // "checkJs": true, /* Report errors in .js files. */ 10 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 11 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 12 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 13 | "sourceMap": false /* Generates corresponding '.map' file. */, 14 | // "outFile": "./", /* Concatenate and emit output to single file. */ 15 | "outDir": "./" /* Redirect output structure to the directory. */, 16 | // "rootDir": "./src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */, 17 | // "composite": true, /* Enable project compilation */ 18 | "removeComments": true /* Do not emit comments to output. */, 19 | // "noEmit": true, /* Do not emit outputs. */ 20 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 21 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 22 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 23 | 24 | /* Strict Type-Checking Options */ 25 | //"strict": true, /* Enable all strict type-checking options. */ 26 | "noImplicitAny": false /* Raise error on expressions and declarations with an implied 'any' type. */, 27 | // "strictNullChecks": true, /* Enable strict null checks. */ 28 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 29 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 30 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 31 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 32 | 33 | /* Additional Checks */ 34 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 35 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 36 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 37 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 38 | 39 | /* Module Resolution Options */ 40 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 41 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 42 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 43 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 44 | // "typeRoots": [], /* List of folders to include type definitions from. */ 45 | // "types": [], /* Type declaration files to be included in compilation. */ 46 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 47 | // "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 48 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 49 | 50 | /* Source Map Options */ 51 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 52 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 53 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 54 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 55 | 56 | /* Experimental Options */ 57 | "experimentalDecorators": true /* Enables experimental support for ES7 decorators. */, 58 | "emitDecoratorMetadata": true /* Enables experimental support for emitting type metadata for decorators. */, 59 | "skipLibCheck": true, 60 | }, 61 | "exclude": ["node_modules", "dist"], 62 | "include": ["./**/*.ts"] 63 | } -------------------------------------------------------------------------------- /typings/interface.d.ts: -------------------------------------------------------------------------------- 1 | import { ClientOptions } from 'nacos'; 2 | export interface ProviderConfig { 3 | serviceName: string; 4 | instance: { 5 | ip: string; 6 | port: number; 7 | [props: string]: any; 8 | }; 9 | groupName: string; 10 | } 11 | export interface SubscriberConfig { 12 | serviceName: string; 13 | } 14 | export interface ConfigEntity { 15 | dataId: string; 16 | groupName: string; 17 | options?: { 18 | unit?: string; 19 | }; 20 | } 21 | export interface NacosConfig { 22 | serverList: string[]; 23 | namespace: string; 24 | configCenter?: { 25 | clientOptions: ClientOptions; 26 | configList: { 27 | [props: string]: ConfigEntity; 28 | }; 29 | }; 30 | subscribers?: { 31 | [props: string]: SubscriberConfig; 32 | }; 33 | providers?: { 34 | [props: string]: ProviderConfig; 35 | }; 36 | [props: string]: any; 37 | } 38 | export interface NacosHost { 39 | valid: boolean; 40 | marked: boolean; 41 | metadata: object; 42 | instanceId: string; 43 | port: number; 44 | healthy: boolean; 45 | ip: string; 46 | clusterName: string; 47 | weight: number; 48 | ephemeral: boolean; 49 | serviceName: string; 50 | enabled: boolean; 51 | [props: string]: any; 52 | } 53 | export interface ForgedNacos { 54 | getRandomInstance(serviceName: string, groupName?: string, clusters?: string, subscribe?: boolean): Promise; 55 | selectRandomInstance(serviceName: string, groupName?: string, clusters?: string, healthy?: boolean, subscribe?: boolean): Promise; 56 | getAllInstances(serviceName: string, groupName?: string, clusters?: string, subscribe?: boolean): Promise; 57 | selectInstances(serviceName: string, groupName?: string, clusters?: string, healthy?: boolean, subscribe?: boolean): Promise; 58 | getServerStatus(): Promise<'UP' | 'DOWN'>; 59 | } 60 | -------------------------------------------------------------------------------- /typings/interface.ts: -------------------------------------------------------------------------------- 1 | import { ClientOptions } from 'nacos'; 2 | 3 | export interface ProviderConfig { 4 | serviceName: string; 5 | instance: { 6 | ip: string; 7 | port: number; 8 | [props: string]: any; 9 | }; 10 | groupName: string; 11 | } 12 | 13 | export interface SubscriberConfig { 14 | serviceName: string; 15 | } 16 | 17 | export interface ConfigEntity { 18 | dataId: string; 19 | groupName: string; 20 | options?: { 21 | unit?: string; 22 | }; 23 | } 24 | 25 | export interface NacosConfig { 26 | serverList: string[]; 27 | namespace: string; 28 | configCenter?: { 29 | clientOptions: ClientOptions; 30 | configList: { 31 | [props: string]: ConfigEntity; 32 | }; 33 | }; 34 | subscribers?: { 35 | [props: string]: SubscriberConfig; 36 | }; 37 | providers?: { 38 | [props: string]: ProviderConfig; 39 | }; 40 | [props: string]: any; 41 | } 42 | 43 | export interface NacosHost { 44 | valid: boolean; 45 | marked: boolean; 46 | metadata: object; 47 | instanceId: string; 48 | port: number; 49 | healthy: boolean; 50 | ip: string; 51 | clusterName: string; 52 | weight: number; 53 | ephemeral: boolean; 54 | serviceName: string; 55 | enabled: boolean; 56 | [props: string]: any; 57 | } 58 | 59 | export interface ForgedNacos { 60 | getRandomInstance( 61 | serviceName: string, 62 | groupName?: string, 63 | clusters?: string, 64 | subscribe?: boolean, 65 | ): Promise; 66 | selectRandomInstance( 67 | serviceName: string, 68 | groupName?: string, 69 | clusters?: string, 70 | healthy?: boolean, 71 | subscribe?: boolean, 72 | ): Promise; 73 | getAllInstances( 74 | serviceName: string, 75 | groupName?: string, 76 | clusters?: string, 77 | subscribe?: boolean, 78 | ): Promise; 79 | selectInstances( 80 | serviceName: string, 81 | groupName?: string, 82 | clusters?: string, 83 | healthy?: boolean, 84 | subscribe?: boolean, 85 | ): Promise; 86 | getServerStatus(): Promise<'UP' | 'DOWN'>; 87 | } 88 | --------------------------------------------------------------------------------