quickblox 2.17.2-beta.2-logger → 2.17.3-logger

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 (124) hide show
  1. package/LICENSE +330 -201
  2. package/README.md +2 -2
  3. package/package.json +1 -2
  4. package/quickblox.js +19389 -21772
  5. package/quickblox.min.js +1 -1
  6. package/src/libs/strophe/strophe.common.js +6657 -0
  7. package/src/libs/strophe/strophe.esm.js +6649 -0
  8. package/src/libs/strophe/strophe.umd.js +6862 -0
  9. package/src/libs/strophe/strophe.umd.min.js +1 -0
  10. package/src/modules/chat/qbChat.js +131 -11
  11. package/src/modules/webrtc/qbWebRTCSignalingProcessor.js +2 -1
  12. package/src/modules/webrtc/qbWebRTCSignalingProvider.js +2 -1
  13. package/src/qbConfig.js +2 -2
  14. package/src/qbProxy.js +1 -1
  15. package/src/qbStrophe.js +2 -6
  16. package/strophejs-1.4.0/.eslintrc.json +264 -0
  17. package/strophejs-1.4.0/.gitattributes +1 -0
  18. package/strophejs-1.4.0/CHANGELOG.md +250 -0
  19. package/strophejs-1.4.0/LICENSE.txt +19 -0
  20. package/strophejs-1.4.0/Makefile +92 -0
  21. package/strophejs-1.4.0/README.md +45 -0
  22. package/strophejs-1.4.0/RELEASE_CHECKLIST.md +16 -0
  23. package/strophejs-1.4.0/contrib/discojs/README.txt +42 -0
  24. package/strophejs-1.4.0/contrib/discojs/css/disco.css +16 -0
  25. package/strophejs-1.4.0/contrib/discojs/index.html +47 -0
  26. package/strophejs-1.4.0/contrib/discojs/punjab.tac +18 -0
  27. package/strophejs-1.4.0/contrib/discojs/scripts/basic.js +102 -0
  28. package/strophejs-1.4.0/contrib/discojs/scripts/disco.js +60 -0
  29. package/strophejs-1.4.0/docs.css +797 -0
  30. package/strophejs-1.4.0/examples/amd.html +21 -0
  31. package/strophejs-1.4.0/examples/attach/README +37 -0
  32. package/strophejs-1.4.0/examples/attach/__init__.py +0 -0
  33. package/strophejs-1.4.0/examples/attach/attacher/__init__.py +0 -0
  34. package/strophejs-1.4.0/examples/attach/attacher/views.py +18 -0
  35. package/strophejs-1.4.0/examples/attach/boshclient.py +158 -0
  36. package/strophejs-1.4.0/examples/attach/manage.py +11 -0
  37. package/strophejs-1.4.0/examples/attach/settings.py +85 -0
  38. package/strophejs-1.4.0/examples/attach/templates/attacher/index.html +88 -0
  39. package/strophejs-1.4.0/examples/attach/urls.py +19 -0
  40. package/strophejs-1.4.0/examples/basic.html +23 -0
  41. package/strophejs-1.4.0/examples/basic.js +73 -0
  42. package/strophejs-1.4.0/examples/echobot.html +25 -0
  43. package/strophejs-1.4.0/examples/echobot.js +79 -0
  44. package/strophejs-1.4.0/examples/main.js +59 -0
  45. package/strophejs-1.4.0/examples/prebind.html +39 -0
  46. package/strophejs-1.4.0/examples/prebind.js +103 -0
  47. package/strophejs-1.4.0/examples/restore.html +24 -0
  48. package/strophejs-1.4.0/examples/restore.js +71 -0
  49. package/strophejs-1.4.0/package-lock.json +8631 -0
  50. package/strophejs-1.4.0/package.json +84 -0
  51. package/strophejs-1.4.0/rollup.config.js +76 -0
  52. package/strophejs-1.4.0/src/bosh.js +916 -0
  53. package/strophejs-1.4.0/src/core.js +3530 -0
  54. package/strophejs-1.4.0/src/md5.js +204 -0
  55. package/strophejs-1.4.0/src/sha1.js +172 -0
  56. package/strophejs-1.4.0/src/shared-connection-worker.js +114 -0
  57. package/strophejs-1.4.0/src/shims.js +123 -0
  58. package/strophejs-1.4.0/src/strophe.js +14 -0
  59. package/strophejs-1.4.0/src/utils.js +63 -0
  60. package/strophejs-1.4.0/src/websocket.js +557 -0
  61. package/strophejs-1.4.0/src/worker-websocket.js +150 -0
  62. package/strophejs-1.4.0/tests/index.html +21 -0
  63. package/strophejs-1.4.0/tests/main.js +49 -0
  64. package/strophejs-1.4.0/tests/tests.js +929 -0
  65. package/strophejs-1.6.1/.eslintrc.json +264 -0
  66. package/strophejs-1.6.1/.gitattributes +1 -0
  67. package/strophejs-1.6.1/.nvmrc +1 -0
  68. package/strophejs-1.6.1/CHANGELOG.md +288 -0
  69. package/strophejs-1.6.1/LICENSE.txt +19 -0
  70. package/strophejs-1.6.1/Makefile +92 -0
  71. package/strophejs-1.6.1/README.md +46 -0
  72. package/strophejs-1.6.1/RELEASE_CHECKLIST.md +18 -0
  73. package/strophejs-1.6.1/babel.config.json +10 -0
  74. package/strophejs-1.6.1/contrib/discojs/README.txt +42 -0
  75. package/strophejs-1.6.1/contrib/discojs/css/disco.css +16 -0
  76. package/strophejs-1.6.1/contrib/discojs/index.html +47 -0
  77. package/strophejs-1.6.1/contrib/discojs/punjab.tac +18 -0
  78. package/strophejs-1.6.1/contrib/discojs/scripts/basic.js +102 -0
  79. package/strophejs-1.6.1/contrib/discojs/scripts/disco.js +60 -0
  80. package/strophejs-1.6.1/docs.css +797 -0
  81. package/strophejs-1.6.1/examples/amd.html +21 -0
  82. package/strophejs-1.6.1/examples/attach/README +37 -0
  83. package/strophejs-1.6.1/examples/attach/__init__.py +0 -0
  84. package/strophejs-1.6.1/examples/attach/attacher/__init__.py +0 -0
  85. package/strophejs-1.6.1/examples/attach/attacher/views.py +18 -0
  86. package/strophejs-1.6.1/examples/attach/boshclient.py +158 -0
  87. package/strophejs-1.6.1/examples/attach/manage.py +11 -0
  88. package/strophejs-1.6.1/examples/attach/settings.py +85 -0
  89. package/strophejs-1.6.1/examples/attach/templates/attacher/index.html +88 -0
  90. package/strophejs-1.6.1/examples/attach/urls.py +19 -0
  91. package/strophejs-1.6.1/examples/basic.html +23 -0
  92. package/strophejs-1.6.1/examples/basic.js +73 -0
  93. package/strophejs-1.6.1/examples/echobot.html +25 -0
  94. package/strophejs-1.6.1/examples/echobot.js +79 -0
  95. package/strophejs-1.6.1/examples/main.js +59 -0
  96. package/strophejs-1.6.1/examples/prebind.html +39 -0
  97. package/strophejs-1.6.1/examples/prebind.js +103 -0
  98. package/strophejs-1.6.1/examples/restore.html +24 -0
  99. package/strophejs-1.6.1/examples/restore.js +71 -0
  100. package/strophejs-1.6.1/package-lock.json +18461 -0
  101. package/strophejs-1.6.1/package.json +87 -0
  102. package/strophejs-1.6.1/rollup.config.js +70 -0
  103. package/strophejs-1.6.1/src/bosh.js +916 -0
  104. package/strophejs-1.6.1/src/builder.js +239 -0
  105. package/strophejs-1.6.1/src/constants.js +155 -0
  106. package/strophejs-1.6.1/src/core.js +2377 -0
  107. package/strophejs-1.6.1/src/sasl-anon.js +17 -0
  108. package/strophejs-1.6.1/src/sasl-external.js +27 -0
  109. package/strophejs-1.6.1/src/sasl-oauthbearer.js +30 -0
  110. package/strophejs-1.6.1/src/sasl-plain.js +32 -0
  111. package/strophejs-1.6.1/src/sasl-sha1.js +24 -0
  112. package/strophejs-1.6.1/src/sasl-sha256.js +24 -0
  113. package/strophejs-1.6.1/src/sasl-sha384.js +24 -0
  114. package/strophejs-1.6.1/src/sasl-sha512.js +24 -0
  115. package/strophejs-1.6.1/src/sasl-xoauth2.js +27 -0
  116. package/strophejs-1.6.1/src/sasl.js +143 -0
  117. package/strophejs-1.6.1/src/scram.js +182 -0
  118. package/strophejs-1.6.1/src/shared-connection-worker.js +114 -0
  119. package/strophejs-1.6.1/src/shims.js +122 -0
  120. package/strophejs-1.6.1/src/strophe.js +15 -0
  121. package/strophejs-1.6.1/src/utils.js +626 -0
  122. package/strophejs-1.6.1/src/websocket.js +556 -0
  123. package/strophejs-1.6.1/src/worker-websocket.js +149 -0
  124. package/strophejs-1.6.1/tests.js +993 -0
