sen-ether-client 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/lib/client.js +14 -1
  2. package/lib/sen.js +63 -33
  3. package/package.json +1 -1
package/lib/client.js CHANGED
@@ -470,6 +470,7 @@ export class EtherClient extends EventEmitter {
470
470
  this.ready = false;
471
471
  this.buses = new Map();
472
472
  this.remoteParticipantsByBusId = new Map();
473
+ this.nextInterestId = randomUInt32();
473
474
  }
474
475
 
475
476
  /**
@@ -997,7 +998,7 @@ export class EtherClient extends EventEmitter {
997
998
  */
998
999
  startInterest(bus, query, options = {}) {
999
1000
  const busState = this.#getBus(bus);
1000
- const id = options.id ?? crc32(query);
1001
+ const id = options.id ?? this.#nextInterestId(busState);
1001
1002
  this.#sendBusControlToRemoteParticipants(busState, {
1002
1003
  type: 'InterestStarted',
1003
1004
  value: { query, id }
@@ -1007,6 +1008,18 @@ export class EtherClient extends EventEmitter {
1007
1008
  return { busName: busState.busName, busId: busState.busId, id, query };
1008
1009
  }
1009
1010
 
1011
+ #nextInterestId(busState) {
1012
+ for (let attempts = 0; attempts < 0xffff_ffff; attempts += 1) {
1013
+ this.nextInterestId = (this.nextInterestId + 1) >>> 0;
1014
+ const id = this.nextInterestId || 1;
1015
+ if (!busState.interests.has(id)) {
1016
+ this.nextInterestId = id;
1017
+ return id;
1018
+ }
1019
+ }
1020
+ throw new Error('could not allocate a SEN interest id');
1021
+ }
1022
+
1010
1023
  #restartInterestForRemote(busState) {
