Browse Source

feat(replace-participant): Replace participant with same jwt in the conf

release-8443
hmuresan 4 years ago
parent
commit
0ed1b4ef04
4 changed files with 112 additions and 14 deletions
  1. 21
    5
      JitsiConference.js
  2. 37
    1
      JitsiParticipant.js
  3. 15
    4
      modules/xmpp/ChatRoom.js
  4. 39
    4
      modules/xmpp/ChatRoom.spec.js

+ 21
- 5
JitsiConference.js View File

516
 /**
516
 /**
517
  * Joins the conference.
517
  * Joins the conference.
518
  * @param password {string} the password
518
  * @param password {string} the password
519
+ * @param replaceParticipant {boolean} whether the current join replaces
520
+ * an existing participant with same jwt from the meeting.
519
  */
521
  */
520
-JitsiConference.prototype.join = function(password) {
522
+JitsiConference.prototype.join = function(password, replaceParticipant = false) {
521
     if (this.room) {
523
     if (this.room) {
522
-        this.room.join(password).then(() => this._maybeSetSITimeout());
524
+        this.room.join(password, replaceParticipant).then(() => this._maybeSetSITimeout());
523
     }
525
     }
524
 };
526
 };
525
 
527
 
1584
  * @param botType the member botType, if any
1586
  * @param botType the member botType, if any
1585
  * @param fullJid the member full jid, if any
1587
  * @param fullJid the member full jid, if any
1586
  * @param features the member botType, if any
1588
  * @param features the member botType, if any
1589
+ * @param isReplaceParticipant whether this join replaces a participant with
1590
+ * the same jwt.
1587
  */
1591
  */
1588
 JitsiConference.prototype.onMemberJoined = function(
1592
 JitsiConference.prototype.onMemberJoined = function(
1589
-        jid, nick, role, isHidden, statsID, status, identity, botType, fullJid, features) {
1593
+        jid, nick, role, isHidden, statsID, status, identity, botType, fullJid, features, isReplaceParticipant) {
1590
     const id = Strophe.getResourceFromJid(jid);
1594
     const id = Strophe.getResourceFromJid(jid);
1591
 
1595
 
1592
     if (id === 'focus' || this.myUserId() === id) {
1596
     if (id === 'focus' || this.myUserId() === id) {
1599
     participant.setRole(role);
1603
     participant.setRole(role);
1600
     participant.setBotType(botType);
1604
     participant.setBotType(botType);
1601
     participant.setFeatures(features);
1605
     participant.setFeatures(features);
1606
+    participant.setIsReplacing(isReplaceParticipant);
1602
 
1607
 
1603
     this.participants[id] = participant;
1608
     this.participants[id] = participant;
1604
     this.eventEmitter.emit(
1609
     this.eventEmitter.emit(
1727
         });
1732
         });
1728
 };
1733
 };
1729
 
1734
 
1735
+/* eslint-disable max-params */
1736
+
1730
 /**
1737
 /**
1731
  * Designates an event indicating that we were kicked from the XMPP MUC.
1738
  * Designates an event indicating that we were kicked from the XMPP MUC.
1732
  * @param {boolean} isSelfPresence - whether it is for local participant
1739
  * @param {boolean} isSelfPresence - whether it is for local participant
1736
  * @param {string?} kickedParticipantId - when it is not a kick for local participant,
1743
  * @param {string?} kickedParticipantId - when it is not a kick for local participant,
1737
  * this is the id of the participant which was kicked.
1744
  * this is the id of the participant which was kicked.
1738
  * @param {string} reason - reason of the participant to kick
1745
  * @param {string} reason - reason of the participant to kick
1746
+ * @param {boolean?} isReplaceParticipant - whether this is a server initiated kick in order
1747
+ * to replace it with a participant with same jwt.
1739
  */
1748
  */
