소스 검색

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

dev1
hmuresan 3 년 전
부모
커밋
0ed1b4ef04
4개의 변경된 파일112개의 추가작업 그리고 14개의 파일을 삭제
  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 파일 보기

@@ -516,10 +516,12 @@ JitsiConference.prototype._init = function(options = {}) {
516 516
 /**
517 517
  * Joins the conference.
518 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 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,9 +1586,11 @@ JitsiConference.prototype.muteParticipant = function(id, mediaType) {
1584 1586
  * @param botType the member botType, if any
1585 1587
  * @param fullJid the member full jid, if any
1586 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 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 1594
     const id = Strophe.getResourceFromJid(jid);
1591 1595
 
1592 1596
     if (id === 'focus' || this.myUserId() === id) {
@@ -1599,6 +1603,7 @@ JitsiConference.prototype.onMemberJoined = function(
1599 1603
     participant.setRole(role);
1600 1604
     participant.setBotType(botType);
1601 1605
     participant.setFeatures(features);
1606
+    participant.setIsReplacing(isReplaceParticipant);
1602 1607
 
1603 1608
     this.participants[id] = participant;
1604 1609
     this.eventEmitter.emit(
@@ -1727,6 +1732,8 @@ JitsiConference.prototype.onMemberLeft = function(jid) {
1727 1732
         });
1728 1733
 };
1729 1734
 
1735
+/* eslint-disable max-params */
1736
+
1730 1737
 /**
1731 1738
  * Designates an event indicating that we were kicked from the XMPP MUC.
1732 1739
  * @param {boolean} isSelfPresence - whether it is for local participant
@@ -1736,8 +1743,15 @@ JitsiConference.prototype.onMemberLeft = function(jid) {
1736 1743
  * @param {string?} kickedParticipantId - when it is not a kick for local participant,
1737 1744
  * this is the id of the participant which was kicked.
1738 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 1755
     // This check which be true when we kick someone else. With the introduction of lobby
1742 1756
     // the ChatRoom KICKED event is now also emitted for ourselves (the kicker) so we want to
1743 1757
     // avoid emitting an event where `undefined` kicked someone.
@@ -1749,7 +1763,7 @@ JitsiConference.prototype.onMemberKicked = function(isSelfPresence, actorId, kic
1749 1763
 
1750 1764
     if (isSelfPresence) {
1751 1765
         this.eventEmitter.emit(
1752
-            JitsiConferenceEvents.KICKED, actorParticipant, reason);
1766
+            JitsiConferenceEvents.KICKED, actorParticipant, reason, isReplaceParticipant);
1753 1767
 
1754 1768
         this.leave();
1755 1769
 
@@ -1758,6 +1772,8 @@ JitsiConference.prototype.onMemberKicked = function(isSelfPresence, actorId, kic
1758 1772
 
1759 1773
     const kickedParticipant = this.participants[kickedParticipantId];
1760 1774
 
1775
+    kickedParticipant.setIsReplaced(isReplaceParticipant);
1776
+
1761 1777
     this.eventEmitter.emit(
1762 1778
         JitsiConferenceEvents.PARTICIPANT_KICKED, actorParticipant, kickedParticipant, reason);
1763 1779
 };

+ 37
- 1
JitsiParticipant.js 파일 보기

@@ -26,8 +26,10 @@ export default class JitsiParticipant {
26 26
      * @param {string} statsID - optional participant statsID
27 27
      * @param {string} status - the initial status if any.
28 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 33
         this._jid = jid;
32 34
         this._id = Strophe.getResourceFromJid(jid);
33 35
         this._conference = conference;
@@ -41,6 +43,8 @@ export default class JitsiParticipant {
41 43
         this._connectionStatus = ParticipantConnectionStatus.ACTIVE;
42 44
         this._properties = {};
43 45
         this._identity = identity;
46
+        this._isReplacing = isReplacing;
47
+        this._isReplaced = isReplaced;
44 48
         this._features = new Set();
45 49
     }
46 50
 
@@ -186,6 +190,22 @@ export default class JitsiParticipant {
186 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 210
      * @returns {Boolean} Whether this participant has muted their audio.
191 211
      */
@@ -233,6 +253,22 @@ export default class JitsiParticipant {
233 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 파일 보기

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

+ 39
- 4
modules/xmpp/ChatRoom.spec.js 파일 보기

@@ -177,7 +177,8 @@ describe('ChatRoom', () => {
177 177
                 undefined,
178 178
                 undefined,
179 179
                 'fulljid',
180
-                undefined // features
180
+                undefined, // features
181
+                0 // isReplaceParticipant
181 182
             ]);
182 183
         });
183 184
 
@@ -207,7 +208,39 @@ describe('ChatRoom', () => {
207 208
                 undefined,
208 209
                 undefined,
209 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 246
         it('parses identity correctly', () => {
@@ -254,7 +287,8 @@ describe('ChatRoom', () => {
254 287
                 expectedIdentity,
255 288
                 undefined,
256 289
                 'fulljid',
257
-                undefined // features
290
+                undefined, // features
291
+                0 // isReplaceParticipant
258 292
             ]);
259 293
         });
260 294
 
@@ -287,7 +321,8 @@ describe('ChatRoom', () => {
287 321
                 undefined,
288 322
                 expectedBotType,
289 323
                 'fulljid',
290
-                undefined // features
324
+                undefined, // features
325
+                0 // isReplaceParticipant
291 326
             ]);
292 327
         });
293 328
 

Loading…
취소
저장