@onify/fake-amqplib 1.0.0 → 3.0.0
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/README.md +90 -30
- package/index.d.ts +60 -0
- package/index.js +628 -365
- package/main.cjs +763 -0
- package/package.json +31 -13
- package/CHANGELOG.md +0 -70
package/index.js
CHANGED
|
@@ -1,17 +1,36 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
const
|
|
1
|
+
import { Broker } from 'smqp';
|
|
2
|
+
import { EventEmitter } from 'events';
|
|
3
|
+
import { format as urlFormat } from 'url';
|
|
4
|
+
|
|
5
|
+
const kSmqp = Symbol.for('smqp');
|
|
6
|
+
const kClosed = Symbol.for('closed');
|
|
7
|
+
const kDeliveryTag = Symbol.for('channel delivery tag');
|
|
8
|
+
const kPrefetch = Symbol.for('prefetch');
|
|
9
|
+
const kChannelPrefetch = Symbol.for('channel prefetch');
|
|
10
|
+
|
|
11
|
+
class AmqplibBroker extends Broker {
|
|
12
|
+
constructor(...args) {
|
|
13
|
+
super(...args);
|
|
14
|
+
this[kDeliveryTag] = 0;
|
|
15
|
+
}
|
|
16
|
+
_getNextDeliveryTag() {
|
|
17
|
+
return ++this[kDeliveryTag];
|
|
18
|
+
}
|
|
19
|
+
_getMessageByDeliveryTag(queue, deliveryTag) {
|
|
20
|
+
const q = this.getQueue(queue);
|
|
21
|
+
return q.messages.find((m) => m.fields.deliveryTag === deliveryTag);
|
|
22
|
+
}
|
|
23
|
+
_getChannelConsumers(channelName) {
|
|
24
|
+
return this.getConsumers().filter((f) => f.options.channelName === channelName);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
8
27
|
|
|
9
28
|
class FakeAmqpError extends Error {
|
|
10
29
|
constructor(message, code, killChannel, killConnection) {
|
|
11
30
|
super(message);
|
|
12
31
|
this.code = code;
|
|
13
32
|
this._killChannel = killChannel;
|
|
14
|
-
this._killConnection
|
|
33
|
+
this._killConnection = killConnection;
|
|
15
34
|
}
|
|
16
35
|
}
|
|
17
36
|
|
|
@@ -21,405 +40,588 @@ class FakeAmqpNotFoundError extends FakeAmqpError {
|
|
|
21
40
|
}
|
|
22
41
|
}
|
|
23
42
|
|
|
24
|
-
|
|
43
|
+
class FakeAmqpUnknownDeliveryTag extends FakeAmqpError {
|
|
44
|
+
constructor(deliveryTag) {
|
|
45
|
+
super(`Channel closed by server: 406 (PRECONDITION-FAILED) with message "PRECONDITION_FAILED - unknown delivery tag ${deliveryTag}`, 406, true, false);
|
|
46
|
+
}
|
|
47
|
+
get _emit() {
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function Message(smqpMessage, deliveryTag) {
|
|
53
|
+
this[kSmqp] = smqpMessage;
|
|
54
|
+
this.fields = { ...smqpMessage.fields, deliveryTag };
|
|
55
|
+
this.content = Buffer.from(smqpMessage.content);
|
|
56
|
+
this.properties = { ...smqpMessage.properties };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export class FakeAmqplibChannel extends EventEmitter {
|
|
60
|
+
constructor(broker, connection) {
|
|
61
|
+
super();
|
|
62
|
+
this.connection = connection;
|
|
63
|
+
|
|
64
|
+
this[kPrefetch] = 10000;
|
|
65
|
+
this[kChannelPrefetch] = Infinity;
|
|
66
|
+
this[kClosed] = false;
|
|
67
|
+
const channelName = this._channelName = `channel-${generateId()}`;
|
|
68
|
+
this._version = connection._version;
|
|
69
|
+
this._broker = broker;
|
|
70
|
+
|
|
71
|
+
this._channelQueue = broker.assertQueue(`#${channelName}`);
|
|
72
|
+
this._emitReturn = this._emitReturn.bind(this);
|
|
25
73
|
|
|
26
|
-
|
|
74
|
+
broker.on('return', this._emitReturn);
|
|
75
|
+
|
|
76
|
+
this._createChannelMessage = this._createChannelMessage.bind(this);
|
|
77
|
+
this._calculateChannelCapacity = this._calculateChannelCapacity.bind(this);
|
|
78
|
+
}
|
|
79
|
+
get _closed() {
|
|
80
|
+
return this[kClosed];
|
|
81
|
+
}
|
|
82
|
+
assertExchange(...args) {
|
|
83
|
+
return this._callBroker(assertExchange, ...args);
|
|
27
84
|
|
|
28
|
-
function
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
85
|
+
function assertExchange(exchange, ...assertArgs) {
|
|
86
|
+
this.assertExchange(exchange, ...assertArgs);
|
|
87
|
+
return { exchange };
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
assertQueue(...args) {
|
|
91
|
+
const connection = this.connection;
|
|
92
|
+
return this._callBroker(assertQueue, ...args);
|
|
93
|
+
|
|
94
|
+
function assertQueue(queueName, ...assertArgs) {
|
|
95
|
+
const name = queueName ? queueName : `amqp.gen-${generateId()}`;
|
|
96
|
+
const options = typeof assertArgs[0] === 'object' ? assertArgs.shift() : {};
|
|
97
|
+
const queue = this.assertQueue(name, { ...options, _connectionId: connection._id }, ...assertArgs);
|
|
98
|
+
return {
|
|
99
|
+
queue: name,
|
|
100
|
+
messageCount: queue.messageCount,
|
|
101
|
+
consumerCount: queue.consumerCount,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
bindExchange(destination, source, ...args) {
|
|
106
|
+
const broker = this._broker;
|
|
107
|
+
return Promise.all([ this.checkExchange(source), this.checkExchange(destination) ]).then(() => {
|
|
108
|
+
return this._callBroker(broker.bindExchange, source, destination, ...args);
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
bindQueue(queue, source, ...args) {
|
|
112
|
+
return Promise.all([ this.checkQueue(queue), this.checkExchange(source) ]).then(() => {
|
|
113
|
+
return this._callBroker(this._broker.bindQueue, queue, source, ...args);
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
checkExchange(name, ...args) {
|
|
117
|
+
const connPath = this.connection._url.pathname;
|
|
118
|
+
return this._callBroker(check, ...args);
|
|
40
119
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
120
|
+
function check() {
|
|
121
|
+
if (!this.getExchange(name)) throw new FakeAmqpNotFoundError('exchange', name, connPath);
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
44
124
|
}
|
|
125
|
+
checkQueue(name, ...args) {
|
|
126
|
+
const connPath = this.connection._url.pathname;
|
|
127
|
+
return this._callBroker(check, ...args);
|
|
128
|
+
|
|
129
|
+
function check() {
|
|
130
|
+
let queue;
|
|
131
|
+
if (!(queue = this.getQueue(name))) {
|
|
132
|
+
throw new FakeAmqpNotFoundError('queue', name, connPath);
|
|
133
|
+
}
|
|
45
134
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
135
|
+
return {
|
|
136
|
+
messageCount: queue.messageCount,
|
|
137
|
+
consumerCount: queue.consumerCount,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
get(queue, ...args) {
|
|
142
|
+
const connPath = this.connection._url.pathname;
|
|
143
|
+
const createMessage = this._createChannelMessage;
|
|
144
|
+
return this._callBroker(getMessage, ...args);
|
|
145
|
+
|
|
146
|
+
function getMessage(...getargs) {
|
|
147
|
+
const q = this.getQueue(queue);
|
|
148
|
+
if (!q) throw new FakeAmqpNotFoundError('queue', queue, connPath);
|
|
149
|
+
const msg = q.get(...getargs) || false;
|
|
150
|
+
if (!msg) return msg;
|
|
151
|
+
|
|
152
|
+
return createMessage(msg, args[0]?.noAck);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
deleteExchange(exchange, ...args) {
|
|
156
|
+
const connPath = this.connection._url.pathname;
|
|
157
|
+
return this._callBroker(check, ...args);
|
|
158
|
+
|
|
159
|
+
function check() {
|
|
160
|
+
const result = this.deleteExchange(exchange, ...args);
|
|
161
|
+
if (!result && this.owner.version < 3.2) throw new FakeAmqpNotFoundError('exchange', exchange, connPath);
|
|
162
|
+
return result;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
deleteQueue(queue, ...args) {
|
|
166
|
+
const connPath = this.connection._url.pathname;
|
|
167
|
+
return this._callBroker(check, ...args);
|
|
168
|
+
|
|
169
|
+
function check() {
|
|
170
|
+
const result = this.deleteQueue(queue, ...args);
|
|
171
|
+
if (!result && this.owner.version < 3.2) throw new FakeAmqpNotFoundError('queue', queue, connPath);
|
|
172
|
+
return result;
|
|
173
|
+
}
|
|
52
174
|
}
|
|
175
|
+
publish(exchange, routingKey, content, options, callback) {
|
|
176
|
+
if (!Buffer.isBuffer(content)) throw new TypeError('content is not a buffer');
|
|
177
|
+
if (exchange === '') return this.sendToQueue(routingKey, content, options, callback);
|
|
178
|
+
|
|
179
|
+
const args = [ this._broker.publish, exchange, routingKey, content ];
|
|
180
|
+
|
|
181
|
+
args.push(options, callback);
|
|
182
|
+
|
|
183
|
+
this.checkExchange(exchange).then(() => {
|
|
184
|
+
return this._callBroker(...args);
|
|
185
|
+
}).catch((err) => {
|
|
186
|
+
this.emit('error', err);
|
|
187
|
+
});
|
|
53
188
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
189
|
+
return true;
|
|
190
|
+
}
|
|
191
|
+
purgeQueue(queue, ...args) {
|
|
192
|
+
const connPath = this.connection._url.pathname;
|
|
193
|
+
return this._callBroker(check, ...args);
|
|
194
|
+
|
|
195
|
+
function check() {
|
|
196
|
+
const result = this.purgeQueue(queue);
|
|
197
|
+
if (!result && this.owner.version < 3.2) throw new FakeAmqpNotFoundError('queue', queue, connPath);
|
|
198
|
+
return result === undefined ? undefined : { messageCount: result };
|
|
57
199
|
}
|
|
58
200
|
}
|
|
201
|
+
sendToQueue(queue, content, options, callback) {
|
|
202
|
+
if (!Buffer.isBuffer(content)) throw new TypeError('content is not a buffer');
|
|
59
203
|
|
|
60
|
-
|
|
61
|
-
const emitter = new EventEmitter();
|
|
62
|
-
const options = connArgs.filter((a) => typeof a !== 'function');
|
|
63
|
-
let closed = false;
|
|
64
|
-
const channels = [];
|
|
65
|
-
const url = normalizeAmqpUrl(amqpUrl);
|
|
204
|
+
const args = [ this._broker.sendToQueue, queue, content ];
|
|
66
205
|
|
|
67
|
-
|
|
68
|
-
_id: generateId(),
|
|
69
|
-
_broker: broker,
|
|
70
|
-
_version: version,
|
|
71
|
-
_url: url,
|
|
72
|
-
get _closed() {
|
|
73
|
-
return closed;
|
|
74
|
-
},
|
|
75
|
-
get _emitter() {
|
|
76
|
-
return emitter;
|
|
77
|
-
},
|
|
78
|
-
options,
|
|
79
|
-
createChannel(...args) {
|
|
80
|
-
if (closed) return resolveOrCallback(args.slice(-1)[0], unavailable());
|
|
206
|
+
args.push(options, callback);
|
|
81
207
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if (closed) return resolveOrCallback(args.slice(-1)[0], unavailable());
|
|
208
|
+
this.checkQueue(queue).then(() => {
|
|
209
|
+
return this._callBroker(...args);
|
|
210
|
+
}).catch((err) => {
|
|
211
|
+
this.emit('error', err);
|
|
212
|
+
});
|
|
88
213
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if (closed) return resolveOrCallback(args.slice(-1)[0]);
|
|
95
|
-
closed = true;
|
|
214
|
+
return true;
|
|
215
|
+
}
|
|
216
|
+
unbindExchange(destination, source, pattern, ...args) {
|
|
217
|
+
const connPath = this.connection._url.pathname;
|
|
218
|
+
return this._callBroker(check, ...args);
|
|
96
219
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
220
|
+
function check() {
|
|
221
|
+
const q = this.getExchange(destination);
|
|
222
|
+
if (!q) throw new FakeAmqpNotFoundError('exchange', destination);
|
|
100
223
|
|
|
101
|
-
|
|
224
|
+
const exchange = this.getExchange(source);
|
|
225
|
+
if (!exchange) throw new FakeAmqpNotFoundError('exchange', source);
|
|
102
226
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
on(...args) {
|
|
106
|
-
return emitter.on(...args);
|
|
107
|
-
},
|
|
108
|
-
once(...args) {
|
|
109
|
-
return emitter.once(...args);
|
|
110
|
-
},
|
|
111
|
-
};
|
|
227
|
+
const result = this.unbindExchange(source, destination, pattern);
|
|
228
|
+
if (!result && this.owner.version <= 3.2) throw new FakeAmqpNotFoundError('binding', pattern, connPath);
|
|
112
229
|
|
|
113
|
-
|
|
114
|
-
return new FakeAmqpError('Connection closed: 504', 504);
|
|
230
|
+
return true;
|
|
115
231
|
}
|
|
116
232
|
}
|
|
233
|
+
unbindQueue(queue, source, pattern, ...args) {
|
|
234
|
+
const connPath = this.connection._url.pathname;
|
|
235
|
+
return this._callBroker(check, ...args);
|
|
117
236
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
const channelName = 'channel-' + generateId();
|
|
122
|
-
const version = connection._version;
|
|
237
|
+
function check() {
|
|
238
|
+
const q = this.getQueue(queue);
|
|
239
|
+
if (!q) throw new FakeAmqpNotFoundError('queue', queue);
|
|
123
240
|
|
|
124
|
-
|
|
241
|
+
const exchange = this.getExchange(source);
|
|
242
|
+
if (!exchange) throw new FakeAmqpNotFoundError('exchange', source);
|
|
125
243
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
return emitter;
|
|
131
|
-
},
|
|
132
|
-
get _closed() {
|
|
133
|
-
return closed;
|
|
134
|
-
},
|
|
135
|
-
assertExchange(...args) {
|
|
136
|
-
return callBroker(assertExchange, ...args);
|
|
137
|
-
|
|
138
|
-
function assertExchange(exchange, ...args) {
|
|
139
|
-
broker.assertExchange(exchange, ...args);
|
|
140
|
-
return {
|
|
141
|
-
exchange,
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
},
|
|
145
|
-
assertQueue(...args) {
|
|
146
|
-
return callBroker(assertQueue, ...args);
|
|
147
|
-
|
|
148
|
-
function assertQueue(queueName, ...args) {
|
|
149
|
-
const name = queueName ? queueName : 'amqp.gen-' + generateId();
|
|
150
|
-
const options = typeof args[0] === 'object' ? args.shift() : {};
|
|
151
|
-
const queue = broker.assertQueue(name, {...options, _connectionId: connection._id}, ...args);
|
|
152
|
-
return {
|
|
153
|
-
queue: name,
|
|
154
|
-
messageCount: queue.messageCount,
|
|
155
|
-
consumerCount: queue.consumerCount,
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
},
|
|
159
|
-
bindExchange(destination, source, ...args) {
|
|
160
|
-
return Promise.all([this.checkExchange(source), this.checkExchange(destination)]).then(() => {
|
|
161
|
-
return callBroker(broker.bindExchange, source, destination, ...args);
|
|
162
|
-
});
|
|
163
|
-
},
|
|
164
|
-
bindQueue(queue, source, ...args) {
|
|
165
|
-
return Promise.all([this.checkQueue(queue), this.checkExchange(source)]).then(() => {
|
|
166
|
-
return callBroker(broker.bindQueue, queue, source, ...args);
|
|
167
|
-
});
|
|
168
|
-
},
|
|
169
|
-
checkExchange(name, ...args) {
|
|
170
|
-
return callBroker(check, ...args);
|
|
244
|
+
const binding = exchange.getBinding(queue, pattern);
|
|
245
|
+
if (!binding && this.owner.version <= 3.2) {
|
|
246
|
+
throw new FakeAmqpNotFoundError('binding', pattern, connPath, this.owner.version < 3.2);
|
|
247
|
+
}
|
|
171
248
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
}
|
|
191
|
-
},
|
|
192
|
-
get(queue, ...args) {
|
|
193
|
-
return callBroker(getMessage, ...args);
|
|
194
|
-
|
|
195
|
-
function getMessage(...getargs) {
|
|
196
|
-
const q = broker.getQueue(queue);
|
|
197
|
-
if (!q) throw new FakeAmqpNotFoundError('queue', queue, connection._url.pathname);
|
|
198
|
-
const msg = q.get(...getargs) || false;
|
|
199
|
-
if (!msg) return msg;
|
|
200
|
-
return new Message(msg);
|
|
201
|
-
}
|
|
202
|
-
},
|
|
203
|
-
deleteExchange(exchange, ...args) {
|
|
204
|
-
return callBroker(check, ...args);
|
|
205
|
-
|
|
206
|
-
function check() {
|
|
207
|
-
const result = broker.deleteExchange(exchange, ...args);
|
|
208
|
-
if (!result && version < 3.2) throw new FakeAmqpNotFoundError('exchange', exchange, connection._url.pathname);
|
|
209
|
-
return result;
|
|
210
|
-
}
|
|
211
|
-
},
|
|
212
|
-
deleteQueue(queue, ...args) {
|
|
213
|
-
return callBroker(check, ...args);
|
|
214
|
-
|
|
215
|
-
function check() {
|
|
216
|
-
const result = broker.deleteQueue(queue, ...args);
|
|
217
|
-
if (!result && version < 3.2) throw new FakeAmqpNotFoundError('queue', queue, connection._url.pathname);
|
|
218
|
-
return result;
|
|
219
|
-
}
|
|
220
|
-
},
|
|
221
|
-
publish(exchange, routingKey, content, options, callback) {
|
|
222
|
-
if (!Buffer.isBuffer(content)) throw new TypeError('content is not a buffer');
|
|
223
|
-
if (exchange === '') return this.sendToQueue(routingKey, content, options, callback);
|
|
249
|
+
this.unbindQueue(queue, source, pattern);
|
|
250
|
+
return true;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
consume(queue, onMessage, options = {}, callback) {
|
|
254
|
+
const { _id: connId, _url: connUrl } = this.connection;
|
|
255
|
+
const createMessage = this._createChannelMessage;
|
|
256
|
+
const calculateCapacity = this._calculateChannelCapacity;
|
|
257
|
+
const channelName = this._channelName;
|
|
258
|
+
const prefetch = this[kPrefetch];
|
|
259
|
+
|
|
260
|
+
return this._callBroker(consume, callback);
|
|
261
|
+
|
|
262
|
+
function consume() {
|
|
263
|
+
const q = queue && this.getQueue(queue);
|
|
264
|
+
if (!q) {
|
|
265
|
+
throw new FakeAmqpNotFoundError('queue', queue, connUrl.pathname);
|
|
266
|
+
}
|
|
224
267
|
|
|
225
|
-
|
|
268
|
+
if (q.exclusive || (q.options.exclusive && q.options._connectionId !== connId)) {
|
|
269
|
+
throw new FakeAmqpError(`Channel closed by server: 403 (ACCESS-REFUSED) with message "ACCESS_REFUSED - queue '${queue}' in vhost '${connUrl.pathname}' in exclusive use"`, 403, true, true);
|
|
270
|
+
}
|
|
226
271
|
|
|
227
|
-
|
|
228
|
-
|
|
272
|
+
const consumer = this.consume(queue, onMessage && handler, {
|
|
273
|
+
...options,
|
|
274
|
+
channelName,
|
|
275
|
+
prefetch: calculateCapacity(prefetch),
|
|
276
|
+
_consumerPrefetch: prefetch,
|
|
277
|
+
});
|
|
229
278
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
}
|
|
279
|
+
const capacityProp = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(consumer), 'capacity');
|
|
280
|
+
Object.defineProperty(consumer, 'capacity', {
|
|
281
|
+
get() {
|
|
282
|
+
return calculateCapacity(capacityProp.get.call(this));
|
|
283
|
+
},
|
|
284
|
+
});
|
|
235
285
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
purgeQueue(queue, ...args) {
|
|
239
|
-
return callBroker(check, ...args);
|
|
240
|
-
|
|
241
|
-
function check() {
|
|
242
|
-
const result = broker.purgeQueue(queue);
|
|
243
|
-
if (!result && version < 3.2) throw new FakeAmqpNotFoundError('queue', queue, connection._url.pathname);
|
|
244
|
-
return result === undefined ? undefined : {messageCount: result};
|
|
245
|
-
}
|
|
246
|
-
},
|
|
247
|
-
sendToQueue(queue, content, options, callback) {
|
|
248
|
-
if (!Buffer.isBuffer(content)) throw new TypeError('content is not a buffer');
|
|
286
|
+
return { consumerTag: consumer.consumerTag };
|
|
287
|
+
}
|
|
249
288
|
|
|
250
|
-
|
|
289
|
+
function handler(_, msg) {
|
|
290
|
+
onMessage(createMessage(msg, options.noAck));
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
cancel(consumerTag, ...args) {
|
|
294
|
+
return this._callBroker(this._broker.cancel, consumerTag, ...args);
|
|
295
|
+
}
|
|
296
|
+
close(callback) {
|
|
297
|
+
if (this[kClosed]) return;
|
|
298
|
+
this._teardown();
|
|
299
|
+
this.emit('close');
|
|
300
|
+
return resolveOrCallback(callback);
|
|
301
|
+
}
|
|
302
|
+
ack(message, allUpTo) {
|
|
303
|
+
const deliveryTag = message.fields.deliveryTag;
|
|
304
|
+
const channelMessage = this._broker._getMessageByDeliveryTag(this._channelQueue.name, deliveryTag);
|
|
305
|
+
const channelQ = this._channelQueue;
|
|
306
|
+
|
|
307
|
+
if (!allUpTo) this._callBroker(ackMessage);
|
|
308
|
+
else this._callBroker(ackAllUpToMessage);
|
|
309
|
+
|
|
310
|
+
function ackMessage() {
|
|
311
|
+
const msg = message[kSmqp];
|
|
312
|
+
if (!channelMessage || !msg.pending) {
|
|
313
|
+
throw new FakeAmqpUnknownDeliveryTag(message.fields.deliveryTag);
|
|
314
|
+
}
|
|
251
315
|
|
|
252
|
-
|
|
253
|
-
|
|
316
|
+
channelQ.ack(channelMessage, false);
|
|
317
|
+
this.ack(msg, false);
|
|
318
|
+
}
|
|
254
319
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
320
|
+
function ackAllUpToMessage() {
|
|
321
|
+
const msg = message[kSmqp];
|
|
322
|
+
if (!channelMessage || !msg.pending) {
|
|
323
|
+
throw new FakeAmqpUnknownDeliveryTag(message.fields.deliveryTag);
|
|
324
|
+
}
|
|
260
325
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
326
|
+
const brokerMessages = allUpToDeliveryTag(channelQ, deliveryTag, 'ack', false);
|
|
327
|
+
for (const brokerMessage of brokerMessages) {
|
|
328
|
+
brokerMessage.ack(false);
|
|
329
|
+
}
|
|
265
330
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
331
|
+
channelQ.ack(channelMessage, false);
|
|
332
|
+
this.ack(msg, false);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
ackAll() {
|
|
336
|
+
const channelQ = this._channelQueue;
|
|
337
|
+
let msg;
|
|
338
|
+
const brokerMessages = [];
|
|
339
|
+
while ((msg = channelQ.get())) {
|
|
340
|
+
brokerMessages.push(msg.content[kSmqp]);
|
|
341
|
+
msg.ack();
|
|
342
|
+
}
|
|
269
343
|
|
|
270
|
-
|
|
271
|
-
|
|
344
|
+
for (const brokerMessage of brokerMessages) {
|
|
345
|
+
brokerMessage.ack();
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
reject(message, requeue = false) {
|
|
349
|
+
const deliveryTag = message.fields.deliveryTag;
|
|
350
|
+
const channelMessage = this._broker._getMessageByDeliveryTag(this._channelQueue.name, deliveryTag);
|
|
351
|
+
const channelQ = this._channelQueue;
|
|
272
352
|
|
|
273
|
-
|
|
274
|
-
if (!result && version <= 3.2) throw new FakeAmqpNotFoundError('binding', pattern, connection._url.pathname);
|
|
353
|
+
this._callBroker(rejectMessage);
|
|
275
354
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
355
|
+
function rejectMessage() {
|
|
356
|
+
const msg = message[kSmqp];
|
|
357
|
+
if (!channelMessage || !msg.pending) {
|
|
358
|
+
throw new FakeAmqpUnknownDeliveryTag(deliveryTag);
|
|
359
|
+
}
|
|
281
360
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
361
|
+
channelQ.reject(channelMessage, false);
|
|
362
|
+
this.reject(msg, requeue);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
nack(message, allUpTo = false, requeue = false) {
|
|
366
|
+
if (this.connection._version < 2.3) throw new Error(`Nack is not implemented in versions before 2.3 (${this.connection._version})`);
|
|
285
367
|
|
|
286
|
-
|
|
287
|
-
|
|
368
|
+
const deliveryTag = message.fields.deliveryTag;
|
|
369
|
+
const channelMessage = this._broker._getMessageByDeliveryTag(this._channelQueue.name, deliveryTag);
|
|
370
|
+
const channelQ = this._channelQueue;
|
|
288
371
|
|
|
289
|
-
|
|
290
|
-
|
|
372
|
+
if (!allUpTo) this._callBroker(nackMessage);
|
|
373
|
+
else this._callBroker(nackAllUpToMessage);
|
|
291
374
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
return callBroker(check, callback);
|
|
298
|
-
|
|
299
|
-
function check() {
|
|
300
|
-
const q = queue && broker.getQueue(queue);
|
|
301
|
-
if (!q) {
|
|
302
|
-
throw new FakeAmqpNotFoundError('queue', queue, connection._url.pathname);
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
if (q.exclusive || (q.options.exclusive && q.options._connectionId !== connection._id)) {
|
|
306
|
-
throw new FakeAmqpError(`Channel closed by server: 403 (ACCESS-REFUSED) with message "ACCESS_REFUSED - queue '${queue}' in vhost '${connection._url.pathname}' in exclusive use"`, 403, true, true);
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
const {consumerTag} = broker.consume(queue, onMessage && handler, {...options, channelName, prefetch});
|
|
310
|
-
return {consumerTag};
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
function handler(_, msg) {
|
|
314
|
-
onMessage(new Message(msg));
|
|
315
|
-
}
|
|
316
|
-
},
|
|
317
|
-
cancel(consumerTag, ...args) {
|
|
318
|
-
return callBroker(broker.cancel, consumerTag, ...args);
|
|
319
|
-
},
|
|
320
|
-
close(callback) {
|
|
321
|
-
if (closed) return;
|
|
322
|
-
broker.off('return', emitReturn);
|
|
323
|
-
const channelConsumers = broker.getConsumers().filter((f) => f.options.channelName === channelName);
|
|
324
|
-
channelConsumers.forEach((c) => broker.cancel(c.consumerTag));
|
|
325
|
-
closed = true;
|
|
326
|
-
emitter.emit('close');
|
|
327
|
-
return resolveOrCallback(callback);
|
|
328
|
-
},
|
|
329
|
-
ack(message, ...args) {
|
|
330
|
-
broker.ack(message[smqpSymbol], ...args);
|
|
331
|
-
},
|
|
332
|
-
ackAll() {
|
|
333
|
-
const consumers = broker.getConsumers().filter(({options}) => options.channelName === channelName);
|
|
334
|
-
consumers.forEach((c) => broker.getConsumer(c.consumerTag).ackAll());
|
|
335
|
-
},
|
|
336
|
-
...(version >= 2.3 ? {
|
|
337
|
-
nack(message, ...args) {
|
|
338
|
-
return broker.nack(message[smqpSymbol], ...args);
|
|
339
|
-
},
|
|
340
|
-
} : undefined),
|
|
341
|
-
reject(message, ...args) {
|
|
342
|
-
broker.reject(message[smqpSymbol], ...args);
|
|
343
|
-
},
|
|
344
|
-
nackAll(requeue = false) {
|
|
345
|
-
const consumers = broker.getConsumers().filter(({options}) => options.channelName === channelName);
|
|
346
|
-
consumers.forEach((c) => broker.getConsumer(c.consumerTag).nackAll(requeue));
|
|
347
|
-
},
|
|
348
|
-
prefetch(val) {
|
|
349
|
-
prefetch = val;
|
|
350
|
-
},
|
|
351
|
-
on(...args) {
|
|
352
|
-
return emitter.on(...args);
|
|
353
|
-
},
|
|
354
|
-
once(...args) {
|
|
355
|
-
return emitter.once(...args);
|
|
356
|
-
},
|
|
357
|
-
};
|
|
375
|
+
function nackMessage() {
|
|
376
|
+
const msg = message[kSmqp];
|
|
377
|
+
if (!channelMessage || !msg.pending) {
|
|
378
|
+
throw new FakeAmqpUnknownDeliveryTag(deliveryTag);
|
|
379
|
+
}
|
|
358
380
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
function onConsumeMessage(event) {
|
|
368
|
-
if (event.properties && event.properties.confirm !== confirm) return;
|
|
369
|
-
switch(event.name) {
|
|
370
|
-
case 'message.nack':
|
|
371
|
-
case 'message.undelivered':
|
|
372
|
-
undelivered = event.name;
|
|
373
|
-
break;
|
|
374
|
-
}
|
|
381
|
+
channelQ.nack(channelMessage, false, false);
|
|
382
|
+
this.nack(msg, false, requeue);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function nackAllUpToMessage() {
|
|
386
|
+
const msg = message[kSmqp];
|
|
387
|
+
if (!channelMessage || !msg.pending) {
|
|
388
|
+
throw new FakeAmqpUnknownDeliveryTag(deliveryTag);
|
|
375
389
|
}
|
|
376
390
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
case 'message.nack':
|
|
381
|
-
return callback(new Error('message nacked'));
|
|
382
|
-
case 'message.undelivered':
|
|
383
|
-
throw callback(new Error('message undelivered'));
|
|
384
|
-
default:
|
|
385
|
-
return callback(null, true);
|
|
386
|
-
}
|
|
391
|
+
const brokerMessages = allUpToDeliveryTag(channelQ, deliveryTag, 'nack', false, false);
|
|
392
|
+
for (const brokerMessage of brokerMessages) {
|
|
393
|
+
brokerMessage.nack(false, requeue);
|
|
387
394
|
}
|
|
388
395
|
|
|
389
|
-
|
|
396
|
+
channelMessage.nack(false, false);
|
|
397
|
+
this.nack(msg, false, requeue);
|
|
390
398
|
}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
return new Promise((resolve, reject) => {
|
|
401
|
-
try {
|
|
402
|
-
const result = fn.call(broker, ...args);
|
|
403
|
-
if (poppedCb) poppedCb(null, result);
|
|
404
|
-
return resolve(result);
|
|
405
|
-
} catch (err) {
|
|
406
|
-
if (err._killConnection) connection.close();
|
|
407
|
-
else if (err._killChannel) closed = true;
|
|
408
|
-
if (!poppedCb) return reject(err);
|
|
409
|
-
poppedCb(err);
|
|
410
|
-
return resolve();
|
|
411
|
-
}
|
|
412
|
-
});
|
|
399
|
+
}
|
|
400
|
+
nackAll(requeue = true) {
|
|
401
|
+
const channelQ = this._channelQueue;
|
|
402
|
+
let msg;
|
|
403
|
+
const brokerMessages = [];
|
|
404
|
+
while ((msg = channelQ.get())) {
|
|
405
|
+
brokerMessages.push(msg.content[kSmqp]);
|
|
406
|
+
msg.reject(false);
|
|
413
407
|
}
|
|
414
408
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
emitter.emit('return', {fields, content, properties});
|
|
418
|
-
});
|
|
409
|
+
for (const brokerMessage of brokerMessages) {
|
|
410
|
+
brokerMessage.reject(requeue);
|
|
419
411
|
}
|
|
420
412
|
}
|
|
413
|
+
prefetch(val, isChannelPrefetch) {
|
|
414
|
+
if (this.connection._version < 3.3) {
|
|
415
|
+
if (isChannelPrefetch !== undefined) {
|
|
416
|
+
return this.connection.close();
|
|
417
|
+
}
|
|
418
|
+
this[kChannelPrefetch] = val;
|
|
419
|
+
} else {
|
|
420
|
+
if (isChannelPrefetch) {
|
|
421
|
+
this[kChannelPrefetch] = val;
|
|
422
|
+
} else {
|
|
423
|
+
this[kPrefetch] = val;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
_callBroker(fn, ...args) {
|
|
428
|
+
let [ poppedCb ] = args.slice(-1);
|
|
429
|
+
if (typeof poppedCb === 'function') args.splice(-1);
|
|
430
|
+
else poppedCb = null;
|
|
431
|
+
|
|
432
|
+
if (this.connection._closed) throw new FakeAmqpError('Connection is closed', 504);
|
|
433
|
+
if (this[kClosed]) throw new Error('Channel is closed');
|
|
434
|
+
|
|
435
|
+
return new Promise((resolve, reject) => {
|
|
436
|
+
try {
|
|
437
|
+
const result = fn.call(this._broker, ...args);
|
|
438
|
+
if (poppedCb) poppedCb(null, result);
|
|
439
|
+
return resolve(result);
|
|
440
|
+
} catch (err) {
|
|
441
|
+
if (err._killConnection) this.connection.close();
|
|
442
|
+
else if (err._killChannel) this._teardown();
|
|
443
|
+
if (err._emit) this.emit('error', err);
|
|
444
|
+
if (!poppedCb) return reject(err);
|
|
445
|
+
poppedCb(err);
|
|
446
|
+
return resolve();
|
|
447
|
+
}
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
_emitReturn({ fields, content, properties }) {
|
|
451
|
+
process.nextTick(() => {
|
|
452
|
+
this.emit('return', { fields, content, properties });
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
_createChannelMessage(smqpMessage, noAck) {
|
|
456
|
+
const deliveryTag = this._broker._getNextDeliveryTag();
|
|
457
|
+
const consumeMessage = new Message(smqpMessage, deliveryTag);
|
|
458
|
+
if (!noAck) {
|
|
459
|
+
const channelQ = this._channelQueue;
|
|
460
|
+
channelQ.queueMessage(consumeMessage.fields, consumeMessage);
|
|
461
|
+
}
|
|
462
|
+
return consumeMessage;
|
|
463
|
+
}
|
|
464
|
+
_teardown() {
|
|
465
|
+
this[kClosed] = true;
|
|
466
|
+
const channelName = this._channelName;
|
|
467
|
+
const broker = this._broker;
|
|
468
|
+
const channelConsumers = broker._getChannelConsumers(channelName);
|
|
469
|
+
channelConsumers.forEach((c) => broker.cancel(c.consumerTag));
|
|
470
|
+
|
|
471
|
+
let msg;
|
|
472
|
+
while ((msg = this._channelQueue.get())) {
|
|
473
|
+
msg.content[kSmqp].reject(true);
|
|
474
|
+
msg.reject(false);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
broker.off('return', this._emitReturn);
|
|
478
|
+
}
|
|
479
|
+
_calculateChannelCapacity(consumerCapacity) {
|
|
480
|
+
const channelPrefetch = this[kChannelPrefetch];
|
|
481
|
+
if (channelPrefetch === Infinity) return consumerCapacity;
|
|
482
|
+
|
|
483
|
+
const channelCapacity = channelPrefetch - this._channelQueue.messageCount;
|
|
484
|
+
|
|
485
|
+
let capacity = consumerCapacity;
|
|
486
|
+
if (channelCapacity <= 0) capacity = 0;
|
|
487
|
+
else if (channelCapacity < capacity) capacity = channelCapacity;
|
|
488
|
+
return capacity;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
export class FakeAmqplibConfirmChannel extends FakeAmqplibChannel {
|
|
493
|
+
publish(exchange, routingKey, content, options, callback) {
|
|
494
|
+
if (!Buffer.isBuffer(content)) throw new TypeError('content is not a buffer');
|
|
495
|
+
if (exchange === '') return this.sendToQueue(routingKey, content, options, callback);
|
|
496
|
+
|
|
497
|
+
const args = [ this._broker.publish, exchange, routingKey, content ];
|
|
498
|
+
|
|
499
|
+
args.push(...addConfirmCallback(this._broker, options, callback));
|
|
500
|
+
|
|
501
|
+
this.checkExchange(exchange).then(() => {
|
|
502
|
+
return this._callBroker(...args);
|
|
503
|
+
}).catch((err) => {
|
|
504
|
+
this.emit('error', err);
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
return true;
|
|
508
|
+
}
|
|
509
|
+
sendToQueue(queue, content, options, callback) {
|
|
510
|
+
if (!Buffer.isBuffer(content)) throw new TypeError('content is not a buffer');
|
|
511
|
+
|
|
512
|
+
const args = [ this._broker.sendToQueue, queue, content ];
|
|
513
|
+
|
|
514
|
+
args.push(...addConfirmCallback(this._broker, options, callback));
|
|
515
|
+
|
|
516
|
+
this.checkQueue(queue).then(() => {
|
|
517
|
+
return this._callBroker(...args);
|
|
518
|
+
}).catch((err) => {
|
|
519
|
+
this.emit('error', err);
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
return true;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
export class FakeAmqplibConnection extends EventEmitter {
|
|
527
|
+
constructor(broker, version, amqpUrl) {
|
|
528
|
+
super();
|
|
529
|
+
this[kClosed] = false;
|
|
530
|
+
this._channels = [];
|
|
531
|
+
this._url = normalizeAmqpUrl(amqpUrl);
|
|
532
|
+
this._id = generateId();
|
|
533
|
+
this._broker = broker;
|
|
534
|
+
this._version = version;
|
|
535
|
+
}
|
|
536
|
+
get _closed() {
|
|
537
|
+
return this[kClosed];
|
|
538
|
+
}
|
|
539
|
+
get connection() {
|
|
540
|
+
return {
|
|
541
|
+
serverProperties: {
|
|
542
|
+
host: this._url.host,
|
|
543
|
+
product: 'RabbitMQ',
|
|
544
|
+
version: `${this._version.toString()}.0`,
|
|
545
|
+
platform: 'OS',
|
|
546
|
+
copyright: 'MIT',
|
|
547
|
+
information: 'fake',
|
|
548
|
+
},
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
createChannel(...args) {
|
|
552
|
+
const callback = args.slice(-1)[0];
|
|
553
|
+
if (this[kClosed]) return resolveOrCallback(callback, new FakeAmqpError('Connection closed: 504', 504));
|
|
554
|
+
|
|
555
|
+
const channel = new FakeAmqplibChannel(this._broker, this);
|
|
556
|
+
this._channels.push(channel);
|
|
557
|
+
return resolveOrCallback(callback, null, channel);
|
|
558
|
+
}
|
|
559
|
+
createConfirmChannel(...args) {
|
|
560
|
+
if (this[kClosed]) return resolveOrCallback(args.slice(-1)[0], new FakeAmqpError('Connection closed: 504', 504));
|
|
561
|
+
|
|
562
|
+
const channel = new FakeAmqplibConfirmChannel(this._broker, this);
|
|
563
|
+
this._channels.push(channel);
|
|
564
|
+
return resolveOrCallback(args.slice(-1)[0], null, channel);
|
|
565
|
+
}
|
|
566
|
+
close(...args) {
|
|
567
|
+
if (this[kClosed]) return resolveOrCallback(args.slice(-1)[0]);
|
|
568
|
+
this[kClosed] = true;
|
|
569
|
+
|
|
570
|
+
this._channels.splice(0).forEach((channel) => channel.close());
|
|
571
|
+
|
|
572
|
+
this.emit('close');
|
|
573
|
+
|
|
574
|
+
return resolveOrCallback(args.slice(-1)[0]);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
export function FakeAmqplib(minorVersion = '3.5') {
|
|
579
|
+
if (!(this instanceof FakeAmqplib)) {
|
|
580
|
+
return new FakeAmqplib(minorVersion);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
this.version = Number(minorVersion);
|
|
584
|
+
this.connections = [];
|
|
585
|
+
|
|
586
|
+
this.connect = this.connect.bind(this);
|
|
587
|
+
this.connectSync = this.connectSync.bind(this);
|
|
588
|
+
this.resetMock = this.resetMock.bind(this);
|
|
589
|
+
this.setVersion = this.setVersion.bind(this);
|
|
421
590
|
}
|
|
422
591
|
|
|
592
|
+
FakeAmqplib.prototype.connect = function fakeConnect(amqpUrl, ...args) {
|
|
593
|
+
const connection = this.connectSync(amqpUrl, ...args);
|
|
594
|
+
return resolveOrCallback(args.slice(-1)[0], null, connection);
|
|
595
|
+
};
|
|
596
|
+
|
|
597
|
+
FakeAmqplib.prototype.connectSync = function fakeConnectSync(amqpUrl, ...args) {
|
|
598
|
+
const { _broker } = this.connections.find((conn) => compareConnectionString(conn._url, amqpUrl)) || {};
|
|
599
|
+
const broker = _broker || new AmqplibBroker(this);
|
|
600
|
+
const connection = new FakeAmqplibConnection(broker, this.version, amqpUrl, ...args);
|
|
601
|
+
|
|
602
|
+
const connections = this.connections;
|
|
603
|
+
|
|
604
|
+
connections.push(connection);
|
|
605
|
+
|
|
606
|
+
connection.once('close', () => {
|
|
607
|
+
const idx = connections.indexOf(connection);
|
|
608
|
+
if (idx > -1) connections.splice(idx, 1);
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
return connection;
|
|
612
|
+
};
|
|
613
|
+
|
|
614
|
+
FakeAmqplib.prototype.resetMock = function fakeResetMock() {
|
|
615
|
+
for (const connection of this.connections.splice(0)) {
|
|
616
|
+
connection._broker.reset();
|
|
617
|
+
}
|
|
618
|
+
};
|
|
619
|
+
|
|
620
|
+
FakeAmqplib.prototype.setVersion = function fakeSetVersion(minorVersion) {
|
|
621
|
+
const n = Number(minorVersion);
|
|
622
|
+
if (!isNaN(n)) this.version = n;
|
|
623
|
+
};
|
|
624
|
+
|
|
423
625
|
function resolveOrCallback(optionalCb, err, ...args) {
|
|
424
626
|
if (typeof optionalCb === 'function') optionalCb(err, ...args);
|
|
425
627
|
if (err) return Promise.reject(err);
|
|
@@ -437,15 +639,8 @@ function compareConnectionString(url1, url2) {
|
|
|
437
639
|
return parsedUrl1.host === parsedUrl2.host && parsedUrl1.pathname === parsedUrl2.pathname;
|
|
438
640
|
}
|
|
439
641
|
|
|
440
|
-
function Message(smqpMessage) {
|
|
441
|
-
this[smqpSymbol] = smqpMessage;
|
|
442
|
-
this.content = smqpMessage.content;
|
|
443
|
-
this.fields = smqpMessage.fields;
|
|
444
|
-
this.properties = smqpMessage.properties;
|
|
445
|
-
}
|
|
446
|
-
|
|
447
642
|
function normalizeAmqpUrl(url) {
|
|
448
|
-
if (!url) return
|
|
643
|
+
if (!url) return new URL('amqp://localhost:5672/');
|
|
449
644
|
if (typeof url === 'string') url = new URL(url);
|
|
450
645
|
|
|
451
646
|
if (!(url instanceof URL)) {
|
|
@@ -460,7 +655,7 @@ function normalizeAmqpUrl(url) {
|
|
|
460
655
|
} = url;
|
|
461
656
|
let auth = username;
|
|
462
657
|
if (auth && password) {
|
|
463
|
-
auth +=
|
|
658
|
+
auth += `:${password}`;
|
|
464
659
|
}
|
|
465
660
|
url = new URL(urlFormat({
|
|
466
661
|
protocol,
|
|
@@ -486,3 +681,71 @@ function normalizeAmqpUrl(url) {
|
|
|
486
681
|
if (!url.pathname) url.pathname = '/';
|
|
487
682
|
return url;
|
|
488
683
|
}
|
|
684
|
+
|
|
685
|
+
function addConfirmCallback(broker, options, callback) {
|
|
686
|
+
const confirm = `msg.${generateId()}`;
|
|
687
|
+
const consumerTag = `ct-${confirm}`;
|
|
688
|
+
options = { ...options, confirm };
|
|
689
|
+
|
|
690
|
+
broker.on('message.*', onConsumeMessage, { consumerTag });
|
|
691
|
+
|
|
692
|
+
let undelivered;
|
|
693
|
+
function onConsumeMessage(event) {
|
|
694
|
+
switch (event.name) {
|
|
695
|
+
case 'message.nack':
|
|
696
|
+
case 'message.undelivered':
|
|
697
|
+
undelivered = event.name;
|
|
698
|
+
break;
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
function confirmCallback() {
|
|
703
|
+
broker.off('message.*', consumerTag);
|
|
704
|
+
switch (undelivered) {
|
|
705
|
+
case 'message.nack':
|
|
706
|
+
return callback(new Error('message nacked'));
|
|
707
|
+
case 'message.undelivered':
|
|
708
|
+
throw callback(new Error('message undelivered'));
|
|
709
|
+
default:
|
|
710
|
+
return callback(null, true);
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
return [ options, confirmCallback ];
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
function allUpToDeliveryTag(q, deliveryTag, op, ...args) {
|
|
718
|
+
const brokerMessages = [];
|
|
719
|
+
|
|
720
|
+
const consumer = q.consume((_, cmsg) => {
|
|
721
|
+
const msgDeliveryTag = cmsg.fields.deliveryTag;
|
|
722
|
+
if (msgDeliveryTag >= deliveryTag) {
|
|
723
|
+
return q.cancel(cmsg.fields.consumerTag);
|
|
724
|
+
}
|
|
725
|
+
brokerMessages.push(cmsg.content[kSmqp]);
|
|
726
|
+
cmsg[op](...args);
|
|
727
|
+
}, { prefetch: Infinity });
|
|
728
|
+
|
|
729
|
+
consumer.cancel();
|
|
730
|
+
|
|
731
|
+
return brokerMessages;
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
const defaultFake = new FakeAmqplib('3.5');
|
|
735
|
+
export const connections = defaultFake.connections;
|
|
736
|
+
|
|
737
|
+
export function connect(amqpUrl, ...args) {
|
|
738
|
+
return defaultFake.connect(amqpUrl, ...args);
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
export function connectSync(amqpUrl, ...args) {
|
|
742
|
+
return defaultFake.connectSync(amqpUrl, ...args);
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
export function resetMock() {
|
|
746
|
+
return defaultFake.resetMock();
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
export function setVersion(minorVersion) {
|
|
750
|
+
return defaultFake.setVersion(minorVersion);
|
|
751
|
+
}
|