1740
-JitsiConference.prototype.onMemberKicked = function(isSelfPresence, actorId, kickedParticipantId, reason) {
1749
+JitsiConference.prototype.onMemberKicked = function(
1750
+        isSelfPresence,
1751
+        actorId,
1752
+        kickedParticipantId,
1753
+        reason,
1754
+        isReplaceParticipant) {
1741
     // This check which be true when we kick someone else. With the introduction of lobby
1755
     // This check which be true when we kick someone else. With the introduction of lobby
1742
     // the ChatRoom KICKED event is now also emitted for ourselves (the kicker) so we want to
1756
     // the ChatRoom KICKED event is now also emitted for ourselves (the kicker) so we want to
1743
     // avoid emitting an event where `undefined` kicked someone.
1757
     // avoid emitting an event where `undefined` kicked someone.
1749
 
1763
 
1750
     if (isSelfPresence) {
1764
     if (isSelfPresence) {
1751
         this.eventEmitter.emit(
1765
         this.eventEmitter.emit(
1752
-            JitsiConferenceEvents.KICKED, actorParticipant, reason);
1766
+            JitsiConferenceEvents.KICKED, actorParticipant, reason, isReplaceParticipant);
1753
 
1767
 
1754
         this.leave();
1768
         this.leave();
1755
 
1769
 
1758
 
1772
 
1759
     const kickedParticipant = this.participants[kickedParticipantId];
1773
     const kickedParticipant = this.participants[kickedParticipantId];
1760
 
1774
 
1775
+    kickedParticipant.setIsReplaced(isReplaceParticipant);
1776
+
1761
     this.eventEmitter.emit(
1777
     this.eventEmitter.emit(
1762
         JitsiConferenceEvents.PARTICIPANT_KICKED, actorParticipant, kickedParticipant, reason);
1778
         JitsiConferenceEvents.PARTICIPANT_KICKED, actorParticipant, kickedParticipant, reason);
1763
 };
1779
 };

+ 37
- 1
JitsiParticipant.js View File

26
      * @param {string} statsID - optional participant statsID
26
      * @param {string} statsID - optional participant statsID
27
      * @param {string} status - the initial status if any.
27
      * @param {string} status - the initial status if any.
28
      * @param {object} identity - the xmpp identity
28
      * @param {object} identity - the xmpp identity
29
+     * @param {boolean?} isReplacing - whether this is a participant replacing another into the meeting.
30
+     * @param {boolean?} isReplaced - whether this is a participant to be kicked and replaced into the meeting.
29
      */
31
      */
30
-    constructor(jid, conference, displayName, hidden, statsID, status, identity) {
32
+    constructor(jid, conference, displayName, hidden, statsID, status, identity, isReplacing, isReplaced) {
31
         this._jid = jid;
33
         this._jid = jid;
32
         this._id = Strophe.getResourceFromJid(jid);
34
         this._id = Strophe.getResourceFromJid(jid);
33
         this._conference = conference;
35
         this._conference = conference;
41
         this._connectionStatus = ParticipantConnectionStatus.ACTIVE;
43
         this._connectionStatus = ParticipantConnectionStatus.ACTIVE;
42
         this._properties = {};
44
         this._properties = {};
43
         this._identity = identity;
45
         this._identity = identity;
46
+        this._isReplacing = isReplacing;
47
+        this._isReplaced = isReplaced;
44
         this._features = new Set();
48
         this._features = new Set();
45
     }
49
     }
46
 
50
 
186
         return this._hidden;
190
         return this._hidden;
187
     }
191
     }
188
 
192
 
193
+    /**
194
+     * @returns {Boolean} Wheter this participants replaces another participant
195
+     * from the meeting.
196
+     */
197
+    isReplacing() {
198
+        return this._isReplacing;
199
+    }
200
+
201
+    /**
202
+     * @returns {Boolean} Wheter this participants will be replaced by another
203
+     * participant in the meeting.
204
+     */
205
+    isReplaced() {
206
+        return this._isReplaced;
207
+    }
208
+
189
     /**
209
     /**
190
      * @returns {Boolean} Whether this participant has muted their audio.
210
      * @returns {Boolean} Whether this participant has muted their audio.
191
      */
