Browse Source

feat(caps): Implement XEP-0115

master
hristoterezov 8 years ago
parent
commit
3f43e1e4e5

+ 5
- 17
JitsiConference.js View File

1
-/* global Strophe, $, Promise */
1
+/* global Strophe, Promise */
2
 
2
 
3
 var logger = require("jitsi-meet-logger").getLogger(__filename);
3
 var logger = require("jitsi-meet-logger").getLogger(__filename);
4
 import RTC from "./modules/RTC/RTC";
4
 import RTC from "./modules/RTC/RTC";
722
     participant._role = role;
722
     participant._role = role;
723
     this.participants[id] = participant;
723
     this.participants[id] = participant;
724
     this.eventEmitter.emit(JitsiConferenceEvents.USER_JOINED, id, participant);
724
     this.eventEmitter.emit(JitsiConferenceEvents.USER_JOINED, id, participant);
725
-    // XXX Since disco is checked in multiple places (e.g.
726
-    // modules/xmpp/strophe.jingle.js, modules/xmpp/strophe.rayo.js), check it
727
-    // here as well.
728
-    var disco = this.xmpp.connection.disco;
729
-    if (disco) {
730
-        disco.info(
731
-            jid, "node", function(iq) {
732
-                participant._supportsDTMF = $(iq).find(
733
-                    '>query>feature[var="urn:xmpp:jingle:dtmf:0"]').length > 0;
734
-                this.updateDTMFSupport();
735
-            }.bind(this)
736
-        );
737
-    } else {
738
-      // FIXME Should participant._supportsDTMF be assigned false here (and
739
-      // this.updateDTMFSupport invoked)?
740
-    }
725
+    this.xmpp.caps.getFeatures(jid).then(features => {
726
+        participant._supportsDTMF = features.has("urn:xmpp:jingle:dtmf:0");
727
+        this.updateDTMFSupport();
728
+    }, error => logger.error(error));
741
 };
729
 };
742
 
730
 
743
 JitsiConference.prototype.onMemberLeft = function (jid) {
731
 JitsiConference.prototype.onMemberLeft = function (jid) {

+ 22
- 0
JitsiConnection.js View File

118
     return this.xmpp.connectionTimes;
118
     return this.xmpp.connectionTimes;
119
 };
119
 };
120
 
120
 
121
+/**
122
+ * Adds new feature to the list of supported features for the local
123
+ * participant.
124
+ * @param {String} feature the name of the feature.
125
+ * @param {boolean} submit if true - the new list of features will be
126
+ * immediately submitted to the others.
127
+ */
128
+JitsiConnection.prototype.addFeature = function(feature, submit = false) {
129
+    return this.xmpp.caps.addFeature(feature, submit);
130
+};
131
+
132
+/**
133
+ * Removes a feature from the list of supported features for the local
134
+ * participant
135
+ * @param {String} feature the name of the feature.
136
+ * @param {boolean} submit if true - the new list of features will be
137
+ * immediately submitted to the others.
138
+ */
139
+JitsiConnection.prototype.removeFeature = function (feature, submit = false) {
140
+    return this.xmpp.caps.removeFeature(feature, submit);
141
+};
142
+
121
 module.exports = JitsiConnection;
143
 module.exports = JitsiConnection;

+ 9
- 0
JitsiParticipant.js View File

257
     supportsDTMF() {
257
     supportsDTMF() {
258
         return this._supportsDTMF;
258
         return this._supportsDTMF;
259
     }
259
     }
260
+
261
+    /**
262
+     * Returns a set with the features for the participant.
263
+     * @param {int} timeout the timeout in ms for reply from the participant.
264
+     * @returns {Promise<Set<String>, Error>}
265
+     */
266
+    getFeatures(timeout = 5000) {
267
+        return this.conference.xmpp.caps.getFeatures(this._jid, timeout);
268
+    }
260
 }
269
 }

+ 8
- 0
doc/API.md View File

232
     - event - the event
232
     - event - the event
233
     - listener - the listener that will be removed.
233
     - listener - the listener that will be removed.
234
 
234
 
