vrpc 3.6.0 → 3.7.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/package.json +2 -2
- package/vrpc/VrpcClient.js +38 -53
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vrpc",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.7.0",
|
|
4
4
|
"description": "Variadic Remote Procedure Calls",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"directories": {
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"bugs": {
|
|
46
46
|
"url": "https://github.com/heisenware/vrpc/issues"
|
|
47
47
|
},
|
|
48
|
-
"homepage": "https://vrpc
|
|
48
|
+
"homepage": "https://docs.heisenware.com/developers/vrpc",
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@heisenware/storage": "^1.2.2",
|
|
51
51
|
"chai": "^4.3.10",
|
package/vrpc/VrpcClient.js
CHANGED
|
@@ -235,11 +235,8 @@ class VrpcClient extends EventEmitter {
|
|
|
235
235
|
`${this._domain}/${agent}/+/__classInfoConcise__`
|
|
236
236
|
)
|
|
237
237
|
}
|
|
238
|
-
// RPC responses
|
|
239
|
-
await this._mqttSubscribe(this._vrpcClientId)
|
|
240
|
-
|
|
241
|
-
// Single wildcard subscription for ALL continuous remote events
|
|
242
|
-
await this._mqttSubscribe(`${this._vrpcClientId}/__e__/#`)
|
|
238
|
+
// Single wildcard catches BOTH RPC responses (length 3) AND events (length 4)
|
|
239
|
+
await this._mqttSubscribe(`${this._vrpcClientId}/#`)
|
|
243
240
|
|
|
244
241
|
// Re-subscribe to all cached event topics
|
|
245
242
|
this._log.debug('Restoring event subscriptions after reconnect...')
|
|
@@ -767,7 +764,7 @@ class VrpcClient extends EventEmitter {
|
|
|
767
764
|
|
|
768
765
|
// Private functions
|
|
769
766
|
|
|
770
|
-
static _createHash (str, length =
|
|
767
|
+
static _createHash (str, length = 16) {
|
|
771
768
|
// Extended DJB2 hash with two accumulators
|
|
772
769
|
let hash1 = 5381
|
|
773
770
|
let hash2 = 52711 // different seed
|
|
@@ -1007,27 +1004,19 @@ class VrpcClient extends EventEmitter {
|
|
|
1007
1004
|
|
|
1008
1005
|
const obsoleteTopics = Object.keys(this._cachedSubscriptions).filter(
|
|
1009
1006
|
topic => {
|
|
1010
|
-
const
|
|
1011
|
-
|
|
1012
|
-
const topicInstance = tokens[6]
|
|
1013
|
-
const topicEvent = tokens[7]
|
|
1014
|
-
return topicInstance === instance && topicEvent === eventName
|
|
1015
|
-
}
|
|
1016
|
-
// Legacy fallback
|
|
1017
|
-
const expectedOld = `${this._domain}/${agent}/${className}/${instance}:${eventName}`
|
|
1018
|
-
return topic.startsWith(expectedOld)
|
|
1007
|
+
const sub = this._cachedSubscriptions[topic]
|
|
1008
|
+
return sub.instance === instance && sub.event === eventName
|
|
1019
1009
|
}
|
|
1020
1010
|
)
|
|
1021
1011
|
|
|
1022
1012
|
obsoleteTopics.forEach(topic => {
|
|
1023
1013
|
const id = `__e__${topic}`
|
|
1024
|
-
const
|
|
1025
|
-
|
|
1014
|
+
const sub = this._cachedSubscriptions[topic]
|
|
1015
|
+
|
|
1016
|
+
sub.listeners.forEach(({ handler }) => {
|
|
1026
1017
|
this._eventEmitter.removeListener(id, handler)
|
|
1027
1018
|
})
|
|
1028
|
-
|
|
1029
|
-
this._mqttUnsubscribe(topic).catch(() => {})
|
|
1030
|
-
}
|
|
1019
|
+
|
|
1031
1020
|
delete this._cachedSubscriptions[topic]
|
|
1032
1021
|
})
|
|
1033
1022
|
try {
|
|
@@ -1284,10 +1273,14 @@ class VrpcClient extends EventEmitter {
|
|
|
1284
1273
|
async _onRemoteEvent ({ agent, className, instance, event, callback }) {
|
|
1285
1274
|
const callbackId = this._getCallbackId(callback)
|
|
1286
1275
|
|
|
1287
|
-
//
|
|
1288
|
-
const
|
|
1276
|
+
// Generate a short, sanitized hash
|
|
1277
|
+
const hashInput = `${agent}-${className}-${
|
|
1289
1278
|
instance || '__static__'
|
|
1290
|
-
}
|
|
1279
|
+
}-${event}-${callbackId}`
|
|
1280
|
+
const topicId = VrpcClient._createHash(hashInput, 12)
|
|
1281
|
+
|
|
1282
|
+
// Route directly to the client's single event inbox wildcard
|
|
1283
|
+
const topic = `${this._vrpcClientId}/${topicId}`
|
|
1291
1284
|
const id = `__e__${topic}`
|
|
1292
1285
|
|
|
1293
1286
|
const handler = ({ a }) => callback.apply(null, a)
|
|
@@ -1298,10 +1291,16 @@ class VrpcClient extends EventEmitter {
|
|
|
1298
1291
|
}
|
|
1299
1292
|
|
|
1300
1293
|
if (!this._cachedSubscriptions[topic]) {
|
|
1301
|
-
|
|
1294
|
+
// Store metadata explicitly
|
|
1295
|
+
this._cachedSubscriptions[topic] = {
|
|
1296
|
+
agent,
|
|
1297
|
+
className,
|
|
1298
|
+
instance,
|
|
1299
|
+
event,
|
|
1300
|
+
listeners: [{ callback, handler }]
|
|
1301
|
+
}
|
|
1302
1302
|
} else {
|
|
1303
|
-
|
|
1304
|
-
this._cachedSubscriptions[topic].push({ callback, handler })
|
|
1303
|
+
this._cachedSubscriptions[topic].listeners.push({ callback, handler })
|
|
1305
1304
|
}
|
|
1306
1305
|
|
|
1307
1306
|
return id
|
|
@@ -1312,29 +1311,22 @@ class VrpcClient extends EventEmitter {
|
|
|
1312
1311
|
if (!callbackId) return null
|
|
1313
1312
|
|
|
1314
1313
|
let foundId = null
|
|
1315
|
-
const topics = Object.keys(this._cachedSubscriptions)
|
|
1316
|
-
t => t.endsWith(`/${callbackId}`) || t.endsWith(`-${callbackId}`)
|
|
1317
|
-
)
|
|
1314
|
+
const topics = Object.keys(this._cachedSubscriptions)
|
|
1318
1315
|
|
|
1319
1316
|
topics.forEach(topic => {
|
|
1320
1317
|
const id = `__e__${topic}`
|
|
1321
|
-
const
|
|
1322
|
-
|
|
1323
|
-
)
|
|
1318
|
+
const sub = this._cachedSubscriptions[topic]
|
|
1319
|
+
|
|
1320
|
+
const index = sub.listeners.findIndex(x => x.callback === callback)
|
|
1324
1321
|
|
|
1325
1322
|
if (index !== -1) {
|
|
1326
1323
|
// Decrease the "reference count" by removing one instance
|
|
1327
|
-
|
|
1324
|
+
sub.listeners.splice(index, 1)
|
|
1328
1325
|
|
|
1329
1326
|
// Only remove from the local event emitter if NO references remain
|
|
1330
|
-
if (
|
|
1327
|
+
if (sub.listeners.length === 0) {
|
|
1331
1328
|
delete this._cachedSubscriptions[topic]
|
|
1332
1329
|
|
|
1333
|
-
// Legacy cleanup just in case
|
|
1334
|
-
if (!topic.includes('__e__')) {
|
|
1335
|
-
this._mqttUnsubscribe(topic).catch(() => {})
|
|
1336
|
-
}
|
|
1337
|
-
|
|
1338
1330
|
// Cleanly wipe all listeners for this specific id
|
|
1339
1331
|
this._eventEmitter.removeAllListeners(id)
|
|
1340
1332
|
}
|
|
@@ -1347,27 +1339,20 @@ class VrpcClient extends EventEmitter {
|
|
|
1347
1339
|
_clearCachedSubscriptions ({ lostAgent, lostInstance }) {
|
|
1348
1340
|
const obsoleteTopics = Object.keys(this._cachedSubscriptions).filter(
|
|
1349
1341
|
topic => {
|
|
1350
|
-
const
|
|
1351
|
-
|
|
1352
|
-
const topicAgent = tokens[4]
|
|
1353
|
-
const topicInstance = tokens[6]
|
|
1354
|
-
return topicAgent === lostAgent || topicInstance === lostInstance
|
|
1355
|
-
}
|
|
1356
|
-
// Legacy fallback
|
|
1357
|
-
const [, agent, , instanceEvent] = topic.split('/')
|
|
1358
|
-
const [instance] = (instanceEvent || '').split(':')
|
|
1359
|
-
return agent === lostAgent || instance === lostInstance
|
|
1342
|
+
const sub = this._cachedSubscriptions[topic]
|
|
1343
|
+
return sub.agent === lostAgent || sub.instance === lostInstance
|
|
1360
1344
|
}
|
|
1361
1345
|
)
|
|
1346
|
+
|
|
1362
1347
|
obsoleteTopics.forEach(topic => {
|
|
1363
1348
|
const id = `__e__${topic}`
|
|
1364
1349
|
this._log.debug(`Clearing subscriptions for obsolete topic: ${topic}`)
|
|
1365
|
-
const
|
|
1366
|
-
|
|
1350
|
+
const sub = this._cachedSubscriptions[topic]
|
|
1351
|
+
|
|
1352
|
+
sub.listeners.forEach(({ handler }) => {
|
|
1367
1353
|
this._eventEmitter.removeListener(id, handler)
|
|
1368
1354
|
})
|
|
1369
|
-
|
|
1370
|
-
this._mqttUnsubscribe(topic)
|
|
1355
|
+
|
|
1371
1356
|
delete this._cachedSubscriptions[topic]
|
|
1372
1357
|
})
|
|
1373
1358
|
}
|