211
      */
233
         this._role = newRole;
253
         this._role = newRole;
234
     }
254
     }
235
 
255
 
256
+    /**
257
+     * Sets whether participant is replacing another based on jwt.
258
+     * @param {String} newIsReplacing - whether is replacing.
259
+     */
260
+    setIsReplacing(newIsReplacing) {
261
+        this._isReplacing = newIsReplacing;
262
+    }
263
+
264
+    /**
265
+     * Sets whether participant is being replaced by another based on jwt.
266
+     * @param {String} newIsReplacing - whether is being replaced.
267
+     */
268
+    setIsReplaced(newIsReplaced) {
269
+        this._isReplaced = newIsReplaced;
270
+    }
271
+
236
     /**
272
     /**
237
      *
273
      *
238
      */
274
      */

+ 15
- 4
modules/xmpp/ChatRoom.js View File

116
         this.roomjid = Strophe.getBareJidFromJid(jid);
116
         this.roomjid = Strophe.getBareJidFromJid(jid);
117
         this.myroomjid = jid;
117
         this.myroomjid = jid;
118
         this.password = password;
118
         this.password = password;
119
+        this.replaceParticipant = false;
119
         logger.info(`Joined MUC as ${this.myroomjid}`);
120
         logger.info(`Joined MUC as ${this.myroomjid}`);
120
         this.members = {};
121
         this.members = {};
121
         this.presMap = {};
122
         this.presMap = {};
182
      * @returns {Promise} - resolved when join completes. At the time of this
183
      * @returns {Promise} - resolved when join completes. At the time of this
183
      * writing it's never rejected.
184
      * writing it's never rejected.
184
      */
185
      */
185
-    join(password) {
186
+    join(password, replaceParticipant) {
186
         this.password = password;
187
         this.password = password;
188
+        this.replaceParticipant = replaceParticipant;
187
 
189
 
188
         return new Promise(resolve => {
190
         return new Promise(resolve => {
189
             this.options.disableFocus
191
             this.options.disableFocus
226
         // be considered as joining, and server can send us the message history
228
         // be considered as joining, and server can send us the message history
227
         // for the room on every presence
229
         // for the room on every presence
228
         if (fromJoin) {
230
         if (fromJoin) {
231
+            if (this.replaceParticipant) {
232
+                pres.c('flip_device').up();
233
+            }
234
+
229
             pres.c('x', { xmlns: this.presMap.xns });
235
             pres.c('x', { xmlns: this.presMap.xns });
230
 
236
 
231
             if (this.password) {
237
             if (this.password) {
433
         const mucUserItem
439
         const mucUserItem
434
             = xElement && xElement.getElementsByTagName('item')[0];
440
             = xElement && xElement.getElementsByTagName('item')[0];
435
 
441
 
442
+        member.isReplaceParticipant
443
+            = pres.getElementsByTagName('flip_device').length;
444
+
436
         member.affiliation
445
         member.affiliation
437
             = mucUserItem && mucUserItem.getAttribute('affiliation');
446
             = mucUserItem && mucUserItem.getAttribute('affiliation');
438
         member.role = mucUserItem && mucUserItem.getAttribute('role');
447
         member.role = mucUserItem && mucUserItem.getAttribute('role');
597
                     member.identity,
606
                     member.identity,
598
                     member.botType,
607
                     member.botType,
599
                     member.jid,
608
                     member.jid,
600
-                    member.features);
609
+                    member.features,
610
+                    member.isReplaceParticipant);
601
 
611
 
602
                 // we are reporting the status with the join
612
                 // we are reporting the status with the join
603
                 // so we do not want a second event about status update
613
                 // so we do not want a second event about status update
958
                         + '>status[code="307"]')
968
                         + '>status[code="307"]')
959
                 .length;
969
                 .length;
960
         const membersKeys = Object.keys(this.members);
970
         const membersKeys = Object.keys(this.members);
971
+        const isReplaceParticipant = $(pres).find('flip_device').length;
961
 
972
 
962
         if (isKick) {
973
         if (isKick) {
963
             const actorSelect
974
             const actorSelect
964
                 = $(pres)
975
                 = $(pres)
965
                 .find('>x[xmlns="http://jabber.org/protocol/muc#user"]>item>actor');
976
                 .find('>x[xmlns="http://jabber.org/protocol/muc#user"]>item>actor');
966
-
967
             let actorNick;
977
             let actorNick;
968
 
978
 
969
             if (actorSelect.length) {
979
             if (actorSelect.length) {
988
                 isSelfPresence,
998
                 isSelfPresence,
989
                 actorNick,
999
                 actorNick,
990
                 Strophe.getResourceFromJid(from),
1000
                 Strophe.getResourceFromJid(from),
991
-                reason);
1001
+                reason,
1002
+                isReplaceParticipant);
992
         }
1003
         }
993
 
1004
 
994
         if (isSelfPresence) {
1005
         if (isSelfPresence) {

+ 39
- 4
modules/xmpp/ChatRoom.spec.js View File

177
                 undefined,
177
                 undefined,
178
                 undefined,
178
                 undefined,
179
                 'fulljid',
179
                 'fulljid',
180
-                undefined // features
180
+                undefined, // features
181
+                0 // isReplaceParticipant
181
             ]);
182
             ]);
182
         });
183
         });
