amqplib 2.2.0 → 2.3.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/CHANGELOG.md +12 -0
- package/callback_api.d.ts +2 -2
- package/index.d.ts +1 -1
- package/lib/callback_model.js +3 -22
- package/lib/channel.js +27 -1
- package/lib/channel_model.js +4 -29
- package/lib/connect.js +8 -0
- package/lib/connection.js +25 -1
- package/lib/frame.js +5 -1
- package/lib/properties.d.ts +4 -0
- package/package.json +12 -2
- package/.claude/commands/lint-disable.md +0 -9
- package/.claude/commands/lint-enable.md +0 -12
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -41
- package/.github/workflows/publish.yml +0 -113
- package/.github/workflows/test.yml +0 -54
- package/CLAUDE.md +0 -12
- package/Makefile +0 -42
- package/bin/amqp-rabbitmq-0.9.1.json +0 -483
- package/bin/generate-defs.js +0 -734
- package/biome.json +0 -51
- package/lefthook.yml +0 -17
- package/test/bitset.test.js +0 -65
- package/test/callback_api.test.js +0 -439
- package/test/channel.test.js +0 -918
- package/test/channel_api.test.js +0 -599
- package/test/codec.test.js +0 -171
- package/test/connect.test.js +0 -155
- package/test/connection.test.js +0 -772
- package/test/data.test.js +0 -33
- package/test/frame.test.js +0 -180
- package/test/lib/data.js +0 -249
- package/test/lib/util.js +0 -223
- package/test/mux.test.js +0 -258
- package/test/recovery.test.js +0 -799
- package/test/uri_spec.test.js +0 -210
package/bin/generate-defs.js
DELETED
|
@@ -1,734 +0,0 @@
|
|
|
1
|
-
const format = require('node:util').format;
|
|
2
|
-
|
|
3
|
-
const defs = require('./amqp-rabbitmq-0.9.1.json');
|
|
4
|
-
|
|
5
|
-
const FRAME_OVERHEAD = 8; // type + channel + size + frame-end
|
|
6
|
-
|
|
7
|
-
const METHOD_OVERHEAD = FRAME_OVERHEAD + 4;
|
|
8
|
-
// F_O + classId + methodId
|
|
9
|
-
|
|
10
|
-
const PROPERTIES_OVERHEAD = FRAME_OVERHEAD + 4 + 8 + 2;
|
|
11
|
-
// F_O + classId + weight + content size + flags
|
|
12
|
-
|
|
13
|
-
const out = process.stdout;
|
|
14
|
-
|
|
15
|
-
function printf(...args) {
|
|
16
|
-
out.write(format.apply(format, args), 'utf8');
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function nl() {
|
|
20
|
-
out.write('\n');
|
|
21
|
-
}
|
|
22
|
-
function println(...args) {
|
|
23
|
-
printf.apply(printf, args);
|
|
24
|
-
nl();
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const constants = {};
|
|
28
|
-
const constant_strs = {};
|
|
29
|
-
|
|
30
|
-
for (let i = 0, len = defs.constants.length; i < len; i++) {
|
|
31
|
-
const cdef = defs.constants[i];
|
|
32
|
-
constants[constantName(cdef)] = cdef.value;
|
|
33
|
-
constant_strs[cdef.value] = cdef.name;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function constantName(def) {
|
|
37
|
-
return def.name.replace(/-/g, '_');
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function methodName(clazz, method) {
|
|
41
|
-
return initial(clazz.name) + method.name.split('-').map(initial).join('');
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function propertyName(dashed) {
|
|
45
|
-
const parts = dashed.split('-');
|
|
46
|
-
return parts[0] + parts.slice(1).map(initial).join('');
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function initial(part) {
|
|
50
|
-
return part.charAt(0).toUpperCase() + part.substr(1);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function argument(a) {
|
|
54
|
-
const type = a.type || domains[a.domain];
|
|
55
|
-
const friendlyName = propertyName(a.name);
|
|
56
|
-
return { type: type, name: friendlyName, default: a['default-value'] };
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const domains = {};
|
|
60
|
-
for (let i = 0, len = defs.domains.length; i < len; i++) {
|
|
61
|
-
const dom = defs.domains[i];
|
|
62
|
-
domains[dom[0]] = dom[1];
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const methods = {};
|
|
66
|
-
const propertieses = {};
|
|
67
|
-
|
|
68
|
-
for (let i = 0, len = defs.classes.length; i < len; i++) {
|
|
69
|
-
const clazz = defs.classes[i];
|
|
70
|
-
for (let j = 0, num = clazz.methods.length; j < num; j++) {
|
|
71
|
-
const method = clazz.methods[j];
|
|
72
|
-
const name = methodName(clazz, method);
|
|
73
|
-
const info = `methodInfo${name}`;
|
|
74
|
-
|
|
75
|
-
methods[name] = {
|
|
76
|
-
id: methodId(clazz, method),
|
|
77
|
-
name: name,
|
|
78
|
-
methodId: method.id,
|
|
79
|
-
clazzId: clazz.id,
|
|
80
|
-
clazz: clazz.name,
|
|
81
|
-
args: method['arguments'].map(argument),
|
|
82
|
-
isReply: method.answer,
|
|
83
|
-
encoder: `encode${name}`,
|
|
84
|
-
decoder: `decode${name}`,
|
|
85
|
-
info: info,
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
if (clazz.properties && clazz.properties.length > 0) {
|
|
89
|
-
const name = propertiesName(clazz);
|
|
90
|
-
const props = clazz.properties;
|
|
91
|
-
propertieses[name] = {
|
|
92
|
-
id: clazz.id,
|
|
93
|
-
name: name,
|
|
94
|
-
encoder: `encode${name}`,
|
|
95
|
-
decoder: `decode${name}`,
|
|
96
|
-
info: `propertiesInfo${name}`,
|
|
97
|
-
args: props.map(argument),
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// OK let's get emitting
|
|
103
|
-
|
|
104
|
-
println(
|
|
105
|
-
'/** @preserve This file is generated by the script\n',
|
|
106
|
-
'* ../bin/generate-defs.js, which is not in general included in a\n',
|
|
107
|
-
'* distribution, but is available in the source repository e.g. at\n',
|
|
108
|
-
'* https://github.com/amqp-node/amqplib/\n',
|
|
109
|
-
'*/',
|
|
110
|
-
);
|
|
111
|
-
|
|
112
|
-
println("'use strict';");
|
|
113
|
-
nl();
|
|
114
|
-
nl();
|
|
115
|
-
println('var codec = require("./codec");');
|
|
116
|
-
println('var encodeTable = codec.encodeTable;');
|
|
117
|
-
println('var decodeFields = codec.decodeFields;');
|
|
118
|
-
nl();
|
|
119
|
-
|
|
120
|
-
println('var SCRATCH = Buffer.alloc(65536);');
|
|
121
|
-
println('var EMPTY_OBJECT = Object.freeze({});');
|
|
122
|
-
|
|
123
|
-
println('module.exports.constants = %s', JSON.stringify(constants));
|
|
124
|
-
nl();
|
|
125
|
-
println('module.exports.constant_strs = %s', JSON.stringify(constant_strs));
|
|
126
|
-
nl();
|
|
127
|
-
println('module.exports.FRAME_OVERHEAD = %d;', FRAME_OVERHEAD);
|
|
128
|
-
nl();
|
|
129
|
-
|
|
130
|
-
println('module.exports.decode = function(id, buf) {');
|
|
131
|
-
println('switch (id) {');
|
|
132
|
-
for (const m in methods) {
|
|
133
|
-
const method = methods[m];
|
|
134
|
-
println('case %d: return %s(buf);', method.id, method.decoder);
|
|
135
|
-
}
|
|
136
|
-
for (const p in propertieses) {
|
|
137
|
-
const props = propertieses[p];
|
|
138
|
-
println('case %d: return %s(buf);', props.id, props.decoder);
|
|
139
|
-
}
|
|
140
|
-
println('default: throw new Error("Unknown class/method ID");');
|
|
141
|
-
println('}}');
|
|
142
|
-
nl();
|
|
143
|
-
|
|
144
|
-
println('module.exports.encodeMethod =', 'function(id, channel, fields) {');
|
|
145
|
-
println('switch (id) {');
|
|
146
|
-
for (const m in methods) {
|
|
147
|
-
const method = methods[m];
|
|
148
|
-
println('case %d: return %s(channel, fields);', method.id, method.encoder);
|
|
149
|
-
}
|
|
150
|
-
println('default: throw new Error("Unknown class/method ID");');
|
|
151
|
-
println('}}');
|
|
152
|
-
nl();
|
|
153
|
-
|
|
154
|
-
println('module.exports.encodeProperties =', 'function(id, channel, size, fields) {');
|
|
155
|
-
println('switch (id) {');
|
|
156
|
-
for (const p in propertieses) {
|
|
157
|
-
const props = propertieses[p];
|
|
158
|
-
println('case %d: return %s(channel, size, fields);', props.id, props.encoder);
|
|
159
|
-
}
|
|
160
|
-
println('default: throw new Error("Unknown class/properties ID");');
|
|
161
|
-
println('}}');
|
|
162
|
-
nl();
|
|
163
|
-
|
|
164
|
-
println('module.exports.info = function(id) {');
|
|
165
|
-
println('switch(id) {');
|
|
166
|
-
for (const m in methods) {
|
|
167
|
-
const method = methods[m];
|
|
168
|
-
println('case %d: return %s; ', method.id, method.info);
|
|
169
|
-
}
|
|
170
|
-
for (const p in propertieses) {
|
|
171
|
-
const properties = propertieses[p];
|
|
172
|
-
println('case %d: return %s', properties.id, properties.info);
|
|
173
|
-
}
|
|
174
|
-
println('default: throw new Error("Unknown class/method ID");');
|
|
175
|
-
println('}}');
|
|
176
|
-
nl();
|
|
177
|
-
|
|
178
|
-
for (const m in methods) {
|
|
179
|
-
const method = methods[m];
|
|
180
|
-
println('module.exports.%s = %d;', m, method.id);
|
|
181
|
-
decoderFn(method);
|
|
182
|
-
nl();
|
|
183
|
-
encoderFn(method);
|
|
184
|
-
nl();
|
|
185
|
-
infoObj(method);
|
|
186
|
-
nl();
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
for (const p in propertieses) {
|
|
190
|
-
const properties = propertieses[p];
|
|
191
|
-
println('module.exports.%s = %d;', p, properties.id);
|
|
192
|
-
encodePropsFn(properties);
|
|
193
|
-
nl();
|
|
194
|
-
decodePropsFn(properties);
|
|
195
|
-
nl();
|
|
196
|
-
infoObj(properties);
|
|
197
|
-
nl();
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
function methodId(clazz, method) {
|
|
201
|
-
return (clazz.id << 16) + method.id;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
function propertiesName(clazz) {
|
|
205
|
-
return `${initial(clazz.name)}Properties`;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
function valTypeTest(arg) {
|
|
209
|
-
switch (arg.type) {
|
|
210
|
-
// everything is booleany
|
|
211
|
-
case 'bit':
|
|
212
|
-
return 'true';
|
|
213
|
-
case 'octet':
|
|
214
|
-
case 'short':
|
|
215
|
-
case 'long':
|
|
216
|
-
case 'longlong':
|
|
217
|
-
case 'timestamp':
|
|
218
|
-
return "typeof val === 'number' && !isNaN(val)";
|
|
219
|
-
case 'shortstr':
|
|
220
|
-
return "typeof val === 'string' &&" + ' Buffer.byteLength(val) < 256';
|
|
221
|
-
case 'longstr':
|
|
222
|
-
return 'Buffer.isBuffer(val)';
|
|
223
|
-
case 'table':
|
|
224
|
-
return "typeof val === 'object'";
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
function typeDesc(t) {
|
|
229
|
-
switch (t) {
|
|
230
|
-
case 'bit':
|
|
231
|
-
return 'booleany';
|
|
232
|
-
case 'octet':
|
|
233
|
-
case 'short':
|
|
234
|
-
case 'long':
|
|
235
|
-
case 'longlong':
|
|
236
|
-
case 'timestamp':
|
|
237
|
-
return 'a number (but not NaN)';
|
|
238
|
-
case 'shortstr':
|
|
239
|
-
return 'a string (up to 255 chars)';
|
|
240
|
-
case 'longstr':
|
|
241
|
-
return 'a Buffer';
|
|
242
|
-
case 'table':
|
|
243
|
-
return 'an object';
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
function defaultValueRepr(arg) {
|
|
248
|
-
switch (arg.type) {
|
|
249
|
-
case 'longstr':
|
|
250
|
-
return format('Buffer.from(%s)', JSON.stringify(arg.default));
|
|
251
|
-
default:
|
|
252
|
-
// assumes no tables as defaults
|
|
253
|
-
return JSON.stringify(arg.default);
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// Emit code to assign the arg value to `val`.
|
|
258
|
-
function assignArg(a) {
|
|
259
|
-
println("val = fields['%s'];", a.name);
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
function assignOrDefault(a) {
|
|
263
|
-
println("val = fields['%s'];", a.name);
|
|
264
|
-
println('if (val === undefined) val = %s;', defaultValueRepr(a));
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
// Emit code for assigning an argument value to `val`, checking that
|
|
268
|
-
// it exists (if it does not have a default) and is the correct
|
|
269
|
-
// type.
|
|
270
|
-
function checkAssignArg(a) {
|
|
271
|
-
assignArg(a);
|
|
272
|
-
println('if (val === undefined) {');
|
|
273
|
-
if (a.default !== undefined) {
|
|
274
|
-
println('val = %s;', defaultValueRepr(a));
|
|
275
|
-
} else {
|
|
276
|
-
println('throw new Error("Missing value for mandatory field \'%s\'");', a.name);
|
|
277
|
-
}
|
|
278
|
-
println('}'); // undefined test
|
|
279
|
-
println('else if (!(%s)) {', valTypeTest(a));
|
|
280
|
-
println('throw new TypeError(');
|
|
281
|
-
println('"Field \'%s\' is the wrong type; must be %s");', a.name, typeDesc(a.type));
|
|
282
|
-
println('}'); // type test
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// Emit code for encoding `val` as a table and assign to a fresh
|
|
286
|
-
// variable (based on the arg name). I use a scratch buffer to compose
|
|
287
|
-
// the encoded table, otherwise I'd have to do a size calculation pass
|
|
288
|
-
// first. I can get away with this only because 1. the encoding
|
|
289
|
-
// procedures are not re-entrant; and, 2. I copy the result into
|
|
290
|
-
// another buffer before returning. `scratchOffset`, `val`, `len` are
|
|
291
|
-
// expected to have been declared.
|
|
292
|
-
function assignTable(a) {
|
|
293
|
-
const varname = tableVar(a);
|
|
294
|
-
println('len = encodeTable(SCRATCH, val, scratchOffset);');
|
|
295
|
-
println('var %s = SCRATCH.slice(scratchOffset, scratchOffset + len);', varname);
|
|
296
|
-
println('scratchOffset += len;');
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
function tableVar(a) {
|
|
300
|
-
return `${a.name}_encoded`;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
function stringLenVar(a) {
|
|
304
|
-
return `${a.name}_len`;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
function assignStringLen(a) {
|
|
308
|
-
const v = stringLenVar(a);
|
|
309
|
-
// Assumes the value or default is in val
|
|
310
|
-
println("var %s = Buffer.byteLength(val, 'utf8');", v);
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
function encoderFn(method) {
|
|
314
|
-
const args = method['args'];
|
|
315
|
-
println('function %s(channel, fields) {', method.encoder);
|
|
316
|
-
println('var offset = 0, val = null, bits = 0, varyingSize = 0;');
|
|
317
|
-
println('var len, scratchOffset = 0;');
|
|
318
|
-
|
|
319
|
-
// Encoding is split into two parts. Some fields have a fixed size
|
|
320
|
-
// (e.g., integers of a specific width), while some have a size that
|
|
321
|
-
// depends on the datum (e.g., strings). Each field will therefore
|
|
322
|
-
// either 1. contribute to the fixed size; or 2. emit code to
|
|
323
|
-
// calculate the size (and possibly the encoded value, in the case
|
|
324
|
-
// of tables).
|
|
325
|
-
let fixedSize = METHOD_OVERHEAD;
|
|
326
|
-
|
|
327
|
-
let bitsInARow = 0;
|
|
328
|
-
|
|
329
|
-
for (let i = 0, len = args.length; i < len; i++) {
|
|
330
|
-
const arg = args[i];
|
|
331
|
-
|
|
332
|
-
if (arg.type !== 'bit') bitsInARow = 0;
|
|
333
|
-
|
|
334
|
-
switch (arg.type) {
|
|
335
|
-
// varying size
|
|
336
|
-
case 'shortstr':
|
|
337
|
-
checkAssignArg(arg);
|
|
338
|
-
assignStringLen(arg);
|
|
339
|
-
println('varyingSize += %s;', stringLenVar(arg));
|
|
340
|
-
fixedSize += 1;
|
|
341
|
-
break;
|
|
342
|
-
case 'longstr':
|
|
343
|
-
checkAssignArg(arg);
|
|
344
|
-
println('varyingSize += val.length;');
|
|
345
|
-
fixedSize += 4;
|
|
346
|
-
break;
|
|
347
|
-
case 'table':
|
|
348
|
-
// For a table we have to encode the table before we can see its
|
|
349
|
-
// length.
|
|
350
|
-
checkAssignArg(arg);
|
|
351
|
-
assignTable(arg);
|
|
352
|
-
println('varyingSize += %s.length;', tableVar(arg));
|
|
353
|
-
break;
|
|
354
|
-
|
|
355
|
-
// fixed size
|
|
356
|
-
case 'octet':
|
|
357
|
-
fixedSize += 1;
|
|
358
|
-
break;
|
|
359
|
-
case 'short':
|
|
360
|
-
fixedSize += 2;
|
|
361
|
-
break;
|
|
362
|
-
case 'long':
|
|
363
|
-
fixedSize += 4;
|
|
364
|
-
break;
|
|
365
|
-
case 'longlong': //fall through
|
|
366
|
-
case 'timestamp':
|
|
367
|
-
fixedSize += 8;
|
|
368
|
-
break;
|
|
369
|
-
case 'bit':
|
|
370
|
-
bitsInARow++;
|
|
371
|
-
// open a fresh pack o' bits
|
|
372
|
-
if (bitsInARow === 1) fixedSize += 1;
|
|
373
|
-
// just used a pack; reset
|
|
374
|
-
else if (bitsInARow === 8) bitsInARow = 0;
|
|
375
|
-
break;
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
println('var buffer = Buffer.alloc(%d + varyingSize);', fixedSize);
|
|
380
|
-
|
|
381
|
-
println('buffer[0] = %d;', constants.FRAME_METHOD);
|
|
382
|
-
println('buffer.writeUInt16BE(channel, 1);');
|
|
383
|
-
// skip size for now, we'll write it in when we know
|
|
384
|
-
println('buffer.writeUInt32BE(%d, 7);', method.id);
|
|
385
|
-
println('offset = 11;');
|
|
386
|
-
|
|
387
|
-
bitsInARow = 0;
|
|
388
|
-
|
|
389
|
-
for (let i = 0, len = args.length; i < len; i++) {
|
|
390
|
-
const a = args[i];
|
|
391
|
-
|
|
392
|
-
// Flush any collected bits before doing a new field
|
|
393
|
-
if (a.type !== 'bit' && bitsInARow > 0) {
|
|
394
|
-
bitsInARow = 0;
|
|
395
|
-
println('buffer[offset] = bits; offset++; bits = 0;');
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
switch (a.type) {
|
|
399
|
-
case 'octet':
|
|
400
|
-
checkAssignArg(a);
|
|
401
|
-
println('buffer.writeUInt8(val, offset); offset++;');
|
|
402
|
-
break;
|
|
403
|
-
case 'short':
|
|
404
|
-
checkAssignArg(a);
|
|
405
|
-
println('buffer.writeUInt16BE(val, offset); offset += 2;');
|
|
406
|
-
break;
|
|
407
|
-
case 'long':
|
|
408
|
-
checkAssignArg(a);
|
|
409
|
-
println('buffer.writeUInt32BE(val, offset); offset += 4;');
|
|
410
|
-
break;
|
|
411
|
-
case 'longlong':
|
|
412
|
-
case 'timestamp':
|
|
413
|
-
checkAssignArg(a);
|
|
414
|
-
println('buffer.writeBigUInt64BE(BigInt(val), offset); offset += 8;');
|
|
415
|
-
break;
|
|
416
|
-
case 'bit':
|
|
417
|
-
checkAssignArg(a);
|
|
418
|
-
println('if (val) bits += %d;', 1 << bitsInARow);
|
|
419
|
-
if (bitsInARow === 7) {
|
|
420
|
-
// I don't think this ever happens, but whatever
|
|
421
|
-
println('buffer[offset] = bits; offset++; bits = 0;');
|
|
422
|
-
bitsInARow = 0;
|
|
423
|
-
} else bitsInARow++;
|
|
424
|
-
break;
|
|
425
|
-
case 'shortstr':
|
|
426
|
-
assignOrDefault(a);
|
|
427
|
-
println('buffer[offset] = %s; offset++;', stringLenVar(a));
|
|
428
|
-
println('buffer.write(val, offset, "utf8"); offset += %s;', stringLenVar(a));
|
|
429
|
-
break;
|
|
430
|
-
case 'longstr':
|
|
431
|
-
assignOrDefault(a);
|
|
432
|
-
println('len = val.length;');
|
|
433
|
-
println('buffer.writeUInt32BE(len, offset); offset += 4;');
|
|
434
|
-
println('val.copy(buffer, offset); offset += len;');
|
|
435
|
-
break;
|
|
436
|
-
case 'table':
|
|
437
|
-
println('offset += %s.copy(buffer, offset);', tableVar(a));
|
|
438
|
-
break;
|
|
439
|
-
default:
|
|
440
|
-
throw new Error(`Unexpected argument type: ${a.type}`);
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
// Flush any collected bits at the end
|
|
445
|
-
if (bitsInARow > 0) {
|
|
446
|
-
println('buffer[offset] = bits; offset++;');
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
println('buffer[offset] = %d;', constants.FRAME_END);
|
|
450
|
-
// size does not include the frame header or frame end byte
|
|
451
|
-
println('buffer.writeUInt32BE(offset - 7, 3);');
|
|
452
|
-
|
|
453
|
-
println('return buffer;');
|
|
454
|
-
println('}');
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
function fieldsDecl(args) {
|
|
458
|
-
println('var fields = {');
|
|
459
|
-
for (let i = 0, num = args.length; i < num; i++) {
|
|
460
|
-
println('%s: undefined,', args[i].name);
|
|
461
|
-
}
|
|
462
|
-
println('};');
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
function decoderFn(method) {
|
|
466
|
-
const args = method.args;
|
|
467
|
-
println('function %s(buffer) {', method.decoder);
|
|
468
|
-
println('var offset = 0, val, len;');
|
|
469
|
-
fieldsDecl(args);
|
|
470
|
-
|
|
471
|
-
let bitsInARow = 0;
|
|
472
|
-
|
|
473
|
-
for (let i = 0, num = args.length; i < num; i++) {
|
|
474
|
-
const a = args[i];
|
|
475
|
-
const field = `fields['${a.name}']`;
|
|
476
|
-
|
|
477
|
-
// Flush any collected bits before doing a new field
|
|
478
|
-
if (a.type !== 'bit' && bitsInARow > 0) {
|
|
479
|
-
bitsInARow = 0;
|
|
480
|
-
println('offset++;');
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
switch (a.type) {
|
|
484
|
-
case 'octet':
|
|
485
|
-
println('val = buffer[offset]; offset++;');
|
|
486
|
-
break;
|
|
487
|
-
case 'short':
|
|
488
|
-
println('val = buffer.readUInt16BE(offset); offset += 2;');
|
|
489
|
-
break;
|
|
490
|
-
case 'long':
|
|
491
|
-
println('val = buffer.readUInt32BE(offset); offset += 4;');
|
|
492
|
-
break;
|
|
493
|
-
case 'longlong':
|
|
494
|
-
case 'timestamp':
|
|
495
|
-
println('val = Number(buffer.readBigUInt64BE(offset)); offset += 8;');
|
|
496
|
-
break;
|
|
497
|
-
case 'bit': {
|
|
498
|
-
const bit = 1 << bitsInARow;
|
|
499
|
-
println('val = !!(buffer[offset] & %d);', bit);
|
|
500
|
-
if (bitsInARow === 7) {
|
|
501
|
-
println('offset++;');
|
|
502
|
-
bitsInARow = 0;
|
|
503
|
-
} else bitsInARow++;
|
|
504
|
-
break;
|
|
505
|
-
}
|
|
506
|
-
case 'longstr':
|
|
507
|
-
println('len = buffer.readUInt32BE(offset); offset += 4;');
|
|
508
|
-
println('val = buffer.subarray(offset, offset + len);');
|
|
509
|
-
println('offset += len;');
|
|
510
|
-
break;
|
|
511
|
-
case 'shortstr':
|
|
512
|
-
println('len = buffer.readUInt8(offset); offset++;');
|
|
513
|
-
println('val = buffer.toString("utf8", offset, offset + len);');
|
|
514
|
-
println('offset += len;');
|
|
515
|
-
break;
|
|
516
|
-
case 'table':
|
|
517
|
-
println('len = buffer.readUInt32BE(offset); offset += 4;');
|
|
518
|
-
println('val = decodeFields(buffer.subarray(offset, offset + len));');
|
|
519
|
-
println('offset += len;');
|
|
520
|
-
break;
|
|
521
|
-
default:
|
|
522
|
-
throw new TypeError(`Unexpected type in argument list: ${a.type}`);
|
|
523
|
-
}
|
|
524
|
-
println('%s = val;', field);
|
|
525
|
-
}
|
|
526
|
-
println('return fields;');
|
|
527
|
-
println('}');
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
function infoObj(thing) {
|
|
531
|
-
const info = JSON.stringify({ id: thing.id, classId: thing.clazzId, methodId: thing.methodId, name: thing.name, args: thing.args });
|
|
532
|
-
println('var %s = module.exports.%s = %s;', thing.info, thing.info, info);
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
// The flags are laid out in groups of fifteen in a short (high to
|
|
536
|
-
// low bits), with a continuation bit (at 0) and another group
|
|
537
|
-
// following if there's more than fifteen. Presence and absence
|
|
538
|
-
// are conflated with true and false, for bit fields (i.e., if the
|
|
539
|
-
// flag for the field is set, it's true, otherwise false).
|
|
540
|
-
//
|
|
541
|
-
// However, none of that is actually used in AMQP 0-9-1. The only
|
|
542
|
-
// instance of properties -- basic properties -- has 14 fields, none
|
|
543
|
-
// of them bits.
|
|
544
|
-
|
|
545
|
-
function flagAt(index) {
|
|
546
|
-
return 1 << (15 - index);
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
function encodePropsFn(props) {
|
|
550
|
-
println('function %s(channel, size, fields) {', props.encoder);
|
|
551
|
-
println('var offset = 0, flags = 0, val, len;');
|
|
552
|
-
println('var scratchOffset = 0, varyingSize = 0;');
|
|
553
|
-
|
|
554
|
-
const fixedSize = PROPERTIES_OVERHEAD;
|
|
555
|
-
|
|
556
|
-
const args = props.args;
|
|
557
|
-
|
|
558
|
-
function incVarying(by) {
|
|
559
|
-
println('varyingSize += %d;', by);
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
for (let i = 0, num = args.length; i < num; i++) {
|
|
563
|
-
const p = args[i];
|
|
564
|
-
|
|
565
|
-
assignArg(p);
|
|
566
|
-
println('if (val != undefined) {');
|
|
567
|
-
|
|
568
|
-
println('if (%s) {', valTypeTest(p));
|
|
569
|
-
switch (p.type) {
|
|
570
|
-
case 'shortstr':
|
|
571
|
-
assignStringLen(p);
|
|
572
|
-
incVarying(1);
|
|
573
|
-
println('varyingSize += %s;', stringLenVar(p));
|
|
574
|
-
break;
|
|
575
|
-
case 'longstr':
|
|
576
|
-
incVarying(4);
|
|
577
|
-
println('varyingSize += val.length;');
|
|
578
|
-
break;
|
|
579
|
-
case 'table':
|
|
580
|
-
assignTable(p);
|
|
581
|
-
println('varyingSize += %s.length;', tableVar(p));
|
|
582
|
-
break;
|
|
583
|
-
case 'octet':
|
|
584
|
-
incVarying(1);
|
|
585
|
-
break;
|
|
586
|
-
case 'short':
|
|
587
|
-
incVarying(2);
|
|
588
|
-
break;
|
|
589
|
-
case 'long':
|
|
590
|
-
incVarying(4);
|
|
591
|
-
break;
|
|
592
|
-
case 'longlong': // fall through
|
|
593
|
-
case 'timestamp':
|
|
594
|
-
incVarying(8);
|
|
595
|
-
break;
|
|
596
|
-
// no case for bit, as they are accounted for in the flags
|
|
597
|
-
}
|
|
598
|
-
println('} else {');
|
|
599
|
-
println('throw new TypeError(');
|
|
600
|
-
println('"Field \'%s\' is the wrong type; must be %s");', p.name, typeDesc(p.type));
|
|
601
|
-
println('}');
|
|
602
|
-
println('}');
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
println('var buffer = Buffer.alloc(%d + varyingSize);', fixedSize);
|
|
606
|
-
|
|
607
|
-
println('buffer[0] = %d', constants.FRAME_HEADER);
|
|
608
|
-
println('buffer.writeUInt16BE(channel, 1);');
|
|
609
|
-
// content class ID and 'weight' (== 0)
|
|
610
|
-
println('buffer.writeUInt32BE(%d, 7);', props.id << 16);
|
|
611
|
-
// skip frame size for now, we'll write it in when we know.
|
|
612
|
-
|
|
613
|
-
// body size
|
|
614
|
-
println('buffer.writeBigUInt64BE(BigInt(size), 11);');
|
|
615
|
-
|
|
616
|
-
println('flags = 0;');
|
|
617
|
-
// we'll write the flags later too
|
|
618
|
-
println('offset = 21;');
|
|
619
|
-
|
|
620
|
-
for (let i = 0, num = args.length; i < num; i++) {
|
|
621
|
-
const p = args[i];
|
|
622
|
-
const flag = flagAt(i);
|
|
623
|
-
|
|
624
|
-
assignArg(p);
|
|
625
|
-
println('if (val != undefined) {');
|
|
626
|
-
if (p.type === 'bit') {
|
|
627
|
-
// which none of them are ..
|
|
628
|
-
println('if (val) flags += %d;', flag);
|
|
629
|
-
} else {
|
|
630
|
-
println('flags += %d;', flag);
|
|
631
|
-
// %%% FIXME only slightly different to the method args encoding
|
|
632
|
-
switch (p.type) {
|
|
633
|
-
case 'octet':
|
|
634
|
-
println('buffer.writeUInt8(val, offset); offset++;');
|
|
635
|
-
break;
|
|
636
|
-
case 'short':
|
|
637
|
-
println('buffer.writeUInt16BE(val, offset); offset += 2;');
|
|
638
|
-
break;
|
|
639
|
-
case 'long':
|
|
640
|
-
println('buffer.writeUInt32BE(val, offset); offset += 4;');
|
|
641
|
-
break;
|
|
642
|
-
case 'longlong':
|
|
643
|
-
case 'timestamp':
|
|
644
|
-
println('buffer.writeBigUInt64BE(BigInt(val), offset);');
|
|
645
|
-
println('offset += 8;');
|
|
646
|
-
break;
|
|
647
|
-
case 'shortstr': {
|
|
648
|
-
const v = stringLenVar(p);
|
|
649
|
-
println('buffer[offset] = %s; offset++;', v);
|
|
650
|
-
println("buffer.write(val, offset, 'utf8');");
|
|
651
|
-
println('offset += %s;', v);
|
|
652
|
-
break;
|
|
653
|
-
}
|
|
654
|
-
case 'longstr':
|
|
655
|
-
println('buffer.writeUInt32BE(val.length, offset);');
|
|
656
|
-
println('offset += 4;');
|
|
657
|
-
println('offset += val.copy(buffer, offset);');
|
|
658
|
-
break;
|
|
659
|
-
case 'table':
|
|
660
|
-
println('offset += %s.copy(buffer, offset);', tableVar(p));
|
|
661
|
-
break;
|
|
662
|
-
default:
|
|
663
|
-
throw new Error(`Unexpected argument type: ${p.type}`);
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
println('}'); // != undefined
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
println('buffer[offset] = %d;', constants.FRAME_END);
|
|
670
|
-
// size does not include the frame header or frame end byte
|
|
671
|
-
println('buffer.writeUInt32BE(offset - 7, 3);');
|
|
672
|
-
println('buffer.writeUInt16BE(flags, 19);');
|
|
673
|
-
println('return buffer.subarray(0, offset + 1);');
|
|
674
|
-
println('}');
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
function decodePropsFn(props) {
|
|
678
|
-
const args = props.args;
|
|
679
|
-
|
|
680
|
-
println('function %s(buffer) {', props.decoder);
|
|
681
|
-
println('var flags, offset = 2, val, len;');
|
|
682
|
-
|
|
683
|
-
println('flags = buffer.readUInt16BE(0);');
|
|
684
|
-
println('if (flags === 0) return {};');
|
|
685
|
-
|
|
686
|
-
fieldsDecl(args);
|
|
687
|
-
|
|
688
|
-
for (let i = 0, num = args.length; i < num; i++) {
|
|
689
|
-
const p = argument(args[i]);
|
|
690
|
-
const field = `fields['${p.name}']`;
|
|
691
|
-
|
|
692
|
-
println('if (flags & %d) {', flagAt(i));
|
|
693
|
-
if (p.type === 'bit') {
|
|
694
|
-
println('%d = true;', field);
|
|
695
|
-
} else {
|
|
696
|
-
switch (p.type) {
|
|
697
|
-
case 'octet':
|
|
698
|
-
println('val = buffer[offset]; offset++;');
|
|
699
|
-
break;
|
|
700
|
-
case 'short':
|
|
701
|
-
println('val = buffer.readUInt16BE(offset); offset += 2;');
|
|
702
|
-
break;
|
|
703
|
-
case 'long':
|
|
704
|
-
println('val = buffer.readUInt32BE(offset); offset += 4;');
|
|
705
|
-
break;
|
|
706
|
-
case 'longlong':
|
|
707
|
-
case 'timestamp':
|
|
708
|
-
println('val = Number(buffer.readBigUInt64BE(offset)); offset += 8;');
|
|
709
|
-
break;
|
|
710
|
-
case 'longstr':
|
|
711
|
-
println('len = buffer.readUInt32BE(offset); offset += 4;');
|
|
712
|
-
println('val = buffer.subarray(offset, offset + len);');
|
|
713
|
-
println('offset += len;');
|
|
714
|
-
break;
|
|
715
|
-
case 'shortstr':
|
|
716
|
-
println('len = buffer.readUInt8(offset); offset++;');
|
|
717
|
-
println('val = buffer.toString("utf8", offset, offset + len);');
|
|
718
|
-
println('offset += len;');
|
|
719
|
-
break;
|
|
720
|
-
case 'table':
|
|
721
|
-
println('len = buffer.readUInt32BE(offset); offset += 4;');
|
|
722
|
-
println('val = decodeFields(buffer.subarray(offset, offset + len));');
|
|
723
|
-
println('offset += len;');
|
|
724
|
-
break;
|
|
725
|
-
default:
|
|
726
|
-
throw new TypeError(`Unexpected type in argument list: ${p.type}`);
|
|
727
|
-
}
|
|
728
|
-
println('%s = val;', field);
|
|
729
|
-
}
|
|
730
|
-
println('}');
|
|
731
|
-
}
|
|
732
|
-
println('return fields;');
|
|
733
|
-
println('}');
|
|
734
|
-
}
|