Browse Source

Don't hang indefinitely + nicer error messages

when a connection can't be established.
JC Brand 7 years ago
parent
commit
bd913734e4

+ 5 - 0
CHANGES.md

@@ -1,5 +1,10 @@
 # Changelog
 
+## 3.2.2 (Unreleased)
+
+- Don't hang indefinitely and provide nicer error messages when a connection
+  can't be established.
+
 ## 3.2.1 (2017-08-29)
 
 ### Bugfixes

+ 7 - 0
css/converse.css

@@ -1990,6 +1990,13 @@
       white-space: normal; }
     #conversejs #controlbox #converse-register .save-submit, #conversejs #controlbox #converse-login .save-submit {
       color: #3AA569; }
+    #conversejs #controlbox #converse-register .conn-feedback p, #conversejs #controlbox #converse-login .conn-feedback p {
+      color: #578EA9;
+      padding-bottom: 0.5em; }
+      #conversejs #controlbox #converse-register .conn-feedback p.feedback-subject.error, #conversejs #controlbox #converse-login .conn-feedback p.feedback-subject.error {
+        font-weight: bold; }
+      #conversejs #controlbox #converse-register .conn-feedback p.error, #conversejs #controlbox #converse-login .conn-feedback p.error {
+        color: #A53214; }
     #conversejs #controlbox #converse-register input, #conversejs #controlbox #converse-login input {
       width: 100%;
       margin: 0.5em 0; }

+ 7 - 0
css/inverse.css

@@ -2058,6 +2058,13 @@ body {
       white-space: normal; }
     #conversejs #controlbox #converse-register .save-submit, #conversejs #controlbox #converse-login .save-submit {
       color: #3AA569; }
+    #conversejs #controlbox #converse-register .conn-feedback p, #conversejs #controlbox #converse-login .conn-feedback p {
+      color: #578EA9;
+      padding-bottom: 0.5em; }
+      #conversejs #controlbox #converse-register .conn-feedback p.feedback-subject.error, #conversejs #controlbox #converse-login .conn-feedback p.feedback-subject.error {
+        font-weight: bold; }
+      #conversejs #controlbox #converse-register .conn-feedback p.error, #conversejs #controlbox #converse-login .conn-feedback p.error {
+        color: #A53214; }
     #conversejs #controlbox #converse-register input, #conversejs #controlbox #converse-login input {
       width: 100%;
       margin: 0.5em 0; }

+ 39 - 39
package-lock.json

@@ -3296,14 +3296,6 @@
             }
           }
         },
-        "string_decoder": {
-          "version": "1.0.1",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "safe-buffer": "5.0.1"
-          }
-        },
         "string-width": {
           "version": "1.0.2",
           "bundled": true,
@@ -3314,6 +3306,14 @@
             "strip-ansi": "3.0.1"
           }
         },
+        "string_decoder": {
+          "version": "1.0.1",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "safe-buffer": "5.0.1"
+          }
+        },
         "stringstream": {
           "version": "0.0.5",
           "bundled": true,
@@ -5080,6 +5080,7 @@
       "integrity": "sha1-+Osa0A3FilUUNjtBylNCgX8L1kY=",
       "dev": true,
       "requires": {
+        "JSONStream": "1.3.1",
         "abbrev": "1.1.0",
         "ansi-regex": "2.1.1",
         "ansicolors": "0.3.2",
@@ -5110,7 +5111,6 @@
         "inherits": "2.0.3",
         "ini": "1.3.4",
         "init-package-json": "1.10.1",
-        "JSONStream": "1.3.1",
         "lazy-property": "1.0.0",
         "lockfile": "1.0.3",
         "lodash._baseindexof": "3.1.0",
@@ -5173,6 +5173,27 @@
         "write-file-atomic": "1.3.3"
       },
       "dependencies": {
+        "JSONStream": {
+          "version": "1.3.1",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "jsonparse": "1.3.0",
+            "through": "2.3.8"
+          },
+          "dependencies": {
+            "jsonparse": {
+              "version": "1.3.0",
+              "bundled": true,
+              "dev": true
+            },
+            "through": {
+              "version": "2.3.8",
+              "bundled": true,
+              "dev": true
+            }
+          }
+        },
         "abbrev": {
           "version": "1.1.0",
           "bundled": true,
@@ -5514,27 +5535,6 @@
             }
           }
         },
