├── docs ├── bg.png ├── index.html ├── stomp-exceptions.html ├── stomp-utils.html ├── rocco.css ├── frame.html └── stomp.html ├── lib ├── stomp-exceptions.js ├── stomp-utils.js ├── frame.js └── stomp.js ├── paige.config ├── README.md ├── package.json ├── LICENSE ├── examples ├── stomp-producer-txn.js ├── stomp-producer.js └── stomp-consumer.js └── test └── test-frame.js /docs/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benjaminws/stomp-js/HEAD/docs/bg.png -------------------------------------------------------------------------------- /lib/stomp-exceptions.js: -------------------------------------------------------------------------------- 1 | var QueueEmpty = exports.QueueEmpty = function() { 2 | this.name = "QueueEmpty"; 3 | this.message = "Queue is Empty"; 4 | }; 5 | 6 | QueueEmpty.prototype.toString = function() { 7 | return this.message; 8 | }; 9 | -------------------------------------------------------------------------------- /paige.config: -------------------------------------------------------------------------------- 1 | { 2 | "title" : "stomp-js", 3 | "content_file" : "README.md", 4 | "include_index" : true, 5 | "docco_files" : "lib/*.js", 6 | "header" : "stomp-js", 7 | "subheader" : "Implementation of the STOMP protocol in node.js", 8 | "background" : "diagonal-noise", 9 | "github" : "https://github.com/benjaminws/stomp-js" 10 | } 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | stomp-js 2 | ======== 3 | 4 | ## Overview 5 | 6 | An exercise with node.js to implement the STOMP protocol. 7 | 8 | For documentation see http://benjaminws.github.com/stomp-js/ 9 | 10 | ## Installation 11 | 12 | `npm install stomp` 13 | 14 | `git clone https://benjaminws@github.com/benjaminws/stomp-js.git` 15 | 16 | ## Examples 17 | 18 | ### Consumer 19 | 20 | See examples/stomp-consumer.js 21 | 22 | ### Producer 23 | 24 | See examples/stomp-producer.js 25 | 26 | ### Producer with Transaction Support 27 | 28 | See examples/stomp-producer-txn.js 29 | 30 | ### Contributors 31 | 32 | rofflwaffls -at- gmail.com 33 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "stomp", 3 | "description": "Implementation of the STOMP protocol in node.js", 4 | "keywords": [ "STOMP", "messaging", "queue", "protocol" ], 5 | "version": "v0.1.1", 6 | "homepage": "https://github.com/benjaminws/stomp-js", 7 | "author": "Benjamin W. Smith ", 8 | "contributors" : [ "rofflwaffls@gmail.com" ], 9 | "main" : "lib/stomp", 10 | "repository" : { 11 | "type" : "git", 12 | "url" : "https://benjaminws@github.com/benjaminws/stomp-js.git" 13 | }, 14 | "directories" : { 15 | "lib": "./lib", 16 | "examples": "./examples" 17 | }, 18 | "licenses" : [{ 19 | "type" : "BSD", 20 | "url" : "https://github.com/benjaminws/stomp-js/raw/master/LICENSE" 21 | }] 22 | } 23 | -------------------------------------------------------------------------------- /lib/stomp-utils.js: -------------------------------------------------------------------------------- 1 | var exceptions = require('./stomp-exceptions'); 2 | var sys = require('util'); 3 | 4 | var StompLogging = exports.StompLogging = function(should_debug) { 5 | this.should_debug = should_debug; 6 | }; 7 | 8 | StompLogging.prototype.debug = function(message) { 9 | if (this.should_debug) { 10 | console.log("debug: " + message); 11 | } 12 | }; 13 | 14 | StompLogging.prototype.warn = function(message) { 15 | console.log("warn: " + message); 16 | }; 17 | 18 | StompLogging.prototype.error = function(message, die) { 19 | console.log("error: " + message); 20 | if (die) { 21 | process.exit(1); 22 | } 23 | }; 24 | 25 | StompLogging.prototype.die = function(message) { 26 | this.error(message, true); 27 | }; 28 | 29 | var StompUtils = exports.StompUtils = function() { 30 | this.available_utils = []; 31 | }; 32 | 33 | StompUtils.prototype.really_defined = function(var_to_test) { 34 | return !(var_to_test == null || var_to_test == undefined); 35 | }; 36 | 37 | StompUtils.prototype.extend = function(destination, source) { 38 | for (var property in source) { 39 | destination[property] = source[property]; 40 | } 41 | return destination; 42 | }; 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010, Benjamin W. Smith 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or 8 | other materials provided with the distribution. 9 | * Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software 10 | without specific prior written permission. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 13 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 14 | COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 15 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 16 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 17 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 | -------------------------------------------------------------------------------- /examples/stomp-producer-txn.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | // Same as stomp-producer.js, but transactional 3 | 4 | var stomp = require('stomp'); 5 | 6 | var num = process.argv[2]; 7 | 8 | // Set to true if you want a receipt 9 | // of all messages sent. 10 | var receipt = false; 11 | 12 | // Set debug to true for more verbose output. 13 | // login and passcode are optional (required by rabbitMQ) 14 | var stomp_args = { 15 | port: 61613, 16 | host: 'localhost', 17 | debug: true, 18 | login: 'guest', 19 | passcode: 'guest', 20 | } 21 | 22 | var client = new stomp.Stomp(stomp_args); 23 | 24 | var queue = '/queue/test_stomp'; 25 | 26 | client.connect(); 27 | 28 | client.on('connected', function() { 29 | num = num || 1000; 30 | for (var i = 0; i < num; i++) { 31 | txn = client.begin(); 32 | client.send({ 33 | 'destination': queue, 34 | 'body': 'Testing' + i, 35 | 'persistent': 'true', 36 | 'transaction': txn 37 | }, receipt); 38 | client.commit(txn); 39 | //client.abort(txn); 40 | } 41 | console.log('Produced ' + num + ' messages'); 42 | client.disconnect(); 43 | }); 44 | 45 | client.on('receipt', function(receipt) { 46 | console.log("RECEIPT: " + receipt); 47 | }); 48 | 49 | client.on('error', function(error_frame) { 50 | console.log(error_frame.body); 51 | client.disconnect(); 52 | }); 53 | 54 | process.on('SIGINT', function() { 55 | console.log('Produced ' + num + ' messages'); 56 | client.disconnect(); 57 | process.exit(0); 58 | }); 59 | -------------------------------------------------------------------------------- /examples/stomp-producer.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var stomp = require('stomp'); 4 | 5 | var num = process.argv[2]; 6 | 7 | // Set to true if you want a receipt 8 | // of all messages sent. 9 | var receipt = true; 10 | 11 | // Set debug to true for more verbose output. 12 | // login and passcode are optional (required by rabbitMQ) 13 | var stomp_args = { 14 | port: 61613, 15 | host: 'localhost', 16 | debug: false, 17 | login: 'guest', 18 | passcode: 'guest', 19 | } 20 | 21 | var client = new stomp.Stomp(stomp_args); 22 | 23 | var queue = '/queue/test_stomp'; 24 | 25 | client.connect(); 26 | 27 | function sleep(milliSeconds) { 28 | var startTime = new Date().getTime(); 29 | while (new Date().getTime() < startTime + milliSeconds); 30 | } 31 | 32 | client.on('connected', function() { 33 | num = num || 1000; 34 | for (var i = 0; i < num; i++) { 35 | client.send({ 36 | 'destination': queue, 37 | 'body': 'Testing\n\ntesting1\n\ntesting2 ' + i, 38 | 'persistent': 'true' 39 | }, receipt); 40 | sleep(250); 41 | } 42 | console.log('Produced ' + num + ' messages'); 43 | client.disconnect(); 44 | }); 45 | 46 | client.on('receipt', function(receipt) { 47 | console.log("RECEIPT: " + receipt); 48 | }); 49 | 50 | client.on('error', function(error_frame) { 51 | console.log(error_frame.body); 52 | client.disconnect(); 53 | }); 54 | 55 | process.on('SIGINT', function() { 56 | console.log('Produced ' + num + ' messages'); 57 | client.disconnect(); 58 | process.exit(0); 59 | }); 60 | -------------------------------------------------------------------------------- /examples/stomp-consumer.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var sys = require('util'); 4 | var stomp = require('stomp'); 5 | 6 | // Set debug to true for more verbose output. 7 | // login and passcode are optional (required by rabbitMQ) 8 | var stomp_args = { 9 | port: 61613, 10 | host: 'localhost', 11 | debug: false, 12 | login: 'guest', 13 | passcode: 'guest', 14 | }; 15 | 16 | var client = new stomp.Stomp(stomp_args); 17 | 18 | // 'activemq.prefetchSize' is optional. 19 | // Specified number will 'fetch' that many messages 20 | // and dump it to the client. 21 | var headers = { 22 | destination: '/queue/test_stomp', 23 | ack: 'client', 24 | // 'activemq.prefetchSize': '10' 25 | }; 26 | 27 | var messages = 0; 28 | 29 | client.connect(); 30 | 31 | function message_callback(body, headers) { 32 | console.log('Message Callback Fired!'); 33 | console.log('Headers: ' + sys.inspect(headers)); 34 | console.log('Body: ' + body); 35 | } 36 | 37 | client.on('connected', function() { 38 | client.subscribe(headers, message_callback); 39 | console.log('Connected'); 40 | }); 41 | 42 | client.on('message', function(message) { 43 | //console.log("HEADERS: " + sys.inspect(message.headers)); 44 | //console.log("BODY: " + message.body); 45 | console.log("Got message: " + message.headers['message-id']); 46 | client.ack(message.headers['message-id']); 47 | messages++; 48 | }); 49 | 50 | client.on('error', function(error_frame) { 51 | console.log(error_frame.body); 52 | client.disconnect(); 53 | }); 54 | 55 | process.on('SIGINT', function() { 56 | console.log('\nConsumed ' + messages + ' messages'); 57 | client.disconnect(); 58 | }); 59 | -------------------------------------------------------------------------------- /test/test-frame.js: -------------------------------------------------------------------------------- 1 | var stomp = require("stomp"); 2 | var testCase = require("nodeunit/nodeunit").testCase; 3 | 4 | module.exports['initialize'] = testCase({ 5 | setUp: function (callback) { 6 | var stomp_args = { 7 | port: 61613, 8 | host: 'localhost', 9 | debug: false, 10 | login: 'guest', 11 | passcode: 'guest', 12 | }; 13 | 14 | this.client = new stomp.Stomp(stomp_args); 15 | callback(); 16 | }, 17 | tearDown: function (callback) { 18 | callback(); 19 | }, 20 | 'port is 61613': function(test) { 21 | test.equal(this.client.port, 61613); 22 | test.done(); 23 | }, 24 | 'host is localhost': function(test) { 25 | test.equal(this.client.host, 'localhost'); 26 | test.done(); 27 | }, 28 | 'debug is false': function(test) { 29 | test.equal(this.client.debug, false); 30 | test.done(); 31 | }, 32 | 'login is guest': function(test) { 33 | test.equal(this.client.login, 'guest'); 34 | test.done(); 35 | }, 36 | 'passcode is guest': function(test) { 37 | test.equal(this.client.passcode, 'guest'); 38 | test.done(); 39 | } 40 | }); 41 | module.exports['connect'] = testCase({ 42 | setUp: function (callback) { 43 | var stomp_args = { 44 | port: 61613, 45 | host: 'localhost', 46 | debug: false, 47 | login: 'guest', 48 | passcode: 'guest', 49 | }; 50 | this.client = new stomp.Stomp(stomp_args); 51 | this._connect = this.client.connect; 52 | this.client.connect = function() { 53 | return true; 54 | }; 55 | callback(); 56 | }, 57 | tearDown: function (callback) { 58 | this.client.connect = this._connect; 59 | callback(); 60 | }, 61 | 'should call connect': function(test) { 62 | test.ok(this.client.connect()); 63 | test.done(); 64 | } 65 | }); 66 | -------------------------------------------------------------------------------- /lib/frame.js: -------------------------------------------------------------------------------- 1 | // ## frame 2 | // 3 | // The `Frame` module provides an object representation of a `Stomp` frame. 4 | // 5 | // ### frame.Frame 6 | // 7 | // An instance of the `Frame` object. 8 | // 9 | // var frame = new frame.Frame(); 10 | // 11 | // ### frame.Frame.build_frame() 12 | // 13 | // Build a frame object from an object of arguments. 14 | // 15 | // var args = { 16 | // command: '', 17 | // headers: {}, 18 | // body: '' 19 | // }; 20 | // 21 | // this_frame = frame.build_frame(args); 22 | // 23 | 24 | 25 | // 26 | // ## Frame - Object representation of a STOMP frame 27 | // 28 | function Frame() { 29 | this.command = null; 30 | this.headers = null; 31 | this.body = null; 32 | }; 33 | 34 | // 35 | // ## Frame.build_frame(args, want_receipt) 36 | // 37 | // **Build frame based on arguments provided** 38 | // 39 | // Takes arguments object needed to build frame (command, headers, body?) 40 | // 41 | // Takes boolean to indicate that you wish to get a receipt (set receipt header) 42 | // 43 | // Returns an object representing a frame 44 | // 45 | Frame.prototype.build_frame = function(args, want_receipt) { 46 | var receipt_stamp = null; 47 | 48 | this.command = args['command']; 49 | this.headers = args['headers']; 50 | this.body = args['body']; 51 | 52 | if (want_receipt) { 53 | var _receipt = ''; 54 | receipt_stamp = Math.floor(Math.random()*99999999999).toString(); 55 | if (this.headers['session'] != undefined) { 56 | _receipt = receipt_stamp + "-" + this.headers['session']; 57 | } 58 | else { 59 | _receipt = receipt_stamp; 60 | } 61 | this.headers['receipt'] = _receipt; 62 | } 63 | return this; 64 | }; 65 | 66 | // 67 | // ## Frame.as_string() 68 | // 69 | // **String representation of Frame object** 70 | // 71 | // Returns `Frame` as string 72 | // 73 | Frame.prototype.as_string = function() { 74 | var header_strs = [], 75 | frame = "", 76 | command = this.command, 77 | headers = this.headers, 78 | body = this.body; 79 | 80 | for (var header in headers) { 81 | header_strs.push(header + ':' + headers[header]); 82 | } 83 | 84 | frame += command + "\n"; 85 | frame += header_strs.join("\n"); 86 | frame += "\n\n"; 87 | 88 | if(body) { 89 | frame += body; 90 | } 91 | 92 | frame += '\x00'; 93 | 94 | return frame; 95 | }; 96 | 97 | module.exports.Frame = Frame; 98 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | index.js