183
 
184
 
207
                 undefined,
208
                 undefined,
208
                 undefined,
209
                 undefined,
209
                 'jid=attr',
210
                 'jid=attr',
210
-                undefined); // features
211
+                undefined, // features
212
+                0); // isReplaceParticipant
213
+        });
214
+
215
+        it('parses muc user replacing other user correctly', () => {
216
+            const presStr = '' +
217
+              '<presence to="tojid" from="fromjid">' +
218
+                  '<x xmlns="http://jabber.org/protocol/muc#user">' +
219
+                      '<item jid="jid=attr" affiliation="affiliation-attr" role="role-attr"/>' +
220
+                  '</x>' +
221
+                  '<flip_device />' +
222
+              '</presence>';
223
+            const pres = new DOMParser().parseFromString(presStr, 'text/xml').documentElement;
224
+
225
+            room.onPresence(pres);
226
+            expect(emitterSpy.calls.count()).toEqual(2);
227
+            expect(emitterSpy.calls.argsFor(0)).toEqual([
228
+                XMPPEvents.PRESENCE_RECEIVED,
229
+                jasmine.any(Object)
230
+            ]);
231
+            expect(emitterSpy).toHaveBeenCalledWith(
232
+              XMPPEvents.MUC_MEMBER_JOINED,
233
+              'fromjid',
234
+              undefined, // nick
235
+              'role-attr', // role
236
+              jasmine.any(Boolean), // isHiddenDomain
237
+              undefined, // statsID
238
+              undefined,
239
+              undefined,
240
+              undefined,
241
+              'jid=attr',
242
+              undefined, // features
243
+              1); // isReplaceParticipant
211
         });
244
         });
212
 
245
 
213
         it('parses identity correctly', () => {
246
         it('parses identity correctly', () => {
254
                 expectedIdentity,
287
                 expectedIdentity,
255
                 undefined,
288
                 undefined,
256
                 'fulljid',
289
                 'fulljid',
257
-                undefined // features
290
+                undefined, // features
291
+                0 // isReplaceParticipant
258
             ]);
292
             ]);
259
         });
293
         });
260
 
294
 
287
                 undefined,
321
                 undefined,
288
                 expectedBotType,
322
                 expectedBotType,
289
                 'fulljid',
323
                 'fulljid',
290
-                undefined // features
324
+                undefined, // features
325
+                0 // isReplaceParticipant
291
             ]);
326
             ]);
292
         });
327
         });
293
 
328
 

Loading…
Cancel
Save