235
+7. addFeature - Adds new feature to the list of supported features for the local participant
236
+    - feature - string, the name of the feature
237
+    - submit - boolean, default false, if true - the new list of features will be immediately submitted to the others.
238
+
239
+8. removeFeature - Removes a feature from the list of supported features for the local participant
240
+    - feature - string, the name of the feature
241
+    - submit - boolean, default false, if true - the new list of features will be immediately submitted to the others.
242
+
235
 JitsiConference
243
 JitsiConference
236
 -----------
244
 -----------
237
 The object represents a conference. We have the following methods to control the conference:
245
 The object represents a conference. We have the following methods to control the conference:

+ 1
- 2
doc/example/index.html View File

4
     <meta charset="UTF-8">
4
     <meta charset="UTF-8">
5
     <title></title>
5
     <title></title>
6
     <script src="libs/jquery-2.1.1.min.js"></script>
6
     <script src="libs/jquery-2.1.1.min.js"></script>
7
-    <script src="libs/strophe/strophe.min.js"></script>
7
+    <script src="libs/strophe/strophe.js"></script>
8
     <script src="libs/strophe/strophe.disco.min.js?v=1"></script>
8
     <script src="libs/strophe/strophe.disco.min.js?v=1"></script>
9
-    <script src="libs/strophe/strophe.caps.jsonly.min.js?v=1"></script>
10
     <script src="../../lib-jitsi-meet.js"></script>
9
     <script src="../../lib-jitsi-meet.js"></script>
11
     <script src="example.js" ></script>
10
     <script src="example.js" ></script>
12
 </head>
11
 </head>

+ 0
- 1
doc/example/libs/strophe/strophe.caps.jsonly.min.js View File

1
-Strophe.addConnectionPlugin("caps",{HASH:"sha-1",node:"http://strophe.im/strophejs/",_ver:"",_connection:null,_knownCapabilities:{},_jidVerIndex:{},init:function(conn){this._connection=conn;Strophe.addNamespace("CAPS","http://jabber.org/protocol/caps");if(!this._connection.disco){throw"Caps plugin requires the disco plugin to be installed."}this._connection.disco.addFeature(Strophe.NS.CAPS);this._connection.addHandler(this._delegateCapabilities.bind(this),Strophe.NS.CAPS)},generateCapsAttrs:function(){return{xmlns:Strophe.NS.CAPS,hash:this.HASH,node:this.node,ver:this.generateVer()}},generateVer:function(){if(this._ver!==""){return this._ver}var ver="",identities=this._connection.disco._identities.sort(this._sortIdentities),identitiesLen=identities.length,features=this._connection.disco._features.sort(),featuresLen=features.length;for(var i=0;i<identitiesLen;i++){var curIdent=identities[i];ver+=curIdent.category+"/"+curIdent.type+"/"+curIdent.lang+"/"+curIdent.name+"<"}for(var i=0;i<featuresLen;i++){ver+=features[i]+"<"}this._ver=b64_sha1(ver);return this._ver},getCapabilitiesByJid:function(jid){if(this._jidVerIndex[jid]){return this._knownCapabilities[this._jidVerIndex[jid]]}return null},_delegateCapabilities:function(stanza){var from=stanza.getAttribute("from"),c=stanza.querySelector("c"),ver=c.getAttribute("ver"),node=c.getAttribute("node");if(!this._knownCapabilities[ver]){return this._requestCapabilities(from,node,ver)}else{this._jidVerIndex[from]=ver}if(!this._jidVerIndex[from]||!this._jidVerIndex[from]!==ver){this._jidVerIndex[from]=ver}return true},_requestCapabilities:function(to,node,ver){if(to!==this._connection.jid){var id=this._connection.disco.info(to,node+"#"+ver);this._connection.addHandler(this._handleDiscoInfoReply.bind(this),Strophe.NS.DISCO_INFO,"iq","result",id,to)}return true},_handleDiscoInfoReply:function(stanza){var query=stanza.querySelector("query"),node=query.getAttribute("node").split("#"),ver=node[1],from=stanza.getAttribute("from");if(!this._knownCapabilities[ver]){var childNodes=query.childNodes,childNodesLen=childNodes.length;this._knownCapabilities[ver]=[];for(var i=0;i<childNodesLen;i++){var node=childNodes[i];this._knownCapabilities[ver].push({name:node.nodeName,attributes:node.attributes})}this._jidVerIndex[from]=ver}else{if(!this._jidVerIndex[from]||!this._jidVerIndex[from]!==ver){this._jidVerIndex[from]=ver}}return false},_sortIdentities:function(a,b){if(a.category>b.category){return 1}if(a.category<b.category){return -1}if(a.type>b.type){return 1}if(a.type<b.type){return -1}if(a.lang>b.lang){return 1}if(a.lang<b.lang){return -1}return 0}});