index.js

stomp-js

2 | 3 |

Overview

4 | 5 |

An exercise with node.js to implement the STOMP protocol.

6 | 7 |

For documentation see doc/stomp.md and doc/frame.md

8 | 9 |

Installation

10 | 11 |

npm install stomp

12 | 13 |

git clone https://benjaminws@github.com/benjaminws/stomp-js.git

14 | 15 |

Examples

16 | 17 |

Consumer

18 | 19 |

See examples/stomp-consumer.js

20 | 21 |

Producer

22 | 23 |

See examples/stomp-producer.js

24 | 25 |

Producer with Transaction Support

26 | 27 |

See examples/stomp-producer-txn.js

28 | 
29 | 
-------------------------------------------------------------------------------- /docs/stomp-exceptions.html: -------------------------------------------------------------------------------- 1 | stomp-exceptions.js

stomp-exceptions.js

QueueEmpty = exports.QueueEmpty = function() {
 2 |     this.name = "QueueEmpty";
 3 |     this.message = "Queue is Empty";
 4 | };
 5 | 
 6 | QueueEmpty.prototype.toString = function() {
 7 |     return this.message;
 8 | };
 9 | 
10 | 
-------------------------------------------------------------------------------- /docs/stomp-utils.html: -------------------------------------------------------------------------------- 1 | stomp-utils.js

