├── .eslintrc ├── .gitignore ├── .jscsrc ├── .jshintrc ├── LICENSE ├── README.md ├── index.js ├── lib ├── connection.js ├── pub.js ├── sub.js ├── task.js └── worker.js ├── package.json └── spec ├── connection.js ├── pub-sub.js ├── publisher.js ├── subscriber.js ├── task-worker.js ├── task.js ├── test.json └── worker.js /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "es6": true 4 | }, 5 | "ecmaFeatures": { 6 | "regexYFlag": true, 7 | "regexUFlag": true 8 | }, 9 | "rules": { 10 | "comma-dangle": [ 11 | 2, 12 | "never" 13 | ], 14 | "no-cond-assign": [ 15 | 2, 16 | "always" 17 | ], 18 | "no-console": 1, 19 | "no-constant-condition": 2, 20 | "no-control-regex": 2, 21 | "no-debugger": 2, 22 | "no-dupe-args": 2, 23 | "no-dupe-keys": 2, 24 | "no-duplicate-case": 2, 25 | "no-empty-character-class": 2, 26 | "no-empty": 2, 27 | "no-ex-assign": 1, 28 | "no-extra-boolean-cast": 1, 29 | "no-extra-parens": [ 30 | 2, 31 | "functions" 32 | ], 33 | "no-extra-semi": 2, 34 | "no-func-assign": 1, 35 | "no-inner-declarations": [ 36 | 2, 37 | "both" 38 | ], 39 | "no-invalid-regexp": 2, 40 | "no-irregular-whitespace": 2, 41 | "no-negated-in-lhs": 2, 42 | "no-obj-calls": 2, 43 | "no-regex-spaces": 2, 44 | "no-sparse-arrays": 2, 45 | "no-unexpected-multiline": 2, 46 | "no-unreachable": 2, 47 | "use-isnan": 2, 48 | "valid-typeof": 2, 49 | "accessor-pairs": 2, 50 | "block-scoped-var": 2, 51 | "consistent-return": 2, 52 | "curly": [ 53 | 2, 54 | "all" 55 | ], 56 | "default-case": 2, 57 | "dot-location": [ 58 | 2, 59 | "property" 60 | ], 61 | "dot-notation": 2, 62 | "eqeqeq": [ 63 | 2, 64 | "smart" 65 | ], 66 | "guard-for-in": 1, 67 | "no-alert": 1, 68 | "no-caller": 2, 69 | "no-case-declarations": 0, 70 | "no-div-regex": 2, 71 | "no-else-return": 2, 72 | "no-empty-label": 2, 73 | "no-empty-pattern": 2, 74 | "no-eq-null": 2, 75 | "no-eval": 2, 76 | "no-extend-native": 2, 77 | "no-extra-bind": 2, 78 | "no-fallthrough": 2, 79 | "no-floating-decimal": 2, 80 | "no-implicit-coercion": [2, 81 | { 82 | "boolean": true, 83 | "number": true, 84 | "string": true 85 | } 86 | ], 87 | "no-implied-eval": 2, 88 | "no-invalid-this": 2, 89 | "no-iterator": 2, 90 | "no-labels": 2, 91 | "no-lone-blocks": 2, 92 | "no-loop-func": 2, 93 | "no-magic-numbers": 1, 94 | "no-multi-spaces": 2, 95 | "no-multi-str": 2, 96 | "no-native-reassign": 2, 97 | "no-new-func": 2, 98 | "no-new-wrappers": 2, 99 | "no-new": 2, 100 | "no-octal-escape": 2, 101 | "no-octal": 2, 102 | "no-param-reassign": 2, 103 | "no-process-env": 1, 104 | "no-proto": 2, 105 | "no-redeclare": [2, { 106 | "builtinGlobals": true 107 | } 108 | ], 109 | "no-return-assign": 2, 110 | "no-script-url": 2, 111 | "no-self-compare": 2, 112 | "no-sequences": 2, 113 | "no-throw-literal": 1, 114 | "no-unused-expressions": 2, 115 | "no-useless-call": 2, 116 | "no-useless-concat": 2, 117 | "no-void": 2, 118 | "no-with": 2, 119 | "radix": 2, 120 | "vars-on-top": 2, 121 | "wrap-iife": [ 122 | 2, 123 | "outside" 124 | ], 125 | "yoda": 2, 126 | "strict": [ 127 | 2, 128 | "function" 129 | ], 130 | "no-catch-shadow": 2, 131 | "no-delete-var": 2, 132 | "no-label-var": 2, 133 | "no-shadow-restricted-names": 2, 134 | "no-shadow": [ 135 | 2, 136 | { 137 | "builtinGlobals": true 138 | } 139 | ], 140 | "no-undef-init": 2, 141 | "no-undef": 2, 142 | "no-undefined": 2, 143 | "no-unused-vars": [ 144 | 2, 145 | { 146 | "vars": "all", 147 | "args": "after-used" 148 | } 149 | ], 150 | "no-use-before-define": 2, 151 | "callback-return": 1, 152 | "handle-callback-err": 2, 153 | "no-new-require": 2, 154 | "no-path-concat": 2, 155 | "no-process-exit": 1, 156 | "no-sync": 1, 157 | "array-bracket-spacing": [ 158 | 2, 159 | "never" 160 | ], 161 | "block-spacing": [ 162 | 2, 163 | "always" 164 | ], 165 | "brace-style": [ 166 | 2, 167 | "1tbs", 168 | { 169 | "allowSingleLine": false 170 | } 171 | ], 172 | "camelcase": [ 173 | 2, 174 | { 175 | "properties": "always" 176 | } 177 | ], 178 | "comma-spacing": [ 179 | 2, 180 | { 181 | "before": false, 182 | "after": true 183 | } 184 | ], 185 | "comma-style": [ 186 | 2, 187 | "last", 188 | { 189 | "exceptions": { 190 | "VariableDeclaration": true 191 | } 192 | } 193 | ], 194 | "computed-property-spacing": [ 195 | 2, 196 | "never" 197 | ], 198 | "consistent-this": [ 199 | 2, 200 | "that" 201 | ], 202 | "eol-last": 2, 203 | "func-names": 1, 204 | "func-style": [ 205 | 1, 206 | "expression", 207 | { 208 | "allowArrowFunctions": true 209 | } 210 | ], 211 | "id-length": 1, 212 | "key-spacing": [ 213 | 2, 214 | { 215 | "beforeColon": false, 216 | "afterColon": true 217 | } 218 | ], 219 | "linebreak-style": [ 220 | 2, 221 | "unix" 222 | ], 223 | "new-cap": 2, 224 | "new-parens": 2, 225 | "newline-after-var": [ 226 | 2, 227 | "always" 228 | ], 229 | "no-array-constructor": 2, 230 | "no-bitwise": 2, 231 | "no-continue": 2, 232 | "no-lonely-if": 2, 233 | "no-mixed-spaces-and-tabs": 2, 234 | "no-multiple-empty-lines": [ 235 | 1, 236 | { 237 | "max": 2, 238 | "maxEOF": 1 239 | } 240 | ], 241 | "no-negated-condition": 1, 242 | "no-nested-ternary": 2, 243 | "no-new-object": 2, 244 | "no-plusplus": 2, 245 | "no-spaced-func": 2, 246 | "no-ternary": 0, 247 | "no-trailing-spaces": [ 248 | 2, 249 | { 250 | "skipBlankLines": false 251 | } 252 | ], 253 | "no-underscore-dangle": 2, 254 | "no-unneeded-ternary": 2, 255 | "object-curly-spacing": [ 256 | 2, 257 | "never" 258 | ], 259 | "one-var": 2, 260 | "operator-assignment": [ 261 | 2, 262 | "always" 263 | ], 264 | "operator-linebreak": [ 265 | 2, 266 | "after" 267 | ], 268 | "quote-props": 2, 269 | "quotes": [ 270 | 2, 271 | "single", 272 | "avoid-escape" 273 | ], 274 | "semi-spacing": 2, 275 | "semi": [ 276 | 2, 277 | "always" 278 | ], 279 | "space-after-keywords": [ 280 | 2, 281 | "always" 282 | ], 283 | "space-before-blocks": [ 284 | 2, 285 | "always" 286 | ], 287 | "space-before-function-paren": [ 288 | 2, 289 | "never" 290 | ], 291 | "space-before-keywords": [ 292 | 2, 293 | "always" 294 | ], 295 | "space-in-parens": [ 296 | 2, 297 | "never" 298 | ], 299 | "space-infix-ops": 2, 300 | "space-return-throw-case": 2, 301 | "space-unary-ops": [ 302 | 2, 303 | { 304 | "words": true, 305 | "nonwords": false 306 | } 307 | ], 308 | "wrap-regex": 2, 309 | "arrow-parens": [ 310 | 2, 311 | "as-needed" 312 | ], 313 | "arrow-spacing": [ 314 | 2, 315 | { 316 | "before": true, 317 | "after": true 318 | } 319 | ], 320 | "constructor-super": 2, 321 | "generator-star-spacing": [ 322 | 2, 323 | { 324 | "before": false, 325 | "after": true 326 | } 327 | ], 328 | "no-arrow-condition": 1, 329 | "no-class-assign": 2, 330 | "no-const-assign": 2, 331 | "no-dupe-class-members": 1, 332 | "no-this-before-super": 2, 333 | "no-var": 1, 334 | "object-shorthand": [ 335 | 2, 336 | "always" 337 | ], 338 | "prefer-arrow-callback": 1, 339 | "prefer-const": 1, 340 | "prefer-spread": 1, 341 | "prefer-template": 2, 342 | "require-yield": 2 343 | } 344 | } 345 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log 3 | -------------------------------------------------------------------------------- /.jscsrc: -------------------------------------------------------------------------------- 1 | { 2 | "esnext": true, 3 | "excludeFiles": [], 4 | "validateIndentation": 2, 5 | "disallowAnonymousFunctions": false, 6 | "disallowDanglingUnderscores": true, 7 | "disallowEmptyBlocks": true, 8 | "disallowFunctionDeclarations": true, 9 | "disallowImplicitTypeConversion": [ 10 | "numeric", 11 | "binary", 12 | "string" 13 | ], 14 | "disallowKeywordsOnNewLine": [ 15 | "else" 16 | ], 17 | "disallowKeywords": [ 18 | "with" 19 | ], 20 | "disallowMixedSpacesAndTabs": true, 21 | "disallowMultipleLineBreaks": true, 22 | "disallowMultipleLineStrings": true, 23 | "disallowMultipleSpaces": true, 24 | "disallowNewlineBeforeBlockStatements": true, 25 | "disallowNotOperatorsInConditionals": true, 26 | "disallowOperatorBeforeLineBreak": [ 27 | ".", 28 | "+" 29 | ], 30 | "disallowSpacesInCallExpression": true, 31 | "disallowYodaConditions": true, 32 | "requireBlocksOnNewline": true, 33 | "requireCurlyBraces": [ 34 | "if", 35 | "else", 36 | "for", 37 | "while", 38 | "do", 39 | "try", 40 | "catch", 41 | "case", 42 | "default" 43 | ], 44 | "requireDotNotation": true, 45 | "requireLineBreakAfterVariableAssignment": true, 46 | "requireLineFeedAtFileEnd": true, 47 | "requireMultipleVarDecl": true, 48 | "requireNamedUnassignedFunctions": false, 49 | "requireOperatorBeforeLineBreak": [ 50 | "?", 51 | "=", 52 | "+", 53 | "-", 54 | "/", 55 | "*", 56 | "==", 57 | "===", 58 | "!=", 59 | "!==", 60 | ">", 61 | ">=", 62 | "<", 63 | "<=" 64 | ], 65 | "requirePaddingNewLineAfterVariableDeclaration": true, 66 | "requirePaddingNewLinesAfterUseStrict": true, 67 | "requirePaddingNewLinesBeforeExport": true, 68 | "requirePaddingNewLinesInObjects": true, 69 | "requireParenthesesAroundIIFE": true, 70 | "requireQuotedKeysInObjects": true, 71 | "requireSpaceBetweenArguments": true, 72 | "requireSpacesInAnonymousFunctionExpression": { 73 | "beforeOpeningRoundBrace": true, 74 | "beforeOpeningCurlyBrace": true, 75 | "allExcept": [ 76 | "shorthand" 77 | ] 78 | }, 79 | "requireSpacesInForStatement": true, 80 | "requireSpacesInFunctionDeclaration": { 81 | "beforeOpeningCurlyBrace": true 82 | }, 83 | "disallowSpacesInFunctionDeclaration": { 84 | "beforeOpeningRoundBrace": true 85 | }, 86 | "requireSpacesInFunctionExpression": { 87 | "beforeOpeningCurlyBrace": true 88 | }, 89 | "disallowSpacesInFunctionExpression": { 90 | "beforeOpeningRoundBrace": true 91 | }, 92 | "requireSpacesInFunction": { 93 | "beforeOpeningCurlyBrace": true 94 | }, 95 | "disallowSpacesInFunction": { 96 | "beforeOpeningRoundBrace": true 97 | }, 98 | "requireSpacesInNamedFunctionExpression": { 99 | "beforeOpeningCurlyBrace": true 100 | }, 101 | "disallowSpacesInNamedFunctionExpression": { 102 | "beforeOpeningRoundBrace": true 103 | }, 104 | "safeContextKeyword": [ 105 | "that" 106 | ], 107 | "validateAlignedFunctionParameters": { 108 | "lineBreakAfterOpeningBraces": true 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "bitwise": true, 3 | "laxcomma": true, 4 | "curly": true, 5 | "eqeqeq": true, 6 | "esnext": true, 7 | "forin": true, 8 | "freeze": true, 9 | "futurehostile": true, 10 | "latedef": true, 11 | "noarg": true, 12 | "nocomma": true, 13 | "nonbsp": true, 14 | "nonew": true, 15 | "notypeof": true, 16 | "singleGroups": true, 17 | "undef": true, 18 | "unused": true, 19 | "plusplus": true 20 | } 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Dario Andrei 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | node-amqp 2 | ========== 3 | Wrapper around the [`amqplib`](https://github.com/squaremo/amqp.node) node library. 4 | 5 | The main goal of this module is to hide the actual procedures needed to establish a amqp connection instantiating objects. 6 | 7 | node-amqp is developed by [720kb](https://720kb.net). 8 | 9 | ## Requirements 10 | Node.js v5.0.0+ 11 | 12 | ## Installation 13 | 14 | This module can be installed via npm issuing: 15 | ``` 16 | $ npm install node-amqp --save 17 | ``` 18 | in your project folder. 19 | 20 | ## Usage 21 | At this moment, the module expose four objects that manage two kind of interactions between actors: 22 | - Publish/Subscribe; 23 | - Work queue. 24 | 25 | The first configuration is achieved with the `Publisher` and `Subscriber` objects; the second is achieved with `Task` and `Worker` objects. 26 | 27 | All these notify theirs connections state with events, at the moment the only usable are: 28 | - `amqp:ready`: emitted when the amqp connection and client channel are correctly instantiated and configured; 29 | - `amqp:connection-closed`: emitted when the amqp connection is closed; 30 | - `amqp:channel-close`: emitted when the client channel opened upon the amqp connection is closed. 31 | 32 | ## Examples 33 | Here are short usage examples: 34 | 35 | #### Publish/Subscribe 36 | ```js 37 | //Publish 38 | const nodeAmqp = require('node-amqp') 39 | , Publisher = nodeAmqp.Publisher 40 | , publisher = new Publisher({ 41 | 'host': '', //e.g. amqp://localhost 42 | 'exchangeName': '', //e.g. node-amqp:exchange-test 43 | 'socketOptions': {} // socket options used for example to configure ssl. Reference for this can be found at http://www.squaremobius.net/amqp.node/channel_api.html#connect 44 | }); 45 | 46 | publisher.send('a message!'); //objects must be serialized, for example in JSON 47 | ``` 48 | 49 | ```js 50 | //Publish 51 | const nodeAmqp = require('node-amqp') 52 | , Subscriber = nodeAmqp.Subscriber; 53 | 54 | class MySubscriber extends Subscriber { 55 | 56 | constructor() { 57 | super({ 58 | 'host': '', //e.g. amqp://localhost 59 | 'exchangeName': '', //e.g. node-amqp:exchange-test 60 | 'socketOptions': {} // socket options used for example to configure ssl. Reference for this can be found at http://www.squaremobius.net/amqp.node/channel_api.html#connect 61 | }); 62 | } 63 | 64 | onMessage(message) { 65 | let messageArrived = message.content.toString(); 66 | 67 | console.info(`${messageArrived} published!`); 68 | } 69 | } 70 | const subscriber = new MySubscriber(); 71 | ``` 72 | 73 | #### Work queue 74 | ```js 75 | //Producer 76 | const nodeAmqp = require('node-amqp') 77 | , Task = nodeAmqp.Task 78 | , task = new Task({ 79 | 'host': '', //e.g. amqp://localhost 80 | 'queueName': '', //e.g. node-amqp:queue-test 81 | 'socketOptions': {} // socket options used for example to configure ssl. Reference for this can be found at http://www.squaremobius.net/amqp.node/channel_api.html#connect 82 | }); 83 | 84 | task.send('a message!'); //objects must be serialized, for example in JSON 85 | ``` 86 | 87 | ```js 88 | //Consumer 89 | const nodeAmqp = require('node-amqp') 90 | , Worker = nodeAmqp.Worker 91 | , worker = new Worker({ 92 | 'host': '', //e.g. amqp://localhost 93 | 'queueName': '', //e.g. node-amqp:queue-test 94 | 'socketOptions': {} // socket options used for example to configure ssl. Reference for this can be found at http://www.squaremobius.net/amqp.node/channel_api.html#connect 95 | }); 96 | 97 | //1st approach register a consumer: 98 | worker.consume() 99 | .then(message => { 100 | worker.cancelConsumer(); //if you want to cancel the consumer call this method. 101 | let messageArrived = message.content.toString(); 102 | 103 | console.info(`${messageArrived} arrived from producer`); 104 | }) 105 | .catch(err => { 106 | 107 | throw new Error(err); 108 | }); 109 | 110 | //2nd approach query for a message: 111 | worker.receive() 112 | .then(message => { 113 | 114 | if (message) { //false if there is nothing on queue 115 | let messageArrived = message.content.toString(); 116 | 117 | console.info(`${messageArrived} present in queue`); 118 | } 119 | }) 120 | .catch(err => { 121 | 122 | throw new Error(err); 123 | }); 124 | 125 | ``` 126 | 127 | ## Contributing 128 | 129 | We will be much grateful if you help us making this project to grow up. 130 | Feel free to contribute by forking, opening issues, pull requests etc. 131 | 132 | ## License 133 | The MIT License (MIT) 134 | 135 | Copyright (c) 2015 Dario Andrei 136 | 137 | Permission is hereby granted, free of charge, to any person obtaining a copy 138 | of this software and associated documentation files (the "Software"), to deal 139 | in the Software without restriction, including without limitation the rights 140 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 141 | copies of the Software, and to permit persons to whom the Software is 142 | furnished to do so, subject to the following conditions: 143 | 144 | The above copyright notice and this permission notice shall be included in all 145 | copies or substantial portions of the Software. 146 | 147 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 148 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 149 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 150 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 151 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 152 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 153 | SOFTWARE. 154 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /*global require,module*/ 2 | (function withNode() { 3 | 'use strict'; 4 | 5 | const amqp = require('amqplib') 6 | , Publisher = require('./lib/pub')(amqp) 7 | , Subscriber = require('./lib/sub')(amqp) 8 | , Task = require('./lib/task')(amqp) 9 | , Worker = require('./lib/worker')(amqp); 10 | 11 | module.exports = { 12 | Publisher, 13 | Subscriber, 14 | Task, 15 | Worker 16 | }; 17 | }()); 18 | -------------------------------------------------------------------------------- /lib/connection.js: -------------------------------------------------------------------------------- 1 | /*global require,module*/ 2 | (function withNode() { 3 | 'use strict'; 4 | 5 | const EventEmitter = require('events') 6 | , channelSym = Symbol('channel') 7 | , fromConnectionToChannelSym = Symbol('fromConnectionToChannel') 8 | , wireUpChannelSym = Symbol('wireUpChannel') 9 | , manageError = err => { 10 | 11 | throw new Error(err); 12 | }; 13 | 14 | class AmpqConnection extends EventEmitter { 15 | 16 | constructor(amqp, amqpConfiguration) { 17 | if (!amqp) { 18 | 19 | throw new Error('amqp driver is invalid'); 20 | } 21 | 22 | if (!amqpConfiguration) { 23 | 24 | throw new Error('Amqp configurations are invalid'); 25 | } 26 | super(); 27 | this[fromConnectionToChannelSym] = connection => { 28 | 29 | if (this[channelSym]) { 30 | 31 | throw new Error('Only one channel can be managed'); 32 | } 33 | 34 | return connection.createChannel(); 35 | }; 36 | this[wireUpChannelSym] = channel => { 37 | 38 | channel.on('error', manageError); 39 | channel.on('close', () => { 40 | 41 | this.emit('amqp:channel-close'); 42 | }); 43 | 44 | channel.on('return', message => { 45 | 46 | this.emit('amqp:channel-message-returned', message); 47 | }); 48 | 49 | channel.on('drain', () => { 50 | 51 | this.emit('amqp:channel-drain'); 52 | }); 53 | 54 | this[channelSym] = channel; 55 | this.emit('amqp:channel-ready', channel); 56 | }; 57 | 58 | amqp.connect(amqpConfiguration.host, amqpConfiguration.socketOptions) 59 | .then(connection => { 60 | 61 | connection.on('error', manageError); 62 | connection.on('close', () => { 63 | 64 | this.emit('amqp:connection-closed'); 65 | }); 66 | 67 | connection.on('blocked', reason => { 68 | 69 | this.emit('amqp:connection-blocked', reason); 70 | }); 71 | 72 | connection.on('unblocked', () => { 73 | 74 | this.emit('amqp:connection-unblocked'); 75 | }); 76 | 77 | this.emit('amqp:connection-ready', connection); 78 | return connection; 79 | }) 80 | .then(this[fromConnectionToChannelSym]) 81 | .then(this[wireUpChannelSym]) 82 | .catch(manageError); 83 | } 84 | 85 | closeConnection() { 86 | 87 | if (this[channelSym] && 88 | this[channelSym].connection) { 89 | 90 | this[channelSym].connection.close(); 91 | delete this[channelSym]; 92 | } else { 93 | 94 | this.on('amqp:channel-ready', () => { 95 | 96 | this[channelSym].connection.close(); 97 | delete this[channelSym]; 98 | }); 99 | } 100 | } 101 | 102 | closeChannel() { 103 | 104 | if (this[channelSym]) { 105 | 106 | this[channelSym].close(); 107 | delete this[channelSym]; 108 | } else { 109 | 110 | this.on('amqp:channel-ready', () => { 111 | 112 | this[channelSym].close(); 113 | delete this[channelSym]; 114 | }); 115 | } 116 | } 117 | } 118 | 119 | module.exports = AmpqConnection; 120 | }()); 121 | -------------------------------------------------------------------------------- /lib/pub.js: -------------------------------------------------------------------------------- 1 | /*global global,require,module*/ 2 | (function withNode() { 3 | 'use strict'; 4 | 5 | const AmpqConnection = require('./connection') 6 | , amqpConfigurationSym = Symbol('amqpConfiguration') 7 | , channelSym = Symbol('channel'); 8 | 9 | module.exports = function exportingFunction(amqp) { 10 | 11 | class AmpqPublish extends AmpqConnection { 12 | 13 | constructor(amqpConfiguration) { 14 | 15 | super(amqp, amqpConfiguration); 16 | this[amqpConfigurationSym] = amqpConfiguration; 17 | this.on('amqp:channel-ready', channel => { 18 | 19 | this[channelSym] = channel; 20 | channel.assertExchange(amqpConfiguration.exchangeName, 'fanout', { 21 | 'durable': false 22 | }) 23 | .then(() => { 24 | 25 | this.emit('amqp:ready', channel); 26 | }) 27 | .catch(err => { 28 | 29 | throw new Error(err); 30 | }); 31 | }); 32 | } 33 | 34 | send(data) { 35 | 36 | if (!data) { 37 | 38 | throw new Error('You must provide a valid payload to send'); 39 | } 40 | const dataToSend = new global.Buffer(data); 41 | 42 | if (this[channelSym]) { 43 | 44 | this[channelSym].publish(this[amqpConfigurationSym].exchangeName, '', dataToSend); 45 | } else { 46 | 47 | this.on('amqp:ready', channel => { 48 | 49 | channel.publish(this[amqpConfigurationSym].exchangeName, '', dataToSend); 50 | }); 51 | } 52 | } 53 | } 54 | 55 | return AmpqPublish; 56 | }; 57 | }()); 58 | -------------------------------------------------------------------------------- /lib/sub.js: -------------------------------------------------------------------------------- 1 | /*global global,require,module*/ 2 | (function withNode() { 3 | 'use strict'; 4 | 5 | const AmpqConnection = require('./connection'); 6 | 7 | module.exports = function exportingFunction(amqp) { 8 | 9 | class AmpqSubscribe extends AmpqConnection { 10 | 11 | constructor(amqpConfiguration) { 12 | 13 | super(amqp, amqpConfiguration); 14 | 15 | /*eslint-disable no-undef */ 16 | /*jshint ignore:start */ 17 | if (new.target === AmpqSubscribe) { 18 | 19 | throw new TypeError('Cannot construct AmpqSubscribe instances directly'); 20 | } 21 | /*jshint ignore:end */ 22 | /*eslint-enable no-undef */ 23 | 24 | if (!this.onMessage || 25 | !(this.onMessage instanceof global.Function)) { 26 | 27 | throw new TypeError('Must override method onMessage an this must be a function'); 28 | } 29 | 30 | this.on('amqp:channel-ready', channel => { 31 | 32 | channel.assertExchange(amqpConfiguration.exchangeName, 'fanout', { 33 | 'durable': false 34 | }) 35 | .then(() => { 36 | 37 | return channel.assertQueue('', { 38 | 'exclusive': true 39 | }); 40 | }) 41 | .then(qok => { 42 | 43 | return channel.bindQueue(qok.queue, amqpConfiguration.exchangeName, '') 44 | .then(() => { 45 | 46 | return qok.queue; 47 | }); 48 | }) 49 | .then(queue => { 50 | 51 | return channel.consume(queue, this.onMessage.bind(this), { 52 | 'noAck': true 53 | }); 54 | }) 55 | .then(consumeInformations => { 56 | 57 | this.emit('amqp:ready', consumeInformations); 58 | }) 59 | .catch(err => { 60 | 61 | throw new Error(err); 62 | }); 63 | }); 64 | } 65 | } 66 | 67 | return AmpqSubscribe; 68 | }; 69 | }()); 70 | -------------------------------------------------------------------------------- /lib/task.js: -------------------------------------------------------------------------------- 1 | /*global global,require,module*/ 2 | (function withNode() { 3 | 'use strict'; 4 | 5 | const AmpqConnection = require('./connection') 6 | , amqpConfigurationSym = Symbol('amqpConfiguration') 7 | , channelSym = Symbol('channel'); 8 | 9 | module.exports = function exportingFunction(amqp) { 10 | 11 | class AmpqTask extends AmpqConnection { 12 | 13 | constructor(amqpConfiguration) { 14 | 15 | super(amqp, amqpConfiguration); 16 | this[amqpConfigurationSym] = amqpConfiguration; 17 | this.on('amqp:channel-ready', channel => { 18 | 19 | this[channelSym] = channel; 20 | channel.assertQueue(amqpConfiguration.queueName, { 21 | 'durable': true 22 | }) 23 | .then(() => { 24 | 25 | this.emit('amqp:ready', channel); 26 | }) 27 | .catch(err => { 28 | 29 | throw new Error(err); 30 | }); 31 | }); 32 | } 33 | 34 | send(data) { 35 | 36 | if (!data) { 37 | 38 | throw new Error('You must provide a valid payload to send'); 39 | } 40 | const dataToSend = new global.Buffer(data) 41 | , queueParameters = { 42 | 'deliveryMode': true 43 | }; 44 | 45 | if (this[channelSym]) { 46 | 47 | this[channelSym].sendToQueue(this[amqpConfigurationSym].queueName, dataToSend, queueParameters); 48 | } else { 49 | 50 | this.on('amqp:ready', channel => { 51 | 52 | channel.sendToQueue(this[amqpConfigurationSym].queueName, dataToSend, queueParameters); 53 | }); 54 | } 55 | } 56 | } 57 | 58 | return AmpqTask; 59 | }; 60 | }()); 61 | -------------------------------------------------------------------------------- /lib/worker.js: -------------------------------------------------------------------------------- 1 | /*global global,require,module*/ 2 | (function withNode() { 3 | 'use strict'; 4 | 5 | const AmpqConnection = require('./connection') 6 | , amqpConfigurationSym = Symbol('amqpConfiguration') 7 | , channelSym = Symbol('channel') 8 | , actualConsumerTagSym = Symbol('actualConsumerTag'); 9 | 10 | module.exports = function exportingFunction(amqp) { 11 | 12 | class AmpqWorker extends AmpqConnection { 13 | 14 | constructor(amqpConfiguration) { 15 | 16 | super(amqp, amqpConfiguration); 17 | this[amqpConfigurationSym] = amqpConfiguration; 18 | this.on('amqp:channel-ready', channel => { 19 | 20 | this[channelSym] = channel; 21 | channel.prefetch(1); 22 | channel.assertQueue(amqpConfiguration.queueName, { 23 | 'durable': true 24 | }) 25 | .then(() => { 26 | 27 | this.emit('amqp:ready', channel); 28 | }) 29 | .catch(err => { 30 | 31 | throw new Error(err); 32 | }); 33 | }); 34 | } 35 | 36 | receive() { 37 | const getMap = { 38 | 'noAck': false 39 | }; 40 | 41 | return new Promise(resolve => { 42 | 43 | if (this[channelSym]) { 44 | 45 | this[channelSym].get(this[amqpConfigurationSym].queueName, getMap) 46 | .then(message => { 47 | 48 | if (message) { 49 | 50 | resolve(message); 51 | this[channelSym].ack(message); 52 | } else { 53 | 54 | resolve(false); 55 | } 56 | }) 57 | .catch(err => { 58 | 59 | throw new Error(err); 60 | }); 61 | } else { 62 | 63 | this.on('amqp:ready', channel => { 64 | 65 | channel.get(this[amqpConfigurationSym].queueName, getMap) 66 | .then(message => { 67 | 68 | if (message) { 69 | 70 | resolve(message); 71 | channel.ack(message); 72 | } else { 73 | 74 | resolve(false); 75 | } 76 | }) 77 | .catch(err => { 78 | 79 | throw new Error(err); 80 | }); 81 | }); 82 | } 83 | }); 84 | } 85 | 86 | consume() { 87 | 88 | const consumeMap = { 89 | 'noAck': false 90 | } 91 | , onConsumeFinished = consumePayload => { 92 | 93 | if (consumePayload) { 94 | 95 | this[actualConsumerTagSym] = consumePayload.consumerTag; 96 | } 97 | }; 98 | 99 | return new global.Promise(resolve => { 100 | 101 | if (this[channelSym]) { 102 | 103 | this[channelSym].consume(this[amqpConfigurationSym].queueName, message => { 104 | 105 | resolve(message); 106 | this[channelSym].ack(message); 107 | }, consumeMap) 108 | .then(onConsumeFinished) 109 | .catch(err => { 110 | 111 | throw new Error(err); 112 | }); 113 | } else { 114 | 115 | this.on('amqp:ready', channel => { 116 | 117 | channel.consume(this[amqpConfigurationSym].queueName, message => { 118 | 119 | resolve(message); 120 | channel.ack(message); 121 | }, consumeMap) 122 | .then(onConsumeFinished) 123 | .catch(err => { 124 | 125 | throw new Error(err); 126 | }); 127 | }); 128 | } 129 | }); 130 | } 131 | 132 | cancelConsumer() { 133 | 134 | if (this[channelSym]) { 135 | 136 | if (this[actualConsumerTagSym]) { 137 | 138 | this[channelSym].cancel(this[actualConsumerTagSym]); 139 | } 140 | } else { 141 | 142 | this.on('amqp:ready', channel => { 143 | 144 | if (this[actualConsumerTagSym]) { 145 | 146 | channel.cancel(this[actualConsumerTagSym]); 147 | } 148 | }); 149 | } 150 | } 151 | 152 | send(data) { 153 | 154 | if (!data) { 155 | 156 | throw new Error('You must provide a valid payload to send'); 157 | } 158 | const dataToSend = new global.Buffer(data) 159 | , queueParameters = { 160 | 'deliveryMode': true 161 | }; 162 | 163 | if (this[channelSym]) { 164 | 165 | this[channelSym].sendToQueue(this[amqpConfigurationSym].queueName, dataToSend, queueParameters); 166 | } else { 167 | 168 | this.on('amqp:ready', channel => { 169 | 170 | channel.sendToQueue(this[amqpConfigurationSym].queueName, dataToSend, queueParameters); 171 | }); 172 | } 173 | } 174 | } 175 | 176 | return AmpqWorker; 177 | }; 178 | }()); 179 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-amqp", 3 | "version": "1.2.1", 4 | "description": "a wrap upon amqplib", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/wouldgo/node-amqp" 9 | }, 10 | "scripts": { 11 | "lint": "eslint -c .eslintrc index.js && jshint -c .jshintrc --reporter=unix index.js && jscs -c .jscsrc index.js", 12 | "precommit": "npm run-script lint && npm test", 13 | "preversion": "npm run-script lint && npm test", 14 | "version": "git add -A .", 15 | "postversion": "git push && git push --tags", 16 | "test": "lab --debug --verbose --colors spec/*.js" 17 | }, 18 | "author": { 19 | "name": "Dario Andrei", 20 | "email": "wouldgo84@gmail.com", 21 | "url": "https://github.com/wouldgo" 22 | }, 23 | "contributors": [ 24 | { 25 | "name": "Filippo Oretti", 26 | "email": "filippo.oretti@gmail.com", 27 | "url": "https://github.com/45kb" 28 | } 29 | ], 30 | "license": "MIT", 31 | "dependencies": { 32 | "amqplib": "^0.4.0" 33 | }, 34 | "devDependencies": { 35 | "code": "^2.1.0", 36 | "eslint": "^1.10.3", 37 | "husky": "^0.10.2", 38 | "jscs": "^2.8.0", 39 | "jshint": "^2.8.0", 40 | "lab": "^8.2.0" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /spec/connection.js: -------------------------------------------------------------------------------- 1 | /*global module,require*/ 2 | (function testing() { 3 | 'use strict'; 4 | 5 | const code = require('code') 6 | , lab = require('lab').script() 7 | , describe = lab.describe 8 | , it = lab.it 9 | , before = lab.before 10 | , expect = code.expect 11 | , testingConfigurations = require('./test.json') 12 | , amqp = require('amqplib') 13 | , Connection = require('../lib/connection'); 14 | 15 | describe('node-amqp connection is correctly instantiated', () => { 16 | let taskMethods; 17 | 18 | before(done => { 19 | 20 | taskMethods = Object.getOwnPropertyNames(Connection.prototype); 21 | done(); 22 | }); 23 | 24 | it('should Connection class must have declared methods', done => { 25 | 26 | expect(taskMethods).to.only.include([ 27 | 'constructor', 28 | 'closeConnection', 29 | 'closeChannel']); 30 | done(); 31 | }); 32 | 33 | it('should instantiate Connection', done => { 34 | const connection = new Connection(amqp, testingConfigurations); 35 | 36 | expect(connection).to.not.be.undefined(); 37 | expect(connection).to.be.an.object(); 38 | expect(connection).to.be.an.instanceof(Connection); 39 | 40 | taskMethods.forEach(anElement => { 41 | 42 | expect(connection[anElement]).to.be.a.function(); 43 | }); 44 | 45 | connection.closeConnection(); 46 | done(); 47 | }); 48 | 49 | it('should instantiate Connection and close connection', done => { 50 | const connection = new Connection(amqp, testingConfigurations); 51 | 52 | connection.on('amqp:connection-closed', () => { 53 | 54 | done(); 55 | }); 56 | connection.closeConnection(); 57 | }); 58 | 59 | it('should instantiate Connection and close channel', done => { 60 | const connection = new Connection(amqp, testingConfigurations); 61 | 62 | connection.on('amqp:channel-close', () => { 63 | 64 | connection.closeConnection(); 65 | done(); 66 | }); 67 | connection.closeChannel(); 68 | }); 69 | 70 | }); 71 | 72 | module.exports = { 73 | lab 74 | }; 75 | }()); 76 | -------------------------------------------------------------------------------- /spec/pub-sub.js: -------------------------------------------------------------------------------- 1 | /*global module,require,global*/ 2 | (function testing() { 3 | 'use strict'; 4 | 5 | const code = require('code') 6 | , lab = require('lab').script() 7 | , describe = lab.describe 8 | , it = lab.it 9 | , before = lab.before 10 | , after = lab.after 11 | , expect = code.expect 12 | , testingConfigurations = require('./test.json') 13 | , nodeAmqp = require('..') 14 | , Publisher = nodeAmqp.Publisher 15 | , Subscriber = nodeAmqp.Subscriber 16 | , exchangedMessage = JSON.stringify({ 17 | 'message': 'hello' 18 | }) 19 | , retryTimeoutMillisec = 20; 20 | 21 | class MySubscriber extends Subscriber { 22 | 23 | constructor() { 24 | super(testingConfigurations); 25 | } 26 | 27 | onMessage(message) { 28 | const messageArrived = message.content.toString(); 29 | 30 | expect(messageArrived).to.be.equal(exchangedMessage); 31 | this.emit('test:finished'); 32 | } 33 | } 34 | 35 | describe('node-amqp publisher talks to subscriber', () => { 36 | const publisher = new Publisher(testingConfigurations) 37 | , subscriber = new MySubscriber(); 38 | let subFinished = false 39 | , pubFinished = false; 40 | 41 | subscriber.on('amqp:ready', () => { 42 | 43 | if (!subFinished) { 44 | 45 | subFinished = true; 46 | } 47 | }); 48 | 49 | publisher.on('amqp:ready', () => { 50 | 51 | if (!pubFinished) { 52 | 53 | pubFinished = true; 54 | } 55 | }); 56 | 57 | subscriber.on('amqp:connection-closed', () => { 58 | 59 | if (subFinished) { 60 | 61 | subFinished = false; 62 | } 63 | }); 64 | 65 | publisher.on('amqp:connection-closed', () => { 66 | 67 | if (pubFinished) { 68 | 69 | pubFinished = false; 70 | } 71 | }); 72 | 73 | before(done => { 74 | 75 | const onTimeoutTrigger = () => { 76 | 77 | if (pubFinished && 78 | subFinished) { 79 | 80 | done(); 81 | } else { 82 | 83 | global.setTimeout(onTimeoutTrigger, retryTimeoutMillisec); 84 | } 85 | }; 86 | 87 | onTimeoutTrigger(); 88 | }); 89 | 90 | after(done => { 91 | 92 | const onTimeoutTrigger = () => { 93 | 94 | if (!pubFinished && 95 | !subFinished) { 96 | 97 | done(); 98 | } else { 99 | 100 | global.setTimeout(onTimeoutTrigger, retryTimeoutMillisec); 101 | } 102 | }; 103 | 104 | onTimeoutTrigger(); 105 | subscriber.closeConnection(); 106 | publisher.closeConnection(); 107 | }); 108 | 109 | it('should publish a message and recieve', done => { 110 | 111 | subscriber.once('test:finished', () => { 112 | 113 | done(); 114 | }); 115 | publisher.send(exchangedMessage); 116 | }); 117 | }); 118 | 119 | module.exports = { 120 | lab 121 | }; 122 | }()); 123 | -------------------------------------------------------------------------------- /spec/publisher.js: -------------------------------------------------------------------------------- 1 | /*global module,require,global*/ 2 | (function testing() { 3 | 'use strict'; 4 | 5 | const code = require('code') 6 | , lab = require('lab').script() 7 | , describe = lab.describe 8 | , it = lab.it 9 | , before = lab.before 10 | , after = lab.after 11 | , expect = code.expect 12 | , testingConfigurations = require('./test.json') 13 | , nodeAmqp = require('..') 14 | , Publisher = nodeAmqp.Publisher 15 | , retryTimeoutMillisec = 20; 16 | 17 | describe('node-amqp publisher is correctly instantiated', () => { 18 | const publisher = new Publisher(testingConfigurations) 19 | , publisherMethods = Object.getOwnPropertyNames(Publisher.prototype); 20 | let publisherFinished = false; 21 | 22 | publisher.on('amqp:ready', () => { 23 | 24 | if (!publisherFinished) { 25 | 26 | publisherFinished = true; 27 | } 28 | }); 29 | 30 | publisher.on('amqp:connection-closed', () => { 31 | 32 | if (publisherFinished) { 33 | 34 | publisherFinished = false; 35 | } 36 | }); 37 | 38 | before(done => { 39 | const onTimeoutTrigger = () => { 40 | 41 | if (publisherFinished) { 42 | 43 | done(); 44 | } else { 45 | 46 | global.setTimeout(onTimeoutTrigger, retryTimeoutMillisec); 47 | } 48 | }; 49 | 50 | onTimeoutTrigger(); 51 | }); 52 | 53 | after(done => { 54 | const onTimeoutTrigger = () => { 55 | 56 | if (publisherFinished) { 57 | 58 | global.setTimeout(onTimeoutTrigger, retryTimeoutMillisec); 59 | } else { 60 | 61 | done(); 62 | } 63 | }; 64 | 65 | onTimeoutTrigger(); 66 | publisher.closeConnection(); 67 | }); 68 | 69 | it('should Publisher class must have declared methods', done => { 70 | 71 | expect(publisherMethods).to.only.include([ 72 | 'constructor', 73 | 'send']); 74 | done(); 75 | }); 76 | 77 | it('should instantiate Publisher', done => { 78 | 79 | expect(publisher).to.not.be.undefined(); 80 | expect(publisher).to.be.an.object(); 81 | expect(publisher).to.be.an.instanceof(Publisher); 82 | 83 | publisherMethods.forEach(anElement => { 84 | 85 | expect(publisher[anElement]).to.be.a.function(); 86 | }); 87 | 88 | publisher.closeConnection(); 89 | done(); 90 | }); 91 | }); 92 | 93 | module.exports = { 94 | lab 95 | }; 96 | }(module, require, global)); 97 | -------------------------------------------------------------------------------- /spec/subscriber.js: -------------------------------------------------------------------------------- 1 | /*global module,require,global*/ 2 | (function testing() { 3 | 'use strict'; 4 | 5 | const code = require('code') 6 | , lab = require('lab').script() 7 | , describe = lab.describe 8 | , it = lab.it 9 | , before = lab.before 10 | , after = lab.after 11 | , expect = code.expect 12 | , testingConfigurations = require('./test.json') 13 | , nodeAmqp = require('..') 14 | , Subscriber = nodeAmqp.Subscriber 15 | , retryTimeoutMillisec = 20; 16 | 17 | class MySubscriber extends Subscriber { 18 | 19 | constructor() { 20 | super(testingConfigurations); 21 | } 22 | 23 | onMessage() { 24 | } 25 | } 26 | 27 | describe('node-amqp subscriber is correctly instantiated', () => { 28 | const mySubscriber = new MySubscriber() 29 | , subscriberMethods = Object.getOwnPropertyNames(Subscriber.prototype); 30 | let subscriberFinished = false; 31 | 32 | mySubscriber.on('amqp:ready', () => { 33 | 34 | if (!subscriberFinished) { 35 | 36 | subscriberFinished = true; 37 | } 38 | }); 39 | 40 | mySubscriber.on('amqp:connection-closed', () => { 41 | 42 | if (subscriberFinished) { 43 | 44 | subscriberFinished = false; 45 | } 46 | }); 47 | 48 | before(done => { 49 | const onTimeoutTrigger = () => { 50 | 51 | if (subscriberFinished) { 52 | 53 | done(); 54 | } else { 55 | 56 | global.setTimeout(onTimeoutTrigger, retryTimeoutMillisec); 57 | } 58 | }; 59 | 60 | onTimeoutTrigger(); 61 | }); 62 | 63 | after(done => { 64 | const onTimeoutTrigger = () => { 65 | 66 | if (subscriberFinished) { 67 | 68 | global.setTimeout(onTimeoutTrigger, retryTimeoutMillisec); 69 | } else { 70 | 71 | done(); 72 | } 73 | }; 74 | 75 | onTimeoutTrigger(); 76 | mySubscriber.closeConnection(); 77 | }); 78 | 79 | it('should Subscriber class must have declared methods', done => { 80 | 81 | expect(subscriberMethods).to.only.include([ 82 | 'constructor' 83 | ]); 84 | done(); 85 | }); 86 | 87 | it('should not instantiate subscriber directly (it\'s an abstract class)', done => { 88 | let subscriber; 89 | 90 | try { 91 | subscriber = new Subscriber(testingConfigurations); 92 | 93 | expect(subscriber).to.be.undefined(); 94 | } catch (err) { 95 | 96 | expect(err).to.be.an.instanceof(Error); 97 | } finally { 98 | 99 | if (subscriber) { 100 | 101 | subscriber.closeConnection(); 102 | } 103 | done(); 104 | } 105 | }); 106 | 107 | it('should instantiate subscriber sub class', done => { 108 | 109 | expect(mySubscriber).to.not.be.undefined(); 110 | expect(mySubscriber).to.be.an.object(); 111 | expect(mySubscriber).to.be.an.instanceof(Subscriber); 112 | 113 | subscriberMethods.forEach(anElement => { 114 | 115 | expect(mySubscriber[anElement]).to.be.a.function(); 116 | }); 117 | 118 | expect(mySubscriber.onMessage).to.be.a.function(); 119 | 120 | mySubscriber.closeConnection(); 121 | done(); 122 | }); 123 | }); 124 | 125 | module.exports = { 126 | lab 127 | }; 128 | }()); 129 | -------------------------------------------------------------------------------- /spec/task-worker.js: -------------------------------------------------------------------------------- 1 | /*global module,require,global*/ 2 | (function testing() { 3 | 'use strict'; 4 | 5 | const code = require('code') 6 | , amqp = require('amqplib') 7 | , lab = require('lab').script() 8 | , describe = lab.describe 9 | , it = lab.it 10 | , before = lab.before 11 | , after = lab.after 12 | , expect = code.expect 13 | , testingConfigurations = require('./test.json') 14 | , nodeAmqp = require('..') 15 | , Task = nodeAmqp.Task 16 | , Worker = nodeAmqp.Worker 17 | , exchangedMessage = JSON.stringify({ 18 | 'first': 'first' 19 | }) 20 | , secondExchangedMessage = JSON.stringify({ 21 | 'second': 'second' 22 | }) 23 | , retryTimeoutMillisec = 20; 24 | 25 | describe('node-amqp task talks to worker', () => { 26 | const task = new Task(testingConfigurations) 27 | , worker = new Worker(testingConfigurations); 28 | let taskFinished = false 29 | , workerFinished = false; 30 | 31 | task.on('amqp:ready', () => { 32 | 33 | if (!taskFinished) { 34 | 35 | taskFinished = true; 36 | } 37 | }); 38 | 39 | worker.on('amqp:ready', () => { 40 | 41 | if (!workerFinished) { 42 | 43 | workerFinished = true; 44 | } 45 | }); 46 | 47 | task.on('amqp:connection-closed', () => { 48 | 49 | if (taskFinished) { 50 | 51 | taskFinished = false; 52 | } 53 | }); 54 | 55 | worker.on('amqp:connection-closed', () => { 56 | 57 | if (workerFinished) { 58 | 59 | workerFinished = false; 60 | } 61 | }); 62 | 63 | before(done => { 64 | const onTimeoutTrigger = () => { 65 | 66 | if (workerFinished && 67 | taskFinished) { 68 | 69 | done(); 70 | } else { 71 | 72 | global.setTimeout(onTimeoutTrigger, retryTimeoutMillisec); 73 | } 74 | }; 75 | 76 | onTimeoutTrigger(); 77 | }); 78 | 79 | after(done => { 80 | const onTimeoutTrigger = () => { 81 | 82 | if (!workerFinished && 83 | !taskFinished) { 84 | 85 | amqp.connect(testingConfigurations.host, testingConfigurations.socketOptions) 86 | .then(connection => { 87 | 88 | return connection.createChannel(); 89 | }) 90 | .then(channel => { 91 | 92 | channel.deleteQueue(testingConfigurations.queueName) 93 | .then(() => { 94 | 95 | channel.connection.close(); 96 | done(); 97 | }); 98 | }); 99 | } else { 100 | 101 | global.setTimeout(onTimeoutTrigger, retryTimeoutMillisec); 102 | } 103 | }; 104 | 105 | onTimeoutTrigger(); 106 | task.closeConnection(); 107 | worker.closeConnection(); 108 | }); 109 | 110 | it('should send and manage a message', done => { 111 | 112 | worker.consume() 113 | .then(message => { 114 | worker.cancelConsumer(); 115 | const messageArrived = message.content.toString(); 116 | 117 | expect(messageArrived).to.be.equal(exchangedMessage); 118 | done(); 119 | }) 120 | .catch(err => { 121 | 122 | done(err); 123 | }); 124 | 125 | task.send(exchangedMessage); 126 | }); 127 | 128 | it('should send and get a message', done => { 129 | 130 | worker.receive() 131 | .then(message => { 132 | 133 | expect(message).to.be.equal(false); 134 | task.send(secondExchangedMessage); 135 | global.setTimeout(() => { 136 | 137 | worker.receive() 138 | .then(anotherMsg => { 139 | const messageArrived = anotherMsg.content.toString(); 140 | 141 | expect(messageArrived).to.be.equal(secondExchangedMessage); 142 | done(); 143 | }) 144 | .catch(err => { 145 | 146 | done(err); 147 | }); 148 | }, 0); 149 | }) 150 | .catch(err => { 151 | 152 | done(err); 153 | }); 154 | }); 155 | }); 156 | 157 | module.exports = { 158 | lab 159 | }; 160 | }()); 161 | -------------------------------------------------------------------------------- /spec/task.js: -------------------------------------------------------------------------------- 1 | /*global module,require*/ 2 | (function testing() { 3 | 'use strict'; 4 | 5 | const code = require('code') 6 | , lab = require('lab').script() 7 | , describe = lab.describe 8 | , it = lab.it 9 | , before = lab.before 10 | , expect = code.expect 11 | , testingConfigurations = require('./test.json') 12 | , nodeAmqp = require('..') 13 | , Task = nodeAmqp.Task; 14 | 15 | describe('node-amqp task is correctly instantiated', () => { 16 | let taskMethods; 17 | 18 | before(done => { 19 | 20 | taskMethods = Object.getOwnPropertyNames(Task.prototype); 21 | done(); 22 | }); 23 | 24 | it('should Task class must have declared methods', done => { 25 | 26 | expect(taskMethods).to.only.include([ 27 | 'constructor', 28 | 'send']); 29 | done(); 30 | }); 31 | 32 | it('should instantiate Task', done => { 33 | const task = new Task(testingConfigurations); 34 | 35 | expect(task).to.not.be.undefined(); 36 | expect(task).to.be.an.object(); 37 | expect(task).to.be.an.instanceof(Task); 38 | 39 | taskMethods.forEach(anElement => { 40 | 41 | expect(task[anElement]).to.be.a.function(); 42 | }); 43 | 44 | task.closeConnection(); 45 | done(); 46 | }); 47 | }); 48 | 49 | module.exports = { 50 | lab 51 | }; 52 | }()); 53 | -------------------------------------------------------------------------------- /spec/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "host": "amqp://localhost", 3 | "exchangeName": "node-amqp:exchange-test", 4 | "queueName": "node-amqp:queue-test", 5 | "socketOptions": {} 6 | } 7 | -------------------------------------------------------------------------------- /spec/worker.js: -------------------------------------------------------------------------------- 1 | /*global module,require*/ 2 | (function testing() { 3 | 'use strict'; 4 | 5 | const code = require('code') 6 | , lab = require('lab').script() 7 | , describe = lab.describe 8 | , it = lab.it 9 | , before = lab.before 10 | , expect = code.expect 11 | , testingConfigurations = require('./test.json') 12 | , nodeAmqp = require('..') 13 | , Worker = nodeAmqp.Worker; 14 | 15 | describe('node-amqp worker is correctly instantiated', () => { 16 | let workerMethods; 17 | 18 | before(done => { 19 | 20 | workerMethods = Object.getOwnPropertyNames(Worker.prototype); 21 | done(); 22 | }); 23 | 24 | it('should Worker class must have declared methods', done => { 25 | 26 | expect(workerMethods).to.only.include([ 27 | 'constructor', 28 | 'receive', 29 | 'consume', 30 | 'send', 31 | 'cancelConsumer']); 32 | done(); 33 | }); 34 | 35 | it('should instantiate Worker', done => { 36 | const worker = new Worker(testingConfigurations); 37 | 38 | expect(worker).to.not.be.undefined(); 39 | expect(worker).to.be.an.object(); 40 | expect(worker).to.be.an.instanceof(Worker); 41 | 42 | workerMethods.forEach(anElement => { 43 | 44 | expect(worker[anElement]).to.be.a.function(); 45 | }); 46 | 47 | worker.closeConnection(); 48 | done(); 49 | }); 50 | }); 51 | 52 | module.exports = { 53 | lab 54 | }; 55 | }()); 56 | --------------------------------------------------------------------------------