+ 210
- 0
modules/xmpp/Caps.js View File

1
+/* global $, b64_sha1, Strophe */
2
+import XMPPEvents from "../../service/xmpp/XMPPEvents";
3
+
4
+/**
5
+ * The property
6
+ */
7
+const IDENTITY_PROPERTIES = ["category", "type", "lang", "name"];
8
+const IDENTITY_PROPERTIES_FOR_COMPARE = ["category", "type", "lang"];
9
+const HASH = "sha-1";
10
+
11
+function compareIdentities(a, b) {
12
+    let res = 0;
13
+    IDENTITY_PROPERTIES_FOR_COMPARE.some(key =>
14
+        (res = ((a[key] > b[key]) && 1) || ((a[key] < b[key]) && -1)) !== 0
15
+    );
16
+    return res;
17
+}
18
+
19
+/**
20
+ * Implements xep-0115 ( http://xmpp.org/extensions/xep-0115.html )
21
+ */
22
+export default class Caps {
23
+    /**
24
+     * Constructs new Caps instance.
25
+     * @param {Strophe.Connection} connection the strophe connection object
26
+     * @param {String} node the value of the node attribute of the "c" xml node
27
+     * that will be sent to the other participants
28
+     */
29
+    constructor(connection = {}, node = "http://jitsi.org/jitsimeet") {
30
+        this.node = node;
31
+        this.disco = connection.disco;
32
+        if(!this.disco) {
33
+            throw new Error(
34
+                "Missing strophe-plugins "
35
+                + "(disco and caps plugins are required)!");
36
+        }
37
+
38
+        this.versionToCapabilities = Object.create(null);
39
+        this.jidToVersion = Object.create(null);
40
+        this.version = "";
41
+        this.rooms = new Set();
42
+
43
+        const emuc = connection.emuc;
44
+        emuc.addListener(XMPPEvents.EMUC_ROOM_ADDED,
45
+            room => this._addChatRoom(room));
46
+        emuc.addListener(XMPPEvents.EMUC_ROOM_REMOVED,
47
+            room => this._removeChatRoom(room));
48
+        for(let jid in emuc.rooms) {
49
+            this._addChatRoom(this.emuc.rooms[jid]);
50
+        }
51
+
52
+        Strophe.addNamespace("CAPS", "http://jabber.org/protocol/caps");
53
+        this.disco.addFeature(Strophe.NS.CAPS);
54
+        connection.addHandler(this._handleCaps.bind(this), Strophe.NS.CAPS);
55
+
56
+        this._onMucMemberLeft = this._removeJidToVersionEntry.bind(this);
57
+    }
58
+
59
+    /**
60
+     * Adds new feature to the list of supported features for the local
61
+     * participant
62
+     * @param {String} feature the name of the feature.
63
+     * @param {boolean} submit if true - new presence with updated "c" node
64
+     * will be sent.
65
+     */
66
+    addFeature(feature, submit = false) {
67
+        this.disco.addFeature(feature);
68
+        this._generateVersion();
69
+        if(submit) {
70
+            this.submit();
71
+        }
72
+    }
73
+
74
+    /**
75
+     * Removes a feature from the list of supported features for the local
76
+     * participant
77
+     * @param {String} feature the name of the feature.
78
+     * @param {boolean} submit if true - new presence with updated "c" node
79
+     * will be sent.
80
+     */
81
+    removeFeature(feature, submit = false) {
82
+        this.disco.removeFeature(feature);
83
+        this._generateVersion();
84
+        if(submit) {
85
+            this.submit();
86
+        }
87
+    }
88
+
89
+    /**
90
+     * Sends new presence stanza for every room from the list of rooms.
91
+     */
92
+    submit() {
93
+        this.rooms.forEach(room => room.sendPresence());
94
+    }
95
+
96
+    /**
97
+     * Returns a set with the features for a participant.
98
+     * @param {String} jid the jid of the participant
99
+     * @param {int} timeout the timeout in ms for reply from the participant.
100
+     * @returns {Promise<Set<String>, Error>}
101
+     */
102
+    getFeatures(jid, timeout = 5000) {
103
+        let user
104
+            = (jid in this.jidToVersion) ? this.jidToVersion[jid] : null;
105
+        if(!user || !(user.version in this.versionToCapabilities))
106
+        {
107
+            const node = (user)? user.node + "#" + user.version : null;
108
+            return new Promise ( (resolve, reject) =>
109
+                this.disco.info(jid, node, response => {
110
+                        const features = new Set();
111
+                        $(response).find(">query>feature").each((idx, el) =>
112
+                            features.add(el.getAttribute("var")));
113
+                        if(user) {
114
+                            this.versionToCapabilities[user.version]
115
+                                = features;
116
+                        }
117
+                        resolve(features);
118
+                    }, reject , timeout)
119
+            );
120
+        }
121
+        return Promise.resolve(this.versionToCapabilities[user.version]);
122
+    }
123
+
124
+    /**
125
+     * Adds ChatRoom instance to the list of rooms. Adds listeners to the room
126
+     * and adds "c" element to the presences of the room.
127
+     * @param {ChatRoom} room the room.
128
+     */
129
+    _addChatRoom(room) {
130
+        this.rooms.add(room);
131
+        room.addListener(XMPPEvents.MUC_MEMBER_LEFT, this._onMucMemberLeft);
132
+        this._fixChatRoomPresenceMap(room);
133
+    }
134
+
135
+    /**
136
+     * Removes ChatRoom instance from the list of rooms. Removes listeners
137
+     * added from the Caps class.
138
+     * @param {ChatRoom} room the room.
139
+     */
140
+    _removeChatRoom(room) {
141
+        this.rooms.delete(room);
142
+        room.removeListener(XMPPEvents.MUC_MEMBER_LEFT, this._onMucMemberLeft);
143
+    }
144
+
145
+    /**
146
+     * Creates/updates the "c" xml node into the presence of the passed room.
147
+     * @param {ChatRoom} room the room.
148
+     */
149
+    _fixChatRoomPresenceMap(room) {
150
+        room.addToPresence("c", {
151
+            attributes: {
152
+                xmlns: Strophe.NS.CAPS,
153
+                hash: HASH,
154
+                node: this.node,
155
+                ver: this.version
156
+            }
157
+        });
158
+    }
159
+
160
+    /**
161
+     * Handles this.version changes.
162
+     */
163
+    _notifyVersionChanged() {
164
+        //update the version for all rooms
165
+        this.rooms.forEach(room => this._fixChatRoomPresenceMap(room));
166
+        this.submit();
167
+    }
168
+
169
+    /**
170
+     * Generates the value for the "ver" attribute.
171
+     */
172
+    _generateVersion() {
173
+        const identities = this.disco._identities.sort(compareIdentities);
174
+        const features = this.disco._features.sort();
175
+        this.version = b64_sha1(
176
+            identities.reduce(
177
+                (accumulatedValue, identity) => {
178
+                    return IDENTITY_PROPERTIES.reduce((tmp, key, idx) => {
179
+                        return (idx === 0 ? "" : "/") + identity[key];
180
+                    }, "") + "<";
181
+                }, ""
182
+            ) + features.reduce((tmp, feature) => feature + "<", "")
183
+        );
184
+        this._notifyVersionChanged();
185
+    }
186
+
187
+    /**
188
+     * Parses the "c" xml node from presence.
189
+     * @param {DOMElement} stanza the presence packet
190
+     */
191
+    _handleCaps(stanza) {
192
+        const from = stanza.getAttribute("from");
193
+        const caps = stanza.querySelector("c");
194
+        const version = caps.getAttribute("ver");
195
+        const node = caps.getAttribute("node");
196
+        this.jidToVersion[from] = {version, node};
197
+        // return true to not remove the handler from Strophe
198
+        return true;
199
+    }
200
+
201
+    /**
202
+     * Removes entry from this.jidToVersion map.
203
+     * @param {String} jid the jid to be removed.
204
+     */
205
+    _removeJidToVersionEntry(jid) {
206
+        if(jid in this.jidToVersion) {
207
+            delete this.jidToVersion[jid];
208
+        }
209
+    }
210
+}

