├── .gitignore
├── .npmignore
├── .travis.yml
├── LICENSE-EDL
├── LICENSE-EPL
├── README.md
├── architecture.ai
├── architecture.png
├── artwork
├── logo-banner-black.ai
├── logo-banner-black.png
├── logo-banner-black.svg
├── logo-banner-transparent.png
├── logo-banner-white.ai
├── logo-banner-white.jpg
├── logo-banner-white.png
├── logo-square-black.ai
├── logo-square-black.png
└── logo-square-black.svg
├── bin
└── ponte
├── edl-v10.html
├── epl-v10.html
├── examples
└── basic.js
├── lib
├── cli.js
├── coap.js
├── http.js
├── persistence.js
├── ponte.js
└── servers.js
├── notice.html
├── package.json
├── public
└── mqttws31.js
└── test
├── cli.js
├── coap.js
├── common.js
├── http_spec.js
├── libraries_inside_hidden_dir.js
├── mocha.opts
├── mqtt.js
├── mqtt_over_websocket.js
├── sample_config.js
├── sample_config_mongodb.js
├── sample_config_mqtt_redis.js
└── sample_config_redis.js
/.gitignore:
--------------------------------------------------------------------------------
1 | lib-cov
2 | *.seed
3 | *.log
4 | *.csv
5 | *.dat
6 | *.out
7 | *.pid
8 | *.gz
9 |
10 | pids
11 | logs
12 | results
13 |
14 | npm-debug.log
15 | node_modules
16 | docs
17 | mosquitto.db
18 | *.pdf
19 | db/
20 |
21 | .project
22 | .settings
23 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | *~
2 | *db
3 | *rdb
4 | *conf
5 | benchmarks
6 | demo
7 | artwork
8 | architecture.ai
9 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - 0.12
4 | - 4
5 | - 5.5
6 | - 5.6
7 | services:
8 | - rabbitmq
9 | - redis-server
10 | - mongodb
11 |
--------------------------------------------------------------------------------
/LICENSE-EDL:
--------------------------------------------------------------------------------
1 | Eclipse Distribution License - v 1.0
2 | Copyright (c) 2007, Eclipse Foundation, Inc. and its licensors.
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are
7 | met:
8 |
9 | * Redistributions of source code must retain the above copyright notice,
10 | this list of conditions and the following disclaimer.
11 | * Redistributions in binary form must reproduce the above copyright
12 | notice, this list of conditions and the following disclaimer in the
13 | documentation and/or other materials provided with the distribution.
14 |
15 | Neither the name of the Eclipse Foundation, Inc. nor the names of its
16 | contributors may be used to endorse or promote products derived from this
17 | software without specific prior written permission. THIS SOFTWARE IS
18 | PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
19 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 | POSSIBILITY OF SUCH DAMAGE.
29 |
--------------------------------------------------------------------------------
/LICENSE-EPL:
--------------------------------------------------------------------------------
1 | Eclipse Public License - v 1.0
2 |
3 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC
4 | LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM
5 | CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
6 |
7 | 1. DEFINITIONS
8 |
9 | "Contribution" means:
10 |
11 | a) in the case of the initial Contributor, the initial code and documentation
12 | distributed under this Agreement, and
13 | b) in the case of each subsequent Contributor:
14 | i) changes to the Program, and
15 | ii) additions to the Program;
16 |
17 | where such changes and/or additions to the Program originate from and are
18 | distributed by that particular Contributor. A Contribution 'originates'
19 | from a Contributor if it was added to the Program by such Contributor
20 | itself or anyone acting on such Contributor's behalf. Contributions do not
21 | include additions to the Program which: (i) are separate modules of
22 | software distributed in conjunction with the Program under their own
23 | license agreement, and (ii) are not derivative works of the Program.
24 |
25 | "Contributor" means any person or entity that distributes the Program.
26 |
27 | "Licensed Patents" mean patent claims licensable by a Contributor which are
28 | necessarily infringed by the use or sale of its Contribution alone or when
29 | combined with the Program.
30 |
31 | "Program" means the Contributions distributed in accordance with this
32 | Agreement.
33 |
34 | "Recipient" means anyone who receives the Program under this Agreement,
35 | including all Contributors.
36 |
37 | 2. GRANT OF RIGHTS
38 | a) Subject to the terms of this Agreement, each Contributor hereby grants
39 | Recipient a non-exclusive, worldwide, royalty-free copyright license to
40 | reproduce, prepare derivative works of, publicly display, publicly
41 | perform, distribute and sublicense the Contribution of such Contributor,
42 | if any, and such derivative works, in source code and object code form.
43 | b) Subject to the terms of this Agreement, each Contributor hereby grants
44 | Recipient a non-exclusive, worldwide, royalty-free patent license under
45 | Licensed Patents to make, use, sell, offer to sell, import and otherwise
46 | transfer the Contribution of such Contributor, if any, in source code and
47 | object code form. This patent license shall apply to the combination of
48 | the Contribution and the Program if, at the time the Contribution is
49 | added by the Contributor, such addition of the Contribution causes such
50 | combination to be covered by the Licensed Patents. The patent license
51 | shall not apply to any other combinations which include the Contribution.
52 | No hardware per se is licensed hereunder.
53 | c) Recipient understands that although each Contributor grants the licenses
54 | to its Contributions set forth herein, no assurances are provided by any
55 | Contributor that the Program does not infringe the patent or other
56 | intellectual property rights of any other entity. Each Contributor
57 | disclaims any liability to Recipient for claims brought by any other
58 | entity based on infringement of intellectual property rights or
59 | otherwise. As a condition to exercising the rights and licenses granted
60 | hereunder, each Recipient hereby assumes sole responsibility to secure
61 | any other intellectual property rights needed, if any. For example, if a
62 | third party patent license is required to allow Recipient to distribute
63 | the Program, it is Recipient's responsibility to acquire that license
64 | before distributing the Program.
65 | d) Each Contributor represents that to its knowledge it has sufficient
66 | copyright rights in its Contribution, if any, to grant the copyright
67 | license set forth in this Agreement.
68 |
69 | 3. REQUIREMENTS
70 |
71 | A Contributor may choose to distribute the Program in object code form under
72 | its own license agreement, provided that:
73 |
74 | a) it complies with the terms and conditions of this Agreement; and
75 | b) its license agreement:
76 | i) effectively disclaims on behalf of all Contributors all warranties
77 | and conditions, express and implied, including warranties or
78 | conditions of title and non-infringement, and implied warranties or
79 | conditions of merchantability and fitness for a particular purpose;
80 | ii) effectively excludes on behalf of all Contributors all liability for
81 | damages, including direct, indirect, special, incidental and
82 | consequential damages, such as lost profits;
83 | iii) states that any provisions which differ from this Agreement are
84 | offered by that Contributor alone and not by any other party; and
85 | iv) states that source code for the Program is available from such
86 | Contributor, and informs licensees how to obtain it in a reasonable
87 | manner on or through a medium customarily used for software exchange.
88 |
89 | When the Program is made available in source code form:
90 |
91 | a) it must be made available under this Agreement; and
92 | b) a copy of this Agreement must be included with each copy of the Program.
93 | Contributors may not remove or alter any copyright notices contained
94 | within the Program.
95 |
96 | Each Contributor must identify itself as the originator of its Contribution,
97 | if
98 | any, in a manner that reasonably allows subsequent Recipients to identify the
99 | originator of the Contribution.
100 |
101 | 4. COMMERCIAL DISTRIBUTION
102 |
103 | Commercial distributors of software may accept certain responsibilities with
104 | respect to end users, business partners and the like. While this license is
105 | intended to facilitate the commercial use of the Program, the Contributor who
106 | includes the Program in a commercial product offering should do so in a manner
107 | which does not create potential liability for other Contributors. Therefore,
108 | if a Contributor includes the Program in a commercial product offering, such
109 | Contributor ("Commercial Contributor") hereby agrees to defend and indemnify
110 | every other Contributor ("Indemnified Contributor") against any losses,
111 | damages and costs (collectively "Losses") arising from claims, lawsuits and
112 | other legal actions brought by a third party against the Indemnified
113 | Contributor to the extent caused by the acts or omissions of such Commercial
114 | Contributor in connection with its distribution of the Program in a commercial
115 | product offering. The obligations in this section do not apply to any claims
116 | or Losses relating to any actual or alleged intellectual property
117 | infringement. In order to qualify, an Indemnified Contributor must:
118 | a) promptly notify the Commercial Contributor in writing of such claim, and
119 | b) allow the Commercial Contributor to control, and cooperate with the
120 | Commercial Contributor in, the defense and any related settlement
121 | negotiations. The Indemnified Contributor may participate in any such claim at
122 | its own expense.
123 |
124 | For example, a Contributor might include the Program in a commercial product
125 | offering, Product X. That Contributor is then a Commercial Contributor. If
126 | that Commercial Contributor then makes performance claims, or offers
127 | warranties related to Product X, those performance claims and warranties are
128 | such Commercial Contributor's responsibility alone. Under this section, the
129 | Commercial Contributor would have to defend claims against the other
130 | Contributors related to those performance claims and warranties, and if a
131 | court requires any other Contributor to pay any damages as a result, the
132 | Commercial Contributor must pay those damages.
133 |
134 | 5. NO WARRANTY
135 |
136 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN
137 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
138 | IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE,
139 | NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each
140 | Recipient is solely responsible for determining the appropriateness of using
141 | and distributing the Program and assumes all risks associated with its
142 | exercise of rights under this Agreement , including but not limited to the
143 | risks and costs of program errors, compliance with applicable laws, damage to
144 | or loss of data, programs or equipment, and unavailability or interruption of
145 | operations.
146 |
147 | 6. DISCLAIMER OF LIABILITY
148 |
149 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY
150 | CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL,
151 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION
152 | LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
153 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
154 | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
155 | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY
156 | OF SUCH DAMAGES.
157 |
158 | 7. GENERAL
159 |
160 | If any provision of this Agreement is invalid or unenforceable under
161 | applicable law, it shall not affect the validity or enforceability of the
162 | remainder of the terms of this Agreement, and without further action by the
163 | parties hereto, such provision shall be reformed to the minimum extent
164 | necessary to make such provision valid and enforceable.
165 |
166 | If Recipient institutes patent litigation against any entity (including a
167 | cross-claim or counterclaim in a lawsuit) alleging that the Program itself
168 | (excluding combinations of the Program with other software or hardware)
169 | infringes such Recipient's patent(s), then such Recipient's rights granted
170 | under Section 2(b) shall terminate as of the date such litigation is filed.
171 |
172 | All Recipient's rights under this Agreement shall terminate if it fails to
173 | comply with any of the material terms or conditions of this Agreement and does
174 | not cure such failure in a reasonable period of time after becoming aware of
175 | such noncompliance. If all Recipient's rights under this Agreement terminate,
176 | Recipient agrees to cease use and distribution of the Program as soon as
177 | reasonably practicable. However, Recipient's obligations under this Agreement
178 | and any licenses granted by Recipient relating to the Program shall continue
179 | and survive.
180 |
181 | Everyone is permitted to copy and distribute copies of this Agreement, but in
182 | order to avoid inconsistency the Agreement is copyrighted and may only be
183 | modified in the following manner. The Agreement Steward reserves the right to
184 | publish new versions (including revisions) of this Agreement from time to
185 | time. No one other than the Agreement Steward has the right to modify this
186 | Agreement. The Eclipse Foundation is the initial Agreement Steward. The
187 | Eclipse Foundation may assign the responsibility to serve as the Agreement
188 | Steward to a suitable separate entity. Each new version of the Agreement will
189 | be given a distinguishing version number. The Program (including
190 | Contributions) may always be distributed subject to the version of the
191 | Agreement under which it was received. In addition, after a new version of the
192 | Agreement is published, Contributor may elect to distribute the Program
193 | (including its Contributions) under the new version. Except as expressly
194 | stated in Sections 2(a) and 2(b) above, Recipient receives no rights or
195 | licenses to the intellectual property of any Contributor under this Agreement,
196 | whether expressly, by implication, estoppel or otherwise. All rights in the
197 | Program not expressly granted under this Agreement are reserved.
198 |
199 | This Agreement is governed by the laws of the State of New York and the
200 | intellectual property laws of the United States of America. No party to this
201 | Agreement will bring a legal action under this Agreement more than one year
202 | after the cause of action arose. Each party waives its rights to a jury trial in
203 | any resulting litigation.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Ponte
2 | =====
3 |
4 | 
5 |
6 | __Ponte__ is a multi-transport Internet of Things / Machine to Machine broker.
7 | As the current state it supports [MQTT](http://mqtt.org/) and REST
8 | APIs over HTTP and CoAP.
9 |
10 | 
11 |
12 | __Ponte__ is under active development, but it should work :).
13 | If you plan to use Ponte in production
14 | [let us know](http://twitter.com/matteocollina), we'll be more than
15 | happy to help you getting started and solve any issue you'll find out.
16 |
17 | A test instance of ponte is available at [ponte.eclipse.org](ponte.eclipse.org), on HTTP,
18 | MQTT and CoAP standard ports.
19 |
20 | Report bugs at the [Eclipse
21 | Bugzilla](https://bugs.eclipse.org/bugs/buglist.cgi?component=Core&product=Ponte&resolution=---)
22 | and join the [mailing list](https://dev.eclipse.org/mailman/listinfo/ponte-dev).
23 |
24 | [](https://github.com/feross/standard)
25 |
26 | ## Installation
27 |
28 | Ponte is a node.js application, so it needs [node.js](http://nodejs.org)
29 | to run. The currently recommended version is node 4.3.1, which is the Longtime Support Version. Ponte is tested against versions 0.12, 4.3.1 and 5. *Attention: you should currently not use ponte with node 5.7*
30 |
31 | ```
32 | $ npm install ponte bunyan -g
33 | $ ponte -v | bunyan
34 | ```
35 |
36 | Then you can connect to it with your preferred [MQTT](http://mqtt.org),
37 | [CoAP](https://datatracker.ietf.org/doc/draft-ietf-core-coap/) or
38 | [HTTP](http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol) client.
39 |
40 | ### Command Line Options
41 |
42 | ```
43 | $ ./bin/ponte --help
44 |
45 | Usage: ponte [options]
46 |
47 | Options:
48 |
49 | -h, --help output usage information
50 | -V, --version output the version number
51 | -m, --mqtt-port the mqtt port to listen to
52 | -p, --http-port the http port to listen to
53 | -a, --coap-port the coap port to listen to
54 | --host the host to listen to
55 | --coap-host the host to listen to for coap requests
56 | --mqtt-host the host to listen to for mqtt requests
57 | --http-host the host to listen to for http requests
58 | -d, --db the path were to store the database
59 | -c, --config the config file to use (override every other option)
60 | -v, --verbose set the bunyan log to INFO
61 | --very-verbose set the bunyan log to DEBUG
62 | ```
63 |
64 | ## Usage Example
65 |
66 | Start ponte:
67 | ```bash
68 | $ ponte -v | bunyan
69 | ```
70 |
71 | ### Publishing from HTTP to MQTT
72 |
73 | Publish from HTTP:
74 |
75 | ```
76 | $ curl -X PUT -d 'world' http://localhost:3000/resources/hello
77 | ```
78 |
79 | The messages from HTTP are _retained_, which means that are sent to
80 | every new subscriber.
81 |
82 | Subscribe using `mosquitto_sub` ([mosquitto](http://mosquitto.org)):
83 |
84 | ```
85 | $ mosquitto_sub -t "hello" -v
86 | hello world
87 | ```
88 |
89 | ### Publishing from MQTT to HTTP
90 |
91 | In order to publish a message that can be read from HTTP,
92 | a MQTT client needs to set the _retain_ flag.
93 | This is how it is done using `mosquitto_pub`:
94 |
95 | ```
96 | $ mosquitto_pub -t hello-from-mqtt -m "world" -r
97 | ```
98 |
99 | Reading the published value is an HTTP GET away:
100 |
101 | ```
102 | $ curl http://localhost:3000/resources/hello-from-mqtt
103 | world
104 | ```
105 |
106 | ### Publishing from CoAP to MQTT
107 |
108 | You can send CoAP messages from the command line using [coap-cli](http://github.com/mcollina/coap-cli)
109 | In the following example we do a CoAP PUT to a resource:
110 |
111 | ```
112 | $ echo -n 'world' | coap put coap://localhost/r/hello
113 | ```
114 |
115 | Subscribe using `mosquitto_sub` ([mosquitto](http://mosquitto.org)):
116 |
117 | ```
118 | $ mosquitto_sub -t "hello" -v
119 | hello world
120 | ```
121 |
122 | ### Publishing MQTT to CoAP
123 |
124 | In order to publish a message that can be read from CoAP,
125 | a MQTT client needs to set the _retain_ flag.
126 | This is how it is done using `mosquitto_pub`:
127 |
128 | ```
129 | $ mosquitto_pub -t hello-from-mqtt -m "world" -r
130 | ```
131 |
132 | In order to receive the live updates with CoAP, we need to
133 | use the observe switch:
134 |
135 | ```
136 | $ coap -o coap://localhost/r/hello-from-mqtt
137 | ```
138 |
139 | ## Embedding
140 |
141 | __Ponte__ can be run in embbedded mode, by listening to specific events:
142 |
143 | ```javascript
144 | var ponte = require("ponte");
145 | var opts = {
146 | logger: {
147 | level: 'info'
148 | },
149 | http: {
150 | port: 3000 // tcp
151 | },
152 | mqtt: {
153 | port: 3001 // tcp
154 | },
155 | coap: {
156 | port: 3000 // udp
157 | },
158 | persistence: {
159 | type: 'level',
160 | path: './db'
161 | }
162 | };
163 | var server = ponte(opts);
164 |
165 | server.on("updated", function(resource, buffer) {
166 | console.log("Resource Updated", resource, buffer);
167 | });
168 |
169 | // Stop the server after 1 minute
170 | setTimeout(function() {
171 | server.close(function() {
172 | console.log("server stopped");
173 | });
174 | }, 60 * 1000);
175 | ```
176 |
177 | ## Configuration
178 |
179 |
180 | ### Configuration with MongoDB
181 |
182 | __Ponte__ can be run on top of MongoDB with the following configuration:
183 |
184 | ```js
185 | module.exports = {
186 | persistence: {
187 | // same as http://mcollina.github.io/mosca/docs/lib/persistence/mongo.js.html
188 | type: "mongo",
189 | url: "mongodb://localhost:27017/ponte"
190 | },
191 | broker: {
192 | // same as https://github.com/mcollina/ascoltatori#mongodb
193 | type: "mongo",
194 | url: "mongodb://localhost:27017/ponte"
195 | },
196 | logger: {
197 | level: 30, // or 20 or 40
198 | name: "MongoPonte"
199 | }
200 | };
201 | ```
202 |
203 | Launch it with `$ ponte -c config.js`.
204 |
205 | ### Configuration with Redis
206 |
207 | __Ponte__ can be run on top of Redis with the following configuration:
208 |
209 | ```js
210 | module.exports = {
211 | persistence: {
212 | // same as http://mcollina.github.io/mosca/docs/lib/persistence/redis.js.html
213 | type: "redis",
214 | host: "localhost"
215 | },
216 | broker: {
217 | // same as https://github.com/mcollina/ascoltatori#redis
218 | type: "redis",
219 | host: "localhost"
220 | },
221 | logger: {
222 | level: 20,
223 | name: "Config Test Logger"
224 | }
225 | };
226 | ```
227 |
228 | Launch it with `$ ponte -c config.js`.
229 |
230 | ### Configuration with MQTT and Redis
231 |
232 | __Ponte__ can be run on top of MQTT broker while using Redis (or similarly MongoDB) with the following configuration:
233 |
234 | ```js
235 | module.exports = {
236 | persistence: {
237 | // same as http://mcollina.github.io/mosca/docs/lib/persistence/redis.js.html
238 | type: "redis",
239 | host: "localhost"
240 | },
241 | broker: {
242 | // same as https://github.com/mcollina/ascoltatori#mqtt
243 | type: "mqtt",
244 | port: "2883",
245 | host: "localhost"
246 | },
247 | logger: {
248 | level: 20,
249 | name: "Config Test Logger"
250 | }
251 | };
252 | ```
253 |
254 | ### Configuration with authentication and authorization callbacks
255 |
256 | ```js
257 | module.exports = {
258 | coap: {
259 | /**
260 | * @param {Object} req The incoming message @link https://github.com/mcollina/node-coap#incoming
261 | * @param {Function} callback The callback function. Has the following structure: callback(error, authenticated, subject)
262 | */
263 | authenticate: function(req, callback) {
264 | // Examples:
265 | // Error: callback(error);
266 | // Authenticated: callback(null, true, { username: 'someone' });
267 | // Not authenticated: callback(null, false);
268 | },
269 | /**
270 | * @param {Object} subject The subject returned by the authenticate function
271 | * @param {string} topic The topic
272 | * @param {Function} callback The callback function. Has the following structure: callback(error, authorized)
273 | */
274 | authorizeGet: function(subject, topic, callback) {
275 | // Examples:
276 | // Error: callback(error);
277 | // Authorized: callback(null, true);
278 | // Not authorized: callback(null, false);
279 | },
280 | /**
281 | * @param {Object} subject The subject returned by the authenticate function
282 | * @param {string} topic The topic
283 | * @param {Buffer} payload The payload
284 | * @param {Function} callback The callback function. Has the following structure: callback(error, authorized)
285 | */
286 | authorizePut: function(subject, topic, payload, callback) {
287 | // Examples:
288 | // Error: callback(error);
289 | // Authorized: callback(null, true);
290 | // Not authorized: callback(null, false);
291 | }
292 | },
293 | http: {
294 | /**
295 | * @param {Object} req The request object
296 | * @param {Function} callback The callback function. Has the following structure: callback(error, authenticated, subject)
297 | */
298 | authenticate: function(req, callback) {
299 | // See coap.authenticate
300 | },
301 | /**
302 | * @param {Object} subject The subject returned by the authenticate function
303 | * @param {string} topic The topic
304 | * @param {Function} callback The callback function. Has the following structure: callback(error, authorized)
305 | */
306 | authorizeGet: function(subject, topic, callback) {
307 | // See coap.authorizeGet
308 | },
309 | /**
310 | * @param {Object} subject The subject returned by the authenticate function
311 | * @param {string} topic The topic
312 | * @param {string} payload The payload
313 | * @param {Function} callback The callback function. Has the following structure: callback(error, authorized)
314 | */
315 | authorizePut: function(subject, topic, payload, callback) {
316 | // See coap.authorizePut
317 | }
318 | },
319 | mqtt: {
320 | /**
321 | * @link https://github.com/mcollina/mosca/wiki/Authentication-&-Authorization
322 | */
323 | authenticate: function(client, username, password, callback) {
324 | // ...
325 | },
326 | authorizePublish: function(client, topic, payload, callback) {
327 | // ...
328 | },
329 | authorizeSubscribe: function(client, topic, callback) {
330 | // ...
331 | }
332 | }
333 | }
334 | ```
335 |
336 | Launch it with `$ ponte -c config.js`.
337 |
338 | ## Pub/Sub Brokers
339 |
340 | __Ponte__ is based on
341 | [Ascoltatori](http://github.com/mcollina/ascoltatori), so it supports the same backends:
342 |
343 | * [RabbitMQ](http://www.rabbitmq.com/) and all implementations of
344 | the [AMQP](http://www.amqp.org/) protocol.
345 | * [Redis](http://redis.io/), the fabulous key/value store by
346 | [@antirez](https://github.com/antirez).
347 | * [Mosquitto](http://mosquitto.org/) and all implementations of the
348 | [MQTT](http://mqtt.org/) protocol.
349 | * [MongoDB](http://www.mongodb.org/), the documental NoSQL that
350 | is revolutionizing how web apps are built.
351 | * [ZeroMQ](http://www.zeromq.org/) without a central broker, so
352 | Ascoltatori can also be used in a P2P fashion.
353 |
354 | ## Persistence
355 |
356 | __Ponte__ requires a persistent storage for HTTP syndication and MQTT
357 | support.
358 | At the current state, it uses [Mosca](http://github.com/mcollina/mosca)
359 | persistence layer.
360 | Thus, it offers several persitence options:
361 |
362 | * [Memory](http://mcollina.github.com/mosca/docs/lib/persistence/memory.js.html),
363 | * [LevelUp](http://mcollina.github.com/mosca/docs/lib/persistence/levelup.js.html),
364 | * [Redis](http://mcollina.github.com/mosca/docs/lib/persistence/redis.js.html),
365 | * [MongoDB](http://mcollina.github.com/mosca/docs/lib/persistence/mongo.js.html)
366 |
367 | All of them can be configured from the configuration file, under the
368 | `persistence` key. The only exception is LevelUp, which can be specified
369 | by using the `--db` option from the command line.
370 |
371 | ## To do
372 |
373 | These are the new features you should expect in the coming
374 | months:
375 |
376 | * [ ] Add Web Hooks support.
377 | * [ ] Document configuration options.
378 | * [ ] Add WebSocket and Server-Sent Events support.
379 | * [ ] Add a Web App for reading and writing.
380 | * [ ] Standalone persistence layer.
381 |
382 | Any help is very welcome, so feel free to submit a pull-request.
383 |
384 | ## Eclipse, QEST and Ponte
385 |
386 | Ponte is a proposal at Eclipse, and this is a pure-JS rewrite of
387 | [QEST](http://github.com/mcollina/qest) in Javascript and on top of
388 | [Mosca](http://github.com/mcollina/mosca).
389 | You can find the Eclipse Project Proposal here:
390 | http://eclipse.org/proposals/technology.ponte/
391 |
392 | ## Contributing to Ponte
393 |
394 | * Install [JavaScript Standard Style] (https://github.com/feross/standard)
395 | ```bash
396 | $ npm i -g standard
397 | ```
398 | * Check out the latest master to make sure the feature hasn't been
399 | implemented or the bug hasn't been fixed yet
400 | * Check out the issue tracker to make sure someone already hasn't
401 | requested it and/or contributed it
402 | * Fork the project
403 | * Start a feature/bugfix branch
404 | * Commit and push until you are happy with your contribution
405 | * Make sure to add tests for it. This is important so I don't break it
406 | in a future version unintentionally.
407 | * Please try not to mess with the Makefile and package.json. If you
408 | want to have your own version, or is otherwise necessary, that is
409 | fine, but please isolate to its own commit so I can cherry-pick around
410 | it.
411 |
412 | ## LICENSE
413 |
414 | __Ponte__ is dual licensed under the "Eclipse Public License - v 1.0" and the
415 | "Eclipse Distribution License - v 1.0".
416 |
--------------------------------------------------------------------------------
/architecture.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eclipse-archived/ponte/5c3f6f96bfe82180314320f15793eee25baf95c3/architecture.ai
--------------------------------------------------------------------------------
/architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eclipse-archived/ponte/5c3f6f96bfe82180314320f15793eee25baf95c3/architecture.png
--------------------------------------------------------------------------------
/artwork/logo-banner-black.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eclipse-archived/ponte/5c3f6f96bfe82180314320f15793eee25baf95c3/artwork/logo-banner-black.ai
--------------------------------------------------------------------------------
/artwork/logo-banner-black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eclipse-archived/ponte/5c3f6f96bfe82180314320f15793eee25baf95c3/artwork/logo-banner-black.png
--------------------------------------------------------------------------------
/artwork/logo-banner-black.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
196 |
--------------------------------------------------------------------------------
/artwork/logo-banner-transparent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eclipse-archived/ponte/5c3f6f96bfe82180314320f15793eee25baf95c3/artwork/logo-banner-transparent.png
--------------------------------------------------------------------------------
/artwork/logo-banner-white.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eclipse-archived/ponte/5c3f6f96bfe82180314320f15793eee25baf95c3/artwork/logo-banner-white.ai
--------------------------------------------------------------------------------
/artwork/logo-banner-white.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eclipse-archived/ponte/5c3f6f96bfe82180314320f15793eee25baf95c3/artwork/logo-banner-white.jpg
--------------------------------------------------------------------------------
/artwork/logo-banner-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eclipse-archived/ponte/5c3f6f96bfe82180314320f15793eee25baf95c3/artwork/logo-banner-white.png
--------------------------------------------------------------------------------
/artwork/logo-square-black.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eclipse-archived/ponte/5c3f6f96bfe82180314320f15793eee25baf95c3/artwork/logo-square-black.ai
--------------------------------------------------------------------------------
/artwork/logo-square-black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eclipse-archived/ponte/5c3f6f96bfe82180314320f15793eee25baf95c3/artwork/logo-square-black.png
--------------------------------------------------------------------------------
/artwork/logo-square-black.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
--------------------------------------------------------------------------------
/bin/ponte:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env node
2 |
3 | /*******************************************************************************
4 | * Copyright (c) 2013-2014 Matteo Collina
5 | * All rights reserved. This program and the accompanying materials
6 | * are made available under the terms of the Eclipse Public License v1.0
7 | * and Eclipse Distribution License v1.0 which accompany this distribution.
8 | *
9 | * The Eclipse Public License is available at
10 | * http://www.eclipse.org/legal/epl-v10.html
11 | * and the Eclipse Distribution License is available at
12 | * http://www.eclipse.org/org/documents/edl-v10.php.
13 | *
14 | * Contributors:
15 | * Matteo Collina - initial API and implementation and/or initial documentation
16 | *******************************************************************************/
17 |
18 | require("../lib/ponte").cli(process.argv, function(err) {
19 | if (err) {
20 | console.log(err);
21 | console.log(err.stack);
22 | process.exit(1);
23 | }
24 | });
25 |
--------------------------------------------------------------------------------
/edl-v10.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Eclipse Distribution License - Version 1.0
8 |
25 |
26 |
27 |
28 |
29 |
30 |
Eclipse Distribution License - v 1.0
31 |
32 |
Copyright (c) 2007, Eclipse Foundation, Inc. and its licensors.
33 |
34 |
All rights reserved.
35 |
Redistribution and use in source and binary forms, with or without modification,
36 | are permitted provided that the following conditions are met:
37 |
Redistributions of source code must retain the above copyright notice,
38 | this list of conditions and the following disclaimer.
39 |
Redistributions in binary form must reproduce the above copyright notice,
40 | this list of conditions and the following disclaimer in the documentation
41 | and/or other materials provided with the distribution.
42 |
Neither the name of the Eclipse Foundation, Inc. nor the names of its
43 | contributors may be used to endorse or promote products derived from
44 | this software without specific prior written permission.
45 |
46 |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
47 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
48 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
49 | IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
50 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
51 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
52 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
53 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
54 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
55 | POSSIBILITY OF SUCH DAMAGE.
THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE
33 | PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR
34 | DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS
35 | AGREEMENT.
36 |
37 |
1. DEFINITIONS
38 |
39 |
"Contribution" means:
40 |
41 |
a) in the case of the initial Contributor, the initial
42 | code and documentation distributed under this Agreement, and
43 |
b) in the case of each subsequent Contributor:
44 |
i) changes to the Program, and
45 |
ii) additions to the Program;
46 |
where such changes and/or additions to the Program
47 | originate from and are distributed by that particular Contributor. A
48 | Contribution 'originates' from a Contributor if it was added to the
49 | Program by such Contributor itself or anyone acting on such
50 | Contributor's behalf. Contributions do not include additions to the
51 | Program which: (i) are separate modules of software distributed in
52 | conjunction with the Program under their own license agreement, and (ii)
53 | are not derivative works of the Program.
54 |
55 |
"Contributor" means any person or entity that distributes
56 | the Program.
57 |
58 |
"Licensed Patents" mean patent claims licensable by a
59 | Contributor which are necessarily infringed by the use or sale of its
60 | Contribution alone or when combined with the Program.
61 |
62 |
"Program" means the Contributions distributed in accordance
63 | with this Agreement.
64 |
65 |
"Recipient" means anyone who receives the Program under
66 | this Agreement, including all Contributors.
67 |
68 |
2. GRANT OF RIGHTS
69 |
70 |
a) Subject to the terms of this Agreement, each
71 | Contributor hereby grants Recipient a non-exclusive, worldwide,
72 | royalty-free copyright license to reproduce, prepare derivative works
73 | of, publicly display, publicly perform, distribute and sublicense the
74 | Contribution of such Contributor, if any, and such derivative works, in
75 | source code and object code form.
76 |
77 |
b) Subject to the terms of this Agreement, each
78 | Contributor hereby grants Recipient a non-exclusive, worldwide,
79 | royalty-free patent license under Licensed Patents to make, use, sell,
80 | offer to sell, import and otherwise transfer the Contribution of such
81 | Contributor, if any, in source code and object code form. This patent
82 | license shall apply to the combination of the Contribution and the
83 | Program if, at the time the Contribution is added by the Contributor,
84 | such addition of the Contribution causes such combination to be covered
85 | by the Licensed Patents. The patent license shall not apply to any other
86 | combinations which include the Contribution. No hardware per se is
87 | licensed hereunder.
88 |
89 |
c) Recipient understands that although each Contributor
90 | grants the licenses to its Contributions set forth herein, no assurances
91 | are provided by any Contributor that the Program does not infringe the
92 | patent or other intellectual property rights of any other entity. Each
93 | Contributor disclaims any liability to Recipient for claims brought by
94 | any other entity based on infringement of intellectual property rights
95 | or otherwise. As a condition to exercising the rights and licenses
96 | granted hereunder, each Recipient hereby assumes sole responsibility to
97 | secure any other intellectual property rights needed, if any. For
98 | example, if a third party patent license is required to allow Recipient
99 | to distribute the Program, it is Recipient's responsibility to acquire
100 | that license before distributing the Program.
101 |
102 |
d) Each Contributor represents that to its knowledge it
103 | has sufficient copyright rights in its Contribution, if any, to grant
104 | the copyright license set forth in this Agreement.
105 |
106 |
3. REQUIREMENTS
107 |
108 |
A Contributor may choose to distribute the Program in object code
109 | form under its own license agreement, provided that:
110 |
111 |
a) it complies with the terms and conditions of this
112 | Agreement; and
113 |
114 |
b) its license agreement:
115 |
116 |
i) effectively disclaims on behalf of all Contributors
117 | all warranties and conditions, express and implied, including warranties
118 | or conditions of title and non-infringement, and implied warranties or
119 | conditions of merchantability and fitness for a particular purpose;
120 |
121 |
ii) effectively excludes on behalf of all Contributors
122 | all liability for damages, including direct, indirect, special,
123 | incidental and consequential damages, such as lost profits;
124 |
125 |
iii) states that any provisions which differ from this
126 | Agreement are offered by that Contributor alone and not by any other
127 | party; and
128 |
129 |
iv) states that source code for the Program is available
130 | from such Contributor, and informs licensees how to obtain it in a
131 | reasonable manner on or through a medium customarily used for software
132 | exchange.
133 |
134 |
When the Program is made available in source code form:
135 |
136 |
a) it must be made available under this Agreement; and
137 |
138 |
b) a copy of this Agreement must be included with each
139 | copy of the Program.
140 |
141 |
Contributors may not remove or alter any copyright notices contained
142 | within the Program.
143 |
144 |
Each Contributor must identify itself as the originator of its
145 | Contribution, if any, in a manner that reasonably allows subsequent
146 | Recipients to identify the originator of the Contribution.
147 |
148 |
4. COMMERCIAL DISTRIBUTION
149 |
150 |
Commercial distributors of software may accept certain
151 | responsibilities with respect to end users, business partners and the
152 | like. While this license is intended to facilitate the commercial use of
153 | the Program, the Contributor who includes the Program in a commercial
154 | product offering should do so in a manner which does not create
155 | potential liability for other Contributors. Therefore, if a Contributor
156 | includes the Program in a commercial product offering, such Contributor
157 | ("Commercial Contributor") hereby agrees to defend and
158 | indemnify every other Contributor ("Indemnified Contributor")
159 | against any losses, damages and costs (collectively "Losses")
160 | arising from claims, lawsuits and other legal actions brought by a third
161 | party against the Indemnified Contributor to the extent caused by the
162 | acts or omissions of such Commercial Contributor in connection with its
163 | distribution of the Program in a commercial product offering. The
164 | obligations in this section do not apply to any claims or Losses
165 | relating to any actual or alleged intellectual property infringement. In
166 | order to qualify, an Indemnified Contributor must: a) promptly notify
167 | the Commercial Contributor in writing of such claim, and b) allow the
168 | Commercial Contributor to control, and cooperate with the Commercial
169 | Contributor in, the defense and any related settlement negotiations. The
170 | Indemnified Contributor may participate in any such claim at its own
171 | expense.
172 |
173 |
For example, a Contributor might include the Program in a commercial
174 | product offering, Product X. That Contributor is then a Commercial
175 | Contributor. If that Commercial Contributor then makes performance
176 | claims, or offers warranties related to Product X, those performance
177 | claims and warranties are such Commercial Contributor's responsibility
178 | alone. Under this section, the Commercial Contributor would have to
179 | defend claims against the other Contributors related to those
180 | performance claims and warranties, and if a court requires any other
181 | Contributor to pay any damages as a result, the Commercial Contributor
182 | must pay those damages.
183 |
184 |
5. NO WARRANTY
185 |
186 |
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
187 | PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
188 | OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION,
189 | ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY
190 | OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely
191 | responsible for determining the appropriateness of using and
192 | distributing the Program and assumes all risks associated with its
193 | exercise of rights under this Agreement , including but not limited to
194 | the risks and costs of program errors, compliance with applicable laws,
195 | damage to or loss of data, programs or equipment, and unavailability or
196 | interruption of operations.
197 |
198 |
6. DISCLAIMER OF LIABILITY
199 |
200 |
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT
201 | NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT,
202 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING
203 | WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF
204 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
205 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR
206 | DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
207 | HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
208 |
209 |
7. GENERAL
210 |
211 |
If any provision of this Agreement is invalid or unenforceable under
212 | applicable law, it shall not affect the validity or enforceability of
213 | the remainder of the terms of this Agreement, and without further action
214 | by the parties hereto, such provision shall be reformed to the minimum
215 | extent necessary to make such provision valid and enforceable.
216 |
217 |
If Recipient institutes patent litigation against any entity
218 | (including a cross-claim or counterclaim in a lawsuit) alleging that the
219 | Program itself (excluding combinations of the Program with other
220 | software or hardware) infringes such Recipient's patent(s), then such
221 | Recipient's rights granted under Section 2(b) shall terminate as of the
222 | date such litigation is filed.
223 |
224 |
All Recipient's rights under this Agreement shall terminate if it
225 | fails to comply with any of the material terms or conditions of this
226 | Agreement and does not cure such failure in a reasonable period of time
227 | after becoming aware of such noncompliance. If all Recipient's rights
228 | under this Agreement terminate, Recipient agrees to cease use and
229 | distribution of the Program as soon as reasonably practicable. However,
230 | Recipient's obligations under this Agreement and any licenses granted by
231 | Recipient relating to the Program shall continue and survive.
232 |
233 |
Everyone is permitted to copy and distribute copies of this
234 | Agreement, but in order to avoid inconsistency the Agreement is
235 | copyrighted and may only be modified in the following manner. The
236 | Agreement Steward reserves the right to publish new versions (including
237 | revisions) of this Agreement from time to time. No one other than the
238 | Agreement Steward has the right to modify this Agreement. The Eclipse
239 | Foundation is the initial Agreement Steward. The Eclipse Foundation may
240 | assign the responsibility to serve as the Agreement Steward to a
241 | suitable separate entity. Each new version of the Agreement will be
242 | given a distinguishing version number. The Program (including
243 | Contributions) may always be distributed subject to the version of the
244 | Agreement under which it was received. In addition, after a new version
245 | of the Agreement is published, Contributor may elect to distribute the
246 | Program (including its Contributions) under the new version. Except as
247 | expressly stated in Sections 2(a) and 2(b) above, Recipient receives no
248 | rights or licenses to the intellectual property of any Contributor under
249 | this Agreement, whether expressly, by implication, estoppel or
250 | otherwise. All rights in the Program not expressly granted under this
251 | Agreement are reserved.
252 |
253 |
This Agreement is governed by the laws of the State of New York and
254 | the intellectual property laws of the United States of America. No party
255 | to this Agreement will bring a legal action under this Agreement more
256 | than one year after the cause of action arose. Each party waives its
257 | rights to a jury trial in any resulting litigation.
258 |
259 |
260 |
261 |
--------------------------------------------------------------------------------
/examples/basic.js:
--------------------------------------------------------------------------------
1 | var ponte = require("../lib/ponte");
2 | var opts = {
3 | logger: {
4 | level: 'info'
5 | },
6 | http: {
7 | port: 3000 // tcp
8 | },
9 | mqtt: {
10 | port: 3001 // tcp
11 | },
12 | coap: {
13 | port: 3000 // udp
14 | },
15 | persistence: {
16 | type: 'level',
17 | path: './db'
18 | }
19 | };
20 | var server = ponte(opts);
21 |
22 | server.on("updated", function(resource, buffer) {
23 | console.log("Resource Updated", resource, buffer.toString());
24 | });
25 |
--------------------------------------------------------------------------------
/lib/cli.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | /*******************************************************************************
3 | * Copyright (c) 2013-2017 Matteo Collina
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Eclipse Distribution License v1.0 which accompany this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | * and the Eclipse Distribution License is available at
11 | * http://www.eclipse.org/org/documents/edl-v10.php.
12 | *
13 | * Contributors:
14 | * Matteo Collina - initial API and implementation and/or initial documentation
15 | * Jovan Kostovski - added standard js for source code style checking
16 | *******************************************************************************/
17 |
18 | /**
19 | * CLI module
20 | * @description A module to hanlde the commandline and starting of Ponte
21 | * @module
22 | */
23 | var commander = require('commander')
24 | var pkg = require('../package.json')
25 | var path = require('path')
26 |
27 | module.exports = function (args, done) {
28 | args = args || []
29 |
30 | var program = new commander.Command()
31 |
32 | program
33 | .version(pkg.version)
34 | .option('-m, --mqtt-port ', 'the mqtt port to listen to', parseInt)
35 | .option('-p, --http-port ', 'the http port to listen to', parseInt)
36 | .option('-a, --coap-port ', 'the coap port to listen to', parseInt)
37 | .option('--host ', 'the host to listen to')
38 | .option('--coap-host ', 'the host to listen to for coap requests')
39 | .option('--mqtt-host ', 'the host to listen to for mqtt requests')
40 | .option('--http-host ', 'the host to listen to for http requests')
41 | .option('-d, --db ', 'the path were to store the database')
42 | .option('-c, --config ', 'the config file to use (override every other option)')
43 | .option('-v, --verbose', 'set the bunyan log to INFO')
44 | .option('--very-verbose', 'set the bunyan log to DEBUG')
45 |
46 | program.parse(args)
47 |
48 | var opts = {
49 | logger: {},
50 | http: {},
51 | mqtt: {},
52 | coap: {},
53 | persistence: {}
54 | }
55 |
56 | if (program.verbose) {
57 | opts.logger.level = 30
58 | } else if (program.veryVerbose) {
59 | opts.logger.level = 20
60 | }
61 |
62 | if (program.httpPort) {
63 | opts.http.port = program.httpPort
64 | }
65 |
66 | if (program.mqttPort) {
67 | opts.mqtt.port = program.mqttPort
68 | }
69 |
70 | if (program.coapPort) {
71 | opts.coap.port = program.coapPort
72 | }
73 |
74 | if (program.host) {
75 | opts.coap.host = program.host
76 | opts.mqtt.host = program.host
77 | opts.http.host = program.host
78 | }
79 |
80 | if (program.coapHost) {
81 | opts.coap.host = program.coapHost
82 | }
83 |
84 | if (program.mqttHost) {
85 | opts.mqtt.host = program.mqttHost
86 | }
87 |
88 | if (program.httpHost) {
89 | opts.http.host = program.httpHost
90 | }
91 |
92 | if (program.db) {
93 | opts.persistence.path = program.db
94 | opts.persistence.type = 'level'
95 | }
96 |
97 | if (program.config) {
98 | opts = require(path.resolve(program.config))
99 | }
100 |
101 | return this(opts, done)
102 | }
103 |
--------------------------------------------------------------------------------
/lib/coap.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | /*******************************************************************************
3 | * Copyright (c) 2013-2017 Matteo Collina
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Eclipse Distribution License v1.0 which accompany this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | * and the Eclipse Distribution License is available at
11 | * http://www.eclipse.org/org/documents/edl-v10.php.
12 | *
13 | * Contributors:
14 | * Matteo Collina - initial API and implementation and/or initial documentation
15 | * Jovan Kostovski - added standard js for source code style checking
16 | *******************************************************************************/
17 | /**
18 | * CoAP Module
19 | * @description This module handles the CoAP requests
20 | * @module
21 | */
22 | var coap = require('coap')
23 | var rRegexp = /^\/r\/(.+)$/
24 | var callback = require('callback-stream')
25 |
26 | /**
27 | * [CoAP description]
28 | * @param {Object} opts
29 | * @param {Function} done [description]
30 | */
31 | function CoAP (opts, done) {
32 | if (!(this instanceof CoAP)) {
33 | return new CoAP(opts, done)
34 | }
35 |
36 | if (typeof opts === 'function') {
37 | done = opts
38 | opts = {}
39 | }
40 |
41 | var that = this
42 |
43 | this._persistence = opts.ponte.persistence
44 | this._broker = opts.ponte.broker
45 | this._ponte = opts.ponte
46 |
47 | if (typeof opts.authenticate === 'function') {
48 | this.authenticate = opts.authenticate
49 | }
50 |
51 | if (typeof opts.authorizeGet === 'function') {
52 | this.authorizeGet = opts.authorizeGet
53 | }
54 |
55 | if (typeof opts.authorizePut === 'function') {
56 | this.authorizePut = opts.authorizePut
57 | }
58 |
59 | var logger = this._logger = opts.ponte.logger.child({ service: 'CoAP' })
60 |
61 | this.server = coap.createServer(function handler (req, res) {
62 | var match = req.url.match(rRegexp)
63 | var topic
64 |
65 | req.on('error', function (err) {
66 | logger.info(err)
67 | })
68 |
69 | res.on('error', function (err) {
70 | logger.info(err)
71 | })
72 |
73 | logger.info({ url: req.url, code: req.code, sender: req.rsinfo, headers: req.headers }, 'request received')
74 |
75 | if (match) {
76 | topic = match[1]
77 | that.authenticate(req, function (err, authenticated, subject) {
78 | if (err) {
79 | that._handleAuthError(err, res)
80 | return
81 | }
82 |
83 | if (!authenticated) {
84 | that._handleNotAuthenticated(res)
85 | return
86 | }
87 |
88 | if (req.method === 'GET') {
89 | that.authorizeGet(subject, topic, function (err, authorized) {
90 | if (err) {
91 | that._handleAuthError(err, res)
92 | return
93 | }
94 |
95 | if (!authorized) {
96 | that._handleNotAuthorized(res)
97 | return
98 | }
99 |
100 | that._handleGET(topic, req, res)
101 | })
102 | } else if (req.method === 'PUT') {
103 | req.pipe(callback(function (err, payload) {
104 | if (err) {
105 | logger.error(err)
106 | return
107 | }
108 | payload = Buffer.concat(payload)
109 |
110 | that.authorizePut(subject, topic, payload, function (err, authorized) {
111 | if (err) {
112 | that._handleAuthError(err, res)
113 | return
114 | }
115 |
116 | if (!authorized) {
117 | that._handleNotAuthorized(res)
118 | return
119 | }
120 |
121 | that._handlePUT(topic, payload, res)
122 | })
123 | }))
124 | }
125 | })
126 | } else {
127 | res.statusCode = '4.04'
128 | res.end()
129 | }
130 | })
131 |
132 | this.server.listen(opts.port, opts.host, function (err) {
133 | done(err, that)
134 | logger.info({ port: opts.port }, 'server started')
135 | })
136 | }
137 |
138 | /**
139 | * Use this function to close the the CoAP server
140 | * @param {Function} done callback to be called
141 | * @return {[type]} [description]
142 | */
143 | CoAP.prototype.close = function (done) {
144 | this.server.close(done)
145 | }
146 |
147 | /**
148 | * Handles the GET requests
149 | * @param {string} topic The topic of the message
150 | * @param {object} req the request object
151 | * @param {object} res the response object
152 | * @return {[type]} [description]
153 | */
154 | CoAP.prototype._handleGET = function (topic, req, res) {
155 | var that = this
156 | var deliver = 'end'
157 | var logger = this._logger
158 | var cb = function (topic, payload) {
159 | logger.debug({ url: req.url, code: req.code, sender: req.rsinfo }, 'sending update')
160 | res.write(payload)
161 | }
162 |
163 | that._persistence.lookupRetained(topic, function (err, packets) {
164 | if (err) {
165 | logger.error(err)
166 | return
167 | }
168 | if (packets.length === 0) {
169 | logger.info({ url: req.url, code: req.code, sender: req.rsinfo }, 'not found')
170 | res.statusCode = '4.04'
171 | return res.end()
172 | }
173 |
174 | if (req.headers.Observe === 0) {
175 | logger.debug({ url: req.url, code: req.code, sender: req.rsinfo }, 'registering for topic')
176 |
177 | deliver = 'write'
178 | that._broker.subscribe(topic, cb)
179 |
180 | req.on('error', function () {
181 | that._broker.unsubscribe(topic, cb)
182 | })
183 |
184 | res.on('finish', function () {
185 | that._broker.unsubscribe(topic, cb)
186 | })
187 | }
188 |
189 | logger.debug({ url: req.url, code: req.code, sender: req.rsinfo }, 'delivering retained')
190 |
191 | res[deliver](packets[0].payload)
192 | })
193 | }
194 |
195 | CoAP.prototype._handlePUT = function (topic, payload, res) {
196 | var that = this
197 |
198 | var packet = { topic: topic, payload: payload, retain: true }
199 |
200 | that._persistence.storeRetained(packet, function () {
201 | that._broker.publish(topic, payload, {}, function () {
202 | res.setOption('Location-Path', '/r/' + topic)
203 | res.statusCode = '2.04'
204 | res.end()
205 |
206 | that._ponte.emit('updated', topic, payload)
207 | })
208 | })
209 | }
210 |
211 | /**
212 | * The function that will be used to authenticate requests.
213 | * This default implementation authenticates everybody.
214 | * The returned subject is just a new Object.
215 | *
216 | * @param {Object} req The incoming message @link https://github.com/mcollina/node-coap#incoming
217 | * @param {Function} cb The callback function. Has the following structure: cb(err, authenticated, subject)
218 | */
219 | CoAP.prototype.authenticate = function (req, cb) {
220 | cb(null, true, {})
221 | }
222 |
223 | /**
224 | * The function that will be used to authorize subjects to GET messages from topics.
225 | * This default implementation authorizes everybody.
226 | *
227 | * @param {Object} subject The subject returned by the authenticate function
228 | * @param {string} topic The topic
229 | * @param {Function} cb The callback function. Has the following structure: cb(err, authorized)
230 | */
231 | CoAP.prototype.authorizeGet = function (subject, topic, cb) {
232 | cb(null, true)
233 | }
234 |
235 | /**
236 | * The function that will be used to authorize subjects to PUT messages to topics.
237 | * This default implementation authorizes everybody.
238 | *
239 | * @param {Object} subject The subject returned by the authenticate function
240 | * @param {string} topic The topic
241 | * @param {Buffer} payload The payload
242 | * @param {Function} cb The callback function. Has the following structure: cb(err, authorized)
243 | */
244 | CoAP.prototype.authorizePut = function (subject, topic, payload, cb) {
245 | cb(null, true)
246 | }
247 |
248 | CoAP.prototype._handleAuthError = function (err, res) {
249 | this._logger.info(err)
250 | res.statusCode = '5.00'
251 | res.end()
252 | }
253 |
254 | CoAP.prototype._handleNotAuthenticated = function (res) {
255 | this._logger.info('authentication denied')
256 | res.statusCode = '4.01'
257 | res.end()
258 | }
259 |
260 | CoAP.prototype._handleNotAuthorized = function (res) {
261 | this._logger.info('not authorized')
262 | res.statusCode = '4.03'
263 | res.end()
264 | }
265 |
266 | module.exports = CoAP
267 |
--------------------------------------------------------------------------------
/lib/http.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | /*******************************************************************************
3 | * Copyright (c) 2013-2017 Matteo Collina
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Eclipse Distribution License v1.0 which accompany this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | * and the Eclipse Distribution License is available at
11 | * http://www.eclipse.org/org/documents/edl-v10.php.
12 | *
13 | * Contributors:
14 | * Matteo Collina - initial API and implementation and/or initial documentation
15 | * Jovan Kostovski - added standard js for source code style checking
16 | *******************************************************************************/
17 |
18 | /**
19 | * HTTP Module
20 | * @description This module handles the HTTP requests
21 | * @module
22 | */
23 | var http = require('http')
24 | var resourcesRegexp = /^\/resources\/(.+)$/
25 | var callback = require('callback-stream')
26 | var bunyan = require('bunyan')
27 | var st = require('st')
28 | var corsify = require('corsify')
29 |
30 | function HTTP (opts, done) {
31 | if (!(this instanceof HTTP)) {
32 | return new HTTP(opts, done)
33 | }
34 |
35 | if (typeof opts === 'function') {
36 | done = opts
37 | opts = {}
38 | }
39 |
40 | var that = this
41 | this._persistence = opts.ponte.persistence
42 | this._ponte = opts.ponte
43 |
44 | if (typeof opts.authenticate === 'function') {
45 | this.authenticate = opts.authenticate
46 | }
47 |
48 | if (typeof opts.authorizeGet === 'function') {
49 | this.authorizeGet = opts.authorizeGet
50 | }
51 |
52 | if (typeof opts.authorizePut === 'function') {
53 | this.authorizePut = opts.authorizePut
54 | }
55 |
56 | var logger = this._logger = opts.ponte.logger.child({
57 | service: 'HTTP',
58 | serializers: {
59 | req: bunyan.stdSerializers.req,
60 | res: bunyan.stdSerializers.res
61 | }
62 | })
63 | this.server = http.createServer(this.buildServer(opts))
64 | this.server.listen(opts.port, opts.host, function (err) {
65 | done(err, that)
66 | logger.info({ port: opts.port }, 'server started')
67 | })
68 |
69 | if (this._ponte.mqtt) {
70 | this._ponte.mqtt.attachHttpServer(this.server)
71 | }
72 | }
73 |
74 | HTTP.prototype.close = function (done) {
75 | this.server.close(done)
76 | }
77 |
78 | HTTP.prototype.buildServer = function (opts) {
79 | var logger = this._logger
80 | var persistence = this._persistence
81 | var ponte = this._ponte
82 |
83 | var authenticate = this.authenticate
84 | var authorizeGet = this.authorizeGet
85 | var authorizePut = this.authorizePut
86 |
87 | function handleAuthError (err, res) {
88 | logger.info(err)
89 | res.statusCode = 500
90 | res.end()
91 | }
92 |
93 | function handleNotAuthenticated (res) {
94 | logger.info('authentication denied')
95 | res.statusCode = 401
96 | res.end()
97 | }
98 |
99 | function handleNotAuthorized (res) {
100 | logger.info('not authorized')
101 | res.statusCode = 403
102 | res.end()
103 | }
104 |
105 | var handlePontePublic = st(opts.publicDirs.ponte, {
106 | index: false,
107 | passthrough: true,
108 | dot: opts.publicDirs.mosca.match(/(^|\/)\./)
109 | })
110 |
111 | var handleMoscaPublic = st(opts.publicDirs.mosca, {
112 | index: false,
113 | passthrough: false,
114 | dot: opts.publicDirs.mosca.match(/(^|\/)\./)
115 | })
116 |
117 | function handleGetResource (subject, topic, req, res) {
118 | if (req.method !== 'GET') {
119 | return false
120 | }
121 |
122 | authorizeGet(subject, topic, function (err, authorized) {
123 | if (err) {
124 | handleAuthError(err, res)
125 | return
126 | }
127 |
128 | if (!authorized) {
129 | handleNotAuthorized(res)
130 | return
131 | }
132 |
133 | persistence.lookupRetained(topic, function (err, packets) {
134 | if (err) {
135 | logger.error(err)
136 | return
137 | }
138 | if (packets.length === 0) {
139 | res.statusCode = 404
140 | res.end('Not found')
141 | } else {
142 | res.end(packets[0].payload)
143 | }
144 | })
145 | })
146 |
147 | return true
148 | }
149 |
150 | function handlePutResource (subject, topic, req, res) {
151 | if (req.method !== 'PUT' && req.method !== 'POST') {
152 | return false
153 | }
154 |
155 | req.pipe(callback(function (err, payload) {
156 | if (err) {
157 | logger.error(err)
158 | return
159 | }
160 | payload = payload[0]
161 |
162 | if (typeof payload === 'undefined') {
163 | payload = ''
164 | }
165 |
166 | authorizePut(subject, topic, payload, function (err, authorized) {
167 | if (err) {
168 | handleAuthError(err, res)
169 | return
170 | }
171 |
172 | if (!authorized) {
173 | handleNotAuthorized(res)
174 | return
175 | }
176 |
177 | var packet = { topic: topic, payload: payload, retain: true }
178 | persistence.storeRetained(packet, function () {
179 | ponte.broker.publish(topic, payload, {}, function () {
180 | res.setHeader('Location', '/resources/' + topic)
181 | res.statusCode = 204
182 | res.end()
183 | ponte.emit('updated', topic, new Buffer(payload))
184 | })
185 | })
186 | })
187 | }))
188 |
189 | return true
190 | }
191 |
192 | function handleNotFound (res) {
193 | res.writeHeader(404)
194 | res.end('Not Found')
195 | }
196 |
197 | return corsify({
198 | endOptions: true
199 | }, function httpServer (req, res) {
200 | logger.info({ req: req })
201 |
202 | res.on('finish', function () {
203 | logger.info({ res: res })
204 | })
205 |
206 | // Only authenticate requests to the resources
207 | var match = req.url.match(resourcesRegexp)
208 | if (match) {
209 | var topic = match[1]
210 |
211 | authenticate(req, function (err, authenticated, subject) {
212 | if (err) {
213 | handleAuthError(err, res)
214 | return
215 | }
216 |
217 | if (!authenticated) {
218 | handleNotAuthenticated(res)
219 | return
220 | }
221 |
222 | var handled =
223 | handleGetResource(subject, topic, req, res) ||
224 | handlePutResource(subject, topic, req, res)
225 |
226 | if (!handled) {
227 | handleNotFound(res)
228 | }
229 | })
230 | } else {
231 | // Public libraries do not require authentication
232 | if (opts.serveLibraries) {
233 | handlePontePublic(req, res, function () {
234 | handleMoscaPublic(req, res)
235 | })
236 | } else {
237 | handleNotFound(res)
238 | }
239 | }
240 | })
241 | }
242 |
243 | /**
244 | * The function that will be used to authenticate requests.
245 | * This default implementation authenticates everybody.
246 | * The returned subject is just a new Object.
247 | *
248 | * @param {Object} req The request object
249 | * @param {Function} cb The callback function. Has the following structure: cb(err, authenticated, subject)
250 | */
251 | HTTP.prototype.authenticate = function (req, cb) {
252 | cb(null, true, {})
253 | }
254 |
255 | /**
256 | * The function that will be used to authorize subjects to GET messages from topics.
257 | * This default implementation authorizes everybody.
258 | *
259 | * @param {Object} subject The subject returned by the authenticate function
260 | * @param {string} topic The topic
261 | * @param {Function} cb The callback function. Has the following structure: cb(err, authorized)
262 | */
263 | HTTP.prototype.authorizeGet = function (subject, topic, cb) {
264 | cb(null, true)
265 | }
266 |
267 | /**
268 | * The function that will be used to authorize subjects to PUT messages to topics.
269 | * This default implementation authorizes everybody.
270 | *
271 | * @param {Object} subject The subject returned by the authenticate function
272 | * @param {string} topic The topic
273 | * @param {string} payload The payload
274 | * @param {Function} cb The callback function. Has the following structure: cb(err, authorized)
275 | */
276 | HTTP.prototype.authorizePut = function (subject, topic, payload, cb) {
277 | cb(null, true)
278 | }
279 |
280 | module.exports = HTTP
281 |
--------------------------------------------------------------------------------
/lib/persistence.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | /*******************************************************************************
3 | * Copyright (c) 2013-2017 Matteo Collina
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Eclipse Distribution License v1.0 which accompany this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | * and the Eclipse Distribution License is available at
11 | * http://www.eclipse.org/org/documents/edl-v10.php.
12 | *
13 | * Contributors:
14 | * Matteo Collina - initial API and implementation and/or initial documentation
15 | * Jovan Kostovski - added standard js for source code style checking
16 | *******************************************************************************/
17 |
18 | var persistences = Object.create(require('mosca').persistence)
19 | persistences.level = persistences.LevelUp
20 | persistences.redis = persistences.Redis
21 | persistences.memory = persistences.Memory
22 | persistences.mongo = persistences.Mongo
23 |
24 | module.exports = function (opts, done) {
25 | var factory = persistences[opts.type]
26 |
27 | if (opts.type === 'memory') {
28 | done(null, factory(opts))
29 | } else {
30 | factory(opts, done)
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/lib/ponte.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | /*******************************************************************************
3 | * Copyright (c) 2013-2017 Matteo Collina
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Eclipse Distribution License v1.0 which accompany this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | * and the Eclipse Distribution License is available at
11 | * http://www.eclipse.org/org/documents/edl-v10.php.
12 | *
13 | * Contributors:
14 | * Matteo Collina - initial API and implementation and/or initial documentation
15 | * Jovan Kostovski - added standard js for source code style checking
16 | *******************************************************************************/
17 |
18 | var async = require('async')
19 | var servers = require('./servers.js')
20 | var EventEmitter = require('events').EventEmitter
21 | var util = require('util')
22 | var xtend = require('xtend')
23 |
24 | function Ponte (opts, done) {
25 | if (!(this instanceof Ponte)) {
26 | return new Ponte(opts, done)
27 | }
28 |
29 | if (typeof opts === 'function') {
30 | done = opts
31 | opts = {}
32 | }
33 |
34 | this.options = opts
35 |
36 | var that = this
37 |
38 | async.eachSeries(servers, function (obj, cb) {
39 | opts[obj.service] = xtend(obj.defaults, opts[obj.service])
40 | opts[obj.service].ponte = that
41 | obj.factory(opts[obj.service], function (err, instance) {
42 | that[obj.service] = instance
43 | cb(err)
44 | })
45 | }, function (err) {
46 | if (done) {
47 | done(err, that)
48 | }
49 | })
50 | }
51 |
52 | util.inherits(Ponte, EventEmitter)
53 |
54 | Ponte.prototype.close = function close (done) {
55 | var that = this
56 | var reversed = [].concat(servers).reverse()
57 | async.eachSeries(reversed, function closeEverything (obj, cb) {
58 | if (typeof that[obj.service].close === 'function') {
59 | that[obj.service].close(cb)
60 | } else {
61 | cb()
62 | }
63 | }, done)
64 | }
65 |
66 | Ponte.cli = require('./cli')
67 |
68 | module.exports = Ponte
69 |
--------------------------------------------------------------------------------
/lib/servers.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | /*******************************************************************************
3 | * Copyright (c) 2013-2017 Matteo Collina
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Eclipse Distribution License v1.0 which accompany this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | * and the Eclipse Distribution License is available at
11 | * http://www.eclipse.org/org/documents/edl-v10.php.
12 | *
13 | * Contributors:
14 | * Matteo Collina - Extracted from ponte.js file.
15 | * Jovan Kostovski - added standard js for source code style checking
16 | *******************************************************************************/
17 |
18 | var mosca = require('mosca')
19 | var HTTP = require('./http')
20 | var CoAP = require('./coap')
21 | var persistence = require('./persistence')
22 | var ascoltatori = require('ascoltatori')
23 | var bunyan = require('bunyan')
24 | var xtend = require('xtend')
25 | var path = require('path')
26 |
27 | module.exports = [{
28 | service: 'logger',
29 | factory: function (opts, done) {
30 | delete opts.ponte
31 | done(null, bunyan.createLogger(opts))
32 | },
33 | defaults: {
34 | name: 'ponte',
35 | level: 40
36 | }
37 | }, {
38 | service: 'broker',
39 | defaults: {
40 | wildcardOne: '+',
41 | wildcardSome: '#',
42 | separator: '/'
43 | },
44 | factory: function (opts, done) {
45 | opts.json = false
46 | ascoltatori.build(opts, function (err, ascoltatore) {
47 | if (err) throw (err)
48 | done(null, ascoltatore)
49 | })
50 | }
51 | }, {
52 | service: 'persistence',
53 | factory: persistence,
54 | defaults: {
55 | type: 'memory'
56 | }
57 | }, {
58 | service: 'mqtt',
59 | factory: function (opts, cb) {
60 | opts.ascoltatore = opts.ponte.broker
61 | opts.logger = xtend(opts.logger || {}, {
62 | childOf: opts.ponte.logger,
63 | level: opts.ponte.logger.level(),
64 | service: 'MQTT'
65 | })
66 | var server = new mosca.Server(opts, function (err, instance) {
67 | if (typeof opts.authenticate === 'function') {
68 | server.authenticate = opts.authenticate
69 | }
70 | if (typeof opts.authorizePublish === 'function') {
71 | server.authorizePublish = opts.authorizePublish
72 | }
73 | if (typeof opts.authorizeSubscribe === 'function') {
74 | server.authorizeSubscribe = opts.authorizeSubscribe
75 | }
76 | cb(err, instance)
77 | })
78 | server.on('published', function moscaPonteEvent (packet) {
79 | if (packet.retain) {
80 | opts.ponte.emit('updated', packet.topic, packet.payload)
81 | }
82 | })
83 | opts.ponte.persistence.wire(server)
84 | }
85 | }, {
86 | service: 'http',
87 | factory: HTTP,
88 | defaults: {
89 | port: 3000,
90 | serveLibraries: true,
91 | publicDirs: {
92 | ponte: path.join(__dirname, '..', 'public'),
93 | mosca: path.join(__dirname, '..', 'node_modules', 'mosca', 'public')
94 | }
95 | }
96 | }, {
97 | service: 'coap',
98 | factory: CoAP,
99 | defaults: {
100 | port: 5683
101 | }
102 | }]
103 |
--------------------------------------------------------------------------------
/notice.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Eclipse Foundation Software User Agreement
7 |
8 |
9 |
10 |
Eclipse Foundation Software User Agreement
11 |
February 1, 2011
12 |
13 |
Usage Of Content
14 |
15 |
THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS
16 | (COLLECTIVELY "CONTENT"). USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND
17 | CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE
18 | OF THE CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR
19 | NOTICES INDICATED OR REFERENCED BELOW. IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND
20 | CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.
21 |
22 |
Applicable Licenses
23 |
24 |
Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the Eclipse Public License Version 1.0
25 | ("EPL"). A copy of the EPL is provided with this Content and is also available at http://www.eclipse.org/legal/epl-v10.html.
26 | For purposes of the EPL, "Program" will mean the Content.
27 |
28 |
Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code
29 | repository ("Repository") in software modules ("Modules") and made available as downloadable archives ("Downloads").
30 |
31 |
32 |
Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content. Typical modules may include plug-ins ("Plug-ins"), plug-in fragments ("Fragments"), and features ("Features").
33 |
Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java™ ARchive) in a directory named "plugins".
34 |
A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material. Each Feature may be packaged as a sub-directory in a directory named "features". Within a Feature, files named "feature.xml" may contain a list of the names and version numbers of the Plug-ins
35 | and/or Fragments associated with that Feature.
36 |
Features may also include other Features ("Included Features"). Within a Feature, files named "feature.xml" may contain a list of the names and version numbers of Included Features.
37 |
38 |
39 |
The terms and conditions governing Plug-ins and Fragments should be contained in files named "about.html" ("Abouts"). The terms and conditions governing Features and
40 | Included Features should be contained in files named "license.html" ("Feature Licenses"). Abouts and Feature Licenses may be located in any directory of a Download or Module
41 | including, but not limited to the following locations:
42 |
43 |
44 |
The top-level (root) directory
45 |
Plug-in and Fragment directories
46 |
Inside Plug-ins and Fragments packaged as JARs
47 |
Sub-directories of the directory named "src" of certain Plug-ins
48 |
Feature directories
49 |
50 |
51 |
Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license ("Feature Update License") during the
52 | installation process. If the Feature contains Included Features, the Feature Update License should either provide you with the terms and conditions governing the Included Features or
53 | inform you where you can locate them. Feature Update Licenses may be found in the "license" property of files named "feature.properties" found within a Feature.
54 | Such Abouts, Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in
55 | that directory.
56 |
57 |
THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS. SOME OF THESE
58 | OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):
IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License is provided, please
70 | contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.
71 |
72 |
73 |
Use of Provisioning Technology
74 |
75 |
The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse
76 | Update Manager ("Provisioning Technology") for the purpose of allowing users to install software, documentation, information and/or
77 | other materials (collectively "Installable Software"). This capability is provided with the intent of allowing such users to
78 | install, extend and update Eclipse-based products. Information about packaging Installable Software is available at http://eclipse.org/equinox/p2/repository_packaging.html
80 | ("Specification").
81 |
82 |
You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the
83 | applicable license agreements relating to the Installable Software to be presented to, and accepted by, the users of the Provisioning Technology
84 | in accordance with the Specification. By using Provisioning Technology in such a manner and making it available in accordance with the
85 | Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:
86 |
87 |
88 |
A series of actions may occur ("Provisioning Process") in which a user may execute the Provisioning Technology
89 | on a machine ("Target Machine") with the intent of installing, extending or updating the functionality of an Eclipse-based
90 | product.
91 |
During the Provisioning Process, the Provisioning Technology may cause third party Installable Software or a portion thereof to be
92 | accessed and copied to the Target Machine.
93 |
Pursuant to the Specification, you will provide to the user the terms and conditions that govern the use of the Installable
94 | Software ("Installable Software Agreement") and such Installable Software Agreement shall be accessed from the Target
95 | Machine in accordance with the Specification. Such Installable Software Agreement must inform the user of the terms and conditions that govern
96 | the Installable Software and must solicit acceptance by the end user in the manner prescribed in such Installable Software Agreement. Upon such
97 | indication of agreement by the user, the provisioning Technology will complete installation of the Installable Software.
98 |
99 |
100 |
Cryptography
101 |
102 |
Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to
103 | another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import,
104 | possession, or use, and re-export of encryption software, to see if this is permitted.
105 |
106 |
Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.
107 |
108 |
109 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ponte",
3 | "version": "0.0.16",
4 | "description": "The Internet of Things Bridge for REST developers",
5 | "main": "lib/ponte.js",
6 | "bin": {
7 | "ponte": "./bin/ponte"
8 | },
9 | "scripts": {
10 | "test": "mocha --recursive --bail --reporter spec test",
11 | "ci": "mocha --recursive --bail --watch test",
12 | "standard-lib": "standard lib/*.js --fix",
13 | "standard-test": "standard test/*.js --fix",
14 | "start": "./bin/ponte -v | bunyan"
15 | },
16 | "pre-commit": [
17 | "standard-lib",
18 | "standard-test",
19 | "test"
20 | ],
21 | "repository": {
22 | "type": "git",
23 | "url": "https://github.com/eclipse/ponte.git"
24 | },
25 | "bugs": {
26 | "url": "https://bugs.eclipse.org/bugs/buglist.cgi?component=Core&product=Ponte&resolution=---"
27 | },
28 | "author": "Matteo Collina ",
29 | "contributors": [
30 | "Jovan Kostovski (https://chombium.wordpress.com)"
31 | ],
32 | "license": "EPL-1.0 OR BSD-3-Clause",
33 | "devDependencies": {
34 | "tmp": "0.0.31",
35 | "superagent": "~3.3.1",
36 | "sinon": "~1.17.7",
37 | "supertest": "~2.0.1",
38 | "chai": "~3.5.0",
39 | "mocha": "~3.2.0",
40 | "mqtt": "~2.2.1",
41 | "pre-commit": "~1.2.2"
42 | },
43 | "dependencies": {
44 | "mosca": "~2.2.0",
45 | "ascoltatori": "~3.2.0",
46 | "commander": "~2.9.0",
47 | "bunyan": "~1.8.5",
48 | "async": "~2.1.4",
49 | "callback-stream": "~1.1.0",
50 | "xtend": "~4.0.1",
51 | "coap": "~0.19.0",
52 | "st": "~1.2.0",
53 | "corsify": "~2.1.0"
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/test/cli.js:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2013-2017 Matteo Collina
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * and Eclipse Distribution License v1.0 which accompany this distribution.
6 | *
7 | * The Eclipse Public License is available at
8 | * http://www.eclipse.org/legal/epl-v10.html
9 | * and the Eclipse Distribution License is available at
10 | * http://www.eclipse.org/org/documents/edl-v10.php.
11 | *
12 | * Contributors:
13 | * Matteo Collina - initial API and implementation and/or initial documentation
14 | * Jovan Kostovski - added standard js for source code style checking
15 | *******************************************************************************/
16 |
17 | /* eslint-env mocha */
18 | /* global expect */
19 |
20 | var ponte = require('../lib/ponte')
21 | var async = require('async')
22 | var tmp = require('tmp')
23 | var mosca = require('mosca')
24 |
25 | describe('ponte.cli', function () {
26 | var servers = null
27 | var args
28 |
29 | beforeEach(function () {
30 | args = ['node', 'ponte']
31 | servers = []
32 | })
33 |
34 | afterEach(function (done) {
35 | async.parallel(servers.map(function (s) {
36 | return function (cb) {
37 | s.close(cb)
38 | }
39 | }), function () {
40 | done()
41 | })
42 | })
43 |
44 | var startServer = function (done, callback) {
45 | return ponte.cli(args, function (err, server) {
46 | if (server) {
47 | servers.unshift(server)
48 | callback(server)
49 | }
50 | done(err)
51 | })
52 | }
53 |
54 | it('must be a function', function () {
55 | expect(ponte.cli).to.be.a('function')
56 | })
57 |
58 | it('should start a ponte', function (done) {
59 | startServer(done, function (server) {
60 | expect(server).to.be.instanceOf(ponte)
61 | })
62 | })
63 |
64 | it('should start a ponte on a specific HTTP port', function (done) {
65 | args.push('-p')
66 | args.push('3042')
67 | startServer(done, function (server) {
68 | expect(server.options.http.port).to.be.eql(3042)
69 | })
70 | })
71 |
72 | it('should start a ponte on a specific MQTT port', function (done) {
73 | args.push('-m')
74 | args.push('3042')
75 | startServer(done, function (server) {
76 | expect(server.options.mqtt.port).to.be.eql(3042)
77 | })
78 | })
79 |
80 | it('should start a ponte on a specific CoAP port', function (done) {
81 | args.push('-a')
82 | args.push('3043')
83 | startServer(done, function (server) {
84 | expect(server.options.coap.port).to.be.eql(3043)
85 | })
86 | })
87 |
88 | it('should start a ponte on a specific HTTP port (long)', function (done) {
89 | args.push('--http-port')
90 | args.push('3042')
91 | startServer(done, function (server) {
92 | expect(server.options.http.port).to.be.eql(3042)
93 | })
94 | })
95 |
96 | it('should start a ponte on a specific MQTT port (long)', function (done) {
97 | args.push('--mqtt-port')
98 | args.push('3042')
99 | startServer(done, function (server) {
100 | expect(server.options.mqtt.port).to.be.eql(3042)
101 | })
102 | })
103 |
104 | it('should start a ponte on a specific CoAP port (long)', function (done) {
105 | args.push('--coap-port')
106 | args.push('3043')
107 | startServer(done, function (server) {
108 | expect(server.options.coap.port).to.be.eql(3043)
109 | })
110 | })
111 |
112 | it('should support a verbose option by setting the bunyan level to 30', function (done) {
113 | args.push('-v')
114 | var s = startServer(done, function (server) {
115 | expect(server.logger.level()).to.equal(30)
116 | })
117 |
118 | if (s.logger) {
119 | s.logger.streams.pop()
120 | }
121 | })
122 |
123 | it('should support a very verbose option by setting the bunyan level to 20', function (done) {
124 | args.push('--very-verbose')
125 | var s = startServer(done, function (server) {
126 | expect(server.logger.level()).to.equal(20)
127 | })
128 |
129 | if (s.logger) {
130 | s.logger.streams.pop()
131 | }
132 | })
133 |
134 | it('should support a config option (short)', function (done) {
135 | args.push('-c')
136 | args.push('test/sample_config.js')
137 | startServer(done, function (server) {
138 | expect(server.options.logger).to.have.property('name', 'Config Test Logger')
139 | })
140 | })
141 |
142 | it('should support a config option (long)', function (done) {
143 | args.push('--config')
144 | args.push('test/sample_config.js')
145 | startServer(done, function (server) {
146 | expect(server.options.logger).to.have.property('name', 'Config Test Logger')
147 | })
148 | })
149 |
150 | it('should support a config option with an absolute path', function (done) {
151 | args.push('-c')
152 | args.push(process.cwd() + '/test/sample_config.js')
153 | startServer(done, function (server) {
154 | expect(server.options.logger).to.have.property('name', 'Config Test Logger')
155 | })
156 | })
157 |
158 | it('should create a leveldb with the --db flag', function (done) {
159 | tmp.dir(function (err, path, fd) {
160 | if (err) {
161 | done(err)
162 | return
163 | }
164 |
165 | args.push('--db')
166 | args.push(path)
167 |
168 | startServer(done, function (server) {
169 | expect(server.persistence).to.be.instanceOf(mosca.persistence.LevelUp)
170 | expect(server.persistence.options.path).to.eql(path)
171 | })
172 | })
173 | })
174 |
175 | it('should start a ponte on a specific host', function (done) {
176 | args.push('--host')
177 | args.push('127.0.0.1')
178 | startServer(done, function (server) {
179 | expect(server.options.http.host).to.be.eql('127.0.0.1')
180 | expect(server.options.mqtt.host).to.be.eql('127.0.0.1')
181 | expect(server.options.coap.host).to.be.eql('127.0.0.1')
182 | })
183 | })
184 |
185 | it('should start a ponte on a specific host for CoAP', function (done) {
186 | args.push('--coap-host')
187 | args.push('::1')
188 | startServer(done, function (server) {
189 | expect(server.options.coap.host).to.be.eql('::1')
190 | })
191 | })
192 |
193 | it('should start a ponte on a specific host for MQTT', function (done) {
194 | args.push('--mqtt-host')
195 | args.push('127.0.0.1')
196 | startServer(done, function (server) {
197 | expect(server.options.mqtt.host).to.be.eql('127.0.0.1')
198 | })
199 | })
200 |
201 | it('should start a ponte on a specific host for HTTP', function (done) {
202 | args.push('--http-host')
203 | args.push('127.0.0.1')
204 | startServer(done, function (server) {
205 | expect(server.options.http.host).to.be.eql('127.0.0.1')
206 | })
207 | })
208 | })
209 |
--------------------------------------------------------------------------------
/test/coap.js:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2013-2017 Matteo Collina
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * and Eclipse Distribution License v1.0 which accompany this distribution.
6 | *
7 | * The Eclipse Public License is available at
8 | * http://www.eclipse.org/legal/epl-v10.html
9 | * and the Eclipse Distribution License is available at
10 | * http://www.eclipse.org/org/documents/edl-v10.php.
11 | *
12 | * Contributors:
13 | * Matteo Collina - initial API and implementation and/or initial documentation
14 | * Jovan Kostovski - added standard js for source code style checking
15 | *******************************************************************************/
16 | /* eslint-env mocha */
17 | /* global ponteSettings, expect */
18 | var ponte = require('../lib/ponte')
19 | var mqtt = require('mqtt')
20 | var coap = require('coap')
21 | var callback = require('callback-stream')
22 |
23 | describe('Ponte as a CoAP API', function () {
24 | var settings
25 | var instance
26 |
27 | describe('without auth problems', function () {
28 | beforeEach(function (done) {
29 | settings = ponteSettings()
30 | instance = ponte(settings, done)
31 | })
32 |
33 | afterEach(function (done) {
34 | instance.close(done)
35 | })
36 |
37 | it('should GET an unknown topic and return a 4.04', function (done) {
38 | var req = coap.request({
39 | port: settings.coap.port,
40 | pathname: '/r/hello'
41 | }).end()
42 |
43 | req.on('response', function (res) {
44 | expect(res.code).to.eql('4.04')
45 | done()
46 | })
47 | })
48 |
49 | it('should GET an unknown path and return a 4.04', function (done) {
50 | var req = coap.request({
51 | port: settings.coap.port,
52 | pathname: '/hello'
53 | }).end()
54 |
55 | req.on('response', function (res) {
56 | expect(res.code).to.eql('4.04')
57 | done()
58 | })
59 | })
60 |
61 | it('should PUT a topic and return a 2.04 (changed)', function (done) {
62 | var req = coap.request({
63 | port: settings.coap.port,
64 | pathname: '/r/hello',
65 | method: 'PUT'
66 | }).end('hello world')
67 |
68 | req.on('response', function (res) {
69 | expect(res.code).to.eql('2.04')
70 | done()
71 | })
72 | })
73 |
74 | it("should PUT a topic and set a 'Location-Path' option", function (done) {
75 | var req = coap.request({
76 | port: settings.coap.port,
77 | pathname: '/r/hello',
78 | method: 'PUT'
79 | }).end('hello world')
80 |
81 | req.on('response', function (res) {
82 | expect(res.headers).to.have.property('Location-Path', '/r/hello')
83 | done()
84 | })
85 | })
86 |
87 | it('should PUT a topic and return a 2.04 (changed) if the topic existed', function (done) {
88 | var req = coap.request({
89 | port: settings.coap.port,
90 | pathname: '/r/hello',
91 | method: 'PUT'
92 | }).end('hello world')
93 |
94 | req.on('response', function (res) {
95 | req = coap.request({
96 | port: settings.coap.port,
97 | pathname: '/r/hello',
98 | method: 'PUT'
99 | }).end('hello matteo')
100 |
101 | req.on('response', function (res) {
102 | expect(res.code).to.eql('2.04')
103 | done()
104 | })
105 | })
106 | })
107 |
108 | it('should PUT and GET a topic and its payload', function (done) {
109 | var req = coap.request({
110 | port: settings.coap.port,
111 | pathname: '/r/hello',
112 | method: 'PUT'
113 | }).end('hello world')
114 |
115 | req.on('response', function (res) {
116 | req = coap.request({
117 | port: settings.coap.port,
118 | pathname: '/r/hello'
119 | }).end()
120 |
121 | req.on('response', function (res) {
122 | expect(res.code).to.eql('2.05')
123 |
124 | res.pipe(callback(function (err, data) {
125 | if (err) throw (err)
126 | expect(data.toString()).to.eql('hello world')
127 | done()
128 | }))
129 | })
130 | })
131 | })
132 |
133 | it('should publish a value to MQTT after PUT', function (done) {
134 | mqtt.connect('mqtt://localhost:' + settings.mqtt.port)
135 | .subscribe('hello', function () {
136 | coap.request({
137 | port: settings.coap.port,
138 | pathname: '/r/hello',
139 | method: 'PUT'
140 | }).end('world')
141 | })
142 |
143 | .on('message', function (topic, payload) {
144 | expect(topic).to.eql('hello')
145 | expect(payload.toString()).to.eql('world')
146 | done()
147 | })
148 | })
149 |
150 | it('should allow to observe resources', function (done) {
151 | var req = coap.request({
152 | port: settings.coap.port,
153 | pathname: '/r/hello',
154 | method: 'PUT'
155 | }).end('abcdef')
156 |
157 | req.on('response', function (res) {
158 | var req2 = coap.request({
159 | port: settings.coap.port,
160 | pathname: '/r/hello',
161 | method: 'GET',
162 | observe: true
163 | })
164 |
165 | req2.on('error', function (err) {
166 | console.log(err)
167 | console.log(err.stack)
168 | })
169 | req2.end()
170 |
171 | req2.on('response', function (res) {
172 | mqtt.connect('mqtt://localhost:' + settings.mqtt.port)
173 | .publish('hello', 'world', { retain: true })
174 | .publish('hello', 'matteo', { retain: true })
175 | .end()
176 |
177 | res.once('data', function (data) {
178 | expect(data.toString()).to.eql('abcdef')
179 | res.once('data', function (data) {
180 | expect(data.toString()).to.eql('world')
181 | res.once('data', function (data) {
182 | done()
183 | })
184 | })
185 | })
186 | })
187 | })
188 | })
189 |
190 | it("should emit an 'updated' event after a put", function (done) {
191 | coap.request({
192 | port: settings.coap.port,
193 | pathname: '/r/hello',
194 | method: 'PUT'
195 | }).end('hello world')
196 |
197 | instance.on('updated', function (resource, value) {
198 | expect(resource).to.eql('hello')
199 | expect(value).to.eql(new Buffer('hello world'))
200 | done()
201 | })
202 | })
203 | })
204 |
205 | describe('with auth problems', function () {
206 | beforeEach(function (done) {
207 | settings = ponteSettings()
208 |
209 | settings.coap.authenticate = function (req, callback) {
210 | if (req.url === '/r/unauthenticated') {
211 | callback(null, false)
212 | } else {
213 | var subject = {}
214 | callback(null, true, subject)
215 | }
216 | }
217 | settings.coap.authorizeGet = function (subject, topic, callback) {
218 | if (topic === 'unauthorizedGet') {
219 | callback(null, false)
220 | } else {
221 | callback(null, true)
222 | }
223 | }
224 | settings.coap.authorizePut = function (subject, topic, payload, callback) {
225 | if (topic === 'unauthorizedPut') {
226 | callback(null, false)
227 | } else {
228 | callback(null, true)
229 | }
230 | }
231 |
232 | instance = ponte(settings, done)
233 | })
234 |
235 | afterEach(function (done) {
236 | instance.close(done)
237 | })
238 |
239 | it('should return 4.01 if a request cannot be authenticated', function (done) {
240 | var req = coap.request({
241 | port: settings.coap.port,
242 | pathname: '/r/unauthenticated'
243 | }).end()
244 |
245 | req.on('response', function (res) {
246 | expect(res.code).to.eql('4.01')
247 | done()
248 | })
249 | })
250 |
251 | it('should return 4.03 if a GET request is not authorized', function (done) {
252 | var req = coap.request({
253 | port: settings.coap.port,
254 | pathname: '/r/unauthorizedGet'
255 | }).end()
256 |
257 | req.on('response', function (res) {
258 | expect(res.code).to.eql('4.03')
259 | done()
260 | })
261 | })
262 |
263 | it('should return 4.03 if a PUT request is not authorized', function (done) {
264 | var req = coap.request({
265 | port: settings.coap.port,
266 | pathname: '/r/unauthorizedPut',
267 | method: 'PUT'
268 | }).end()
269 |
270 | req.on('response', function (res) {
271 | expect(res.code).to.eql('4.03')
272 | done()
273 | })
274 | })
275 | })
276 | })
277 |
--------------------------------------------------------------------------------
/test/common.js:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2013-2017 Matteo Collina
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * and Eclipse Distribution License v1.0 which accompany this distribution.
6 | *
7 | * The Eclipse Public License is available at
8 | * http://www.eclipse.org/legal/epl-v10.html
9 | * and the Eclipse Distribution License is available at
10 | * http://www.eclipse.org/org/documents/edl-v10.php.
11 | *
12 | * Contributors:
13 | * Matteo Collina - initial API and implementation and/or initial documentation
14 | * Jovan Kostovski - added standard js for source code style checking
15 | *******************************************************************************/
16 |
17 | global.sinon = require('sinon')
18 | global.chai = require('chai')
19 | global.expect = require('chai').expect
20 |
21 | var portCounter = 30042
22 | global.nextPort = function () {
23 | return ++portCounter
24 | }
25 | /* global nextPort */
26 | global.ponteSettings = function () {
27 | return {
28 | logger: {
29 | name: 'ponteTests',
30 | level: 60
31 | },
32 | http: {
33 | port: nextPort()
34 | },
35 | coap: {
36 | port: nextPort()
37 | },
38 | mqtt: {
39 | port: nextPort()
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/test/http_spec.js:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2013-2017 Matteo Collina
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * and Eclipse Distribution License v1.0 which accompany this distribution.
6 | *
7 | * The Eclipse Public License is available at
8 | * http://www.eclipse.org/legal/epl-v10.html
9 | * and the Eclipse Distribution License is available at
10 | * http://www.eclipse.org/org/documents/edl-v10.php.
11 | *
12 | * Contributors:
13 | * Matteo Collina - initial API and implementation and/or initial documentation
14 | * Jovan Kostovski - added standard js for source code style checking
15 | *******************************************************************************/
16 |
17 | /* eslint-env mocha */
18 | /* global ponteSettings, expect */
19 |
20 | var request = require('supertest')
21 | var ponte = require('../lib/ponte')
22 | var mqtt = require('mqtt')
23 |
24 | describe('Ponte as an HTTP API', function () {
25 | var settings
26 | var instance
27 |
28 | describe('without auth problems', function () {
29 | beforeEach(function (done) {
30 | settings = ponteSettings()
31 | instance = ponte(settings, done)
32 | })
33 |
34 | afterEach(function (done) {
35 | instance.close(done)
36 | })
37 |
38 | it('should GET an unknown topic and return a 404', function (done) {
39 | request(instance.http.server)
40 | .get('/resources/hello')
41 | .expect(404, done)
42 | })
43 |
44 | it('should PUT a topic and return a 204', function (done) {
45 | request(instance.http.server)
46 | .put('/resources/hello')
47 | .send('hello world')
48 | .expect(204, done)
49 | })
50 |
51 | it('should PUT a topic and return a Location header', function (done) {
52 | request(instance.http.server)
53 | .put('/resources/hello')
54 | .send('hello world')
55 | .expect('Location', '/resources/hello', done)
56 | })
57 |
58 | it('should PUT and GET a topic and its payload', function (done) {
59 | request(instance.http.server)
60 | .put('/resources/hello')
61 | .set('content-type', 'text/plain')
62 | .send('hello world')
63 | .expect(204, function () {
64 | request(instance.http.server)
65 | .get('/resources/hello')
66 | .expect(200, 'hello world', done)
67 | })
68 | })
69 |
70 | it('should POST and GET a topic and its payload', function (done) {
71 | request(instance.http.server)
72 | .post('/resources/hello')
73 | .set('content-type', 'text/plain')
74 | .send('hello world')
75 | .expect(204, function () {
76 | request(instance.http.server)
77 | .get('/resources/hello')
78 | .expect(200, 'hello world', done)
79 | })
80 | })
81 |
82 | it('should publish a value to MQTT after PUT', function (done) {
83 | mqtt.connect('mqtt://localhost:' + settings.mqtt.port)
84 |
85 | .subscribe('hello', function () {
86 | request(instance.http.server)
87 | .put('/resources/hello')
88 | .send('world')
89 | .end(function (err) {
90 | if (err) {
91 | done(err)
92 | }
93 | })
94 | })
95 |
96 | .on('message', function (topic, payload) {
97 | expect(topic).to.eql('hello')
98 | expect(payload.toString()).to.eql('world')
99 | done()
100 | })
101 | })
102 |
103 | it("should emit an 'updated' event after a put", function (done) {
104 | request(instance.http.server)
105 | .put('/resources/hello')
106 | .set('content-type', 'text/plain')
107 | .send('hello world')
108 | .end(function () {})
109 |
110 | instance.on('updated', function (resource, value) {
111 | expect(resource).to.eql('hello')
112 | expect(value).to.eql(new Buffer('hello world'))
113 | done()
114 | })
115 | })
116 |
117 | it('should GET the index and return a 404', function (done) {
118 | request(instance.http.server)
119 | .get('')
120 | .expect(404, done)
121 | })
122 |
123 | it('should handle CORS headers', function (done) {
124 | request(instance.http.server)
125 | .options('/resources/hello')
126 | .set('Origin', 'http://somehost.org')
127 | .expect('Access-Control-Allow-Origin', 'http://somehost.org')
128 | .expect('Access-Control-Allow-Methods', 'POST, GET, PUT, DELETE, OPTIONS, XMODIFY')
129 | .expect('Access-Control-Max-Age', '86400')
130 | .expect('Access-Control-Allow-Headers', 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept')
131 | .expect(200, done)
132 | })
133 | })
134 |
135 | describe('with auth problems', function () {
136 | beforeEach(function (done) {
137 | settings = ponteSettings()
138 |
139 | settings.http.authenticate = function (req, callback) {
140 | if (req.url === '/resources/unauthenticated') {
141 | callback(null, false)
142 | } else {
143 | var subject = {}
144 | callback(null, true, subject)
145 | }
146 | }
147 | settings.http.authorizeGet = function (subject, topic, callback) {
148 | if (topic === 'unauthorizedGet') {
149 | callback(null, false)
150 | } else {
151 | callback(null, true)
152 | }
153 | }
154 | settings.http.authorizePut = function (subject, topic, payload, callback) {
155 | if (topic === 'unauthorizedPut') {
156 | callback(null, false)
157 | } else {
158 | callback(null, true)
159 | }
160 | }
161 |
162 | instance = ponte(settings, done)
163 | })
164 |
165 | afterEach(function (done) {
166 | instance.close(done)
167 | })
168 |
169 | it('should return 401 if a request cannot be authenticated', function (done) {
170 | request(instance.http.server)
171 | .get('/resources/unauthenticated')
172 | .expect(401, done)
173 | })
174 |
175 | it('should return 403 if a GET request is not authorized', function (done) {
176 | request(instance.http.server)
177 | .get('/resources/unauthorizedGet')
178 | .expect(403, done)
179 | })
180 |
181 | it('should return 403 if a PUT request is not authorized', function (done) {
182 | request(instance.http.server)
183 | .put('/resources/unauthorizedPut')
184 | .set('content-type', 'text/plain')
185 | .send('hello world')
186 | .expect(403, done)
187 | })
188 | })
189 | })
190 |
--------------------------------------------------------------------------------
/test/libraries_inside_hidden_dir.js:
--------------------------------------------------------------------------------
1 | /* eslint-env mocha */
2 | /* global ponteSettings */
3 |
4 | var request = require('supertest')
5 | var ponte = require('../lib/ponte')
6 | var async = require('async')
7 | var fs = require('fs')
8 | var path = require('path')
9 |
10 | describe('Ponte as an HTTP server that serves libraries', function () {
11 | var settings
12 | var instance
13 |
14 | function remove () {
15 | try {
16 | fs.unlinkSync(path.join(__dirname, '.hidden', 'mqttws31.js'))
17 | fs.unlinkSync(path.join(__dirname, '.hidden', 'mqtt.js'))
18 | fs.rmdirSync(path.join(__dirname, '.hidden'))
19 | } catch (e) {
20 | return e.code !== 'NOENT'
21 | }
22 | return true
23 | }
24 |
25 | function cp (opts, done) {
26 | var toStream = fs.createWriteStream(opts.to)
27 | fs.createReadStream(opts.from).pipe(toStream)
28 | toStream.on('finish', done)
29 | }
30 |
31 | function prepare (defaults, newSettings, done) {
32 | defaults.http.publicDirs = {
33 | ponte: path.join(__dirname, '..', 'public'),
34 | mosca: path.join(__dirname, '..', 'node_modules', 'mosca', 'public')
35 | }
36 | if (!remove()) { return done(new Error('Failed to remove test artifacts from previous attempt.')) }
37 | try {
38 | fs.mkdirSync(path.join(__dirname, '.hidden'))
39 | } catch (e) {
40 | return done(new Error('Failed to create .hidden directory.'))
41 | }
42 | async.map([
43 | {
44 | from: defaults.http.publicDirs.ponte + '/mqttws31.js',
45 | to: newSettings.http.publicDirs.ponte + '/mqttws31.js'
46 | },
47 | {
48 | from: defaults.http.publicDirs.mosca + '/mqtt.js',
49 | to: newSettings.http.publicDirs.mosca + '/mqtt.js'
50 | }
51 | ], cp, done)
52 | }
53 |
54 | beforeEach(function (done) {
55 | settings = ponteSettings()
56 | settings.http.publicDirs = {
57 | ponte: path.join(__dirname, '.hidden'),
58 | mosca: path.join(__dirname, '.hidden')
59 | }
60 | prepare(ponteSettings(), settings, function (err) {
61 | if (err) {
62 | return done(err)
63 | }
64 | instance = ponte(settings, done)
65 | })
66 | })
67 |
68 | afterEach(function (done) {
69 | instance.close(function (err) {
70 | if (!remove()) {
71 | return done(new Error('Failed to cleanup the test artifacts'))
72 | }
73 | done(err)
74 | })
75 | })
76 |
77 | describe('with libraries inside the ' + path.join(__dirname, '.hidden directory'), function () {
78 | it('should serve the mqttws31.js file', function (done) {
79 | var file = fs.readFileSync(path.join(__dirname, '..', 'public', 'mqttws31.js'))
80 | request(instance.http.server)
81 | .get('/mqttws31.js')
82 | .expect(200, file.toString(), done)
83 | })
84 |
85 | it('should serve the mqtt.js file', function (done) {
86 | var file = fs.readFileSync(path.join(__dirname, '..', 'node_modules', 'mosca', 'public', 'mqtt.js'))
87 | request(instance.http.server)
88 | .get('/mqtt.js')
89 | .expect(200, file.toString(), done)
90 | })
91 | })
92 | })
93 |
--------------------------------------------------------------------------------
/test/mocha.opts:
--------------------------------------------------------------------------------
1 | --reporter dot
2 | --require test/common
3 | --ui bdd
4 | --growl
5 | --colors
6 | --globals s
7 |
--------------------------------------------------------------------------------
/test/mqtt.js:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2013-2017 Matteo Collina
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * and Eclipse Distribution License v1.0 which accompany this distribution.
6 | *
7 | * The Eclipse Public License is available at
8 | * http://www.eclipse.org/legal/epl-v10.html
9 | * and the Eclipse Distribution License is available at
10 | * http://www.eclipse.org/org/documents/edl-v10.php.
11 | *
12 | * Contributors:
13 | * Matteo Collina - initial API and implementation and/or initial documentation
14 | * Jovan Kostovski - added standard js for source code style checking
15 | *******************************************************************************/
16 |
17 | /* eslint-env mocha */
18 | /* global ponteSettings, expect */
19 |
20 | var request = require('supertest')
21 | var mqtt = require('mqtt')
22 | var ponte = require('../lib/ponte')
23 |
24 | describe('Ponte as an MQTT server', function () {
25 | var settings
26 | var instance
27 |
28 | describe('without auth problems', function () {
29 | beforeEach(function (done) {
30 | settings = ponteSettings()
31 | instance = ponte(settings, done)
32 | })
33 |
34 | afterEach(function (done) {
35 | instance.close(done)
36 | })
37 |
38 | function connect () {
39 | return mqtt.connect('mqtt://localhost:' + settings.mqtt.port)
40 | }
41 |
42 | it('should allow a client to publish and subscribe', function (done) {
43 | var client = connect()
44 | client
45 | .subscribe('/hello')
46 | .publish('/hello', 'world')
47 | .on('message', function (topic, payload) {
48 | expect(topic).to.eql('/hello')
49 | expect(payload.toString()).to.eql('world')
50 | done()
51 | })
52 | })
53 |
54 | it('should support wildcards', function (done) {
55 | var client = connect()
56 | client
57 | .subscribe('#')
58 | .publish('hello', 'world')
59 | .on('message', function (topic, payload) {
60 | expect(topic).to.eql('hello')
61 | expect(payload.toString()).to.eql('world')
62 | done()
63 | })
64 | })
65 |
66 | it('should expose retained messages to HTTP', function (done) {
67 | var client = connect()
68 | client
69 | .publish('hello', 'world', { retain: true, qos: 1 }, function () {
70 | request(instance.http.server)
71 | .get('/resources/hello')
72 | .expect(200, 'world', done)
73 | })
74 | })
75 |
76 | it('should expose retained messages to HTTP (double slash)', function (done) {
77 | var client = connect()
78 | client
79 | .publish('/hello', 'world', { retain: true, qos: 1 }, function () {
80 | request(instance.http.server)
81 | .get('/resources//hello')
82 | .expect(200, 'world', done)
83 | })
84 | })
85 |
86 | it("should emit an 'updated' event after a publish", function (done) {
87 | var client = connect()
88 | client.publish('/hello', 'world',
89 | { retain: true, qos: 1 },
90 | function () {
91 | client.end()
92 | })
93 |
94 | instance.on('updated', function (resource, value) {
95 | expect(resource).to.eql('/hello')
96 | expect(value).to.eql(new Buffer('world'))
97 | done()
98 | })
99 | })
100 | })
101 |
102 | describe('with auth problems', function () {
103 | beforeEach(function (done) {
104 | settings = ponteSettings()
105 |
106 | settings.mqtt.authenticate = function (client, username, password, callback) {
107 | if (username === 'authenticationError') {
108 | callback(new Error('Authentication error'))
109 | } else if (username === 'notAuthorized') {
110 | callback(null, false)
111 | } else {
112 | client.user = 'user'
113 | callback(null, true)
114 | }
115 | }
116 | settings.mqtt.authorizePublish = function (client, topic, payload, callback) {
117 | if (topic === 'unauthorizedPublish') {
118 | callback(null, false)
119 | } else {
120 | callback(null, true)
121 | }
122 | }
123 | settings.mqtt.authorizeSubscribe = function (client, topic, callback) {
124 | if (topic === 'unauthorizedSubscribe') {
125 | callback(null, false)
126 | } else {
127 | callback(null, true)
128 | }
129 | }
130 |
131 | instance = ponte(settings, done)
132 | })
133 |
134 | afterEach(function (done) {
135 | instance.close(done)
136 | })
137 |
138 | it('should throw a connection error if there is an authentication error', function (done) {
139 | var client = mqtt.connect('mqtt://localhost:' + settings.mqtt.port, {
140 | username: 'authenticationError',
141 | password: ''
142 | })
143 | client.on('connect', function () {
144 | client.end()
145 | done(new Error('Expected connection error'))
146 | })
147 | client.on('error', function (error) {
148 | client.end()
149 | expect(error.message).to.eql('Connection refused: Bad username or password')
150 | done()
151 | })
152 | })
153 |
154 | it('should throw a connection error if the user is not authorized', function (done) {
155 | var client = mqtt.connect('mqtt://localhost:' + settings.mqtt.port, {
156 | username: 'authenticationError',
157 | password: ''
158 | })
159 | client.on('connect', function () {
160 | client.end()
161 | done(new Error('Expected connection error'))
162 | })
163 | client.on('error', function (error) {
164 | client.end()
165 | expect(error.message).to.eql('Connection refused: Bad username or password')
166 | done()
167 | })
168 | })
169 |
170 | it('should close the connection if an unauthorized publish is attempted', function (done) {
171 | var client = mqtt.connect('mqtt://localhost:' + settings.mqtt.port)
172 | var error
173 | client.on('message', function () {
174 | error = new Error('Expected connection close')
175 | client.end()
176 | })
177 | var closeListener = function () {
178 | client.removeListener('close', closeListener)
179 | if (error) {
180 | done(error)
181 | } else {
182 | client.end()
183 | done()
184 | }
185 | }
186 | client.on('close', closeListener)
187 | client.subscribe('unauthorizedPublish')
188 | .publish('unauthorizedPublish', 'world')
189 | })
190 |
191 | it('should denny the subscription when an unauthorized subscribe is attempted', function (done) {
192 | var client = mqtt.connect('mqtt://localhost:' + settings.mqtt.port)
193 | client.subscribe('unauthorizedSubscribe', function (err, subscribes) {
194 | if (err) throw (err)
195 | client.end()
196 | expect(subscribes[0].qos).to.eql(0x80)
197 | done()
198 | })
199 | })
200 | })
201 | })
202 |
--------------------------------------------------------------------------------
/test/mqtt_over_websocket.js:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2013-2017 Matteo Collina
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * and Eclipse Distribution License v1.0 which accompany this distribution.
6 | *
7 | * The Eclipse Public License is available at
8 | * http://www.eclipse.org/legal/epl-v10.html
9 | * and the Eclipse Distribution License is available at
10 | * http://www.eclipse.org/org/documents/edl-v10.php.
11 | *
12 | * Contributors:
13 | * Matteo Collina - initial API and implementation and/or initial documentation
14 | * Jovan Kostovski - added standard js for source code style checking
15 | *******************************************************************************/
16 |
17 | /* eslint-env mocha */
18 | /* global ponteSettings, expect */
19 |
20 | var request = require('supertest')
21 | var mqtt = require('mqtt')
22 | var ponte = require('../lib/ponte')
23 | var fs = require('fs')
24 | var path = require('path')
25 |
26 | describe('Ponte as an MQTT-over-WebSocket server', function () {
27 | var settings
28 | var instance
29 |
30 | beforeEach(function (done) {
31 | settings = ponteSettings()
32 | instance = ponte(settings, done)
33 | })
34 |
35 | afterEach(function (done) {
36 | instance.close(done)
37 | })
38 |
39 | function connect () {
40 | return mqtt.connect('ws://localhost:' + settings.http.port)
41 | }
42 |
43 | it('should allow a client to publish and subscribe', function (done) {
44 | var client = connect()
45 | client
46 | .subscribe('/hello')
47 | .publish('/hello', 'world')
48 | .on('message', function (topic, payload) {
49 | client.end()
50 |
51 | expect(topic).to.eql('/hello')
52 | expect(payload.toString()).to.eql('world')
53 | done()
54 | })
55 | })
56 |
57 | it('should expose retained messages to HTTP', function (done) {
58 | var client = connect()
59 | client
60 | .publish('hello', 'world', { retain: true, qos: 1 }, function () {
61 | client.end()
62 |
63 | request(instance.http.server)
64 | .get('/resources/hello')
65 | .expect(200, 'world', done)
66 | })
67 | })
68 |
69 | it('should expose retained messages to HTTP (double slash)', function (done) {
70 | var client = connect()
71 | client
72 | .publish('/hello', 'world', { retain: true, qos: 1 }, function () {
73 | client.end()
74 |
75 | request(instance.http.server)
76 | .get('/resources//hello')
77 | .expect(200, 'world', done)
78 | })
79 | })
80 |
81 | it("should emit an 'updated' event after a publish", function (done) {
82 | var client = connect()
83 | client.publish('/hello', 'world',
84 | { retain: true, qos: 1 },
85 | function () {
86 | client.end()
87 | })
88 |
89 | instance.on('updated', function (resource, value) {
90 | expect(resource).to.eql('/hello')
91 | expect(value).to.eql(new Buffer('world'))
92 | done()
93 | })
94 | })
95 |
96 | describe('with the serve libraries option', function () {
97 | it('should serve the mqttws31.js file', function (done) {
98 | var file = fs.readFileSync(path.join(__dirname, '..', 'public', 'mqttws31.js'))
99 | request(instance.http.server)
100 | .get('/mqttws31.js')
101 | .expect(200, file.toString(), done)
102 | })
103 |
104 | it('should serve the mqtt.js file', function (done) {
105 | var file = fs.readFileSync(path.join(__dirname, '..', 'node_modules', 'mosca', 'public', 'mqtt.js'))
106 | request(instance.http.server)
107 | .get('/mqtt.js')
108 | .expect(200, file.toString(), done)
109 | })
110 | })
111 |
112 | describe('without the serve libraries option', function () {
113 | beforeEach(function () {
114 | settings.http.serveLibraries = false
115 | })
116 |
117 | it('should serve the mqttws31.js file', function (done) {
118 | request(instance.http.server)
119 | .get('/mqttws31.js')
120 | .expect(404, done)
121 | })
122 |
123 | it('should serve the mqtt.js file', function (done) {
124 | request(instance.http.server)
125 | .get('/mqtt.js')
126 | .expect(404, done)
127 | })
128 | })
129 | })
130 |
--------------------------------------------------------------------------------
/test/sample_config.js:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2013-2017 Matteo Collina
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * and Eclipse Distribution License v1.0 which accompany this distribution.
6 | *
7 | * The Eclipse Public License is available at
8 | * http://www.eclipse.org/legal/epl-v10.html
9 | * and the Eclipse Distribution License is available at
10 | * http://www.eclipse.org/org/documents/edl-v10.php.
11 | *
12 | * Contributors:
13 | * Matteo Collina - initial API and implementation and/or initial documentation
14 | * Jovan Kostovski - added standard js for source code style checking
15 | *******************************************************************************/
16 |
17 | module.exports = {
18 | logger: {
19 | name: 'Config Test Logger'
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/test/sample_config_mongodb.js:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2013-2017 Matteo Collina
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * and Eclipse Distribution License v1.0 which accompany this distribution.
6 | *
7 | * The Eclipse Public License is available at
8 | * http://www.eclipse.org/legal/epl-v10.html
9 | * and the Eclipse Distribution License is available at
10 | * http://www.eclipse.org/org/documents/edl-v10.php.
11 | *
12 | * Contributors:
13 | * Matteo Collina
14 | * Jovan Kostovski
15 | *******************************************************************************/
16 |
17 | module.exports = {
18 | persistence: {
19 | // same as http://mcollina.github.io/mosca/docs/lib/persistence/mongo.js.html
20 | type: 'mongo',
21 | url: 'mongodb://localhost:27017/ponte'
22 | },
23 | broker: {
24 | // same as https://github.com/mcollina/ascoltatori#mongodb
25 | type: 'mongo',
26 | url: 'mongodb://localhost:27017/ponte'
27 | },
28 | logger: {
29 | level: 20,
30 | name: 'Config Test Logger'
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/test/sample_config_mqtt_redis.js:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2013-2017 Matteo Collina
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * and Eclipse Distribution License v1.0 which accompany this distribution.
6 | *
7 | * The Eclipse Public License is available at
8 | * http://www.eclipse.org/legal/epl-v10.html
9 | * and the Eclipse Distribution License is available at
10 | * http://www.eclipse.org/org/documents/edl-v10.php.
11 | *
12 | * Contributors:
13 | * Matteo Collina
14 | * Jovan Kostovski
15 | *******************************************************************************/
16 |
17 | module.exports = {
18 | persistence: {
19 | // same as http://mcollina.github.io/mosca/docs/lib/persistence/redis.js.html
20 | type: 'redis',
21 | host: 'localhost'
22 | },
23 | broker: {
24 | // same as https://github.com/mcollina/ascoltatori#mqtt
25 | type: 'mqtt',
26 | port: '2883',
27 | host: 'localhost'
28 | },
29 | logger: {
30 | level: 20,
31 | name: 'Config Test Logger'
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/test/sample_config_redis.js:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2013-2017 Matteo Collina
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Eclipse Public License v1.0
5 | * and Eclipse Distribution License v1.0 which accompany this distribution.
6 | *
7 | * The Eclipse Public License is available at
8 | * http://www.eclipse.org/legal/epl-v10.html
9 | * and the Eclipse Distribution License is available at
10 | * http://www.eclipse.org/org/documents/edl-v10.php.
11 | *
12 | * Contributors:
13 | * Matteo Collina
14 | * Jovan Kostovski
15 | *******************************************************************************/
16 |
17 | module.exports = {
18 | persistence: {
19 | // same as http://mcollina.github.io/mosca/docs/lib/persistence/redis.js.html
20 | type: 'redis',
21 | host: 'localhost'
22 | },
23 | broker: {
24 | // same as https://github.com/mcollina/ascoltatori#redis
25 | type: 'redis',
26 | host: 'localhost'
27 | },
28 | logger: {
29 | level: 20,
30 | name: 'Config Test Logger'
31 | }
32 | }
33 |
--------------------------------------------------------------------------------