Skip to content

Commit

Permalink
Add new 'login' hook
Browse files Browse the repository at this point in the history
This removes the leaky abstraction where BOSH plugin functions need
to be called from outside of it.
  • Loading branch information
jcbrand committed Nov 10, 2023
1 parent 1d3b4d7 commit 521d04d
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 18 deletions.
5 changes: 3 additions & 2 deletions docs/source/plugin_development.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/entry.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {};
Expand Down
28 changes: 25 additions & 3 deletions src/headless/plugins/bosh.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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");
}
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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 ************************/
Expand Down
2 changes: 1 addition & 1 deletion src/headless/shared/_converse.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* @module:shared_converse
* @module:shared.converse
*/
import log from '../log.js';
import i18n from './i18n.js';
Expand Down
43 changes: 32 additions & 11 deletions src/headless/shared/api/user.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
/**
* @module:shared.api.user
*/
import _converse from '../_converse.js';
import presence_api from './presence.js';
import connection_api from '../connection/api.js';
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.
*
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -114,3 +133,5 @@ export default {
}
}
}

export default api;

0 comments on commit 521d04d

Please sign in to comment.