stomp-utils.js

var exceptions = require('./stomp-exceptions');
 2 | var sys = require('util');
 3 | 
 4 | StompLogging = exports.StompLogging = function(should_debug) {
 5 |     this.should_debug = should_debug;
 6 | };
 7 | 
 8 | StompLogging.prototype.debug = function(message) {
 9 |     if (this.should_debug) {
10 |         console.log("debug: " + message);
11 |     }
12 | };
13 | 
14 | StompLogging.prototype.warn = function(message) {
15 |     console.log("warn: " + message);
16 | };
17 | 
18 | StompLogging.prototype.error = function(message, die) {
19 |     console.log("error: " + message);
20 |     if (die) {
21 |         process.exit(1);
22 |     }
23 | };
24 | 
25 | StompLogging.prototype.die = function(message) {
26 |     this.error(message, true);
27 | };
28 | 
29 | StompUtils = exports.StompUtils = function() {
30 |     this.available_utils = [];
31 | };
32 | 
33 | StompUtils.prototype.really_defined = function(var_to_test) {
34 |     return !(var_to_test == null || var_to_test == undefined);
35 | };
36 | 
37 | StompUtils.prototype.extend = function(destination, source) {
38 |     for (var property in source) {
39 |         destination[property] = source[property];
40 |     }
41 |     return destination;
42 | };
43 | 
44 | 
-------------------------------------------------------------------------------- /docs/rocco.css: -------------------------------------------------------------------------------- 1 | #navbar { 2 | position: fixed; 3 | width: 960px; 4 | height: 34px; 5 | background: #fff; 6 | border-bottom: 1px solid #cdcdcd; 7 | border-right: 1px solid #cdcdcd; 8 | border-bottom-right-radius: 5px; 9 | -webkit-border-bottom-right-radius: 5px; 10 | -moz-border-bottom-right-radius: 5px; 11 | z-index: 9; 12 | } 13 | #navbar a, #navbar a:visited { 14 | font-weight: normal; 15 | padding: 0 2px; 16 | text-decoration: none; 17 | color: #3f6fa5; 18 | } 19 | #navbar a:active, #navbar a:hover { 20 | text-decoration: underline; 21 | } 22 | #navbar h3 { 23 | top: 0; 24 | margin: 0; 25 | padding: 4px 20px; 26 | } 27 | #navbar h3 a { 28 | float: left; 29 | display: block; 30 | padding-right: 20px; 31 | } 32 | #container { 33 | padding-top: 20px; 34 | } 35 | body { 36 | background: #fff url("bg.png"); 37 | } 38 | /*--------------------- Layout and Typography ----------------------------*/ 39 | body { 40 | font-family: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif; 41 | font-size: 15px; 42 | line-height: 22px; 43 | color: #252519; 44 | margin: 0; padding: 0; 45 | } 46 | a { 47 | color: #261a3b; 48 | } 49 | a:visited { 50 | color: #261a3b; 51 | } 52 | p { 53 | margin: 0 0 15px 0; 54 | } 55 | h1, h2, h3, h4, h5, h6 { 56 | margin: 0px 0 15px 0; 57 | } 58 | h1 { 59 | margin-top: 40px; 60 | } 61 | #container { 62 | position: relative; 63 | } 64 | #background { 65 | position: fixed; 66 | top: 0; left: 525px; right: 0; bottom: 0; 67 | background: #f5f5ff; 68 | border-left: 1px solid #e5e5ee; 69 | z-index: -1; 70 | } 71 | #jump_to, #jump_page { 72 | background: white; 73 | border-bottom: 1px solid #cdcdcd; 74 | border-left: 1px solid #cdcdcd; 75 | border-bottom-left-radius: 5px; 76 | -webkit-border-bottom-left-radius: 5px; 77 | -moz-border-radius-bottomleft: 5px; 78 | cursor: pointer; 79 | text-align: right; 80 | } 81 | #jump_to, #jump_wrapper { 82 | position: fixed; 83 | right: 0; top: 0; 84 | padding: 5px 30px; 85 | } 86 | #jump_wrapper { 87 | padding: 0; 88 | display: none; 89 | } 90 | #jump_to:hover #jump_wrapper { 91 | display: block; 92 | } 93 | #jump_page { 94 | padding: 5px 0 3px; 95 | margin: 0 0 25px 25px; 96 | } 97 | #jump_page .source { 98 | display: block; 99 | padding: 5px 30px; 100 | text-decoration: none; 101 | border-top: 1px solid #eee; 102 | } 103 | #jump_page .source:hover { 104 | background: #f5f5ff; 105 | } 106 | #jump_page .source:first-child { 107 | } 108 | table td { 109 | border: 0; 110 | outline: 0; 111 | } 112 | td.docs, th.docs { 113 | max-width: 450px; 114 | min-width: 450px; 115 | min-height: 5px; 116 | padding: 10px 25px 1px 50px; 117 | overflow-x: hidden; 118 | vertical-align: top; 119 | text-align: left; 120 | } 121 | .docs pre { 122 | margin: 15px 0 15px; 123 | padding-left: 15px; 124 | } 125 | .docs p tt, .docs p code { 126 | background: #f8f8ff; 127 | border: 1px solid #dedede; 128 | font-size: 12px; 129 | padding: 0 0.2em; 130 | } 131 | .pilwrap { 132 | position: relative; 133 | } 134 | .pilcrow { 135 | font: 12px Arial; 136 | text-decoration: none; 137 | color: #454545; 138 | position: absolute; 139 | top: 3px; left: -20px; 140 | padding: 1px 2px; 141 | opacity: 0; 142 | -webkit-transition: opacity 0.2s linear; 143 | } 144 | td.docs:hover .pilcrow { 145 | opacity: 1; 146 | } 147 | td.code, th.code { 148 | padding: 14px 15px 16px 25px; 149 | width: 100%; 150 | vertical-align: top; 151 | background: #f5f5ff; 152 | border-left: 1px solid #e5e5ee; 153 | } 154 | pre, tt, code { 155 | font-size: 12px; line-height: 18px; 156 | font-family: Menlo, Monaco, Consolas, "Lucida Console", monospace; 157 | margin: 0; padding: 0; 158 | } 159 | 160 | 161 | /*---------------------- Syntax Highlighting -----------------------------*/ 162 | td.linenos { background-color: #f0f0f0; padding-right: 10px; } 163 | span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; } 164 | body .hll { background-color: #ffffcc } 165 | body .c { color: #408080; font-style: italic } /* Comment */ 166 | body .err { border: 1px solid #FF0000 } /* Error */ 167 | body .k { color: #954121 } /* Keyword */ 168 | body .o { color: #666666 } /* Operator */ 169 | body .cm { color: #408080; font-style: italic } /* Comment.Multiline */ 170 | body .cp { color: #BC7A00 } /* Comment.Preproc */ 171 | body .c1 { color: #408080; font-style: italic } /* Comment.Single */ 172 | body .cs { color: #408080; font-style: italic } /* Comment.Special */ 173 | body .gd { color: #A00000 } /* Generic.Deleted */ 174 | body .ge { font-style: italic } /* Generic.Emph */ 175 | body .gr { color: #FF0000 } /* Generic.Error */ 176 | body .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 177 | body .gi { color: #00A000 } /* Generic.Inserted */ 178 | body .go { color: #808080 } /* Generic.Output */ 179 | body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ 180 | body .gs { font-weight: bold } /* Generic.Strong */ 181 | body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 182 | body .gt { color: #0040D0 } /* Generic.Traceback */ 183 | body .kc { color: #954121 } /* Keyword.Constant */ 184 | body .kd { color: #954121; font-weight: bold } /* Keyword.Declaration */ 185 | body .kn { color: #954121; font-weight: bold } /* Keyword.Namespace */ 186 | body .kp { color: #954121 } /* Keyword.Pseudo */ 187 | body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */ 188 | body .kt { color: #B00040 } /* Keyword.Type */ 189 | body .m { color: #666666 } /* Literal.Number */ 190 | body .s { color: #219161 } /* Literal.String */ 191 | body .na { color: #7D9029 } /* Name.Attribute */ 192 | body .nb { color: #954121 } /* Name.Builtin */ 193 | body .nc { color: #0000FF; font-weight: bold } /* Name.Class */ 194 | body .no { color: #880000 } /* Name.Constant */ 195 | body .nd { color: #AA22FF } /* Name.Decorator */ 196 | body .ni { color: #999999; font-weight: bold } /* Name.Entity */ 197 | body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ 198 | body .nf { color: #0000FF } /* Name.Function */ 199 | body .nl { color: #A0A000 } /* Name.Label */ 200 | body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ 201 | body .nt { color: #954121; font-weight: bold } /* Name.Tag */ 202 | body .nv { color: #19469D } /* Name.Variable */ 203 | body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ 204 | body .w { color: #bbbbbb } /* Text.Whitespace */ 205 | body .mf { color: #666666 } /* Literal.Number.Float */ 206 | body .mh { color: #666666 } /* Literal.Number.Hex */ 207 | body .mi { color: #666666 } /* Literal.Number.Integer */ 208 | body .mo { color: #666666 } /* Literal.Number.Oct */ 209 | body .sb { color: #219161 } /* Literal.String.Backtick */ 210 | body .sc { color: #219161 } /* Literal.String.Char */ 211 | body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */ 212 | body .s2 { color: #219161 } /* Literal.String.Double */ 213 | body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ 214 | body .sh { color: #219161 } /* Literal.String.Heredoc */ 215 | body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ 216 | body .sx { color: #954121 } /* Literal.String.Other */ 217 | body .sr { color: #BB6688 } /* Literal.String.Regex */ 218 | body .s1 { color: #219161 } /* Literal.String.Single */ 219 | body .ss { color: #19469D } /* Literal.String.Symbol */ 220 | body .bp { color: #954121 } /* Name.Builtin.Pseudo */ 221 | body .vc { color: #19469D } /* Name.Variable.Class */ 222 | body .vg { color: #19469D } /* Name.Variable.Global */ 223 | body .vi { color: #19469D } /* Name.Variable.Instance */ 224 | body .il { color: #666666 } /* Literal.Number.Integer.Long */ -------------------------------------------------------------------------------- /docs/frame.html: -------------------------------------------------------------------------------- 1 | frame.js