+ 2
- 10
modules/xmpp/ChatRoom.js View File

152
             pres.up();
152
             pres.up();
153
         }
153
         }
154
 
154
 
155
-        // Send XEP-0115 'c' stanza that contains our capabilities info
156
-        var connection = this.connection;
157
-        var caps = connection.caps;
158
-        if (caps) {
159
-            caps.node = this.xmpp.options.clientNode;
160
-            pres.c('c', caps.generateCapsAttrs()).up();
161
-        }
162
-
163
         parser.JSON2packet(this.presMap.nodes, pres);
155
         parser.JSON2packet(this.presMap.nodes, pres);
164
-        connection.send(pres);
156
+        this.connection.send(pres);
165
         if (fromJoin) {
157
         if (fromJoin) {
166
             // XXX We're pressed for time here because we're beginning a complex
158
             // XXX We're pressed for time here because we're beginning a complex
167
             // and/or lengthy conference-establishment process which supposedly
159
             // and/or lengthy conference-establishment process which supposedly
168
             // involves multiple RTTs. We don't have the time to wait for Strophe to
160
             // involves multiple RTTs. We don't have the time to wait for Strophe to
169
             // decide to send our IQ.
161
             // decide to send our IQ.
170
-            connection.flush();
162
+            this.connection.flush();
171
         }
163
         }
