amqplib 0.5.1 → 0.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.npmignore +0 -1
- package/CHANGELOG.md +84 -0
- package/Makefile +2 -1
- package/README.md +4 -4
- package/bin/generate-defs.js +723 -0
- package/callback_api.js +1 -0
- package/channel_api.js +1 -0
- package/examples/headers.js +2 -2
- package/examples/receive_generator.js +39 -0
- package/examples/send_generators.js +1 -1
- package/examples/ssl.js +1 -1
- package/examples/tutorials/callback_api/emit_log.js +1 -1
- package/examples/tutorials/callback_api/emit_log_direct.js +1 -1
- package/examples/tutorials/callback_api/emit_log_topic.js +1 -1
- package/examples/tutorials/callback_api/new_task.js +1 -1
- package/examples/tutorials/callback_api/rpc_client.js +1 -1
- package/examples/tutorials/callback_api/rpc_server.js +1 -1
- package/examples/tutorials/callback_api/send.js +1 -1
- package/examples/tutorials/emit_log.js +1 -1
- package/examples/tutorials/emit_log_direct.js +1 -1
- package/examples/tutorials/emit_log_topic.js +1 -1
- package/examples/tutorials/new_task.js +1 -1
- package/examples/tutorials/rpc_client.js +1 -1
- package/examples/tutorials/rpc_server.js +1 -1
- package/examples/tutorials/send.js +1 -1
- package/examples/waitForConfirms.js +1 -1
- package/lib/api_args.js +2 -0
- package/lib/channel.js +30 -12
- package/lib/codec.js +64 -38
- package/lib/connect.js +26 -15
- package/lib/connection.js +6 -4
- package/lib/credentials.js +20 -3
- package/lib/defs.js +203 -75
- package/lib/frame.js +2 -1
- package/package-lock.json +711 -0
- package/package.json +11 -9
- package/test/callback_api.js +6 -5
- package/test/channel.js +88 -75
- package/test/channel_api.js +38 -24
- package/test/codec.js +48 -9
- package/test/connect.js +88 -3
- package/test/connection.js +57 -56
- package/test/data.js +32 -9
- package/test/frame.js +4 -4
- package/test/mux.js +10 -6
- package/test/util.js +16 -2
package/callback_api.js
CHANGED
package/channel_api.js
CHANGED
package/examples/headers.js
CHANGED
|
@@ -37,6 +37,6 @@ function bindAndConsume(ch, ex, q) {
|
|
|
37
37
|
|
|
38
38
|
function send(ch, ex) {
|
|
39
39
|
// The headers for a message are given as an option to `publish`:
|
|
40
|
-
ch.publish(ex.exchange, '',
|
|
41
|
-
ch.publish(ex.exchange, '',
|
|
40
|
+
ch.publish(ex.exchange, '', Buffer.from('hello'), {headers: {baz: 'boo'}});
|
|
41
|
+
ch.publish(ex.exchange, '', Buffer.from('world'), {headers: {foo: 'bar'}});
|
|
42
42
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
'use strict';
|
|
4
|
+
const co = require('co');
|
|
5
|
+
const amqp = require('amqplib');
|
|
6
|
+
const readline = require('readline');
|
|
7
|
+
|
|
8
|
+
co(function* () {
|
|
9
|
+
const myConsumer = (msg) => {
|
|
10
|
+
if (msg !== null) {
|
|
11
|
+
console.log('consuming message %s in generator', JSON.stringify(msg.content.toString()));
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
const conn = yield amqp.connect('amqp://localhost');
|
|
15
|
+
try {
|
|
16
|
+
// create a message to consume
|
|
17
|
+
const q = 'hello';
|
|
18
|
+
const msg = 'Hello World!';
|
|
19
|
+
const channel = yield conn.createChannel();
|
|
20
|
+
yield channel.assertQueue(q);
|
|
21
|
+
channel.sendToQueue(q, Buffer.from(msg));
|
|
22
|
+
console.log(" [x] Sent '%s'", msg);
|
|
23
|
+
// consume the message
|
|
24
|
+
yield channel.consume(q, myConsumer, { noAck: true });
|
|
25
|
+
}
|
|
26
|
+
catch (e) {
|
|
27
|
+
throw e;
|
|
28
|
+
}
|
|
29
|
+
}).catch(err => {
|
|
30
|
+
console.warn('Error:', err);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const rl = readline.createInterface({
|
|
34
|
+
input: process.stdin,
|
|
35
|
+
output: process.stdout
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// pend until message is consumed
|
|
39
|
+
rl.question('newline to exit', () => process.exit());
|
|
@@ -21,7 +21,7 @@ co(function* () {
|
|
|
21
21
|
|
|
22
22
|
yield channel.assertQueue(q);
|
|
23
23
|
|
|
24
|
-
channel.sendToQueue(q,
|
|
24
|
+
channel.sendToQueue(q, Buffer.from(msg));
|
|
25
25
|
|
|
26
26
|
// if message has been nacked, this will result in an error (rejected promise);
|
|
27
27
|
yield channel.waitForConfirms();
|
package/examples/ssl.js
CHANGED
|
@@ -59,6 +59,6 @@ var open = amqp.connect('amqps://localhost', opts);
|
|
|
59
59
|
open.then(function(conn) {
|
|
60
60
|
process.on('SIGINT', conn.close.bind(conn));
|
|
61
61
|
return conn.createChannel().then(function(ch) {
|
|
62
|
-
ch.sendToQueue('foo',
|
|
62
|
+
ch.sendToQueue('foo', Buffer.from('Hello World!'));
|
|
63
63
|
});
|
|
64
64
|
}).then(null, console.warn);
|
|
@@ -17,7 +17,7 @@ function on_connect(err, conn) {
|
|
|
17
17
|
ch.assertExchange(ex, 'fanout', {durable: false});
|
|
18
18
|
var msg = process.argv.slice(2).join(' ') ||
|
|
19
19
|
'info: Hello World!';
|
|
20
|
-
ch.publish(ex, '',
|
|
20
|
+
ch.publish(ex, '', Buffer.from(msg));
|
|
21
21
|
console.log(" [x] Sent '%s'", msg);
|
|
22
22
|
ch.close(function() { conn.close(); });
|
|
23
23
|
}
|
|
@@ -20,7 +20,7 @@ function on_connect(err, conn) {
|
|
|
20
20
|
function on_channel_open(err, ch) {
|
|
21
21
|
if (err !== null) return bail(err, conn);
|
|
22
22
|
ch.assertExchange(ex, 'direct', exopts, function(err, ok) {
|
|
23
|
-
ch.publish(ex, severity,
|
|
23
|
+
ch.publish(ex, severity, Buffer.from(message));
|
|
24
24
|
ch.close(function() { conn.close(); });
|
|
25
25
|
});
|
|
26
26
|
}
|
|
@@ -17,7 +17,7 @@ function on_connect(err, conn) {
|
|
|
17
17
|
conn.createChannel(function(err, ch) {
|
|
18
18
|
ch.assertExchange(ex, 'topic', exopts, function(err, ok) {
|
|
19
19
|
if (err !== null) return bail(err, conn);
|
|
20
|
-
ch.publish(ex, key,
|
|
20
|
+
ch.publish(ex, key, Buffer.from(message));
|
|
21
21
|
console.log(" [x] Sent %s:'%s'", key, message);
|
|
22
22
|
ch.close(function() { conn.close(); });
|
|
23
23
|
});
|
|
@@ -17,7 +17,7 @@ function on_connect(err, conn) {
|
|
|
17
17
|
ch.assertQueue(q, {durable: true}, function(err, _ok) {
|
|
18
18
|
if (err !== null) return bail(err, conn);
|
|
19
19
|
var msg = process.argv.slice(2).join(' ') || "Hello World!";
|
|
20
|
-
ch.sendToQueue(q,
|
|
20
|
+
ch.sendToQueue(q, Buffer.from(msg), {persistent: true});
|
|
21
21
|
console.log(" [x] Sent '%s'", msg);
|
|
22
22
|
ch.close(function() { conn.close(); });
|
|
23
23
|
});
|
|
@@ -39,7 +39,7 @@ function on_connect(err, conn) {
|
|
|
39
39
|
var queue = ok.queue;
|
|
40
40
|
ch.consume(queue, maybeAnswer, {noAck:true});
|
|
41
41
|
console.log(' [x] Requesting fib(%d)', n);
|
|
42
|
-
ch.sendToQueue('rpc_queue',
|
|
42
|
+
ch.sendToQueue('rpc_queue', Buffer.from(n.toString()), {
|
|
43
43
|
replyTo: queue, correlationId: correlationId
|
|
44
44
|
});
|
|
45
45
|
});
|
|
@@ -35,7 +35,7 @@ function on_connect(err, conn) {
|
|
|
35
35
|
var n = parseInt(msg.content.toString());
|
|
36
36
|
console.log(' [.] fib(%d)', n);
|
|
37
37
|
ch.sendToQueue(msg.properties.replyTo,
|
|
38
|
-
|
|
38
|
+
Buffer.from(fib(n).toString()),
|
|
39
39
|
{correlationId: msg.properties.correlationId});
|
|
40
40
|
ch.ack(msg);
|
|
41
41
|
}
|
|
@@ -17,7 +17,7 @@ function on_connect(err, conn) {
|
|
|
17
17
|
if (err !== null) return bail(err, conn);
|
|
18
18
|
ch.assertQueue(q, {durable: false}, function(err, ok) {
|
|
19
19
|
if (err !== null) return bail(err, conn);
|
|
20
|
-
ch.sendToQueue(q,
|
|
20
|
+
ch.sendToQueue(q, Buffer.from(msg));
|
|
21
21
|
console.log(" [x] Sent '%s'", msg);
|
|
22
22
|
ch.close(function() { conn.close(); });
|
|
23
23
|
});
|
|
@@ -11,7 +11,7 @@ amqp.connect('amqp://localhost').then(function(conn) {
|
|
|
11
11
|
'info: Hello World!';
|
|
12
12
|
|
|
13
13
|
return ok.then(function() {
|
|
14
|
-
ch.publish(ex, '',
|
|
14
|
+
ch.publish(ex, '', Buffer.from(message));
|
|
15
15
|
console.log(" [x] Sent '%s'", message);
|
|
16
16
|
return ch.close();
|
|
17
17
|
});
|
|
@@ -12,7 +12,7 @@ amqp.connect('amqp://localhost').then(function(conn) {
|
|
|
12
12
|
var ok = ch.assertExchange(ex, 'direct', {durable: false});
|
|
13
13
|
|
|
14
14
|
return ok.then(function() {
|
|
15
|
-
ch.publish(ex, severity,
|
|
15
|
+
ch.publish(ex, severity, Buffer.from(message));
|
|
16
16
|
console.log(" [x] Sent %s:'%s'", severity, message);
|
|
17
17
|
return ch.close();
|
|
18
18
|
});
|
|
@@ -11,7 +11,7 @@ amqp.connect('amqp://localhost').then(function(conn) {
|
|
|
11
11
|
var ex = 'topic_logs';
|
|
12
12
|
var ok = ch.assertExchange(ex, 'topic', {durable: false});
|
|
13
13
|
return ok.then(function() {
|
|
14
|
-
ch.publish(ex, key,
|
|
14
|
+
ch.publish(ex, key, Buffer.from(message));
|
|
15
15
|
console.log(" [x] Sent %s:'%s'", key, message);
|
|
16
16
|
return ch.close();
|
|
17
17
|
});
|
|
@@ -10,7 +10,7 @@ amqp.connect('amqp://localhost').then(function(conn) {
|
|
|
10
10
|
|
|
11
11
|
return ok.then(function() {
|
|
12
12
|
var msg = process.argv.slice(2).join(' ') || "Hello World!";
|
|
13
|
-
ch.sendToQueue(q,
|
|
13
|
+
ch.sendToQueue(q, Buffer.from(msg), {deliveryMode: true});
|
|
14
14
|
console.log(" [x] Sent '%s'", msg);
|
|
15
15
|
return ch.close();
|
|
16
16
|
});
|
|
@@ -40,7 +40,7 @@ amqp.connect('amqp://localhost').then(function(conn) {
|
|
|
40
40
|
|
|
41
41
|
ok = ok.then(function(queue) {
|
|
42
42
|
console.log(' [x] Requesting fib(%d)', n);
|
|
43
|
-
ch.sendToQueue('rpc_queue',
|
|
43
|
+
ch.sendToQueue('rpc_queue', Buffer.from(n.toString()), {
|
|
44
44
|
correlationId: corrId, replyTo: queue
|
|
45
45
|
});
|
|
46
46
|
});
|
|
@@ -31,7 +31,7 @@ amqp.connect('amqp://localhost').then(function(conn) {
|
|
|
31
31
|
console.log(' [.] fib(%d)', n);
|
|
32
32
|
var response = fib(n);
|
|
33
33
|
ch.sendToQueue(msg.properties.replyTo,
|
|
34
|
-
|
|
34
|
+
Buffer.from(response.toString()),
|
|
35
35
|
{correlationId: msg.properties.correlationId});
|
|
36
36
|
ch.ack(msg);
|
|
37
37
|
}
|
|
@@ -15,7 +15,7 @@ amqp.connect('amqp://localhost').then(function(conn) {
|
|
|
15
15
|
// (when `false`) that you should wait for the event `'drain'`
|
|
16
16
|
// to fire before writing again. We're just doing the one write,
|
|
17
17
|
// so we'll ignore it.
|
|
18
|
-
ch.sendToQueue(q,
|
|
18
|
+
ch.sendToQueue(q, Buffer.from(msg));
|
|
19
19
|
console.log(" [x] Sent '%s'", msg);
|
|
20
20
|
return ch.close();
|
|
21
21
|
});
|
|
@@ -12,7 +12,7 @@ function mkCallback(i) {
|
|
|
12
12
|
amqp.connect().then(function(c) {
|
|
13
13
|
c.createConfirmChannel().then(function(ch) {
|
|
14
14
|
for (var i=0; i < NUM_MSGS; i++) {
|
|
15
|
-
ch.publish('amq.topic', 'whatever',
|
|
15
|
+
ch.publish('amq.topic', 'whatever', Buffer.from('blah'), {}, mkCallback(i));
|
|
16
16
|
}
|
|
17
17
|
ch.waitForConfirms().then(function() {
|
|
18
18
|
console.log('All messages done');
|
package/lib/api_args.js
CHANGED
|
@@ -58,6 +58,8 @@ Args.assertQueue = function(queue, options) {
|
|
|
58
58
|
options.deadLetterRoutingKey);
|
|
59
59
|
setIfDefined(argt, 'x-max-length', options.maxLength);
|
|
60
60
|
setIfDefined(argt, 'x-max-priority', options.maxPriority);
|
|
61
|
+
setIfDefined(argt, 'x-overflow', options.overflow);
|
|
62
|
+
setIfDefined(argt, 'x-queue-mode', options.queueMode);
|
|
61
63
|
|
|
62
64
|
return {
|
|
63
65
|
queue: queue,
|
package/lib/channel.js
CHANGED
|
@@ -16,7 +16,7 @@ var EventEmitter = require('events').EventEmitter;
|
|
|
16
16
|
var fmt = require('util').format;
|
|
17
17
|
var IllegalOperationError = require('./error').IllegalOperationError;
|
|
18
18
|
var stackCapture = require('./error').stackCapture;
|
|
19
|
-
|
|
19
|
+
var Buffer = require('safe-buffer').Buffer
|
|
20
20
|
function Channel(connection) {
|
|
21
21
|
EventEmitter.call( this );
|
|
22
22
|
this.connection = connection;
|
|
@@ -33,6 +33,12 @@ function Channel(connection) {
|
|
|
33
33
|
this.on('nack', this.handleConfirm.bind(this, function(cb) {
|
|
34
34
|
if (cb) cb(new Error('message nacked'));
|
|
35
35
|
}));
|
|
36
|
+
this.on('close', function () {
|
|
37
|
+
var cb;
|
|
38
|
+
while (cb = this.unconfirmed.shift()) {
|
|
39
|
+
if (cb) cb(new Error('channel closed'));
|
|
40
|
+
}
|
|
41
|
+
})
|
|
36
42
|
// message frame state machine
|
|
37
43
|
this.handleMessage = acceptDeliveryOrReturn;
|
|
38
44
|
}
|
|
@@ -103,9 +109,10 @@ C._rpc = function(method, fields, expect, cb) {
|
|
|
103
109
|
// We have detected a problem, so it's up to us to close the
|
|
104
110
|
// channel
|
|
105
111
|
var expectedName = methodName(expect);
|
|
112
|
+
|
|
106
113
|
var e = new Error(fmt("Expected %s; got %s",
|
|
107
114
|
expectedName, inspect(f, false)));
|
|
108
|
-
self.closeWithError(fmt('Expected %s; got %s',
|
|
115
|
+
self.closeWithError(f.id, fmt('Expected %s; got %s',
|
|
109
116
|
expectedName, methodName(f.id)),
|
|
110
117
|
defs.constants.UNEXPECTED_FRAME, e);
|
|
111
118
|
return cb(e);
|
|
@@ -124,7 +131,11 @@ C._rpc = function(method, fields, expect, cb) {
|
|
|
124
131
|
? fmt("Operation failed: %s; %s",
|
|
125
132
|
methodName(method), closeMsg(err))
|
|
126
133
|
: fmt("Channel closed by server: %s", closeMsg(err));
|
|
127
|
-
|
|
134
|
+
var closeFrameError = new Error(e);
|
|
135
|
+
closeFrameError.code = err.fields.replyCode;
|
|
136
|
+
closeFrameError.classId = err.fields.classId;
|
|
137
|
+
closeFrameError.methodId = err.fields.methodId;
|
|
138
|
+
return cb(closeFrameError);
|
|
128
139
|
}
|
|
129
140
|
}
|
|
130
141
|
|
|
@@ -186,7 +197,7 @@ C.toClosing = function(capturedStack, k) {
|
|
|
186
197
|
};
|
|
187
198
|
|
|
188
199
|
C._rejectPending = function() {
|
|
189
|
-
function rej(r) {
|
|
200
|
+
function rej(r) {
|
|
190
201
|
r(new Error("Channel ended, no reply will be forthcoming"));
|
|
191
202
|
}
|
|
192
203
|
if (this.reply !== null) rej(this.reply);
|
|
@@ -210,10 +221,15 @@ C.closeBecause = function(reason, code, k) {
|
|
|
210
221
|
// If we close because there's been an error, we need to distinguish
|
|
211
222
|
// between what we tell the server (`reason`) and what we report as
|
|
212
223
|
// the cause in the client (`error`).
|
|
213
|
-
C.closeWithError = function(reason, code, error) {
|
|
224
|
+
C.closeWithError = function(id, reason, code, error) {
|
|
214
225
|
var self = this;
|
|
215
226
|
this.closeBecause(reason, code, function() {
|
|
216
227
|
error.code = code;
|
|
228
|
+
// content frames and consumer errors do not provide a method a class/method ID
|
|
229
|
+
if (id) {
|
|
230
|
+
error.classId = defs.info(id).classId;
|
|
231
|
+
error.methodId = defs.info(id).methodId;
|
|
232
|
+
}
|
|
217
233
|
self.emit('error', error);
|
|
218
234
|
});
|
|
219
235
|
};
|
|
@@ -232,15 +248,15 @@ C.acceptMessageFrame = function(f) {
|
|
|
232
248
|
}
|
|
233
249
|
catch (msg) {
|
|
234
250
|
if (typeof msg === 'string') {
|
|
235
|
-
this.closeWithError(msg, defs.constants.UNEXPECTED_FRAME,
|
|
251
|
+
this.closeWithError(f.id, msg, defs.constants.UNEXPECTED_FRAME,
|
|
236
252
|
new Error(msg));
|
|
237
253
|
}
|
|
238
254
|
else if (msg instanceof Error) {
|
|
239
|
-
this.closeWithError('Error while processing message',
|
|
255
|
+
this.closeWithError(f.id, 'Error while processing message',
|
|
240
256
|
defs.constants.INTERNAL_ERROR, msg);
|
|
241
257
|
}
|
|
242
258
|
else {
|
|
243
|
-
this.closeWithError('Internal error while processing message',
|
|
259
|
+
this.closeWithError(f.id, 'Internal error while processing message',
|
|
244
260
|
defs.constants.INTERNAL_ERROR,
|
|
245
261
|
new Error(msg.toString()));
|
|
246
262
|
}
|
|
@@ -283,15 +299,15 @@ function acceptMessage(continuation) {
|
|
|
283
299
|
if (f.id === defs.BasicProperties) {
|
|
284
300
|
message.properties = f.fields;
|
|
285
301
|
totalSize = remaining = f.size;
|
|
286
|
-
|
|
302
|
+
|
|
287
303
|
// for zero-length messages, content frames aren't required.
|
|
288
304
|
if (totalSize === 0) {
|
|
289
|
-
message.content =
|
|
305
|
+
message.content = Buffer.alloc(0);
|
|
290
306
|
continuation(message);
|
|
291
307
|
return acceptDeliveryOrReturn;
|
|
292
308
|
}
|
|
293
309
|
else {
|
|
294
|
-
return content;
|
|
310
|
+
return content;
|
|
295
311
|
}
|
|
296
312
|
}
|
|
297
313
|
else {
|
|
@@ -405,6 +421,8 @@ C.accept = function(f) {
|
|
|
405
421
|
|
|
406
422
|
var error = new Error(emsg);
|
|
407
423
|
error.code = f.fields.replyCode;
|
|
424
|
+
error.classId = f.fields.classId;
|
|
425
|
+
error.methodId = f.fields.methodId;
|
|
408
426
|
this.emit('error', error);
|
|
409
427
|
|
|
410
428
|
var s = stackCapture(emsg);
|
|
@@ -413,7 +431,7 @@ C.accept = function(f) {
|
|
|
413
431
|
|
|
414
432
|
case defs.BasicFlow:
|
|
415
433
|
// RabbitMQ doesn't send this, it just blocks the TCP socket
|
|
416
|
-
return this.closeWithError("Flow not implemented",
|
|
434
|
+
return this.closeWithError(f.id, "Flow not implemented",
|
|
417
435
|
defs.constants.NOT_IMPLEMENTED,
|
|
418
436
|
new Error('Flow not implemented'));
|
|
419
437
|
|
package/lib/codec.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//
|
|
1
|
+
//
|
|
2
2
|
//
|
|
3
3
|
//
|
|
4
4
|
|
|
@@ -110,6 +110,40 @@ function encodeFieldValue(buffer, value, offset) {
|
|
|
110
110
|
type = value['!'];
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
// If it's a JS number, we'll have to guess what type to encode it
|
|
114
|
+
// as.
|
|
115
|
+
if (type == 'number') {
|
|
116
|
+
// Making assumptions about the kind of number (floating point
|
|
117
|
+
// v integer, signed, unsigned, size) desired is dangerous in
|
|
118
|
+
// general; however, in practice RabbitMQ uses only
|
|
119
|
+
// longstrings and unsigned integers in its arguments, and
|
|
120
|
+
// other clients generally conflate number types anyway. So
|
|
121
|
+
// the only distinction we care about is floating point vs
|
|
122
|
+
// integers, preferring integers since those can be promoted
|
|
123
|
+
// if necessary. If floating point is required, we may as well
|
|
124
|
+
// use double precision.
|
|
125
|
+
if (isFloatingPoint(val)) {
|
|
126
|
+
type = 'double';
|
|
127
|
+
}
|
|
128
|
+
else { // only signed values are used in tables by
|
|
129
|
+
// RabbitMQ. It *used* to (< v3.3.0) treat the byte 'b'
|
|
130
|
+
// type as unsigned, but most clients (and the spec)
|
|
131
|
+
// think it's signed, and now RabbitMQ does too.
|
|
132
|
+
if (val < 128 && val >= -128) {
|
|
133
|
+
type = 'byte';
|
|
134
|
+
}
|
|
135
|
+
else if (val >= -0x8000 && val < 0x8000) {
|
|
136
|
+
type = 'short'
|
|
137
|
+
}
|
|
138
|
+
else if (val >= -0x80000000 && val < 0x80000000) {
|
|
139
|
+
type = 'int';
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
type = 'long';
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
113
147
|
function tag(t) { buffer.write(t, offset); offset++; }
|
|
114
148
|
|
|
115
149
|
switch (type) {
|
|
@@ -141,44 +175,36 @@ function encodeFieldValue(buffer, value, offset) {
|
|
|
141
175
|
tag('t');
|
|
142
176
|
buffer.writeUInt8((val) ? 1 : 0, offset); offset++;
|
|
143
177
|
break;
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
// type as unsigned, but most clients (and the spec)
|
|
162
|
-
// think it's signed, and now RabbitMQ does too.
|
|
163
|
-
if (val < 128 && val >= -128) {
|
|
164
|
-
tag('b');
|
|
165
|
-
buffer.writeInt8(val, offset); offset++;
|
|
166
|
-
}
|
|
167
|
-
else if (val >= -0x8000 && val < 0x8000) { // short
|
|
168
|
-
tag('s');
|
|
169
|
-
buffer.writeInt16BE(val, offset); offset += 2;
|
|
170
|
-
}
|
|
171
|
-
else if (val >= -0x80000000 && val < 0x80000000) { // int
|
|
172
|
-
tag('I');
|
|
173
|
-
buffer.writeInt32BE(val, offset); offset += 4;
|
|
174
|
-
}
|
|
175
|
-
else { // long
|
|
176
|
-
tag('l');
|
|
177
|
-
ints.writeInt64BE(buffer, val, offset); offset += 8;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
178
|
+
// These are the types that are either guessed above, or
|
|
179
|
+
// explicitly given using the {'!': type} notation.
|
|
180
|
+
case 'double':
|
|
181
|
+
case 'float64':
|
|
182
|
+
tag('d');
|
|
183
|
+
buffer.writeDoubleBE(val, offset);
|
|
184
|
+
offset += 8;
|
|
185
|
+
break;
|
|
186
|
+
case 'byte':
|
|
187
|
+
case 'int8':
|
|
188
|
+
tag('b');
|
|
189
|
+
buffer.writeInt8(val, offset); offset++;
|
|
190
|
+
break;
|
|
191
|
+
case 'short':
|
|
192
|
+
case 'int16':
|
|
193
|
+
tag('s');
|
|
194
|
+
buffer.writeInt16BE(val, offset); offset += 2;
|
|
180
195
|
break;
|
|
181
|
-
|
|
196
|
+
case 'int':
|
|
197
|
+
case 'int32':
|
|
198
|
+
tag('I');
|
|
199
|
+
buffer.writeInt32BE(val, offset); offset += 4;
|
|
200
|
+
break;
|
|
201
|
+
case 'long':
|
|
202
|
+
case 'int64':
|
|
203
|
+
tag('l');
|
|
204
|
+
ints.writeInt64BE(buffer, val, offset); offset += 8;
|
|
205
|
+
break;
|
|
206
|
+
|
|
207
|
+
// Now for exotic types, those can _only_ be denoted by using
|
|
182
208
|
// `{'!': type, value: val}
|
|
183
209
|
case 'timestamp':
|
|
184
210
|
tag('T');
|
package/lib/connect.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
9
|
-
var URL = require('url');
|
|
9
|
+
var URL = require('url-parse');
|
|
10
10
|
var QS = require('querystring');
|
|
11
11
|
var Connection = require('./connection').Connection;
|
|
12
12
|
var fmt = require('util').format;
|
|
@@ -76,13 +76,12 @@ function openFrames(vhost, query, credentials, extraClientProperties) {
|
|
|
76
76
|
};
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
// Decide on credentials based on what we're supplied
|
|
79
|
+
// Decide on credentials based on what we're supplied.
|
|
80
80
|
function credentialsFromUrl(parts) {
|
|
81
81
|
var user = 'guest', passwd = 'guest';
|
|
82
|
-
if (parts.
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
passwd = auth[1];
|
|
82
|
+
if (parts.username != '' || parts.password != '') {
|
|
83
|
+
user = (parts.username) ? unescape(parts.username) : '';
|
|
84
|
+
passwd = (parts.password) ? unescape(parts.password) : '';
|
|
86
85
|
}
|
|
87
86
|
return credentials.plain(user, passwd);
|
|
88
87
|
}
|
|
@@ -110,17 +109,25 @@ function connect(url, socketOptions, openCallback) {
|
|
|
110
109
|
sockopts.port = url.port || ((protocol === 'amqp:') ? 5672 : 5671);
|
|
111
110
|
|
|
112
111
|
var user, pass;
|
|
113
|
-
if
|
|
114
|
-
|
|
115
|
-
|
|
112
|
+
// Only default if both are missing, to have the same behaviour as
|
|
113
|
+
// the stringly URL.
|
|
114
|
+
if (url.username == undefined && url.password == undefined) {
|
|
115
|
+
user = 'guest'; pass = 'guest';
|
|
116
116
|
} else {
|
|
117
|
-
user = url.username;
|
|
118
|
-
pass = url.password;
|
|
117
|
+
user = url.username || '';
|
|
118
|
+
pass = url.password || '';
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
|
|
121
|
+
var config = {
|
|
122
|
+
locale: url.locale,
|
|
123
|
+
channelMax: url.channelMax,
|
|
124
|
+
frameMax: url.frameMax,
|
|
125
|
+
heartbeat: url.heartbeat,
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
fields = openFrames(url.vhost, config, sockopts.credentials || credentials.plain(user, pass), extraClientProperties);
|
|
122
129
|
} else {
|
|
123
|
-
var parts = URL
|
|
130
|
+
var parts = URL(url, true); // yes, parse the query string
|
|
124
131
|
protocol = parts.protocol;
|
|
125
132
|
sockopts.host = parts.hostname;
|
|
126
133
|
sockopts.port = parseInt(parts.port) || ((protocol === 'amqp:') ? 5672 : 5671);
|
|
@@ -159,8 +166,11 @@ function connect(url, socketOptions, openCallback) {
|
|
|
159
166
|
}
|
|
160
167
|
|
|
161
168
|
if (timeout) {
|
|
162
|
-
sock.setTimeout(
|
|
163
|
-
|
|
169
|
+
sock.setTimeout(timeout, function() {
|
|
170
|
+
sock.end();
|
|
171
|
+
sock.destroy();
|
|
172
|
+
openCallback(new Error('connect ETIMEDOUT'));
|
|
173
|
+
});
|
|
164
174
|
}
|
|
165
175
|
|
|
166
176
|
sock.once('error', function(err) {
|
|
@@ -170,3 +180,4 @@ function connect(url, socketOptions, openCallback) {
|
|
|
170
180
|
}
|
|
171
181
|
|
|
172
182
|
module.exports.connect = connect;
|
|
183
|
+
module.exports.credentialsFromUrl = credentialsFromUrl;
|
package/lib/connection.js
CHANGED
|
@@ -9,6 +9,7 @@ var constants = defs.constants;
|
|
|
9
9
|
var frame = require('./frame');
|
|
10
10
|
var HEARTBEAT = frame.HEARTBEAT;
|
|
11
11
|
var Mux = require('./mux').Mux;
|
|
12
|
+
var Buffer = require('safe-buffer').Buffer
|
|
12
13
|
|
|
13
14
|
var Duplex =
|
|
14
15
|
require('stream').Duplex ||
|
|
@@ -43,7 +44,7 @@ function Connection(underlying) {
|
|
|
43
44
|
this.muxer = new Mux(stream);
|
|
44
45
|
|
|
45
46
|
// frames
|
|
46
|
-
this.rest =
|
|
47
|
+
this.rest = Buffer.alloc(0);
|
|
47
48
|
this.frameMax = constants.FRAME_MIN_SIZE;
|
|
48
49
|
this.sentSinceLastCheck = false;
|
|
49
50
|
this.recvSinceLastCheck = false;
|
|
@@ -204,6 +205,7 @@ C.open = function(allFields, openCallback0) {
|
|
|
204
205
|
allFields.mechanism)));
|
|
205
206
|
return;
|
|
206
207
|
}
|
|
208
|
+
self.serverProperties = start.fields.serverProperties;
|
|
207
209
|
send(defs.ConnectionStartOk);
|
|
208
210
|
wait(afterStartOk);
|
|
209
211
|
}
|
|
@@ -464,7 +466,7 @@ C.freshChannel = function(channel, options) {
|
|
|
464
466
|
C.releaseChannel = function(channel) {
|
|
465
467
|
this.freeChannels.clear(channel);
|
|
466
468
|
var buffer = this.channels[channel].buffer;
|
|
467
|
-
|
|
469
|
+
buffer.end(); // will also cause it to be unpiped
|
|
468
470
|
this.channels[channel] = null;
|
|
469
471
|
};
|
|
470
472
|
|
|
@@ -550,7 +552,7 @@ C.sendMessage = function(channel,
|
|
|
550
552
|
var allLen = methodHeaderLen + bodyLen;
|
|
551
553
|
|
|
552
554
|
if (allLen < SINGLE_CHUNK_THRESHOLD) {
|
|
553
|
-
var all =
|
|
555
|
+
var all = Buffer.alloc(allLen);
|
|
554
556
|
var offset = mframe.copy(all, 0);
|
|
555
557
|
offset += pframe.copy(all, offset);
|
|
556
558
|
|
|
@@ -560,7 +562,7 @@ C.sendMessage = function(channel,
|
|
|
560
562
|
}
|
|
561
563
|
else {
|
|
562
564
|
if (methodHeaderLen < SINGLE_CHUNK_THRESHOLD) {
|
|
563
|
-
var both =
|
|
565
|
+
var both = Buffer.alloc(methodHeaderLen);
|
|
564
566
|
var offset = mframe.copy(both, 0);
|
|
565
567
|
pframe.copy(both, offset);
|
|
566
568
|
buffer.write(both);
|
package/lib/credentials.js
CHANGED
|
@@ -8,19 +8,36 @@
|
|
|
8
8
|
// * PLAIN (send username and password in the plain)
|
|
9
9
|
// * EXTERNAL (assume the server will figure out who you are from
|
|
10
10
|
// context, i.e., your SSL certificate)
|
|
11
|
+
var Buffer = require('safe-buffer').Buffer
|
|
12
|
+
var codec = require('./codec')
|
|
11
13
|
|
|
12
14
|
module.exports.plain = function(user, passwd) {
|
|
13
15
|
return {
|
|
14
16
|
mechanism: 'PLAIN',
|
|
15
17
|
response: function() {
|
|
16
|
-
return
|
|
17
|
-
}
|
|
18
|
+
return Buffer.from(['', user, passwd].join(String.fromCharCode(0)))
|
|
19
|
+
},
|
|
20
|
+
username: user,
|
|
21
|
+
password: passwd
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
module.exports.amqplain = function(user, passwd) {
|
|
26
|
+
return {
|
|
27
|
+
mechanism: 'AMQPLAIN',
|
|
28
|
+
response: function() {
|
|
29
|
+
const buffer = Buffer.alloc(16384);
|
|
30
|
+
const size = codec.encodeTable(buffer, { LOGIN: user, PASSWORD: passwd}, 0);
|
|
31
|
+
return buffer.slice(4, size);
|
|
32
|
+
},
|
|
33
|
+
username: user,
|
|
34
|
+
password: passwd
|
|
18
35
|
}
|
|
19
36
|
}
|
|
20
37
|
|
|
21
38
|
module.exports.external = function() {
|
|
22
39
|
return {
|
|
23
40
|
mechanism: 'EXTERNAL',
|
|
24
|
-
response: function() { return
|
|
41
|
+
response: function() { return Buffer.from(''); }
|
|
25
42
|
}
|
|
26
43
|
}
|