frame.js

frame

2 | 3 |

The Frame module provides an object representation of a Stomp frame.

4 | 5 |

frame.Frame

6 | 7 |

An instance of the Frame object.

8 | 9 |
var frame = new frame.Frame();
10 | 11 |

frame.Frame.build_frame()

12 | 13 |

Build a frame object from an object of arguments.

14 | 15 |
var args = {
16 |     command: '',
17 |     headers: {},
18 |     body: ''
19 | };
20 | 
21 | this_frame = frame.build_frame(args);

Frame - Object representation of a STOMP frame

function Frame() {
22 |     this.command = null;
23 |     this.headers = null;
24 |     this.body = null;
25 | };

Frame.buildframe(args, wantreceipt)

26 | 27 |

Build frame based on arguments provided

28 | 29 |

Takes arguments object needed to build frame (command, headers, body?)

30 | 31 |

Takes boolean to indicate that you wish to get a receipt (set receipt header)

32 | 33 |

Returns an object representing a frame

Frame.prototype.build_frame = function(args, want_receipt) {
34 |     var receipt_stamp = null;
35 | 
36 |     this.command = args['command'];
37 |     this.headers = args['headers'];
38 |     this.body = args['body'];
39 | 
40 |     if (want_receipt) {
41 |         var _receipt = '';
42 |         receipt_stamp = Math.floor(Math.random()*99999999999).toString();
43 |         if (this.headers['session'] != undefined) {
44 |             _receipt = receipt_stamp + "-" + this.headers['session'];
45 |         }
46 |         else {
47 |             _receipt = receipt_stamp;
48 |         }
49 |         this.headers['receipt'] = _receipt;
50 |     }
51 |     return this;
52 | };

Frame.as_string()

53 | 54 |

String representation of Frame object

55 | 56 |

Returns Frame as string