172
     }
164
     }
173
 
165
 

+ 29
- 8
modules/xmpp/ConnectionPlugin.js View File

1
+import Listenable from "../util/Listenable";
2
+
1
 /**
3
 /**
2
- * Base class for strophe connection plugins.
4
+ * Creates ConnectionPlugin class that extends the passed class.
5
+ * @param {Class} base the definition of the class that will be extended by
6
+ * ConnectionPlugin
3
  */
7
  */
4
-export default class ConnectionPlugin {
5
-    constructor() {
6
-        this.connection = null;
7
-    }
8
-    init (connection) {
9
-        this.connection = connection;
10
-    }
8
+function getConnectionPluginDefinition(base = class{}) {
9
+    /**
10
+     * Base class for strophe connection plugins.
11
+     */
12
+    return class extends base {
13
+        constructor(...args) {
14
+            super(...args);
15
+            this.connection = null;
16
+        }
17
+        init (connection) {
18
+            this.connection = connection;
19
+        }
20
+    };
11
 }
21
 }
22
+
23
+/**
24
+ * ConnectionPlugin class.
25
+ */
26
+export default getConnectionPluginDefinition();
27
+
28
+/**
29
+ * ConnectionPlugin class that extends Listenable.
30
+ */
31
+export const ConnectionPluginListenable
32
+    = getConnectionPluginDefinition(Listenable);

+ 7
- 2
modules/xmpp/strophe.emuc.js View File

7
 import {getLogger} from "jitsi-meet-logger";
7
 import {getLogger} from "jitsi-meet-logger";
8
 const logger = getLogger(__filename);
8
 const logger = getLogger(__filename);
9
 import ChatRoom from "./ChatRoom";
9
 import ChatRoom from "./ChatRoom";
10
-import ConnectionPlugin from "./ConnectionPlugin";
10
+import {ConnectionPluginListenable} from "./ConnectionPlugin";
11
+import XMPPEvents from "../../service/xmpp/XMPPEvents";
11
 
12
 
