├── .eslintignore ├── .eslintrc ├── test ├── fixtures │ └── apps │ │ ├── ons-test │ │ ├── package.json │ │ ├── app.js │ │ ├── app │ │ │ ├── ons │ │ │ │ └── TEST_TOPIC.js │ │ │ └── router.js │ │ └── config │ │ │ └── config.unittest.js │ │ └── ons-test-dynamic │ │ ├── package.json │ │ ├── app │ │ ├── ons │ │ │ └── TEST_TOPIC.js │ │ └── router.js │ │ ├── app.js │ │ └── config │ │ └── config.unittest.js ├── config.js └── ons.test.js ├── .gitignore ├── app └── extend │ └── context.js ├── config ├── config.prod.js └── config.default.js ├── app.js ├── .autod.conf.js ├── LICENSE ├── History.md ├── package.json ├── .travis.yml ├── lib └── ons.js └── README.md /.eslintignore: -------------------------------------------------------------------------------- 1 | coverage 2 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint-config-egg" 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/apps/ons-test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ons-test", 3 | "version": "0.0.1" 4 | } -------------------------------------------------------------------------------- /test/fixtures/apps/ons-test-dynamic/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ons-test-dynamic", 3 | "version": "0.0.1" 4 | } 5 | -------------------------------------------------------------------------------- /test/fixtures/apps/ons-test/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = app => { 4 | app.onsMsgs = new Map(); 5 | }; 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | logs/ 2 | npm-debug.log 3 | node_modules/ 4 | coverage/ 5 | .idea/ 6 | run/ 7 | .DS_Store 8 | *.swp 9 | 10 | -------------------------------------------------------------------------------- /app/extend/context.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | get ons() { 5 | return this.app.ons; 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /config/config.prod.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.ons = { 4 | default: { 5 | onsAddr: 'http://onsaddr-internal.aliyun.com:8080/rocketmq/nsaddr4client-internal', 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const ONS = require('./lib/ons'); 4 | 5 | module.exports = app => { 6 | app.ons = new ONS(app); 7 | app.beforeStart(async () => { 8 | await app.ons.init(); 9 | }); 10 | }; 11 | -------------------------------------------------------------------------------- /test/fixtures/apps/ons-test/app/ons/TEST_TOPIC.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | class TestSubscriber { 4 | constructor(ctx) { 5 | this.ctx = ctx; 6 | this.app = ctx.app; 7 | } 8 | 9 | async subscribe(msg) { 10 | this.app.onsMsgs.set(msg.msgId, msg); 11 | } 12 | } 13 | 14 | module.exports = TestSubscriber; 15 | -------------------------------------------------------------------------------- /test/fixtures/apps/ons-test-dynamic/app/ons/TEST_TOPIC.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | class TestSubscriber { 4 | constructor(ctx) { 5 | this.ctx = ctx; 6 | this.app = ctx.app; 7 | } 8 | 9 | async subscribe(msg) { 10 | this.app.onsMsgs.set(msg.msgId, msg); 11 | } 12 | } 13 | 14 | module.exports = TestSubscriber; 15 | -------------------------------------------------------------------------------- /test/fixtures/apps/ons-test-dynamic/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = app => { 4 | app.onsMsgs = new Map(); 5 | app.beforeStart(function* () { 6 | yield app.ons.createConsumer(app.config.ons.dynamicSub, { 7 | TEST_TOPIC: require('./app/ons/TEST_TOPIC'), 8 | }); 9 | yield app.ons.createProducer(app.config.ons.dynamicPub); 10 | }); 11 | }; 12 | -------------------------------------------------------------------------------- /.autod.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | write: true, 5 | prefix: '^', 6 | plugin: 'autod-egg', 7 | test: [ 8 | 'test', 9 | 'benchmark', 10 | ], 11 | devdep: [ 12 | 'egg', 13 | 'egg-bin', 14 | 'autod', 15 | 'autod-egg', 16 | 'eslint', 17 | 'eslint-config-egg', 18 | 'webstorm-disable-index', 19 | ], 20 | exclude: [ 21 | './test/fixtures', 22 | './docs', 23 | './coverage', 24 | ], 25 | }; 26 | -------------------------------------------------------------------------------- /test/fixtures/apps/ons-test/config/config.unittest.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const config = require('../../../../config'); 4 | 5 | exports.keys = '123456'; 6 | 7 | exports.ons = { 8 | default: { 9 | accessKey: config.accessKey, 10 | secretKey: config.secretKey, 11 | onsAddr: config.onsAddr, 12 | }, 13 | sub: [{ 14 | consumerGroup: config.consumerGroup, 15 | topics: [ 16 | 'TEST_TOPIC', 17 | ], 18 | }], 19 | pub: [{ 20 | producerGroup: config.producerGroup, 21 | topics: [ 22 | 'TEST_TOPIC', 23 | ], 24 | }], 25 | }; 26 | -------------------------------------------------------------------------------- /test/fixtures/apps/ons-test-dynamic/config/config.unittest.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const config = require('../../../../config'); 4 | 5 | exports.keys = '123456'; 6 | 7 | exports.ons = { 8 | default: { 9 | accessKey: config.accessKey, 10 | secretKey: config.secretKey, 11 | onsAddr: config.onsAddr, 12 | }, 13 | dynamicSub: { 14 | consumerGroup: config.consumerGroup, 15 | topics: [ 16 | 'TEST_TOPIC', 17 | ], 18 | }, 19 | dynamicPub: { 20 | producerGroup: config.producerGroup, 21 | topics: [ 22 | 'TEST_TOPIC', 23 | ], 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /test/config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const env = process.env; 4 | 5 | // export ALI_SDK_ONS_ID=your-accesskey 6 | // export ALI_SDK_ONS_SECRET=your-secretkey 7 | // export ALI_SDK_ONS_CGROUP=your-consumer-group 8 | // export ALI_SDK_ONS_PGROUP=your-producer-group 9 | // export ALI_SDK_ONS_TOPIC=your-topic 10 | 11 | module.exports = { 12 | accessKey: env.ALI_SDK_ONS_ID, 13 | secretKey: env.ALI_SDK_ONS_SECRET, 14 | producerGroup: env.ALI_SDK_ONS_PGROUP, 15 | consumerGroup: env.ALI_SDK_ONS_CGROUP, 16 | topic: env.ALI_SDK_ONS_TOPIC, 17 | onsAddr: 'http://onsaddr-internet.aliyun.com/rocketmq/nsaddr4client-internet', 18 | }; 19 | -------------------------------------------------------------------------------- /test/fixtures/apps/ons-test/app/router.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assert = require('assert'); 4 | const sleep = require('mz-modules/sleep'); 5 | 6 | module.exports = app => { 7 | app.get('/', function* () { 8 | this.body = 'hi, ' + app.plugins.ons.name; 9 | }); 10 | 11 | app.get('/sendMessage', function* () { 12 | const Message = this.ons.Message; 13 | const msg = new Message('TEST_TOPIC', // topic 14 | 'TagA', // tag 15 | 'Hello ONS !!!' // body 16 | ); 17 | const sendResult = yield this.ons.send(msg); 18 | assert.equal(sendResult.sendStatus, 'SEND_OK'); 19 | 20 | while (!app.onsMsgs.has(sendResult.msgId)) { 21 | yield sleep(100); 22 | } 23 | this.body = 'ok'; 24 | }); 25 | }; 26 | -------------------------------------------------------------------------------- /test/fixtures/apps/ons-test-dynamic/app/router.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assert = require('assert'); 4 | const sleep = require('mz-modules/sleep'); 5 | 6 | module.exports = app => { 7 | app.get('/', function* () { 8 | this.body = 'hi, ' + app.plugins.ons.name; 9 | }); 10 | 11 | app.get('/sendMessage', function* () { 12 | const Message = this.ons.Message; 13 | const msg = new Message('TEST_TOPIC', // topic 14 | 'TagA', // tag 15 | 'Hello ONS !!!' // body 16 | ); 17 | const sendResult = yield this.ons.send(msg); 18 | assert.equal(sendResult.sendStatus, 'SEND_OK'); 19 | 20 | while (!app.onsMsgs.has(sendResult.msgId)) { 21 | yield sleep(100); 22 | } 23 | this.body = 'ok'; 24 | }); 25 | }; 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Alibaba Group Holding Limited and other contributors. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | 2 | 2.0.0 / 2018-07-26 3 | ================== 4 | 5 | **others** 6 | * [[`3a3b039`](http://github.com/eggjs/egg-ons/commit/3a3b03924d55210be49561fb84cfc0b8f2971ac3)] - refactor: use async await (Yiyu He <>) 7 | 8 | 1.1.0 / 2018-05-03 9 | ================== 10 | 11 | **features** 12 | * [[`097d576`](http://github.com/eggjs/egg-ons/commit/097d5765352e7f177170ec8f2b782d1034815a0d)] - feat: support dynamic create comsumer and producer (dead-horse <>) 13 | 14 | **others** 15 | * [[`9b46e9c`](http://github.com/eggjs/egg-ons/commit/9b46e9c4029d8cc9509ce1bf7afee9f98c083ebe)] - f (dead-horse <>) 16 | * [[`d86ed69`](http://github.com/eggjs/egg-ons/commit/d86ed69333093bdf3c0f637310f9d8b1e6c9d3d6)] - f (dead-horse <>) 17 | * [[`ebf5adc`](http://github.com/eggjs/egg-ons/commit/ebf5adc3087111a0a92dc6eeada6700a67be3f55)] - f (dead-horse <>) 18 | * [[`9a66754`](http://github.com/eggjs/egg-ons/commit/9a667549f4cb48ce7487c14039a441ae0956d2d0)] - doc: fix wrong plural config key (Hongcai Deng <>) 19 | * [[`9b97d3b`](http://github.com/eggjs/egg-ons/commit/9b97d3b6358053b003dd01be3fe91f9a688cd9db)] - chore: release 1.0.0 (xiaochen.gaoxc <>), 20 | 21 | 1.0.0 / 2017-10-19 22 | ================== 23 | 24 | * feat: implment ons plugin for egg 25 | -------------------------------------------------------------------------------- /test/ons.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const mm = require('egg-mock'); 4 | 5 | describe('test/ons.test.js', () => { 6 | describe('init', () => { 7 | let app; 8 | before(() => { 9 | app = mm.app({ 10 | baseDir: 'apps/ons-test', 11 | }); 12 | return app.ready(); 13 | }); 14 | 15 | after(() => app.close()); 16 | afterEach(mm.restore); 17 | 18 | it('should GET /', () => { 19 | return app.httpRequest() 20 | .get('/') 21 | .expect('hi, ons') 22 | .expect(200); 23 | }); 24 | 25 | it('should GET /sendMessage', () => { 26 | return app.httpRequest() 27 | .get('/sendMessage') 28 | .expect('ok') 29 | .expect(200); 30 | }); 31 | }); 32 | 33 | describe('dynamic', () => { 34 | let app; 35 | before(() => { 36 | app = mm.app({ 37 | baseDir: 'apps/ons-test-dynamic', 38 | }); 39 | return app.ready(); 40 | }); 41 | 42 | after(() => app.close()); 43 | afterEach(mm.restore); 44 | 45 | it('should GET /', () => { 46 | return app.httpRequest() 47 | .get('/') 48 | .expect('hi, ons') 49 | .expect(200); 50 | }); 51 | 52 | it('should GET /sendMessage', () => { 53 | return app.httpRequest() 54 | .get('/sendMessage') 55 | .expect('ok') 56 | .expect(200); 57 | }); 58 | }); 59 | }); 60 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "egg-ons", 3 | "version": "2.0.0", 4 | "description": "aliyun ons plugin for egg", 5 | "eggPlugin": { 6 | "name": "ons" 7 | }, 8 | "keywords": [ 9 | "egg", 10 | "eggPlugin", 11 | "egg-plugin" 12 | ], 13 | "dependencies": { 14 | "ali-ons": "^3.0.0" 15 | }, 16 | "devDependencies": { 17 | "autod": "^3.0.1", 18 | "autod-egg": "^1.1.0", 19 | "egg": "^2.9.1", 20 | "egg-bin": "^4.7.1", 21 | "egg-mock": "^3.17.3", 22 | "eslint": "^5.2.0", 23 | "eslint-config-egg": "^7.0.0", 24 | "webstorm-disable-index": "^1.2.0" 25 | }, 26 | "engines": { 27 | "node": ">=8.0.0" 28 | }, 29 | "scripts": { 30 | "test": "npm run lint -- --fix && egg-bin pkgfiles && npm run test-local", 31 | "test-local": "egg-bin test", 32 | "cov": "egg-bin cov", 33 | "lint": "eslint .", 34 | "ci": "egg-bin pkgfiles --check && npm run lint && npm run cov", 35 | "pkgfiles": "egg-bin pkgfiles", 36 | "autod": "autod" 37 | }, 38 | "files": [ 39 | "app", 40 | "config", 41 | "app.js", 42 | "lib" 43 | ], 44 | "repository": { 45 | "type": "git", 46 | "url": "git+https://github.com/eggjs/egg-ons.git" 47 | }, 48 | "bugs": { 49 | "url": "https://github.com/eggjs/egg/issues" 50 | }, 51 | "homepage": "https://github.com/eggjs/egg-ons#readme", 52 | "author": "gxcsoccer ", 53 | "license": "MIT" 54 | } 55 | -------------------------------------------------------------------------------- /config/config.default.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | 5 | module.exports = appInfo => { 6 | return { 7 | /** 8 | * egg-ons default config 9 | * @member Config#ons 10 | */ 11 | ons: { 12 | default: { 13 | // 公有云生产环境:http://onsaddr-internal.aliyun.com:8080/rocketmq/nsaddr4client-internal 14 | // 公有云公测环境:http://onsaddr-internet.aliyun.com/rocketmq/nsaddr4client-internet 15 | // 杭州金融云环境:http://jbponsaddr-internal.aliyun.com:8080/rocketmq/nsaddr4client-internal 16 | // 杭州深圳云环境:http://mq4finance-sz.addr.aliyun.com:8080/rocketmq/nsaddr4client-internal 17 | onsAddr: 'http://onsaddr-internet.aliyun.com/rocketmq/nsaddr4client-internet', 18 | // accessKey: 'your-accesskey', 19 | // secretKey: 'your-secretkey', 20 | }, 21 | sub: [ 22 | // { 23 | // consumerGroup: 'your-group', 24 | // accessKey: 'your-accesskey', 25 | // secretKey: 'your-secretkey', 26 | // topics: [ 27 | // 'your-topic-1', 28 | // 'your-topic-2', 29 | // ], 30 | // } 31 | ], 32 | pub: [ 33 | // { 34 | // producerGroup: 'your-group', 35 | // accessKey: 'your-accesskey', 36 | // secretKey: 'your-secretkey', 37 | // topics: [ 38 | // 'your-topic-1', 39 | // 'your-topic-2', 40 | // ], 41 | // } 42 | ], 43 | }, 44 | customLogger: { 45 | onsLogger: { 46 | consoleLevel: 'NONE', 47 | file: path.join(appInfo.root, 'logs', appInfo.name, 'ons.log'), 48 | }, 49 | }, 50 | }; 51 | }; 52 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - '8' 5 | - '10' 6 | install: 7 | - npm i npminstall && npminstall 8 | env: 9 | global: 10 | - secure: CV9zBiXYvJp5UmlT8P4qYlzXsLZQlKJ9CFq6nRVoE1bex8dVmWUq6bCuqad2Vz0xuQ/5dfZ4AQ9Ie0ZrXhDF/u6MTc6dTMR95lSo5nymxKH4fc01nLgMDDim0+NFWdUz/4ak3kKvmj9DNEfo3Bqpsv/kvJkkm0jSndXiwF1rzRZSQWDerrAIHXPJocWHWHGSTBPTntaZkz1tpX2Rac8KgAiKX5t4M6yGwTc6XaQSLZx7jlGMf5ew5gaefm5GpKaqJYr7Im+Jgo1FzkTk5y3G8qJEvvCFNc8Paoq1f7IQ0y9kxKTBifQpy7PoFlqFDycxBob2KtkbHO6oRhh0K89Vy9yJxEJjyPv/VSIF4fw12Ss20TadiBTWq2t7kHuFC1A5ok5GDDKYsMCZS1wj3uu+ZALKW3NoWOvzqx1wOavDEpvwnVhd5GSK7NHiKq3ZgGfMzaecNgeKjEARRNRBnzT6zQum1LLoYhqkpmhqsG88CEyaMVBrUGRPmXVAXNcLL9NosiAcHZm8B1H9/k1l4ws2ITZpiIyeuXDvbC0HaNiHMF9KJHJcrXxE5PsMFXibpOZ7gt1ZYJCwtL6g2HEzPyfUCtfQDh6QWAUKvkilKuSJzy+q23UD3j4JxKJkUOD9ouuPY4QvnVilBgMeCAG2CZwT6rWM8eLxQkaLPBpnuWFJC4Y= 11 | - secure: crj1da2pszVYSA2lNs8hMfrfTJbSQZzZGRBuZs6T5dH82tV00uImACjKx9INerpzDpF5lpKk5fqDeLuLcjugwwWLtrjlb8wYdAtFC8DfQBnSQXfOElZwjw4wRN5ljxf7pu4mH6Aair1g0Qsx6NqQSNjtJOvshSU01Ay/TK0HyKQKhutEiZSMPVL4OU3rjbKn8OYTiqfxf4Pejunxlprz6wFDImRsFBBVAjNdrUYUmOdXS5lMMJkUyPIt9qol+YXgBZc5OhFdlEZkIGPRQq+tqW9e3NzpE5CiwprhAZ4f01gMF/LFvn6Jh+4UsHtMf3RZMoAvo51uu7Ufq3LJB/Ik2P50EL2AsCGQJPv0h5QvQd8Ov/75ptM29vli4LbRoThicj42z1bGDc13gv1n/W/fF0NrqaBY5pa6hiFySCNlkfzzTvrdwaoyOhKGEgwaTz4eorcje/PSlyMnhw81BBi7LiOzzyT87CwPUoHlAJFVH08S4hfXn3ronW7tOpCuRbsy0lTHxiHQvw189VBp3Q1sI5aBbQub2Loq7py0bjwAeX2DYzbwmEFyQcaYvRZlmQZA1EvGE6AABYL/OBG2NFa0j7KygBVdMCjd+HeBf3BEb/BQju9KtjyZDlztmFirfov42FRuqX5DkdrtMEaqeYGhXDPnmiaCpuW01xBoh+ZlpKc= 12 | - secure: KONxQUtXWm6DP2IrPIL+7ctxiBl7PiZrzNqVb79pRo2Cgu+brjxmGyeiDUKPHwt87ARB5sBhv08YSoEgk81/O4yr52Mcod/yPhL6618ODrqJYp5O3bfFqOv0NFKrkuXopB1rx93NHslEk3484OyQI1BXtFwyYPe9GCWlr79+KsRz1wytxdaZdrhB8vRHXcfD4IyXiEPb1FNbrJqpWgGtEX/N568ydjo1d0uBDWoLUVG0VSP6DdbOq7iL9OQDwsm9OqL60XVigTOqfAtNRiY8h0HuLmS+d+disqaVcxG6ShPvOQWrk5mywi+9oMUNchjzuY/VTPXCwrhPGGJvyeef+lDvk12z0FB2to4Wn/GstdGz2bUxZZZU6098V+b2FTm/O1BM0wdIHzRBqqStAhPrCcJhvUd8FxnymiLJz61GjgBDG/ZTGWHs/XHlkisG1Ara/5PbKdUoVXFa+rENfew4/tfFJTqDBfiwtLW28yBffAc0VmUFcuU1IsrQoL2ChgjshH04f3oqAPsmr2jOwndAWazNYFNkJQHeb/OYGmG2SnuSv3OW2CMx6+eSjbu73CDIOhubif4mMRP7eNnvHust7vhGpnUV04ILjAtLPdflWHSmfRhSRzdf17uITy+GeJjm0fzDjSa+bHxSmg0FzOW5WCeanx9po9MOr3Cbhc127z0= 13 | - secure: DAbLTkNwoWZiKS7rBOwgxusYhpqWTSUv5PCZUb17tJLeaQLtm5NwBWdfJjbDO+zzpf5EsHcn/4bsk20AQDSDljx2Q+XB6oR+/2720VaUM5eyZ9bom6BuYkBDZIoqMTLK2g+Hz93JrOELi3Ib1s43pUeiLQ/iUE/z3ADlKHB0oLGcvbfwZXLSTJCnmk13+KoUf9pagSjVI0ll+xrmQVksSPoW5JsWtCef0ZECFcfo+l56D4vA099mp61+jr91pLTVk81PNt/pNm0xFIBfaL2YFgyGJaH4mU52fJ75yK6SenwPcwGKMOYI7XBmhu9jD1hxnOVP7qZK+VPM7rWyUlLFmQ27kYJ+Gwf5+oG58g17/ZVh+DgNZtibajWQ10mMy1kMdDo2ZRUQQefGU8pz2w9CZPl7N+N/ingxL49xpiGlLpkHnidEhfmtgFGUgnUj7JlA7ZH8apCRvu12zzAo4DQOr9uwYOKAQt2RuqkzbRQr/9+NfyohNOfoRl+42fY9U0s+Ze7n/r7je/BaLWXN9sJJ2RM8G48n1xjYy9EfO5tnYgWcwbVNtgqxm69J2yjhJ2mrqeLQx4SeZtKlMET4tZRDTaD2Hy/3HwkBMei6Tj+wP+l3SU7k8jCQ2Oh1/mKe2bjyMWhvWvsPYEYqLG3eVXAVgkyzlnYT3XZcp4wcD+B5qGE= 14 | - secure: bpmaovS3V/AlLBuzAN+9SFRTIM8BUASlZ1zDLSvm2iCeIucTl4YvggC6/y/iDeyeqZ33ZuWj7xrQ6UOCnTqprbdopScOnWHVN21MKngFAb9BM5huQMBUd4sZmTPFgO5LuFs7E6/+idfzp9MA1XQQDGda0ZAK3D9ggq7dD+9dfcMsBQck/WBEPOu0KI8YJruSA6jvPFV3mtfdO0YA7HCjw0leGHLJfJaKKUxvKy+uvn9/9KqBB0l+b8r74+4N+ybXsywSeRKxsPx2xeOvMHv//qOK1/T02LVUelBpmq60C8xnzvzsJ3dbE/5AJ9PTOW4mmZ5wzSZl/zFvKz2Fj0FCL1vJBYxYMTNm29xr3hlDYgF808alLdVMaDR9W+EztTGc8h3fxPxeldfgxti4Xl90IyKmbVRH+HyVK+VuIbQEKHhpFKViXhgw0WuwLlP8453SRoBN60EQy+4WU7IYgmDMachXPL6tkpHcEr8u/vy2SlmjZwm1rkMjrbN3/zw1WbAkt+vn7gPiKHju1h1uJptmyQmbUvCGY6DOM8fwfKZwf1Yridqe4U57TK2ixp9GSOwYrdM1jRCVUBo0WUv50RF3tAgKk2HLqYWvZ9DbEkfPw/BH2Q5NsNARhi3k6frn0P0LasrvMInVdrIg3Uz0YrStxPrGmM8tEnepEvPRIIbEyjM= 15 | script: npm run ci 16 | after_script: 17 | - npminstall codecov && codecov 18 | -------------------------------------------------------------------------------- /lib/ons.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Message = require('ali-ons').Message; 4 | const Consumer = require('ali-ons').Consumer; 5 | const Producer = require('ali-ons').Producer; 6 | const path = require('path'); 7 | const assert = require('assert'); 8 | 9 | module.exports = class ONS { 10 | constructor(app) { 11 | this.app = app; 12 | this.logger = app.getLogger('onsLogger'); 13 | this.config = app.config.ons; 14 | app.ready(() => { 15 | this.appReady = true; 16 | }); 17 | 18 | this.consumerMap = new Map(); 19 | this.producerMap = new Map(); 20 | this.topic2Producer = new Map(); 21 | this.Message = Message; 22 | } 23 | 24 | async init() { 25 | const { app } = this; 26 | const { sub, pub } = this.config; 27 | const directory = path.join(app.config.baseDir, 'app/ons'); 28 | app.loader.loadToApp(directory, 'ONSSubscribers', { 29 | caseStyle(filepath) { 30 | return filepath.substring(0, filepath.lastIndexOf('.')).split('/'); 31 | }, 32 | }); 33 | for (const options of sub) { 34 | await this.createConsumer(options, app.ONSSubscribers); 35 | } 36 | 37 | for (const options of pub) { 38 | await this.createProducer(options); 39 | } 40 | } 41 | 42 | _errorHandler(err) { 43 | // avoid output error message into stderr before app get ready 44 | this.appReady ? this.logger.error(err) : this.logger.warn(err); 45 | } 46 | 47 | async createConsumer(options, Subscribers) { 48 | const { app, consumerMap, logger, config } = this; 49 | const consumer = new Consumer(Object.assign({ 50 | httpclient: app.httpclient, 51 | logger, 52 | }, config.default, options)); 53 | consumer.on('error', err => this._errorHandler(err)); 54 | const key = `${consumer.consumerGroup}-${consumer.clientId}`; 55 | assert(!consumerMap.has(key), `[egg-ons] duplicate consumer, consumerGroup=${consumer.consumerGroup}, clientId=${consumer.clientId}`); 56 | consumerMap.set(key, consumer); 57 | 58 | await consumer.ready(); 59 | logger.info('[egg-ons] consumer: %s is ready, messageModel: %s', consumer.consumerGroup, consumer.messageModel); 60 | 61 | app.beforeClose(async function() { 62 | await consumer.close(); 63 | logger.info('[egg-ons] consumer: %s is closed, messageModel: %s', consumer.consumerGroup, consumer.messageModel); 64 | }); 65 | 66 | const topics = options.topics || []; 67 | for (const topic of topics) { 68 | const Subscriber = Subscribers[topic]; 69 | if (!Subscriber) { 70 | app.coreLogger.warn('[egg-ons] CANNOT find the subscription logic for topic=%s', topic); 71 | continue; 72 | } 73 | 74 | consumer.subscribe(topic, Subscriber.subExpression || '*', async function(msg) { 75 | const ctx = app.createAnonymousContext(); 76 | const subscriber = new Subscriber(ctx); 77 | await subscriber.subscribe(msg); 78 | }); 79 | } 80 | } 81 | 82 | async createProducer(options) { 83 | const { app, producerMap, logger, config, topic2Producer } = this; 84 | const producer = new Producer(Object.assign({ 85 | httpclient: app.httpclient, 86 | logger, 87 | }, config.default, options)); 88 | producer.on('error', err => this._errorHandler(err)); 89 | assert(!producerMap.has(producer.producerGroup), `[egg-ons] duplicate producer, producerGroup=${producer.producerGroup}`); 90 | producerMap.set(producer.producerGroup, producer); 91 | 92 | const topics = options.topics || []; 93 | for (const topic of topics) { 94 | topic2Producer.set(topic, producer); 95 | } 96 | 97 | await producer.ready(); 98 | logger.info('[egg-ons] producer: %s is ready', producer.producerGroup); 99 | 100 | app.beforeClose(async function() { 101 | await producer.close(); 102 | logger.info('[egg-ons] producer: %s is closed', producer.producerGroup); 103 | }); 104 | } 105 | 106 | async send(msg) { 107 | assert(msg && msg.topic, '[egg-ons] send(msg) msg.topic is required'); 108 | const producer = this.topic2Producer.get(msg.topic); 109 | assert(producer, `[egg-ons] CANNOT find producer for topic=${msg.topic}`); 110 | return await producer.send(msg); 111 | } 112 | }; 113 | 114 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # egg-ons 2 | 3 | [![NPM version][npm-image]][npm-url] 4 | [![build status][travis-image]][travis-url] 5 | [![Test coverage][codecov-image]][codecov-url] 6 | [![David deps][david-image]][david-url] 7 | [![Known Vulnerabilities][snyk-image]][snyk-url] 8 | [![npm download][download-image]][download-url] 9 | 10 | [npm-image]: https://img.shields.io/npm/v/egg-ons.svg?style=flat-square 11 | [npm-url]: https://npmjs.org/package/egg-ons 12 | [travis-image]: https://img.shields.io/travis/eggjs/egg-ons.svg?style=flat-square 13 | [travis-url]: https://travis-ci.org/eggjs/egg-ons 14 | [codecov-image]: https://img.shields.io/codecov/c/github/eggjs/egg-ons.svg?style=flat-square 15 | [codecov-url]: https://codecov.io/github/eggjs/egg-ons?branch=master 16 | [david-image]: https://img.shields.io/david/eggjs/egg-ons.svg?style=flat-square 17 | [david-url]: https://david-dm.org/eggjs/egg-ons 18 | [snyk-image]: https://snyk.io/test/npm/egg-ons/badge.svg?style=flat-square 19 | [snyk-url]: https://snyk.io/test/npm/egg-ons 20 | [download-image]: https://img.shields.io/npm/dm/egg-ons.svg?style=flat-square 21 | [download-url]: https://npmjs.org/package/egg-ons 22 | 23 | aliyun ons plugin for egg 24 | 25 | ## Install 26 | 27 | ```bash 28 | $ npm i egg-ons --save 29 | ``` 30 | 31 | ## Usage 32 | 33 | ```js 34 | // {app_root}/config/plugin.js 35 | exports.ons = { 36 | enable: true, 37 | package: 'egg-ons', 38 | }; 39 | ``` 40 | 41 | ## Configuration 42 | 43 | ```js 44 | // {app_root}/config/config.default.js 45 | exports.ons = { 46 | default: { 47 | accessKey: 'your-accessKey', 48 | secretKey: 'your-secretKey', 49 | // prod:http://onsaddr-internal.aliyun.com:8080/rocketmq/nsaddr4client-internal 50 | // dev: http://onsaddr-internet.aliyun.com/rocketmq/nsaddr4client-internet 51 | // onsAddr: 'http://onsaddr-internet.aliyun.com/rocketmq/nsaddr4client-internet', 52 | }, 53 | sub: [{ 54 | consumerGroup: 'your-consumer-group', 55 | topics: [ 56 | 'your-topic', 57 | ], 58 | }], 59 | pub: [{ 60 | producerGroup: 'your-producer-group', 61 | topics: [ 62 | 'your-topic', 63 | ], 64 | }], 65 | }; 66 | ``` 67 | 68 | see [config/config.default.js](config/config.default.js) for more detail. 69 | 70 | ## Example 71 | 72 | ### Consumer 73 | 74 | put your subscription codes under the folder `{app_root}/app/ons` and named as the topic name e.g `TP_NAME.js` 75 | 76 | ``` 77 | . 78 | ├── app 79 | │   ├── ons 80 | │   │   └── TP_NAME.js 81 | │   ├── public 82 | │   └── router.js 83 | ├── config 84 | │   └── config.default.js 85 | ├── package.json 86 | ``` 87 | 88 | you should implment a subscriber as blow 89 | 90 | ```js 91 | // TP_NAME.js 92 | 'use strict'; 93 | 94 | class TestSubscriber { 95 | constructor(ctx) { 96 | this.ctx = ctx; 97 | } 98 | 99 | * subscribe(msg) { 100 | yield this.ctx.service.messageService.process(msg); 101 | } 102 | 103 | static get subExpression() { 104 | return 'TagA'; 105 | } 106 | } 107 | 108 | module.exports = TestSubscriber; 109 | ``` 110 | 111 | see [RPC](https://github.com/eggjs/egg/issues/1468) for more detail. 112 | 113 | ### Producer 114 | 115 | using `app.ons / ctx.ons` to create & send messages 116 | 117 | ```js 118 | const Message = ctx.ons.Message; 119 | const msg = new Message('TP_NAME', // topic 120 | 'TagA', // tag 121 | 'Hello ONS !!!' // body 122 | ); 123 | const sendResult = yield ctx.ons.send(msg); 124 | ``` 125 | 126 | ## Questions & Suggestions 127 | 128 | Please open an issue [here](https://github.com/eggjs/egg/issues). 129 | 130 | 131 | ## Secure Keys 132 | 133 | ping @fengmk2 to give you the access key! 134 | 135 | - [ons secure keys](https://sharelock.io/1/AbXLnDfKcK5syo0rNnmIfYFagr-YZ9FdYjsV84rrQ0E.Q7hdg2/gPqxUCvlzQ2Kc6TEodWs3pOngxYpzKOAw-oCAgQZ4ZFZ8UF5HD/78NoP0krmaT7I4Ny_h7t4xhiAY2aLzwYlRwlHEmeEPeD7_6ZOI/J_QxBEFyEtAej_CMTL-5gJJS-dOA3lkyy8n3b7--0rJrSt2Vru/KY4Sdu6rwnsU9VZwAr-G2R_P8XiR4pHoHXuppYYbbcuu1PCQNK/rM8ajQMGMZg_PUqQWxaI6_zq0rr8gnmydeebKY0FBkkRRcDbat/v5eDQH6VrBSAqfMcoMEGWBMBeyFId3ClpO5LI0Bh1QFlvD9VbY/1LYQf3B475RvP5mpOgvdvx4xaCMdzSEXjbfZ6eQbDyT7QdF75S/hqr7u5Mclln66T718GxKCZ7XselJFPzxWyLv9Wos8gFIuNBl59/XhsrYXMf7In_W_qZQ84EvuB38CD5GubHsboVkuL0p3eOM4Vj3u/qGUQNUXa5CbGwHg1tKzP3E5eJLCiNX5DCTH2np-YDQJ5BOic27/Gy95jKwNTqowGT-n8vOpzn3b2ZIPDBZW2xaSI5NCYrbAMc9lbm/R-Vg751_pFx51fI1C4VoMBC44qgb5auUwtnEbl-DvKDuI2qb6b/-grhrQBp5wMZPBZMi5YfiOGQJxSMhxfGLjTwOJhCnojlcjls1Z/DMEaYzol0xDRdJYG5VwlaKUyIU_iAMfhFU7XZI_T3cqXdI3Pxg/XaCm0n2iJIJMjh0FE.G5xap1BPeUo3wZzXanJa8A#) 136 | 137 | ## License 138 | 139 | [MIT](LICENSE) 140 | --------------------------------------------------------------------------------