UNPKG

broadcast-channel

Version:

A BroadcastChannel that works in New Browsers, Old Browsers, WebWorkers, NodeJs, Deno and iframes

109 lines (105 loc) 3.35 kB
import { randomToken } from './util.js'; import { sendLeaderMessage, beLeader } from './leader-election-util.js'; /** * A faster version of the leader elector that uses the WebLock API * @link https://developer.mozilla.org/en-US/docs/Web/API/Web_Locks_API */ export var LeaderElectionWebLock = function LeaderElectionWebLock(broadcastChannel, options) { var _this = this; this.broadcastChannel = broadcastChannel; broadcastChannel._befC.push(function () { return _this.die(); }); this._options = options; this.isLeader = false; this.isDead = false; this.token = randomToken(); this._lstns = []; this._unl = []; this._dpL = function () {}; // onduplicate listener this._dpLC = false; // true when onduplicate called this._wKMC = {}; // stuff for cleanup // lock name this.lN = 'pubkey-bc||' + broadcastChannel.method.type + '||' + broadcastChannel.name; }; var LEADER_DIE_ABORT_SIGNAL_MESSAGE = 'LeaderElectionWebLock.die() called'; LeaderElectionWebLock.prototype = { hasLeader: function hasLeader() { var _this2 = this; return navigator.locks.query().then(function (locks) { var relevantLocks = locks.held ? locks.held.filter(function (lock) { return lock.name === _this2.lN; }) : []; if (relevantLocks && relevantLocks.length > 0) { return true; } else { return false; } }); }, awaitLeadership: function awaitLeadership() { var _this3 = this; if (!this._wLMP) { this._wKMC.c = new AbortController(); var returnPromise = new Promise(function (res, rej) { _this3._wKMC.res = res; _this3._wKMC.rej = rej; }); this._wLMP = new Promise(function (res, reject) { navigator.locks.request(_this3.lN, { signal: _this3._wKMC.c.signal }, function () { // if the lock resolved, we can drop the abort controller _this3._wKMC.c = undefined; beLeader(_this3); res(); return returnPromise; })["catch"](function (err) { if (err.message && err.message === LEADER_DIE_ABORT_SIGNAL_MESSAGE) { /** * In this case we do nothing! * The leader died and awaitLeadership() * will never resolve. Also since this is not an error, * it will not throw. */ } else { if (_this3._wKMC.rej) { _this3._wKMC.rej(err); } reject(err); } }); }); } return this._wLMP; }, set onduplicate(_fn) { // Do nothing because there are no duplicates in the WebLock version }, die: function die() { var _this4 = this; this._lstns.forEach(function (listener) { return _this4.broadcastChannel.removeEventListener('internal', listener); }); this._lstns = []; this._unl.forEach(function (uFn) { return uFn.remove(); }); this._unl = []; if (this.isLeader) { this.isLeader = false; } this.isDead = true; if (this._wKMC.res) { this._wKMC.res(); } /** * We have to fire an abort signal * so that the navigator.locks.request stops. */ if (this._wKMC.c) { this._wKMC.c.abort(new Error(LEADER_DIE_ABORT_SIGNAL_MESSAGE)); } return sendLeaderMessage(this, 'death'); } };