1011
1024
  for (const participant of this.#remoteParticipantsForBus(busState.busId)) {
1012
1025
  for (const interest of busState.interests.values()) {
package/lib/sen.js CHANGED
@@ -161,8 +161,20 @@ function normalizeTimestampNs(value) {
161
161
  return typeof value === 'bigint' ? value : BigInt(value);
162
162
  }
163
163
 
164
- function stateRequestKey(interestId, objectId) {
165
- return `${interestId >>> 0}:${objectId >>> 0}`;
164
+ function stateRequestKey(interestId, ownerId, objectId) {
165
+ return `${interestId >>> 0}:${remoteObjectKey(ownerId, objectId)}`;
166
+ }
167
+
168
+ function remoteObjectKey(ownerId, objectId) {
169
+ const owner = ownerId === undefined || ownerId === null ? 'unknown' : String(ownerId >>> 0);
170
+ return `${owner}:${objectId >>> 0}`;
171
+ }
172
+
173
+ function eventOwnerId(event) {
174
+ if (event?.ownerId !== undefined) {
175
+ return event.ownerId;
176
+ }
177
+ return event?.multicast ? undefined : event?.to;
166
178
  }
167
179
 
168
180
  async function waitForSessionBuses(session, timeoutMs) {
@@ -1312,43 +1324,36 @@ export class SenBus extends EventEmitter {
1312
1324
  }
1313
1325
 
1314
1326
  handleObjectsPublished(event) {
1327
+ const ownerId = eventOwnerId(event);
1315
1328
  const newTypeHashes = new Set();
1316
1329
  for (const discovery of event.discoveries ?? []) {
1317
1330
  const interest = this.interests.get(discovery.interestId);
1318
- if (interest && event.ownerId !== undefined) {
1319
- if (interest.ownerId !== undefined && interest.ownerId !== event.ownerId) {
1320
- this.#resetInterestForOwner(interest, event.ownerId);
1321
- } else {
1322
- interest.ownerId = event.ownerId;
1323
- }
1331
+ if (!interest) {
1332
+ continue;
1333
+ }
1334
+ if (ownerId !== undefined) {
1335
+ interest.ownerId ??= ownerId;
1336
+ interest.ownerIds.add(ownerId >>> 0);
1324
1337
  }
1325
1338
 
1326
1339
  for (const info of discovery.objects ?? []) {
1327
- let object = this.objectsById.get(info.id);
1328
- if (object && event.ownerId !== undefined && object.ownerId !== event.ownerId) {
1329
- this.#removeObjectFromAllInterests(object, {
1330
- reason: 'ownerChanged',
1331
- ownerId: event.ownerId,
1332
- previousOwnerId: object.ownerId
1333
- });
1334
- object = undefined;
1335
- }
1340
+ let object = this.#objectByOwnerAndId(ownerId, info.id);
1336
1341
  const isNewObject = !object;
1337
1342
  if (!object) {
1338
1343
  object = new SenRemoteObject(this, {
1339
1344
  ...info,
1340
- ownerId: event.ownerId,
1345
+ ownerId,
1341
1346
  interestId: discovery.interestId
1342
1347
  });
1343
- this.objectsById.set(object.id, object);
1348
+ this.objectsById.set(object.key, object);
1344
1349
  } else {
1345
1350
  object.attachInterest(discovery.interestId);
1346
1351
  object.updateDiscoveryInfo({
1347
1352
  ...info,
1348
- ownerId: event.ownerId
1353
+ ownerId
1349
1354
  });
1350
1355
  }
1351
- interest?.objectsById.set(object.id, object);
1356
+ interest?.objectsById.set(object.key, object);
1352
1357
  if (info.state?.length) {
1353
1358
  object.applyState(info.state, 'published', info.time, { interestId: discovery.interestId });
1354
1359
  }
@@ -1367,10 +1372,14 @@ export class SenBus extends EventEmitter {
1367
1372
  }
1368
1373
 
1369
1374
  handleObjectsRemoved(event) {
1375
+ const ownerId = eventOwnerId(event);
1370
1376
  for (const removal of event.removals ?? []) {
1377
+ const interest = this.interests.get(removal.interestId);
1378
+ if (!interest) {
1379
+ continue;
1380
+ }
1371
1381
  for (const id of removal.ids ?? []) {
1372
- const object = this.objectsById.get(id);
1373
- const interest = this.interests.get(removal.interestId);
1382
+ const object = this.#objectByOwnerAndId(ownerId, id);
1374
1383
  if (object) {
1375
1384
  this.#removeObjectFromInterest(object, removal.interestId, interest);
1376
1385
  }
@@ -1419,14 +1428,16 @@ export class SenBus extends EventEmitter {
1419
1428
 
1420
1429
  #removeObjectFromInterest(object, interestId, interest, detail = {}) {
1421
1430
  const normalizedInterestId = interestId >>> 0;
1422
- this.stateRequestedObjectIds.delete(stateRequestKey(normalizedInterestId, object.id));
1423
- interest?.objectsById.delete(object.id);
1431
+ this.stateRequestedObjectIds.delete(stateRequestKey(normalizedInterestId, object.ownerId, object.id));
1432
+ interest?.objectsById.delete(object.key);
1424
1433
  object.detachInterest(normalizedInterestId);
1425
1434
  object.emit('remove', { interestId: normalizedInterestId, ...detail });
1426
1435
  interest?.emit('remove', object);
1427
1436
  if (object.interestIds.size === 0) {
1428
- this.objectsById.delete(object.id);
1429
- this.requestedTypeHashes.delete(object.typeHash);
1437
+ this.objectsById.delete(object.key);
1438
+ if (![...this.objectsById.values()].some(item => item.typeHash === object.typeHash)) {
1439
+ this.requestedTypeHashes.delete(object.typeHash);
1440
+ }
1430
1441
  this.emit('remove', object);
1431
1442
  this.sen.emit('remove', object);
1432
1443
  }
@@ -1491,10 +1502,15 @@ export class SenBus extends EventEmitter {
1491
1502
  }
1492
1503
 
1493
1504
  handleObjectsStateResponse(event) {
1505
+ const ownerId = eventOwnerId(event);
1494
1506
  for (const response of event.responses ?? []) {
1507
+ const interest = this.interests.get(response.interestId);
1508
+ if (!interest) {
1509
+ continue;
1510
+ }
1495
1511
  for (const state of response.objectStates ?? []) {
1496
- const object = this.objectsById.get(state.id);
1497
- if (!object || (event.ownerId !== undefined && object.ownerId !== event.ownerId)) {
1512
+ const object = this.#objectByOwnerAndId(ownerId, state.id);
1513
+ if (!object || !interest.objectsById.has(object.key)) {
1498
1514
  continue;
1499
1515
  }
1500
1516
  object.applyState(state.state, 'state', state.timestamp, { interestId: response.interestId });
@@ -1503,7 +1519,7 @@ export class SenBus extends EventEmitter {
1503
1519
  }
1504
1520
 
1505
1521
  handleRuntimeObjectUpdate(event) {
1506
- const object = this.objectsById.get(event.update.objectId);
1522
+ const object = this.#objectByOwnerAndId(eventOwnerId(event), event.update.objectId);
1507
1523
  if (!object) {
1508
1524
  return;
1509
1525
  }
@@ -1511,8 +1527,9 @@ export class SenBus extends EventEmitter {
1511
1527
  }
1512
1528
 
1513
1529
  handleRuntimeEvents(event) {
1530
+ const ownerId = eventOwnerId(event);
1514
1531
  for (const item of event.events ?? []) {
1515
- const object = this.objectsById.get(item.producerId);
1532
+ const object = this.#objectByOwnerAndId(ownerId, item.producerId);
1516
1533
  if (!object) {
1517
1534
  continue;
1518
1535
  }
@@ -1583,7 +1600,7 @@ export class SenBus extends EventEmitter {
1583
1600
  if (!object.spec) {
1584
1601
  continue;
1585
1602
  }
1586
- const key = stateRequestKey(interest.id, object.id);
1603
+ const key = stateRequestKey(interest.id, object.ownerId, object.id);
1587
1604
  if (!force && this.stateRequestedObjectIds.has(key)) {
1588
1605
  continue;
1589
1606
  }
@@ -1656,6 +1673,14 @@ export class SenBus extends EventEmitter {
1656
1673
  }
1657
1674
  }
1658
1675
  }
1676
+
1677
+ #objectByOwnerAndId(ownerId, objectId) {
1678
+ if (ownerId !== undefined && ownerId !== null) {
1679
+ return this.objectsById.get(remoteObjectKey(ownerId, objectId));
1680
+ }
1681
+ const id = objectId >>> 0;
1682
+ return [...this.objectsById.values()].find(object => object.id === id);
1683
+ }
1659
1684
  }
1660
1685
 
1661
1686
  export class SenInterest extends EventEmitter {
@@ -1665,6 +1690,7 @@ export class SenInterest extends EventEmitter {
1665
1690
  this.id = id;
1666
1691
  this.query = query;
1667
1692
  this.ownerId = undefined;
1693
+ this.ownerIds = new Set();
1668
1694
  this.options = { ...options };
1669
1695
  this.propertyNames = normalizePropertyNames(options.properties ?? options.propertyNames);
1670
1696
  this.changeMode = options.changeMode ?? (options.batch ? 'batch' : 'individual');
@@ -1867,6 +1893,10 @@ export class SenRemoteObject extends EventEmitter {
1867
1893
  return this.propertyTimestamps.get(name);
1868
1894
  }
1869
1895
 
1896
+ get key() {
1897
+ return remoteObjectKey(this.ownerId, this.id);
1898
+ }
1899
+
1870
1900
  isReadyForInterest(interestId) {
1871
1901
  return this.readyInterestIds.has(interestId >>> 0);
1872
1902
  }
@@ -2002,7 +2032,7 @@ export class SenRemoteObject extends EventEmitter {
2002
2032
 
2003
2033
  const interests = [];
2004
2034
  for (const interest of this.bus.interests.values()) {
2005
- if (interest.objectsById.has(this.id)) {
2035
+ if (interest.objectsById.has(this.key) || interest.objectsById.has(this.id)) {
2006
2036
  interests.push(interest);
2007
2037
  }
2008
2038
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sen-ether-client",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Pure JavaScript SEN client for existing kernels over ether",
5
5
  "senCompatibility": {
6
6
  "kernelProtocolVersion": 9,