Преглед на файлове

Add new 'login' hook

This removes the leaky abstraction where BOSH plugin functions need
to be called from outside of it.
JC Brand преди 1 година
родител
ревизия
ede6af3480
променени са 5 файла, в които са добавени 62 реда и са изтрити 18 реда
  1. 3 2
      docs/source/plugin_development.rst
  2. 1 1
      src/entry.js
  3. 25 3
      src/headless/plugins/bosh.js
  4. 1 1
      src/headless/shared/_converse.js
  5. 32 11
      src/headless/shared/api/user.js

+ 3 - 2
docs/source/plugin_development.rst

@@ -455,12 +455,13 @@ Hooks
 -----
 
 Converse has the concept of ``hooks``, which are special events that allow you
-to modify it's behaviour at runtime.
+to modify behaviour at runtime.
 
 A hook is similar to an event, but it differs in two meaningful ways:
 
 1. Converse will wait for all handlers of a hook to finish before continuing inside the function from where the hook was triggered.
-2. Each hook contains a payload, which the handlers can modify or extend, before returning it (either to the function that triggered the hook or to subsequent handlers).
+2. Each hook contains a payload, which the handlers can modify or extend, before returning it
+   (either to the function that triggered the hook or to subsequent handlers).
 
 These two properties of hooks makes it possible for 3rd party plugins to
 intercept and update data, allowing them to modify Converse without the need of

+ 1 - 1
src/entry.js

@@ -13,7 +13,7 @@
 // Once the rest converse.js has been loaded, window.converse will be replaced
 // with the full-fledged public API.
 /**
- * @typedef {module:shared_converse.ConversePrivateGlobal} ConversePrivateGlobal
+ * @typedef {module:shared.converse.ConversePrivateGlobal} ConversePrivateGlobal
  */
 
 const plugins = {};

+ 25 - 3
src/headless/plugins/bosh.js

@@ -2,12 +2,14 @@
  * @copyright The Converse.js contributors
  * @license Mozilla Public License (MPLv2)
  * @description Converse.js plugin which add support for XEP-0206: XMPP Over BOSH
+ *
+ * @typedef {module:shared.api.user} LoginHookPayload
  */
 import 'strophe.js/src/bosh';
 import _converse from '../shared/_converse.js';
 import api, { converse } from '../shared/api/index.js';
 import log from "../log.js";
-import { BOSH_WAIT } from '../shared/constants.js';
+import { BOSH_WAIT, PREBIND } from '../shared/constants.js';
 import { Model } from '@converse/skeletor';
 import { setUserJID, } from '../utils/init.js';
 import { isTestEnv } from '../utils/session.js';
@@ -56,7 +58,7 @@ converse.plugins.add('converse-bosh', {
         }
 
 
-        _converse.startNewPreboundBOSHSession = function () {
+        function startNewPreboundBOSHSession () {
             if (!api.settings.get('prebind_url')) {
                 throw new Error("startNewPreboundBOSHSession: If you use prebind then you MUST supply a prebind_url");
             }
@@ -93,7 +95,7 @@ converse.plugins.add('converse-bosh', {
         }
 
 
-        _converse.restoreBOSHSession = async function () {
+        async function restoreBOSHSession () {
             const jid = (await initBOSHSession()).get('jid');
             const connection = api.connection.get();
             if (jid && (connection._proto instanceof Strophe.Bosh)) {
@@ -129,6 +131,26 @@ converse.plugins.add('converse-bosh', {
             }
         });
 
+        api.listen.on('login',
+            /**
+             * @param {unknown} _
+             * @param {LoginHookPayload} payload
+             */
+            async (_, payload) => {
+                if (payload.success) return payload;
+
+                const { automatic } = payload;
+                // See whether there is a BOSH session to re-attach to
+                if (await restoreBOSHSession()) {
+                    return { ...payload, success: true };
+                } else if (api.settings.get("authentication") === PREBIND && (!automatic || api.settings.get("auto_login"))) {
+                    startNewPreboundBOSHSession();
+                    return { ...payload, success: true };
+                }
+                return payload;
+            }
+        );
+
         api.listen.on('addClientFeatures', () => api.disco.own.features.add(Strophe.NS.BOSH));
 
         /************************ END Event Handlers ************************/

+ 1 - 1
src/headless/shared/_converse.js

@@ -1,5 +1,5 @@
 /**
- * @module:shared_converse
+ * @module:shared.converse
  */
 import log from '../log.js';
 import i18n from './i18n.js';

+ 32 - 11
src/headless/shared/api/user.js

@@ -1,3 +1,6 @@
+/**
+ * @module:shared.api.user
+ */
 import _converse from '../_converse.js';
 import presence_api from './presence.js';
 import connection_api from '../connection/api.js';
@@ -5,9 +8,9 @@ import { replacePromise } from '../../utils/session.js';
 import { attemptNonPreboundSession, setUserJID } from '../../utils/init.js';
 import { getOpenPromise } from '@converse/openpromise';
 import { user_settings_api } from '../settings/api.js';
-import { LOGOUT, PREBIND } from '../constants.js';
+import { LOGOUT } from '../constants.js';
 
-export default {
+const api = {
     /**
      * This grouping collects API functions related to the current logged in user.
      *
@@ -57,15 +60,31 @@ export default {
                 jid = await setUserJID(jid);
             }
 
-            // See whether there is a BOSH session to re-attach to
-            const bosh_plugin = _converse.pluggable.plugins['converse-bosh'];
-            if (bosh_plugin?.enabled()) {
-                if (await _converse.restoreBOSHSession()) {
-                    return;
-                } else if (api.settings.get("authentication") === PREBIND && (!automatic || api.settings.get("auto_login"))) {
-                    return _converse.startNewPreboundBOSHSession();
-                }
-            }
+            /**
+             * *Hook* which allows 3rd party code to attempt logging in before
+             * the core code attempts it.
+             *
+             * Note: If the hook handler has logged the user in, it should set the
+             * `success` flag on the payload to `true`.
+             *
+             * @typedef {Object} LoginHookPayload
+             * @property {string} jid
+             * @property {string} password
+             * @property {boolean} [automatic] - An internally used flag that indicates whether
+             *  this method was called automatically once the connection has been initialized.
+             * @property {boolean} [success] - A flag which indicates whether
+             * login has succeeded. If a hook handler receives a payload with
+             * this flag, it should NOT attempt to log in.
+             * If a handler has successfully logged in, it should return the
+             * payload with this flag set to true.
+             *
+             * @event _converse#login
+             * @param {typeof api.user} context
+             * @param {LoginHookPayload} payload
+             */
+            const { success } = await _converse.api.hook('login', this, { jid, password, automatic });
+            if (success) return;
+
             password = password || api.settings.get("password");
             const credentials = (jid && password) ? { jid, password } : null;
             attemptNonPreboundSession(credentials, automatic);
@@ -114,3 +133,5 @@ export default {
         }
     }
 }
+
+export default api;