12
-class MucConnectionPlugin extends ConnectionPlugin {
13
+class MucConnectionPlugin extends ConnectionPluginListenable {
13
     constructor(xmpp) {
14
     constructor(xmpp) {
14
         super();
15
         super();
15
         this.xmpp = xmpp;
16
         this.xmpp = xmpp;
40
         }
41
         }
41
         this.rooms[roomJid] = new ChatRoom(this.connection, jid,
42
         this.rooms[roomJid] = new ChatRoom(this.connection, jid,
42
             password, this.xmpp, options);
43
             password, this.xmpp, options);
44
+        this.eventEmitter.emit(
45
+            XMPPEvents.EMUC_ROOM_ADDED, this.rooms[roomJid]);
43
         return this.rooms[roomJid];
46
         return this.rooms[roomJid];
44
     }
47
     }
45
 
48
 
46
     doLeave (jid) {
49
     doLeave (jid) {
50
+        this.eventEmitter.emit(
51
+            XMPPEvents.EMUC_ROOM_REMOVED, this.rooms[jid]);
47
         delete this.rooms[jid];
52
         delete this.rooms[jid];
48
     }
53
     }
49
 
54
 

+ 18
- 28
modules/xmpp/strophe.ping.js View File

1
-/* global $, $iq, Strophe */
1
+/* global $iq, Strophe */
2
 
2
 
3
 import { getLogger } from "jitsi-meet-logger";
3
 import { getLogger } from "jitsi-meet-logger";
4
 const logger = getLogger(__filename);
4
 const logger = getLogger(__filename);
20
  */
20
  */
21
 const PING_THRESHOLD = 3;
21
 const PING_THRESHOLD = 3;
22
 
22
 
23
-
24
-
25
-
26
 /**
23
 /**
27
  * XEP-0199 ping plugin.
24
  * XEP-0199 ping plugin.
28
  *
25
  *
29
  * Registers "urn:xmpp:ping" namespace under Strophe.NS.PING.
26
  * Registers "urn:xmpp:ping" namespace under Strophe.NS.PING.
30
  */
27
  */
