├── .autod.conf.js
├── .eslintignore
├── .eslintrc
├── .github
├── PULL_REQUEST_TEMPLATE.md
└── workflows
│ └── nodejs.yml
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.EN.md
├── README.md
├── agent.js
├── app.js
├── appveyor.yml
├── bootstrap.js
├── config
└── config.default.js
├── lib
├── DataBus.js
└── mqttClient.js
├── package-lock.json
├── package.json
└── test
├── fixtures
└── apps
│ └── mqtt-plugin-test
│ ├── app
│ ├── controller
│ │ └── home.js
│ └── router.js
│ ├── config
│ └── config.default.js
│ └── package.json
└── mqtt-plugin.test.js
/.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-ci',
14 | 'egg-bin',
15 | 'autod',
16 | 'autod-egg',
17 | 'eslint',
18 | 'eslint-config-egg',
19 | ],
20 | exclude: [
21 | './test/fixtures',
22 | './docs',
23 | './coverage',
24 | ],
25 | };
26 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | coverage
2 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "eslint-config-egg"
3 | }
4 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
10 |
11 | ##### Checklist
12 |
13 |
14 | - [ ] `npm test` passes
15 | - [ ] tests and/or benchmarks are included
16 | - [ ] documentation is changed or added
17 | - [ ] commit message follows commit guidelines
18 |
19 | ##### Affected core subsystem(s)
20 |
21 |
22 |
23 | ##### Description of change
24 |
25 |
--------------------------------------------------------------------------------
/.github/workflows/nodejs.yml:
--------------------------------------------------------------------------------
1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
3 |
4 | name: Node.js CI
5 |
6 | on:
7 | push:
8 | branches: [ master ]
9 | pull_request:
10 | branches: [ master ]
11 |
12 | jobs:
13 | build:
14 |
15 | runs-on: ${{ matrix.os }}
16 |
17 | strategy:
18 | matrix:
19 | node-version: [8.x, 10.x]
20 | os: [ubuntu-latest, windows-latest, macos-latest]
21 |
22 | steps:
23 | - uses: actions/checkout@v2
24 | - name: Use Node.js ${{ matrix.node-version }}
25 | uses: actions/setup-node@v1
26 | with:
27 | node-version: ${{ matrix.node-version }}
28 | - run: npm i -g npminstall && npminstall
29 | - run: npm run ci
30 | env:
31 | CI: true
32 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | logs/
2 | npm-debug.log
3 | node_modules/
4 | coverage/
5 | .idea/
6 | run/
7 | .DS_Store
8 | *.swp
9 |
10 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 |
2 | language: node_js
3 | node_js:
4 | - '8'
5 | - '10'
6 | before_install:
7 | - npm i npminstall -g
8 | install:
9 | - npminstall
10 | script:
11 | - npm run ci
12 | after_script:
13 | - npminstall codecov && codecov
14 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2019-present 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 |
--------------------------------------------------------------------------------
/README.EN.md:
--------------------------------------------------------------------------------
1 | # egg-mqtt-plugin
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-mqtt-plugin.svg?style=flat-square
11 | [npm-url]: https://npmjs.org/package/egg-mqtt-plugin
12 | [travis-image]: https://img.shields.io/travis/eggjs/egg-mqtt-plugin.svg?style=flat-square
13 | [travis-url]: https://travis-ci.org/eggjs/egg-mqtt-plugin
14 | [codecov-image]: https://img.shields.io/codecov/c/github/eggjs/egg-mqtt-plugin.svg?style=flat-square
15 | [codecov-url]: https://codecov.io/github/eggjs/egg-mqtt-plugin?branch=master
16 | [david-image]: https://img.shields.io/david/eggjs/egg-mqtt-plugin.svg?style=flat-square
17 | [david-url]: https://david-dm.org/eggjs/egg-mqtt-plugin
18 | [snyk-image]: https://snyk.io/test/npm/egg-mqtt-plugin/badge.svg?style=flat-square
19 | [snyk-url]: https://snyk.io/test/npm/egg-mqtt-plugin
20 | [download-image]: https://img.shields.io/npm/dm/egg-mqtt-plugin.svg?style=flat-square
21 | [download-url]: https://npmjs.org/package/egg-mqtt-plugin
22 |
23 |
26 |
27 | 更详细的使用请阅读[中文文档](README.md)
28 |
29 | ## Install
30 |
31 | ```bash
32 | $ npm i egg-mqtt-plugin --save
33 | ```
34 |
35 | ## Usage
36 |
37 | ```js
38 | // {app_root}/config/plugin.js
39 | exports.mqtt = {
40 | enable: true,
41 | package: 'egg-mqtt-plugin',
42 | };
43 | ```
44 |
45 | ## Configuration
46 |
47 | ```js
48 | // {app_root}/config/config.default.js
49 | exports.mqtt = {
50 | host: 'mqtt://xxx.xxx.x.x',
51 | port: 1883,
52 | username: 'username',
53 | password: 'password',
54 | clientId: 'client_id',
55 | options: {
56 | keeplive: 60,
57 | protocolId: 'MQTT',
58 | protocol: 'MQTT',
59 | protocolVersion: 4,
60 | clean: true,
61 | rejectUnauthorized: false,
62 | reconnectPeriod: 1000,
63 | connectTimeout: 30 * 1000,
64 | },
65 | topics: {
66 | 'topic-topic-topic': { qos: 0 },
67 | },
68 | };
69 | ```
70 |
71 | see [config/config.default.js](config/config.default.js) for more detail.
72 |
73 | ## Example
74 |
75 |
76 |
77 | ## Questions & Suggestions
78 |
79 | Please open an issue [here](https://github.com/eggjs/egg/issues).
80 |
81 | ## License
82 |
83 | [MIT](LICENSE)
84 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # egg-mqtt-plugin
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-mqtt-plugin.svg?style=flat-square
11 | [npm-url]: https://npmjs.org/package/egg-mqtt-plugin
12 | [travis-image]: https://img.shields.io/travis/eggjs/egg-mqtt-plugin.svg?style=flat-square
13 | [travis-url]: https://travis-ci.org/eggjs/egg-mqtt-plugin
14 | [codecov-image]: https://img.shields.io/codecov/c/github/eggjs/egg-mqtt-plugin.svg?style=flat-square
15 | [codecov-url]: https://codecov.io/github/eggjs/egg-mqtt-plugin?branch=master
16 | [david-image]: https://img.shields.io/david/eggjs/egg-mqtt-plugin.svg?style=flat-square
17 | [david-url]: https://david-dm.org/eggjs/egg-mqtt-plugin
18 | [snyk-image]: https://snyk.io/test/npm/egg-mqtt-plugin/badge.svg?style=flat-square
19 | [snyk-url]: https://snyk.io/test/npm/egg-mqtt-plugin
20 | [download-image]: https://img.shields.io/npm/dm/egg-mqtt-plugin.svg?style=flat-square
21 | [download-url]: https://npmjs.org/package/egg-mqtt-plugin
22 |
23 |
24 | ## 依赖说明
25 |
26 | ### 依赖的 egg 版本
27 |
28 | egg-mqtt-plugin 版本 | egg 2.x
29 | --- | ---
30 | 1.x | 😁
31 | 0.x | ❌
32 |
33 |
34 | ## 开启插件
35 |
36 | ```js
37 | // config/plugin.js
38 | exports.mqtt = {
39 | enable: true,
40 | package: 'egg-mqtt-plugin',
41 | };
42 |
43 | // config/default.js
44 | config.mqtt = {
45 | host: 'mqtt://xxx.xxx.x.x',
46 | port: 1883,
47 | username: 'username',
48 | password: 'password',
49 | clientId: 'client_id',
50 | topics: {
51 | 'topic-topic-topic': { qos: 0 },
52 | },
53 | // options:{},
54 | // DataBus: true,
55 | }
56 | ```
57 |
58 |
59 | [详细配置](#config)
60 | [插件介绍](#info)
61 | [插件的使用](#use)
62 | [插件的使用.建立链接](#use-link)
63 | [插件的使用.发布](#use-publish)
64 | [插件的使用.订阅](#use-subscribe)
65 | [插件的使用.取消订阅](#use-unsubscribe)
66 | [插件的使用.监听订阅消息](#use-message)
67 | [Mqtt类](#mqtt)
68 | [示例](#example)
69 | [issue](#issue)
70 | [license](#license)
71 |
72 | ## 详细配置
73 |
74 | 请到 [config/config.default.js](config/config.default.js) 查看详细配置项说明。
75 |
76 | |配置项|类型|必填|默认值|描述|
77 | |:- | :-| :-| :-| :-|
78 | |host|string|√|
79 | |port|number|√|
80 | |username|string|√|
81 | |password|string|√|
82 | |clientId|string|√|
83 | |DataBus|boolean|×|true|是否需要统一的数据输出|
84 | |topics|object|×| |需要订阅的topic,参照[mqtt.subsceibe()](https://www.npmjs.com/package/mqtt#connect)
85 | |options|object|×||keeplive,connectTimeout等配置,参照[mqtt.connect()](https://www.npmjs.com/package/mqtt#connect)
86 |
87 | > `topics`用来创建订阅,会传入`mqtt.subsceibe()`方法,`options`会传入`mqtt.connect()`方法,更加详细的配置参数请参考[文档](https://www.npmjs.com/package/mqtt#connect)
88 |
89 |
90 |
91 |
92 | ## 插件介绍
93 |
94 | 使用过一些mqtt插件,发现并不能满足业务开发的需求。有的插件在生产环境和多进程环境下无法使用,为了能够在多进程下使用mqtt客户端并且能够有一个比较舒服的使用方式。
95 |
96 | 为了在多进程下使用mqtt,根据egg官方文档的建议,长连接的维护一般放在agent进程中。所以`egg-mqtt-plugin`插件基于`mqtt.js`在agent进程中维护长连接,并且由agent进程来完成发布和订阅事件,通过进程间的通讯由agent进程将订阅的消息内容随机的发送到一个work进程,work进程将需要发布的消息发送给agent进程。agent进程不参与具体的业务逻辑,只维护长连接和监听发布订阅事件。
97 |
98 | mqtt实例运行在agent进程上,所以在work进程上无法对mqtt实例进行操作,`egg-mqtt-plugin`提供了统一数据出口(需要开启`DataBus`)和Mqtt类。
99 |
100 |
101 | ## 插件的使用
102 |
103 | > 插件得到publish、subscribe、unsubscribe等方法建议在agent.js或者在一个http请求的生命周期(controller、service、middleware、route)中使用。如果在非agent进程和一个http请求的生命周期中使用,多进程
104 | 环境下会导致每个worker进程都调用一次,从而导致了重复调用。这个问题会在后续版本中优化,可以在任何地方调用并且不会导致重复调用的情况。
105 |
106 | 获取订阅消息的message()方法不会多次触发,可以在任何地方使用。
107 |
108 | ### 建立链接
109 |
110 | 开启插件并填写好相关配置,在框架启动的时候时候会自动进行mqtt链接。
111 |
112 | ### 发布
113 |
114 | > 因为多进程的原因最好在一个http请求的生命周期(controller、service、middleware、route)中或者agent中调用,如果其他地方使用会出现重复发布的情况。
115 |
116 | 消息的发布需要使用Mqtt实例,调用Mqtt实例的`publish()`方法即可。
117 |
118 | Mqtt类由 'egg-mqtt-start/bootstrap.js'文件暴露出来,实例化Mqtt的时候需要使用`app`作为参数。
119 |
120 | publish()方法需要传入一个对象参数,其中包括topic、message、options等信息,更详细的参数可以参考[mqtt.publish()文档](https://www.npmjs.com/package/mqtt#connect)。
121 |
122 | ```js
123 | 'use strict';
124 |
125 | const Mqtt = require('egg-mqtt-start/bootstrap');
126 |
127 | const mqtt = new Mqtt(this.app);
128 |
129 | const topic = 'xxx-xxx-xxx';
130 | const message = '这是我要发布的信息';
131 | const options = { qos: 0 };
132 |
133 | mqtt.publish(topic, message, options, err => {
134 | console.log('发布完成');
135 | });
136 |
137 | ```
138 |
139 | ### 订阅
140 |
141 | > 因为多进程的原因最好在一个http请求的生命周期(controller、service、middleware、route)中或者agent中调用,如果其他地方使用会出现重复订阅的情况。
142 |
143 | 订阅有两种方式,一种是通过config.default.js配置文件中`topics`参数进行配置,另一种是手动调用`subscribe()`方法。更详细的参数可以参考[mqtt.subscribe()文档](https://www.npmjs.com/package/mqtt#connect)。
144 |
145 |
146 | ```js
147 | 'use strict';
148 |
149 | const Mqtt = require('egg-mqtt-start/bootstrap');
150 |
151 | const mqtt = new Mqtt(this.app);
152 |
153 | const topic = 'xxx-xxx-xxx';
154 | const options = { qos: 0 };
155 |
156 | mqtt.subscribe(topic, options, (err, granted) => {
157 | console.log(granted.topic);
158 | });
159 |
160 | ```
161 |
162 |
163 | ### 取消订阅
164 |
165 | 取消订阅直接调用`Mqtt`类的`unsubscribe()`方法就可以了。
166 |
167 | ```js
168 | const Mqtt = require('egg-mqtt-start/bootstrap');
169 |
170 | const mqtt = new Mqtt(this.app);
171 |
172 | const topic = 'xxx-xxx-xxx';
173 | const options = { qos: 0 };
174 |
175 | mqtt.unsubscribe(topic, options, err => {
176 | console.log('取消订阅');
177 | });;
178 |
179 | ```
180 |
181 | ### 监听订阅消息
182 |
183 | 获取订阅的消息有两种方式,一种是开启`config.default.js`配置文件中`DataBus:true`选项(默认开启),订阅的所有消息和`app`都会统一的被发送到`/app/mqtt/DataBus.js`文件中,
184 | 开启此功能后`DataBus.js`文件会在项目启动后自动创建,也可以自己手动创建,格式如下例子:
185 |
186 | ```js
187 | 'use strict';
188 |
189 | // /app/mqtt/DataBus.js
190 |
191 | module.exports = async (app, data) => {
192 | console.log('收到数据');
193 | console.log(data.topic);
194 | };
195 |
196 | ```
197 |
198 | 另一种获取订阅的消息的方式是调用`message()`方法,需要传入一个回调函数,插件会将`topic`和相应的消息信息传入回调函数的参数中。
199 |
200 | ```js
201 |
202 | const Mqtt = require('egg-mqtt-plugin/bootstrap');
203 |
204 | const mqtt = new Mqtt(this.app);
205 |
206 | mqtt.message((topic, message) => {
207 | console.log(topic);
208 | })
209 |
210 | ```
211 |
212 |
213 | ## Mqtt类
214 |
215 | `egg-mqtt-plugin`是基于`mqtt.js`进行封装并且是在`agent`进程上进行实例化的,所以在我们的业务代码中,无法使用`mqtt.js`实例提供的相应的方法,为了保证正常的时候用,
216 | `egg-mqtt-plugin`通过`bootstrap.js`文件导出一个`Mqtt`类,在这个类中通过进程间通讯间接的实现了`mqtt.js`实例上的部分方法。目前的版本暂时没有显示部分方法的回调函数功能。
217 |
218 | ```js
219 |
220 | const Mqtt = require('egg-mqtt-plugin/bootstrap');
221 |
222 | // 获取mqtt实例的时候需要传入当前环境下的app对象
223 | cosnt mqtt = new Mqtt(this.app);
224 |
225 | // 发布
226 | mqtt.publish('topic', '我是发布的消息体', { qos: 0 }, callback);
227 |
228 | // 订阅
229 | mqtt.subscribe('topic', { qos: 0 }, callback);
230 |
231 | // 取消订阅
232 | mqtt.unsubscribe('topic', { qos: 0 }, callback);
233 |
234 | // 监听消息
235 | mqtt.message((topic, message) => {
236 | console.log(topic);
237 | });
238 |
239 |
240 | ```
241 |
242 |
243 | ## 示例
244 |
245 |
246 | ## 提问交流
247 |
248 | 请到 [egg issues](https://github.com/lp-liupan/egg-mqtt-plugin/issues) 异步交流。
249 |
250 | ## License
251 |
252 | [MIT](LICENSE)
253 |
--------------------------------------------------------------------------------
/agent.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const fs = require('fs');
4 | const mqttClient = require('./lib/mqttClient');
5 |
6 | class AppBootHook {
7 |
8 | constructor(agent) {
9 | this.agent = agent;
10 | }
11 |
12 |
13 | async didLoad() {
14 | // 建立mqtt链接
15 | this.agent.mqtt = mqttClient(this.agent.config.mqtt, this.agent);
16 | }
17 |
18 |
19 | async serverDidReady() {
20 |
21 | // 通过配置直接订阅
22 | if (this.agent.config.mqtt.topics) {
23 | await this.agent.mqtt.subscribe({ ...this.agent.config.mqtt.topics }, (err, granted) => {
24 | if (err) {
25 | this.agent.coreLogger.error('[egg-mqtt-plugin] subscribe err : %s', err);
26 | return;
27 | }
28 | granted.forEach(element => {
29 | this.agent.logger.info('[egg-mqtt-plugin] subscribe topic: %s success!', element.topic);
30 | });
31 | });
32 | }
33 |
34 |
35 | // 检查是否需要统一的数据出口,需要存在指定的文件,不存在就创建
36 | if (this.agent.config.mqtt.DataBus && !fs.existsSync('./app/mqtt/DataBus.js')) {
37 | if (!fs.existsSync('./app/mqtt')) {
38 | fs.mkdirSync('./app/mqtt');
39 | }
40 | const DataBus = fs.readFileSync('./node_modules/egg-mqtt-plugin/lib/DataBus.js', 'utf8');
41 | fs.writeFileSync('./app/mqtt/DataBus.js', DataBus);
42 | }
43 |
44 |
45 | this.agent.mqtt.on('message', (topic, message) => {
46 | // 向worker进程发送数据
47 | this.agent.messenger.sendRandom('mqtt-subscribe', {
48 | topic,
49 | message: message.toString(),
50 | });
51 | });
52 |
53 | // 注册mqtt的publish事件
54 | this.agent.messenger.on('mqtt-publish', data => {
55 | this.agent.mqtt.publish(data.topic, data.message, data.options, err => {
56 | this.agent.coreLogger.error('[egg-mqtt-plugin] publish error : %s', err);
57 | this.agent.messenger.sendTo(data.pid, data.action, err);
58 | });
59 | });
60 |
61 | // 注册mqtt的subscribe事件
62 | this.agent.messenger.on('mqtt-subscribe', data => {
63 | this.agent.mqtt.subscribe(data.topic, data.options, (err, granted) => {
64 | if (err) {
65 | this.agent.coreLogger.error('[egg-mqtt-plugin] subscribe error : %s', err);
66 | return;
67 | }
68 | this.agent.coreLogger.info('[egg-mqtt-plugin] subscribe succese : %s', granted);
69 | this.agent.messenger.sendTo(data.pid, data.action, { err, granted });
70 | });
71 | });
72 |
73 | // 注册mqtt的unsubscribe事件
74 | this.agent.messenger.on('mqtt-unsubscribe', data => {
75 | this.agent.mqtt.unsubscribe(data.topic, data.options, err => {
76 | this.agent.coreLogger.error('[egg-mqtt-plugin] unsubscribe error : %s', err);
77 | this.agent.messenger.sendTo(data.pid, data.action, err);
78 | });
79 | });
80 | }
81 |
82 |
83 | }
84 |
85 | module.exports = AppBootHook;
86 |
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 |
5 | class AppBootHook {
6 | constructor(app) {
7 | this.app = app;
8 |
9 | }
10 |
11 | async serverDidReady() {
12 |
13 | if (this.app.config.mqtt.DataBus) {
14 | const src = path.join(path.resolve('./'), '/app/mqtt/DataBus.js');
15 | this.app.messenger.on('mqtt-subscribe', data => {
16 | this.app.coreLogger.info('[egg-mqtt-plugin] send to worker DataBus success!');
17 | (require(src))(this.app, data);
18 | });
19 | }
20 |
21 | }
22 | }
23 |
24 | module.exports = AppBootHook;
25 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | environment:
2 | matrix:
3 | - nodejs_version: '8'
4 | - nodejs_version: '10'
5 |
6 | install:
7 | - ps: Install-Product node $env:nodejs_version
8 | - npm i npminstall && node_modules\.bin\npminstall
9 |
10 | test_script:
11 | - node --version
12 | - npm --version
13 | - npm run test
14 |
15 | build: off
16 |
--------------------------------------------------------------------------------
/bootstrap.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { v4 } = require('uuid');
4 |
5 | class Mqtt {
6 |
7 | constructor(app) {
8 | this.app = app;
9 | this.pid = process.pid;
10 | }
11 |
12 |
13 | publish(topic, message, options, callback) {
14 | const action = `mqtt-publish:${v4()}`;
15 | const data = { topic, message, options, action, pid: this.pid };
16 | this.action('mqtt-publish', data, callback, action);
17 | }
18 |
19 | subscribe(topic, options, callback) {
20 | const action = `mqtt-subscribe:${v4()}`;
21 | const data = { topic, options, action, pid: this.pid };
22 | this.action('mqtt-subscribe', data, callback, action);
23 | }
24 |
25 | unsubscribe(topic, options, callback) {
26 | const action = `mqtt-unsubscribe:${v4()}`;
27 | const data = { topic, options, action, pid: this.pid };
28 | this.action('mqtt-unsubscribe', data, callback, action);
29 | }
30 |
31 | message(callback) {
32 | this.app.messenger.on('mqtt-subscribe', data => {
33 | callback(data.topic, data.message);
34 | });
35 | }
36 |
37 |
38 | /**
39 | * 进程间通讯
40 | * @param {string} name
41 | * @param {*} data
42 | * @param {function} callback
43 | * @param {string} action
44 | */
45 | action(name, data, callback, action) {
46 |
47 | this.app.messenger.sendToAgent(name, data);
48 |
49 | // 提供回调函数
50 | this.app.messenger.once(action, data => {
51 | if (data && data.granted) {
52 | callback(data.err, data.granted);
53 | } else {
54 | callback(data);
55 | }
56 | });
57 | }
58 |
59 | }
60 |
61 | module.exports = Mqtt;
62 |
--------------------------------------------------------------------------------
/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * egg-mqtt-plugin default config
5 | * @member Config#mqtt
6 | * @property {String} SOME_KEY - some description
7 | */
8 | exports.mqtt = {
9 | host: 'mqtt://xxx.xxx.x.x',
10 | port: 1883,
11 | username: 'username',
12 | password: 'password',
13 | clientId: 'client_id',
14 | options: {
15 | keeplive: 60,
16 | protocolId: 'MQTT',
17 | protocol: 'MQTT',
18 | protocolVersion: 4,
19 | clean: true,
20 | rejectUnauthorized: false,
21 | reconnectPeriod: 1000,
22 | connectTimeout: 30 * 1000,
23 | },
24 |
25 | DataBus: true,
26 |
27 | // topics: {
28 | // 'topic-topic-topic': { qos: 0 },
29 | // },
30 | };
31 |
--------------------------------------------------------------------------------
/lib/DataBus.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = async (app, data) => {
4 | console.log('收到数据');
5 | console.log(data.topic);
6 | };
7 |
--------------------------------------------------------------------------------
/lib/mqttClient.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const mqtt = require('mqtt');
4 |
5 | module.exports = config => {
6 | const mqttClient = mqtt.connect(config.host, {
7 | host: config.host,
8 | port: config.port,
9 | username: config.username,
10 | password: config.password,
11 | clientId: config.clientId,
12 | ...config.options,
13 | });
14 | return mqttClient;
15 | };
16 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "egg-mqtt-plugin",
3 | "version": "1.1.1",
4 | "description": "mqtt-client for egg. 使用mqtt包封装的egg客户端插件",
5 | "private": false,
6 | "eggPlugin": {
7 | "name": "mqtt"
8 | },
9 | "keywords": [
10 | "mqtt",
11 | "egg-mqtt",
12 | "egg-mqtt-plugin",
13 | "egg",
14 | "eggPlugin",
15 | "egg-plugin"
16 | ],
17 | "dependencies": {
18 | "mqtt": "^4.1.0",
19 | "uuid": "^8.3.0"
20 | },
21 | "devDependencies": {
22 | "autod": "^3.0.1",
23 | "autod-egg": "^1.1.0",
24 | "egg": "^2.16.0",
25 | "egg-bin": "^4.11.0",
26 | "egg-ci": "^1.11.0",
27 | "egg-mock": "^3.21.0",
28 | "eslint": "^5.13.0",
29 | "eslint-config-egg": "^7.1.0"
30 | },
31 | "engines": {
32 | "node": ">=8.0.0"
33 | },
34 | "scripts": {
35 | "test": "npm run lint -- --fix && egg-bin pkgfiles && npm run test-local",
36 | "test-local": "egg-bin test",
37 | "cov": "egg-bin cov",
38 | "lint": "eslint .",
39 | "ci": "egg-bin pkgfiles --check && npm run lint && npm run cov",
40 | "pkgfiles": "egg-bin pkgfiles",
41 | "autod": "autod"
42 | },
43 | "files": [
44 | "config",
45 | "agent.js",
46 | "lib",
47 | "app.js",
48 | "bootstrap.js"
49 | ],
50 | "ci": {
51 | "version": "8, 10"
52 | },
53 | "repository": {
54 | "type": "git",
55 | "url": "git+https://github.com/lp-liupan/egg-mqtt-plugin.git"
56 | },
57 | "bugs": {
58 | "url": "https://github.com/lp-liupan/egg-mqtt-plugin/issues"
59 | },
60 | "homepage": "https://github.com/lp-liupan/egg-mqtt-plugin",
61 | "author": "liupan",
62 | "license": "MIT"
63 | }
--------------------------------------------------------------------------------
/test/fixtures/apps/mqtt-plugin-test/app/controller/home.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Controller = require('egg').Controller;
4 |
5 | class HomeController extends Controller {
6 | async index() {
7 | this.ctx.body = 'hi, ' + this.app.plugins.mqtt.name;
8 | }
9 | }
10 |
11 | module.exports = HomeController;
12 |
--------------------------------------------------------------------------------
/test/fixtures/apps/mqtt-plugin-test/app/router.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = app => {
4 | const { router, controller } = app;
5 |
6 | router.get('/', controller.home.index);
7 | };
8 |
--------------------------------------------------------------------------------
/test/fixtures/apps/mqtt-plugin-test/config/config.default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.keys = '123456';
4 |
--------------------------------------------------------------------------------
/test/fixtures/apps/mqtt-plugin-test/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mqtt-plugin-test",
3 | "version": "0.0.1"
4 | }
--------------------------------------------------------------------------------
/test/mqtt-plugin.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const mock = require('egg-mock');
4 |
5 | describe('test/mqtt-plugin.test.js', () => {
6 | let app;
7 | before(() => {
8 | app = mock.app({
9 | baseDir: 'apps/mqtt-plugin-test',
10 | });
11 | return app.ready();
12 | });
13 |
14 | after(() => app.close());
15 | afterEach(mock.restore);
16 |
17 | it('should GET /', () => {
18 | return app.httpRequest()
19 | .get('/')
20 | .expect('hi, mqtt')
21 | .expect(200);
22 | });
23 | });
24 |
--------------------------------------------------------------------------------