├── .gitignore ├── README.md ├── dist ├── websocket-nats.dev.js ├── websocket-nats.js ├── websocket-nats.min.js └── websocket-nats.min.js.map ├── entry.js ├── index.js ├── lib ├── crypto.js ├── nats.js ├── net.js └── tls.js ├── package.json ├── test └── index.html ├── update-lib.sh └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/node 3 | 4 | ### Node ### 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | 10 | # Runtime data 11 | pids 12 | *.pid 13 | *.seed 14 | 15 | # Directory for instrumented libs generated by jscoverage/JSCover 16 | lib-cov 17 | 18 | # Coverage directory used by tools like istanbul 19 | coverage 20 | 21 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 22 | .grunt 23 | 24 | # node-waf configuration 25 | .lock-wscript 26 | 27 | # Compiled binary addons (http://nodejs.org/api/addons.html) 28 | build/Release 29 | 30 | # Dependency directories 31 | node_modules 32 | jspm_packages 33 | 34 | # Optional npm cache directory 35 | .npm 36 | 37 | # Optional REPL history 38 | .node_repl_history 39 | 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # websocket-nats 2 | [![npm](https://img.shields.io/npm/v/websocket-nats.svg)](https://www.npmjs.com/package/websocket-nats) 3 | [![License MIT](https://img.shields.io/npm/l/websocket-nats.svg)](http://opensource.org/licenses/MIT) 4 | 5 | An in-browser websocket client for [NATS](http://nats.io/), a lightweight, high-performance cloud native messaging system. 6 | 7 | ## Installation 8 | 9 | ### NPM 10 | ```bash 11 | npm install websocket-nats 12 | ``` 13 | 14 | ### CDN 15 | Normal, development, and minified versions of the bundle can obtained via [RawGit](http://rawgit.com/). 16 | 17 | ```html 18 | 19 | ``` 20 | 21 | Development (includes eval sourcemaps): 22 | 23 | ```html 24 | 25 | ``` 26 | 27 | Minified (for production use): 28 | 29 | ```html 30 | 31 | ``` 32 | 33 | ## Prerequisites 34 | 35 | You will need a Websocket-to-TCP proxy to connect to your `gnatsd` instance 36 | over websockets. You may provide your own or use 37 | [ws-tcp-relay](https://github.com/isobit/ws-tcp-relay). 38 | 39 | ## Basic Usage 40 | 41 | Usage is the same as [node-nats](https://github.com/nats-io/node-nats), but a 42 | url to your websocket/TCP proxy should be provided instead of one pointing 43 | directly at your `gnatsd` instance. 44 | 45 | ```javascript 46 | 47 | var nats = require('websocket-nats').connect('ws://localhost:4223'); 48 | 49 | // Simple Publisher 50 | nats.publish('foo', 'Hello World!'); 51 | 52 | // Simple Subscriber 53 | nats.subscribe('foo', function(msg) { 54 | console.log('Received a message: ' + msg); 55 | }); 56 | 57 | // Unsubscribing 58 | var sid = nats.subscribe('foo', function(msg) {}); 59 | nats.unsubscribe(sid); 60 | 61 | // Request Streams 62 | var sid = nats.request('request', function(response) { 63 | console.log('Got a response in msg stream: ' + response); 64 | }); 65 | 66 | // Request with Auto-Unsubscribe. Will unsubscribe after 67 | // the first response is received via {'max':1} 68 | nats.request('help', null, {'max':1}, function(response) { 69 | console.log('Got a response for help: ' + response); 70 | }); 71 | 72 | // Replies 73 | nats.subscribe('help', function(request, replyTo) { 74 | nats.publish(replyTo, 'I can help!'); 75 | }); 76 | 77 | // Close connection 78 | nats.close(); 79 | 80 | ``` 81 | 82 | ## Wildcard Subscriptions 83 | 84 | ```javascript 85 | 86 | // "*" matches any token, at any level of the subject. 87 | nats.subscribe('foo.*.baz', function(msg, reply, subject) { 88 | console.log('Msg received on [' + subject + '] : ' + msg); 89 | }); 90 | 91 | nats.subscribe('foo.bar.*', function(msg, reply, subject) { 92 | console.log('Msg received on [' + subject + '] : ' + msg); 93 | }); 94 | 95 | // ">" matches any length of the tail of a subject, and can only be 96 | // the last token E.g. 'foo.>' will match 'foo.bar', 'foo.bar.baz', 97 | // 'foo.foo.bar.bax.22' 98 | nats.subscribe('foo.>', function(msg, reply, subject) { 99 | console.log('Msg received on [' + subject + '] : ' + msg); 100 | }); 101 | 102 | ``` 103 | 104 | ## Queue Groups 105 | 106 | ```javascript 107 | // All subscriptions with the same queue name will form a queue group. 108 | // Each message will be delivered to only one subscriber per queue group, 109 | // queuing semantics. You can have as many queue groups as you wish. 110 | // Normal subscribers will continue to work as expected. 111 | nats.subscribe('foo', {'queue':'job.workers'}, function() { 112 | received += 1; 113 | }); 114 | 115 | ``` 116 | ## Clustered Usage 117 | 118 | ```javascript 119 | var nats = require('websocket-nats'); 120 | 121 | var servers = ['ws://nats.io:4222', 'ws://nats.io:5222', 'ws://nats.io:6222']; 122 | 123 | // Randomly connect to a server in the cluster group. 124 | var nc = nats.connect({'servers': servers}); 125 | 126 | // currentServer is the URL of the connected server. 127 | console.log("Connected to " + nc.currentServer.host); 128 | 129 | // Preserve order when connecting to servers. 130 | nc = nats.connect({'dontRandomize': true, 'servers':servers}); 131 | 132 | ``` 133 | ## TLS 134 | 135 | TLS is currently not supported. You'll have to configure your websocket/TCP 136 | proxy to use TLS properly. 137 | 138 | ## Secure Websockets 139 | 140 | Connections can be made to secure websockets by using the `wss` protocol in the 141 | url passed to `NATS.connect`: 142 | 143 | ```javascript 144 | NATS.connect('wss://user:pass@localhost:4223'); 145 | ``` 146 | 147 | ## Advanced Usage 148 | 149 | ```javascript 150 | 151 | // Publish with closure, callback fires when server has processed the message 152 | nats.publish('foo', 'You done?', function() { 153 | console.log('msg processed!'); 154 | }); 155 | 156 | // Flush connection to server, callback fires when all messages have 157 | // been processed. 158 | nats.flush(function() { 159 | console.log('All clear!'); 160 | }); 161 | 162 | // If you want to make sure NATS yields during the processing 163 | // of messages, you can use an option to specify a yieldTime in ms. 164 | // During the processing of the inbound stream, we will yield if we 165 | // spend more then yieldTime milliseconds processing. 166 | var nc = nats.connect({port: PORT, yieldTime: 10}); 167 | 168 | // Timeouts for subscriptions 169 | var sid = nats.subscribe('foo', function() { 170 | received += 1; 171 | }); 172 | 173 | // Timeout unless a certain number of messages have been received 174 | nats.timeout(sid, timeout_ms, expected, function() { 175 | timeout = true; 176 | }); 177 | 178 | // Auto-unsubscribe after MAX_WANTED messages received 179 | nats.subscribe('foo', {'max':MAX_WANTED}); 180 | nats.unsubscribe(sid, MAX_WANTED); 181 | 182 | // Multiple connections 183 | var nats = require('websocket-nats'); 184 | var nc1 = nats.connect(); 185 | var nc2 = nats.connect(); 186 | 187 | nc1.subscribe('foo'); 188 | nc2.publish('foo'); 189 | 190 | // Encodings 191 | 192 | // By default messages received will be decoded using UTF8. To change that, 193 | // set the encoding option on the connection. 194 | 195 | nc = nats.connect({'servers':servers, 'encoding': 'ascii'}); 196 | 197 | ``` 198 | 199 | See examples and benchmarks for more information.. 200 | 201 | ## License 202 | 203 | (The MIT License) 204 | 205 | Copyright (c) 2015 Apcera Inc.
206 | Copyright (c) 2011-2015 Derek Collison 207 | 208 | Permission is hereby granted, free of charge, to any person obtaining a copy 209 | of this software and associated documentation files (the "Software"), to 210 | deal in the Software without restriction, including without limitation the 211 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 212 | sell copies of the Software, and to permit persons to whom the Software is 213 | furnished to do so, subject to the following conditions: 214 | 215 | The above copyright notice and this permission notice shall be included in 216 | all copies or substantial portions of the Software. 217 | 218 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 219 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 220 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 221 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 222 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 223 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 224 | IN THE SOFTWARE. 225 | -------------------------------------------------------------------------------- /dist/websocket-nats.min.js: -------------------------------------------------------------------------------- 1 | !function(t){function e(r){if(n[r])return n[r].exports;var i=n[r]={exports:{},id:r,loaded:!1};return t[r].call(i.exports,i,i.exports,e),i.loaded=!0,i.exports}var n={};return e.m=t,e.c=n,e.p="/dist/",e(0)}([function(t,e,n){window.NATS=n(1)},function(t,e,n){(function(t,r){/*! 2 | * Nats 3 | * Copyright(c) 2012-2016 Apcera Inc. All rights reserved. 4 | * Copyright(c) 2011-2014 Derek Collison (derek.collison@gmail.com) 5 | * MIT Licensed 6 | */ 7 | "use strict";function i(t){f.EventEmitter.call(this),this.parseOptions(t),this.initState(),this.createConnection()}function o(t){for(var e=t.length-1;e>0;e--){var n=Math.floor(Math.random()*(e+1)),r=t[e];t[e]=t[n],t[n]=r}return t}function s(t){this.url=t,this.didConnect=!1,this.reconnects=0}var h=n(8),u=n(13),a=n(14),c=n(9),f=n(12),l=n(20),p="0.6.8",d=4222,g="nats://localhost:",v=g+d,y=512,m=0,_=1,w=2e3,b=10,E=/^MSG\s+([^\s\r\n]+)\s+([^\s\r\n]+)\s+(([^\s\r\n]+)[^\S\r\n]+)?(\d+)\r\n/i,S=/^\+OK\s*\r\n/i,A=/^-ERR\s+('.+')?\r\n/i,x=/^PING\r\n/i,B=/^PONG\r\n/i,T=/^INFO\s+([^\r\n]+)\r\n/i,O=/^SUB\s+([^\r\n]+)\r\n/i,R="\r\n",I=R.length,C="",k=" ",P="SUB",U="UNSUB",j="CONNECT",L="PING"+R,z="PONG"+R,M="Subject must be supplied",N="Message can't be a function",Y="Reply can't be a function",D="Connection closed",q="Message should be a JSON object",F="User and Token can not both be provided",H=65536;e.version=p;var J=e.createInbox=function(){return"_INBOX."+l.next()};e.connect=function(t){return new i(t)},c.inherits(i,f.EventEmitter),i.prototype.createInbox=J,i.prototype.assignOption=function(t,e,n){void 0===n&&(n=e),void 0!==t[e]&&(this.options[n]=t[e])},i.prototype.parseOptions=function(e){var n=this.options={verbose:!1,pedantic:!1,reconnect:!0,maxReconnectAttempts:b,reconnectTimeWait:w,encoding:"utf8",tls:!1,waitOnFirstConnect:!1};void 0===e?n.url=v:"number"==typeof e?n.url=g+e:"string"==typeof e?n.url=e:"object"==typeof e&&(void 0!==e.port&&(n.url=g+e.port),this.assignOption(e,"url"),this.assignOption(e,"uri","url"),this.assignOption(e,"user"),this.assignOption(e,"pass"),this.assignOption(e,"token"),this.assignOption(e,"password","pass"),this.assignOption(e,"verbose"),this.assignOption(e,"pedantic"),this.assignOption(e,"reconnect"),this.assignOption(e,"maxReconnectAttempts"),this.assignOption(e,"reconnectTimeWait"),this.assignOption(e,"servers"),this.assignOption(e,"urls","servers"),this.assignOption(e,"noRandomize"),this.assignOption(e,"NoRandomize","noRandomize"),this.assignOption(e,"dontRandomize","noRandomize"),this.assignOption(e,"encoding"),this.assignOption(e,"tls"),this.assignOption(e,"secure","tls"),this.assignOption(e,"name"),this.assignOption(e,"client","name"),this.assignOption(e,"yieldTime"),this.assignOption(e,"waitOnFirstConnect"),this.assignOption(e,"json"));var r=this;if(r.user=n.user,r.pass=n.pass,r.token=n.token,r.user&&r.token)throw new Error(F);if(!t.isEncoding(n.encoding))throw new Error("Invalid Encoding:"+n.encoding);r.encoding=n.encoding,r.servers=[],Array.isArray(n.servers)?n.servers.forEach(function(t){r.servers.push(new s(a.parse(t)))}):(void 0===n.url&&(n.url=v),r.servers.push(new s(a.parse(n.url)))),n.noRandomize!==!0&&o(r.servers)},i.prototype.selectServer=function(){var t=this,e=t.servers.shift();if(t.currentServer=e,t.url=e.url,"auth"in e.url&&e.url.auth){var n=e.url.auth.split(":");1!==n.length?(void 0===t.options.user&&(t.user=n[0]),void 0===t.options.pass&&(t.pass=n[1])):void 0===t.options.token&&(t.token=n[0])}t.servers.push(e)},i.prototype.checkTLSMismatch=function(){return this.info.tls_required===!0&&this.options.tls===!1?(this.emit("error","Server requires a secure connection."),this.closeStream(),!0):this.info.tls_required===!1&&this.options.tls!==!1?(this.emit("error","Server does not support a secure connection."),this.closeStream(),!0):this.info.tls_verify===!0&&void 0===this.options.tls.cert&&(this.emit("error","Server requires a client certificate."),this.closeStream(),!0)},i.prototype.connectCB=function(){var t=this.reconnecting,e=t===!0?"reconnect":"connect";this.reconnecting=!1,this.reconnects=0,this.wasConnected=!0,this.currentServer.didConnect=!0,this.emit(e,this),this.flushPending()},i.prototype.setupHandlers=function(){var e=this,n=e.stream;void 0!==n&&(n.on("connect",function(){e.connected=!0}),n.on("close",function(t){e.closeStream(),e.emit("disconnect"),e.closed===!0||e.options.reconnect===!1||e.reconnects>=e.options.maxReconnectAttempts&&e.options.maxReconnectAttempts!==-1?e.emit("close"):e.scheduleReconnect()}),n.on("error",function(t){e.wasConnected===!0&&e.currentServer.didConnect===!0||(e.wasConnected===!1&&e.currentServer.didConnect===!1&&(e.options.waitOnFirstConnect?e.currentServer.didConnect=!0:e.servers.splice(e.servers.length-1,1)),e.wasConnected===!1&&0===e.servers.length&&e.emit("error","Could not connect to server: "+t),e.closeStream())}),n.on("data",function(n){e.inbound?e.inbound=t.concat([e.inbound,n]):e.inbound=n,e.processInbound()}))},i.prototype.sendConnect=function(){var t={lang:"node",version:p,verbose:this.options.verbose,pedantic:this.options.pedantic};void 0!==this.user&&(t.user=this.user,t.pass=this.pass),void 0!==this.token&&(t.auth_token=this.token),void 0!==this.options.name&&(t.name=this.options.name),this.stream.write(j+k+JSON.stringify(t)+R)},i.prototype.createConnection=function(){var e=[],n=[],r=0,i=this;if(null!==i.pending){var o=0;i.pending.forEach(function(s){var h=t.isBuffer(s)?s.length:t.byteLength(s);if(s===L&&null!==i.pongs&&o3&&"P"==s[0]&&"U"==s[1]&&"B"==s[2]&&(n.push(s),r+=h)})}this.pongs=e,this.pending=n,this.pSize=r,this.pstate=m,this.info=null,this.infoReceived=!1,this.selectServer(),this.stream=h.createConnection(this.url),this.setupHandlers()},i.prototype.initState=function(){this.ssid=1,this.subs={},this.reconnects=0,this.connected=!1,this.wasConnected=!1,this.reconnecting=!1,this.server=null,this.pending=[]},i.prototype.close=function(){this.closed=!0,this.removeAllListeners(),this.closeStream(),this.ssid=-1,this.subs=null,this.pstate=-1,this.pongs=null,this.pending=null,this.pSize=0},i.prototype.closeStream=function(){null!==this.stream&&(this.stream.end(),this.stream.destroy(),this.stream=null),this.connected!==!0&&this.closed!==!0||(this.pongs=null,this.pending=null,this.pSize=0,this.connected=!1),this.inbound=null},i.prototype.flushPending=function(){if(this.connected!==!1&&null!==this.pending&&0!==this.pending.length&&this.infoReceived===!0){var e=this,n=function(t){return e.pending=[],e.pSize=0,e.stream.write(t)};if(this.pBufs){for(var r=!0,i=0;iH&&this.flushPending()},i.prototype.sendSubscriptions=function(){var t="";for(var e in this.subs)if(this.subs.hasOwnProperty(e)){var n,r=this.subs[e];n=r.qgroup?[P,r.subject,r.qgroup,e+R]:[P,r.subject,e+R],t+=n.join(k)}t.length>0&&this.stream.write(t)},i.prototype.processInbound=function(){var e,n,i=this;for(i.stream.resume(),void 0!==i.options.yieldTime&&(n=Date.now());!i.closed&&i.inbound&&i.inbound.length>0;){switch(i.pstate){case m:var o=i.inbound.toString("binary",0,y);if(null!==(e=E.exec(o)))i.payload={subj:e[1],sid:parseInt(e[2],10),reply:e[4],size:parseInt(e[5],10)},i.payload.psize=i.payload.size+I,i.pstate=_;else if(null!==(e=S.exec(o)));else if(null!==(e=A.exec(o)))i.emit("error",e[1]);else if(null!==(e=B.exec(o))){var s=i.pongs&&i.pongs.shift();s&&s()}else if(null!==(e=x.exec(o)))i.sendCommand(z);else{if(null===(e=T.exec(o)))return;if(i.info=JSON.parse(e[1]),i.checkTLSMismatch()===!0)return;if(i.infoReceived===!1){if(i.options.tls!==!1&&i.stream.encrypted!==!0){var h={socket:i.stream};if("object"==typeof i.options.tls)for(var a in i.options.tls)h[a]=i.options.tls[a];i.stream=u.connect(h,function(){i.flushPending()}),i.setupHandlers()}i.sendConnect(),i.sendSubscriptions(),i.pongs.unshift(function(){i.connectCB()}),i.stream.write(L),i.infoReceived=!0,i.stripPendingSubs(),i.flushPending()}}break;case _:if(i.inbound.lengthi.options.yieldTime)return i.stream.pause(),void r(i.processInbound.bind(this))}if(e&&!this.closed){var f=e[0].length;f>=i.inbound.length?i.inbound=null:i.inbound=i.inbound.slice(f)}e=null}},i.prototype.processMsg=function(){var e=this.subs[this.payload.sid];if(void 0!==e&&(e.received+=1,e.timeout&&e.received>=e.expected&&(clearTimeout(e.timeout),e.timeout=null),void 0!==e.max&&(e.received===e.max?(delete this.subs[this.payload.sid],this.emit("unsubscribe",this.payload.sid,e.subject)):e.received>e.max&&(this.unsubscribe(this.payload.sid),e.callback=null)),e.callback)){var n=this.payload.msg;if(this.options.json)try{n=JSON.parse(new t(this.payload.msg,this.options.encoding).toString())}catch(t){n=t}e.callback(n,this.payload.reply,this.payload.subj,this.payload.sid)}},i.prototype.addServer=function(t){this.servers.push(new s(a.parse(t))),this.options.noRandomize!==!0&&o(this.servers)},i.prototype.flush=function(t){if(this.closed){if("function"==typeof t)return void t(new Error(D));throw new Error(D)}this.pongs&&(this.pongs.push(t),this.sendCommand(L),this.flushPending())},i.prototype.publish=function(e,n,r,i){if("function"==typeof e&&(i=e,e=void 0),n||(n=C),!e){if(!i)throw new Error(M);i(new Error(M))}if("function"==typeof n){if(i||r)return void i(new Error(N));i=n,n=C,r=void 0}if("function"==typeof r){if(i)return void i(new Error(Y));i=r,r=void 0}var o;if(o=void 0===r?"PUB "+e+k:"PUB "+e+k+r+k,"ArrayBuffer"in window&&ArrayBuffer.isView(n)&&(n=t.from(n)),t.isBuffer(n)){var s=new t(o.length+n.length+2*I+n.length.toString().length),h=s.write(o+n.length+R);n.copy(s,h),s.write(R,h+n.length),this.sendCommand(s)}else{var u=n;if(this.options.json){if("object"!=typeof n||Array.isArray(n))throw new Error(q);try{u=JSON.stringify(n)}catch(t){throw new Error(q)}}this.sendCommand(o+t.byteLength(u)+R+u+R)}if(void 0!==i)this.flush(i);else if(this.closed)throw new Error(D)},i.prototype.subscribe=function(t,e,n){if(this.closed)throw new Error(D);var r,i;"function"==typeof e?(n=e,e=void 0):e&&"object"==typeof e&&(r=e.queue,i=e.max),this.ssid+=1,this.subs[this.ssid]={subject:t,callback:n,received:0};var o;return"string"==typeof r?(this.subs[this.ssid].qgroup=r,o=[P,t,r,this.ssid+R]):o=[P,t,this.ssid+R],this.sendCommand(o.join(k)),this.emit("subscribe",this.ssid,t,e),i&&this.unsubscribe(this.ssid,i),this.ssid},i.prototype.unsubscribe=function(t,e){if(t&&!this.closed){var n;n=e?[U,t,e+R]:[U,t+R],this.sendCommand(n.join(k));var r=this.subs[t];void 0!==r&&(r.max=e,(void 0===r.max||r.received>=r.max)&&(delete this.subs[t],this.emit("unsubscribe",t,r.subject)))}},i.prototype.timeout=function(t,e,n,r){if(t){var i=this.subs[t];null!==i&&(i.expected=n,i.timeout=setTimeout(function(){r(t)},e))}},i.prototype.request=function(t,e,n,r){"function"==typeof e&&(r=e,e=C,n=null),"function"==typeof n&&(r=n,n=null);var i=J(),o=this.subscribe(i,n,function(t,e){r(t,e)});return this.publish(t,e,i),o},i.prototype.numSubscriptions=function(){return Object.keys(this.subs).length},i.prototype.reconnect=function(){this.closed||(this.reconnects+=1,this.createConnection(),this.currentServer.didConnect===!0&&this.emit("reconnecting"))},i.prototype.scheduleReconnect=function(){var t=this;if(0!==t.servers.length){t.wasConnected===!0&&(t.reconnecting=!0);var e=0;t.servers[0].didConnect===!0&&(e=this.options.reconnectTimeWait),setTimeout(function(){t.reconnect()},e)}}}).call(e,n(2).Buffer,n(6).setImmediate)},function(t,e,n){(function(t,r){/*! 8 | * The buffer module from node.js, for the browser. 9 | * 10 | * @author Feross Aboukhadijeh 11 | * @license MIT 12 | */ 13 | "use strict";function i(){try{var t=new Uint8Array(1);return t.__proto__={__proto__:Uint8Array.prototype,foo:function(){return 42}},42===t.foo()&&"function"==typeof t.subarray&&0===t.subarray(1,1).byteLength}catch(t){return!1}}function o(){return t.TYPED_ARRAY_SUPPORT?2147483647:1073741823}function s(e,n){if(o()=o())throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+o().toString(16)+" bytes");return 0|t}function v(e){return+e!=e&&(e=0),t.alloc(+e)}function y(e,n){if(t.isBuffer(e))return e.length;if("undefined"!=typeof ArrayBuffer&&"function"==typeof ArrayBuffer.isView&&(ArrayBuffer.isView(e)||e instanceof ArrayBuffer))return e.byteLength;"string"!=typeof e&&(e=""+e);var r=e.length;if(0===r)return 0;for(var i=!1;;)switch(n){case"ascii":case"latin1":case"binary":return r;case"utf8":case"utf-8":case void 0:return J(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*r;case"hex":return r>>>1;case"base64":return $(e).length;default:if(i)return J(e).length;n=(""+n).toLowerCase(),i=!0}}function m(t,e,n){var r=!1;if((void 0===e||e<0)&&(e=0),e>this.length)return"";if((void 0===n||n>this.length)&&(n=this.length),n<=0)return"";if(n>>>=0,e>>>=0,n<=e)return"";for(t||(t="utf8");;)switch(t){case"hex":return P(this,e,n);case"utf8":case"utf-8":return R(this,e,n);case"ascii":return C(this,e,n);case"latin1":case"binary":return k(this,e,n);case"base64":return O(this,e,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return U(this,e,n);default:if(r)throw new TypeError("Unknown encoding: "+t);t=(t+"").toLowerCase(),r=!0}}function _(t,e,n){var r=t[e];t[e]=t[n],t[n]=r}function w(e,n,r,i,o){if(0===e.length)return-1;if("string"==typeof r?(i=r,r=0):r>2147483647?r=2147483647:r<-2147483648&&(r=-2147483648),r=+r,isNaN(r)&&(r=o?0:e.length-1),r<0&&(r=e.length+r),r>=e.length){if(o)return-1;r=e.length-1}else if(r<0){if(!o)return-1;r=0}if("string"==typeof n&&(n=t.from(n,i)),t.isBuffer(n))return 0===n.length?-1:b(e,n,r,i,o);if("number"==typeof n)return n&=255,t.TYPED_ARRAY_SUPPORT&&"function"==typeof Uint8Array.prototype.indexOf?o?Uint8Array.prototype.indexOf.call(e,n,r):Uint8Array.prototype.lastIndexOf.call(e,n,r):b(e,[n],r,i,o);throw new TypeError("val must be string, number or Buffer")}function b(t,e,n,r,i){function o(t,e){return 1===s?t[e]:t.readUInt16BE(e*s)}var s=1,h=t.length,u=e.length;if(void 0!==r&&(r=String(r).toLowerCase(),"ucs2"===r||"ucs-2"===r||"utf16le"===r||"utf-16le"===r)){if(t.length<2||e.length<2)return-1;s=2,h/=2,u/=2,n/=2}var a;if(i){var c=-1;for(a=n;ah&&(n=h-u),a=n;a>=0;a--){for(var f=!0,l=0;li&&(r=i)):r=i;var o=e.length;if(o%2!==0)throw new TypeError("Invalid hex string");r>o/2&&(r=o/2);for(var s=0;s239?4:o>223?3:o>191?2:1;if(i+h<=n){var u,a,c,f;switch(h){case 1:o<128&&(s=o);break;case 2:u=t[i+1],128===(192&u)&&(f=(31&o)<<6|63&u,f>127&&(s=f));break;case 3:u=t[i+1],a=t[i+2],128===(192&u)&&128===(192&a)&&(f=(15&o)<<12|(63&u)<<6|63&a,f>2047&&(f<55296||f>57343)&&(s=f));break;case 4:u=t[i+1],a=t[i+2],c=t[i+3],128===(192&u)&&128===(192&a)&&128===(192&c)&&(f=(15&o)<<18|(63&u)<<12|(63&a)<<6|63&c,f>65535&&f<1114112&&(s=f))}}null===s?(s=65533,h=1):s>65535&&(s-=65536,r.push(s>>>10&1023|55296),s=56320|1023&s),r.push(s),i+=h}return I(r)}function I(t){var e=t.length;if(e<=tt)return String.fromCharCode.apply(String,t);for(var n="",r=0;rr)&&(n=r);for(var i="",o=e;on)throw new RangeError("Trying to access beyond buffer length")}function L(e,n,r,i,o,s){if(!t.isBuffer(e))throw new TypeError('"buffer" argument must be a Buffer instance');if(n>o||ne.length)throw new RangeError("Index out of range")}function z(t,e,n,r){e<0&&(e=65535+e+1);for(var i=0,o=Math.min(t.length-n,2);i>>8*(r?i:1-i)}function M(t,e,n,r){e<0&&(e=4294967295+e+1);for(var i=0,o=Math.min(t.length-n,4);i>>8*(r?i:3-i)&255}function N(t,e,n,r,i,o){if(n+r>t.length)throw new RangeError("Index out of range");if(n<0)throw new RangeError("Index out of range")}function Y(t,e,n,r,i){return i||N(t,e,n,4,3.4028234663852886e38,-3.4028234663852886e38),X.write(t,e,n,r,23,4),n+4}function D(t,e,n,r,i){return i||N(t,e,n,8,1.7976931348623157e308,-1.7976931348623157e308),X.write(t,e,n,r,52,8),n+8}function q(t){if(t=F(t).replace(et,""),t.length<2)return"";for(;t.length%4!==0;)t+="=";return t}function F(t){return t.trim?t.trim():t.replace(/^\s+|\s+$/g,"")}function H(t){return t<16?"0"+t.toString(16):t.toString(16)}function J(t,e){e=e||1/0;for(var n,r=t.length,i=null,o=[],s=0;s55295&&n<57344){if(!i){if(n>56319){(e-=3)>-1&&o.push(239,191,189);continue}if(s+1===r){(e-=3)>-1&&o.push(239,191,189);continue}i=n;continue}if(n<56320){(e-=3)>-1&&o.push(239,191,189),i=n;continue}n=(i-55296<<10|n-56320)+65536}else i&&(e-=3)>-1&&o.push(239,191,189);if(i=null,n<128){if((e-=1)<0)break;o.push(n)}else if(n<2048){if((e-=2)<0)break;o.push(n>>6|192,63&n|128)}else if(n<65536){if((e-=3)<0)break;o.push(n>>12|224,n>>6&63|128,63&n|128)}else{if(!(n<1114112))throw new Error("Invalid code point");if((e-=4)<0)break;o.push(n>>18|240,n>>12&63|128,n>>6&63|128,63&n|128)}}return o}function G(t){for(var e=[],n=0;n>8,i=n%256,o.push(i),o.push(r);return o}function $(t){return K.toByteArray(q(t))}function V(t,e,n,r){for(var i=0;i=e.length||i>=t.length);++i)e[i+n]=t[i];return i}function Z(t){return t!==t}var K=n(3),X=n(4),Q=n(5);e.Buffer=t,e.SlowBuffer=v,e.INSPECT_MAX_BYTES=50,t.TYPED_ARRAY_SUPPORT=void 0!==r.TYPED_ARRAY_SUPPORT?r.TYPED_ARRAY_SUPPORT:i(),e.kMaxLength=o(),t.poolSize=8192,t._augment=function(e){return e.__proto__=t.prototype,e},t.from=function(t,e,n){return h(null,t,e,n)},t.TYPED_ARRAY_SUPPORT&&(t.prototype.__proto__=Uint8Array.prototype,t.__proto__=Uint8Array,"undefined"!=typeof Symbol&&Symbol.species&&t[Symbol.species]===t&&Object.defineProperty(t,Symbol.species,{value:null,configurable:!0})),t.alloc=function(t,e,n){return a(null,t,e,n)},t.allocUnsafe=function(t){return c(null,t)},t.allocUnsafeSlow=function(t){return c(null,t)},t.isBuffer=function(t){return!(null==t||!t._isBuffer)},t.compare=function(e,n){if(!t.isBuffer(e)||!t.isBuffer(n))throw new TypeError("Arguments must be Buffers");if(e===n)return 0;for(var r=e.length,i=n.length,o=0,s=Math.min(r,i);o0&&(t=this.toString("hex",0,n).match(/.{2}/g).join(" "),this.length>n&&(t+=" ... ")),""},t.prototype.compare=function(e,n,r,i,o){if(!t.isBuffer(e))throw new TypeError("Argument must be a Buffer");if(void 0===n&&(n=0),void 0===r&&(r=e?e.length:0),void 0===i&&(i=0),void 0===o&&(o=this.length),n<0||r>e.length||i<0||o>this.length)throw new RangeError("out of range index");if(i>=o&&n>=r)return 0;if(i>=o)return-1;if(n>=r)return 1;if(n>>>=0,r>>>=0,i>>>=0,o>>>=0,this===e)return 0;for(var s=o-i,h=r-n,u=Math.min(s,h),a=this.slice(i,o),c=e.slice(n,r),f=0;fi)&&(n=i),t.length>0&&(n<0||e<0)||e>this.length)throw new RangeError("Attempt to write outside buffer bounds");r||(r="utf8");for(var o=!1;;)switch(r){case"hex":return E(this,t,e,n);case"utf8":case"utf-8":return S(this,t,e,n);case"ascii":return A(this,t,e,n);case"latin1":case"binary":return x(this,t,e,n);case"base64":return B(this,t,e,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return T(this,t,e,n);default:if(o)throw new TypeError("Unknown encoding: "+r);r=(""+r).toLowerCase(),o=!0}},t.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};var tt=4096;t.prototype.slice=function(e,n){var r=this.length;e=~~e,n=void 0===n?r:~~n,e<0?(e+=r,e<0&&(e=0)):e>r&&(e=r),n<0?(n+=r,n<0&&(n=0)):n>r&&(n=r),n0&&(i*=256);)r+=this[t+--e]*i;return r},t.prototype.readUInt8=function(t,e){return e||j(t,1,this.length),this[t]},t.prototype.readUInt16LE=function(t,e){return e||j(t,2,this.length),this[t]|this[t+1]<<8},t.prototype.readUInt16BE=function(t,e){return e||j(t,2,this.length),this[t]<<8|this[t+1]},t.prototype.readUInt32LE=function(t,e){return e||j(t,4,this.length),(this[t]|this[t+1]<<8|this[t+2]<<16)+16777216*this[t+3]},t.prototype.readUInt32BE=function(t,e){return e||j(t,4,this.length),16777216*this[t]+(this[t+1]<<16|this[t+2]<<8|this[t+3])},t.prototype.readIntLE=function(t,e,n){t|=0,e|=0,n||j(t,e,this.length);for(var r=this[t],i=1,o=0;++o=i&&(r-=Math.pow(2,8*e)),r},t.prototype.readIntBE=function(t,e,n){t|=0,e|=0,n||j(t,e,this.length);for(var r=e,i=1,o=this[t+--r];r>0&&(i*=256);)o+=this[t+--r]*i;return i*=128,o>=i&&(o-=Math.pow(2,8*e)),o},t.prototype.readInt8=function(t,e){return e||j(t,1,this.length),128&this[t]?(255-this[t]+1)*-1:this[t]},t.prototype.readInt16LE=function(t,e){e||j(t,2,this.length);var n=this[t]|this[t+1]<<8;return 32768&n?4294901760|n:n},t.prototype.readInt16BE=function(t,e){e||j(t,2,this.length);var n=this[t+1]|this[t]<<8;return 32768&n?4294901760|n:n},t.prototype.readInt32LE=function(t,e){return e||j(t,4,this.length),this[t]|this[t+1]<<8|this[t+2]<<16|this[t+3]<<24},t.prototype.readInt32BE=function(t,e){return e||j(t,4,this.length),this[t]<<24|this[t+1]<<16|this[t+2]<<8|this[t+3]},t.prototype.readFloatLE=function(t,e){return e||j(t,4,this.length),X.read(this,t,!0,23,4)},t.prototype.readFloatBE=function(t,e){return e||j(t,4,this.length),X.read(this,t,!1,23,4)},t.prototype.readDoubleLE=function(t,e){return e||j(t,8,this.length),X.read(this,t,!0,52,8)},t.prototype.readDoubleBE=function(t,e){return e||j(t,8,this.length),X.read(this,t,!1,52,8)},t.prototype.writeUIntLE=function(t,e,n,r){if(t=+t,e|=0,n|=0,!r){var i=Math.pow(2,8*n)-1;L(this,t,e,n,i,0)}var o=1,s=0;for(this[e]=255&t;++s=0&&(s*=256);)this[e+o]=t/s&255;return e+n},t.prototype.writeUInt8=function(e,n,r){return e=+e,n|=0,r||L(this,e,n,1,255,0),t.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),this[n]=255&e,n+1},t.prototype.writeUInt16LE=function(e,n,r){return e=+e,n|=0,r||L(this,e,n,2,65535,0),t.TYPED_ARRAY_SUPPORT?(this[n]=255&e,this[n+1]=e>>>8):z(this,e,n,!0),n+2},t.prototype.writeUInt16BE=function(e,n,r){return e=+e,n|=0,r||L(this,e,n,2,65535,0),t.TYPED_ARRAY_SUPPORT?(this[n]=e>>>8,this[n+1]=255&e):z(this,e,n,!1),n+2},t.prototype.writeUInt32LE=function(e,n,r){return e=+e,n|=0,r||L(this,e,n,4,4294967295,0),t.TYPED_ARRAY_SUPPORT?(this[n+3]=e>>>24,this[n+2]=e>>>16,this[n+1]=e>>>8,this[n]=255&e):M(this,e,n,!0),n+4},t.prototype.writeUInt32BE=function(e,n,r){return e=+e,n|=0,r||L(this,e,n,4,4294967295,0),t.TYPED_ARRAY_SUPPORT?(this[n]=e>>>24,this[n+1]=e>>>16,this[n+2]=e>>>8,this[n+3]=255&e):M(this,e,n,!1),n+4},t.prototype.writeIntLE=function(t,e,n,r){if(t=+t,e|=0,!r){var i=Math.pow(2,8*n-1);L(this,t,e,n,i-1,-i)}var o=0,s=1,h=0;for(this[e]=255&t;++o>0)-h&255;return e+n},t.prototype.writeIntBE=function(t,e,n,r){if(t=+t,e|=0,!r){var i=Math.pow(2,8*n-1);L(this,t,e,n,i-1,-i)}var o=n-1,s=1,h=0;for(this[e+o]=255&t;--o>=0&&(s*=256);)t<0&&0===h&&0!==this[e+o+1]&&(h=1),this[e+o]=(t/s>>0)-h&255;return e+n},t.prototype.writeInt8=function(e,n,r){return e=+e,n|=0,r||L(this,e,n,1,127,-128),t.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),e<0&&(e=255+e+1),this[n]=255&e,n+1},t.prototype.writeInt16LE=function(e,n,r){return e=+e,n|=0,r||L(this,e,n,2,32767,-32768),t.TYPED_ARRAY_SUPPORT?(this[n]=255&e,this[n+1]=e>>>8):z(this,e,n,!0),n+2},t.prototype.writeInt16BE=function(e,n,r){return e=+e,n|=0,r||L(this,e,n,2,32767,-32768),t.TYPED_ARRAY_SUPPORT?(this[n]=e>>>8,this[n+1]=255&e):z(this,e,n,!1),n+2},t.prototype.writeInt32LE=function(e,n,r){return e=+e,n|=0,r||L(this,e,n,4,2147483647,-2147483648),t.TYPED_ARRAY_SUPPORT?(this[n]=255&e,this[n+1]=e>>>8,this[n+2]=e>>>16,this[n+3]=e>>>24):M(this,e,n,!0),n+4},t.prototype.writeInt32BE=function(e,n,r){return e=+e,n|=0,r||L(this,e,n,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),t.TYPED_ARRAY_SUPPORT?(this[n]=e>>>24,this[n+1]=e>>>16,this[n+2]=e>>>8,this[n+3]=255&e):M(this,e,n,!1),n+4},t.prototype.writeFloatLE=function(t,e,n){return Y(this,t,e,!0,n)},t.prototype.writeFloatBE=function(t,e,n){return Y(this,t,e,!1,n)},t.prototype.writeDoubleLE=function(t,e,n){return D(this,t,e,!0,n)},t.prototype.writeDoubleBE=function(t,e,n){return D(this,t,e,!1,n)},t.prototype.copy=function(e,n,r,i){if(r||(r=0),i||0===i||(i=this.length),n>=e.length&&(n=e.length),n||(n=0),i>0&&i=this.length)throw new RangeError("sourceStart out of bounds");if(i<0)throw new RangeError("sourceEnd out of bounds");i>this.length&&(i=this.length),e.length-n=0;--o)e[o+n]=this[o+r];else if(s<1e3||!t.TYPED_ARRAY_SUPPORT)for(o=0;o>>=0,r=void 0===r?this.length:r>>>0,e||(e=0);var s;if("number"==typeof e)for(s=n;s0)throw new Error("Invalid string. Length must be a multiple of 4");return"="===t[e-2]?2:"="===t[e-1]?1:0}function r(t){return 3*t.length/4-n(t)}function i(t){var e,r,i,o,s,h,u=t.length;s=n(t),h=new c(3*u/4-s),i=s>0?u-4:u;var f=0;for(e=0,r=0;e>16&255,h[f++]=o>>8&255,h[f++]=255&o;return 2===s?(o=a[t.charCodeAt(e)]<<2|a[t.charCodeAt(e+1)]>>4,h[f++]=255&o):1===s&&(o=a[t.charCodeAt(e)]<<10|a[t.charCodeAt(e+1)]<<4|a[t.charCodeAt(e+2)]>>2,h[f++]=o>>8&255,h[f++]=255&o),h}function o(t){return u[t>>18&63]+u[t>>12&63]+u[t>>6&63]+u[63&t]}function s(t,e,n){for(var r,i=[],s=e;sc?c:a+h));return 1===r?(e=t[n-1],i+=u[e>>2],i+=u[e<<4&63],i+="=="):2===r&&(e=(t[n-2]<<8)+t[n-1],i+=u[e>>10],i+=u[e>>4&63],i+=u[e<<2&63],i+="="),o.push(i),o.join("")}e.byteLength=r,e.toByteArray=i,e.fromByteArray=h;for(var u=[],a=[],c="undefined"!=typeof Uint8Array?Uint8Array:Array,f="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",l=0,p=f.length;l>1,c=-7,f=n?i-1:0,l=n?-1:1,p=t[e+f];for(f+=l,o=p&(1<<-c)-1,p>>=-c,c+=h;c>0;o=256*o+t[e+f],f+=l,c-=8);for(s=o&(1<<-c)-1,o>>=-c,c+=r;c>0;s=256*s+t[e+f],f+=l,c-=8);if(0===o)o=1-a;else{if(o===u)return s?NaN:(p?-1:1)*(1/0);s+=Math.pow(2,r),o-=a}return(p?-1:1)*s*Math.pow(2,o-r)},e.write=function(t,e,n,r,i,o){var s,h,u,a=8*o-i-1,c=(1<>1,l=23===i?Math.pow(2,-24)-Math.pow(2,-77):0,p=r?0:o-1,d=r?1:-1,g=e<0||0===e&&1/e<0?1:0;for(e=Math.abs(e),isNaN(e)||e===1/0?(h=isNaN(e)?1:0,s=c):(s=Math.floor(Math.log(e)/Math.LN2),e*(u=Math.pow(2,-s))<1&&(s--,u*=2),e+=s+f>=1?l/u:l*Math.pow(2,1-f),e*u>=2&&(s++,u/=2),s+f>=c?(h=0,s=c):s+f>=1?(h=(e*u-1)*Math.pow(2,i),s+=f):(h=e*Math.pow(2,f-1)*Math.pow(2,i),s=0));i>=8;t[n+p]=255&h,p+=d,h/=256,i-=8);for(s=s<0;t[n+p]=255&s,p+=d,s/=256,a-=8);t[n+p-d]|=128*g}},function(t,e){var n={}.toString;t.exports=Array.isArray||function(t){return"[object Array]"==n.call(t)}},function(t,e,n){(function(t,r){function i(t,e){this._id=t,this._clearFn=e}var o=n(7).nextTick,s=Function.prototype.apply,h=Array.prototype.slice,u={},a=0;e.setTimeout=function(){return new i(s.call(setTimeout,window,arguments),clearTimeout)},e.setInterval=function(){return new i(s.call(setInterval,window,arguments),clearInterval)},e.clearTimeout=e.clearInterval=function(t){t.close()},i.prototype.unref=i.prototype.ref=function(){},i.prototype.close=function(){this._clearFn.call(window,this._id)},e.enroll=function(t,e){clearTimeout(t._idleTimeoutId),t._idleTimeout=e},e.unenroll=function(t){clearTimeout(t._idleTimeoutId),t._idleTimeout=-1},e._unrefActive=e.active=function(t){clearTimeout(t._idleTimeoutId);var e=t._idleTimeout;e>=0&&(t._idleTimeoutId=setTimeout(function(){t._onTimeout&&t._onTimeout()},e))},e.setImmediate="function"==typeof t?t:function(t){var n=a++,r=!(arguments.length<2)&&h.call(arguments,1);return u[n]=!0,o(function(){u[n]&&(r?t.apply(null,r):t.call(null),e.clearImmediate(n))}),n},e.clearImmediate="function"==typeof r?r:function(t){delete u[t]}}).call(e,n(6).setImmediate,n(6).clearImmediate)},function(t,e){function n(){throw new Error("setTimeout has not been defined")}function r(){throw new Error("clearTimeout has not been defined")}function i(t){if(c===setTimeout)return setTimeout(t,0);if((c===n||!c)&&setTimeout)return c=setTimeout,setTimeout(t,0);try{return c(t,0)}catch(e){try{return c.call(null,t,0)}catch(e){return c.call(this,t,0)}}}function o(t){if(f===clearTimeout)return clearTimeout(t);if((f===r||!f)&&clearTimeout)return f=clearTimeout,clearTimeout(t);try{return f(t)}catch(e){try{return f.call(null,t)}catch(e){return f.call(this,t)}}}function s(){g&&p&&(g=!1,p.length?d=p.concat(d):v=-1,d.length&&h())}function h(){if(!g){var t=i(s);g=!0;for(var e=d.length;e;){for(p=d,d=[];++v1)for(var n=1;n=3&&(r.depth=arguments[2]),arguments.length>=4&&(r.colors=arguments[3]),g(n)?r.showHidden=n:n&&e._extend(r,n),b(r.showHidden)&&(r.showHidden=!1),b(r.depth)&&(r.depth=2),b(r.colors)&&(r.colors=!1),b(r.customInspect)&&(r.customInspect=!0),r.colors&&(r.stylize=o),u(r,t,r.depth)}function o(t,e){var n=i.styles[e];return n?"["+i.colors[n][0]+"m"+t+"["+i.colors[n][1]+"m":t}function s(t,e){return t}function h(t){var e={};return t.forEach(function(t,n){e[t]=!0}),e}function u(t,n,r){if(t.customInspect&&n&&B(n.inspect)&&n.inspect!==e.inspect&&(!n.constructor||n.constructor.prototype!==n)){var i=n.inspect(r,t);return _(i)||(i=u(t,i,r)),i}var o=a(t,n);if(o)return o;var s=Object.keys(n),g=h(s);if(t.showHidden&&(s=Object.getOwnPropertyNames(n)),x(n)&&(s.indexOf("message")>=0||s.indexOf("description")>=0))return c(n);if(0===s.length){if(B(n)){var v=n.name?": "+n.name:"";return t.stylize("[Function"+v+"]","special")}if(E(n))return t.stylize(RegExp.prototype.toString.call(n),"regexp");if(A(n))return t.stylize(Date.prototype.toString.call(n),"date");if(x(n))return c(n)}var y="",m=!1,w=["{","}"];if(d(n)&&(m=!0,w=["[","]"]),B(n)){var b=n.name?": "+n.name:"";y=" [Function"+b+"]"}if(E(n)&&(y=" "+RegExp.prototype.toString.call(n)),A(n)&&(y=" "+Date.prototype.toUTCString.call(n)),x(n)&&(y=" "+c(n)),0===s.length&&(!m||0==n.length))return w[0]+y+w[1];if(r<0)return E(n)?t.stylize(RegExp.prototype.toString.call(n),"regexp"):t.stylize("[Object]","special");t.seen.push(n);var S;return S=m?f(t,n,r,g,s):s.map(function(e){return l(t,n,r,g,e,m)}),t.seen.pop(),p(S,y,w)}function a(t,e){if(b(e))return t.stylize("undefined","undefined");if(_(e)){var n="'"+JSON.stringify(e).replace(/^"|"$/g,"").replace(/'/g,"\\'").replace(/\\"/g,'"')+"'";return t.stylize(n,"string")}return m(e)?t.stylize(""+e,"number"):g(e)?t.stylize(""+e,"boolean"):v(e)?t.stylize("null","null"):void 0}function c(t){return"["+Error.prototype.toString.call(t)+"]"}function f(t,e,n,r,i){for(var o=[],s=0,h=e.length;s-1&&(h=o?h.split("\n").map(function(t){return" "+t}).join("\n").substr(2):"\n"+h.split("\n").map(function(t){return" "+t}).join("\n"))):h=t.stylize("[Circular]","special")),b(s)){if(o&&i.match(/^\d+$/))return h;s=JSON.stringify(""+i),s.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)?(s=s.substr(1,s.length-2),s=t.stylize(s,"name")):(s=s.replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'"),s=t.stylize(s,"string"))}return s+": "+h}function p(t,e,n){var r=0,i=t.reduce(function(t,e){return r++,e.indexOf("\n")>=0&&r++,t+e.replace(/\u001b\[\d\d?m/g,"").length+1},0);return i>60?n[0]+(""===e?"":e+"\n ")+" "+t.join(",\n ")+" "+n[1]:n[0]+e+" "+t.join(", ")+" "+n[1]}function d(t){return Array.isArray(t)}function g(t){return"boolean"==typeof t}function v(t){return null===t}function y(t){return null==t}function m(t){return"number"==typeof t}function _(t){return"string"==typeof t}function w(t){return"symbol"==typeof t}function b(t){return void 0===t}function E(t){return S(t)&&"[object RegExp]"===O(t)}function S(t){return"object"==typeof t&&null!==t}function A(t){return S(t)&&"[object Date]"===O(t)}function x(t){return S(t)&&("[object Error]"===O(t)||t instanceof Error)}function B(t){return"function"==typeof t}function T(t){return null===t||"boolean"==typeof t||"number"==typeof t||"string"==typeof t||"symbol"==typeof t||"undefined"==typeof t}function O(t){return Object.prototype.toString.call(t)}function R(t){return t<10?"0"+t.toString(10):t.toString(10)}function I(){var t=new Date,e=[R(t.getHours()),R(t.getMinutes()),R(t.getSeconds())].join(":");return[t.getDate(),j[t.getMonth()],e].join(" ")}function C(t,e){return Object.prototype.hasOwnProperty.call(t,e)}var k=/%[sdj%]/g;e.format=function(t){if(!_(t)){for(var e=[],n=0;n=o)return t;switch(t){case"%s":return String(r[n++]);case"%d":return Number(r[n++]);case"%j":try{return JSON.stringify(r[n++])}catch(t){return"[Circular]"}default:return t}}),h=r[n];n0&&this._events[t].length>i&&(this._events[t].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[t].length),"function"==typeof console.trace&&console.trace())),this},n.prototype.on=n.prototype.addListener,n.prototype.once=function(t,e){function n(){this.removeListener(t,n),i||(i=!0,e.apply(this,arguments))}if(!r(e))throw TypeError("listener must be a function");var i=!1;return n.listener=e,this.on(t,n),this},n.prototype.removeListener=function(t,e){var n,i,s,h;if(!r(e))throw TypeError("listener must be a function");if(!this._events||!this._events[t])return this;if(n=this._events[t],s=n.length,i=-1,n===e||r(n.listener)&&n.listener===e)delete this._events[t],this._events.removeListener&&this.emit("removeListener",t,e);else if(o(n)){for(h=s;h-- >0;)if(n[h]===e||n[h].listener&&n[h].listener===e){i=h;break}if(i<0)return this;1===n.length?(n.length=0,delete this._events[t]):n.splice(i,1),this._events.removeListener&&this.emit("removeListener",t,e)}return this},n.prototype.removeAllListeners=function(t){var e,n;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[t]&&delete this._events[t],this;if(0===arguments.length){for(e in this._events)"removeListener"!==e&&this.removeAllListeners(e);return this.removeAllListeners("removeListener"),this._events={},this}if(n=this._events[t],r(n))this.removeListener(t,n);else if(n)for(;n.length;)this.removeListener(t,n[n.length-1]);return delete this._events[t],this},n.prototype.listeners=function(t){var e;return e=this._events&&this._events[t]?r(this._events[t])?[this._events[t]]:this._events[t].slice():[]},n.prototype.listenerCount=function(t){if(this._events){var e=this._events[t];if(r(e))return 1;if(e)return e.length}return 0},n.listenerCount=function(t,e){return t.listenerCount(e)}},function(t,e){e.connect=function(t,e){throw"TLS is not supported in the browser. Use WSS instead."}},function(t,e,n){function r(){this.protocol=null,this.slashes=null,this.auth=null,this.host=null,this.port=null,this.hostname=null,this.hash=null,this.search=null,this.query=null,this.pathname=null,this.path=null,this.href=null}function i(t,e,n){if(t&&a(t)&&t instanceof r)return t;var i=new r;return i.parse(t,e,n),i}function o(t){return u(t)&&(t=i(t)),t instanceof r?t.format():r.prototype.format.call(t)}function s(t,e){return i(t,!1,!0).resolve(e)}function h(t,e){return t?i(t,!1,!0).resolveObject(e):e}function u(t){return"string"==typeof t}function a(t){return"object"==typeof t&&null!==t}function c(t){return null===t}function f(t){return null==t}var l=n(15);e.parse=i,e.resolve=s,e.resolveObject=h,e.format=o,e.Url=r;var p=/^([a-z0-9.+-]+:)/i,d=/:[0-9]*$/,g=["<",">",'"',"`"," ","\r","\n","\t"],v=["{","}","|","\\","^","`"].concat(g),y=["'"].concat(v),m=["%","/","?",";","#"].concat(y),_=["/","?","#"],w=255,b=/^[a-z0-9A-Z_-]{0,63}$/,E=/^([a-z0-9A-Z_-]{0,63})(.*)$/,S={javascript:!0,"javascript:":!0},A={javascript:!0,"javascript:":!0},x={http:!0,https:!0,ftp:!0,gopher:!0,file:!0,"http:":!0,"https:":!0,"ftp:":!0,"gopher:":!0,"file:":!0},B=n(17);r.prototype.parse=function(t,e,n){if(!u(t))throw new TypeError("Parameter 'url' must be a string, not "+typeof t);var r=t;r=r.trim();var i=p.exec(r);if(i){i=i[0];var o=i.toLowerCase();this.protocol=o,r=r.substr(i.length)}if(n||i||r.match(/^\/\/[^@\/]+@[^@\/]+/)){var s="//"===r.substr(0,2);!s||i&&A[i]||(r=r.substr(2),this.slashes=!0)}if(!A[i]&&(s||i&&!x[i])){for(var h=-1,a=0;a<_.length;a++){var c=r.indexOf(_[a]);c!==-1&&(h===-1||c127?"x":O[I];if(!R.match(b)){var k=v.slice(0,a),P=v.slice(a+1),U=O.match(E);U&&(k.push(U[1]),P.unshift(U[2])),P.length&&(r="/"+P.join(".")+r),this.hostname=k.join(".");break}}}if(this.hostname.length>w?this.hostname="":this.hostname=this.hostname.toLowerCase(),!g){for(var j=this.hostname.split("."),L=[],a=0;a0)&&n.host.split("@");v&&(n.auth=v.shift(),n.host=n.hostname=v.shift())}return n.search=t.search,n.query=t.query,c(n.pathname)&&c(n.search)||(n.path=(n.pathname?n.pathname:"")+(n.search?n.search:"")),n.href=n.format(),n}if(!d.length)return n.pathname=null,n.search?n.path="/"+n.search:n.path=null,n.href=n.format(),n;for(var y=d.slice(-1)[0],m=(n.host||t.host)&&("."===y||".."===y)||""===y,_=0,w=d.length;w>=0;w--)y=d[w],"."==y?d.splice(w,1):".."===y?(d.splice(w,1),_++):_&&(d.splice(w,1),_--);if(!l&&!p)for(;_--;_)d.unshift("..");!l||""===d[0]||d[0]&&"/"===d[0].charAt(0)||d.unshift(""),m&&"/"!==d.join("/").substr(-1)&&d.push("");var b=""===d[0]||d[0]&&"/"===d[0].charAt(0);if(g){n.hostname=n.host=b?"":d.length?d.shift():"";var v=!!(n.host&&n.host.indexOf("@")>0)&&n.host.split("@");v&&(n.auth=v.shift(),n.host=n.hostname=v.shift())}return l=l||n.host&&d.length,l&&!b&&d.unshift(""),d.length?n.pathname=d.join("/"):(n.pathname=null,n.path=null),c(n.pathname)&&c(n.search)||(n.path=(n.pathname?n.pathname:"")+(n.search?n.search:"")),n.auth=t.auth||n.auth,n.slashes=n.slashes||t.slashes,n.href=n.format(),n},r.prototype.parseHost=function(){var t=this.host,e=d.exec(t);e&&(e=e[0],":"!==e&&(this.port=e.substr(1)),t=t.substr(0,t.length-e.length)),t&&(this.hostname=t)}},function(t,e,n){var r;(function(t,i){!function(o){function s(t){throw RangeError(k[t])}function h(t,e){for(var n=t.length,r=[];n--;)r[n]=e(t[n]);return r}function u(t,e){var n=t.split("@"),r="";n.length>1&&(r=n[0]+"@",t=n[1]),t=t.replace(C,".");var i=t.split("."),o=h(i,e).join(".");return r+o}function a(t){for(var e,n,r=[],i=0,o=t.length;i=55296&&e<=56319&&i65535&&(t-=65536,e+=j(t>>>10&1023|55296),t=56320|1023&t),e+=j(t)}).join("")}function f(t){return t-48<10?t-22:t-65<26?t-65:t-97<26?t-97:b}function l(t,e){return t+22+75*(t<26)-((0!=e)<<5)}function p(t,e,n){var r=0;for(t=n?U(t/x):t>>1,t+=U(t/e);t>P*S>>1;r+=b)t=U(t/P);return U(r+(P+1)*t/(t+A))}function d(t){var e,n,r,i,o,h,u,a,l,d,g=[],v=t.length,y=0,m=T,_=B;for(n=t.lastIndexOf(O),n<0&&(n=0),r=0;r=128&&s("not-basic"),g.push(t.charCodeAt(r));for(i=n>0?n+1:0;i=v&&s("invalid-input"),a=f(t.charCodeAt(i++)),(a>=b||a>U((w-y)/h))&&s("overflow"),y+=a*h,l=u<=_?E:u>=_+S?S:u-_,!(aU(w/d)&&s("overflow"),h*=d;e=g.length+1,_=p(y-o,e,0==o),U(y/e)>w-m&&s("overflow"),m+=U(y/e),y%=e,g.splice(y++,0,m)}return c(g)}function g(t){var e,n,r,i,o,h,u,c,f,d,g,v,y,m,_,A=[];for(t=a(t),v=t.length,e=T,n=0,o=B,h=0;h=e&&gU((w-n)/y)&&s("overflow"),n+=(u-e)*y,e=u,h=0;hw&&s("overflow"),g==e){for(c=n,f=b;d=f<=o?E:f>=o+S?S:f-o,!(c= 0x80 (not a basic code point)","invalid-input":"Invalid input"},P=b-E,U=Math.floor,j=String.fromCharCode;_={version:"1.3.2",ucs2:{decode:a,encode:c},decode:d,encode:g,toASCII:y,toUnicode:v},r=function(){return _}.call(e,n,e,t),!(void 0!==r&&(t.exports=r))}(this)}).call(e,n(16)(t),function(){return this}())},function(t,e){t.exports=function(t){return t.webpackPolyfill||(t.deprecate=function(){},t.paths=[],t.children=[],t.webpackPolyfill=1),t}},function(t,e,n){"use strict";e.decode=e.parse=n(18),e.encode=e.stringify=n(19)},function(t,e){"use strict";function n(t,e){return Object.prototype.hasOwnProperty.call(t,e)}t.exports=function(t,e,r,i){e=e||"&",r=r||"=";var o={};if("string"!=typeof t||0===t.length)return o;var s=/\+/g;t=t.split(e);var h=1e3;i&&"number"==typeof i.maxKeys&&(h=i.maxKeys);var u=t.length;h>0&&u>h&&(u=h);for(var a=0;a=0?(c=d.substr(0,g),f=d.substr(g+1)):(c=d,f=""),l=decodeURIComponent(c),p=decodeURIComponent(f),n(o,l)?Array.isArray(o[l])?o[l].push(p):o[l]=[o[l],p]:o[l]=p}return o}},function(t,e){"use strict";var n=function(t){switch(typeof t){case"string":return t;case"boolean":return t?"true":"false";case"number":return isFinite(t)?t:"";default:return""}};t.exports=function(t,e,r,i){return e=e||"&",r=r||"=",null===t&&(t=void 0),"object"==typeof t?Object.keys(t).map(function(i){var o=encodeURIComponent(n(i))+r;return Array.isArray(t[i])?t[i].map(function(t){return o+encodeURIComponent(n(t))}).join(e):o+encodeURIComponent(n(t[i]))}).join(e):i?encodeURIComponent(n(i))+r+encodeURIComponent(n(t)):""}},function(t,e,n){t.exports=n(21)},function(t,e,n){(function(t){/*! 15 | * Nats 16 | * Copyright(c) 2016 Apcera Inc. All rights reserved. 17 | * MIT Licensed 18 | */ 19 | "use strict";function r(){this.buf=new t(p),this.init()}var i=n(22),o="0.6.8",s="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ",h=36,u=12,a=10,c=0xcfd41b9100000,f=33,l=333,p=u+a;e.version=o,r.prototype.init=function(){this.setPre(),this.initSeqAndInc(),this.fillSeq()},r.prototype.initSeqAndInc=function(){this.seq=Math.floor(Math.random()*c),this.inc=Math.floor(Math.random()*(l-f)+f)},r.prototype.setPre=function(){for(var t=i.randomBytes(u),e=0;e=u;e--)this.buf[e]=s.charCodeAt(t%h),t=Math.floor(t/h)},r.prototype.next=function(){return this.seq+=this.inc,this.seq>c&&this.setPre(),this.initSeqAndInc(),this.fillSeq(),this.buf.toString("ascii")};var d=new r;e.reset=function(){d.init()},e.next=function(){return d.next()},e._global=d}).call(e,n(2).Buffer)},function(t,e,n){(function(t){function r(){var t=[].slice.call(arguments).join(" ");throw new Error([t,"we accept pull requests","http://github.com/dominictarr/crypto-browserify"].join("\n"))}function i(t,e){for(var n in t)e(t[n],n)}var o=n(23);e.createHash=n(25),e.createHmac=n(34),e.randomBytes=function(e,n){if(!n||!n.call)return new t(o(e));try{n.call(this,void 0,new t(o(e)))}catch(t){n(t)}},e.getHashes=function(){return["sha1","sha256","sha512","md5","rmd160"]};var s=n(35)(e);e.pbkdf2=s.pbkdf2,e.pbkdf2Sync=s.pbkdf2Sync,i(["createCredentials","createCipher","createCipheriv","createDecipher","createDecipheriv","createSign","createVerify","createDiffieHellman"],function(t){e[t]=function(){r("sorry,",t,"is not implemented yet")}})}).call(e,n(2).Buffer)},function(t,e,n){(function(e,r){!function(){var i=("undefined"==typeof window?e:window)||{};_crypto=i.crypto||i.msCrypto||n(24),t.exports=function(t){if(_crypto.getRandomValues){var e=new r(t);return _crypto.getRandomValues(e),e}if(_crypto.randomBytes)return _crypto.randomBytes(t);throw new Error("secure random number generation not supported by this browser\nuse chrome, FireFox or Internet Explorer 11")}}()}).call(e,function(){return this}(),n(2).Buffer)},function(t,e){},function(t,e,n){(function(e){function r(t){return function(){var n=[],r={update:function(t,r){return e.isBuffer(t)||(t=new e(t,r)),n.push(t),this},digest:function(r){var i=e.concat(n),o=t(i);return n=null,r?o.toString(r):o}};return r}}var i=n(26),o=r(n(31)),s=r(n(33));t.exports=function(t){return"md5"===t?new o:"rmd160"===t?new s:i(t)}}).call(e,n(2).Buffer)},function(t,e,n){var e=t.exports=function(t){var n=e[t];if(!n)throw new Error(t+" is not supported (we accept pull requests)");return new n},r=n(2).Buffer,i=n(27)(r);e.sha1=n(28)(r,i),e.sha256=n(29)(r,i),e.sha512=n(30)(r,i)},function(t,e){t.exports=function(t){function e(e,n){this._block=new t(e),this._finalSize=n,this._blockSize=e,this._len=0,this._s=0}return e.prototype.init=function(){this._s=0,this._len=0},e.prototype.update=function(e,n){"string"==typeof e&&(n=n||"utf8",e=new t(e,n));for(var r=this._len+=e.length,i=this._s=this._s||0,o=0,s=this._block;i=8*this._finalSize&&(this._update(this._block),this._block.fill(0)),this._block.writeInt32BE(e,this._blockSize-4);var n=this._update(this._block)||this._hash();return t?n.toString(t):n},e.prototype._update=function(){throw new Error("_update must be implemented by subclass")},e}},function(t,e,n){var r=n(9).inherits;t.exports=function(t,e){function n(){return d.length?d.pop().init():this instanceof n?(this._w=p,e.call(this,64,56),this._h=null,void this.init()):new n}function i(t,e,n,r){return t<20?e&n|~e&r:t<40?e^n^r:t<60?e&n|e&r|n&r:e^n^r}function o(t){return t<20?1518500249:t<40?1859775393:t<60?-1894007588:-899497514}function s(t,e){return t+e|0}function h(t,e){return t<>>32-e}var u=0,a=4,c=8,f=12,l=16,p=new("undefined"==typeof Int32Array?Array:Int32Array)(80),d=[];return r(n,e),n.prototype.init=function(){return this._a=1732584193,this._b=4023233417,this._c=2562383102,this._d=271733878,this._e=3285377520,e.prototype.init.call(this),this},n.prototype._POOL=d,n.prototype._update=function(t){var e,n,r,u,a,c,f,l,p,d;e=c=this._a,n=f=this._b,r=l=this._c,u=p=this._d,a=d=this._e;for(var g=this._w,v=0;v<80;v++){var y=g[v]=v<16?t.readInt32BE(4*v):h(g[v-3]^g[v-8]^g[v-14]^g[v-16],1),m=s(s(h(e,5),i(v,n,r,u)),s(s(a,y),o(v)));a=u,u=r,r=h(n,30),n=e,e=m}this._a=s(e,c),this._b=s(n,f),this._c=s(r,l),this._d=s(u,p),this._e=s(a,d)},n.prototype._hash=function(){d.length<100&&d.push(this);var e=new t(20);return e.writeInt32BE(0|this._a,u),e.writeInt32BE(0|this._b,a),e.writeInt32BE(0|this._c,c),e.writeInt32BE(0|this._d,f),e.writeInt32BE(0|this._e,l),e},n}},function(t,e,n){var r=n(9).inherits;t.exports=function(t,e){function n(){this.init(),this._w=p,e.call(this,64,56)}function i(t,e){return t>>>e|t<<32-e}function o(t,e){return t>>>e}function s(t,e,n){return t&e^~t&n}function h(t,e,n){return t&e^t&n^e&n}function u(t){return i(t,2)^i(t,13)^i(t,22)}function a(t){return i(t,6)^i(t,11)^i(t,25)}function c(t){return i(t,7)^i(t,18)^o(t,3)}function f(t){return i(t,17)^i(t,19)^o(t,10)}var l=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298],p=new Array(64);return r(n,e),n.prototype.init=function(){return this._a=1779033703,this._b=-1150833019,this._c=1013904242,this._d=-1521486534,this._e=1359893119,this._f=-1694144372,this._g=528734635,this._h=1541459225,this._len=this._s=0,this},n.prototype._update=function(t){var e,n,r,i,o,p,d,g,v,y,m=this._w;e=0|this._a,n=0|this._b,r=0|this._c,i=0|this._d,o=0|this._e,p=0|this._f,d=0|this._g,g=0|this._h;for(var _=0;_<64;_++){var w=m[_]=_<16?t.readInt32BE(4*_):f(m[_-2])+m[_-7]+c(m[_-15])+m[_-16];v=g+a(o)+s(o,p,d)+l[_]+w,y=u(e)+h(e,n,r),g=d,d=p,p=o,o=i+v,i=r,r=n,n=e,e=v+y}this._a=e+this._a|0,this._b=n+this._b|0,this._c=r+this._c|0,this._d=i+this._d|0,this._e=o+this._e|0,this._f=p+this._f|0,this._g=d+this._g|0,this._h=g+this._h|0},n.prototype._hash=function(){var e=new t(32);return e.writeInt32BE(this._a,0),e.writeInt32BE(this._b,4),e.writeInt32BE(this._c,8),e.writeInt32BE(this._d,12),e.writeInt32BE(this._e,16),e.writeInt32BE(this._f,20),e.writeInt32BE(this._g,24),e.writeInt32BE(this._h,28),e},n}},function(t,e,n){var r=n(9).inherits;t.exports=function(t,e){function n(){this.init(),this._w=u,e.call(this,128,112)}function i(t,e,n){return t>>>n|e<<32-n}function o(t,e,n){return t&e^~t&n}function s(t,e,n){return t&e^t&n^e&n}var h=[1116352408,3609767458,1899447441,602891725,3049323471,3964484399,3921009573,2173295548,961987163,4081628472,1508970993,3053834265,2453635748,2937671579,2870763221,3664609560,3624381080,2734883394,310598401,1164996542,607225278,1323610764,1426881987,3590304994,1925078388,4068182383,2162078206,991336113,2614888103,633803317,3248222580,3479774868,3835390401,2666613458,4022224774,944711139,264347078,2341262773,604807628,2007800933,770255983,1495990901,1249150122,1856431235,1555081692,3175218132,1996064986,2198950837,2554220882,3999719339,2821834349,766784016,2952996808,2566594879,3210313671,3203337956,3336571891,1034457026,3584528711,2466948901,113926993,3758326383,338241895,168717936,666307205,1188179964,773529912,1546045734,1294757372,1522805485,1396182291,2643833823,1695183700,2343527390,1986661051,1014477480,2177026350,1206759142,2456956037,344077627,2730485921,1290863460,2820302411,3158454273,3259730800,3505952657,3345764771,106217008,3516065817,3606008344,3600352804,1432725776,4094571909,1467031594,275423344,851169720,430227734,3100823752,506948616,1363258195,659060556,3750685593,883997877,3785050280,958139571,3318307427,1322822218,3812723403,1537002063,2003034995,1747873779,3602036899,1955562222,1575990012,2024104815,1125592928,2227730452,2716904306,2361852424,442776044,2428436474,593698344,2756734187,3733110249,3204031479,2999351573,3329325298,3815920427,3391569614,3928383900,3515267271,566280711,3940187606,3454069534,4118630271,4000239992,116418474,1914138554,174292421,2731055270,289380356,3203993006,460393269,320620315,685471733,587496836,852142971,1086792851,1017036298,365543100,1126000580,2618297676,1288033470,3409855158,1501505948,4234509866,1607167915,987167468,1816402316,1246189591],u=new Array(160);return r(n,e),n.prototype.init=function(){return this._a=1779033703,this._b=-1150833019,this._c=1013904242,this._d=-1521486534,this._e=1359893119,this._f=-1694144372,this._g=528734635,this._h=1541459225,this._al=-205731576,this._bl=-2067093701,this._cl=-23791573,this._dl=1595750129,this._el=-1377402159,this._fl=725511199,this._gl=-79577749,this._hl=327033209,this._len=this._s=0,this},n.prototype._update=function(t){var e,n,r,u,a,c,f,l,p,d,g,v,y,m,_,w,b=this._w;e=0|this._a,n=0|this._b,r=0|this._c,u=0|this._d,a=0|this._e,c=0|this._f,f=0|this._g,l=0|this._h,p=0|this._al,d=0|this._bl,g=0|this._cl,v=0|this._dl,y=0|this._el,m=0|this._fl,_=0|this._gl,w=0|this._hl;for(var E=0;E<80;E++){var S,A,x=2*E;if(E<16)S=b[x]=t.readInt32BE(4*x),A=b[x+1]=t.readInt32BE(4*x+4);else{var B=b[x-30],T=b[x-30+1],O=i(B,T,1)^i(B,T,8)^B>>>7,R=i(T,B,1)^i(T,B,8)^i(T,B,7);B=b[x-4],T=b[x-4+1];var I=i(B,T,19)^i(T,B,29)^B>>>6,C=i(T,B,19)^i(B,T,29)^i(T,B,6),k=b[x-14],P=b[x-14+1],U=b[x-32],j=b[x-32+1];A=R+P,S=O+k+(A>>>0>>0?1:0),A+=C,S=S+I+(A>>>0>>0?1:0),A+=j,S=S+U+(A>>>0>>0?1:0),b[x]=S,b[x+1]=A}var L=s(e,n,r),z=s(p,d,g),M=i(e,p,28)^i(p,e,2)^i(p,e,7),N=i(p,e,28)^i(e,p,2)^i(e,p,7),Y=i(a,y,14)^i(a,y,18)^i(y,a,9),D=i(y,a,14)^i(y,a,18)^i(a,y,9),q=h[x],F=h[x+1],H=o(a,c,f),J=o(y,m,_),G=w+D,W=l+Y+(G>>>0>>0?1:0);G+=J,W=W+H+(G>>>0>>0?1:0),G+=F,W=W+q+(G>>>0>>0?1:0),G+=A,W=W+S+(G>>>0>>0?1:0);var $=N+z,V=M+L+($>>>0>>0?1:0);l=f,w=_,f=c,_=m,c=a,m=y,y=v+G|0,a=u+W+(y>>>0>>0?1:0)|0,u=r,v=g,r=n,g=d,n=e,d=p,p=G+$|0,e=W+V+(p>>>0>>0?1:0)|0}this._al=this._al+p|0,this._bl=this._bl+d|0,this._cl=this._cl+g|0,this._dl=this._dl+v|0,this._el=this._el+y|0,this._fl=this._fl+m|0,this._gl=this._gl+_|0,this._hl=this._hl+w|0,this._a=this._a+e+(this._al>>>0

>>0?1:0)|0,this._b=this._b+n+(this._bl>>>0>>0?1:0)|0,this._c=this._c+r+(this._cl>>>0>>0?1:0)|0,this._d=this._d+u+(this._dl>>>0>>0?1:0)|0,this._e=this._e+a+(this._el>>>0>>0?1:0)|0,this._f=this._f+c+(this._fl>>>0>>0?1:0)|0,this._g=this._g+f+(this._gl>>>0<_>>>0?1:0)|0,this._h=this._h+l+(this._hl>>>0>>0?1:0)|0},n.prototype._hash=function(){function e(t,e,r){n.writeInt32BE(t,r),n.writeInt32BE(e,r+4)}var n=new t(64);return e(this._a,this._al,0),e(this._b,this._bl,8),e(this._c,this._cl,16),e(this._d,this._dl,24),e(this._e,this._el,32),e(this._f,this._fl,40),e(this._g,this._gl,48),e(this._h,this._hl,56),n},n}},function(t,e,n){function r(t,e){t[e>>5]|=128<>>9<<4)+14]=e;for(var n=1732584193,r=-271733879,i=-1732584194,c=271733878,f=0;f>16)+(e>>16)+(n>>16);return r<<16|65535&n}function c(t,e){return t<>>32-e}var f=n(32);t.exports=function(t){return f.hash(t,r,16)}},function(t,e,n){(function(e){function n(t,n){if(t.length%o!==0){var r=t.length+(o-t.length%o);t=e.concat([t,s],r)}for(var i=[],h=n?t.readInt32BE:t.readInt32LE,u=0;u>>32-e}function u(t){var n=[1732584193,4023233417,2562383102,271733878,3285377520];"string"==typeof t&&(t=new e(t,"utf8"));var r=g(t),i=8*t.length,o=8*t.length;r[i>>>5]|=128<<24-i%32,r[(i+64>>>9<<4)+14]=16711935&(o<<8|o>>>24)|4278255360&(o<<24|o>>>8);for(var s=0;s>>24)|4278255360&(h<<24|h>>>8)}var u=v(n);return new e(u)}t.exports=u;/** @preserve 20 | (c) 2012 by Cédric Mesnil. All rights reserved. 21 | 22 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 23 | 24 | - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 25 | - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 26 | 27 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | var a=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,7,4,13,1,10,6,15,3,12,0,9,5,2,14,11,8,3,10,14,4,9,15,8,1,2,7,0,6,13,11,5,12,1,9,11,10,0,8,12,4,13,3,7,15,14,5,6,2,4,0,5,9,7,12,2,10,14,1,3,8,11,6,15,13],c=[5,14,7,0,9,2,11,4,13,6,15,8,1,10,3,12,6,11,3,7,0,13,5,10,14,15,8,12,4,9,1,2,15,5,1,3,7,14,6,9,11,8,12,2,10,0,4,13,8,6,4,1,3,11,15,0,5,12,2,13,9,7,10,14,12,15,10,4,1,5,8,7,6,2,13,14,0,3,9,11],f=[11,14,15,12,5,8,7,9,11,13,14,15,6,7,9,8,7,6,8,13,11,9,7,15,7,12,15,9,11,7,13,12,11,13,6,7,14,9,13,15,14,8,13,6,5,12,7,5,11,12,14,15,14,15,9,8,9,14,5,6,8,6,5,12,9,15,5,11,6,8,13,12,5,12,13,14,11,8,5,6],l=[8,9,9,11,13,15,15,5,7,7,8,11,14,14,12,6,9,13,15,7,12,8,9,11,7,7,12,7,6,15,13,11,9,7,15,11,8,6,6,14,12,13,5,14,13,13,7,5,15,5,8,11,14,14,6,14,6,9,12,9,12,5,15,8,8,5,12,9,12,5,14,6,8,13,6,5,15,13,11,11],p=[0,1518500249,1859775393,2400959708,2840853838],d=[1352829926,1548603684,1836072691,2053994217,0],g=function(t){for(var e=[],n=0,r=0;n>>5]|=t[n]<<24-r%32;return e},v=function(t){for(var e=[],n=0;n<32*t.length;n+=8)e.push(t[n>>>5]>>>24-n%32&255);return e},y=function(t,e,u){for(var g=0;g<16;g++){var v=u+g,y=e[v];e[v]=16711935&(y<<8|y>>>24)|4278255360&(y<<24|y>>>8)}var m,_,w,b,E,S,A,x,B,T;S=m=t[0],A=_=t[1],x=w=t[2],B=b=t[3],T=E=t[4];for(var O,g=0;g<80;g+=1)O=m+e[u+a[g]]|0,O+=g<16?n(_,w,b)+p[0]:g<32?r(_,w,b)+p[1]:g<48?i(_,w,b)+p[2]:g<64?o(_,w,b)+p[3]:s(_,w,b)+p[4],O|=0,O=h(O,f[g]),O=O+E|0,m=E,E=b,b=h(w,10),w=_,_=O,O=S+e[u+c[g]]|0,O+=g<16?s(A,x,B)+d[0]:g<32?o(A,x,B)+d[1]:g<48?i(A,x,B)+d[2]:g<64?r(A,x,B)+d[3]:n(A,x,B)+d[4],O|=0,O=h(O,l[g]),O=O+T|0,S=T,T=B,B=h(x,10),x=A,A=O;O=t[1]+w+B|0,t[1]=t[2]+b+T|0,t[2]=t[3]+E+S|0,t[3]=t[4]+m+A|0,t[4]=t[0]+_+x|0,t[0]=O}}).call(e,n(2).Buffer)},function(t,e,n){(function(e){function r(t,n){if(!(this instanceof r))return new r(t,n);this._opad=u,this._alg=t;var s="sha512"===t?128:64;n=this._key=e.isBuffer(n)?n:new e(n),n.length>s?n=i(t).update(n).digest():n.length(Math.pow(2,32)-1)*h))throw new TypeError("keylen exceeds maximum length");d.copy(a,0,0,h);for(var g=1;g 0) { 8 | crypto.getRandomValues(buf); 9 | } 10 | return buf; 11 | }; 12 | -------------------------------------------------------------------------------- /lib/nats.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Nats 3 | * Copyright(c) 2012-2016 Apcera Inc. All rights reserved. 4 | * Copyright(c) 2011-2014 Derek Collison (derek.collison@gmail.com) 5 | * MIT Licensed 6 | */ 7 | 8 | /* jslint node: true */ 9 | 'use strict'; 10 | 11 | /** 12 | * Module Dependencies 13 | */ 14 | 15 | var net = require('net'), 16 | tls = require('tls'), 17 | url = require('url'), 18 | util = require('util'), 19 | events = require('events'), 20 | nuid = require('nuid'); 21 | 22 | /** 23 | * Constants 24 | */ 25 | 26 | var VERSION = '0.6.8', 27 | 28 | DEFAULT_PORT = 4222, 29 | DEFAULT_PRE = 'nats://localhost:', 30 | DEFAULT_URI = DEFAULT_PRE + DEFAULT_PORT, 31 | 32 | MAX_CONTROL_LINE_SIZE = 512, 33 | 34 | // Parser state 35 | AWAITING_CONTROL = 0, 36 | AWAITING_MSG_PAYLOAD = 1, 37 | 38 | // Reconnect Parameters, 2 sec wait, 10 tries 39 | DEFAULT_RECONNECT_TIME_WAIT = 2*1000, 40 | DEFAULT_MAX_RECONNECT_ATTEMPTS = 10, 41 | 42 | // Protocol 43 | //CONTROL_LINE = /^(.*)\r\n/, // TODO: remove / never used 44 | 45 | MSG = /^MSG\s+([^\s\r\n]+)\s+([^\s\r\n]+)\s+(([^\s\r\n]+)[^\S\r\n]+)?(\d+)\r\n/i, 46 | OK = /^\+OK\s*\r\n/i, 47 | ERR = /^-ERR\s+('.+')?\r\n/i, 48 | PING = /^PING\r\n/i, 49 | PONG = /^PONG\r\n/i, 50 | INFO = /^INFO\s+([^\r\n]+)\r\n/i, 51 | SUBRE = /^SUB\s+([^\r\n]+)\r\n/i, 52 | 53 | CR_LF = '\r\n', 54 | CR_LF_LEN = CR_LF.length, 55 | EMPTY = '', 56 | SPC = ' ', 57 | 58 | // Protocol 59 | //PUB = 'PUB', // TODO: remove / never used 60 | SUB = 'SUB', 61 | UNSUB = 'UNSUB', 62 | CONNECT = 'CONNECT', 63 | 64 | // Responses 65 | PING_REQUEST = 'PING' + CR_LF, 66 | PONG_RESPONSE = 'PONG' + CR_LF, 67 | 68 | // Errors 69 | BAD_SUBJECT = 'Subject must be supplied', 70 | BAD_MSG = 'Message can\'t be a function', 71 | BAD_REPLY = 'Reply can\'t be a function', 72 | CONN_CLOSED = 'Connection closed', 73 | BAD_JSON_MSG = 'Message should be a JSON object', 74 | BAD_AUTHENTICATION = 'User and Token can not both be provided', 75 | 76 | // Pedantic Mode support 77 | //Q_SUB = /^([^\.\*>\s]+|>$|\*)(\.([^\.\*>\s]+|>$|\*))*$/, // TODO: remove / never used 78 | //Q_SUB_NO_WC = /^([^\.\*>\s]+)(\.([^\.\*>\s]+))*$/, // TODO: remove / never used 79 | 80 | FLUSH_THRESHOLD = 65536; 81 | 82 | /** 83 | * Library Version 84 | */ 85 | 86 | exports.version = VERSION; 87 | 88 | /** 89 | * Create a properly formatted inbox subject. 90 | * 91 | * @api public 92 | */ 93 | 94 | var createInbox = exports.createInbox = function() { 95 | return ("_INBOX." + nuid.next()); 96 | }; 97 | 98 | /** 99 | * Initialize a client with the appropriate options. 100 | * 101 | * @param {Mixed} opts 102 | * @api public 103 | */ 104 | 105 | function Client(opts) { 106 | events.EventEmitter.call(this); 107 | this.parseOptions(opts); 108 | this.initState(); 109 | this.createConnection(); 110 | } 111 | 112 | /** 113 | * Connect to a nats-server and return the client. 114 | * Argument can be a url, or an object with a 'url' 115 | * property and additional options. 116 | * 117 | * @params {Mixed} opts 118 | * 119 | * @api public 120 | */ 121 | 122 | exports.connect = function(opts) { 123 | return new Client(opts); 124 | }; 125 | 126 | /** 127 | * Connected clients are event emitters. 128 | */ 129 | 130 | util.inherits(Client, events.EventEmitter); 131 | 132 | /** 133 | * Allow createInbox to be called on a client. 134 | * 135 | * @api public 136 | */ 137 | 138 | Client.prototype.createInbox = createInbox; 139 | 140 | Client.prototype.assignOption = function(opts, prop, assign) { 141 | if (assign === undefined) { 142 | assign = prop; 143 | } 144 | if (opts[prop] !== undefined) { 145 | this.options[assign] = opts[prop]; 146 | } 147 | }; 148 | 149 | function shuffle(array) { 150 | for (var i = array.length - 1; i > 0; i--) { 151 | var j = Math.floor(Math.random() * (i + 1)); 152 | var temp = array[i]; 153 | array[i] = array[j]; 154 | array[j] = temp; 155 | } 156 | return array; 157 | } 158 | 159 | /** 160 | * Parse the conctructor/connect options. 161 | * 162 | * @param {Mixed} opts 163 | * @api private 164 | */ 165 | 166 | Client.prototype.parseOptions = function(opts) { 167 | var options = this.options = { 168 | 'verbose' : false, 169 | 'pedantic' : false, 170 | 'reconnect' : true, 171 | 'maxReconnectAttempts' : DEFAULT_MAX_RECONNECT_ATTEMPTS, 172 | 'reconnectTimeWait' : DEFAULT_RECONNECT_TIME_WAIT, 173 | 'encoding' : 'utf8', 174 | 'tls' : false, 175 | 'waitOnFirstConnect' : false, 176 | }; 177 | 178 | if (undefined === opts) { 179 | options.url = DEFAULT_URI; 180 | } else if ('number' === typeof opts) { 181 | options.url = DEFAULT_PRE + opts; 182 | } else if ('string' === typeof opts) { 183 | options.url = opts; 184 | } else if ('object' === typeof opts) { 185 | if (opts.port !== undefined) { 186 | options.url = DEFAULT_PRE + opts.port; 187 | } 188 | // Pull out various options here 189 | this.assignOption(opts, 'url'); 190 | this.assignOption(opts, 'uri', 'url'); 191 | this.assignOption(opts, 'user'); 192 | this.assignOption(opts, 'pass'); 193 | this.assignOption(opts, 'token'); 194 | this.assignOption(opts, 'password', 'pass'); 195 | this.assignOption(opts, 'verbose'); 196 | this.assignOption(opts, 'pedantic'); 197 | this.assignOption(opts, 'reconnect'); 198 | this.assignOption(opts, 'maxReconnectAttempts'); 199 | this.assignOption(opts, 'reconnectTimeWait'); 200 | this.assignOption(opts, 'servers'); 201 | this.assignOption(opts, 'urls', 'servers'); 202 | this.assignOption(opts, 'noRandomize'); 203 | this.assignOption(opts, 'NoRandomize', 'noRandomize'); 204 | this.assignOption(opts, 'dontRandomize', 'noRandomize'); 205 | this.assignOption(opts, 'encoding'); 206 | this.assignOption(opts, 'tls'); 207 | this.assignOption(opts, 'secure', 'tls'); 208 | this.assignOption(opts, 'name'); 209 | this.assignOption(opts, 'client', 'name'); 210 | this.assignOption(opts, 'yieldTime'); 211 | this.assignOption(opts, 'waitOnFirstConnect'); 212 | this.assignOption(opts, 'json'); 213 | } 214 | 215 | var client = this; 216 | 217 | // Set user/pass as needed if in options. 218 | client.user = options.user; 219 | client.pass = options.pass; 220 | 221 | // Set token as needed if in options. 222 | client.token = options.token; 223 | 224 | // Authentication - make sure authentication is valid. 225 | if (client.user && client.token) { 226 | throw(new Error(BAD_AUTHENTICATION)); 227 | } 228 | 229 | // Encoding - make sure its valid. 230 | if (Buffer.isEncoding(options.encoding)) { 231 | client.encoding = options.encoding; 232 | } else { 233 | throw new Error('Invalid Encoding:' + options.encoding); 234 | } 235 | // For cluster support 236 | client.servers = []; 237 | 238 | if (Array.isArray(options.servers)) { 239 | options.servers.forEach(function(server) { 240 | client.servers.push(new Server(url.parse(server))); 241 | }); 242 | } else { 243 | if (undefined === options.url) { 244 | options.url = DEFAULT_URI; 245 | } 246 | client.servers.push(new Server(url.parse(options.url))); 247 | } 248 | 249 | // Randomize if needed 250 | if (options.noRandomize !== true) { 251 | shuffle(client.servers); 252 | } 253 | }; 254 | 255 | /** 256 | * Create a new server. 257 | * 258 | * @api private 259 | */ 260 | 261 | function Server(url) { 262 | this.url = url; 263 | this.didConnect = false; 264 | this.reconnects = 0; 265 | } 266 | 267 | /** 268 | * Properly select the next server. 269 | * We rotate the server list as we go, 270 | * we also pull auth from urls as needed, or 271 | * if they were set in options use that as override. 272 | * 273 | * @api private 274 | */ 275 | 276 | Client.prototype.selectServer = function() { 277 | var client = this; 278 | var server = client.servers.shift(); 279 | 280 | // Place in client context. 281 | client.currentServer = server; 282 | client.url = server.url; 283 | if ('auth' in server.url && !!server.url.auth) { 284 | var auth = server.url.auth.split(':'); 285 | if (auth.length !== 1) { 286 | if (client.options.user === undefined) { 287 | client.user = auth[0]; 288 | } 289 | if (client.options.pass === undefined) { 290 | client.pass = auth[1]; 291 | } 292 | } else { 293 | if (client.options.token === undefined) { 294 | client.token = auth[0]; 295 | } 296 | } 297 | } 298 | client.servers.push(server); 299 | }; 300 | 301 | /** 302 | * Check for TLS configuration mismatch. 303 | * 304 | * @api private 305 | */ 306 | 307 | Client.prototype.checkTLSMismatch = function() { 308 | if (this.info.tls_required === true && 309 | this.options.tls === false) { 310 | this.emit('error', 'Server requires a secure connection.'); 311 | this.closeStream(); 312 | return true; 313 | } 314 | 315 | if (this.info.tls_required === false && 316 | this.options.tls !== false) { 317 | this.emit('error', 'Server does not support a secure connection.'); 318 | this.closeStream(); 319 | return true; 320 | } 321 | 322 | if (this.info.tls_verify === true && 323 | this.options.tls.cert === undefined) { 324 | this.emit('error', 'Server requires a client certificate.'); 325 | this.closeStream(); 326 | return true; 327 | } 328 | return false; 329 | }; 330 | 331 | /** 332 | * Callback for first flush/connect. 333 | * 334 | * @api private 335 | */ 336 | 337 | Client.prototype.connectCB = function() { 338 | var wasReconnecting = this.reconnecting; 339 | var event = (wasReconnecting === true) ? 'reconnect' : 'connect'; 340 | this.reconnecting = false; 341 | this.reconnects = 0; 342 | this.wasConnected = true; 343 | this.currentServer.didConnect = true; 344 | 345 | this.emit(event, this); 346 | 347 | this.flushPending(); 348 | }; 349 | 350 | 351 | /** 352 | * Properly setup a stream event handlers. 353 | * 354 | * @api private 355 | */ 356 | 357 | Client.prototype.setupHandlers = function() { 358 | var client = this; 359 | var stream = client.stream; 360 | 361 | if (undefined === stream) { 362 | return; 363 | } 364 | 365 | stream.on('connect', function() { 366 | client.connected = true; 367 | }); 368 | 369 | stream.on('close', function(hadError) { 370 | client.closeStream(); 371 | client.emit('disconnect'); 372 | if (client.closed === true || 373 | client.options.reconnect === false || 374 | ((client.reconnects >= client.options.maxReconnectAttempts) && client.options.maxReconnectAttempts !== -1)) { 375 | client.emit('close'); 376 | } else { 377 | client.scheduleReconnect(); 378 | } 379 | }); 380 | 381 | stream.on('error', function(exception) { 382 | // If we were connected just return, close event will process 383 | if (client.wasConnected === true && client.currentServer.didConnect === true) { 384 | return; 385 | } 386 | 387 | // if the current server did not connect at all, and we in 388 | // general have not connected to any server, remove it from 389 | // this list. Unless overidden 390 | if (client.wasConnected === false && client.currentServer.didConnect === false) { 391 | // We can override this behavior with waitOnFirstConnect, which will 392 | // treat it like a reconnect scenario. 393 | if (client.options.waitOnFirstConnect) { 394 | // Pretend to move us into a reconnect state. 395 | client.currentServer.didConnect = true; 396 | } else { 397 | client.servers.splice(client.servers.length-1, 1); 398 | } 399 | } 400 | 401 | // Only bubble up error if we never had connected 402 | // to the server and we only have one. 403 | if (client.wasConnected === false && client.servers.length === 0) { 404 | client.emit('error', 'Could not connect to server: ' + exception); 405 | } 406 | client.closeStream(); 407 | }); 408 | 409 | stream.on('data', function (data) { 410 | // If inbound exists, concat them together. We try to avoid this for split 411 | // messages, so this should only really happen for a split control line. 412 | // Long term answer is hand rolled parser and not regexp. 413 | if (client.inbound) { 414 | client.inbound = Buffer.concat([client.inbound, data]); 415 | } else { 416 | client.inbound = data; 417 | } 418 | 419 | // Process the inbound queue. 420 | client.processInbound(); 421 | }); 422 | }; 423 | 424 | /** 425 | * Send the connect command. This needs to happen after receiving the first 426 | * INFO message and after TLS is established if necessary. 427 | * 428 | * @api private 429 | */ 430 | 431 | Client.prototype.sendConnect = function() { 432 | // Queue the connect command. 433 | var cs = { 434 | 'lang' : 'node', 435 | 'version' : VERSION, 436 | 'verbose' : this.options.verbose, 437 | 'pedantic': this.options.pedantic 438 | }; 439 | if (this.user !== undefined) { 440 | cs.user = this.user; 441 | cs.pass = this.pass; 442 | } 443 | if (this.token !== undefined) { 444 | cs.auth_token = this.token; 445 | } 446 | if (this.options.name !== undefined) { 447 | cs.name = this.options.name; 448 | } 449 | 450 | // If we enqueued requests before we received INFO from the server, or we 451 | // reconnected, there be other data pending, write this immediately instead 452 | // of adding it to the queue. 453 | this.stream.write(CONNECT + SPC + JSON.stringify(cs) + CR_LF); 454 | }; 455 | 456 | /** 457 | * Properly setup a stream connection with proper events. 458 | * 459 | * @api private 460 | */ 461 | 462 | Client.prototype.createConnection = function() { 463 | // Commands may have been queued during reconnect. Discard everything except: 464 | // 1) ping requests with a pong callback 465 | // 2) publish requests 466 | // 467 | // Rationale: CONNECT and SUBs are written directly upon connecting, any PONG 468 | // response is no longer relevant, and any UNSUB will be accounted for when we 469 | // sync our SUBs. Without this, users of the client may miss state transitions 470 | // via callbacks, would have to track the client's internal connection state, 471 | // and may have to double buffer messages (which we are already doing) if they 472 | // wanted to ensure their messages reach the server. 473 | var pong = []; 474 | var pend = []; 475 | var pSize = 0; 476 | var client = this; 477 | if (client.pending !== null) { 478 | var pongIndex = 0; 479 | client.pending.forEach(function(cmd) { 480 | var cmdLen = Buffer.isBuffer(cmd) ? cmd.length : Buffer.byteLength(cmd); 481 | if (cmd === PING_REQUEST && client.pongs !== null && pongIndex < client.pongs.length) { 482 | // filter out any useless ping requests (no pong callback, nop flush) 483 | var p = client.pongs[pongIndex++]; 484 | if (p !== undefined) { 485 | pend.push(cmd); 486 | pSize += cmdLen; 487 | pong.push(p); 488 | } 489 | } else if (cmd.length > 3 && cmd[0] == 'P' && cmd[1] == 'U' && cmd[2] == 'B') { 490 | pend.push(cmd); 491 | pSize += cmdLen; 492 | } 493 | }); 494 | } 495 | this.pongs = pong; 496 | this.pending = pend; 497 | this.pSize = pSize; 498 | 499 | this.pstate = AWAITING_CONTROL; 500 | 501 | // Clear info processing. 502 | this.info = null; 503 | this.infoReceived = false; 504 | 505 | // Select a server to connect to. 506 | this.selectServer(); 507 | // Create the stream. 508 | this.stream = net.createConnection(this.url); 509 | // Setup the proper handlers. 510 | this.setupHandlers(); 511 | }; 512 | 513 | /** 514 | * Initialize client state. 515 | * 516 | * @api private 517 | */ 518 | 519 | Client.prototype.initState = function() { 520 | this.ssid = 1; 521 | this.subs = {}; 522 | this.reconnects = 0; 523 | this.connected = false; 524 | this.wasConnected = false; 525 | this.reconnecting = false; 526 | this.server = null; 527 | this.pending = []; 528 | }; 529 | 530 | /** 531 | * Close the connection to the server. 532 | * 533 | * @api public 534 | */ 535 | 536 | Client.prototype.close = function() { 537 | this.closed = true; 538 | this.removeAllListeners(); 539 | this.closeStream(); 540 | this.ssid = -1; 541 | this.subs = null; 542 | this.pstate = -1; 543 | this.pongs = null; 544 | this.pending = null; 545 | this.pSize = 0; 546 | }; 547 | 548 | /** 549 | * Close down the stream and clear state. 550 | * 551 | * @api private 552 | */ 553 | 554 | Client.prototype.closeStream = function() { 555 | if (this.stream !== null) { 556 | this.stream.end(); 557 | this.stream.destroy(); 558 | this.stream = null; 559 | } 560 | if (this.connected === true || this.closed === true) { 561 | this.pongs = null; 562 | this.pending = null; 563 | this.pSize = 0; 564 | this.connected = false; 565 | } 566 | this.inbound = null; 567 | }; 568 | 569 | /** 570 | * Flush all pending data to the server. 571 | * 572 | * @api private 573 | */ 574 | 575 | Client.prototype.flushPending = function() { 576 | if (this.connected === false || 577 | this.pending === null || 578 | this.pending.length === 0 || 579 | this.infoReceived !== true) { 580 | return; 581 | } 582 | 583 | var client = this; 584 | var write = function(data) { 585 | client.pending = []; 586 | client.pSize = 0; 587 | return client.stream.write(data); 588 | }; 589 | if (!this.pBufs) { 590 | // All strings, fastest for now. 591 | return write(this.pending.join(EMPTY)); 592 | } else { 593 | // We have some or all Buffers. Figure out if we can optimize. 594 | var allBufs = true; 595 | for (var i=0; i < this.pending.length; i++){ 596 | if (!Buffer.isBuffer(this.pending[i])) { 597 | allBufs = false; 598 | break; 599 | } 600 | } 601 | // If all buffers, concat together and write once. 602 | if (allBufs) { 603 | return write(Buffer.concat(this.pending, this.pSize)); 604 | } else { 605 | // We have a mix, so write each one individually. 606 | var pending = this.pending; 607 | this.pending = []; 608 | this.pSize = 0; 609 | var result = true; 610 | for (i=0; i < pending.length; i++){ 611 | result = this.stream.write(pending[i]) && result; 612 | } 613 | return result; 614 | } 615 | } 616 | }; 617 | 618 | /** 619 | * Strips all SUBS commands from pending during initial connection completed since 620 | * we send the subscriptions as a separate operation. 621 | * 622 | * @api private 623 | */ 624 | 625 | Client.prototype.stripPendingSubs = function() { 626 | var pending = this.pending; 627 | this.pending = []; 628 | this.pSize = 0; 629 | for (var i=0; i < pending.length; i++){ 630 | if (!SUBRE.test(pending[i])) { 631 | // Re-queue the command. 632 | this.sendCommand(pending[i]); 633 | } 634 | } 635 | }; 636 | 637 | /** 638 | * Send commands to the server or queue them up if connection pending. 639 | * 640 | * @api private 641 | */ 642 | 643 | Client.prototype.sendCommand = function(cmd) { 644 | // Buffer to cut down on system calls, increase throughput. 645 | // When receive gets faster, should make this Buffer based.. 646 | 647 | if (this.closed || this.pending === null) { return; } 648 | 649 | this.pending.push(cmd); 650 | if (!Buffer.isBuffer(cmd)) { 651 | this.pSize += Buffer.byteLength(cmd); 652 | } else { 653 | this.pSize += cmd.length; 654 | this.pBufs = true; 655 | } 656 | 657 | if (this.connected === true) { 658 | // First one let's setup flush.. 659 | if (this.pending.length === 1) { 660 | var self = this; 661 | setImmediate(function() { 662 | self.flushPending(); 663 | }); 664 | } else if (this.pSize > FLUSH_THRESHOLD) { 665 | // Flush in place when threshold reached.. 666 | this.flushPending(); 667 | } 668 | } 669 | }; 670 | 671 | /** 672 | * Sends existing subscriptions to new server after reconnect. 673 | * 674 | * @api private 675 | */ 676 | 677 | Client.prototype.sendSubscriptions = function() { 678 | var protos = ""; 679 | for (var sid in this.subs) { 680 | if (this.subs.hasOwnProperty(sid)) { 681 | var sub = this.subs[sid]; 682 | var proto; 683 | if (sub.qgroup) { 684 | proto = [SUB, sub.subject, sub.qgroup, sid + CR_LF]; 685 | } else { 686 | proto = [SUB, sub.subject, sid + CR_LF]; 687 | } 688 | protos += proto.join(SPC); 689 | } 690 | } 691 | if (protos.length > 0) { 692 | this.stream.write(protos); 693 | } 694 | }; 695 | 696 | /** 697 | * Process the inbound data queue. 698 | * 699 | * @api private 700 | */ 701 | 702 | Client.prototype.processInbound = function() { 703 | var client = this; 704 | 705 | // Hold any regex matches. 706 | var m; 707 | 708 | // For optional yield 709 | var start; 710 | 711 | // unpause if needed. 712 | // FIXME(dlc) client.stream.isPaused() causes 0.10 to fail 713 | client.stream.resume(); 714 | 715 | /* jshint -W083 */ 716 | 717 | if (client.options.yieldTime !== undefined) { 718 | start = Date.now(); 719 | } 720 | 721 | while (!client.closed && client.inbound && client.inbound.length > 0) { 722 | switch (client.pstate) { 723 | 724 | case AWAITING_CONTROL: 725 | // Regex only works on strings, so convert once to be more efficient. 726 | // Long term answer is a hand rolled parser, not regex. 727 | var buf = client.inbound.toString('binary', 0, MAX_CONTROL_LINE_SIZE); 728 | if ((m = MSG.exec(buf)) !== null) { 729 | client.payload = { 730 | subj : m[1], 731 | sid : parseInt(m[2], 10), 732 | reply : m[4], 733 | size : parseInt(m[5], 10) 734 | }; 735 | client.payload.psize = client.payload.size + CR_LF_LEN; 736 | client.pstate = AWAITING_MSG_PAYLOAD; 737 | } else if ((m = OK.exec(buf)) !== null) { 738 | // Ignore for now.. 739 | } else if ((m = ERR.exec(buf)) !== null) { 740 | client.emit('error', m[1]); 741 | } else if ((m = PONG.exec(buf)) !== null) { 742 | var cb = client.pongs && client.pongs.shift(); 743 | if (cb) { cb(); } // FIXME: Should we check for exceptions? 744 | } else if ((m = PING.exec(buf)) !== null) { 745 | client.sendCommand(PONG_RESPONSE); 746 | } else if ((m = INFO.exec(buf)) !== null) { 747 | client.info = JSON.parse(m[1]); 748 | // Check on TLS mismatch. 749 | if (client.checkTLSMismatch() === true) { 750 | return; 751 | } 752 | // Process first INFO 753 | if (client.infoReceived === false) { 754 | // Switch over to TLS as needed. 755 | if (client.options.tls !== false && 756 | client.stream.encrypted !== true) { 757 | var tlsOpts = {socket: client.stream}; 758 | if ('object' === typeof client.options.tls) { 759 | for (var key in client.options.tls) { 760 | tlsOpts[key] = client.options.tls[key]; 761 | } 762 | } 763 | client.stream = tls.connect(tlsOpts, function() { 764 | client.flushPending(); 765 | }); 766 | client.setupHandlers(); 767 | } 768 | 769 | // Send the connect message and subscriptions immediately 770 | client.sendConnect(); 771 | client.sendSubscriptions(); 772 | 773 | client.pongs.unshift(function() { client.connectCB(); }); 774 | client.stream.write(PING_REQUEST); 775 | 776 | // Mark as received 777 | client.infoReceived = true; 778 | client.stripPendingSubs(); 779 | client.flushPending(); 780 | } 781 | } else { 782 | // FIXME, check line length for something weird. 783 | // Nothing here yet, return 784 | return; 785 | } 786 | break; 787 | 788 | case AWAITING_MSG_PAYLOAD: 789 | 790 | // If we do not have the complete message, hold onto the chunks 791 | // and assemble when we have all we need. This optimizes for 792 | // when we parse a large buffer down to a small number of bytes, 793 | // then we receive a large chunk. This avoids a big copy with a 794 | // simple concat above. 795 | if (client.inbound.length < client.payload.psize) { 796 | if (undefined === client.payload.chunks) { 797 | client.payload.chunks = []; 798 | } 799 | client.payload.chunks.push(client.inbound); 800 | client.payload.psize -= client.inbound.length; 801 | client.inbound = null; 802 | return; 803 | } 804 | 805 | // If we are here we have the complete message. 806 | // Check to see if we have existing chunks 807 | if (client.payload.chunks) { 808 | client.payload.chunks.push(client.inbound.slice(0, client.payload.psize)); 809 | var mbuf = Buffer.concat(client.payload.chunks, client.payload.size+CR_LF_LEN); 810 | client.payload.msg = mbuf.toString(client.encoding, 0, client.payload.size); 811 | } else { 812 | client.payload.msg = client.inbound.toString(client.encoding, 0, client.payload.size); 813 | } 814 | 815 | // Eat the size of the inbound that represents the message. 816 | if (client.inbound.length === client.payload.psize) { 817 | client.inbound = null; 818 | } else { 819 | client.inbound = client.inbound.slice(client.payload.psize); 820 | } 821 | 822 | // process the message 823 | client.processMsg(); 824 | 825 | // Reset 826 | client.pstate = AWAITING_CONTROL; 827 | client.payload = null; 828 | 829 | // Check to see if we have an option to yield for other events after yieldTime. 830 | if (start !== undefined) { 831 | if ((Date.now() - start) > client.options.yieldTime) { 832 | client.stream.pause(); 833 | setImmediate(client.processInbound.bind(this)); 834 | return; 835 | } 836 | } 837 | break; 838 | } 839 | 840 | // This is applicable for a regex match to eat the bytes we used from a control line. 841 | if (m && !this.closed) { 842 | // Chop inbound 843 | var psize = m[0].length; 844 | if (psize >= client.inbound.length) { 845 | client.inbound = null; 846 | } else { 847 | client.inbound = client.inbound.slice(psize); 848 | } 849 | } 850 | m = null; 851 | } 852 | }; 853 | 854 | /** 855 | * Process a delivered message and deliver to appropriate subscriber. 856 | * 857 | * @api private 858 | */ 859 | 860 | Client.prototype.processMsg = function() { 861 | var sub = this.subs[this.payload.sid]; 862 | if (sub !== undefined) { 863 | sub.received += 1; 864 | // Check for a timeout, and cancel if received >= expected 865 | if (sub.timeout) { 866 | if (sub.received >= sub.expected) { 867 | clearTimeout(sub.timeout); 868 | sub.timeout = null; 869 | } 870 | } 871 | // Check for auto-unsubscribe 872 | if (sub.max !== undefined) { 873 | if (sub.received === sub.max) { 874 | delete this.subs[this.payload.sid]; 875 | this.emit('unsubscribe', this.payload.sid, sub.subject); 876 | } else if (sub.received > sub.max) { 877 | this.unsubscribe(this.payload.sid); 878 | sub.callback = null; 879 | } 880 | } 881 | 882 | if (sub.callback) { 883 | var msg = this.payload.msg; 884 | if (this.options.json) { 885 | try { 886 | msg = JSON.parse(new Buffer(this.payload.msg, this.options.encoding).toString()); 887 | } catch (e) { 888 | msg = e; 889 | } 890 | } 891 | sub.callback(msg, this.payload.reply, this.payload.subj, this.payload.sid); 892 | } 893 | } 894 | }; 895 | 896 | /** 897 | * Push a new cluster server. 898 | * 899 | * @param {String} uri 900 | * @api public 901 | */ 902 | 903 | Client.prototype.addServer = function(uri) { 904 | this.servers.push(new Server(url.parse(uri))); 905 | 906 | if (this.options.noRandomize !== true) { 907 | shuffle(this.servers); 908 | } 909 | }; 910 | 911 | /** 912 | * Flush outbound queue to server and call optional callback when server has processed 913 | * all data. 914 | * 915 | * @param {Function} opt_callback 916 | * @api public 917 | */ 918 | 919 | Client.prototype.flush = function(opt_callback) { 920 | if (this.closed) { 921 | if (typeof opt_callback === 'function') { 922 | opt_callback(new Error(CONN_CLOSED)); 923 | return; 924 | } else { 925 | throw(new Error(CONN_CLOSED)); 926 | } 927 | } 928 | if (this.pongs) { 929 | this.pongs.push(opt_callback); 930 | this.sendCommand(PING_REQUEST); 931 | this.flushPending(); 932 | } 933 | }; 934 | 935 | /** 936 | * Publish a message to the given subject, with optional reply and callback. 937 | * 938 | * @param {String} subject 939 | * @param {String} opt_msg 940 | * @param {String} opt_reply 941 | * @param {Function} opt_callback 942 | * @api public 943 | */ 944 | 945 | Client.prototype.publish = function(subject, msg, opt_reply, opt_callback) { 946 | // They only supplied a callback function. 947 | if (typeof subject === 'function') { 948 | opt_callback = subject; 949 | subject = undefined; 950 | } 951 | if (!msg) { msg = EMPTY; } 952 | if (!subject) { 953 | if (opt_callback) { 954 | opt_callback(new Error(BAD_SUBJECT)); 955 | } else { 956 | throw(new Error(BAD_SUBJECT)); 957 | } 958 | } 959 | if (typeof msg === 'function') { 960 | if (opt_callback || opt_reply) { 961 | opt_callback(new Error(BAD_MSG)); 962 | return; 963 | } 964 | opt_callback = msg; 965 | msg = EMPTY; 966 | opt_reply = undefined; 967 | } 968 | if (typeof opt_reply === 'function') { 969 | if (opt_callback) { 970 | opt_callback(new Error(BAD_REPLY)); 971 | return; 972 | } 973 | opt_callback = opt_reply; 974 | opt_reply = undefined; 975 | } 976 | 977 | // Hold PUB SUB [REPLY] 978 | var psub; 979 | if (opt_reply === undefined) { 980 | psub = 'PUB ' + subject + SPC; 981 | } else { 982 | psub = 'PUB ' + subject + SPC + opt_reply + SPC; 983 | } 984 | 985 | if ('ArrayBuffer' in window && ArrayBuffer.isView(msg)) { 986 | msg = Buffer.from(msg); 987 | } 988 | 989 | // Need to treat sending buffers different. 990 | if (!Buffer.isBuffer(msg)) { 991 | var str = msg; 992 | if (this.options.json) { 993 | if (typeof msg !== 'object' || Array.isArray(msg)) { 994 | throw(new Error(BAD_JSON_MSG)); 995 | } 996 | try { 997 | str = JSON.stringify(msg); 998 | } catch (e) { 999 | throw(new Error(BAD_JSON_MSG)); 1000 | } 1001 | } 1002 | this.sendCommand(psub + Buffer.byteLength(str) + CR_LF + str + CR_LF); 1003 | } else { 1004 | var b = new Buffer(psub.length + msg.length + (2 * CR_LF_LEN) + msg.length.toString().length); 1005 | var len = b.write(psub + msg.length + CR_LF); 1006 | msg.copy(b, len); 1007 | b.write(CR_LF, len + msg.length); 1008 | this.sendCommand(b); 1009 | } 1010 | 1011 | if (opt_callback !== undefined) { 1012 | this.flush(opt_callback); 1013 | } else if (this.closed) { 1014 | throw(new Error(CONN_CLOSED)); 1015 | } 1016 | }; 1017 | 1018 | /** 1019 | * Subscribe to a given subject, with optional options and callback. opts can be 1020 | * ommitted, even with a callback. The Subscriber Id is returned. 1021 | * 1022 | * @param {String} subject 1023 | * @param {Object} opts 1024 | * @param {Function} callback 1025 | * @return {Mixed} 1026 | * @api public 1027 | */ 1028 | 1029 | Client.prototype.subscribe = function(subject, opts, callback) { 1030 | if (this.closed) { 1031 | throw(new Error(CONN_CLOSED)); 1032 | } 1033 | var qgroup, max; 1034 | if (typeof opts === 'function') { 1035 | callback = opts; 1036 | opts = undefined; 1037 | } else if (opts && typeof opts === 'object') { 1038 | // FIXME, check exists, error otherwise.. 1039 | qgroup = opts.queue; 1040 | max = opts.max; 1041 | } 1042 | this.ssid += 1; 1043 | this.subs[this.ssid] = { 'subject':subject, 'callback':callback, 'received':0 }; 1044 | 1045 | var proto; 1046 | if (typeof qgroup === 'string') { 1047 | this.subs[this.ssid].qgroup = qgroup; 1048 | proto = [SUB, subject, qgroup, this.ssid + CR_LF]; 1049 | } else { 1050 | proto = [SUB, subject, this.ssid + CR_LF]; 1051 | } 1052 | 1053 | this.sendCommand(proto.join(SPC)); 1054 | this.emit('subscribe', this.ssid, subject, opts); 1055 | 1056 | if (max) { 1057 | this.unsubscribe(this.ssid, max); 1058 | } 1059 | return this.ssid; 1060 | }; 1061 | 1062 | /** 1063 | * Unsubscribe to a given Subscriber Id, with optional max parameter. 1064 | * 1065 | * @param {Mixed} sid 1066 | * @param {Number} opt_max 1067 | * @api public 1068 | */ 1069 | 1070 | Client.prototype.unsubscribe = function(sid, opt_max) { 1071 | if (!sid || this.closed) { return; } 1072 | 1073 | var proto; 1074 | if (opt_max) { 1075 | proto = [UNSUB, sid, opt_max + CR_LF]; 1076 | } else { 1077 | proto = [UNSUB, sid + CR_LF]; 1078 | } 1079 | this.sendCommand(proto.join(SPC)); 1080 | 1081 | var sub = this.subs[sid]; 1082 | if (sub === undefined) { 1083 | return; 1084 | } 1085 | sub.max = opt_max; 1086 | if (sub.max === undefined || (sub.received >= sub.max)) { 1087 | delete this.subs[sid]; 1088 | this.emit('unsubscribe', sid, sub.subject); 1089 | } 1090 | }; 1091 | 1092 | /** 1093 | * Set a timeout on a subscription. 1094 | * 1095 | * @param {Mixed} sid 1096 | * @param {Number} timeout 1097 | * @param {Number} expected 1098 | * @api public 1099 | */ 1100 | 1101 | Client.prototype.timeout = function(sid, timeout, expected, callback) { 1102 | if (!sid) { return; } 1103 | var sub = this.subs[sid]; 1104 | if (sub === null) { return; } 1105 | sub.expected = expected; 1106 | sub.timeout = setTimeout(function() { callback(sid); }, timeout); 1107 | }; 1108 | 1109 | /** 1110 | * Publish a message with an implicit inbox listener as the reply. Message is optional. 1111 | * This should be treated as a subscription. You can optionally indicate how many 1112 | * messages you only want to receive using opt_options = {max:N}. Otherwise you 1113 | * will need to unsubscribe to stop the message stream. 1114 | * The Subscriber Id is returned. 1115 | * 1116 | * @param {String} subject 1117 | * @param {String} opt_msg 1118 | * @param {Object} opt_options 1119 | * @param {Function} callback 1120 | * @return {Mixed} 1121 | * @api public 1122 | */ 1123 | 1124 | Client.prototype.request = function(subject, opt_msg, opt_options, callback) { 1125 | if (typeof opt_msg === 'function') { 1126 | callback = opt_msg; 1127 | opt_msg = EMPTY; 1128 | opt_options = null; 1129 | } 1130 | if (typeof opt_options === 'function') { 1131 | callback = opt_options; 1132 | opt_options = null; 1133 | } 1134 | var inbox = createInbox(); 1135 | var s = this.subscribe(inbox, opt_options, function(msg, reply) { 1136 | callback(msg, reply); 1137 | }); 1138 | this.publish(subject, opt_msg, inbox); 1139 | return s; 1140 | }; 1141 | 1142 | /** 1143 | * Report number of outstanding subscriptions on this connection. 1144 | * 1145 | * @return {Number} 1146 | * @api public 1147 | */ 1148 | 1149 | Client.prototype.numSubscriptions = function() { 1150 | return Object.keys(this.subs).length; 1151 | }; 1152 | 1153 | /** 1154 | * Reconnect to the server. 1155 | * 1156 | * @api private 1157 | */ 1158 | 1159 | Client.prototype.reconnect = function() { 1160 | if (this.closed) { return; } 1161 | this.reconnects += 1; 1162 | this.createConnection(); 1163 | if (this.currentServer.didConnect === true) { 1164 | this.emit('reconnecting'); 1165 | } 1166 | }; 1167 | 1168 | /** 1169 | * Setup a timer event to attempt reconnect. 1170 | * 1171 | * @api private 1172 | */ 1173 | 1174 | Client.prototype.scheduleReconnect = function() { 1175 | var client = this; 1176 | // Just return if no more servers 1177 | if (client.servers.length === 0) { 1178 | return; 1179 | } 1180 | // Don't set reconnecting state if we are just trying 1181 | // for the first time. 1182 | if (client.wasConnected === true) { 1183 | client.reconnecting = true; 1184 | } 1185 | // Only stall if we have connected before. 1186 | var wait = 0; 1187 | if (client.servers[0].didConnect === true) { 1188 | wait = this.options.reconnectTimeWait; 1189 | } 1190 | setTimeout(function() { client.reconnect(); }, wait); 1191 | }; 1192 | -------------------------------------------------------------------------------- /lib/net.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var util = require('util'); 4 | var EventEmitter = require('events').EventEmitter; 5 | 6 | function WebSocketProxy(url) { 7 | var self = this; 8 | EventEmitter.call(this); 9 | this.sock = new WebSocket(url); 10 | this.sock.addEventListener('open', function(e) { 11 | self.emit('connect'); 12 | }); 13 | this.sock.addEventListener('message', function(e) { 14 | self.emit('data', new Buffer(e.data)); 15 | }); 16 | this.sock.addEventListener('error', function(e) { 17 | self.emit('error', e); 18 | }); 19 | this.sock.addEventListener('close', function(e) { 20 | self.emit('close'); 21 | }); 22 | } 23 | util.inherits(WebSocketProxy, EventEmitter); 24 | 25 | WebSocketProxy.prototype.end = function() { 26 | this.destroy(); 27 | } 28 | 29 | WebSocketProxy.prototype.destroy = function() { 30 | if ( 31 | this.sock.readyState === WebSocket.CONNECTING || 32 | this.sock.readyState === WebSocket.OPEN 33 | ) { 34 | this.sock.close(); 35 | } 36 | } 37 | 38 | WebSocketProxy.prototype.write = function(data) { 39 | if (this.sock.readyState === WebSocket.OPEN) { 40 | this.sock.send(data); 41 | } 42 | } 43 | 44 | WebSocketProxy.prototype.pause = function() { 45 | console.warn('WebSocketProxy stream pause/resume is not supported yet.'); 46 | } 47 | 48 | WebSocketProxy.prototype.resume = function() {} 49 | 50 | exports.createConnection = function(url) { 51 | // The url is rebuilt to avoid including the auth credentials. 52 | return new WebSocketProxy(url.format({ 53 | protocol: url.protocol, 54 | slashes: url.slashes, 55 | host: url.host, 56 | hostname: url.hostname, 57 | port: url.port, 58 | pathname: url.pathname, 59 | search: url.search, 60 | path: url.path, 61 | query: url.query, 62 | hash: url.hash 63 | })); 64 | } 65 | -------------------------------------------------------------------------------- /lib/tls.js: -------------------------------------------------------------------------------- 1 | exports.connect = function(opts, cb) { 2 | throw "TLS is not supported in the browser. Use WSS instead."; 3 | } 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "websocket-nats", 3 | "version": "0.3.3", 4 | "description": "An in-browser websocket client for [NATS](http://nats.io/), a lightweight, high-performance cloud native messaging system.", 5 | "keywords": [ 6 | "websocket", 7 | "websockets", 8 | "ws", 9 | "nats", 10 | "browser" 11 | ], 12 | "license": "MIT", 13 | "author": { 14 | "name": "Josh Glendenning", 15 | "email": "josh@isobit.io" 16 | }, 17 | "main": "index.js", 18 | "repository": "isobit/websocket-nats", 19 | "scripts": { 20 | "build": "webpack && npm run build:prod && npm run build:dev", 21 | "build:prod": "NODE_ENV=prod webpack", 22 | "build:dev": "NODE_ENV=dev webpack", 23 | "version": "npm run build && git add -A dist", 24 | "push": "git push && git push --tags && npm publish" 25 | }, 26 | "browser": { 27 | "crypto": "./lib/crypto.js", 28 | "net": "./lib/net.js", 29 | "tls": "./lib/tls.js" 30 | }, 31 | "devDependencies": { 32 | "webpack": "^1.13.0" 33 | }, 34 | "dependencies": { 35 | "nuid": "^0.6.8" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /update-lib.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | curl 'https://raw.githubusercontent.com/nats-io/node-nats/master/lib/nats.js' > /tmp/nats.js 3 | vimdiff lib/nats.js /tmp/nats.js 4 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const webpack = require('webpack'); 3 | 4 | module.exports = { 5 | entry: './entry.js', 6 | output: { 7 | path: path.resolve(__dirname, './dist'), 8 | publicPath: '/dist/', 9 | filename: 'websocket-nats.js' 10 | } 11 | }; 12 | 13 | if (process.env.NODE_ENV === 'dev') { 14 | module.exports.output.filename = 'websocket-nats.dev.js'; 15 | module.exports.devtool = '#eval-source-map'; 16 | } 17 | 18 | if (process.env.NODE_ENV === 'prod') { 19 | module.exports.output.filename = 'websocket-nats.min.js'; 20 | module.exports.devtool = '#source-map'; 21 | module.exports.plugins = (module.exports.plugins || []).concat([ 22 | new webpack.optimize.UglifyJsPlugin({minimize: true}) 23 | ]); 24 | } 25 | --------------------------------------------------------------------------------