@@ -0,0 +1,557 @@
1
+ /*
2
+ This program is distributed under the terms of the MIT license.
3
+ Please see the LICENSE file for details.
4
+
5
+ Copyright 2006-2008, OGG, LLC
6
+ */
7
+
8
+ /* global window, clearTimeout, WebSocket, DOMParser */
9
+
10
+ import { DOMParser, Websocket } from './shims'; // eslint-disable-line no-unused-vars
11
+ import { $build, Strophe } from './core';
12
+
13
+
14
+ /** Class: Strophe.WebSocket
15
+ * _Private_ helper class that handles WebSocket Connections
16
+ *
17
+ * The Strophe.WebSocket class is used internally by Strophe.Connection
18
+ * to encapsulate WebSocket sessions. It is not meant to be used from user's code.
19
+ */
20
+
21
+ /** File: websocket.js
22
+ * A JavaScript library to enable XMPP over Websocket in Strophejs.
23
+ *
24
+ * This file implements XMPP over WebSockets for Strophejs.
25
+ * If a Connection is established with a Websocket url (ws://...)
26
+ * Strophe will use WebSockets.
27
+ * For more information on XMPP-over-WebSocket see RFC 7395:
28
+ * http://tools.ietf.org/html/rfc7395
29
+ *
30
+ * WebSocket support implemented by Andreas Guth (andreas.guth@rwth-aachen.de)
31
+ */
32
+ Strophe.Websocket = class Websocket {
33
+
34
+ /** PrivateConstructor: Strophe.Websocket
35
+ * Create and initialize a Strophe.WebSocket object.
36
+ * Currently only sets the connection Object.
37
+ *
38
+ * Parameters:
39
+ * (Strophe.Connection) connection - The Strophe.Connection that will use WebSockets.
40
+ *
41
+ * Returns:
42
+ * A new Strophe.WebSocket object.
43
+ */
44
+ constructor (connection) {
45
+ this._conn = connection;
46
+ this.strip = "wrapper";
47
+
48
+ const service = connection.service;
49
+ if (service.indexOf("ws:") !== 0 && service.indexOf("wss:") !== 0) {
50
+ // If the service is not an absolute URL, assume it is a path and put the absolute
51
+ // URL together from options, current URL and the path.
52
+ let new_service = "";
53
+ if (connection.options.protocol === "ws" && window.location.protocol !== "https:") {
54
+ new_service += "ws";
55
+ } else {
56
+ new_service += "wss";
57
+ }
58
+
59
+ new_service += "://" + window.location.host;
60
+ if (service.indexOf("/") !== 0) {
61
+ new_service += window.location.pathname + service;
62
+ } else {
63
+ new_service += service;
64
+ }
65
+ connection.service = new_service;
66
+ }
67
+ }
68
+
69
+ /** PrivateFunction: _buildStream
70
+ * _Private_ helper function to generate the <stream> start tag for WebSockets
71
+ *
72
+ * Returns:
73
+ * A Strophe.Builder with a <stream> element.
74
+ */
75
+ _buildStream () {
76
+ return $build("open", {
77
+ "xmlns": Strophe.NS.FRAMING,
78
+ "to": this._conn.domain,
79
+ "version": '1.0'
80
+ });
81
+ }
82
+
83
+ /** PrivateFunction: _checkStreamError
84
+ * _Private_ checks a message for stream:error
85
+ *
86
+ * Parameters:
87
+ * (Strophe.Request) bodyWrap - The received stanza.
88
+ * connectstatus - The ConnectStatus that will be set on error.
89
+ * Returns:
90
+ * true if there was a streamerror, false otherwise.
91
+ */
92
+ _checkStreamError (bodyWrap, connectstatus) {
93
+ let errors;
94
+ if (bodyWrap.getElementsByTagNameNS) {
95
+ errors = bodyWrap.getElementsByTagNameNS(Strophe.NS.STREAM, "error");
96
+ } else {
97
+ errors = bodyWrap.getElementsByTagName("stream:error");
98
+ }
99
+ if (errors.length === 0) {
100
+ return false;
101
+ }
102
+
103
+ const error = errors[0];
104
+
105
+ let condition = "";
106
+ let text = "";
107
+
108
+ const ns = "urn:ietf:params:xml:ns:xmpp-streams";
109
+ for (let i=0; i<error.childNodes.length; i++) {
110
+ const e = error.childNodes[i];
111
+ if (e.getAttribute("xmlns") !== ns) {
112
+ break;
113
+ } if (e.nodeName === "text") {
114
+ text = e.textContent;
115
+ } else {
116
+ condition = e.nodeName;
117
+ }
118
+ }
119
+
120
+ let errorString = "WebSocket stream error: ";
121
+ if (condition) {
122
+ errorString += condition;
123
+ } else {
124
+ errorString += "unknown";
125
+ }
126
+ if (text) {
127
+ errorString += " - " + text;
128
+ }
129
+ Strophe.error(errorString);
130
+
131
+ // close the connection on stream_error
132
+ this._conn._changeConnectStatus(connectstatus, condition);
133
+ this._conn._doDisconnect();
134
+ return true;
135
+ }
136
+
137
+ /** PrivateFunction: _reset
138
+ * Reset the connection.
139
+ *
140
+ * This function is called by the reset function of the Strophe Connection.
141
+ * Is not needed by WebSockets.
142
+ */
143
+ _reset () { // eslint-disable-line class-methods-use-this
144
+ return;
145
+ }
146
+
147
+ /** PrivateFunction: _connect
148
+ * _Private_ function called by Strophe.Connection.connect
149
+ *
150
+ * Creates a WebSocket for a connection and assigns Callbacks to it.
151
+ * Does nothing if there already is a WebSocket.
152
+ */
153
+ _connect () {
154
+ // Ensure that there is no open WebSocket from a previous Connection.
155
+ this._closeSocket();
156
+ this.socket = new WebSocket(this._conn.service, "xmpp");
157
+ this.socket.onopen = () => this._onOpen();
158
+ this.socket.onerror = (e) => this._onError(e);
159
+ this.socket.onclose = (e) => this._onClose(e);
160
+ // Gets replaced with this._onMessage once _onInitialMessage is called
161
+ this.socket.onmessage = (message) => this._onInitialMessage(message);
162
+ this._conn.clientLogger('_connect method was called with WebSocket protocol');
163
+ }
164
+
165
+ /** PrivateFunction: _connect_cb
166
+ * _Private_ function called by Strophe.Connection._connect_cb
167
+ *
168
+ * checks for stream:error
169
+ *
170
+ * Parameters:
171
+ * (Strophe.Request) bodyWrap - The received stanza.
172
+ */
173
+ _connect_cb (bodyWrap) {
174
+ const error = this._checkStreamError(bodyWrap, Strophe.Status.CONNFAIL);
175
+ if (error) {
176
+ return Strophe.Status.CONNFAIL;
177
+ }
178
+ }
179
+
180
+ /** PrivateFunction: _handleStreamStart
181
+ * _Private_ function that checks the opening <open /> tag for errors.
182
+ *
183
+ * Disconnects if there is an error and returns false, true otherwise.
184
+ *
185
+ * Parameters:
186
+ * (Node) message - Stanza containing the <open /> tag.
187
+ */
188
+ _handleStreamStart (message) {
189
+ let error = false;
190
+
191
+ // Check for errors in the <open /> tag
192
+ const ns = message.getAttribute("xmlns");
193
+ if (typeof ns !== "string") {
194
+ error = "Missing xmlns in <open />";
195
+ } else if (ns !== Strophe.NS.FRAMING) {
196
+ error = "Wrong xmlns in <open />: " + ns;
197
+ }
198
+
199
+ const ver = message.getAttribute("version");
200
+ if (typeof ver !== "string") {
201
+ error = "Missing version in <open />";
202
+ } else if (ver !== "1.0") {
203
+ error = "Wrong version in <open />: " + ver;
204
+ }
205
+
206
+ if (error) {
207
+ this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, error);
208
+ this._conn._doDisconnect();
209
+ return false;
210
+ }
211
+ return true;
212
+ }
213
+
214
+ /** PrivateFunction: _onInitialMessage
215
+ * _Private_ function that handles the first connection messages.
216
+ *
217
+ * On receiving an opening stream tag this callback replaces itself with the real
218
+ * message handler. On receiving a stream error the connection is terminated.
219
+ */
220
+ _onInitialMessage (message) {
221
+ if (message.data.indexOf("<open ") === 0 || message.data.indexOf("<?xml") === 0) {
222
+ // Strip the XML Declaration, if there is one
223
+ const data = message.data.replace(/^(<\?.*?\?>\s*)*/, "");
224
+ if (data === '') return;
225
+
226
+ const streamStart = new DOMParser().parseFromString(data, "text/xml").documentElement;
227
+ this._conn.xmlInput(streamStart);
228
+ this._conn.rawInput(message.data);
229
+
230
+ //_handleStreamSteart will check for XML errors and disconnect on error
231
+ if (this._handleStreamStart(streamStart)) {
232
+ //_connect_cb will check for stream:error and disconnect on error
233
+ this._connect_cb(streamStart);
234
+ }
235
+ } else if (message.data.indexOf("<close ") === 0) { // <close xmlns="urn:ietf:params:xml:ns:xmpp-framing />
236
+ // Parse the raw string to an XML element
237
+ const parsedMessage = new DOMParser().parseFromString(message.data, "text/xml").documentElement;
238
+ // Report this input to the raw and xml handlers
239
+ this._conn.xmlInput(parsedMessage);
240
+ this._conn.rawInput(message.data);
241
+ const see_uri = parsedMessage.getAttribute("see-other-uri");
242
+ if (see_uri) {
243
+ const service = this._conn.service;
244
+ // Valid scenarios: WSS->WSS, WS->ANY
245
+ const isSecureRedirect = (service.indexOf("wss:") >= 0 && see_uri.indexOf("wss:") >= 0) || (service.indexOf("ws:") >= 0);
246
+ if (isSecureRedirect) {
247
+ this._conn._changeConnectStatus(
248
+ Strophe.Status.REDIRECT,
249
+ "Received see-other-uri, resetting connection"
250
+ );
251
+ this._conn.reset();
252
+ this._conn.service = see_uri;
253
+ this._connect();
254
+ }
255
+ } else {
256
+ this._conn._changeConnectStatus(
257
+ Strophe.Status.CONNFAIL,
258
+ "Received closing stream"
259
+ );
260
+ this._conn._doDisconnect();
261
+ }
262
+ } else {
263
+ this._replaceMessageHandler();
264
+ const string = this._streamWrap(message.data);
265
+ const elem = new DOMParser().parseFromString(string, "text/xml").documentElement;
266
+ this._conn._connect_cb(elem, null, message.data);
267
+ }
268
+ }
269
+
270
+ /** PrivateFunction: _replaceMessageHandler
271
+ *
272
+ * Called by _onInitialMessage in order to replace itself with the general message handler.
273
+ * This method is overridden by Strophe.WorkerWebsocket, which manages a
274
+ * websocket connection via a service worker and doesn't have direct access
275
+ * to the socket.
276
+ */
277
+ _replaceMessageHandler () {
278
+ this.socket.onmessage = (m) => this._onMessage(m);
279
+ }
280
+
281
+ /** PrivateFunction: _disconnect
282
+ * _Private_ function called by Strophe.Connection.disconnect
283
+ *
284
+ * Disconnects and sends a last stanza if one is given
285
+ *
286
+ * Parameters:
287
+ * (Request) pres - This stanza will be sent before disconnecting.
288
+ */
289
+ _disconnect (pres) {
290
+ if (this.socket && this.socket.readyState !== WebSocket.CLOSED) {
291
+ if (pres) {
292
+ this._conn.send(pres);
293
+ }
294
+ const close = $build("close", { "xmlns": Strophe.NS.FRAMING });
295
+ this._conn.xmlOutput(close.tree());
296
+ const closeString = Strophe.serialize(close);
297
+ this._conn.rawOutput(closeString);
298
+ try {
299
+ this.socket.send(closeString);
300
+ } catch (e) {
301
+ Strophe.warn("Couldn't send <close /> tag.");
302
+ }
303
+ }
304
+ setTimeout(() => this._conn._doDisconnect, 0);
305
+ }
306
+
307
+ /** PrivateFunction: _doDisconnect
308
+ * _Private_ function to disconnect.
309
+ *
310
+ * Just closes the Socket for WebSockets
311
+ */
312
+ _doDisconnect () {
313
+ Strophe.debug("WebSockets _doDisconnect was called");
314
+ this._closeSocket();
315
+ }
316
+
317
+ /** PrivateFunction _streamWrap
318
+ * _Private_ helper function to wrap a stanza in a <stream> tag.
319
+ * This is used so Strophe can process stanzas from WebSockets like BOSH
320
+ */
321
+ _streamWrap (stanza) { // eslint-disable-line class-methods-use-this
322
+ return "<wrapper>" + stanza + '</wrapper>';
323
+ }
324
+
325
+
326
+ /** PrivateFunction: _closeSocket
327
+ * _Private_ function to close the WebSocket.
328
+ *
329
+ * Closes the socket if it is still open and deletes it
330
+ */
331
+ _closeSocket () {
332
+ if (this.socket) {
333
+ try {
334
+ this.socket.onclose = null;
335
+ this.socket.onerror = null;
336
+ this.socket.onmessage = null;
337
+ this.socket.close();
338
+ } catch (e) {
339
+ Strophe.debug(e.message);
340
+ }
341
+ }
342
+ this.socket = null;
343
+ }
344
+
345
+ /** PrivateFunction: _emptyQueue
346
+ * _Private_ function to check if the message queue is empty.
347
+ *
348
+ * Returns:
349
+ * True, because WebSocket messages are send immediately after queueing.
350
+ */
351
+ _emptyQueue () { // eslint-disable-line class-methods-use-this
352
+ return true;
353
+ }
354
+
355
+ /** PrivateFunction: _onClose
356
+ * _Private_ function to handle websockets closing.
357
+ */
358
+ _onClose (e) {
359
+ if (this._conn.connected && !this._conn.disconnecting) {
360
+ Strophe.error("Websocket closed unexpectedly");
361
+ this._conn._doDisconnect();
362
+ } else if (e && e.code === 1006 && !this._conn.connected && this.socket) {
363
+ // in case the onError callback was not called (Safari 10 does not
364
+ // call onerror when the initial connection fails) we need to
365
+ // dispatch a CONNFAIL status update to be consistent with the
366
+ // behavior on other browsers.
367
+ Strophe.error("Websocket closed unexcectedly");
368
+ this._conn._changeConnectStatus(
369
+ Strophe.Status.CONNFAIL,
370
+ "The WebSocket connection could not be established or was disconnected."
371
+ );
372
+ this._conn._doDisconnect();
373
+ } else {
374
+ Strophe.debug("Websocket closed");
375
+ }
376
+ }
377
+
378
+ /** PrivateFunction: _no_auth_received
379
+ *
380
+ * Called on stream start/restart when no stream:features
381
+ * has been received.
382
+ */
383
+ _no_auth_received (callback) {
384
+ Strophe.error("Server did not offer a supported authentication mechanism");
385
+ this._conn._changeConnectStatus(
386
+ Strophe.Status.CONNFAIL,
387
+ Strophe.ErrorCondition.NO_AUTH_MECH
388
+ );
389
+ if (callback) {
390
+ callback.call(this._conn);
391
+ }
392
+ this._conn._doDisconnect();
393
+ }
394
+
395
+ /** PrivateFunction: _onDisconnectTimeout
396
+ * _Private_ timeout handler for handling non-graceful disconnection.
397
+ *
398
+ * This does nothing for WebSockets
399
+ */
400
+ _onDisconnectTimeout () {} // eslint-disable-line class-methods-use-this
401
+
402
+ /** PrivateFunction: _abortAllRequests
403
+ * _Private_ helper function that makes sure all pending requests are aborted.
404
+ */
405
+ _abortAllRequests () {} // eslint-disable-line class-methods-use-this
406
+
407
+ /** PrivateFunction: _onError
408
+ * _Private_ function to handle websockets errors.
409
+ *
410
+ * Parameters:
411
+ * (Object) error - The websocket error.
412
+ */
413
+ _onError (error) {
414
+ Strophe.error("Websocket error " + error);
415
+ this._conn._changeConnectStatus(
416
+ Strophe.Status.CONNFAIL,
417
+ "The WebSocket connection could not be established or was disconnected."
418
+ );
419
+ this._disconnect();
420
+ }
421
+
422
+ /** PrivateFunction: _onIdle
423
+ * _Private_ function called by Strophe.Connection._onIdle
424
+ *
425
+ * sends all queued stanzas
426
+ */
427
+ _onIdle () {
428
+ const data = this._conn._data;
429
+ if (data.length > 0 && !this._conn.paused) {
430
+ for (let i=0; i<data.length; i++) {
431
+ if (data[i] !== null) {
432
+ let stanza;
433
+ if (data[i] === "restart") {
434
+ stanza = this._buildStream().tree();
435
+ } else {
436
+ stanza = data[i];
437
+ }
438
+ const rawStanza = Strophe.serialize(stanza);
439
+ this._conn.xmlOutput(stanza);
440
+ this._conn.rawOutput(rawStanza);
441
+ this.socket.send(rawStanza);
442
+ }
443
+ }
444
+ this._conn._data = [];
445
+ }
446
+ }
447
+
448
+ /** PrivateFunction: _onMessage
449
+ * _Private_ function to handle websockets messages.
450
+ *
451
+ * This function parses each of the messages as if they are full documents.
452
+ * [TODO : We may actually want to use a SAX Push parser].
453
+ *
454
+ * Since all XMPP traffic starts with
455
+ * <stream:stream version='1.0'
456
+ * xml:lang='en'
457
+ * xmlns='jabber:client'
458
+ * xmlns:stream='http://etherx.jabber.org/streams'
459
+ * id='3697395463'
460
+ * from='SERVER'>
461
+ *
462
+ * The first stanza will always fail to be parsed.
463
+ *
464
+ * Additionally, the seconds stanza will always be <stream:features> with
465
+ * the stream NS defined in the previous stanza, so we need to 'force'
466
+ * the inclusion of the NS in this stanza.
467
+ *
468
+ * Parameters:
469
+ * (string) message - The websocket message.
470
+ */
471
+ _onMessage (message) {
472
+ let elem;
473
+ // check for closing stream
474
+ const close = '<close xmlns="urn:ietf:params:xml:ns:xmpp-framing" />';
475
+ if (message.data === close) {
476
+ this._conn.rawInput(close);
477
+ this._conn.xmlInput(message);
478
+ if (!this._conn.disconnecting) {
479
+ this._conn._doDisconnect();
480
+ }
481
+ return;
482
+ } else if (message.data.search("<open ") === 0) {
483
+ // This handles stream restarts
484
+ elem = new DOMParser().parseFromString(message.data, "text/xml").documentElement;
485
+ if (!this._handleStreamStart(elem)) {
486
+ return;
487
+ }
488
+ } else {
489
+ const data = this._streamWrap(message.data);
490
+ elem = new DOMParser().parseFromString(data, "text/xml").documentElement;
491
+ }
492
+
493
+ if (this._checkStreamError(elem, Strophe.Status.ERROR)) {
494
+ return;
495
+ }
496
+
497
+ //handle unavailable presence stanza before disconnecting
498
+ if (this._conn.disconnecting &&
499
+ elem.firstChild.nodeName === "presence" &&
500
+ elem.firstChild.getAttribute("type") === "unavailable") {
501
+ this._conn.xmlInput(elem);
502
+ this._conn.rawInput(Strophe.serialize(elem));
503
+ // if we are already disconnecting we will ignore the unavailable stanza and
504
+ // wait for the </stream:stream> tag before we close the connection
505
+ return;
506
+ }
507
+ this._conn._dataRecv(elem, message.data);
508
+ }
509
+
510
+ /** PrivateFunction: _onOpen
511
+ * _Private_ function to handle websockets connection setup.
512
+ *
513
+ * The opening stream tag is sent here.
514
+ */
515
+ _onOpen () {
516
+ Strophe.debug("Websocket open");
517
+ const start = this._buildStream();
518
+ this._conn.xmlOutput(start.tree());
519
+
520
+ const startString = Strophe.serialize(start);
521
+ this._conn.rawOutput(startString);
522
+ this.socket.send(startString);
523
+ }
524
+
525
+ /** PrivateFunction: _reqToData
526
+ * _Private_ function to get a stanza out of a request.
527
+ *
528
+ * WebSockets don't use requests, so the passed argument is just returned.
529
+ *
530
+ * Parameters:
531
+ * (Object) stanza - The stanza.
532
+ *
533
+ * Returns:
534
+ * The stanza that was passed.
535
+ */
536
+ _reqToData (stanza) { // eslint-disable-line class-methods-use-this
537
+ return stanza;
538
+ }
539
+
540
+ /** PrivateFunction: _send
541
+ * _Private_ part of the Connection.send function for WebSocket
542
+ *
543
+ * Just flushes the messages that are in the queue
544
+ */
545
+ _send () {
546
+ this._conn.flush();
547
+ }
548
+
549
+ /** PrivateFunction: _sendRestart
550
+ *
551
+ * Send an xmpp:restart stanza.
552
+ */
553
+ _sendRestart () {
554
+ clearTimeout(this._conn._idleTimeout);
555
+ this._conn._onIdle.bind(this._conn)();
556
+ }
557
+ };
@@ -0,0 +1,150 @@
1
+ /*
2
+ This program is distributed under the terms of the MIT license.
3
+ Please see the LICENSE file for details.
4
+
5
+ Copyright 2020, JC Brand
6
+ */
7
+
8
+ import './websocket.js';
9
+ import { $build, Strophe } from './core.js';
10
+
11
+ const lmap = {};
12
+ lmap['debug'] = Strophe.LogLevel.DEBUG;
13
+ lmap['info'] = Strophe.LogLevel.INFO;
14
+ lmap['warn'] = Strophe.LogLevel.WARN;
15
+ lmap['error'] = Strophe.LogLevel.ERROR;
16
+ lmap['fatal'] = Strophe.LogLevel.FATAL;
17
+
18
+
19
+ /** Class: Strophe.WorkerWebsocket
20
+ * _Private_ helper class that handles a websocket connection inside a shared worker.
21
+ */
22
+ Strophe.WorkerWebsocket = class WorkerWebsocket extends Strophe.Websocket {
23
+
24
+ /** PrivateConstructor: Strophe.WorkerWebsocket
25
+ * Create and initialize a Strophe.WorkerWebsocket object.
26
+ *
27
+ * Parameters:
28
+ * (Strophe.Connection) connection - The Strophe.Connection
29
+ *
30
+ * Returns:
31
+ * A new Strophe.WorkerWebsocket object.
32
+ */
33
+ constructor (connection) {
34
+ super(connection);
35
+ this._conn = connection;
36
+ this.worker = new SharedWorker(this._conn.options.worker, 'Strophe XMPP Connection');
37
+ this.worker.onerror = (e) => {
38
+ console?.error(e);
39
+ Strophe.log(Strophe.LogLevel.ERROR, `Shared Worker Error: ${e}`);
40
+ }
41
+ }
42
+
43
+ get socket () {
44
+ return {
45
+ 'send': str => this.worker.port.postMessage(['send', str])
46
+ }
47
+ }
48
+
49
+ _connect () {
50
+ this._messageHandler = (m) => this._onInitialMessage(m);
51
+ this.worker.port.start();
52
+ this.worker.port.onmessage = (ev) => this._onWorkerMessage(ev);
53
+ this.worker.port.postMessage(['_connect', this._conn.service, this._conn.jid]);
54
+ this._conn.clientLogger('_connect method was called with WebSocket worker protocol');
55
+ }
56
+
57
+ _attach (callback) {
58
+ this._messageHandler = (m) => this._onMessage(m);
59
+ this._conn.connect_callback = callback;
60
+ this.worker.port.start();
61
+ this.worker.port.onmessage = (ev) => this._onWorkerMessage(ev);
62
+ this.worker.port.postMessage(['_attach', this._conn.service]);
63
+ }
64
+
65
+ _attachCallback (status, jid) {
66
+ if (status === Strophe.Status.ATTACHED) {
67
+ this._conn.jid = jid;
68
+ this._conn.authenticated = true;
69
+ this._conn.connected = true;
70
+ this._conn.restored = true;
71
+ this._conn._changeConnectStatus(Strophe.Status.ATTACHED);
72
+ } else if (status === Strophe.Status.ATTACHFAIL) {
73
+ this._conn.authenticated = false;
74
+ this._conn.connected = false;
75
+ this._conn.restored = false;
76
+ this._conn._changeConnectStatus(Strophe.Status.ATTACHFAIL);
77
+ }
78
+ }
79
+
80
+ _disconnect (readyState, pres) {
81
+ pres && this._conn.send(pres);
82
+ const close = $build("close", { "xmlns": Strophe.NS.FRAMING });
83
+ this._conn.xmlOutput(close.tree());
84
+ const closeString = Strophe.serialize(close);
85
+ this._conn.rawOutput(closeString);
86
+ this.worker.port.postMessage(['send', closeString]);
87
+ this._conn._doDisconnect();
88
+ }
89
+
90
+ _onClose (e) {
91
+ if (this._conn.connected && !this._conn.disconnecting) {
92
+ Strophe.error("Websocket closed unexpectedly");
93
+ this._conn._doDisconnect();
94
+ } else if (e && e.code === 1006 && !this._conn.connected) {
95
+ // in case the onError callback was not called (Safari 10 does not
96
+ // call onerror when the initial connection fails) we need to
97
+ // dispatch a CONNFAIL status update to be consistent with the
98
+ // behavior on other browsers.
99
+ Strophe.error("Websocket closed unexcectedly");
100
+ this._conn._changeConnectStatus(
101
+ Strophe.Status.CONNFAIL,
102
+ "The WebSocket connection could not be established or was disconnected."
103
+ );
104
+ this._conn._doDisconnect();
105
+ } else {
106
+ Strophe.debug("Websocket closed");
107
+ }
108
+ }
109
+
110
+ _closeSocket () {
111
+ this.worker.port.postMessage(['_closeSocket']);
112
+ }
113
+
114
+ /** PrivateFunction: _replaceMessageHandler
115
+ *
116
+ * Called by _onInitialMessage in order to replace itself with the general message handler.
117
+ * This method is overridden by Strophe.WorkerWebsocket, which manages a
118
+ * websocket connection via a service worker and doesn't have direct access
119
+ * to the socket.
120
+ */
121
+ _replaceMessageHandler () {
122
+ this._messageHandler = (m) => this._onMessage(m);
123
+ }
124
+
125
+ /** PrivateFunction: _onWorkerMessage
126
+ * _Private_ function that handles messages received from the service worker
127
+ */
128
+ _onWorkerMessage (ev) {
129
+ const { data } = ev;
130
+ const method_name = data[0];
131
+ if (method_name === '_onMessage') {
132
+ this._messageHandler(data[1]);
133
+ } else if (method_name in this) {
134
+ try {
135
+ this[method_name].apply(this, ev.data.slice(1));
136
+ } catch (e) {
137
+ Strophe.log(Strophe.LogLevel.ERROR, e);
138
+ }
139
+ } else if (method_name === 'log') {
140
+ const level = data[1];
141
+ const msg = data[2]
142
+ Strophe.log(lmap[level], msg);
143
+ } else {
144
+ Strophe.log(
145
+ Strophe.LogLevel.ERROR,
146
+ `Found unhandled service worker message: ${data}`
147
+ );
148
+ }
149
+ }
150
+ }