-        "JSONStream": {
-          "version": "1.3.1",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "jsonparse": "1.3.0",
-            "through": "2.3.8"
-          },
-          "dependencies": {
-            "jsonparse": {
-              "version": "1.3.0",
-              "bundled": true,
-              "dev": true
-            },
-            "through": {
-              "version": "2.3.8",
-              "bundled": true,
-              "dev": true
-            }
-          }
-        },
         "lazy-property": {
           "version": "1.0.0",
           "bundled": true,
@@ -9005,15 +9005,6 @@
       "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=",
       "dev": true
     },
-    "string_decoder": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
-      "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
-      "dev": true,
-      "requires": {
-        "safe-buffer": "5.1.1"
-      }
-    },
     "string-length": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/string-length/-/string-length-1.0.1.tgz",
@@ -9034,6 +9025,15 @@
         "strip-ansi": "3.0.1"
       }
     },
+    "string_decoder": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
+      "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "5.1.1"
+      }
+    },
     "stringstream": {
       "version": "0.0.5",
       "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",

+ 12 - 0
sass/_controlbox.scss

@@ -113,6 +113,18 @@
             .save-submit {
                 color: $save-button-color;
             }
+            .conn-feedback {
+                p {
+                    color: $controlbox-head-color;
+                    padding-bottom: 0.5em;
+                    &.feedback-subject.error {
+                        font-weight: bold;
+                    }
+                    &.error {
+                        color: $error-color;
+                    }
+                }
+            }
             input {
                 width: 100%;
                 margin: 0.5em 0;

+ 0 - 3
src/config.js

@@ -43,7 +43,6 @@ require.config({
         "strophe.vcard":            "node_modules/strophejs-plugin-vcard/strophe.vcard",
         "text":                     "node_modules/text/text",
         "tpl":                      "node_modules/lodash-template-loader/loader",
-        "typeahead":                "components/typeahead.js/index",
         "underscore":               "src/underscore-shim",
         "utils":                    "src/utils",
         "xss":                      "node_modules/xss/dist/xss",
@@ -108,8 +107,6 @@ require.config({
 
     packages: [{
         'name': 'moment',
-        // This location is relative to baseUrl. Choose bower_components
-        // or node_modules, depending on how moment was installed.
         'location': 'node_modules/moment',
         'main': 'moment'
     }],

+ 37 - 2
src/converse-controlbox.js

@@ -269,6 +269,17 @@
                     return this;
                 },
 
+                showLoginPanel () {
+                    if (!_.isUndefined(this.loginpanel)) {
+                        this.renderLoginPanel();
+                    } else {
+                        this.loginpanel.$el.find('input#jid').focus();
+                        if (!this.loginpanel.$el.is(':visible')) {
+                            this.loginpanel.$el.show();
+                        }
+                    }
+                },
+
                 renderLoginPanel () {
                     this.loginpanel = new _converse.LoginPanel({
                         '$parent': this.$el.find('.controlbox-panes'),
@@ -390,6 +401,9 @@
                             'PREBIND': _converse.PREBIND,
                             'auto_login': _converse.auto_login,
                             'authentication': _converse.authentication,
+                            'conn_feedback_class': _converse.connfeedback.get('klass'),
+                            'conn_feedback_subject': _converse.connfeedback.get('subject'),
+                            'conn_feedback_message': _converse.connfeedback.get('message'),
                             'label_username': __('XMPP Username:'),
                             'label_password': __('Password:'),
                             'label_anon_login': __('Click here to log in anonymously'),
@@ -399,6 +413,7 @@
                         })
                     ));
                     this.$tabs = cfg.$parent.parent().find('#controlbox-tabs');
+                    _converse.connfeedback.on('change', this.showConnectionFeedback, this);
                 },
 
                 render () {
@@ -410,6 +425,25 @@
                     return this;
                 },
 
+                showConnectionFeedback () {
+                    const klass = _converse.connfeedback.get('klass');
+                    function insert (text, el) {
+                        el.textContent = text;
+                        el.classList.remove('error');
+                        if (klass) {
+                            el.classList.add(klass);
+                        }
+                    }
+                    insert(
+                        _converse.connfeedback.get('subject'),
+                        this.el.querySelector('.conn-feedback .feedback-subject')
+                    )
+                    insert(
+                        _converse.connfeedback.get('message'),
+                        this.el.querySelector('.conn-feedback .feedback-message')
+                    )
+                },
+
                 authenticate (ev) {
                     /* Authenticate the user based on a form submission event.
                      */
@@ -743,6 +777,7 @@
                     this.updateOnlineCount();
                     const that = this;
                     _converse.api.waitUntil('initialized').then(() => {
+                        this.render();
                         _converse.roster.on("add", that.updateOnlineCount, that);
                         _converse.roster.on('change', that.updateOnlineCount, that);
                         _converse.roster.on("destroy", that.updateOnlineCount, that);
@@ -756,7 +791,7 @@
                     // artifacts (i.e. on page load the toggle is shown only to then
                     // seconds later be hidden in favor of the control box).
                     this.el.innerHTML = tpl_controlbox_toggle({
-                        'label_toggle': __('Toggle chat')
+                        'label_toggle': _converse.connection.connected ? __('Contacts') : __('Toggle chat')
                     })
                     return this;
                 },
@@ -823,7 +858,7 @@
                 const view = _converse.chatboxviews.get('controlbox');
                 view.model.set({connected:false});
                 view.$('#controlbox-tabs').empty();
-                view.renderLoginPanel();
+                view.showLoginPanel();
             };
             _converse.on('disconnected', disconnect);
 

+ 44 - 25
src/converse-core.js

@@ -407,19 +407,10 @@
         };
 
         this.giveFeedback = function (subject, klass, message) {
-            _.forEach(document.querySelectorAll('.conn-feedback'), (el) => {
-                el.classList.add('conn-feedback');
-                el.textContent = subject;
-                if (klass) {
-                    el.classList.add(klass);
-                } else {
-                    el.classList.remove('error');
-                }
-            });
-            _converse.emit('feedback', {
+            _converse.connfeedback.set({
+                'subject': subject,
                 'klass': klass,
-                'message': message,
-                'subject': subject
+                'message': message
             });
         };
 
@@ -462,6 +453,8 @@
              * Will either start a teardown process for converse.js or attempt
              * to reconnect.
              */
+            const reason = _converse.disconnection_reason;
+
             if (_converse.disconnection_cause === Strophe.Status.AUTHFAIL) {
                 if (_converse.credentials_url && _converse.auto_reconnect) {
                     /* In this case, we reconnect, because we might be receiving
@@ -473,7 +466,9 @@
                     return _converse.disconnect();
                 }
             } else if (_converse.disconnection_cause === _converse.LOGOUT ||
-                    _converse.disconnection_reason === "host-unknown" ||
+                    (!_.isUndefined(reason) && reason === _.get(Strophe, 'ErrorCondition.NO_AUTH_MECH')) ||
+                    reason === "host-unknown" ||
+                    reason === "remote-connection-failed" ||
                     !_converse.auto_reconnect) {
                 return _converse.disconnect();
             }
@@ -494,7 +489,7 @@
             }
         };
 
-        this.onConnectStatusChanged = function (status, condition) {
+        this.onConnectStatusChanged = function (status, message) {
             /* Callback method called by Strophe as the Strophe.Connection goes
              * through various states while establishing or tearing down a
              * connection.
@@ -517,29 +512,38 @@
                     _converse.onConnected();
                 }
             } else if (status === Strophe.Status.DISCONNECTED) {
-                _converse.setDisconnectionCause(status, condition);
+                _converse.setDisconnectionCause(status, message);
                 _converse.onDisconnected();
             } else if (status === Strophe.Status.ERROR) {
                 _converse.giveFeedback(
-                    __('Connection error'), 'error',
+                    __('Connection error'),
+                    'error',
                     __('An error occurred while connecting to the chat server.')
                 );
             } else if (status === Strophe.Status.CONNECTING) {
-                _converse.giveFeedback(__('Connecting'));
+                _converse.giveFeedback(__('Connecting'));
             } else if (status === Strophe.Status.AUTHENTICATING) {
-                _converse.giveFeedback(__('Authenticating'));
+                _converse.giveFeedback(__('Authenticating'));
             } else if (status === Strophe.Status.AUTHFAIL) {
-                _converse.giveFeedback(__('Authentication Failed'), 'error');
-                _converse.setDisconnectionCause(status, condition, true);
+                _converse.giveFeedback(__('Authentication failed: '+message), 'error');
+                _converse.setDisconnectionCause(status, message, true);
                 _converse.onDisconnected();
             } else if (status === Strophe.Status.CONNFAIL) {
+                let feedback = message;
+                if (message === "host-unknown" || message == "remote-connection-failed") {
+                    feedback = __("Sorry, we could not connect to the XMPP host with domain: ") +
+                        `\"${Strophe.getDomainFromJid(_converse.connection.jid)}\"`;
+                } else if (!_.isUndefined(message) && message === _.get(Strophe, 'ErrorCondition.NO_AUTH_MECH')) {
+                    feedback = __("The XMPP server did not offer a supported authentication mechanism");
+                }
                 _converse.giveFeedback(
-                    __('Connection failed'), 'error',
-                    __('An error occurred while connecting to the chat server: '+condition)
+                    __('Connection failed'),
+                    'error',
+                    feedback
                 );
-                _converse.setDisconnectionCause(status, condition);
+                _converse.setDisconnectionCause(status, message);
             } else if (status === Strophe.Status.DISCONNECTING) {
-                _converse.setDisconnectionCause(status, condition);
+                _converse.setDisconnectionCause(status, message);
             }
         };
 
@@ -749,7 +753,6 @@
             _converse.roster.onConnected();
             _converse.populateRoster();
             _converse.registerPresenceHandler();
-            _converse.giveFeedback(__('Contacts'));
             if (reconnecting) {
                 _converse.xmppstatus.sendPresence();
             } else {
@@ -1511,6 +1514,22 @@
             }
         });
 
+        this.ConnectionFeedback = Backbone.Model.extend({
+
+            initialize () {
+                this.on('change', this.emitConnectionFeedbackChange);
+            },
+
+            emitConnectionFeedbackChange () {
+                _converse.emit('connfeedback', {
+                    'klass': _converse.connfeedback.get('klass'),
+                    'message': _converse.connfeedback.get('message'),
+                    'subject': _converse.connfeedback.get('subject')
+                });
+            }
+        });
+        this.connfeedback = new this.ConnectionFeedback();
+
         this.XMPPStatus = Backbone.Model.extend({
             initialize () {
                 this.set({

+ 1 - 1
src/templates/controlbox_toggle.html

@@ -1 +1 @@
-<span class="conn-feedback">{{{label_toggle}}}</span>
+<span class="toggle-feedback">{{{label_toggle}}}</span>

+ 4 - 1
src/templates/login_panel.html

@@ -2,6 +2,10 @@
     {[ if (auto_login) { ]}
         <span class="spinner login-submit"/>
     {[ } ]}
+    <div class="conn-feedback">
+        <p class="feedback-subject {{ conn_feedback_class }}">{{ conn_feedback_subject }}</p>
+        <p class="feedback-message {{ conn_feedback_class }}">{{ conn_feedback_message }} </p>
+    </div>
     {[ if (!auto_login) { ]}
         {[ if (authentication == LOGIN || authentication == EXTERNAL) { ]}
             <label>{{{label_username}}}</label>
@@ -11,7 +15,6 @@
                 <input type="password" name="password" placeholder="{{{placeholder_password}}}">
             {[ } ]}
             <input class="pure-button button-primary" type="submit" value="{{{label_login}}}">
-            <span class="conn-feedback"></span>
         {[ } ]}
         {[ if (authentication == ANONYMOUS) { ]}
             <input class="pure-button button-primary login-anon" type="submit" value="{{{label_anon_login}}}"/>