broadcast-channel
Version:
A BroadcastChannel that works in New Browsers, Old Browsers, WebWorkers, NodeJs, Deno and iframes
89 lines (86 loc) • 2.69 kB
JavaScript
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;
};
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) {
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 () {});
});
}
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();
}
if (this._wKMC.c) {
this._wKMC.c.abort('LeaderElectionWebLock.die() called');
}
return sendLeaderMessage(this, 'death');
}
};