amqplib 0.4.0 → 0.5.1
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/CHANGELOG.md +38 -0
- package/Makefile +1 -1
- package/README.md +27 -17
- package/channel_api.js +6 -6
- package/examples/headers.js +42 -0
- package/examples/send_generators.js +42 -0
- package/examples/tutorials/README.md +1 -1
- package/examples/tutorials/emit_log.js +3 -4
- package/examples/tutorials/emit_log_direct.js +3 -4
- package/examples/tutorials/emit_log_topic.js +3 -4
- package/examples/tutorials/new_task.js +4 -5
- package/examples/tutorials/package.json +2 -3
- package/examples/tutorials/receive.js +4 -4
- package/examples/tutorials/receive_logs.js +1 -1
- package/examples/tutorials/receive_logs_direct.js +2 -2
- package/examples/tutorials/receive_logs_topic.js +6 -6
- package/examples/tutorials/rpc_client.js +25 -26
- package/examples/tutorials/rpc_server.js +1 -1
- package/examples/tutorials/send.js +9 -5
- package/examples/tutorials/worker.js +1 -1
- package/examples/waitForConfirms.js +2 -2
- package/lib/callback_model.js +13 -12
- package/lib/channel_model.js +58 -66
- package/lib/connection.js +19 -16
- package/lib/heartbeat.js +1 -1
- package/package.json +3 -3
- package/test/channel.js +37 -32
- package/test/channel_api.js +104 -116
- package/test/util.js +19 -19
package/lib/channel_model.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
'use strict';
|
|
6
6
|
|
|
7
7
|
var defs = require('./defs');
|
|
8
|
-
var
|
|
8
|
+
var Promise = require('bluebird');
|
|
9
9
|
var inherits = require('util').inherits;
|
|
10
10
|
var EventEmitter = require('events').EventEmitter;
|
|
11
11
|
var BaseChannel = require('./channel').BaseChannel;
|
|
@@ -29,12 +29,7 @@ module.exports.ChannelModel = ChannelModel;
|
|
|
29
29
|
var CM = ChannelModel.prototype;
|
|
30
30
|
|
|
31
31
|
CM.close = function() {
|
|
32
|
-
|
|
33
|
-
this.connection.close(function (err) {
|
|
34
|
-
if (err === null) closed.resolve();
|
|
35
|
-
else closed.reject(err);
|
|
36
|
-
});
|
|
37
|
-
return closed.promise;
|
|
32
|
+
return Promise.fromCallback(this.connection.close.bind(this.connection));
|
|
38
33
|
};
|
|
39
34
|
|
|
40
35
|
// Channels
|
|
@@ -59,17 +54,18 @@ var C = Channel.prototype;
|
|
|
59
54
|
// response's fields; this is intended to be suitable for implementing
|
|
60
55
|
// API procedures.
|
|
61
56
|
C.rpc = function(method, fields, expect) {
|
|
62
|
-
var
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
57
|
+
var self = this;
|
|
58
|
+
return Promise.fromCallback(function(cb) {
|
|
59
|
+
return self._rpc(method, fields, expect, cb);
|
|
60
|
+
})
|
|
61
|
+
.then(function(f) {
|
|
62
|
+
return f.fields;
|
|
66
63
|
});
|
|
67
|
-
return reply.promise;
|
|
68
64
|
};
|
|
69
65
|
|
|
70
66
|
// Do the remarkably simple channel open handshake
|
|
71
67
|
C.open = function() {
|
|
72
|
-
return
|
|
68
|
+
return Promise.try(this.allocate.bind(this)).then(
|
|
73
69
|
function(ch) {
|
|
74
70
|
return ch.rpc(defs.ChannelOpen, {outOfBand: ""},
|
|
75
71
|
defs.ChannelOpenOk);
|
|
@@ -77,10 +73,11 @@ C.open = function() {
|
|
|
77
73
|
};
|
|
78
74
|
|
|
79
75
|
C.close = function() {
|
|
80
|
-
var
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
76
|
+
var self = this;
|
|
77
|
+
return Promise.fromCallback(function(cb) {
|
|
78
|
+
return self.closeBecause("Goodbye", defs.constants.REPLY_SUCCESS,
|
|
79
|
+
cb);
|
|
80
|
+
});
|
|
84
81
|
};
|
|
85
82
|
|
|
86
83
|
// === Public API, declaring queues and stuff ===
|
|
@@ -151,7 +148,7 @@ C.bindExchange = function(dest, source, pattern, argt) {
|
|
|
151
148
|
C.unbindExchange = function(dest, source, pattern, argt) {
|
|
152
149
|
return this.rpc(defs.ExchangeUnbind,
|
|
153
150
|
Args.unbindExchange(dest, source, pattern, argt),
|
|
154
|
-
defs.ExchangeUnbindOk);
|
|
151
|
+
defs.ExchangeUnbindOk);
|
|
155
152
|
};
|
|
156
153
|
|
|
157
154
|
// Working with messages
|
|
@@ -170,58 +167,52 @@ C.consume = function(queue, callback, options) {
|
|
|
170
167
|
// NB we want the callback to be run synchronously, so that we've
|
|
171
168
|
// registered the consumerTag before any messages can arrive.
|
|
172
169
|
var fields = Args.consume(queue, options);
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}
|
|
181
|
-
else reply.reject(err);
|
|
182
|
-
});
|
|
183
|
-
return reply.promise;
|
|
170
|
+
return Promise.fromCallback(function(cb) {
|
|
171
|
+
self._rpc(defs.BasicConsume, fields, defs.BasicConsumeOk, cb);
|
|
172
|
+
})
|
|
173
|
+
.then(function(ok) {
|
|
174
|
+
self.registerConsumer(ok.fields.consumerTag, callback);
|
|
175
|
+
return ok.fields;
|
|
176
|
+
});
|
|
184
177
|
};
|
|
185
178
|
|
|
186
179
|
C.cancel = function(consumerTag) {
|
|
187
180
|
var self = this;
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
});
|
|
198
|
-
return reply.promise;
|
|
181
|
+
return Promise.fromCallback(function(cb) {
|
|
182
|
+
self._rpc(defs.BasicCancel, Args.cancel(consumerTag),
|
|
183
|
+
defs.BasicCancelOk,
|
|
184
|
+
cb);
|
|
185
|
+
})
|
|
186
|
+
.then(function(ok) {
|
|
187
|
+
self.unregisterConsumer(consumerTag);
|
|
188
|
+
return ok.fields;
|
|
189
|
+
});
|
|
199
190
|
};
|
|
200
191
|
|
|
201
192
|
C.get = function(queue, options) {
|
|
202
|
-
var reply = defer();
|
|
203
193
|
var self = this;
|
|
204
194
|
var fields = Args.get(queue, options);
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
195
|
+
return Promise.fromCallback(function(cb) {
|
|
196
|
+
return self.sendOrEnqueue(defs.BasicGet, fields, cb);
|
|
197
|
+
})
|
|
198
|
+
.then(function(f) {
|
|
199
|
+
if (f.id === defs.BasicGetEmpty) {
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
else if (f.id === defs.BasicGetOk) {
|
|
203
|
+
var fields = f.fields;
|
|
204
|
+
return new Promise(function(resolve) {
|
|
212
205
|
self.handleMessage = acceptMessage(function(m) {
|
|
213
206
|
m.fields = fields;
|
|
214
|
-
|
|
207
|
+
resolve(m);
|
|
215
208
|
});
|
|
216
|
-
}
|
|
217
|
-
else {
|
|
218
|
-
reply.reject(new Error("Unexpected response to BasicGet: " +
|
|
219
|
-
inspect(f)));
|
|
220
|
-
}
|
|
209
|
+
});
|
|
221
210
|
}
|
|
222
|
-
else
|
|
223
|
-
|
|
224
|
-
|
|
211
|
+
else {
|
|
212
|
+
throw new Error("Unexpected response to BasicGet: " +
|
|
213
|
+
inspect(f));
|
|
214
|
+
}
|
|
215
|
+
})
|
|
225
216
|
};
|
|
226
217
|
|
|
227
218
|
C.ack = function(message, allUpTo) {
|
|
@@ -308,19 +299,20 @@ CC.sendToQueue = function(queue, content, options, cb) {
|
|
|
308
299
|
};
|
|
309
300
|
|
|
310
301
|
CC.waitForConfirms = function() {
|
|
311
|
-
var
|
|
302
|
+
var awaiting = [];
|
|
312
303
|
var unconfirmed = this.unconfirmed;
|
|
313
304
|
unconfirmed.forEach(function(val, index) {
|
|
314
305
|
if (val === null); // already confirmed
|
|
315
306
|
else {
|
|
316
|
-
var confirmed =
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
307
|
+
var confirmed = new Promise(function(resolve, reject) {
|
|
308
|
+
unconfirmed[index] = function(err) {
|
|
309
|
+
if (val) val(err);
|
|
310
|
+
if (err === null) resolve();
|
|
311
|
+
else reject(err);
|
|
312
|
+
};
|
|
313
|
+
});
|
|
314
|
+
awaiting.push(confirmed);
|
|
323
315
|
}
|
|
324
316
|
});
|
|
325
|
-
return
|
|
317
|
+
return Promise.all(awaiting);
|
|
326
318
|
};
|
package/lib/connection.js
CHANGED
|
@@ -87,12 +87,12 @@ function channel0(connection) {
|
|
|
87
87
|
connection.sendMethod(0, defs.ConnectionCloseOk, {});
|
|
88
88
|
var emsg = fmt('Connection closed: %s', closeMsg(f));
|
|
89
89
|
var s = stackCapture(emsg);
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
90
|
+
var e = new Error(emsg);
|
|
91
|
+
e.code = f.fields.replyCode;
|
|
92
|
+
if (isFatalError(e)) {
|
|
93
93
|
connection.emit('error', e);
|
|
94
94
|
}
|
|
95
|
-
connection.toClosed(s,
|
|
95
|
+
connection.toClosed(s, e);
|
|
96
96
|
}
|
|
97
97
|
else if (f.id === defs.ConnectionBlocked) {
|
|
98
98
|
connection.emit('blocked', f.fields.reason);
|
|
@@ -148,7 +148,7 @@ C.open = function(allFields, openCallback0) {
|
|
|
148
148
|
// This is where we'll put our negotiated values
|
|
149
149
|
var tunedOptions = Object.create(allFields);
|
|
150
150
|
|
|
151
|
-
function
|
|
151
|
+
function wait(k) {
|
|
152
152
|
self.step(function(err, frame) {
|
|
153
153
|
if (err !== null) bail(err);
|
|
154
154
|
else if (frame.channel !== 0) {
|
|
@@ -161,7 +161,7 @@ C.open = function(allFields, openCallback0) {
|
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
function expect(Method, k) {
|
|
164
|
-
|
|
164
|
+
wait(function(frame) {
|
|
165
165
|
if (frame.id === Method) k(frame);
|
|
166
166
|
else {
|
|
167
167
|
bail(new Error(
|
|
@@ -205,7 +205,7 @@ C.open = function(allFields, openCallback0) {
|
|
|
205
205
|
return;
|
|
206
206
|
}
|
|
207
207
|
send(defs.ConnectionStartOk);
|
|
208
|
-
|
|
208
|
+
wait(afterStartOk);
|
|
209
209
|
}
|
|
210
210
|
|
|
211
211
|
function afterStartOk(reply) {
|
|
@@ -350,7 +350,7 @@ C.onSocketError = function(err) {
|
|
|
350
350
|
this.expectSocketClose = true;
|
|
351
351
|
this.emit('error', err);
|
|
352
352
|
var s = stackCapture('Socket error');
|
|
353
|
-
this.toClosed(s, err
|
|
353
|
+
this.toClosed(s, err);
|
|
354
354
|
}
|
|
355
355
|
};
|
|
356
356
|
|
|
@@ -375,7 +375,7 @@ C.toClosing = function(capturedStack, k) {
|
|
|
375
375
|
if (f.id === defs.ConnectionCloseOk) {
|
|
376
376
|
if (k) k();
|
|
377
377
|
var s = stackCapture('ConnectionCloseOk received');
|
|
378
|
-
this.toClosed(s,
|
|
378
|
+
this.toClosed(s, undefined);
|
|
379
379
|
}
|
|
380
380
|
else if (f.id === defs.ConnectionClose) {
|
|
381
381
|
send(0, defs.ConnectionCloseOk, {});
|
|
@@ -395,9 +395,10 @@ C._closeChannels = function(capturedStack) {
|
|
|
395
395
|
};
|
|
396
396
|
|
|
397
397
|
// A close has been confirmed. Cease all communication.
|
|
398
|
-
C.toClosed = function(capturedStack,
|
|
398
|
+
C.toClosed = function(capturedStack, maybeErr) {
|
|
399
399
|
this._closeChannels(capturedStack);
|
|
400
|
-
var info = fmt('Connection closed (%s)',
|
|
400
|
+
var info = fmt('Connection closed (%s)',
|
|
401
|
+
(maybeErr) ? maybeErr.toString() : 'by client');
|
|
401
402
|
// Tidy up, invalidate enverything, dynamite the bridges.
|
|
402
403
|
invalidateSend(this, info, capturedStack);
|
|
403
404
|
this.accept = invalidOp(info, capturedStack);
|
|
@@ -408,7 +409,7 @@ C.toClosed = function(capturedStack, msg) {
|
|
|
408
409
|
// This is certainly true now, if it wasn't before
|
|
409
410
|
this.expectSocketClose = true;
|
|
410
411
|
this.stream.end();
|
|
411
|
-
this.emit('close',
|
|
412
|
+
this.emit('close', maybeErr);
|
|
412
413
|
};
|
|
413
414
|
|
|
414
415
|
// ===
|
|
@@ -421,9 +422,10 @@ C.startHeartbeater = function() {
|
|
|
421
422
|
this.checkSend.bind(this),
|
|
422
423
|
this.checkRecv.bind(this));
|
|
423
424
|
hb.on('timeout', function() {
|
|
424
|
-
|
|
425
|
+
var hberr = new Error("Heartbeat timeout");
|
|
426
|
+
self.emit('error', hberr);
|
|
425
427
|
var s = stackCapture('Heartbeat timeout');
|
|
426
|
-
self.toClosed(s);
|
|
428
|
+
self.toClosed(s, hberr);
|
|
427
429
|
});
|
|
428
430
|
hb.on('beat', function() {
|
|
429
431
|
self.sendHeartbeat();
|
|
@@ -629,8 +631,8 @@ function wrapStream(s) {
|
|
|
629
631
|
}
|
|
630
632
|
}
|
|
631
633
|
|
|
632
|
-
function
|
|
633
|
-
switch (
|
|
634
|
+
function isFatalError(error) {
|
|
635
|
+
switch (error && error.code) {
|
|
634
636
|
case defs.constants.CONNECTION_FORCED:
|
|
635
637
|
case defs.constants.REPLY_SUCCESS:
|
|
636
638
|
return false;
|
|
@@ -640,3 +642,4 @@ function closeIsError(fields) {
|
|
|
640
642
|
}
|
|
641
643
|
|
|
642
644
|
module.exports.Connection = Connection;
|
|
645
|
+
module.exports.isFatalError = isFatalError;
|
package/lib/heartbeat.js
CHANGED
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
// at least twice before sending another)
|
|
41
41
|
//
|
|
42
42
|
// This design is based largely on RabbitMQ's heartbeating:
|
|
43
|
-
// https://github.com/rabbitmq/rabbitmq-
|
|
43
|
+
// https://github.com/rabbitmq/rabbitmq-common/blob/master/src/rabbit_heartbeat.erl
|
|
44
44
|
|
|
45
45
|
// %% Yes, I could apply the same 'actually passage of time' thing to
|
|
46
46
|
// %% send as well as to recv.
|
package/package.json
CHANGED
|
@@ -2,20 +2,20 @@
|
|
|
2
2
|
"name": "amqplib",
|
|
3
3
|
"homepage": "http://squaremo.github.io/amqp.node/",
|
|
4
4
|
"main": "./channel_api.js",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.5.1",
|
|
6
6
|
"description": "An AMQP 0-9-1 (e.g., RabbitMQ) library and client.",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
9
|
"url": "https://github.com/squaremo/amqp.node.git"
|
|
10
10
|
},
|
|
11
11
|
"engines": {
|
|
12
|
-
"node": ">=0.8 <
|
|
12
|
+
"node": ">=0.8 <6 || ^6"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"bitsyntax": "~0.0.4",
|
|
16
16
|
"buffer-more-ints": "0.0.2",
|
|
17
17
|
"readable-stream": "1.x >=1.1.9",
|
|
18
|
-
"
|
|
18
|
+
"bluebird": "^3.4.6"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"mocha": "~1",
|
package/test/channel.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
'use strict';
|
|
4
4
|
|
|
5
5
|
var assert = require('assert');
|
|
6
|
-
var
|
|
6
|
+
var Promise = require('bluebird');
|
|
7
7
|
var Channel = require('../lib/channel').Channel;
|
|
8
8
|
var Connection = require('../lib/connection').Connection;
|
|
9
9
|
var util = require('./util');
|
|
@@ -76,14 +76,12 @@ var DELIVER_FIELDS = {
|
|
|
76
76
|
};
|
|
77
77
|
|
|
78
78
|
function open(ch) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
});
|
|
86
|
-
return opened.promise;
|
|
79
|
+
return Promise.try(function() {
|
|
80
|
+
ch.allocate();
|
|
81
|
+
return Promise.fromCallback(function(cb) {
|
|
82
|
+
ch._rpc(defs.ChannelOpen, {outOfBand: ''}, defs.ChannelOpenOk, cb);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
87
85
|
}
|
|
88
86
|
|
|
89
87
|
suite("channel open and close", function() {
|
|
@@ -112,10 +110,9 @@ test("open, close", channelTest(
|
|
|
112
110
|
function(ch, done) {
|
|
113
111
|
open(ch)
|
|
114
112
|
.then(function() {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
return closed.promise;
|
|
113
|
+
return new Promise(function(resolve) {
|
|
114
|
+
ch.closeBecause("Bye", defs.constants.REPLY_SUCCESS, resolve);
|
|
115
|
+
});
|
|
119
116
|
})
|
|
120
117
|
.then(succeed(done), fail(done));
|
|
121
118
|
},
|
|
@@ -204,7 +201,7 @@ test("RPC", channelTest(
|
|
|
204
201
|
prefetchSize: 0,
|
|
205
202
|
global: false
|
|
206
203
|
};
|
|
207
|
-
|
|
204
|
+
|
|
208
205
|
ch._rpc(defs.BasicQos, fields, defs.BasicQosOk, wheeboom);
|
|
209
206
|
ch._rpc(defs.BasicQos, fields, defs.BasicQosOk, wheeboom);
|
|
210
207
|
ch._rpc(defs.BasicQos, fields, defs.BasicQosOk, wheeboom);
|
|
@@ -233,7 +230,7 @@ test("Bad RPC", channelTest(
|
|
|
233
230
|
assert.strictEqual(505, error.code);
|
|
234
231
|
succeed(errLatch)();
|
|
235
232
|
});
|
|
236
|
-
|
|
233
|
+
|
|
237
234
|
open(ch)
|
|
238
235
|
.then(function() {
|
|
239
236
|
ch._rpc(defs.BasicRecover, {requeue: true}, defs.BasicRecoverOk,
|
|
@@ -257,27 +254,34 @@ test("Bad RPC", channelTest(
|
|
|
257
254
|
test("RPC on closed channel", channelTest(
|
|
258
255
|
function(ch, done) {
|
|
259
256
|
open(ch);
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
257
|
+
|
|
258
|
+
var close = new Promise(function(resolve) {
|
|
259
|
+
ch.on('error', function(error) {
|
|
260
|
+
assert.strictEqual(504, error.code);
|
|
261
|
+
resolve();
|
|
262
|
+
});
|
|
264
263
|
});
|
|
265
264
|
|
|
266
|
-
function failureCb(
|
|
265
|
+
function failureCb(resolve, reject) {
|
|
267
266
|
return function(err) {
|
|
268
|
-
if (err !== null)
|
|
269
|
-
else
|
|
267
|
+
if (err !== null) resolve();
|
|
268
|
+
else reject();
|
|
270
269
|
}
|
|
271
270
|
}
|
|
272
271
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
.
|
|
280
|
-
|
|
272
|
+
var fail1 = new Promise(function(resolve, reject) {
|
|
273
|
+
return ch._rpc(defs.BasicRecover, {requeue:true}, defs.BasicRecoverOk,
|
|
274
|
+
failureCb(resolve, reject));
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
var fail2 = new Promise(function(resolve, reject) {
|
|
278
|
+
return ch._rpc(defs.BasicRecover, {requeue:true}, defs.BasicRecoverOk,
|
|
279
|
+
failureCb(resolve, reject));
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
Promise.join(close, fail1, fail2)
|
|
283
|
+
.then(succeed(done))
|
|
284
|
+
.catch(fail(done));
|
|
281
285
|
},
|
|
282
286
|
function(send, await, done, ch) {
|
|
283
287
|
await(defs.BasicRecover)()
|
|
@@ -289,7 +293,8 @@ test("RPC on closed channel", channelTest(
|
|
|
289
293
|
}, ch);
|
|
290
294
|
return await(defs.ChannelCloseOk);
|
|
291
295
|
})
|
|
292
|
-
.then(succeed(done)
|
|
296
|
+
.then(succeed(done))
|
|
297
|
+
.catch(fail(done));
|
|
293
298
|
}));
|
|
294
299
|
|
|
295
300
|
test("publish all < single chunk threshold", channelTest(
|
|
@@ -453,7 +458,7 @@ test("bad properties send", channelTest(
|
|
|
453
458
|
},
|
|
454
459
|
function(send, await, done, ch) {
|
|
455
460
|
done();
|
|
456
|
-
}));
|
|
461
|
+
}));
|
|
457
462
|
|
|
458
463
|
test("bad consumer", channelTest(
|
|
459
464
|
function(ch, done) {
|