telemersive-bus 0.6.14 → 0.6.16

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 (2) hide show
  1. package/lib/BusManager.js +80 -54
  2. package/package.json +1 -1
package/lib/BusManager.js CHANGED
@@ -32,6 +32,10 @@ class BusManager {
32
32
  this.roomHousekeep = {};
33
33
  this.houseKeepingInProgress = false;
34
34
  this.housekeepingId = 0;
35
+ // promise set while cleanOut is actively mutating this.rooms, null otherwise.
36
+ // startHousekeeping awaits it before snapshotting this.rooms, so a new cycle
37
+ // cannot start before the previous one's room deletions have fully settled.
38
+ this.cleanOutInProgress = null;
35
39
  this.chatManagers = {};
36
40
  this.switchBoardURI = null;
37
41
  }
@@ -120,6 +124,12 @@ class BusManager {
120
124
  * when peer leaves a room
121
125
  */
122
126
  startHousekeeping = async () => {
127
+ // wait for any in-flight cleanOut to fully settle before snapshotting this.rooms.
128
+ // this prevents overlap where a still-running cleanOut's slow stopServerSidePortScripts
129
+ // finishes (and deletes from this.rooms) after a new cycle already snapshotted them.
130
+ if (this.cleanOutInProgress) {
131
+ await this.cleanOutInProgress;
132
+ }
123
133
  // we dont want to start another housekeeping process until the previous one has finished
124
134
  if(!this.houseKeepingInProgress){
125
135
  this.houseKeepingInProgress = true;
@@ -168,6 +178,8 @@ class BusManager {
168
178
  console.log(` -> housekeeping -> pinging all rooms ...`);
169
179
  const keys = Object.keys(this.rooms);
170
180
 
181
+ // clean up auto-generated subscriptions from prior cycles before subscribing again
182
+ await this.communicator.unsubscribe(this.busTopics.baseRoomAlivePing("+").build());
171
183
  // subscribe to all room ping alive topic
172
184
  await this.communicator.subscribe(new BusMsgSub(this.busTopics.baseRoomAlivePing("+").build(), this.onRoomAlive, PeerCredentials, 0));
173
185
 
@@ -266,62 +278,76 @@ class BusManager {
266
278
  if (myId !== this.housekeepingId) {
267
279
  return;
268
280
  }
269
- if(this.houseKeepingInProgress) {
270
- console.log(` -> housekeeping -> cleaning out ...`);
271
- // flag the room as being in the process to be removed
272
- const flag4cleanupRooms = (currentRoom) => this.rooms[currentRoom.roomName].flagRoom4cleanup = true;
273
- Object.values(this.roomHousekeep).forEach(flag4cleanupRooms);
274
-
275
- // kick out the non-responding peers
276
- const kickOutPeer = async (currentPeer) => {
277
- console.log(` <- remove peer '${currentPeer.peerName}' from room '${currentPeer.roomName}' `);
278
- // first we send clear retain message to peer joined addresses that have not replied:
279
- await this.communicator.clearRetain(this.busTopics.roomPeerJoin(currentPeer.roomName, currentPeer.peerId).build());
280
-
281
- // create the payload for the leave message
282
- const infoPayload = {
283
- timestamp: Math.round(new Date().getTime() / 1000),
284
- peerId: currentPeer.peerId,
285
- peerName: currentPeer.peerName,
286
- roomName: currentPeer.roomName
287
- };
288
-
289
- // sends the left message to all peers joined in the same room
290
- await this.communicator.publish(
291
- new BusMsgPub(
292
- this.busTopics.roomPeerLeft(currentPeer.roomName, currentPeer.peerId).build(),
293
- PeerInfo, 2, true).encode(infoPayload));
294
- }
295
- const peerCleanup = async () => {
296
- for (const peer of Object.values(this.peerHousekeep)) {
297
- await kickOutPeer(peer);
298
- }
299
- };
300
- await peerCleanup();
301
-
302
- // And now remove the rooms
303
- const cleanupRooms = async (currentRoom) => await this.deleteRoom(currentRoom.roomName);
304
- const housekeeping = async () => {
305
- for (const room of Object.values(this.roomHousekeep)) {
306
- await cleanupRooms(room);
281
+ // expose the in-flight cleanOut as a promise so the next startHousekeeping can await it
282
+ // and avoid snapshotting this.rooms while deleteRoom is still mutating it.
283
+ this.cleanOutInProgress = (async () => {
284
+ try {
285
+ if(this.houseKeepingInProgress) {
286
+ console.log(` -> housekeeping -> cleaning out ...`);
287
+ // flag the room as being in the process to be removed. the entry may already have
288
+ // been deleted from this.rooms by an earlier overlapping cleanOut whose slow
289
+ // stopServerSidePortScripts only just finished in that case, nothing to flag.
290
+ const flag4cleanupRooms = (currentRoom) => {
291
+ const room = this.rooms[currentRoom.roomName];
292
+ if (room) room.flagRoom4cleanup = true;
293
+ };
294
+ Object.values(this.roomHousekeep).forEach(flag4cleanupRooms);
295
+
296
+ // kick out the non-responding peers
297
+ const kickOutPeer = async (currentPeer) => {
298
+ console.log(` <- remove peer '${currentPeer.peerName}' from room '${currentPeer.roomName}' `);
299
+ // first we send clear retain message to peer joined addresses that have not replied:
300
+ await this.communicator.clearRetain(this.busTopics.roomPeerJoin(currentPeer.roomName, currentPeer.peerId).build());
301
+
302
+ // create the payload for the leave message
303
+ const infoPayload = {
304
+ timestamp: Math.round(new Date().getTime() / 1000),
305
+ peerId: currentPeer.peerId,
306
+ peerName: currentPeer.peerName,
307
+ roomName: currentPeer.roomName
308
+ };
309
+
310
+ // sends the left message to all peers joined in the same room
311
+ await this.communicator.publish(
312
+ new BusMsgPub(
313
+ this.busTopics.roomPeerLeft(currentPeer.roomName, currentPeer.peerId).build(),
314
+ PeerInfo, 2, true).encode(infoPayload));
315
+ }
316
+ const peerCleanup = async () => {
317
+ for (const peer of Object.values(this.peerHousekeep)) {
318
+ await kickOutPeer(peer);
319
+ }
320
+ };
321
+ await peerCleanup();
322
+
323
+ // And now remove the rooms
324
+ const cleanupRooms = async (currentRoom) => await this.deleteRoom(currentRoom.roomName);
325
+ const housekeeping = async () => {
326
+ for (const room of Object.values(this.roomHousekeep)) {
327
+ await cleanupRooms(room);
328
+ }
329
+ };
330
+ await housekeeping();
331
+
332
+ console.log(` -> housekeeping DONE`);
333
+ } else {
334
+ console.log(` -> housekeeping was interrupted`);
307
335
  }
308
- };
309
- await housekeeping();
310
-
311
- console.log(` -> housekeeping DONE`);
312
- } else {
313
- console.log(` -> housekeeping was interrupted`);
314
- }
315
336
 
316
- // and we stop by unsubscribing to all peer info messages inside all rooms
317
- await this.communicator.unsubscribe(this.busTopics.roomPeerJoin('+', '+').build());
318
- // unsubscribing to all room ping alive topic
319
- await this.communicator.unsubscribe(this.busTopics.baseRoomAlivePing("+").build());
320
- // cleanup the communicator
321
- this.communicator.clearAutoGeneratedSubscriptions();
322
- // set this flag to false at the end to make sure a new houskeeping cycle can only be started once
323
- // all topics are unsubscribed - otherwise it won't gather the joined peers inside the room.
324
- this.houseKeepingInProgress = false;
337
+ // and we stop by unsubscribing to all peer info messages inside all rooms
338
+ await this.communicator.unsubscribe(this.busTopics.roomPeerJoin('+', '+').build());
339
+ // unsubscribing to all room ping alive topic
340
+ await this.communicator.unsubscribe(this.busTopics.baseRoomAlivePing("+").build());
341
+ // cleanup the communicator
342
+ this.communicator.clearAutoGeneratedSubscriptions();
343
+ // set this flag to false at the end to make sure a new houskeeping cycle can only be started once
344
+ // all topics are unsubscribed - otherwise it won't gather the joined peers inside the room.
345
+ this.houseKeepingInProgress = false;
346
+ } finally {
347
+ this.cleanOutInProgress = null;
348
+ }
349
+ })();
350
+ await this.cleanOutInProgress;
325
351
  }
326
352
 
327
353
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "telemersive-bus",
3
- "version": "0.6.14",
3
+ "version": "0.6.16",
4
4
  "description": "MQTT based data protocol to manage unlimited peers, connected by rooms, where all peers joined to a room can exchange private data. It provides a simple chat mechanism, latency pinging, publish-subscribe mechanism (based on mqtt) and a OSC-like data stream. ",
5
5
  "main": "index.js",
6
6
  "directories": {