Frame.prototype.as_string = function() {
57 |     var header_strs = [],
58 |         frame = "",
59 |         command = this.command,
60 |         headers = this.headers,
61 |         body = this.body;
62 | 
63 |     for (var header in headers) {
64 |        header_strs.push(header + ':' + headers[header]);
65 |     }
66 | 
67 |     frame += command + "\n";
68 |     frame += header_strs.join("\n");
69 |     frame += "\n\n";
70 | 
71 |     if(body) {
72 |         frame += body;
73 |     }
74 | 
75 |     frame += '\x00';
76 | 
77 |     return frame;
78 | };
79 | 
80 | module.exports.Frame = Frame;
81 | 
82 | 
-------------------------------------------------------------------------------- /lib/stomp.js: -------------------------------------------------------------------------------- 1 | // ## stomp 2 | // 3 | // The `Stomp` module provides you with a client interface for interacting with STOMP messaging brokers 4 | // 5 | // ### stomp.Stomp 6 | // 7 | // An instance of the `Stomp` object. Initialized like so: 8 | // 9 | // var stomp_args = { 10 | // port: 61613, 11 | // host: 'localhost', 12 | // debug: false, 13 | // login: 'guest', 14 | // passcode: 'guest', 15 | // }; 16 | // 17 | // var client = new stomp.Stomp(stomp_args); 18 | // 19 | // If debug is set to true, extra output will be printed to the console. 20 | 21 | // ## Helpers to handle frames, and do parsing 22 | 23 | var events = require('events'), 24 | net = require('net'), 25 | tls = require('tls'), 26 | sys = require('util'), 27 | util = require('util'), 28 | frame = require('./frame'), 29 | stomp_utils = require('./stomp-utils'), 30 | exceptions = require('./stomp-exceptions'), 31 | utils = new stomp_utils.StompUtils(), 32 | log = null; 33 | 34 | 35 | function parse_command(data) { 36 | var command, 37 | this_string = data.toString('utf8', 0, data.length); 38 | command = this_string.split('\n'); 39 | return command[0]; 40 | }; 41 | 42 | function parse_headers(raw_headers) { 43 | var headers = {}, 44 | headers_split = raw_headers.split('\n'); 45 | 46 | for (var i = 0; i < headers_split.length; i++) { 47 | var header = headers_split[i].split(':'); 48 | if (header.length > 1) { 49 | var header_key = header.shift().trim(); 50 | var header_val = header.join(':').trim(); 51 | headers[header_key] = header_val; 52 | continue; 53 | } 54 | } 55 | return headers; 56 | }; 57 | 58 | function parse_frame(chunk) { 59 | var args = {}, 60 | data = null, 61 | command = null, 62 | headers = null, 63 | body = null, 64 | headers_str = null; 65 | 66 | if (!utils.really_defined(chunk)) { 67 | return null; 68 | } 69 | 70 | command = parse_command(chunk); 71 | data = chunk.slice(command.length + 1, chunk.length); 72 | data = data.toString('utf8', 0, data.length); 73 | 74 | var the_rest = data.split('\n\n'); 75 | headers = parse_headers(the_rest[0]); 76 | body = the_rest.slice(1, the_rest.length); 77 | 78 | if ('content-length' in headers) { 79 | headers['bytes_message'] = true; 80 | } 81 | 82 | args = { 83 | command: command, 84 | headers: headers, 85 | body: body 86 | } 87 | 88 | var this_frame = new frame.Frame(); 89 | var return_frame = this_frame.build_frame(args); 90 | 91 | return return_frame; 92 | }; 93 | 94 | function _connect(stomp) { 95 | log = stomp.log; 96 | 97 | if (stomp.ssl) { 98 | log.debug('Connecting to ' + stomp.host + ':' + stomp.port + ' using SSL'); 99 | stomp.socket = tls.connect(stomp.port, stomp.host, stomp.ssl_options, function() { 100 | log.debug('SSL connection complete'); 101 | if (!stomp.socket.authorized) { 102 | log.error('SSL is not authorized: '+stomp.socket.authorizationError); 103 | if (stomp.ssl_validate) { 104 | _disconnect(stomp); 105 | return; 106 | } 107 | } 108 | _setupListeners(stomp); 109 | }); 110 | } 111 | else { 112 | log.debug('Connecting to ' + stomp.host + ':' + stomp.port); 113 | stomp.socket = new net.Socket(); 114 | stomp.socket.connect(stomp.port, stomp.host); 115 | _setupListeners(stomp); 116 | } 117 | } 118 | 119 | function _setupListeners(stomp) { 120 | function _connected() { 121 | log.debug('Connected to socket'); 122 | var headers = {}; 123 | if (utils.really_defined(stomp.login) && 124 | utils.really_defined(stomp.passcode)) { 125 | headers.login = stomp.login; 126 | headers.passcode = stomp.passcode; 127 | } 128 | if (utils.really_defined(stomp["client-id"])) { 129 | headers["client-id"] = stomp["client-id"]; 130 | } 131 | if (utils.really_defined(stomp["vhost"])) { 132 | headers["host"] = stomp["vhost"]; 133 | } 134 | stomp_connect(stomp, headers); 135 | } 136 | 137 | var socket = stomp.socket; 138 | 139 | socket.setKeepAlive(true); 140 | 141 | socket.on('drain', function(data) { 142 | log.debug('draining'); 143 | }); 144 | 145 | var buffer = ''; 146 | socket.on('data', function(chunk) { 147 | buffer += chunk; 148 | var frames = buffer.split('\0\n'); 149 | 150 | // Temporary fix : NULL,LF is not a guranteed standard, the LF is optional, so lets deal with it. (Rauls) 151 | if (frames.length == 1) { 152 | frames = buffer.split('\0'); 153 | } 154 | 155 | if (frames.length == 1) return; 156 | buffer = frames.pop(); 157 | 158 | var parsed_frame = null; 159 | var _frame = null; 160 | while (_frame = frames.shift()) { 161 | parsed_frame = parse_frame(_frame); 162 | stomp.handle_new_frame(parsed_frame); 163 | } 164 | }); 165 | 166 | socket.on('end', function() { 167 | log.debug("end"); 168 | }); 169 | 170 | socket.on('error', function(error) { 171 | log.error(error.stack + 'error name: ' + error.name); 172 | stomp.emit("error", error); 173 | }); 174 | 175 | socket.on('close', function(error) { 176 | log.debug('disconnected'); 177 | if (error) { 178 | log.error('Disconnected with error: ' + error); 179 | } 180 | stomp.emit("disconnected", error); 181 | }); 182 | 183 | if (stomp.ssl) { 184 | _connected(); 185 | } else { 186 | socket.on('connect', _connected); 187 | } 188 | }; 189 | 190 | function stomp_connect(stomp, headers) { 191 | var _frame = new frame.Frame(), 192 | args = {}, 193 | headers = headers || {}; 194 | 195 | args['command'] = 'CONNECT'; 196 | args['headers'] = headers; 197 | 198 | var frame_to_send = _frame.build_frame(args); 199 | 200 | send_frame(stomp, frame_to_send); 201 | }; 202 | 203 | function _disconnect(stomp) { 204 | var socket = stomp.socket; 205 | socket.end(); 206 | 207 | if (socket.readyState == 'readOnly') { 208 | socket.destroy(); 209 | } 210 | 211 | log.debug('disconnect called'); 212 | }; 213 | 214 | function send_command(stomp, command, headers, body, want_receipt) { 215 | var want_receipt = want_receipt || false; 216 | 217 | if (!utils.really_defined(headers)) { 218 | headers = {}; 219 | } 220 | 221 | var args = { 222 | 'command': command, 223 | 'headers': headers, 224 | 'body': body 225 | }; 226 | 227 | var _frame = new frame.Frame(); 228 | var this_frame = _frame.build_frame(args, want_receipt); 229 | send_frame(stomp, this_frame); 230 | 231 | return this_frame; 232 | }; 233 | 234 | function send_frame(stomp, _frame) { 235 | var socket = stomp.socket; 236 | var frame_str = _frame.as_string(); 237 | 238 | if (socket.write(frame_str) === false) { 239 | log.debug('Write buffered'); 240 | } 241 | 242 | return true; 243 | }; 244 | 245 | // 246 | // ## Stomp - Client API 247 | // 248 | // Takes an argument object 249 | // 250 | function Stomp(args) { 251 | events.EventEmitter.call(this); 252 | 253 | this.port = args['port'] || 61613; 254 | this.host = args['host'] || '127.0.0.1'; 255 | this.debug = args['debug']; 256 | this.login = args['login'] || null; 257 | this.passcode = args['passcode'] || null; 258 | this.log = new stomp_utils.StompLogging(this.debug); 259 | this._subscribed_to = {}; 260 | this.session = null; 261 | this.ssl = args['ssl'] ? true : false; 262 | this.ssl_validate = args['ssl_validate'] ? true : false; 263 | this.ssl_options = args['ssl_options'] || {}; 264 | this['client-id'] = args['client-id'] || null; 265 | if(typeof args.vhost !== 'undefined'){ 266 | this.vhost = args['vhost'] ; 267 | } 268 | }; 269 | 270 | // ## Stomp is an EventEmitter 271 | util.inherits(Stomp, events.EventEmitter); 272 | 273 | // ## Stomp.connect() 274 | // 275 | // **Begin connection** 276 | // 277 | Stomp.prototype.connect = function() { 278 | _connect(this); 279 | }; 280 | 281 | // ## Stomp.is_a_message(frame) 282 | // 283 | // **Test that `Frame` is a message** 284 | // 285 | // Takes a `Frame` object 286 | // 287 | Stomp.prototype.is_a_message = function(this_frame) { 288 | return (this_frame.headers !== null && 289 | utils.really_defined(this_frame.headers['message-id'])) 290 | } 291 | 292 | // ## Stomp.should_run_message_callback 293 | // 294 | // **Handle any registered message callbacks** 295 | // 296 | // Takes a `Frame` object 297 | // 298 | Stomp.prototype.should_run_message_callback = function(this_frame) { 299 | // The matching subscribed queue will be found in the subscription headers 300 | // in the case of a reply-to temp queue with rabbitmq 301 | var subscription = this._subscribed_to[this_frame.headers.destination] || 302 | this._subscribed_to[this_frame.headers.subscription]; 303 | if (this_frame.headers.destination !== null && subscription !== null) { 304 | if (subscription.enabled && subscription.callback !== null && 305 | typeof subscription.callback === 'function') { 306 | subscription.callback(this_frame.body, this_frame.headers); 307 | } 308 | } 309 | } 310 | 311 | // ## Stomp.handle\_new_frame(frame) 312 | // 313 | // **Handle frame based on type. Emit events when needed.** 314 | // 315 | // Takes a `Frame` object 316 | // 317 | Stomp.prototype.handle_new_frame = function(this_frame) { 318 | switch (this_frame.command) { 319 | case "MESSAGE": 320 | if (this.is_a_message(this_frame)) { 321 | this.should_run_message_callback(this_frame); 322 | this.emit('message', this_frame); 323 | } 324 | break; 325 | case "CONNECTED": 326 | log.debug('Connected to STOMP'); 327 | this.session = this_frame.headers['session']; 328 | this.emit('connected'); 329 | break; 330 | case "RECEIPT": 331 | this.emit('receipt', this_frame.headers['receipt-id']); 332 | break; 333 | case "ERROR": 334 | this.emit('error', this_frame); 335 | break; 336 | default: 337 | console.log("Could not parse command: " + this_frame.command); 338 | } 339 | }; 340 | 341 | // 342 | // ## Stomp.disconnect() 343 | // 344 | // **Disconnect from STOMP broker** 345 | // 346 | Stomp.prototype.disconnect = function() { 347 | _disconnect(this); 348 | } 349 | 350 | // 351 | // ## Stomp.subscribe(headers, callback) 352 | // 353 | // **Subscribe to destination (queue or topic)** 354 | // 355 | // Takes a header object 356 | // 357 | // Takes a callback function 358 | // 359 | Stomp.prototype.subscribe = function(headers, callback) { 360 | var destination = headers['destination']; 361 | headers['session'] = this.session; 362 | send_command(this, 'SUBSCRIBE', headers); 363 | 364 | /** 365 | / Maybe we could subscribe to mulitple queues? 366 | / if (destination instanceof Array) { 367 | / for (var = i; i < 0; i++) { 368 | / this._subscribed_to[destination[i]] = { enabled: true, callback: callback }; 369 | / } 370 | / } 371 | / else { 372 | / this._subscribed_to[destination] = { enabled: true, callback: callback }; 373 | / } 374 | / 375 | */ 376 | 377 | this._subscribed_to[destination] = { enabled: true, callback: callback }; 378 | this.log.debug('subscribed to: ' + destination + ' with headers ' + sys.inspect(headers)); 379 | }; 380 | 381 | // 382 | // ## Stomp.unsubscribe(headers) 383 | // 384 | // **Unsubscribe from destination (queue or topic)** 385 | // 386 | // Takes a header object 387 | // 388 | Stomp.prototype.unsubscribe = function(headers) { 389 | var destination = headers['destination']; 390 | headers['session'] = this.session; 391 | send_command(this, 'UNSUBSCRIBE', headers); 392 | this._subscribed_to[destination].enabled = false; 393 | this.log.debug('no longer subscribed to: ' + destination); 394 | }; 395 | 396 | // 397 | // ## Stomp.ack(message_id) 398 | // 399 | // **Acknowledge received message** 400 | // 401 | // Takes a string representing the message id to ack 402 | // 403 | Stomp.prototype.ack = function(message_id) { 404 | send_command(this, 'ACK', {'message-id': message_id}); 405 | this.log.debug('acknowledged message: ' + message_id); 406 | }; 407 | 408 | 409 | // 410 | // ## Stomp.nack(message_id) 411 | // 412 | // **Deny received message** 413 | // 414 | // Takes a string representing the message id to nack 415 | // 416 | Stomp.prototype.nack = function(message_id) { 417 | send_command(this, 'NACK', {'message-id': message_id}); 418 | this.log.debug('denied message: ' + message_id); 419 | }; 420 | 421 | // 422 | // ## Stomp.nack(message_id) 423 | // 424 | // **Deny received message** 425 | // 426 | // Takes a string representing the message id to nack 427 | // 428 | Stomp.prototype.nack = function(message_id) { 429 | send_command(this, 'NACK', {'message-id': message_id}); 430 | this.log.debug('denied message: ' + message_id); 431 | }; 432 | 433 | // 434 | // ## Stomp.begin() 435 | // 436 | // **Begin transaction** 437 | // 438 | // Return a string representing the generated transaction id 439 | // 440 | Stomp.prototype.begin = function() { 441 | var transaction_id = Math.floor(Math.random()*99999999999).toString(); 442 | send_command(this, 'BEGIN', {'transaction': transaction_id}); 443 | this.log.debug('begin transaction: ' + transaction_id); 444 | return transaction_id; 445 | }; 446 | 447 | // 448 | // ## Stomp.commit(transaction_id) 449 | // 450 | // **Commit transaction** 451 | // 452 | // Takes a string representing the transaction id generated by stomp.Stomp.begin() 453 | // 454 | Stomp.prototype.commit = function(transaction_id) { 455 | send_command(this, 'COMMIT', {'transaction': transaction_id}); 456 | this.log.debug('commit transaction: ' + transaction_id); 457 | }; 458 | 459 | // 460 | // ## Stomp.abort(transaction_id) 461 | // 462 | // **Abort transaction** 463 | // 464 | // Takes a string representing the transaction id generated by stomp.Stomp.begin() 465 | // 466 | Stomp.prototype.abort = function(transaction_id) { 467 | send_command(this, 'ABORT', {'transaction': transaction_id}); 468 | this.log.debug('abort transaction: ' + transaction_id); 469 | }; 470 | 471 | // 472 | // ## Stomp.send(headers, want_receipt) 473 | // 474 | // **Send MESSAGE to STOMP broker** 475 | // 476 | // Takes a header object (destination is required) 477 | // 478 | // Takes a boolean requesting receipt of the sent message 479 | // 480 | // Returns a `Frame` object representing the message sent 481 | // 482 | Stomp.prototype.send = function(headers, want_receipt) { 483 | var destination = headers['destination'], 484 | body = headers['body'] || null; 485 | delete headers['body']; 486 | headers['session'] = this.session; 487 | return send_command(this, 'SEND', headers, body, want_receipt) 488 | }; 489 | 490 | module.exports.Stomp = Stomp; 491 | -------------------------------------------------------------------------------- /docs/stomp.html: -------------------------------------------------------------------------------- 1 | stomp.js