31
 class PingConnectionPlugin extends ConnectionPlugin {
28
 class PingConnectionPlugin extends ConnectionPlugin {
32
-    constructor() {
29
+    /**
30
+     * Contructs new object
31
+     * @param {XMPP} xmpp the xmpp module.
32
+     * @constructor
33
+     */
34
+    constructor(xmpp) {
33
         super();
35
         super();
34
         this.failedPings = 0;
36
         this.failedPings = 0;
37
+        this.xmpp = xmpp;
35
     }
38
     }
36
 
39
 
37
     /**
40
     /**
65
      * <tt>true</tt> if XEP-0199 ping is supported by given <tt>jid</tt>
68
      * <tt>true</tt> if XEP-0199 ping is supported by given <tt>jid</tt>
66
      */
69
      */
67
     hasPingSupport (jid, callback) {
70
     hasPingSupport (jid, callback) {
68
-        const disco = this.connection.disco;
69
-        // XXX The following disco.info was observed to throw a "TypeError:
70
-        // Cannot read property 'info' of undefined" during porting to React
71
-        // Native. Since disco is checked in multiple places (e.g.
72
-        // strophe.jingle.js, strophe.rayo.js), check it here as well.
73
-        if (disco) {
74
-            disco.info(jid, null, (result)  => {
75
-                const ping
76
-                    = $(result).find('>>feature[var="urn:xmpp:ping"]');
77
-                callback(ping.length > 0);
78
-            }, (error) => {
79
-                const errmsg = "Ping feature discovery error";
80
-                GlobalOnErrorHandler.callErrorHandler(new Error(
81
-                    errmsg + ": " + error));
82
-                logger.error(errmsg, error);
83
-                callback(false);
84
-            });
85
-        } else {
86
-          // FIXME Should callback be invoked here? Maybe with false as an
87
-          // argument?
88
-        }
71
+        this.xmpp.caps.getFeatures(jid).then(features =>
72
+            callback(features.has("urn:xmpp:ping")), error => {
73
+            const errmsg = "Ping feature discovery error";
74
+            GlobalOnErrorHandler.callErrorHandler(new Error(
75
+                errmsg + ": " + error));
76
+            logger.error(errmsg, error);
77
+            callback(false);
78
+        });
89
     }
79
     }
90
 
80
 
91
     /**
81
     /**
138
     }
128
     }
139
 }
129
 }
140
 
130
 
141
-export default function () {
142
-    Strophe.addConnectionPlugin('ping', new PingConnectionPlugin());
131
+export default function (xmpp) {
132
+    Strophe.addConnectionPlugin('ping', new PingConnectionPlugin(xmpp));
143
 }
133
 }

+ 0
- 4
modules/xmpp/strophe.rayo.js View File

9
 class RayoConnectionPlugin extends ConnectionPlugin {
9
 class RayoConnectionPlugin extends ConnectionPlugin {
10
     init (connection) {
10
     init (connection) {
11
         super.init(connection);
11
         super.init(connection);
12
-        const disco = this.connection.disco;
13
-        if (disco) {
14
-            disco.addFeature('urn:xmpp:rayo:client:1');
15
-        }
16
 
12
 
17
         this.connection.addHandler(
13
         this.connection.addHandler(
18
             this.onRayo.bind(this), RAYO_XMLNS, 'iq', 'set', null, null);
14
             this.onRayo.bind(this), RAYO_XMLNS, 'iq', 'set', null, null);

+ 23
- 22
modules/xmpp/xmpp.js View File

13
 import initRayo from "./strophe.rayo";
13
 import initRayo from "./strophe.rayo";
14
 import initStropheLogger from "./strophe.logger";
14
 import initStropheLogger from "./strophe.logger";
15
 import Listenable from "../util/Listenable";
15
 import Listenable from "../util/Listenable";
16
+import Caps from "./Caps";
16
 
17
 
17
 function createConnection(token, bosh = '/http-bind') {
18
 function createConnection(token, bosh = '/http-bind') {
18
     // Append token as URL param
19
     // Append token as URL param
38
 
39
 
39
         this.connection = createConnection(token, options.bosh);
40
         this.connection = createConnection(token, options.bosh);
40
 
41
 
41
-        if(!this.connection.disco || !this.connection.caps)
42
-            throw new Error(
43
-                "Missing strophe-plugins (disco and caps plugins are required)!");
42
+        this.caps = new Caps(this.connection, this.options.clientNode);
44
 
43
 
45
         // Initialize features advertised in disco-info
44
         // Initialize features advertised in disco-info
46
         this.initFeaturesList();
45
         this.initFeaturesList();
57
      * Initializes the list of feature advertised through the disco-info mechanism
56
      * Initializes the list of feature advertised through the disco-info mechanism
58
      */
57
      */
59
     initFeaturesList () {
58
     initFeaturesList () {
60
-        const disco = this.connection.disco;
61
-        if (!disco)
62
-            return;
63
-
64
         // http://xmpp.org/extensions/xep-0167.html#support
59
         // http://xmpp.org/extensions/xep-0167.html#support
65
         // http://xmpp.org/extensions/xep-0176.html#support
60
         // http://xmpp.org/extensions/xep-0176.html#support
66
-        disco.addFeature('urn:xmpp:jingle:1');
67
-        disco.addFeature('urn:xmpp:jingle:apps:rtp:1');
68
-        disco.addFeature('urn:xmpp:jingle:transports:ice-udp:1');
69
-        disco.addFeature('urn:xmpp:jingle:apps:dtls:0');
70
-        disco.addFeature('urn:xmpp:jingle:transports:dtls-sctp:1');
71
-        disco.addFeature('urn:xmpp:jingle:apps:rtp:audio');
72
-        disco.addFeature('urn:xmpp:jingle:apps:rtp:video');
61
+        this.caps.addFeature('urn:xmpp:jingle:1');
62
+        this.caps.addFeature('urn:xmpp:jingle:apps:rtp:1');
63
+        this.caps.addFeature('urn:xmpp:jingle:transports:ice-udp:1');
64
+        this.caps.addFeature('urn:xmpp:jingle:apps:dtls:0');
65
+        this.caps.addFeature('urn:xmpp:jingle:transports:dtls-sctp:1');
66
+        this.caps.addFeature('urn:xmpp:jingle:apps:rtp:audio');
67
+        this.caps.addFeature('urn:xmpp:jingle:apps:rtp:video');
73
 
68
 
74
         if (RTCBrowserType.isChrome() || RTCBrowserType.isOpera()
69
         if (RTCBrowserType.isChrome() || RTCBrowserType.isOpera()
75
             || RTCBrowserType.isTemasysPluginUsed()) {
70
             || RTCBrowserType.isTemasysPluginUsed()) {
76
-            disco.addFeature('urn:ietf:rfc:4588');
71
+            this.caps.addFeature('urn:ietf:rfc:4588');
77
         }
72
         }
78
 
73
 
79
         // this is dealt with by SDP O/A so we don't need to announce this
74
         // this is dealt with by SDP O/A so we don't need to announce this
80
-        //disco.addFeature('urn:xmpp:jingle:apps:rtp:rtcp-fb:0'); // XEP-0293
81
-        //disco.addFeature('urn:xmpp:jingle:apps:rtp:rtp-hdrext:0'); // XEP-0294
75
+        // XEP-0293
76
+        //this.caps.addFeature('urn:xmpp:jingle:apps:rtp:rtcp-fb:0');
77
+        // XEP-0294
78
+        //this.caps.addFeature('urn:xmpp:jingle:apps:rtp:rtp-hdrext:0');
82
 
79
 
83
-        disco.addFeature('urn:ietf:rfc:5761'); // rtcp-mux
84
-        disco.addFeature('urn:ietf:rfc:5888'); // a=group, e.g. bundle
80
+        this.caps.addFeature('urn:ietf:rfc:5761'); // rtcp-mux
81
+        this.caps.addFeature('urn:ietf:rfc:5888'); // a=group, e.g. bundle
85
 
82
 
86
-        //disco.addFeature('urn:ietf:rfc:5576'); // a=ssrc
83
+        //this.caps.addFeature('urn:ietf:rfc:5576'); // a=ssrc
87
 
84
 
88
         // Enable Lipsync ?
85
         // Enable Lipsync ?
89
         if (RTCBrowserType.isChrome() && false !== this.options.enableLipSync) {
86
         if (RTCBrowserType.isChrome() && false !== this.options.enableLipSync) {
90
             logger.info("Lip-sync enabled !");
87
             logger.info("Lip-sync enabled !");
91
-            disco.addFeature('http://jitsi.org/meet/lipsync');
88
+            this.caps.addFeature('http://jitsi.org/meet/lipsync');
89
+        }
90
+
91
+        if(this.connection.rayo) {
92
+            this.caps.addFeature('urn:xmpp:rayo:client:1');
92
         }
93
         }
93
     }
94
     }
94
 
95
 
371
         initEmuc(this);
372
         initEmuc(this);
372
         initJingle(this, this.eventEmitter);
373
         initJingle(this, this.eventEmitter);
373
         initStropheUtil();
374
         initStropheUtil();
374
-        initPing(this, this.eventEmitter);
375
+        initPing(this);
375
         initRayo();
376
         initRayo();
376
         initStropheLogger();
377
         initStropheLogger();
377
     }
378
     }

+ 8
- 0
service/xmpp/XMPPEvents.js View File

43
     // Designates an event indicating that the display name of a participant
43
     // Designates an event indicating that the display name of a participant
44
     // has changed.
44
     // has changed.
45
     DISPLAY_NAME_CHANGED: "xmpp.display_name_changed",
45
     DISPLAY_NAME_CHANGED: "xmpp.display_name_changed",
46
+    /**
47
+     * Chat room instance have been added to Strophe.emuc plugin.
48
+     */
49
+    EMUC_ROOM_ADDED: "xmpp.emuc_room_added",
50
+    /**
51
+     * Chat room instance have been removed from Strophe.emuc plugin.
52
+     */
53
+    EMUC_ROOM_REMOVED: "xmpp.emuc_room_removed",
46
     ETHERPAD: "xmpp.etherpad",
54
     ETHERPAD: "xmpp.etherpad",
47
     FOCUS_DISCONNECTED: 'xmpp.focus_disconnected',
55
     FOCUS_DISCONNECTED: 'xmpp.focus_disconnected',
48
     FOCUS_LEFT: "xmpp.focus_left",
56
     FOCUS_LEFT: "xmpp.focus_left",

Loading…
Cancel
Save