infinispan 0.14.0 → 0.16.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/.githooks/commit-msg +9 -0
- package/.githooks/configure-hooks +7 -0
- package/.githooks/configure-hooks.bat +15 -0
- package/.gitmessage +7 -0
- package/AI-CODE.md +86 -0
- package/README.md +53 -75
- package/SECURITY.md +27 -0
- package/lib/codec.js +50 -1
- package/lib/functional.js +25 -0
- package/lib/infinispan.js +299 -18
- package/lib/io.js +3 -1
- package/lib/listeners.js +116 -2
- package/lib/protocols.js +168 -20
- package/lib/transaction.js +123 -0
- package/lib/uri.js +206 -0
- package/package.json +8 -3
- package/server/.keep +0 -0
- package/types/index.d.ts +44 -0
- package/Dockerfile.server +0 -8
- package/docker-compose.yml +0 -272
- package/gen-asciidoc.sh +0 -46
- package/run-docker-testsuite.sh +0 -72
package/lib/infinispan.js
CHANGED
|
@@ -13,10 +13,12 @@
|
|
|
13
13
|
var f = require('./functional');
|
|
14
14
|
var codec = require('./codec');
|
|
15
15
|
var u = require('./utils');
|
|
16
|
+
var uri = require('./uri');
|
|
16
17
|
var protocols = require('./protocols');
|
|
17
18
|
var io = require('./io');
|
|
18
19
|
var listeners = require('./listeners');
|
|
19
20
|
var nearCacheFactory = require('./near-cache');
|
|
21
|
+
var tx = require('./transaction');
|
|
20
22
|
|
|
21
23
|
var Client = function(addrs, clientOpts) {
|
|
22
24
|
var logger = u.logger('client');
|
|
@@ -38,6 +40,7 @@
|
|
|
38
40
|
var p = protocolResolver(clientOpts['version']);
|
|
39
41
|
var listen = listeners(p);
|
|
40
42
|
var nc = clientOpts.nearCache ? nearCacheFactory(clientOpts.nearCache.maxEntries) : null;
|
|
43
|
+
var txCtx = null;
|
|
41
44
|
|
|
42
45
|
var TINY = 16, SMALL = 32, MEDIUM = 64, BIG = 128;
|
|
43
46
|
|
|
@@ -326,6 +329,17 @@
|
|
|
326
329
|
* @since 0.3
|
|
327
330
|
*/
|
|
328
331
|
get: function(k) {
|
|
332
|
+
if (txCtx) {
|
|
333
|
+
var local = txCtx.getLocalValue(k);
|
|
334
|
+
if (local.found) return Promise.resolve(local.value);
|
|
335
|
+
var ctx = transport.context(SMALL);
|
|
336
|
+
logger.debugf('Invoke transactional get(msgId=%d,key=%s)', ctx.id, u.str(k));
|
|
337
|
+
var decoder = p.decodeWithMeta();
|
|
338
|
+
return futureKey(ctx, 0x1B, k, p.encodeKey(k), decoder).then(function(meta) {
|
|
339
|
+
txCtx.trackRead(k, meta);
|
|
340
|
+
return meta ? meta.value : undefined;
|
|
341
|
+
});
|
|
342
|
+
}
|
|
329
343
|
if (nc) {
|
|
330
344
|
var cached = nc.get(k);
|
|
331
345
|
if (cached !== undefined) {
|
|
@@ -438,6 +452,8 @@
|
|
|
438
452
|
* Lifespan for the stored entry.
|
|
439
453
|
* @property {DurationUnit} maxIdle -
|
|
440
454
|
* Max idle time for the stored entry.
|
|
455
|
+
* @property {Number} flags - Bitwise OR of Hot Rod flags
|
|
456
|
+
* (e.g. infinispan.flags.SKIP_CACHE_LOAD | infinispan.flags.SKIP_INDEXING).
|
|
441
457
|
* @since 0.3
|
|
442
458
|
*/
|
|
443
459
|
/**
|
|
@@ -454,6 +470,11 @@
|
|
|
454
470
|
* @since 0.3
|
|
455
471
|
*/
|
|
456
472
|
put: function(k, v, opts) {
|
|
473
|
+
if (txCtx) {
|
|
474
|
+
logger.debugf('Transactional put(key=%s)', u.str(k));
|
|
475
|
+
txCtx.trackPut(k, v);
|
|
476
|
+
return Promise.resolve(undefined);
|
|
477
|
+
}
|
|
457
478
|
if (nc) nc.remove(k);
|
|
458
479
|
var ctx = transport.context(MEDIUM);
|
|
459
480
|
logger.debugl(function() { return ['Invoke put(msgId=%d,key=%s,value=%s,opts=%s)',
|
|
@@ -485,6 +506,11 @@
|
|
|
485
506
|
* @since 0.3
|
|
486
507
|
*/
|
|
487
508
|
remove: function(k, opts) {
|
|
509
|
+
if (txCtx) {
|
|
510
|
+
logger.debugf('Transactional remove(key=%s)', u.str(k));
|
|
511
|
+
txCtx.trackRemove(k);
|
|
512
|
+
return Promise.resolve(true);
|
|
513
|
+
}
|
|
488
514
|
if (nc) nc.remove(k);
|
|
489
515
|
var ctx = transport.context(SMALL);
|
|
490
516
|
logger.debugl(function() {return ['Invoke remove(msgId=%d,key=%s,opts=%s)',
|
|
@@ -824,6 +850,58 @@
|
|
|
824
850
|
return false;
|
|
825
851
|
});
|
|
826
852
|
},
|
|
853
|
+
/**
|
|
854
|
+
* Continuous query options.
|
|
855
|
+
*
|
|
856
|
+
* @typedef {Object} ContinuousQueryOptions
|
|
857
|
+
* @property {Object} [params] - Named parameter bindings for the Ickle query.
|
|
858
|
+
* @since 0.16
|
|
859
|
+
*/
|
|
860
|
+
/**
|
|
861
|
+
* Register a continuous query that watches for cache changes
|
|
862
|
+
* matching the given Ickle query.
|
|
863
|
+
*
|
|
864
|
+
* @param {String} queryString Ickle query string.
|
|
865
|
+
* @param {ContinuousQueryOptions=} opts Optional CQ options.
|
|
866
|
+
* @returns {Promise<Object>}
|
|
867
|
+
* A promise completed with a ContinuousQuery handle.
|
|
868
|
+
* Use cq.on('joining', fn), cq.on('leaving', fn), cq.on('updated', fn)
|
|
869
|
+
* to receive events.
|
|
870
|
+
* @memberof Client#
|
|
871
|
+
* @since 0.16
|
|
872
|
+
*/
|
|
873
|
+
addContinuousQuery: function(queryString, opts) {
|
|
874
|
+
var ctx = transport.context(SMALL);
|
|
875
|
+
logger.debugf('Invoke addContinuousQuery(msgId=%d,query=%s)', ctx.id, queryString);
|
|
876
|
+
return listen.addContinuousQueryListener(transport, ctx, queryString, opts);
|
|
877
|
+
},
|
|
878
|
+
/**
|
|
879
|
+
* Remove a continuous query.
|
|
880
|
+
*
|
|
881
|
+
* @param {Object} cq ContinuousQuery handle returned by addContinuousQuery.
|
|
882
|
+
* @returns {Promise}
|
|
883
|
+
* A promise completed when the continuous query has been removed.
|
|
884
|
+
* @memberof Client#
|
|
885
|
+
* @since 0.16
|
|
886
|
+
*/
|
|
887
|
+
removeContinuousQuery: function(cq) {
|
|
888
|
+
var listenerId = cq.getListenerId();
|
|
889
|
+
var ctx = transport.context(SMALL);
|
|
890
|
+
logger.debugf('Invoke removeContinuousQuery(msgId=%d,listenerId=%s)', ctx.id, listenerId);
|
|
891
|
+
var conn = listen.findConnectionListener(listenerId);
|
|
892
|
+
if (!f.existy(conn))
|
|
893
|
+
return Promise.reject(
|
|
894
|
+
new Error(`No server connection for CQ listener (listenerId=${ listenerId })`));
|
|
895
|
+
|
|
896
|
+
var remote = futurePinned(ctx, 0x27, p.encodeListenerId(listenerId), p.complete(p.hasSuccess), conn);
|
|
897
|
+
return remote.then(function (success) {
|
|
898
|
+
if (success) {
|
|
899
|
+
listen.removeListeners(listenerId);
|
|
900
|
+
return true;
|
|
901
|
+
}
|
|
902
|
+
return false;
|
|
903
|
+
});
|
|
904
|
+
},
|
|
827
905
|
/**
|
|
828
906
|
* Add script to server(s).
|
|
829
907
|
*
|
|
@@ -1020,6 +1098,122 @@
|
|
|
1020
1098
|
logger.debugf('Invoke counterGetAndSet(msgId=%d,name=%s,value=%d)', ctx.id, name, value);
|
|
1021
1099
|
return future(ctx, 0x7F, p.encodeCounterNameValue(name, value), p.decodeCounterValue);
|
|
1022
1100
|
},
|
|
1101
|
+
/**
|
|
1102
|
+
* Get all values associated with a key in the multimap.
|
|
1103
|
+
*
|
|
1104
|
+
* @param {(String|Object)} k Key to retrieve.
|
|
1105
|
+
* @returns {Promise.<Array>}
|
|
1106
|
+
* A promise that will be completed with an array of values,
|
|
1107
|
+
* or an empty array if the key does not exist.
|
|
1108
|
+
* @memberof Client#
|
|
1109
|
+
* @since 0.16
|
|
1110
|
+
*/
|
|
1111
|
+
multimapGet: function(k) {
|
|
1112
|
+
var ctx = transport.context(SMALL);
|
|
1113
|
+
logger.debugf('Invoke multimapGet(msgId=%d,key=%s)', ctx.id, u.str(k));
|
|
1114
|
+
return futureKey(ctx, 0x67, k, p.encodeMultimapKey(k), p.decodeMultimapCollection());
|
|
1115
|
+
},
|
|
1116
|
+
/**
|
|
1117
|
+
* Add a value to the collection associated with a key in the multimap.
|
|
1118
|
+
*
|
|
1119
|
+
* @param {(String|Object)} k Key.
|
|
1120
|
+
* @param {(String|Object)} v Value to add.
|
|
1121
|
+
* @param {Object=} opts Optional store options (lifespan, maxIdle).
|
|
1122
|
+
* @returns {Promise}
|
|
1123
|
+
* A promise that will be completed when the value has been added.
|
|
1124
|
+
* @memberof Client#
|
|
1125
|
+
* @since 0.16
|
|
1126
|
+
*/
|
|
1127
|
+
multimapPut: function(k, v, opts) {
|
|
1128
|
+
var ctx = transport.context(MEDIUM);
|
|
1129
|
+
logger.debugf('Invoke multimapPut(msgId=%d,key=%s,value=%s)', ctx.id, u.str(k), u.str(v));
|
|
1130
|
+
return futureKey(ctx, 0x6B, k, p.encodeMultimapPut(k, v), p.complete(_.constant(undefined)), opts);
|
|
1131
|
+
},
|
|
1132
|
+
/**
|
|
1133
|
+
* Remove all values associated with a key in the multimap.
|
|
1134
|
+
*
|
|
1135
|
+
* @param {(String|Object)} k Key to remove.
|
|
1136
|
+
* @returns {Promise.<Boolean>}
|
|
1137
|
+
* A promise that will be completed with true if the key existed.
|
|
1138
|
+
* @memberof Client#
|
|
1139
|
+
* @since 0.16
|
|
1140
|
+
*/
|
|
1141
|
+
multimapRemoveKey: function(k) {
|
|
1142
|
+
var ctx = transport.context(SMALL);
|
|
1143
|
+
logger.debugf('Invoke multimapRemoveKey(msgId=%d,key=%s)', ctx.id, u.str(k));
|
|
1144
|
+
return futureKey(ctx, 0x6D, k, p.encodeMultimapKey(k), p.decodeMultimapBoolean);
|
|
1145
|
+
},
|
|
1146
|
+
/**
|
|
1147
|
+
* Remove a specific value from the collection associated with a key.
|
|
1148
|
+
*
|
|
1149
|
+
* @param {(String|Object)} k Key.
|
|
1150
|
+
* @param {(String|Object)} v Value to remove.
|
|
1151
|
+
* @returns {Promise.<Boolean>}
|
|
1152
|
+
* A promise that will be completed with true if the entry existed.
|
|
1153
|
+
* @memberof Client#
|
|
1154
|
+
* @since 0.16
|
|
1155
|
+
*/
|
|
1156
|
+
multimapRemoveEntry: function(k, v) {
|
|
1157
|
+
var ctx = transport.context(SMALL);
|
|
1158
|
+
logger.debugf('Invoke multimapRemoveEntry(msgId=%d,key=%s,value=%s)', ctx.id, u.str(k), u.str(v));
|
|
1159
|
+
return futureKey(ctx, 0x6F, k, p.encodeMultimapKeyValue(k, v), p.decodeMultimapBoolean);
|
|
1160
|
+
},
|
|
1161
|
+
/**
|
|
1162
|
+
* Get the total number of key-value pairs in the multimap.
|
|
1163
|
+
*
|
|
1164
|
+
* @returns {Promise.<Number>}
|
|
1165
|
+
* A promise that will be completed with the total size.
|
|
1166
|
+
* @memberof Client#
|
|
1167
|
+
* @since 0.16
|
|
1168
|
+
*/
|
|
1169
|
+
multimapSize: function() {
|
|
1170
|
+
var ctx = transport.context(SMALL);
|
|
1171
|
+
logger.debugf('Invoke multimapSize(msgId=%d)', ctx.id);
|
|
1172
|
+
return future(ctx, 0x71, p.encodeMultimapSupportsDuplicates(), p.decodeMultimapSize);
|
|
1173
|
+
},
|
|
1174
|
+
/**
|
|
1175
|
+
* Check whether a specific key-value pair exists in the multimap.
|
|
1176
|
+
*
|
|
1177
|
+
* @param {(String|Object)} k Key.
|
|
1178
|
+
* @param {(String|Object)} v Value.
|
|
1179
|
+
* @returns {Promise.<Boolean>}
|
|
1180
|
+
* A promise that will be completed with true if the entry exists.
|
|
1181
|
+
* @memberof Client#
|
|
1182
|
+
* @since 0.16
|
|
1183
|
+
*/
|
|
1184
|
+
multimapContainsEntry: function(k, v) {
|
|
1185
|
+
var ctx = transport.context(SMALL);
|
|
1186
|
+
logger.debugf('Invoke multimapContainsEntry(msgId=%d,key=%s,value=%s)', ctx.id, u.str(k), u.str(v));
|
|
1187
|
+
return futureKey(ctx, 0x73, k, p.encodeMultimapKeyValue(k, v), p.decodeMultimapBoolean);
|
|
1188
|
+
},
|
|
1189
|
+
/**
|
|
1190
|
+
* Check whether a key exists in the multimap.
|
|
1191
|
+
*
|
|
1192
|
+
* @param {(String|Object)} k Key to check.
|
|
1193
|
+
* @returns {Promise.<Boolean>}
|
|
1194
|
+
* A promise that will be completed with true if the key exists.
|
|
1195
|
+
* @memberof Client#
|
|
1196
|
+
* @since 0.16
|
|
1197
|
+
*/
|
|
1198
|
+
multimapContainsKey: function(k) {
|
|
1199
|
+
var ctx = transport.context(SMALL);
|
|
1200
|
+
logger.debugf('Invoke multimapContainsKey(msgId=%d,key=%s)', ctx.id, u.str(k));
|
|
1201
|
+
return futureKey(ctx, 0x75, k, p.encodeMultimapKey(k), p.decodeMultimapBoolean);
|
|
1202
|
+
},
|
|
1203
|
+
/**
|
|
1204
|
+
* Check whether any key contains the given value in the multimap.
|
|
1205
|
+
*
|
|
1206
|
+
* @param {(String|Object)} v Value to check.
|
|
1207
|
+
* @returns {Promise.<Boolean>}
|
|
1208
|
+
* A promise that will be completed with true if any key contains the value.
|
|
1209
|
+
* @memberof Client#
|
|
1210
|
+
* @since 0.16
|
|
1211
|
+
*/
|
|
1212
|
+
multimapContainsValue: function(v) {
|
|
1213
|
+
var ctx = transport.context(SMALL);
|
|
1214
|
+
logger.debugf('Invoke multimapContainsValue(msgId=%d,value=%s)', ctx.id, u.str(v));
|
|
1215
|
+
return future(ctx, 0x77, p.encodeMultimapValue(v), p.decodeMultimapBoolean);
|
|
1216
|
+
},
|
|
1023
1217
|
/**
|
|
1024
1218
|
* Get server topology related information.
|
|
1025
1219
|
*
|
|
@@ -1208,6 +1402,73 @@
|
|
|
1208
1402
|
logger.debugf('Invoke admin.removeSchema(msgId=%d,name=%s)', ctx.id, name);
|
|
1209
1403
|
return future(ctx, 0x2B, p.encodeNameParams('@@schemas@delete', {name: name}), p.decodeValue());
|
|
1210
1404
|
}
|
|
1405
|
+
},
|
|
1406
|
+
/**
|
|
1407
|
+
* Get the transaction manager for this client.
|
|
1408
|
+
* Transactions buffer put/remove operations locally and send them
|
|
1409
|
+
* to the server atomically on commit via PREPARE_TX_2.
|
|
1410
|
+
* During an active transaction, get() reads local writes first,
|
|
1411
|
+
* falling back to getWithMetadata to capture entry versions for
|
|
1412
|
+
* conflict detection.
|
|
1413
|
+
*
|
|
1414
|
+
* @returns {Object} Transaction manager with begin(), commit(), and rollback() methods.
|
|
1415
|
+
* @memberof Client#
|
|
1416
|
+
* @since 0.16
|
|
1417
|
+
*/
|
|
1418
|
+
getTransactionManager: function() {
|
|
1419
|
+
return {
|
|
1420
|
+
begin: function() {
|
|
1421
|
+
if (txCtx) throw new Error('Transaction already active');
|
|
1422
|
+
txCtx = new tx.TransactionContext();
|
|
1423
|
+
logger.debugf('Transaction started (xid=%s)',
|
|
1424
|
+
txCtx.xid.globalTxId.toString('hex'));
|
|
1425
|
+
return Promise.resolve();
|
|
1426
|
+
},
|
|
1427
|
+
commit: function() {
|
|
1428
|
+
if (!txCtx) throw new Error('No active transaction');
|
|
1429
|
+
var xid = txCtx.xid;
|
|
1430
|
+
var mods = txCtx.getModifications();
|
|
1431
|
+
if (mods.length === 0) {
|
|
1432
|
+
txCtx = null;
|
|
1433
|
+
return Promise.resolve();
|
|
1434
|
+
}
|
|
1435
|
+
var ctx = transport.context(BIG);
|
|
1436
|
+
logger.debugf('Invoke prepareTx(msgId=%d, mods=%d)', ctx.id, mods.length);
|
|
1437
|
+
var decoder = p.decodeXaResponse();
|
|
1438
|
+
return future(ctx, 0x7D, p.encodePrepare(xid, mods, true, 60000), decoder)
|
|
1439
|
+
.then(function(xaCode) {
|
|
1440
|
+
txCtx = null;
|
|
1441
|
+
if (xaCode !== tx.XA_OK && xaCode !== tx.XA_RDONLY) {
|
|
1442
|
+
throw new Error(`Transaction prepare failed: XA code ${xaCode}`);
|
|
1443
|
+
}
|
|
1444
|
+
})
|
|
1445
|
+
.catch(function(err) {
|
|
1446
|
+
txCtx = null;
|
|
1447
|
+
throw err;
|
|
1448
|
+
});
|
|
1449
|
+
},
|
|
1450
|
+
rollback: function() {
|
|
1451
|
+
if (!txCtx) throw new Error('No active transaction');
|
|
1452
|
+
var xid = txCtx.xid;
|
|
1453
|
+
var mods = txCtx.getModifications();
|
|
1454
|
+
if (mods.length === 0) {
|
|
1455
|
+
txCtx = null;
|
|
1456
|
+
return Promise.resolve();
|
|
1457
|
+
}
|
|
1458
|
+
var ctx = transport.context(SMALL);
|
|
1459
|
+
logger.debugf('Invoke rollbackTx(msgId=%d)', ctx.id);
|
|
1460
|
+
var decoder = p.decodeXaResponse();
|
|
1461
|
+
return future(ctx, 0x3F, p.encodeXidOnly(xid), decoder)
|
|
1462
|
+
.then(function() { txCtx = null; })
|
|
1463
|
+
.catch(function(err) {
|
|
1464
|
+
txCtx = null;
|
|
1465
|
+
throw err;
|
|
1466
|
+
});
|
|
1467
|
+
},
|
|
1468
|
+
isActive: function() {
|
|
1469
|
+
return txCtx !== null;
|
|
1470
|
+
}
|
|
1471
|
+
};
|
|
1211
1472
|
}
|
|
1212
1473
|
};
|
|
1213
1474
|
};
|
|
@@ -1294,8 +1555,24 @@
|
|
|
1294
1555
|
*/
|
|
1295
1556
|
/**
|
|
1296
1557
|
* Infinispan client constructor taking an optional initial address,
|
|
1297
|
-
*
|
|
1298
|
-
* as well as optional configuration settings.
|
|
1558
|
+
* multiple addresses, or a Hot Rod URI string to which the client
|
|
1559
|
+
* will try to connect, as well as optional configuration settings.
|
|
1560
|
+
*
|
|
1561
|
+
* @example
|
|
1562
|
+
* // Connect with a Hot Rod URI
|
|
1563
|
+
* client('hotrod://admin:password@localhost:11222')
|
|
1564
|
+
*
|
|
1565
|
+
* @example
|
|
1566
|
+
* // URI with TLS and query parameters
|
|
1567
|
+
* client('hotrods://admin:password@localhost:11222?trust_ca=/ca.pem')
|
|
1568
|
+
*
|
|
1569
|
+
* @example
|
|
1570
|
+
* // URI with programmatic overrides
|
|
1571
|
+
* client('hotrod://admin:password@localhost:11222', {authentication: {saslMechanism: 'SCRAM-SHA-256'}})
|
|
1572
|
+
*
|
|
1573
|
+
* @example
|
|
1574
|
+
* // URI with multiple servers
|
|
1575
|
+
* client('hotrod://admin:password@node1:11222,node2:11322')
|
|
1299
1576
|
*
|
|
1300
1577
|
* @example
|
|
1301
1578
|
* client({port: 11222, host: 'localhost'})
|
|
@@ -1310,18 +1587,31 @@
|
|
|
1310
1587
|
* client([{port: 11522, host: 'myhost'}, {port: 11622, host: 'myhost'}],
|
|
1311
1588
|
* {version: '2.2', cacheName: 'myCache'})
|
|
1312
1589
|
*
|
|
1313
|
-
* @param {(ServerAddress|ServerAddress[])} args
|
|
1314
|
-
*
|
|
1315
|
-
*
|
|
1590
|
+
* @param {(String|ServerAddress|ServerAddress[])} args
|
|
1591
|
+
* A Hot Rod URI string (hotrod:// or hotrods://), a single server address,
|
|
1592
|
+
* or an array of server addresses. If none provided, the client connects
|
|
1593
|
+
* to localhost:11222 by default.
|
|
1316
1594
|
* @param {ClientOptions=} options
|
|
1317
|
-
* Optional configuration settings.
|
|
1595
|
+
* Optional configuration settings. When a URI is provided, these settings
|
|
1596
|
+
* override URI values.
|
|
1318
1597
|
* @constructs Client
|
|
1319
1598
|
* @returns {Promise<ReturnType<Client>>} A promise that resolves to a connected client.
|
|
1320
1599
|
* @since 0.3
|
|
1321
1600
|
*/
|
|
1601
|
+
exports.flags = protocols.FLAGS;
|
|
1602
|
+
|
|
1322
1603
|
exports.client = function client(args, options) {
|
|
1323
|
-
var
|
|
1324
|
-
|
|
1604
|
+
var addrs, uriOpts;
|
|
1605
|
+
if (uri.isHotrodURI(args)) {
|
|
1606
|
+
var parsed = uri.parseHotrodURI(args);
|
|
1607
|
+
addrs = parsed.servers;
|
|
1608
|
+
uriOpts = parsed.options;
|
|
1609
|
+
} else {
|
|
1610
|
+
addrs = u.normalizeAddresses(args);
|
|
1611
|
+
uriOpts = {};
|
|
1612
|
+
}
|
|
1613
|
+
var merged = f.deepMerge(Client.config, uriOpts, options || {});
|
|
1614
|
+
var c = new Client(addrs, merged);
|
|
1325
1615
|
|
|
1326
1616
|
return c.connect();
|
|
1327
1617
|
};
|
|
@@ -1389,16 +1679,7 @@
|
|
|
1389
1679
|
enabled: false,
|
|
1390
1680
|
secureProtocol: 'TLS_client_method',
|
|
1391
1681
|
trustCerts: [],
|
|
1392
|
-
|
|
1393
|
-
key: undefined,
|
|
1394
|
-
passphrase: undefined,
|
|
1395
|
-
cert: undefined
|
|
1396
|
-
},
|
|
1397
|
-
sniHostName: undefined,
|
|
1398
|
-
cryptoStore: {
|
|
1399
|
-
path: undefined,
|
|
1400
|
-
passphrase: undefined
|
|
1401
|
-
}
|
|
1682
|
+
sniHostName: undefined
|
|
1402
1683
|
},
|
|
1403
1684
|
dataFormat : {
|
|
1404
1685
|
keyType: 'text/plain',
|
package/lib/io.js
CHANGED
|
@@ -1116,6 +1116,9 @@
|
|
|
1116
1116
|
f.actions(p.stepsHeaderBody(ctx, 0x23, p.sasl(transport.authOpts(), holder), undefined), codec.bytesEncoded)(ctx);
|
|
1117
1117
|
var result = transport.writeCommandPinned(ctx, p.decodeSasl, conn);
|
|
1118
1118
|
return result.then(function (r) {
|
|
1119
|
+
if (r.complete) {
|
|
1120
|
+
return r;
|
|
1121
|
+
}
|
|
1119
1122
|
ctx = u.context(16);
|
|
1120
1123
|
ctx.topologyId = topologyId;
|
|
1121
1124
|
holder.challenge = r.response;
|
|
@@ -1123,7 +1126,6 @@
|
|
|
1123
1126
|
return transport.writeCommandPinned(ctx, p.decodeSasl, conn).then(function (r) {
|
|
1124
1127
|
return r;
|
|
1125
1128
|
});
|
|
1126
|
-
return r;
|
|
1127
1129
|
});
|
|
1128
1130
|
}
|
|
1129
1131
|
|
package/lib/listeners.js
CHANGED
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
|
|
11
11
|
var events = require('events');
|
|
12
12
|
|
|
13
|
+
var CQ_FACTORY = 'continuous-query-filter-converter-factory';
|
|
14
|
+
|
|
13
15
|
module.exports = listeners;
|
|
14
16
|
|
|
15
17
|
/**
|
|
@@ -132,8 +134,10 @@
|
|
|
132
134
|
dispatchEvent: function(event, listenerId, bytebuf, emitFunc) {
|
|
133
135
|
return function() {
|
|
134
136
|
var l = listeners.get(listenerId);
|
|
135
|
-
if (f.existy(l))
|
|
136
|
-
|
|
137
|
+
if (f.existy(l)) {
|
|
138
|
+
var emit = l.cqEmit || emitFunc;
|
|
139
|
+
return emit(event, l.emitter, bytebuf, listenerId);
|
|
140
|
+
}
|
|
137
141
|
|
|
138
142
|
logger.error('No emitter exists for listener %s', listenerId);
|
|
139
143
|
return true;
|
|
@@ -152,7 +156,117 @@
|
|
|
152
156
|
setProtocol: function(newProtocol) {
|
|
153
157
|
protocol = newProtocol;
|
|
154
158
|
},
|
|
159
|
+
/**
|
|
160
|
+
* Register a continuous query listener.
|
|
161
|
+
* @param {Object} transport Transport instance.
|
|
162
|
+
* @param {Object} ctx Request context.
|
|
163
|
+
* @param {string} queryString Ickle query string.
|
|
164
|
+
* @param {Object} [opts] Options with optional params map.
|
|
165
|
+
* @returns {Promise<Object>} ContinuousQuery handle.
|
|
166
|
+
*/
|
|
167
|
+
addContinuousQueryListener: function(transport, ctx, queryString, opts) {
|
|
168
|
+
opts = opts || {};
|
|
169
|
+
var listenerId = _.uniqueId('cq_');
|
|
170
|
+
logger.debugl(function() {
|
|
171
|
+
return ['Invoke addContinuousQueryListener(msgId=%d,query=%s,listenerId=%s)',
|
|
172
|
+
ctx.id, queryString, listenerId]; });
|
|
173
|
+
|
|
174
|
+
var cqParams = buildCQParams(queryString, opts.params);
|
|
175
|
+
|
|
176
|
+
var listenerOpts = {
|
|
177
|
+
includeState: true,
|
|
178
|
+
useRawData: true,
|
|
179
|
+
filterFactory: { name: CQ_FACTORY, params: cqParams },
|
|
180
|
+
converterFactory: { name: CQ_FACTORY, params: cqParams }
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
var encodeListenerAddCommon = protocol.encodeListenerAdd(listenerId, listenerOpts)();
|
|
184
|
+
var encodeListenerAddInterests = protocol.encodeListenerInterests(listenerOpts);
|
|
185
|
+
var encodeListenerAdd = function() {
|
|
186
|
+
return f.cat(encodeListenerAddCommon, encodeListenerAddInterests);
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
var bufferedEvents = [];
|
|
190
|
+
var buffering = true;
|
|
191
|
+
|
|
192
|
+
var cqEmitFn = function(event, emitter, bytebuf) {
|
|
193
|
+
var payloadLength = codec.decodeVariableBytes()(bytebuf);
|
|
194
|
+
if (!f.existy(payloadLength) || !f.existy(payloadLength.answer))
|
|
195
|
+
return false;
|
|
196
|
+
var payload = payloadLength.answer;
|
|
197
|
+
var wrapped = codec.decodeWrappedMessage(payload);
|
|
198
|
+
if (!f.existy(wrapped) || !f.existy(wrapped.wrappedMessage))
|
|
199
|
+
return true;
|
|
200
|
+
var cqResult = codec.decodeContinuousQueryResult(wrapped.wrappedMessage);
|
|
201
|
+
if (buffering) {
|
|
202
|
+
bufferedEvents.push(cqResult);
|
|
203
|
+
} else {
|
|
204
|
+
emitter.emit(cqResult.resultType, cqResult.key, cqResult.value, cqResult.projection);
|
|
205
|
+
}
|
|
206
|
+
return true;
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
var preWrite = function(conn) {
|
|
210
|
+
var emitter = new events.EventEmitter();
|
|
211
|
+
listeners.put(listenerId, {
|
|
212
|
+
id: listenerId,
|
|
213
|
+
emitter: emitter,
|
|
214
|
+
conn: conn,
|
|
215
|
+
cqEmit: cqEmitFn
|
|
216
|
+
});
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
var remote = futurePreWrite(transport, ctx, 0x25
|
|
220
|
+
, encodeListenerAdd, protocol.complete(protocol.hasSuccess)
|
|
221
|
+
, listenerOpts, preWrite);
|
|
222
|
+
|
|
223
|
+
return remote
|
|
224
|
+
.then(function(success) {
|
|
225
|
+
if (success) {
|
|
226
|
+
var l = listeners.get(listenerId);
|
|
227
|
+
var emitter = l.emitter;
|
|
228
|
+
return {
|
|
229
|
+
on: function(event, callback) {
|
|
230
|
+
emitter.on(event, callback);
|
|
231
|
+
if (buffering) {
|
|
232
|
+
buffering = false;
|
|
233
|
+
bufferedEvents.forEach(function(ev) {
|
|
234
|
+
emitter.emit(ev.resultType, ev.key, ev.value, ev.projection);
|
|
235
|
+
});
|
|
236
|
+
bufferedEvents = [];
|
|
237
|
+
}
|
|
238
|
+
return this;
|
|
239
|
+
},
|
|
240
|
+
getListenerId: function() { return listenerId; }
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
listen.removeListeners(listenerId);
|
|
244
|
+
return undefined;
|
|
245
|
+
})
|
|
246
|
+
.catch(function(err) {
|
|
247
|
+
listen.removeListeners(listenerId);
|
|
248
|
+
throw err;
|
|
249
|
+
});
|
|
250
|
+
},
|
|
155
251
|
};
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Build CQ factory params from query and named params.
|
|
255
|
+
* @param {string} queryString Ickle query.
|
|
256
|
+
* @param {Object} [params] Named parameter map.
|
|
257
|
+
* @returns {Buffer[]} Array of wrapped param byte arrays.
|
|
258
|
+
*/
|
|
259
|
+
function buildCQParams(queryString, params) {
|
|
260
|
+
var result = [codec.wrapScalar(queryString)];
|
|
261
|
+
if (f.existy(params)) {
|
|
262
|
+
_.each(params, function(value, name) {
|
|
263
|
+
result.push(codec.wrapScalar(name));
|
|
264
|
+
result.push(codec.wrapScalar(value));
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
return result;
|
|
268
|
+
}
|
|
269
|
+
|
|
156
270
|
return listen;
|
|
157
271
|
}
|
|
158
272
|
|