stomp.js

stomp

2 | 3 |

The Stomp module provides you with a client interface for interacting with STOMP messaging brokers

4 | 5 |

stomp.Stomp

6 | 7 |

An instance of the Stomp object. Initialized like so:

8 | 9 |
var stomp_args = {
 10 |     port: 61613,
 11 |     host: 'localhost',
 12 |     debug: false,
 13 |     login: 'guest',
 14 |     passcode: 'guest',
 15 | };
 16 | 
 17 | var client = new stomp.Stomp(stomp_args);
18 | 19 |

If debug is set to true, extra output will be printed to the console.

Helpers to handle frames, and do parsing

var net = require('net'),
 20 |     tls = require('tls'),
 21 |     sys = require('util'),
 22 |     frame = require('./frame'),
 23 |     stomp_utils = require('./stomp-utils'),
 24 |     exceptions = require('./stomp-exceptions'),
 25 |     utils = new stomp_utils.StompUtils(),
 26 |     log = null;
 27 | 
 28 | 
 29 | function parse_command(data) {
 30 |     var command,
 31 |         this_string = data.toString('utf8', 0, data.length);
 32 |     command = this_string.split('\n');
 33 |     return command[0];
 34 | };
 35 | 
 36 | function parse_headers(headers_str) {
 37 |     var these_headers = {},
 38 |         one_header = [],
 39 |         header_key = null,
 40 |         header_val = null,
 41 |         headers_split = headers_str.split('\n');
 42 | 
 43 |     for (var i = 0; i < headers_split.length; i++) {
 44 |         one_header = headers_split[i].split(':');
 45 |         if (one_header.length > 1) {
 46 |             header_key = one_header.shift();
 47 |             header_val = one_header.join(':');
 48 |             these_headers[header_key] = header_val;
 49 |         }
 50 |         else {
 51 |             these_headers[one_header[0]] = one_header[1];
 52 |         }
 53 |     }
 54 |     return these_headers;
 55 | };
 56 | 
 57 | function parse_frame(chunk) {
 58 |     var args = {},
 59 |         data = null,
 60 |         command = null,
 61 |         headers = null,
 62 |         body = null,
 63 |         headers_str = null;
 64 | 
 65 |     if (!utils.really_defined(chunk))
 66 |         return null;
 67 | 
 68 |     command = parse_command(chunk);
 69 |     data = chunk.slice(command.length + 1, chunk.length);
 70 |     data = data.toString('utf8', 0, data.length);
 71 | 
 72 |     var the_rest = data.split('\n\n');
 73 |     headers = parse_headers(the_rest[0]);
 74 |     body = the_rest.slice(1, the_rest.length);
 75 | 
 76 |     if ('content-length' in headers)
 77 |        headers['bytes_message'] = true;
 78 | 
 79 |     args = {
 80 |         command: command,
 81 |         headers: headers,
 82 |         body: body
 83 |     }
 84 | 
 85 |     var this_frame = new frame.Frame();
 86 |     var return_frame = this_frame.build_frame(args);
 87 | 
 88 |     return return_frame;
 89 | };
 90 | 
 91 | function _connect(stomp) {
 92 |     log = stomp.log;
 93 | 
 94 |     if (stomp.ssl) {
 95 |         log.debug('Connecting to ' + stomp.host + ':' + stomp.port + ' using SSL');
 96 |         stomp.socket = tls.connect(stomp.port, stomp.host, stomp.ssl_options, function() {
 97 |             log.debug('SSL connection complete');
 98 |             if (!stomp.socket.authorized) {
 99 |                 log.error('SSL is not authorized: '+stomp.socket.authorizationError);
100 |                 if (stomp.ssl_validate) {
101 |                     _disconnect(stomp);
102 |                     return;
103 |                 }
104 |             }
105 |             _setupListeners(stomp);
106 |         });
107 |     } else {
108 |         log.debug('Connecting to ' + stomp.host + ':' + stomp.port);
109 |         stomp.socket = new net.Socket();
110 |         stomp.socket.connect(stomp.port, stomp.host);
111 |         _setupListeners(stomp);
112 |     }
113 | }
114 | 
115 | function _setupListeners(stomp) {
116 |     function _connected() {
117 |         log.debug('Connected to socket');
118 |         var headers = {};
119 |         if (utils.really_defined(stomp.login) &&
120 |             utils.really_defined(stomp.passcode)) {
121 |             headers.login = stomp.login;
122 |             headers.passcode = stomp.passcode;
123 |         }
124 |         if (utils.really_defined(stomp["client-id"])) {
125 |             headers["client-id"] = stomp["client-id"];
126 |         }
127 |         stomp_connect(stomp, headers);
128 |     }
129 | 
130 |     var socket = stomp.socket;
131 | 
132 |     socket.on('drain', function(data) {
133 |         log.debug('draining');
134 |     });
135 | 
136 |     var buffer = '';
137 |     socket.on('data', function(chunk) {
138 |         buffer += chunk;
139 |         var frames = buffer.split('\0\n');

Temporary fix : NULL,LF is not a guranteed standard, the LF is optional, so lets deal with it. (Rauls)

        if (frames.length == 1) {
140 |             frames = buffer.split('\0');
141 |         }
142 | 
143 |         if (frames.length == 1) return;
144 |         buffer = frames.pop();
145 | 
146 |         var parsed_frame = null;
147 |         var _frame = null;
148 |         while (_frame = frames.shift()) {
149 |             parsed_frame = parse_frame(_frame);
150 |             stomp.handle_new_frame(parsed_frame);
151 |         }
152 |     });
153 | 
154 |     socket.on('end', function() {
155 |         log.debug("end");
156 |     });
157 | 
158 |     socket.on('error', function(error) {
159 |         log.error(error.stack + 'error name: ' + error.name);
160 |         stomp.emit("error", error);
161 |     });
162 | 
163 |     socket.on('close', function(error) {
164 |         log.debug('disconnected');
165 |         if (error) {
166 |             log.error('Disconnected with error: ' + error);
167 |         }
168 |         stomp.emit("disconnected", error);
169 |     });
170 | 
171 |     if (stomp.ssl) {
172 |         _connected();
173 |     } else {
174 |         socket.on('connect', _connected);
175 |     }
176 | };
177 | 
178 | function stomp_connect(stomp, headers) {
179 |     var _frame = new frame.Frame(),
180 |         args = {},
181 |         headers = headers || {};
182 | 
183 |     args['command'] = 'CONNECT';
184 |     args['headers'] = headers;
185 | 
186 |     var frame_to_send = _frame.build_frame(args);
187 | 
188 |     send_frame(stomp, frame_to_send);
189 | };
190 | 
191 | function _disconnect(stomp) {
192 |     var socket = stomp.socket;
193 |     socket.end();
194 |     if (socket.readyState == 'readOnly')
195 |         socket.destroy();
196 |     log.debug('disconnect called');
197 | };
198 | 
199 | function send_command(stomp, command, headers, body, want_receipt) {
200 |     var want_receipt = want_receipt || false;
201 |     if (!utils.really_defined(headers))
202 |         headers = {};
203 | 
204 |     var args = {
205 |         'command': command,
206 |         'headers': headers,
207 |         'body': body
208 |     };
209 | 
210 |     var _frame = new frame.Frame();
211 |     var this_frame = _frame.build_frame(args, want_receipt);
212 |     send_frame(stomp, this_frame);
213 | 
214 |     return this_frame;
215 | };
216 | 
217 | function send_frame(stomp, _frame) {
218 |     var socket = stomp.socket;
219 |     var frame_str = _frame.as_string();
220 | 
221 |     if (socket.write(frame_str) === false) {
222 |         log.debug('Write buffered');
223 |     }
224 | 
225 |     return true;
226 | };

