├── .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 | ![Ponte Logo](https://raw.githubusercontent.com/eclipse/ponte/master/artwork/logo-banner-white.png) 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 | ![Ponte Architecture](https://raw.githubusercontent.com/eclipse/ponte/master/architecture.png) 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 | [![Standard - JavaScript Style Guide](https://cdn.rawgit.com/feross/standard/master/badge.svg)](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 | 6 | 7 | 8 | 9 | 17 | 24 | 30 | 34 | 42 | 43 | 44 | 45 | 46 | 48 | 50 | 51 | 52 | 53 | 57 | 63 | 68 | 73 | 79 | 83 | 86 | 90 | 95 | 103 | 106 | 111 | 115 | 120 | 128 | 134 | 137 | 143 | 147 | 153 | 157 | 163 | 165 | 171 | 177 | 183 | 187 | 193 | 194 | 195 | 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 | 6 | 7 | 8 | 9 | 10 | 12 | 14 | 15 | 16 | 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.

56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /epl-v10.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Eclipse Public License - Version 1.0 8 | 25 | 26 | 27 | 28 | 29 | 30 |

Eclipse Public License - v 1.0

31 | 32 |

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):

59 | 60 | 68 | 69 |

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 |
  1. 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.
  2. 91 |
  3. 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.
  4. 93 |
  5. 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.
  6. 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 | --------------------------------------------------------------------------------