Stomp - Client API

227 | 228 |

Takes an argument object

function Stomp(args) {
229 |     this.port = args['port'] || 61613;
230 |     this.host = args['host'] || "127.0.0.1";
231 |     this.debug = args['debug'];
232 |     this.login = args['login'] || null;
233 |     this.passcode = args['passcode'] || null;
234 |     this.log = new StompLogging(this.debug);
235 |     this._subscribed_to = {};
236 |     this.session = null;
237 |     this.ssl = args['ssl'] ? true : false;
238 |     this.ssl_validate = args['ssl_validate'] ? true : false;
239 |     this.ssl_options = args['ssl_options'] || {};
240 |     this['client-id'] = args['client-id'] || null;
241 | };

Stomp is an EventEmitter

Stomp.prototype = new process.EventEmitter();

Stomp.connect()

242 | 243 |

Begin connection

Stomp.prototype.connect = function() {
244 |     _connect(this);
245 | };

Stomp.handle_new_frame()

246 | 247 |

Handle frame based on type. Emit events when needed.

248 | 249 |

Takes a Frame object

Stomp.prototype.handle_new_frame = function(this_frame) {
250 |     switch (this_frame.command) {
251 |         case "MESSAGE":
252 |             if (utils.really_defined(this_frame.headers['message-id'])) {
253 |                 if (this_frame.headers !== null && this_frame.headers.destination !== null && this._subscribed_to[this_frame.headers.destination] !== null) {
254 |                     var subscription = this._subscribed_to[this_frame.headers.destination];
255 |                     if (subscription.enabled && subscription.callback !== null && typeof(subscription.callback) == 'function') {
256 |                         subscription.callback(this_frame.body, this_frame.headers);
257 |                     }
258 |                 }
259 |                 this.emit('message', this_frame);
260 |             }
261 | 
262 |             break;
263 |         case "CONNECTED":
264 |             log.debug('Connected to STOMP');
265 |             this.session = this_frame.headers['session'];
266 |             this.emit('connected');
267 |             break;
268 |         case "RECEIPT":
269 |             this.emit('receipt', this_frame.headers['receipt-id']);
270 |             break;
271 |         case "ERROR":
272 |             this.emit('error', this_frame);
273 |             break;
274 |         default:
275 |             console.log("Could not parse command: " + this_frame.command);
276 |     }
277 | };

Stomp.disconnect()

278 | 279 |

Disconnect from STOMP broker

Stomp.prototype.disconnect = function() {
280 |     _disconnect(this);
281 | }

Stomp.subscribe(headers, callback)

282 | 283 |

Subscribe to destination (queue or topic)

284 | 285 |

Takes a header object

286 | 287 |

Takes a callback function

Stomp.prototype.subscribe = function(headers, callback) {
288 |     var destination = headers['destination'];
289 |     headers['session'] = this.session;
290 |     send_command(this, 'SUBSCRIBE', headers);
291 | 
292 |     /**
293 |     / Maybe we could subscribe to mulitple queues?
294 |     / if (destination instanceof Array) {
295 |     /   for (var = i; i < 0; i++) {
296 |     /     this._subscribed_to[destination[i]] = { enabled: true, callback: callback };
297 |     /   }
298 |     / }
299 |     / else {
300 |     /     this._subscribed_to[destination] = { enabled: true, callback: callback };
301 |     / }
302 |     /
303 |     */
304 | 
305 |     this._subscribed_to[destination] = { enabled: true, callback: callback };
306 |     this.log.debug('subscribed to: ' + destination + ' with headers ' + sys.inspect(headers));
307 | };

Stomp.unsubscribe()

308 | 309 |

Unsubscribe from destination (queue or topic)

310 | 311 |

Takes a header object

Stomp.prototype.unsubscribe = function(headers) {
312 |     var destination = headers['destination'];
313 |     headers['session'] = this.session;
314 |     send_command(this, 'UNSUBSCRIBE', headers);
315 |     this._subscribed_to[destination].enabled = false;
316 |     this.log.debug('no longer subscribed to: ' + destination);
317 | };

Stomp.ack()

318 | 319 |

Acknowledge received message

320 | 321 |

Takes a string representing the message id to ack

Stomp.prototype.ack = function(message_id) {
322 |     send_command(this, 'ACK', {'message-id': message_id});
323 |     this.log.debug('acknowledged message: ' + message_id);
324 | };

Stomp.begin()

325 | 326 |

Begin transaction

327 | 328 |

Return a string representing the generated transaction id

Stomp.prototype.begin = function() {
329 |     var transaction_id = Math.floor(Math.random()*99999999999).toString();
330 |     send_command(this, 'BEGIN', {'transaction': transaction_id});
331 |     this.log.debug('begin transaction: ' + transaction_id);
332 |     return transaction_id;
333 | };

Stomp.commit()

334 | 335 |

Commit transaction

336 | 337 |

Takes a string representing the transaction id generated by stomp.Stomp.begin()

Stomp.prototype.commit = function(transaction_id) {
338 |     send_command(this, 'COMMIT', {'transaction': transaction_id});
339 |     this.log.debug('commit transaction: ' + transaction_id);
340 | };

Stomp.abort()

341 | 342 |

Abort transaction

343 | 344 |

Takes a string representing the transaction id generated by stomp.Stomp.begin()

Stomp.prototype.abort = function(transaction_id) {
345 |     send_command(this, 'ABORT', {'transaction': transaction_id});
346 |     this.log.debug('abort transaction: ' + transaction_id);
347 | };

Stomp.send()

348 | 349 |

Send MESSAGE to STOMP broker

350 | 351 |

Takes a header object (destination is required)

352 | 353 |

Takes a boolean requesting recipt of the sent message

354 | 355 |

Returns a Frame object representing the message sent

Stomp.prototype.send = function(headers, want_receipt) {
356 |     var destination = headers['destination'],
357 |     body = headers['body'] || null;
358 |     delete headers['body'];
359 |     headers['session'] = this.session;
360 |     return send_command(this, 'SEND', headers, body, want_receipt)
361 | };
362 | 
363 | module.exports.Stomp = Stomp;
364 | 
365 | 
--------------------------------------------------------------------------------