From b7723460cd90aeb558047eb4861e4f0c358fefcc Mon Sep 17 00:00:00 2001
From: pubkey <8926560+pubkey@users.noreply.github.com>
Date: Mon, 31 Oct 2022 21:14:31 +0100
Subject: [PATCH] 4.18.1
---
.github/README.md | 16 +
CHANGELOG.md | 4 +
README.md | 19 +-
dist/es5node/broadcast-channel.js | 80 +--
dist/es5node/browserify.index.js | 1 -
dist/es5node/index.es5.js | 2 +-
dist/es5node/index.js | 2 -
dist/es5node/leader-election.js | 103 +---
dist/es5node/method-chooser.js | 26 +-
dist/es5node/methods/indexed-db.js | 84 +--
dist/es5node/methods/localstorage.js | 42 +-
dist/es5node/methods/native.js | 13 -
dist/es5node/methods/node.js | 219 +-------
dist/es5node/methods/simulate.js | 9 -
dist/es5node/options.js | 26 +-
dist/es5node/util.js | 11 +-
dist/esbrowser/broadcast-channel.js | 73 +--
dist/esbrowser/browserify.index.js | 1 -
dist/esbrowser/index.es5.js | 1 +
dist/esbrowser/leader-election.js | 101 +---
dist/esbrowser/method-chooser.js | 17 +-
dist/esbrowser/methods/indexed-db.js | 65 +--
dist/esbrowser/methods/localstorage.js | 27 +-
dist/esbrowser/methods/native.js | 4 -
dist/esbrowser/methods/node.js | 169 ++----
dist/esbrowser/options.js | 25 +-
dist/esbrowser/util.js | 5 +-
dist/esnode/broadcast-channel.js | 73 +--
dist/esnode/browserify.index.js | 1 -
dist/esnode/index.es5.js | 1 +
dist/esnode/leader-election.js | 101 +---
dist/esnode/method-chooser.js | 21 +-
dist/esnode/methods/indexed-db.js | 65 +--
dist/esnode/methods/localstorage.js | 27 +-
dist/esnode/methods/native.js | 4 -
dist/esnode/methods/node.js | 169 ++----
dist/esnode/options.js | 25 +-
dist/esnode/util.js | 5 +-
dist/lib/broadcast-channel.js | 80 +--
dist/lib/browser.js | 399 ++++----------
dist/lib/browser.min.js | 2 +-
dist/lib/browserify.index.js | 1 -
dist/lib/index.es5.js | 2 +-
dist/lib/index.js | 2 -
dist/lib/leader-election.js | 103 +---
dist/lib/method-chooser.js | 24 +-
dist/lib/methods/indexed-db.js | 84 +--
dist/lib/methods/localstorage.js | 42 +-
dist/lib/methods/native.js | 13 -
dist/lib/methods/node.js | 219 +-------
dist/lib/methods/simulate.js | 9 -
dist/lib/options.js | 26 +-
dist/lib/util.js | 11 +-
docs/e2e.js | 707 ++++++++-----------------
docs/iframe.js | 431 ++++-----------
docs/index.js | 428 ++++-----------
docs/leader-iframe.js | 430 ++++-----------
docs/worker.js | 449 +++++-----------
package.json | 2 +-
59 files changed, 1300 insertions(+), 3801 deletions(-)
diff --git a/.github/README.md b/.github/README.md
index 94fbe3fa..e4bd3396 100644
--- a/.github/README.md
+++ b/.github/README.md
@@ -29,6 +29,22 @@ A BroadcastChannel that allows you to send data between different browser-tabs o
This behaves similar to the [BroadcastChannel-API](https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API) which is currently only featured in [some browsers](https://caniuse.com/#feat=broadcastchannel).
+
+# Sponsored by
+
+
+
+
+
+
+ The JavaScript Database
+
+
+
## Using the BroadcastChannel
```bash
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1dc1f936..7a455a0b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,10 @@
## X.X.X (comming soon)
+## 4.18.1 (31 October 2022)
+
+- Updated dependencies
+
## 4.18.0 (6 October 2022)
diff --git a/README.md b/README.md
index fdd2b8e1..a2f3d04a 100644
--- a/README.md
+++ b/README.md
@@ -23,7 +23,8 @@
+ alt="follow on Twitter" />
+
![demo.gif](docs/files/demo.gif)
@@ -34,3 +35,19 @@ A BroadcastChannel that allows you to send data between different browser-tabs o
And a LeaderElection over the channels.
# [Read the full documentation on github](https://github.com/pubkey/broadcast-channel)
+
+
+# Sponsored by
+
+
+
+
+
+
+ The JavaScript Database
+
+
diff --git a/dist/es5node/broadcast-channel.js b/dist/es5node/broadcast-channel.js
index 8f3fc9bf..d8162620 100644
--- a/dist/es5node/broadcast-channel.js
+++ b/dist/es5node/broadcast-channel.js
@@ -6,13 +6,9 @@ Object.defineProperty(exports, "__esModule", {
exports.OPEN_BROADCAST_CHANNELS = exports.BroadcastChannel = void 0;
exports.clearNodeFolder = clearNodeFolder;
exports.enforceOptions = enforceOptions;
-
var _util = require("./util.js");
-
var _methodChooser = require("./method-chooser.js");
-
var _options = require("./options.js");
-
/**
* Contains all open channels,
* used in tests to ensure everything is closed.
@@ -20,77 +16,73 @@ var _options = require("./options.js");
var OPEN_BROADCAST_CHANNELS = new Set();
exports.OPEN_BROADCAST_CHANNELS = OPEN_BROADCAST_CHANNELS;
var lastId = 0;
-
var BroadcastChannel = function BroadcastChannel(name, options) {
// identifier of the channel to debug stuff
this.id = lastId++;
OPEN_BROADCAST_CHANNELS.add(this);
this.name = name;
-
if (ENFORCED_OPTIONS) {
options = ENFORCED_OPTIONS;
}
-
this.options = (0, _options.fillOptionsWithDefaults)(options);
- this.method = (0, _methodChooser.chooseMethod)(this.options); // isListening
+ this.method = (0, _methodChooser.chooseMethod)(this.options);
+ // isListening
this._iL = false;
+
/**
* _onMessageListener
* setting onmessage twice,
* will overwrite the first listener
*/
-
this._onML = null;
+
/**
* _addEventListeners
*/
-
this._addEL = {
message: [],
internal: []
};
+
/**
* Unsend message promises
* where the sending is still in progress
* @type {Set}
*/
-
this._uMP = new Set();
+
/**
* _beforeClose
* array of promises that will be awaited
* before the channel is closed
*/
-
this._befC = [];
+
/**
* _preparePromise
*/
-
this._prepP = null;
-
_prepareChannel(this);
-}; // STATICS
+};
+
+// STATICS
/**
* used to identify if someone overwrites
* window.BroadcastChannel with this
* See methods/native.js
*/
-
-
exports.BroadcastChannel = BroadcastChannel;
BroadcastChannel._pubkey = true;
+
/**
* clears the tmp-folder if is node
* @return {Promise} true if has run, false if not node
*/
-
function clearNodeFolder(options) {
options = (0, _options.fillOptionsWithDefaults)(options);
var method = (0, _methodChooser.chooseMethod)(options);
-
if (method.type === 'node') {
return method.clearNodeFolder().then(function () {
return true;
@@ -99,19 +91,17 @@ function clearNodeFolder(options) {
return _util.PROMISE_RESOLVED_FALSE;
}
}
+
/**
* if set, this method is enforced,
* no mather what the options are
*/
-
-
var ENFORCED_OPTIONS;
-
function enforceOptions(options) {
ENFORCED_OPTIONS = options;
-} // PROTOTYPE
-
+}
+// PROTOTYPE
BroadcastChannel.prototype = {
postMessage: function postMessage(msg) {
if (this.closed) {
@@ -123,87 +113,77 @@ BroadcastChannel.prototype = {
*/
JSON.stringify(msg));
}
-
return _post(this, 'message', msg);
},
postInternal: function postInternal(msg) {
return _post(this, 'internal', msg);
},
-
set onmessage(fn) {
var time = this.method.microSeconds();
var listenObj = {
time: time,
fn: fn
};
-
_removeListenerObject(this, 'message', this._onML);
-
if (fn && typeof fn === 'function') {
this._onML = listenObj;
-
_addListenerObject(this, 'message', listenObj);
} else {
this._onML = null;
}
},
-
addEventListener: function addEventListener(type, fn) {
var time = this.method.microSeconds();
var listenObj = {
time: time,
fn: fn
};
-
_addListenerObject(this, type, listenObj);
},
removeEventListener: function removeEventListener(type, fn) {
var obj = this._addEL[type].find(function (obj) {
return obj.fn === fn;
});
-
_removeListenerObject(this, type, obj);
},
close: function close() {
var _this = this;
-
if (this.closed) {
return;
}
-
OPEN_BROADCAST_CHANNELS["delete"](this);
this.closed = true;
var awaitPrepare = this._prepP ? this._prepP : _util.PROMISE_RESOLVED_VOID;
this._onML = null;
this._addEL.message = [];
- return awaitPrepare // wait until all current sending are processed
+ return awaitPrepare
+ // wait until all current sending are processed
.then(function () {
return Promise.all(Array.from(_this._uMP));
- }) // run before-close hooks
+ })
+ // run before-close hooks
.then(function () {
return Promise.all(_this._befC.map(function (fn) {
return fn();
}));
- }) // close the channel
+ })
+ // close the channel
.then(function () {
return _this.method.close(_this._state);
});
},
-
get type() {
return this.method.type;
},
-
get isClosed() {
return this.closed;
}
-
};
+
/**
* Post a message over the channel
* @returns {Promise} that resolved when the message sending is done
*/
-
function _post(broadcastChannel, type, msg) {
var time = broadcastChannel.method.microSeconds();
var msgObj = {
@@ -213,25 +193,22 @@ function _post(broadcastChannel, type, msg) {
};
var awaitPrepare = broadcastChannel._prepP ? broadcastChannel._prepP : _util.PROMISE_RESOLVED_VOID;
return awaitPrepare.then(function () {
- var sendPromise = broadcastChannel.method.postMessage(broadcastChannel._state, msgObj); // add/remove to unsend messages list
+ var sendPromise = broadcastChannel.method.postMessage(broadcastChannel._state, msgObj);
+ // add/remove to unsend messages list
broadcastChannel._uMP.add(sendPromise);
-
sendPromise["catch"]().then(function () {
return broadcastChannel._uMP["delete"](sendPromise);
});
return sendPromise;
});
}
-
function _prepareChannel(channel) {
var maybePromise = channel.method.create(channel.name, channel.options);
-
if ((0, _util.isPromise)(maybePromise)) {
channel._prepP = maybePromise;
maybePromise.then(function (s) {
// used in tests to simulate slow runtime
-
/*if (channel.options.prepareDelay) {
await new Promise(res => setTimeout(res, this.options.prepareDelay));
}*/
@@ -241,30 +218,25 @@ function _prepareChannel(channel) {
channel._state = maybePromise;
}
}
-
function _hasMessageListeners(channel) {
if (channel._addEL.message.length > 0) return true;
if (channel._addEL.internal.length > 0) return true;
return false;
}
-
function _addListenerObject(channel, type, obj) {
channel._addEL[type].push(obj);
-
_startListening(channel);
}
-
function _removeListenerObject(channel, type, obj) {
channel._addEL[type] = channel._addEL[type].filter(function (o) {
return o !== obj;
});
-
_stopListening(channel);
}
-
function _startListening(channel) {
if (!channel._iL && _hasMessageListeners(channel)) {
// someone is listening, start subscribing
+
var listenerFn = function listenerFn(msgObj) {
channel._addEL[msgObj.type].forEach(function (listenerObject) {
/**
@@ -278,15 +250,12 @@ function _startListening(channel) {
*/
var hundredMsInMicro = 100 * 1000;
var minMessageTime = listenerObject.time - hundredMsInMicro;
-
if (msgObj.time >= minMessageTime) {
listenerObject.fn(msgObj.data);
}
});
};
-
var time = channel.method.microSeconds();
-
if (channel._prepP) {
channel._prepP.then(function () {
channel._iL = true;
@@ -298,7 +267,6 @@ function _startListening(channel) {
}
}
}
-
function _stopListening(channel) {
if (channel._iL && !_hasMessageListeners(channel)) {
// noone is listening, stop subscribing
diff --git a/dist/es5node/browserify.index.js b/dist/es5node/browserify.index.js
index a30fe523..f9966b51 100644
--- a/dist/es5node/browserify.index.js
+++ b/dist/es5node/browserify.index.js
@@ -1,7 +1,6 @@
"use strict";
var _module = require('./index.es5.js');
-
var BroadcastChannel = _module.BroadcastChannel;
var createLeaderElection = _module.createLeaderElection;
window['BroadcastChannel2'] = BroadcastChannel;
diff --git a/dist/es5node/index.es5.js b/dist/es5node/index.es5.js
index e754438d..61d6ab29 100644
--- a/dist/es5node/index.es5.js
+++ b/dist/es5node/index.es5.js
@@ -1,7 +1,6 @@
"use strict";
var _index = require("./index.js");
-
/**
* because babel can only export on default-attribute,
* we use this for the non-module-build
@@ -10,6 +9,7 @@ var _index = require("./index.js");
* but
* var BroadcastChannel = require('broadcast-channel');
*/
+
module.exports = {
BroadcastChannel: _index.BroadcastChannel,
createLeaderElection: _index.createLeaderElection,
diff --git a/dist/es5node/index.js b/dist/es5node/index.js
index 57d1b9aa..f3b4f471 100644
--- a/dist/es5node/index.js
+++ b/dist/es5node/index.js
@@ -39,7 +39,5 @@ Object.defineProperty(exports, "enforceOptions", {
return _broadcastChannel.enforceOptions;
}
});
-
var _broadcastChannel = require("./broadcast-channel.js");
-
var _leaderElection = require("./leader-election.js");
\ No newline at end of file
diff --git a/dist/es5node/leader-election.js b/dist/es5node/leader-election.js
index 5c3a9715..1e2b8cb5 100644
--- a/dist/es5node/leader-election.js
+++ b/dist/es5node/leader-election.js
@@ -5,37 +5,30 @@ Object.defineProperty(exports, "__esModule", {
});
exports.beLeader = beLeader;
exports.createLeaderElection = createLeaderElection;
-
var _util = require("./util.js");
-
var _unload = require("unload");
-
var LeaderElection = function LeaderElection(broadcastChannel, options) {
var _this = this;
-
this.broadcastChannel = broadcastChannel;
this._options = options;
this.isLeader = false;
this.hasLeader = false;
this.isDead = false;
this.token = (0, _util.randomToken)();
+
/**
* Apply Queue,
* used to ensure we do not run applyOnce()
* in parallel.
*/
+ this._aplQ = _util.PROMISE_RESOLVED_VOID;
+ // amount of unfinished applyOnce() calls
+ this._aplQC = 0;
- this._aplQ = _util.PROMISE_RESOLVED_VOID; // amount of unfinished applyOnce() calls
-
- this._aplQC = 0; // things to clean up
-
+ // things to clean up
this._unl = []; // _unloads
-
this._lstns = []; // _listeners
-
this._dpL = function () {}; // onduplicate listener
-
-
this._dpLC = false; // true when onduplicate called
/**
@@ -43,55 +36,47 @@ var LeaderElection = function LeaderElection(broadcastChannel, options) {
* we still listen to messages to ensure the hasLeader flag
* is set correctly.
*/
-
var hasLeaderListener = function hasLeaderListener(msg) {
if (msg.context === 'leader') {
if (msg.action === 'death') {
_this.hasLeader = false;
}
-
if (msg.action === 'tell') {
_this.hasLeader = true;
}
}
};
-
this.broadcastChannel.addEventListener('internal', hasLeaderListener);
-
this._lstns.push(hasLeaderListener);
};
-
LeaderElection.prototype = {
/**
* Returns true if the instance is leader,
* false if not.
* @async
*/
- applyOnce: function applyOnce( // true if the applyOnce() call came from the fallbackInterval cycle
+ applyOnce: function applyOnce(
+ // true if the applyOnce() call came from the fallbackInterval cycle
isFromFallbackInterval) {
var _this2 = this;
-
if (this.isLeader) {
return (0, _util.sleep)(0, true);
}
-
if (this.isDead) {
return (0, _util.sleep)(0, false);
}
+
/**
* Already applying more then once,
* -> wait for the apply queue to be finished.
*/
-
-
if (this._aplQC > 1) {
return this._aplQ;
}
+
/**
* Add a new apply-run
*/
-
-
var applyRun = function applyRun() {
/**
* Optimization shortcuts.
@@ -101,7 +86,6 @@ LeaderElection.prototype = {
if (_this2.isLeader) {
return _util.PROMISE_RESOLVED_TRUE;
}
-
var stopCriteria = false;
var stopCriteriaPromiseResolve;
/**
@@ -110,7 +94,6 @@ LeaderElection.prototype = {
* have to await the responseTime when it is already clear
* that the election failed.
*/
-
var stopCriteriaPromise = new Promise(function (res) {
stopCriteriaPromiseResolve = function stopCriteriaPromiseResolve() {
stopCriteria = true;
@@ -118,11 +101,9 @@ LeaderElection.prototype = {
};
});
var recieved = [];
-
var handleMessage = function handleMessage(msg) {
if (msg.context === 'leader' && msg.token != _this2.token) {
recieved.push(msg);
-
if (msg.action === 'apply') {
// other is applying
if (msg.token > _this2.token) {
@@ -133,7 +114,6 @@ LeaderElection.prototype = {
stopCriteriaPromiseResolve();
}
}
-
if (msg.action === 'tell') {
// other is already leader
stopCriteriaPromiseResolve();
@@ -141,8 +121,8 @@ LeaderElection.prototype = {
}
}
};
-
_this2.broadcastChannel.addEventListener('internal', handleMessage);
+
/**
* If the applyOnce() call came from the fallbackInterval,
* we can assume that the election runs in the background and
@@ -153,26 +133,24 @@ LeaderElection.prototype = {
* But also it takes longer which is not a problem because we anyway
* run in the background.
*/
-
-
var waitForAnswerTime = isFromFallbackInterval ? _this2._options.responseTime * 4 : _this2._options.responseTime;
-
var applyPromise = _sendMessage(_this2, 'apply') // send out that this one is applying
.then(function () {
return Promise.race([(0, _util.sleep)(waitForAnswerTime), stopCriteriaPromise.then(function () {
return Promise.reject(new Error());
})]);
- }) // send again in case another instance was just created
+ })
+ // send again in case another instance was just created
.then(function () {
return _sendMessage(_this2, 'apply');
- }) // let others time to respond
+ })
+ // let others time to respond
.then(function () {
return Promise.race([(0, _util.sleep)(waitForAnswerTime), stopCriteriaPromise.then(function () {
return Promise.reject(new Error());
})]);
})["catch"](function () {}).then(function () {
_this2.broadcastChannel.removeEventListener('internal', handleMessage);
-
if (!stopCriteria) {
// no stop criteria -> own is leader
return beLeader(_this2).then(function () {
@@ -183,10 +161,8 @@ LeaderElection.prototype = {
return false;
}
});
-
return applyPromise;
};
-
this._aplQC = this._aplQC + 1;
this._aplQ = this._aplQ.then(function () {
return applyRun();
@@ -198,82 +174,68 @@ LeaderElection.prototype = {
});
},
awaitLeadership: function awaitLeadership() {
- if (
- /* _awaitLeadershipPromise */
+ if ( /* _awaitLeadershipPromise */
!this._aLP) {
this._aLP = _awaitLeadershipOnce(this);
}
-
return this._aLP;
},
-
set onduplicate(fn) {
this._dpL = fn;
},
-
die: function die() {
var _this3 = this;
-
this._lstns.forEach(function (listener) {
return _this3.broadcastChannel.removeEventListener('internal', listener);
});
-
this._lstns = [];
-
this._unl.forEach(function (uFn) {
return uFn.remove();
});
-
this._unl = [];
-
if (this.isLeader) {
this.hasLeader = false;
this.isLeader = false;
}
-
this.isDead = true;
return _sendMessage(this, 'death');
}
};
+
/**
* @param leaderElector {LeaderElector}
*/
-
function _awaitLeadershipOnce(leaderElector) {
if (leaderElector.isLeader) {
return _util.PROMISE_RESOLVED_VOID;
}
-
return new Promise(function (res) {
var resolved = false;
-
function finish() {
if (resolved) {
return;
}
-
resolved = true;
leaderElector.broadcastChannel.removeEventListener('internal', whenDeathListener);
res(true);
- } // try once now
-
+ }
+ // try once now
leaderElector.applyOnce().then(function () {
if (leaderElector.isLeader) {
finish();
}
});
+
/**
* Try on fallbackInterval
* @recursive
*/
-
var tryOnFallBack = function tryOnFallBack() {
return (0, _util.sleep)(leaderElector._options.fallbackInterval).then(function () {
if (leaderElector.isDead || resolved) {
return;
}
-
if (leaderElector.isLeader) {
finish();
} else {
@@ -287,9 +249,9 @@ function _awaitLeadershipOnce(leaderElector) {
}
});
};
+ tryOnFallBack();
- tryOnFallBack(); // try when other leader dies
-
+ // try when other leader dies
var whenDeathListener = function whenDeathListener(msg) {
if (msg.context === 'leader' && msg.action === 'death') {
leaderElector.hasLeader = false;
@@ -300,17 +262,14 @@ function _awaitLeadershipOnce(leaderElector) {
});
}
};
-
leaderElector.broadcastChannel.addEventListener('internal', whenDeathListener);
-
leaderElector._lstns.push(whenDeathListener);
});
}
+
/**
* sends and internal message over the broadcast-channel
*/
-
-
function _sendMessage(leaderElector, action) {
var msgJson = {
context: 'leader',
@@ -319,21 +278,17 @@ function _sendMessage(leaderElector, action) {
};
return leaderElector.broadcastChannel.postInternal(msgJson);
}
-
function beLeader(leaderElector) {
leaderElector.isLeader = true;
leaderElector.hasLeader = true;
var unloadFn = (0, _unload.add)(function () {
return leaderElector.die();
});
-
leaderElector._unl.push(unloadFn);
-
var isLeaderListener = function isLeaderListener(msg) {
if (msg.context === 'leader' && msg.action === 'apply') {
_sendMessage(leaderElector, 'tell');
}
-
if (msg.context === 'leader' && msg.action === 'tell' && !leaderElector._dpLC) {
/**
* another instance is also leader!
@@ -344,49 +299,35 @@ function beLeader(leaderElector) {
* @link https://github.com/pubkey/broadcast-channel/issues/385
*/
leaderElector._dpLC = true;
-
leaderElector._dpL(); // message the lib user so the app can handle the problem
-
-
_sendMessage(leaderElector, 'tell'); // ensure other leader also knows the problem
-
}
};
leaderElector.broadcastChannel.addEventListener('internal', isLeaderListener);
-
leaderElector._lstns.push(isLeaderListener);
-
return _sendMessage(leaderElector, 'tell');
}
-
function fillOptionsWithDefaults(options, channel) {
if (!options) options = {};
options = JSON.parse(JSON.stringify(options));
-
if (!options.fallbackInterval) {
options.fallbackInterval = 3000;
}
-
if (!options.responseTime) {
options.responseTime = channel.method.averageResponseTime(channel.options);
}
-
return options;
}
-
function createLeaderElection(channel, options) {
if (channel._leaderElector) {
throw new Error('BroadcastChannel already has a leader-elector');
}
-
options = fillOptionsWithDefaults(options, channel);
var elector = new LeaderElection(channel, options);
-
channel._befC.push(function () {
return elector.die();
});
-
channel._leaderElector = elector;
return elector;
}
\ No newline at end of file
diff --git a/dist/es5node/method-chooser.js b/dist/es5node/method-chooser.js
index 4bdab13a..0e616cf7 100644
--- a/dist/es5node/method-chooser.js
+++ b/dist/es5node/method-chooser.js
@@ -1,61 +1,51 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
-
var _typeof = require("@babel/runtime/helpers/typeof");
-
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.chooseMethod = chooseMethod;
-
var _native = _interopRequireDefault(require("./methods/native.js"));
-
var _indexedDb = _interopRequireDefault(require("./methods/indexed-db.js"));
-
var _localstorage = _interopRequireDefault(require("./methods/localstorage.js"));
-
var _simulate = _interopRequireDefault(require("./methods/simulate.js"));
-
var NodeMethod = _interopRequireWildcard(require("./methods/node.js"));
-
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
-
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
-
// the line below will be removed from es5/browser builds
+
// order is important
-var METHODS = [_native["default"], // fastest
+var METHODS = [_native["default"],
+// fastest
_indexedDb["default"], _localstorage["default"]];
-
function chooseMethod(options) {
- var chooseMethods = [].concat(options.methods, METHODS).filter(Boolean); // the line below will be removed from es5/browser builds
+ var chooseMethods = [].concat(options.methods, METHODS).filter(Boolean);
- chooseMethods.push(NodeMethod); // directly chosen
+ // the line below will be removed from es5/browser builds
+ chooseMethods.push(NodeMethod);
+ // directly chosen
if (options.type) {
if (options.type === 'simulate') {
// only use simulate-method if directly chosen
return _simulate["default"];
}
-
var ret = chooseMethods.find(function (m) {
return m.type === options.type;
});
if (!ret) throw new Error('method-type ' + options.type + ' not found');else return ret;
}
+
/**
* if no webworker support is needed,
* remove idb from the list so that localstorage is been chosen
*/
-
-
if (!options.webWorkerSupport) {
chooseMethods = chooseMethods.filter(function (m) {
return m.type !== 'idb';
});
}
-
var useMethod = chooseMethods.find(function (method) {
return method.canBeUsed();
});
diff --git a/dist/es5node/methods/indexed-db.js b/dist/es5node/methods/indexed-db.js
index dc38ebe8..b3b21767 100644
--- a/dist/es5node/methods/indexed-db.js
+++ b/dist/es5node/methods/indexed-db.js
@@ -22,13 +22,9 @@ exports.postMessage = postMessage;
exports.removeMessagesById = removeMessagesById;
exports.type = void 0;
exports.writeMessage = writeMessage;
-
var _util = require("../util.js");
-
var _obliviousSet = require("oblivious-set");
-
var _options = require("../options.js");
-
/**
* this method uses indexeddb to store the messages
* There is currently no observerAPI for idb
@@ -37,58 +33,54 @@ var _options = require("../options.js");
* When working on this, ensure to use these performance optimizations:
* @link https://rxdb.info/slow-indexeddb.html
*/
+
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var DB_PREFIX = 'pubkey.broadcast-channel-0-';
var OBJECT_STORE_ID = 'messages';
+
/**
* Use relaxed durability for faster performance on all transactions.
* @link https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/
*/
-
var TRANSACTION_SETTINGS = {
durability: 'relaxed'
};
exports.TRANSACTION_SETTINGS = TRANSACTION_SETTINGS;
var type = 'idb';
exports.type = type;
-
function getIdb() {
if (typeof indexedDB !== 'undefined') return indexedDB;
-
if (typeof window !== 'undefined') {
if (typeof window.mozIndexedDB !== 'undefined') return window.mozIndexedDB;
if (typeof window.webkitIndexedDB !== 'undefined') return window.webkitIndexedDB;
if (typeof window.msIndexedDB !== 'undefined') return window.msIndexedDB;
}
-
return false;
}
+
/**
* If possible, we should explicitly commit IndexedDB transactions
* for better performance.
* @link https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/
*/
-
-
function commitIndexedDBTransaction(tx) {
if (tx.commit) {
tx.commit();
}
}
-
function createDatabase(channelName) {
- var IndexedDB = getIdb(); // create table
+ var IndexedDB = getIdb();
+ // create table
var dbName = DB_PREFIX + channelName;
+
/**
* All IndexedDB databases are opened without version
* because it is a bit faster, especially on firefox
* @link http://nparashuram.com/IndexedDB/perf/#Open%20Database%20with%20version
*/
-
var openRequest = IndexedDB.open(dbName);
-
openRequest.onupgradeneeded = function (ev) {
var db = ev.target.result;
db.createObjectStore(OBJECT_STORE_ID, {
@@ -96,24 +88,21 @@ function createDatabase(channelName) {
autoIncrement: true
});
};
-
var dbPromise = new Promise(function (res, rej) {
openRequest.onerror = function (ev) {
return rej(ev);
};
-
openRequest.onsuccess = function () {
res(openRequest.result);
};
});
return dbPromise;
}
+
/**
* writes the new message to the database
* so other readers can find it
*/
-
-
function writeMessage(db, readerUuid, messageJson) {
var time = new Date().getTime();
var writeObject = {
@@ -126,17 +115,14 @@ function writeMessage(db, readerUuid, messageJson) {
tx.oncomplete = function () {
return res();
};
-
tx.onerror = function (ev) {
return rej(ev);
};
-
var objectStore = tx.objectStore(OBJECT_STORE_ID);
objectStore.add(writeObject);
commitIndexedDBTransaction(tx);
});
}
-
function getAllMessages(db) {
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS);
var objectStore = tx.objectStore(OBJECT_STORE_ID);
@@ -144,10 +130,9 @@ function getAllMessages(db) {
return new Promise(function (res) {
objectStore.openCursor().onsuccess = function (ev) {
var cursor = ev.target.result;
-
if (cursor) {
- ret.push(cursor.value); //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
-
+ ret.push(cursor.value);
+ //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor["continue"]();
} else {
commitIndexedDBTransaction(tx);
@@ -156,31 +141,28 @@ function getAllMessages(db) {
};
});
}
-
function getMessagesHigherThan(db, lastCursorId) {
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS);
var objectStore = tx.objectStore(OBJECT_STORE_ID);
var ret = [];
var keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity);
+
/**
* Optimization shortcut,
* if getAll() can be used, do not use a cursor.
* @link https://rxdb.info/slow-indexeddb.html
*/
-
if (objectStore.getAll) {
var getAllRequest = objectStore.getAll(keyRangeValue);
return new Promise(function (res, rej) {
getAllRequest.onerror = function (err) {
return rej(err);
};
-
getAllRequest.onsuccess = function (e) {
res(e.target.result);
};
});
}
-
function openCursor() {
// Occasionally Safari will fail on IDBKeyRange.bound, this
// catches that error, having it open the cursor to the first
@@ -192,17 +174,13 @@ function getMessagesHigherThan(db, lastCursorId) {
return objectStore.openCursor();
}
}
-
return new Promise(function (res, rej) {
var openCursorRequest = openCursor();
-
openCursorRequest.onerror = function (err) {
return rej(err);
};
-
openCursorRequest.onsuccess = function (ev) {
var cursor = ev.target.result;
-
if (cursor) {
if (cursor.value.id < lastCursorId + 1) {
cursor["continue"](lastCursorId + 1);
@@ -217,12 +195,10 @@ function getMessagesHigherThan(db, lastCursorId) {
};
});
}
-
function removeMessagesById(channelState, ids) {
if (channelState.closed) {
return Promise.resolve([]);
}
-
var tx = channelState.db.transaction(OBJECT_STORE_ID, 'readwrite', TRANSACTION_SETTINGS);
var objectStore = tx.objectStore(OBJECT_STORE_ID);
return Promise.all(ids.map(function (id) {
@@ -234,7 +210,6 @@ function removeMessagesById(channelState, ids) {
});
}));
}
-
function getOldMessages(db, ttl) {
var olderThen = new Date().getTime() - ttl;
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS);
@@ -243,13 +218,11 @@ function getOldMessages(db, ttl) {
return new Promise(function (res) {
objectStore.openCursor().onsuccess = function (ev) {
var cursor = ev.target.result;
-
if (cursor) {
var msgObk = cursor.value;
-
if (msgObk.time < olderThen) {
- ret.push(msgObk); //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
-
+ ret.push(msgObk);
+ //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor["continue"]();
} else {
// no more old messages,
@@ -263,7 +236,6 @@ function getOldMessages(db, ttl) {
};
});
}
-
function cleanOldMessages(channelState) {
return getOldMessages(channelState.db, channelState.options.idb.ttl).then(function (tooOld) {
return removeMessagesById(channelState, tooOld.map(function (msg) {
@@ -271,7 +243,6 @@ function cleanOldMessages(channelState) {
}));
});
}
-
function create(channelName, options) {
options = (0, _options.fillOptionsWithDefaults)(options);
return createDatabase(channelName).then(function (db) {
@@ -281,7 +252,6 @@ function create(channelName, options) {
channelName: channelName,
options: options,
uuid: (0, _util.randomToken)(),
-
/**
* emittedMessagesIds
* contains all messages that have been emitted before
@@ -294,30 +264,27 @@ function create(channelName, options) {
readQueuePromises: [],
db: db
};
+
/**
* Handle abrupt closes that do not originate from db.close().
* This could happen, for example, if the underlying storage is
* removed or if the user clears the database in the browser's
* history preferences.
*/
-
db.onclose = function () {
state.closed = true;
if (options.idb.onclose) options.idb.onclose();
};
+
/**
* if service-workers are used,
* we have no 'storage'-event if they post a message,
* therefore we also have to set an interval
*/
-
-
_readLoop(state);
-
return state;
});
}
-
function _readLoop(state) {
if (state.closed) return;
readNewMessages(state).then(function () {
@@ -326,25 +293,21 @@ function _readLoop(state) {
return _readLoop(state);
});
}
-
function _filterMessage(msgObj, state) {
if (msgObj.uuid === state.uuid) return false; // send by own
-
if (state.eMIs.has(msgObj.id)) return false; // already emitted
-
if (msgObj.data.time < state.messagesCallbackTime) return false; // older then onMessageCallback
-
return true;
}
+
/**
* reads all new messages from the database and emits them
*/
-
-
function readNewMessages(state) {
// channel already closed
- if (state.closed) return _util.PROMISE_RESOLVED_VOID; // if no one is listening, we do not need to scan for new messages
+ if (state.closed) return _util.PROMISE_RESOLVED_VOID;
+ // if no one is listening, we do not need to scan for new messages
if (!state.messagesCallback) return _util.PROMISE_RESOLVED_VOID;
return getMessagesHigherThan(state.db, state.lastCursorId).then(function (newerMessages) {
var useMessages = newerMessages
@@ -352,21 +315,18 @@ function readNewMessages(state) {
* there is a bug in iOS where the msgObj can be undefined some times
* so we filter them out
* @link https://github.com/pubkey/broadcast-channel/issues/19
- */
- .filter(function (msgObj) {
+ */.filter(function (msgObj) {
return !!msgObj;
}).map(function (msgObj) {
if (msgObj.id > state.lastCursorId) {
state.lastCursorId = msgObj.id;
}
-
return msgObj;
}).filter(function (msgObj) {
return _filterMessage(msgObj, state);
}).sort(function (msgObjA, msgObjB) {
return msgObjA.time - msgObjB.time;
}); // sort by time
-
useMessages.forEach(function (msgObj) {
if (state.messagesCallback) {
state.eMIs.add(msgObj.id);
@@ -376,12 +336,10 @@ function readNewMessages(state) {
return _util.PROMISE_RESOLVED_VOID;
});
}
-
function close(channelState) {
channelState.closed = true;
channelState.db.close();
}
-
function postMessage(channelState, messageJson) {
channelState.writeBlockPromise = channelState.writeBlockPromise.then(function () {
return writeMessage(channelState.db, channelState.uuid, messageJson);
@@ -393,27 +351,21 @@ function postMessage(channelState, messageJson) {
});
return channelState.writeBlockPromise;
}
-
function onMessage(channelState, fn, time) {
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
readNewMessages(channelState);
}
-
function canBeUsed() {
var idb = getIdb();
-
if (!idb) {
return false;
}
-
return true;
}
-
function averageResponseTime(options) {
return options.idb.fallbackInterval * 2;
}
-
var _default = {
create: create,
close: close,
diff --git a/dist/es5node/methods/localstorage.js b/dist/es5node/methods/localstorage.js
index 1f308a9f..0a3d58bb 100644
--- a/dist/es5node/methods/localstorage.js
+++ b/dist/es5node/methods/localstorage.js
@@ -16,13 +16,9 @@ exports.postMessage = postMessage;
exports.removeStorageEventListener = removeStorageEventListener;
exports.storageKey = storageKey;
exports.type = void 0;
-
var _obliviousSet = require("oblivious-set");
-
var _options = require("../options.js");
-
var _util = require("../util.js");
-
/**
* A localStorage-only method which uses localstorage and its 'storage'-event
* This does not work inside of webworkers because they have no access to locastorage
@@ -30,41 +26,38 @@ var _util = require("../util.js");
* @link https://caniuse.com/#feat=namevalue-storage
* @link https://caniuse.com/#feat=indexeddb
*/
+
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var KEY_PREFIX = 'pubkey.broadcastChannel-';
var type = 'localstorage';
+
/**
* copied from crosstab
* @link https://github.com/tejacques/crosstab/blob/master/src/crosstab.js#L32
*/
-
exports.type = type;
-
function getLocalStorage() {
var localStorage;
if (typeof window === 'undefined') return null;
-
try {
localStorage = window.localStorage;
localStorage = window['ie8-eventlistener/storage'] || window.localStorage;
- } catch (e) {// New versions of Firefox throw a Security exception
+ } catch (e) {
+ // New versions of Firefox throw a Security exception
// if cookies are disabled. See
// https://bugzilla.mozilla.org/show_bug.cgi?id=1028153
}
-
return localStorage;
}
-
function storageKey(channelName) {
return KEY_PREFIX + channelName;
}
+
/**
* writes the new message to the storage
* and fires the storage-event so other readers can find it
*/
-
-
function postMessage(channelState, messageJson) {
return new Promise(function (res) {
(0, _util.sleep)().then(function () {
@@ -77,12 +70,12 @@ function postMessage(channelState, messageJson) {
};
var value = JSON.stringify(writeObj);
getLocalStorage().setItem(key, value);
+
/**
* StorageEvent does not fire the 'storage' event
* in the window that changes the state of the local storage.
* So we fire it manually
*/
-
var ev = document.createEvent('Event');
ev.initEvent('storage', true, true);
ev.key = key;
@@ -92,52 +85,42 @@ function postMessage(channelState, messageJson) {
});
});
}
-
function addStorageEventListener(channelName, fn) {
var key = storageKey(channelName);
-
var listener = function listener(ev) {
if (ev.key === key) {
fn(JSON.parse(ev.newValue));
}
};
-
window.addEventListener('storage', listener);
return listener;
}
-
function removeStorageEventListener(listener) {
window.removeEventListener('storage', listener);
}
-
function create(channelName, options) {
options = (0, _options.fillOptionsWithDefaults)(options);
-
if (!canBeUsed()) {
throw new Error('BroadcastChannel: localstorage cannot be used');
}
-
var uuid = (0, _util.randomToken)();
+
/**
* eMIs
* contains all messages that have been emitted before
* @type {ObliviousSet}
*/
-
var eMIs = new _obliviousSet.ObliviousSet(options.localstorage.removeTimeout);
var state = {
channelName: channelName,
uuid: uuid,
eMIs: eMIs // emittedMessagesIds
-
};
+
state.listener = addStorageEventListener(channelName, function (msgObj) {
if (!state.messagesCallback) return; // no listener
-
if (msgObj.uuid === uuid) return; // own message
-
if (!msgObj.token || eMIs.has(msgObj.token)) return; // already emitted
-
if (msgObj.data.time && msgObj.data.time < state.messagesCallbackTime) return; // too old
eMIs.add(msgObj.token);
@@ -145,20 +128,16 @@ function create(channelName, options) {
});
return state;
}
-
function close(channelState) {
removeStorageEventListener(channelState.listener);
}
-
function onMessage(channelState, fn, time) {
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
}
-
function canBeUsed() {
var ls = getLocalStorage();
if (!ls) return false;
-
try {
var key = '__broadcastchannel_check';
ls.setItem(key, 'works');
@@ -169,22 +148,17 @@ function canBeUsed() {
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API#Private_Browsing_Incognito_modes
return false;
}
-
return true;
}
-
function averageResponseTime() {
var defaultTime = 120;
var userAgent = navigator.userAgent.toLowerCase();
-
if (userAgent.includes('safari') && !userAgent.includes('chrome')) {
// safari is much slower so this time is higher
return defaultTime * 2;
}
-
return defaultTime;
}
-
var _default = {
create: create,
close: close,
diff --git a/dist/es5node/methods/native.js b/dist/es5node/methods/native.js
index 8118f760..cabcfb3e 100644
--- a/dist/es5node/methods/native.js
+++ b/dist/es5node/methods/native.js
@@ -11,20 +11,16 @@ exports.microSeconds = exports["default"] = void 0;
exports.onMessage = onMessage;
exports.postMessage = postMessage;
exports.type = void 0;
-
var _util = require("../util.js");
-
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var type = 'native';
exports.type = type;
-
function create(channelName) {
var state = {
messagesCallback: null,
bc: new BroadcastChannel(channelName),
subFns: [] // subscriberFunctions
-
};
state.bc.onmessage = function (msg) {
@@ -32,15 +28,12 @@ function create(channelName) {
state.messagesCallback(msg.data);
}
};
-
return state;
}
-
function close(channelState) {
channelState.bc.close();
channelState.subFns = [];
}
-
function postMessage(channelState, messageJson) {
try {
channelState.bc.postMessage(messageJson, false);
@@ -49,31 +42,25 @@ function postMessage(channelState, messageJson) {
return Promise.reject(err);
}
}
-
function onMessage(channelState, fn) {
channelState.messagesCallback = fn;
}
-
function canBeUsed() {
if (typeof window === 'undefined') {
return false;
}
-
if (typeof BroadcastChannel === 'function') {
if (BroadcastChannel._pubkey) {
throw new Error('BroadcastChannel: Do not overwrite window.BroadcastChannel with this module, this is not a polyfill');
}
-
return true;
} else {
return false;
}
}
-
function averageResponseTime() {
return 150;
}
-
var _default = {
create: create,
close: close,
diff --git a/dist/es5node/methods/node.js b/dist/es5node/methods/node.js
index a3aa3c7e..76d38bc5 100644
--- a/dist/es5node/methods/node.js
+++ b/dist/es5node/methods/node.js
@@ -1,7 +1,6 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
-
Object.defineProperty(exports, "__esModule", {
value: true
});
@@ -35,37 +34,21 @@ exports.socketInfoPath = socketInfoPath;
exports.socketPath = socketPath;
exports.type = void 0;
exports.writeMessage = writeMessage;
-
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
-
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
-
var _util = _interopRequireDefault(require("util"));
-
var _fs = _interopRequireDefault(require("fs"));
-
var _crypto = _interopRequireDefault(require("crypto"));
-
var _os = _interopRequireDefault(require("os"));
-
var _events = _interopRequireDefault(require("events"));
-
var _net = _interopRequireDefault(require("net"));
-
var _path = _interopRequireDefault(require("path"));
-
var _rimraf = _interopRequireDefault(require("rimraf"));
-
var _pQueue = _interopRequireDefault(require("p-queue"));
-
var _unload = require("unload");
-
var _options = require("../options.js");
-
var _util2 = require("../util.js");
-
var _obliviousSet = require("oblivious-set");
-
/**
* this method is used in nodejs-environments.
* The ipc is handled via sockets and file-writes to the tmp-folder
@@ -84,29 +67,18 @@ function cleanPipeName(str) {
return str;
}
}
-
var mkdir = _util["default"].promisify(_fs["default"].mkdir);
-
var writeFile = _util["default"].promisify(_fs["default"].writeFile);
-
var readFile = _util["default"].promisify(_fs["default"].readFile);
-
var unlink = _util["default"].promisify(_fs["default"].unlink);
-
var readdir = _util["default"].promisify(_fs["default"].readdir);
-
var chmod = _util["default"].promisify(_fs["default"].chmod);
-
var removeDir = _util["default"].promisify(_rimraf["default"]);
-
var OTHER_INSTANCES = {};
var TMP_FOLDER_NAME = 'pubkey.bc';
-
var TMP_FOLDER_BASE = _path["default"].join(_os["default"].tmpdir(), TMP_FOLDER_NAME);
-
exports.TMP_FOLDER_BASE = TMP_FOLDER_BASE;
var getPathsCache = new Map();
-
function getPaths(channelName) {
if (!getPathsCache.has(channelName)) {
/**
@@ -116,21 +88,16 @@ function getPaths(channelName) {
* in using the same folders for different channels.
*/
var channelHash = _crypto["default"].createHash('sha256').update(channelName).digest('hex');
+
/**
* because the length of socket-paths is limited, we use only the first 20 chars
* and also start with A to ensure we do not start with a number
* @link https://serverfault.com/questions/641347/check-if-a-path-exceeds-maximum-for-unix-domain-socket
*/
-
-
var channelFolder = 'A' + channelHash.substring(0, 20);
-
var channelPathBase = _path["default"].join(TMP_FOLDER_BASE, channelFolder);
-
var folderPathReaders = _path["default"].join(channelPathBase, 'rdrs');
-
var folderPathMessages = _path["default"].join(channelPathBase, 'msgs');
-
var ret = {
channelBase: channelPathBase,
readers: folderPathReaders,
@@ -139,16 +106,12 @@ function getPaths(channelName) {
getPathsCache.set(channelName, ret);
return ret;
}
-
return getPathsCache.get(channelName);
}
-
var ENSURE_BASE_FOLDER_EXISTS_PROMISE = null;
-
function ensureBaseFolderExists() {
return _ensureBaseFolderExists.apply(this, arguments);
}
-
function _ensureBaseFolderExists() {
_ensureBaseFolderExists = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee3() {
return _regenerator["default"].wrap(function _callee3$(_context3) {
@@ -160,9 +123,7 @@ function _ensureBaseFolderExists() {
return null;
});
}
-
return _context3.abrupt("return", ENSURE_BASE_FOLDER_EXISTS_PROMISE);
-
case 2:
case "end":
return _context3.stop();
@@ -172,7 +133,6 @@ function _ensureBaseFolderExists() {
}));
return _ensureBaseFolderExists.apply(this, arguments);
}
-
function ensureFoldersExist(_x, _x2) {
return _ensureFoldersExist.apply(this, arguments);
}
@@ -180,8 +140,6 @@ function ensureFoldersExist(_x, _x2) {
* removes the tmp-folder
* @return {Promise}
*/
-
-
function _ensureFoldersExist() {
_ensureFoldersExist = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee4(channelName, paths) {
var chmodValue;
@@ -192,13 +150,11 @@ function _ensureFoldersExist() {
paths = paths || getPaths(channelName);
_context4.next = 3;
return ensureBaseFolderExists();
-
case 3:
_context4.next = 5;
return mkdir(paths.channelBase)["catch"](function () {
return null;
});
-
case 5:
_context4.next = 7;
return Promise.all([mkdir(paths.readers)["catch"](function () {
@@ -206,7 +162,6 @@ function _ensureFoldersExist() {
}), mkdir(paths.messages)["catch"](function () {
return null;
})]);
-
case 7:
// set permissions so other users can use the same channel
chmodValue = '777';
@@ -214,7 +169,6 @@ function _ensureFoldersExist() {
return Promise.all([chmod(paths.channelBase, chmodValue), chmod(paths.readers, chmodValue), chmod(paths.messages, chmodValue)])["catch"](function () {
return null;
});
-
case 10:
case "end":
return _context4.stop();
@@ -224,11 +178,9 @@ function _ensureFoldersExist() {
}));
return _ensureFoldersExist.apply(this, arguments);
}
-
function clearNodeFolder() {
return _clearNodeFolder.apply(this, arguments);
}
-
function _clearNodeFolder() {
_clearNodeFolder = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee5() {
return _regenerator["default"].wrap(function _callee5$(_context5) {
@@ -239,18 +191,14 @@ function _clearNodeFolder() {
_context5.next = 2;
break;
}
-
throw new Error('BroadcastChannel.clearNodeFolder(): path is wrong');
-
case 2:
ENSURE_BASE_FOLDER_EXISTS_PROMISE = null;
_context5.next = 5;
return removeDir(TMP_FOLDER_BASE);
-
case 5:
ENSURE_BASE_FOLDER_EXISTS_PROMISE = null;
return _context5.abrupt("return", true);
-
case 7:
case "end":
return _context5.stop();
@@ -260,29 +208,22 @@ function _clearNodeFolder() {
}));
return _clearNodeFolder.apply(this, arguments);
}
-
function socketPath(channelName, readerUuid, paths) {
paths = paths || getPaths(channelName);
-
var socketPath = _path["default"].join(paths.readers, readerUuid + '.s');
-
return cleanPipeName(socketPath);
}
-
function socketInfoPath(channelName, readerUuid, paths) {
paths = paths || getPaths(channelName);
-
var socketPath = _path["default"].join(paths.readers, readerUuid + '.json');
-
return socketPath;
}
+
/**
* Because it is not possible to get all socket-files in a folder,
* when used under fucking windows,
* we have to set a normal file so other readers know our socket exists
*/
-
-
function createSocketInfoFile(channelName, readerUuid, paths) {
var pathToFile = socketInfoPath(channelName, readerUuid, paths);
return writeFile(pathToFile, JSON.stringify({
@@ -291,16 +232,14 @@ function createSocketInfoFile(channelName, readerUuid, paths) {
return pathToFile;
});
}
+
/**
* returns the amount of channel-folders in the tmp-directory
* @return {Promise}
*/
-
-
function countChannelFolders() {
return _countChannelFolders.apply(this, arguments);
}
-
function _countChannelFolders() {
_countChannelFolders = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee6() {
var folders;
@@ -310,15 +249,12 @@ function _countChannelFolders() {
case 0:
_context6.next = 2;
return ensureBaseFolderExists();
-
case 2:
_context6.next = 4;
return readdir(TMP_FOLDER_BASE);
-
case 4:
folders = _context6.sent;
return _context6.abrupt("return", folders.length);
-
case 6:
case "end":
return _context6.stop();
@@ -328,7 +264,6 @@ function _countChannelFolders() {
}));
return _countChannelFolders.apply(this, arguments);
}
-
function connectionError(_x3) {
return _connectionError.apply(this, arguments);
}
@@ -336,8 +271,6 @@ function connectionError(_x3) {
* creates the socket-file and subscribes to it
* @return {{emitter: EventEmitter, server: any}}
*/
-
-
function _connectionError() {
_connectionError = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee7(originalError) {
var count, addObj, text, newError;
@@ -347,28 +280,23 @@ function _connectionError() {
case 0:
_context7.next = 2;
return countChannelFolders();
-
case 2:
count = _context7.sent;
-
if (!(count < 30)) {
_context7.next = 5;
break;
}
-
return _context7.abrupt("return", originalError);
-
case 5:
addObj = {};
Object.entries(originalError).forEach(function (_ref3) {
var k = _ref3[0],
- v = _ref3[1];
+ v = _ref3[1];
return addObj[k] = v;
});
text = 'BroadcastChannel.create(): error: ' + 'This might happen if you have created to many channels, ' + 'like when you use BroadcastChannel in unit-tests.' + 'Try using BroadcastChannel.clearNodeFolder() to clear the tmp-folder before each test.' + 'See https://github.com/pubkey/broadcast-channel#clear-tmp-folder';
newError = new Error(text + ': ' + JSON.stringify(addObj, null, 2));
return _context7.abrupt("return", newError);
-
case 10:
case "end":
return _context7.stop();
@@ -378,11 +306,9 @@ function _connectionError() {
}));
return _connectionError.apply(this, arguments);
}
-
function createSocketEventEmitter(_x4, _x5, _x6) {
return _createSocketEventEmitter.apply(this, arguments);
}
-
function _createSocketEventEmitter() {
_createSocketEventEmitter = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee10(channelName, readerUuid, paths) {
var pathToSocket, emitter, server;
@@ -409,11 +335,9 @@ function _createSocketEventEmitter() {
case 0:
_context8.next = 2;
return connectionError(err);
-
case 2:
useErr = _context8.sent;
reject(useErr);
-
case 4:
case "end":
return _context8.stop();
@@ -421,7 +345,6 @@ function _createSocketEventEmitter() {
}
}, _callee8);
}));
-
return function (_x26) {
return _ref4.apply(this, arguments);
};
@@ -437,19 +360,15 @@ function _createSocketEventEmitter() {
_context9.next = 7;
break;
}
-
_context9.next = 3;
return connectionError(err);
-
case 3:
useErr = _context9.sent;
reject(useErr);
_context9.next = 8;
break;
-
case 7:
resolve(res);
-
case 8:
case "end":
return _context9.stop();
@@ -457,20 +376,17 @@ function _createSocketEventEmitter() {
}
}, _callee9);
}));
-
return function (_x27, _x28) {
return _ref5.apply(this, arguments);
};
}());
});
-
case 5:
return _context10.abrupt("return", {
path: pathToSocket,
emitter: emitter,
server: server
});
-
case 6:
case "end":
return _context10.stop();
@@ -480,7 +396,6 @@ function _createSocketEventEmitter() {
}));
return _createSocketEventEmitter.apply(this, arguments);
}
-
function openClientConnection(_x7, _x8) {
return _openClientConnection.apply(this, arguments);
}
@@ -489,8 +404,6 @@ function openClientConnection(_x7, _x8) {
* so other readers can find it
* @return {Promise}
*/
-
-
function _openClientConnection() {
_openClientConnection = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee11(channelName, readerUuid) {
var pathToSocket, client;
@@ -508,7 +421,6 @@ function _openClientConnection() {
return rej(err);
});
}));
-
case 3:
case "end":
return _context11.stop();
@@ -518,7 +430,6 @@ function _openClientConnection() {
}));
return _openClientConnection.apply(this, arguments);
}
-
function writeMessage(channelName, readerUuid, messageJson, paths) {
paths = paths || getPaths(channelName);
var time = microSeconds();
@@ -529,9 +440,7 @@ function writeMessage(channelName, readerUuid, messageJson, paths) {
};
var token = (0, _util2.randomToken)();
var fileName = time + '_' + readerUuid + '_' + token + '.json';
-
var msgPath = _path["default"].join(paths.messages, fileName);
-
return writeFile(msgPath, JSON.stringify(writeObject)).then(function () {
return {
time: time,
@@ -541,16 +450,14 @@ function writeMessage(channelName, readerUuid, messageJson, paths) {
};
});
}
+
/**
* returns the uuids of all readers
* @return {string[]}
*/
-
-
function getReadersUuids(_x9, _x10) {
return _getReadersUuids.apply(this, arguments);
}
-
function _getReadersUuids() {
_getReadersUuids = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee12(channelName, paths) {
var readersPath, files;
@@ -562,7 +469,6 @@ function _getReadersUuids() {
readersPath = paths.readers;
_context12.next = 4;
return readdir(readersPath);
-
case 4:
files = _context12.sent;
return _context12.abrupt("return", files.map(function (file) {
@@ -573,7 +479,6 @@ function _getReadersUuids() {
.map(function (split) {
return split[0];
}));
-
case 6:
case "end":
return _context12.stop();
@@ -583,11 +488,9 @@ function _getReadersUuids() {
}));
return _getReadersUuids.apply(this, arguments);
}
-
function messagePath(_x11, _x12, _x13, _x14) {
return _messagePath.apply(this, arguments);
}
-
function _messagePath() {
_messagePath = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee13(channelName, time, token, writerUuid) {
var fileName, msgPath;
@@ -598,7 +501,6 @@ function _messagePath() {
fileName = time + '_' + writerUuid + '_' + token + '.json';
msgPath = _path["default"].join(getPaths(channelName).messages, fileName);
return _context13.abrupt("return", msgPath);
-
case 3:
case "end":
return _context13.stop();
@@ -608,11 +510,9 @@ function _messagePath() {
}));
return _messagePath.apply(this, arguments);
}
-
function getAllMessages(_x15, _x16) {
return _getAllMessages.apply(this, arguments);
}
-
function _getAllMessages() {
_getAllMessages = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee14(channelName, paths) {
var messagesPath, files;
@@ -624,7 +524,6 @@ function _getAllMessages() {
messagesPath = paths.messages;
_context14.next = 4;
return readdir(messagesPath);
-
case 4:
files = _context14.sent;
return _context14.abrupt("return", files.map(function (file) {
@@ -637,7 +536,6 @@ function _getAllMessages() {
token: split[2]
};
}));
-
case 6:
case "end":
return _context14.stop();
@@ -647,7 +545,6 @@ function _getAllMessages() {
}));
return _getAllMessages.apply(this, arguments);
}
-
function getSingleMessage(channelName, msgObj, paths) {
paths = paths || getPaths(channelName);
return {
@@ -657,17 +554,14 @@ function getSingleMessage(channelName, msgObj, paths) {
token: msgObj.to
};
}
-
function readMessage(messageObj) {
return readFile(messageObj.path, 'utf8').then(function (content) {
return JSON.parse(content);
});
}
-
function cleanOldMessages(_x17, _x18) {
return _cleanOldMessages.apply(this, arguments);
}
-
function _cleanOldMessages() {
_cleanOldMessages = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee15(messageObjects, ttl) {
var olderThen;
@@ -676,7 +570,6 @@ function _cleanOldMessages() {
switch (_context15.prev = _context15.next) {
case 0:
olderThen = microSeconds() - ttl * 1000; // convert ttl to microseconds
-
_context15.next = 3;
return Promise.all(messageObjects.filter(function (obj) {
return obj.time < olderThen;
@@ -685,7 +578,6 @@ function _cleanOldMessages() {
return null;
});
}));
-
case 3:
case "end":
return _context15.stop();
@@ -695,32 +587,28 @@ function _cleanOldMessages() {
}));
return _cleanOldMessages.apply(this, arguments);
}
-
var type = 'node';
+
/**
* creates a new channelState
* @return {Promise}
*/
-
exports.type = type;
-
function create(_x19) {
return _create.apply(this, arguments);
}
-
function _create() {
_create = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee16(channelName) {
var options,
- time,
- paths,
- ensureFolderExistsPromise,
- uuid,
- state,
- _yield$Promise$all,
- socketEE,
- infoFilePath,
- _args16 = arguments;
-
+ time,
+ paths,
+ ensureFolderExistsPromise,
+ uuid,
+ state,
+ _yield$Promise$all,
+ socketEE,
+ infoFilePath,
+ _args16 = arguments;
return _regenerator["default"].wrap(function _callee16$(_context16) {
while (1) {
switch (_context16.prev = _context16.next) {
@@ -739,7 +627,6 @@ function _create() {
paths: paths,
// contains all messages that have been emitted before
emittedMessagesIds: new _obliviousSet.ObliviousSet(options.node.ttl * 2),
-
/**
* Used to ensure we do not write too many files at once
* which could throw an error.
@@ -763,18 +650,17 @@ function _create() {
OTHER_INSTANCES[channelName].push(state);
_context16.next = 11;
return ensureFolderExistsPromise;
-
case 11:
_context16.next = 13;
return Promise.all([createSocketEventEmitter(channelName, uuid, paths), createSocketInfoFile(channelName, uuid, paths), refreshReaderClients(state)]);
-
case 13:
_yield$Promise$all = _context16.sent;
socketEE = _yield$Promise$all[0];
infoFilePath = _yield$Promise$all[1];
state.socketEE = socketEE;
- state.infoFilePath = infoFilePath; // when new message comes in, we read it and emit it
+ state.infoFilePath = infoFilePath;
+ // when new message comes in, we read it and emit it
socketEE.emitter.on('data', function (data) {
// if the socket is used fast, it may appear that multiple messages are flushed at once
// so we have to split them before
@@ -791,7 +677,6 @@ function _create() {
});
});
return _context16.abrupt("return", state);
-
case 20:
case "end":
return _context16.stop();
@@ -801,27 +686,21 @@ function _create() {
}));
return _create.apply(this, arguments);
}
-
function _filterMessage(msgObj, state) {
if (msgObj.senderUuid === state.uuid) return false; // not send by own
-
if (state.emittedMessagesIds.has(msgObj.token)) return false; // not already emitted
-
if (!state.messagesCallback) return false; // no listener
-
if (msgObj.time < state.messagesCallbackTime) return false; // not older then onMessageCallback
-
if (msgObj.time < state.time) return false; // msgObj is older then channel
state.emittedMessagesIds.add(msgObj.token);
return true;
}
+
/**
* when the socket pings, so that we now new messages came,
* run this
*/
-
-
function handleMessagePing(_x20, _x21) {
return _handleMessagePing.apply(this, arguments);
}
@@ -829,8 +708,6 @@ function handleMessagePing(_x20, _x21) {
* ensures that the channelState is connected with all other readers
* @return {Promise}
*/
-
-
function _handleMessagePing() {
_handleMessagePing = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee17(state, msgObj) {
var messages, useMessages;
@@ -842,27 +719,21 @@ function _handleMessagePing() {
_context17.next = 2;
break;
}
-
return _context17.abrupt("return");
-
case 2:
if (msgObj) {
_context17.next = 8;
break;
}
-
_context17.next = 5;
return getAllMessages(state.channelName, state.paths);
-
case 5:
messages = _context17.sent;
_context17.next = 9;
break;
-
case 8:
// get single message
messages = [getSingleMessage(state.channelName, msgObj, state.paths)];
-
case 9:
useMessages = messages.filter(function (msgObj) {
return _filterMessage(msgObj, state);
@@ -870,14 +741,11 @@ function _handleMessagePing() {
return msgObjA.time - msgObjB.time;
}); // sort by time
// if no listener or message, so not do anything
-
if (!(!useMessages.length || !state.messagesCallback)) {
_context17.next = 12;
break;
}
-
return _context17.abrupt("return");
-
case 12:
_context17.next = 14;
return Promise.all(useMessages.map(function (msgObj) {
@@ -885,17 +753,14 @@ function _handleMessagePing() {
return msgObj.content = content;
});
}));
-
case 14:
useMessages.forEach(function (msgObj) {
state.emittedMessagesIds.add(msgObj.token);
-
if (state.messagesCallback) {
// emit to subscribers
state.messagesCallback(msgObj.content.data);
}
});
-
case 15:
case "end":
return _context17.stop();
@@ -905,7 +770,6 @@ function _handleMessagePing() {
}));
return _handleMessagePing.apply(this, arguments);
}
-
function refreshReaderClients(channelState) {
return getReadersUuids(channelState.channelName, channelState.paths).then(function (otherReaders) {
// remove subscriptions to closed readers
@@ -920,18 +784,14 @@ function refreshReaderClients(channelState) {
_context.prev = 0;
_context.next = 3;
return channelState.otherReaderClients[readerUuid].destroy();
-
case 3:
_context.next = 7;
break;
-
case 5:
_context.prev = 5;
_context.t0 = _context["catch"](0);
-
case 7:
delete channelState.otherReaderClients[readerUuid];
-
case 8:
case "end":
return _context.stop();
@@ -939,12 +799,12 @@ function refreshReaderClients(channelState) {
}
}, _callee, null, [[0, 5]]);
}));
-
return function (_x22) {
return _ref.apply(this, arguments);
};
- }()); // add new readers
+ }());
+ // add new readers
return Promise.all(otherReaders.filter(function (readerUuid) {
return readerUuid !== channelState.uuid;
}) // not own
@@ -959,37 +819,29 @@ function refreshReaderClients(channelState) {
switch (_context2.prev = _context2.next) {
case 0:
_context2.prev = 0;
-
if (!channelState.closed) {
_context2.next = 3;
break;
}
-
return _context2.abrupt("return");
-
case 3:
_context2.prev = 3;
_context2.next = 6;
return openClientConnection(channelState.channelName, readerUuid);
-
case 6:
client = _context2.sent;
channelState.otherReaderClients[readerUuid] = client;
_context2.next = 12;
break;
-
case 10:
_context2.prev = 10;
_context2.t0 = _context2["catch"](3);
-
case 12:
_context2.next = 16;
break;
-
case 14:
_context2.prev = 14;
_context2.t1 = _context2["catch"](0);
-
case 16:
case "end":
return _context2.stop();
@@ -997,19 +849,17 @@ function refreshReaderClients(channelState) {
}
}, _callee2, null, [[0, 14], [3, 10]]);
}));
-
return function (_x23) {
return _ref2.apply(this, arguments);
};
}()));
});
}
+
/**
* post a message to the other readers
* @return {Promise}
*/
-
-
function postMessage(_x24, _x25) {
return _postMessage.apply(this, arguments);
}
@@ -1019,8 +869,6 @@ function postMessage(_x24, _x25) {
* This might not happen often in production
* but will speed up things when this module is used in unit-tests.
*/
-
-
function _postMessage() {
_postMessage = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee19(channelState, messageJson) {
var writePromise;
@@ -1033,7 +881,6 @@ function _postMessage() {
});
channelState.writeBlockPromise = channelState.writeBlockPromise.then( /*#__PURE__*/(0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee18() {
var _yield$Promise$all2, msgObj, pingStr, writeToReadersPromise;
-
return _regenerator["default"].wrap(function _callee18$(_context18) {
while (1) {
switch (_context18.prev = _context18.next) {
@@ -1042,11 +889,9 @@ function _postMessage() {
return new Promise(function (res) {
return setTimeout(res, 0);
});
-
case 2:
_context18.next = 4;
return Promise.all([writePromise, refreshReaderClients(channelState)]);
-
case 4:
_yield$Promise$all2 = _context18.sent;
msgObj = _yield$Promise$all2[0];
@@ -1065,16 +910,13 @@ function _postMessage() {
* to not waste resources on cleaning up,
* only if random-int matches, we clean up old messages
*/
-
if ((0, _util2.randomInt)(0, 20) === 0) {
/* await */
getAllMessages(channelState.channelName, channelState.paths).then(function (allMessages) {
return cleanOldMessages(allMessages, channelState.options.node.ttl);
});
}
-
return _context18.abrupt("return", writeToReadersPromise);
-
case 11:
case "end":
return _context18.stop();
@@ -1083,7 +925,6 @@ function _postMessage() {
}, _callee18);
})));
return _context19.abrupt("return", channelState.writeBlockPromise);
-
case 3:
case "end":
return _context19.stop();
@@ -1093,13 +934,11 @@ function _postMessage() {
}));
return _postMessage.apply(this, arguments);
}
-
function emitOverFastPath(state, msgObj, messageJson) {
if (!state.options.node.useFastPath) {
// disabled
return;
}
-
var others = OTHER_INSTANCES[state.channelName].filter(function (s) {
return s !== state;
});
@@ -1114,19 +953,17 @@ function emitOverFastPath(state, msgObj, messageJson) {
otherState.messagesCallback(messageJson);
});
}
-
function onMessage(channelState, fn) {
var time = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : microSeconds();
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
handleMessagePing(channelState);
}
+
/**
* closes the channel
* @return {Promise}
*/
-
-
function close(channelState) {
if (channelState.closed) return;
channelState.closed = true;
@@ -1134,35 +971,30 @@ function close(channelState) {
OTHER_INSTANCES[channelState.channelName] = OTHER_INSTANCES[channelState.channelName].filter(function (o) {
return o !== channelState;
});
-
if (channelState.removeUnload) {
channelState.removeUnload.remove();
}
-
return new Promise(function (res) {
if (channelState.socketEE) channelState.socketEE.emitter.removeAllListeners();
Object.values(channelState.otherReaderClients).forEach(function (client) {
return client.destroy();
});
-
if (channelState.infoFilePath) {
try {
_fs["default"].unlinkSync(channelState.infoFilePath);
} catch (err) {}
}
+
/**
* the server get closed lazy because others might still write on it
* and have not found out that the infoFile was deleted
*/
-
-
setTimeout(function () {
channelState.socketEE.server.close();
res();
}, 200);
});
}
-
function canBeUsed() {
if (typeof _fs["default"].mkdir === 'function') {
return true;
@@ -1170,23 +1002,20 @@ function canBeUsed() {
return false;
}
}
+
/**
* on node we use a relatively height averageResponseTime,
* because the file-io might be in use.
* Also it is more important that the leader-election is reliable,
* then to have a fast election.
*/
-
-
function averageResponseTime() {
return 200;
}
-
function microSeconds() {
// convert nano to micro seconds
return parseInt(now() / 1000);
}
-
function now() {
return Number(process.hrtime.bigint()); // returns nanoseconds
}
\ No newline at end of file
diff --git a/dist/es5node/methods/simulate.js b/dist/es5node/methods/simulate.js
index f0ce13c5..46d5cfde 100644
--- a/dist/es5node/methods/simulate.js
+++ b/dist/es5node/methods/simulate.js
@@ -11,15 +11,12 @@ exports.microSeconds = exports["default"] = void 0;
exports.onMessage = onMessage;
exports.postMessage = postMessage;
exports.type = void 0;
-
var _util = require("../util.js");
-
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var type = 'simulate';
exports.type = type;
var SIMULATE_CHANNELS = new Set();
-
function create(channelName) {
var state = {
name: channelName,
@@ -28,11 +25,9 @@ function create(channelName) {
SIMULATE_CHANNELS.add(state);
return state;
}
-
function close(channelState) {
SIMULATE_CHANNELS["delete"](channelState);
}
-
function postMessage(channelState, messageJson) {
return new Promise(function (res) {
return setTimeout(function () {
@@ -50,19 +45,15 @@ function postMessage(channelState, messageJson) {
}, 5);
});
}
-
function onMessage(channelState, fn) {
channelState.messagesCallback = fn;
}
-
function canBeUsed() {
return true;
}
-
function averageResponseTime() {
return 5;
}
-
var _default = {
create: create,
close: close,
diff --git a/dist/es5node/options.js b/dist/es5node/options.js
index c8435340..36c0e4e8 100644
--- a/dist/es5node/options.js
+++ b/dist/es5node/options.js
@@ -4,33 +4,35 @@ Object.defineProperty(exports, "__esModule", {
value: true
});
exports.fillOptionsWithDefaults = fillOptionsWithDefaults;
-
function fillOptionsWithDefaults() {
var originalOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- var options = JSON.parse(JSON.stringify(originalOptions)); // main
-
- if (typeof options.webWorkerSupport === 'undefined') options.webWorkerSupport = true; // indexed-db
+ var options = JSON.parse(JSON.stringify(originalOptions));
- if (!options.idb) options.idb = {}; // after this time the messages get deleted
+ // main
+ if (typeof options.webWorkerSupport === 'undefined') options.webWorkerSupport = true;
+ // indexed-db
+ if (!options.idb) options.idb = {};
+ // after this time the messages get deleted
if (!options.idb.ttl) options.idb.ttl = 1000 * 45;
- if (!options.idb.fallbackInterval) options.idb.fallbackInterval = 150; // handles abrupt db onclose events.
-
- if (originalOptions.idb && typeof originalOptions.idb.onclose === 'function') options.idb.onclose = originalOptions.idb.onclose; // localstorage
+ if (!options.idb.fallbackInterval) options.idb.fallbackInterval = 150;
+ // handles abrupt db onclose events.
+ if (originalOptions.idb && typeof originalOptions.idb.onclose === 'function') options.idb.onclose = originalOptions.idb.onclose;
+ // localstorage
if (!options.localstorage) options.localstorage = {};
- if (!options.localstorage.removeTimeout) options.localstorage.removeTimeout = 1000 * 60; // custom methods
+ if (!options.localstorage.removeTimeout) options.localstorage.removeTimeout = 1000 * 60;
- if (originalOptions.methods) options.methods = originalOptions.methods; // node
+ // custom methods
+ if (originalOptions.methods) options.methods = originalOptions.methods;
+ // node
if (!options.node) options.node = {};
if (!options.node.ttl) options.node.ttl = 1000 * 60 * 2; // 2 minutes;
-
/**
* On linux use 'ulimit -Hn' to get the limit of open files.
* On ubuntu this was 4096 for me, so we use half of that as maxParallelWrites default.
*/
-
if (!options.node.maxParallelWrites) options.node.maxParallelWrites = 2048;
if (typeof options.node.useFastPath === 'undefined') options.node.useFastPath = true;
return options;
diff --git a/dist/es5node/util.js b/dist/es5node/util.js
index bf51ea5e..c63716c9 100644
--- a/dist/es5node/util.js
+++ b/dist/es5node/util.js
@@ -9,7 +9,6 @@ exports.microSeconds = microSeconds;
exports.randomInt = randomInt;
exports.randomToken = randomToken;
exports.sleep = sleep;
-
/**
* returns true if the given object is a promise
*/
@@ -20,14 +19,12 @@ function isPromise(obj) {
return false;
}
}
-
var PROMISE_RESOLVED_FALSE = Promise.resolve(false);
exports.PROMISE_RESOLVED_FALSE = PROMISE_RESOLVED_FALSE;
var PROMISE_RESOLVED_TRUE = Promise.resolve(true);
exports.PROMISE_RESOLVED_TRUE = PROMISE_RESOLVED_TRUE;
var PROMISE_RESOLVED_VOID = Promise.resolve();
exports.PROMISE_RESOLVED_VOID = PROMISE_RESOLVED_VOID;
-
function sleep(time, resolveWith) {
if (!time) time = 0;
return new Promise(function (res) {
@@ -36,21 +33,19 @@ function sleep(time, resolveWith) {
}, time);
});
}
-
function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
+
/**
* https://stackoverflow.com/a/8084248
*/
-
-
function randomToken() {
return Math.random().toString(36).substring(2);
}
-
var lastMs = 0;
var additional = 0;
+
/**
* returns the current time in micro-seconds,
* WARNING: This is a pseudo-function
@@ -58,10 +53,8 @@ var additional = 0;
* This is enough in browsers, and this function will not be used in nodejs.
* The main reason for this hack is to ensure that BroadcastChannel behaves equal to production when it is used in fast-running unit tests.
*/
-
function microSeconds() {
var ms = new Date().getTime();
-
if (ms === lastMs) {
additional++;
return ms * 1000 + additional;
diff --git a/dist/esbrowser/broadcast-channel.js b/dist/esbrowser/broadcast-channel.js
index 09502c09..d62e7a95 100644
--- a/dist/esbrowser/broadcast-channel.js
+++ b/dist/esbrowser/broadcast-channel.js
@@ -1,11 +1,11 @@
import { isPromise, PROMISE_RESOLVED_FALSE, PROMISE_RESOLVED_VOID } from './util.js';
import { chooseMethod } from './method-chooser.js';
import { fillOptionsWithDefaults } from './options.js';
+
/**
* Contains all open channels,
* used in tests to ensure everything is closed.
*/
-
export var OPEN_BROADCAST_CHANNELS = new Set();
var lastId = 0;
export var BroadcastChannel = function BroadcastChannel(name, options) {
@@ -13,69 +13,67 @@ export var BroadcastChannel = function BroadcastChannel(name, options) {
this.id = lastId++;
OPEN_BROADCAST_CHANNELS.add(this);
this.name = name;
-
if (ENFORCED_OPTIONS) {
options = ENFORCED_OPTIONS;
}
-
this.options = fillOptionsWithDefaults(options);
- this.method = chooseMethod(this.options); // isListening
+ this.method = chooseMethod(this.options);
+ // isListening
this._iL = false;
+
/**
* _onMessageListener
* setting onmessage twice,
* will overwrite the first listener
*/
-
this._onML = null;
+
/**
* _addEventListeners
*/
-
this._addEL = {
message: [],
internal: []
};
+
/**
* Unsend message promises
* where the sending is still in progress
* @type {Set}
*/
-
this._uMP = new Set();
+
/**
* _beforeClose
* array of promises that will be awaited
* before the channel is closed
*/
-
this._befC = [];
+
/**
* _preparePromise
*/
-
this._prepP = null;
-
_prepareChannel(this);
-}; // STATICS
+};
+
+// STATICS
/**
* used to identify if someone overwrites
* window.BroadcastChannel with this
* See methods/native.js
*/
-
BroadcastChannel._pubkey = true;
+
/**
* clears the tmp-folder if is node
* @return {Promise} true if has run, false if not node
*/
-
export function clearNodeFolder(options) {
options = fillOptionsWithDefaults(options);
var method = chooseMethod(options);
-
if (method.type === 'node') {
return method.clearNodeFolder().then(function () {
return true;
@@ -84,16 +82,17 @@ export function clearNodeFolder(options) {
return PROMISE_RESOLVED_FALSE;
}
}
+
/**
* if set, this method is enforced,
* no mather what the options are
*/
-
var ENFORCED_OPTIONS;
export function enforceOptions(options) {
ENFORCED_OPTIONS = options;
-} // PROTOTYPE
+}
+// PROTOTYPE
BroadcastChannel.prototype = {
postMessage: function postMessage(msg) {
if (this.closed) {
@@ -105,87 +104,77 @@ BroadcastChannel.prototype = {
*/
JSON.stringify(msg));
}
-
return _post(this, 'message', msg);
},
postInternal: function postInternal(msg) {
return _post(this, 'internal', msg);
},
-
set onmessage(fn) {
var time = this.method.microSeconds();
var listenObj = {
time: time,
fn: fn
};
-
_removeListenerObject(this, 'message', this._onML);
-
if (fn && typeof fn === 'function') {
this._onML = listenObj;
-
_addListenerObject(this, 'message', listenObj);
} else {
this._onML = null;
}
},
-
addEventListener: function addEventListener(type, fn) {
var time = this.method.microSeconds();
var listenObj = {
time: time,
fn: fn
};
-
_addListenerObject(this, type, listenObj);
},
removeEventListener: function removeEventListener(type, fn) {
var obj = this._addEL[type].find(function (obj) {
return obj.fn === fn;
});
-
_removeListenerObject(this, type, obj);
},
close: function close() {
var _this = this;
-
if (this.closed) {
return;
}
-
OPEN_BROADCAST_CHANNELS["delete"](this);
this.closed = true;
var awaitPrepare = this._prepP ? this._prepP : PROMISE_RESOLVED_VOID;
this._onML = null;
this._addEL.message = [];
- return awaitPrepare // wait until all current sending are processed
+ return awaitPrepare
+ // wait until all current sending are processed
.then(function () {
return Promise.all(Array.from(_this._uMP));
- }) // run before-close hooks
+ })
+ // run before-close hooks
.then(function () {
return Promise.all(_this._befC.map(function (fn) {
return fn();
}));
- }) // close the channel
+ })
+ // close the channel
.then(function () {
return _this.method.close(_this._state);
});
},
-
get type() {
return this.method.type;
},
-
get isClosed() {
return this.closed;
}
-
};
+
/**
* Post a message over the channel
* @returns {Promise} that resolved when the message sending is done
*/
-
function _post(broadcastChannel, type, msg) {
var time = broadcastChannel.method.microSeconds();
var msgObj = {
@@ -195,25 +184,22 @@ function _post(broadcastChannel, type, msg) {
};
var awaitPrepare = broadcastChannel._prepP ? broadcastChannel._prepP : PROMISE_RESOLVED_VOID;
return awaitPrepare.then(function () {
- var sendPromise = broadcastChannel.method.postMessage(broadcastChannel._state, msgObj); // add/remove to unsend messages list
+ var sendPromise = broadcastChannel.method.postMessage(broadcastChannel._state, msgObj);
+ // add/remove to unsend messages list
broadcastChannel._uMP.add(sendPromise);
-
sendPromise["catch"]().then(function () {
return broadcastChannel._uMP["delete"](sendPromise);
});
return sendPromise;
});
}
-
function _prepareChannel(channel) {
var maybePromise = channel.method.create(channel.name, channel.options);
-
if (isPromise(maybePromise)) {
channel._prepP = maybePromise;
maybePromise.then(function (s) {
// used in tests to simulate slow runtime
-
/*if (channel.options.prepareDelay) {
await new Promise(res => setTimeout(res, this.options.prepareDelay));
}*/
@@ -223,30 +209,25 @@ function _prepareChannel(channel) {
channel._state = maybePromise;
}
}
-
function _hasMessageListeners(channel) {
if (channel._addEL.message.length > 0) return true;
if (channel._addEL.internal.length > 0) return true;
return false;
}
-
function _addListenerObject(channel, type, obj) {
channel._addEL[type].push(obj);
-
_startListening(channel);
}
-
function _removeListenerObject(channel, type, obj) {
channel._addEL[type] = channel._addEL[type].filter(function (o) {
return o !== obj;
});
-
_stopListening(channel);
}
-
function _startListening(channel) {
if (!channel._iL && _hasMessageListeners(channel)) {
// someone is listening, start subscribing
+
var listenerFn = function listenerFn(msgObj) {
channel._addEL[msgObj.type].forEach(function (listenerObject) {
/**
@@ -260,15 +241,12 @@ function _startListening(channel) {
*/
var hundredMsInMicro = 100 * 1000;
var minMessageTime = listenerObject.time - hundredMsInMicro;
-
if (msgObj.time >= minMessageTime) {
listenerObject.fn(msgObj.data);
}
});
};
-
var time = channel.method.microSeconds();
-
if (channel._prepP) {
channel._prepP.then(function () {
channel._iL = true;
@@ -280,7 +258,6 @@ function _startListening(channel) {
}
}
}
-
function _stopListening(channel) {
if (channel._iL && !_hasMessageListeners(channel)) {
// noone is listening, stop subscribing
diff --git a/dist/esbrowser/browserify.index.js b/dist/esbrowser/browserify.index.js
index e500d3df..bd935158 100644
--- a/dist/esbrowser/browserify.index.js
+++ b/dist/esbrowser/browserify.index.js
@@ -1,5 +1,4 @@
var module = require('./index.es5.js');
-
var BroadcastChannel = module.BroadcastChannel;
var createLeaderElection = module.createLeaderElection;
window['BroadcastChannel2'] = BroadcastChannel;
diff --git a/dist/esbrowser/index.es5.js b/dist/esbrowser/index.es5.js
index 4d6b827b..60f0b76e 100644
--- a/dist/esbrowser/index.es5.js
+++ b/dist/esbrowser/index.es5.js
@@ -6,6 +6,7 @@
* but
* var BroadcastChannel = require('broadcast-channel');
*/
+
import { BroadcastChannel, createLeaderElection, clearNodeFolder, enforceOptions, beLeader } from './index.js';
module.exports = {
BroadcastChannel: BroadcastChannel,
diff --git a/dist/esbrowser/leader-election.js b/dist/esbrowser/leader-election.js
index c8c9cbb4..3b2c615c 100644
--- a/dist/esbrowser/leader-election.js
+++ b/dist/esbrowser/leader-election.js
@@ -1,32 +1,27 @@
import { sleep, randomToken, PROMISE_RESOLVED_VOID, PROMISE_RESOLVED_TRUE } from './util.js';
import { add as unloadAdd } from 'unload';
-
var LeaderElection = function LeaderElection(broadcastChannel, options) {
var _this = this;
-
this.broadcastChannel = broadcastChannel;
this._options = options;
this.isLeader = false;
this.hasLeader = false;
this.isDead = false;
this.token = randomToken();
+
/**
* Apply Queue,
* used to ensure we do not run applyOnce()
* in parallel.
*/
+ this._aplQ = PROMISE_RESOLVED_VOID;
+ // amount of unfinished applyOnce() calls
+ this._aplQC = 0;
- this._aplQ = PROMISE_RESOLVED_VOID; // amount of unfinished applyOnce() calls
-
- this._aplQC = 0; // things to clean up
-
+ // things to clean up
this._unl = []; // _unloads
-
this._lstns = []; // _listeners
-
this._dpL = function () {}; // onduplicate listener
-
-
this._dpLC = false; // true when onduplicate called
/**
@@ -34,55 +29,47 @@ var LeaderElection = function LeaderElection(broadcastChannel, options) {
* we still listen to messages to ensure the hasLeader flag
* is set correctly.
*/
-
var hasLeaderListener = function hasLeaderListener(msg) {
if (msg.context === 'leader') {
if (msg.action === 'death') {
_this.hasLeader = false;
}
-
if (msg.action === 'tell') {
_this.hasLeader = true;
}
}
};
-
this.broadcastChannel.addEventListener('internal', hasLeaderListener);
-
this._lstns.push(hasLeaderListener);
};
-
LeaderElection.prototype = {
/**
* Returns true if the instance is leader,
* false if not.
* @async
*/
- applyOnce: function applyOnce( // true if the applyOnce() call came from the fallbackInterval cycle
+ applyOnce: function applyOnce(
+ // true if the applyOnce() call came from the fallbackInterval cycle
isFromFallbackInterval) {
var _this2 = this;
-
if (this.isLeader) {
return sleep(0, true);
}
-
if (this.isDead) {
return sleep(0, false);
}
+
/**
* Already applying more then once,
* -> wait for the apply queue to be finished.
*/
-
-
if (this._aplQC > 1) {
return this._aplQ;
}
+
/**
* Add a new apply-run
*/
-
-
var applyRun = function applyRun() {
/**
* Optimization shortcuts.
@@ -92,7 +79,6 @@ LeaderElection.prototype = {
if (_this2.isLeader) {
return PROMISE_RESOLVED_TRUE;
}
-
var stopCriteria = false;
var stopCriteriaPromiseResolve;
/**
@@ -101,7 +87,6 @@ LeaderElection.prototype = {
* have to await the responseTime when it is already clear
* that the election failed.
*/
-
var stopCriteriaPromise = new Promise(function (res) {
stopCriteriaPromiseResolve = function stopCriteriaPromiseResolve() {
stopCriteria = true;
@@ -109,11 +94,9 @@ LeaderElection.prototype = {
};
});
var recieved = [];
-
var handleMessage = function handleMessage(msg) {
if (msg.context === 'leader' && msg.token != _this2.token) {
recieved.push(msg);
-
if (msg.action === 'apply') {
// other is applying
if (msg.token > _this2.token) {
@@ -124,7 +107,6 @@ LeaderElection.prototype = {
stopCriteriaPromiseResolve();
}
}
-
if (msg.action === 'tell') {
// other is already leader
stopCriteriaPromiseResolve();
@@ -132,8 +114,8 @@ LeaderElection.prototype = {
}
}
};
-
_this2.broadcastChannel.addEventListener('internal', handleMessage);
+
/**
* If the applyOnce() call came from the fallbackInterval,
* we can assume that the election runs in the background and
@@ -144,26 +126,24 @@ LeaderElection.prototype = {
* But also it takes longer which is not a problem because we anyway
* run in the background.
*/
-
-
var waitForAnswerTime = isFromFallbackInterval ? _this2._options.responseTime * 4 : _this2._options.responseTime;
-
var applyPromise = _sendMessage(_this2, 'apply') // send out that this one is applying
.then(function () {
return Promise.race([sleep(waitForAnswerTime), stopCriteriaPromise.then(function () {
return Promise.reject(new Error());
})]);
- }) // send again in case another instance was just created
+ })
+ // send again in case another instance was just created
.then(function () {
return _sendMessage(_this2, 'apply');
- }) // let others time to respond
+ })
+ // let others time to respond
.then(function () {
return Promise.race([sleep(waitForAnswerTime), stopCriteriaPromise.then(function () {
return Promise.reject(new Error());
})]);
})["catch"](function () {}).then(function () {
_this2.broadcastChannel.removeEventListener('internal', handleMessage);
-
if (!stopCriteria) {
// no stop criteria -> own is leader
return beLeader(_this2).then(function () {
@@ -174,10 +154,8 @@ LeaderElection.prototype = {
return false;
}
});
-
return applyPromise;
};
-
this._aplQC = this._aplQC + 1;
this._aplQ = this._aplQ.then(function () {
return applyRun();
@@ -189,82 +167,68 @@ LeaderElection.prototype = {
});
},
awaitLeadership: function awaitLeadership() {
- if (
- /* _awaitLeadershipPromise */
+ if ( /* _awaitLeadershipPromise */
!this._aLP) {
this._aLP = _awaitLeadershipOnce(this);
}
-
return this._aLP;
},
-
set onduplicate(fn) {
this._dpL = fn;
},
-
die: function die() {
var _this3 = this;
-
this._lstns.forEach(function (listener) {
return _this3.broadcastChannel.removeEventListener('internal', listener);
});
-
this._lstns = [];
-
this._unl.forEach(function (uFn) {
return uFn.remove();
});
-
this._unl = [];
-
if (this.isLeader) {
this.hasLeader = false;
this.isLeader = false;
}
-
this.isDead = true;
return _sendMessage(this, 'death');
}
};
+
/**
* @param leaderElector {LeaderElector}
*/
-
function _awaitLeadershipOnce(leaderElector) {
if (leaderElector.isLeader) {
return PROMISE_RESOLVED_VOID;
}
-
return new Promise(function (res) {
var resolved = false;
-
function finish() {
if (resolved) {
return;
}
-
resolved = true;
leaderElector.broadcastChannel.removeEventListener('internal', whenDeathListener);
res(true);
- } // try once now
-
+ }
+ // try once now
leaderElector.applyOnce().then(function () {
if (leaderElector.isLeader) {
finish();
}
});
+
/**
* Try on fallbackInterval
* @recursive
*/
-
var tryOnFallBack = function tryOnFallBack() {
return sleep(leaderElector._options.fallbackInterval).then(function () {
if (leaderElector.isDead || resolved) {
return;
}
-
if (leaderElector.isLeader) {
finish();
} else {
@@ -278,9 +242,9 @@ function _awaitLeadershipOnce(leaderElector) {
}
});
};
+ tryOnFallBack();
- tryOnFallBack(); // try when other leader dies
-
+ // try when other leader dies
var whenDeathListener = function whenDeathListener(msg) {
if (msg.context === 'leader' && msg.action === 'death') {
leaderElector.hasLeader = false;
@@ -291,17 +255,14 @@ function _awaitLeadershipOnce(leaderElector) {
});
}
};
-
leaderElector.broadcastChannel.addEventListener('internal', whenDeathListener);
-
leaderElector._lstns.push(whenDeathListener);
});
}
+
/**
* sends and internal message over the broadcast-channel
*/
-
-
function _sendMessage(leaderElector, action) {
var msgJson = {
context: 'leader',
@@ -310,21 +271,17 @@ function _sendMessage(leaderElector, action) {
};
return leaderElector.broadcastChannel.postInternal(msgJson);
}
-
export function beLeader(leaderElector) {
leaderElector.isLeader = true;
leaderElector.hasLeader = true;
var unloadFn = unloadAdd(function () {
return leaderElector.die();
});
-
leaderElector._unl.push(unloadFn);
-
var isLeaderListener = function isLeaderListener(msg) {
if (msg.context === 'leader' && msg.action === 'apply') {
_sendMessage(leaderElector, 'tell');
}
-
if (msg.context === 'leader' && msg.action === 'tell' && !leaderElector._dpLC) {
/**
* another instance is also leader!
@@ -335,49 +292,35 @@ export function beLeader(leaderElector) {
* @link https://github.com/pubkey/broadcast-channel/issues/385
*/
leaderElector._dpLC = true;
-
leaderElector._dpL(); // message the lib user so the app can handle the problem
-
-
_sendMessage(leaderElector, 'tell'); // ensure other leader also knows the problem
-
}
};
leaderElector.broadcastChannel.addEventListener('internal', isLeaderListener);
-
leaderElector._lstns.push(isLeaderListener);
-
return _sendMessage(leaderElector, 'tell');
}
-
function fillOptionsWithDefaults(options, channel) {
if (!options) options = {};
options = JSON.parse(JSON.stringify(options));
-
if (!options.fallbackInterval) {
options.fallbackInterval = 3000;
}
-
if (!options.responseTime) {
options.responseTime = channel.method.averageResponseTime(channel.options);
}
-
return options;
}
-
export function createLeaderElection(channel, options) {
if (channel._leaderElector) {
throw new Error('BroadcastChannel already has a leader-elector');
}
-
options = fillOptionsWithDefaults(options, channel);
var elector = new LeaderElection(channel, options);
-
channel._befC.push(function () {
return elector.die();
});
-
channel._leaderElector = elector;
return elector;
}
\ No newline at end of file
diff --git a/dist/esbrowser/method-chooser.js b/dist/esbrowser/method-chooser.js
index 4ab50593..74f4bda3 100644
--- a/dist/esbrowser/method-chooser.js
+++ b/dist/esbrowser/method-chooser.js
@@ -1,38 +1,39 @@
import NativeMethod from './methods/native.js';
import IndexeDbMethod from './methods/indexed-db.js';
import LocalstorageMethod from './methods/localstorage.js';
-import SimulateMethod from './methods/simulate.js'; // the line below will be removed from es5/browser builds
+import SimulateMethod from './methods/simulate.js';
+// the line below will be removed from es5/browser builds
-
-var METHODS = [NativeMethod, // fastest
+// order is important
+var METHODS = [NativeMethod,
+// fastest
IndexeDbMethod, LocalstorageMethod];
export function chooseMethod(options) {
- var chooseMethods = [].concat(options.methods, METHODS).filter(Boolean); // the line below will be removed from es5/browser builds
+ var chooseMethods = [].concat(options.methods, METHODS).filter(Boolean);
+ // the line below will be removed from es5/browser builds
+ // directly chosen
if (options.type) {
if (options.type === 'simulate') {
// only use simulate-method if directly chosen
return SimulateMethod;
}
-
var ret = chooseMethods.find(function (m) {
return m.type === options.type;
});
if (!ret) throw new Error('method-type ' + options.type + ' not found');else return ret;
}
+
/**
* if no webworker support is needed,
* remove idb from the list so that localstorage is been chosen
*/
-
-
if (!options.webWorkerSupport) {
chooseMethods = chooseMethods.filter(function (m) {
return m.type !== 'idb';
});
}
-
var useMethod = chooseMethods.find(function (method) {
return method.canBeUsed();
});
diff --git a/dist/esbrowser/methods/indexed-db.js b/dist/esbrowser/methods/indexed-db.js
index 75f983c0..24727d1a 100644
--- a/dist/esbrowser/methods/indexed-db.js
+++ b/dist/esbrowser/methods/indexed-db.js
@@ -6,55 +6,54 @@
* When working on this, ensure to use these performance optimizations:
* @link https://rxdb.info/slow-indexeddb.html
*/
+
import { sleep, randomInt, randomToken, microSeconds as micro, PROMISE_RESOLVED_VOID } from '../util.js';
export var microSeconds = micro;
import { ObliviousSet } from 'oblivious-set';
import { fillOptionsWithDefaults } from '../options.js';
var DB_PREFIX = 'pubkey.broadcast-channel-0-';
var OBJECT_STORE_ID = 'messages';
+
/**
* Use relaxed durability for faster performance on all transactions.
* @link https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/
*/
-
export var TRANSACTION_SETTINGS = {
durability: 'relaxed'
};
export var type = 'idb';
export function getIdb() {
if (typeof indexedDB !== 'undefined') return indexedDB;
-
if (typeof window !== 'undefined') {
if (typeof window.mozIndexedDB !== 'undefined') return window.mozIndexedDB;
if (typeof window.webkitIndexedDB !== 'undefined') return window.webkitIndexedDB;
if (typeof window.msIndexedDB !== 'undefined') return window.msIndexedDB;
}
-
return false;
}
+
/**
* If possible, we should explicitly commit IndexedDB transactions
* for better performance.
* @link https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/
*/
-
export function commitIndexedDBTransaction(tx) {
if (tx.commit) {
tx.commit();
}
}
export function createDatabase(channelName) {
- var IndexedDB = getIdb(); // create table
+ var IndexedDB = getIdb();
+ // create table
var dbName = DB_PREFIX + channelName;
+
/**
* All IndexedDB databases are opened without version
* because it is a bit faster, especially on firefox
* @link http://nparashuram.com/IndexedDB/perf/#Open%20Database%20with%20version
*/
-
var openRequest = IndexedDB.open(dbName);
-
openRequest.onupgradeneeded = function (ev) {
var db = ev.target.result;
db.createObjectStore(OBJECT_STORE_ID, {
@@ -62,23 +61,21 @@ export function createDatabase(channelName) {
autoIncrement: true
});
};
-
var dbPromise = new Promise(function (res, rej) {
openRequest.onerror = function (ev) {
return rej(ev);
};
-
openRequest.onsuccess = function () {
res(openRequest.result);
};
});
return dbPromise;
}
+
/**
* writes the new message to the database
* so other readers can find it
*/
-
export function writeMessage(db, readerUuid, messageJson) {
var time = new Date().getTime();
var writeObject = {
@@ -91,11 +88,9 @@ export function writeMessage(db, readerUuid, messageJson) {
tx.oncomplete = function () {
return res();
};
-
tx.onerror = function (ev) {
return rej(ev);
};
-
var objectStore = tx.objectStore(OBJECT_STORE_ID);
objectStore.add(writeObject);
commitIndexedDBTransaction(tx);
@@ -108,10 +103,9 @@ export function getAllMessages(db) {
return new Promise(function (res) {
objectStore.openCursor().onsuccess = function (ev) {
var cursor = ev.target.result;
-
if (cursor) {
- ret.push(cursor.value); //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
-
+ ret.push(cursor.value);
+ //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor["continue"]();
} else {
commitIndexedDBTransaction(tx);
@@ -125,25 +119,23 @@ export function getMessagesHigherThan(db, lastCursorId) {
var objectStore = tx.objectStore(OBJECT_STORE_ID);
var ret = [];
var keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity);
+
/**
* Optimization shortcut,
* if getAll() can be used, do not use a cursor.
* @link https://rxdb.info/slow-indexeddb.html
*/
-
if (objectStore.getAll) {
var getAllRequest = objectStore.getAll(keyRangeValue);
return new Promise(function (res, rej) {
getAllRequest.onerror = function (err) {
return rej(err);
};
-
getAllRequest.onsuccess = function (e) {
res(e.target.result);
};
});
}
-
function openCursor() {
// Occasionally Safari will fail on IDBKeyRange.bound, this
// catches that error, having it open the cursor to the first
@@ -155,17 +147,13 @@ export function getMessagesHigherThan(db, lastCursorId) {
return objectStore.openCursor();
}
}
-
return new Promise(function (res, rej) {
var openCursorRequest = openCursor();
-
openCursorRequest.onerror = function (err) {
return rej(err);
};
-
openCursorRequest.onsuccess = function (ev) {
var cursor = ev.target.result;
-
if (cursor) {
if (cursor.value.id < lastCursorId + 1) {
cursor["continue"](lastCursorId + 1);
@@ -184,7 +172,6 @@ export function removeMessagesById(channelState, ids) {
if (channelState.closed) {
return Promise.resolve([]);
}
-
var tx = channelState.db.transaction(OBJECT_STORE_ID, 'readwrite', TRANSACTION_SETTINGS);
var objectStore = tx.objectStore(OBJECT_STORE_ID);
return Promise.all(ids.map(function (id) {
@@ -204,13 +191,11 @@ export function getOldMessages(db, ttl) {
return new Promise(function (res) {
objectStore.openCursor().onsuccess = function (ev) {
var cursor = ev.target.result;
-
if (cursor) {
var msgObk = cursor.value;
-
if (msgObk.time < olderThen) {
- ret.push(msgObk); //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
-
+ ret.push(msgObk);
+ //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor["continue"]();
} else {
// no more old messages,
@@ -240,7 +225,6 @@ export function create(channelName, options) {
channelName: channelName,
options: options,
uuid: randomToken(),
-
/**
* emittedMessagesIds
* contains all messages that have been emitted before
@@ -253,30 +237,27 @@ export function create(channelName, options) {
readQueuePromises: [],
db: db
};
+
/**
* Handle abrupt closes that do not originate from db.close().
* This could happen, for example, if the underlying storage is
* removed or if the user clears the database in the browser's
* history preferences.
*/
-
db.onclose = function () {
state.closed = true;
if (options.idb.onclose) options.idb.onclose();
};
+
/**
* if service-workers are used,
* we have no 'storage'-event if they post a message,
* therefore we also have to set an interval
*/
-
-
_readLoop(state);
-
return state;
});
}
-
function _readLoop(state) {
if (state.closed) return;
readNewMessages(state).then(function () {
@@ -285,25 +266,21 @@ function _readLoop(state) {
return _readLoop(state);
});
}
-
function _filterMessage(msgObj, state) {
if (msgObj.uuid === state.uuid) return false; // send by own
-
if (state.eMIs.has(msgObj.id)) return false; // already emitted
-
if (msgObj.data.time < state.messagesCallbackTime) return false; // older then onMessageCallback
-
return true;
}
+
/**
* reads all new messages from the database and emits them
*/
-
-
function readNewMessages(state) {
// channel already closed
- if (state.closed) return PROMISE_RESOLVED_VOID; // if no one is listening, we do not need to scan for new messages
+ if (state.closed) return PROMISE_RESOLVED_VOID;
+ // if no one is listening, we do not need to scan for new messages
if (!state.messagesCallback) return PROMISE_RESOLVED_VOID;
return getMessagesHigherThan(state.db, state.lastCursorId).then(function (newerMessages) {
var useMessages = newerMessages
@@ -311,21 +288,18 @@ function readNewMessages(state) {
* there is a bug in iOS where the msgObj can be undefined some times
* so we filter them out
* @link https://github.com/pubkey/broadcast-channel/issues/19
- */
- .filter(function (msgObj) {
+ */.filter(function (msgObj) {
return !!msgObj;
}).map(function (msgObj) {
if (msgObj.id > state.lastCursorId) {
state.lastCursorId = msgObj.id;
}
-
return msgObj;
}).filter(function (msgObj) {
return _filterMessage(msgObj, state);
}).sort(function (msgObjA, msgObjB) {
return msgObjA.time - msgObjB.time;
}); // sort by time
-
useMessages.forEach(function (msgObj) {
if (state.messagesCallback) {
state.eMIs.add(msgObj.id);
@@ -335,7 +309,6 @@ function readNewMessages(state) {
return PROMISE_RESOLVED_VOID;
});
}
-
export function close(channelState) {
channelState.closed = true;
channelState.db.close();
@@ -358,11 +331,9 @@ export function onMessage(channelState, fn, time) {
}
export function canBeUsed() {
var idb = getIdb();
-
if (!idb) {
return false;
}
-
return true;
}
export function averageResponseTime(options) {
diff --git a/dist/esbrowser/methods/localstorage.js b/dist/esbrowser/methods/localstorage.js
index 5a4adcc6..a0bb80e5 100644
--- a/dist/esbrowser/methods/localstorage.js
+++ b/dist/esbrowser/methods/localstorage.js
@@ -5,39 +5,39 @@
* @link https://caniuse.com/#feat=namevalue-storage
* @link https://caniuse.com/#feat=indexeddb
*/
+
import { ObliviousSet } from 'oblivious-set';
import { fillOptionsWithDefaults } from '../options.js';
import { sleep, randomToken, microSeconds as micro } from '../util.js';
export var microSeconds = micro;
var KEY_PREFIX = 'pubkey.broadcastChannel-';
export var type = 'localstorage';
+
/**
* copied from crosstab
* @link https://github.com/tejacques/crosstab/blob/master/src/crosstab.js#L32
*/
-
export function getLocalStorage() {
var localStorage;
if (typeof window === 'undefined') return null;
-
try {
localStorage = window.localStorage;
localStorage = window['ie8-eventlistener/storage'] || window.localStorage;
- } catch (e) {// New versions of Firefox throw a Security exception
+ } catch (e) {
+ // New versions of Firefox throw a Security exception
// if cookies are disabled. See
// https://bugzilla.mozilla.org/show_bug.cgi?id=1028153
}
-
return localStorage;
}
export function storageKey(channelName) {
return KEY_PREFIX + channelName;
}
+
/**
* writes the new message to the storage
* and fires the storage-event so other readers can find it
*/
-
export function postMessage(channelState, messageJson) {
return new Promise(function (res) {
sleep().then(function () {
@@ -50,12 +50,12 @@ export function postMessage(channelState, messageJson) {
};
var value = JSON.stringify(writeObj);
getLocalStorage().setItem(key, value);
+
/**
* StorageEvent does not fire the 'storage' event
* in the window that changes the state of the local storage.
* So we fire it manually
*/
-
var ev = document.createEvent('Event');
ev.initEvent('storage', true, true);
ev.key = key;
@@ -67,13 +67,11 @@ export function postMessage(channelState, messageJson) {
}
export function addStorageEventListener(channelName, fn) {
var key = storageKey(channelName);
-
var listener = function listener(ev) {
if (ev.key === key) {
fn(JSON.parse(ev.newValue));
}
};
-
window.addEventListener('storage', listener);
return listener;
}
@@ -82,32 +80,27 @@ export function removeStorageEventListener(listener) {
}
export function create(channelName, options) {
options = fillOptionsWithDefaults(options);
-
if (!canBeUsed()) {
throw new Error('BroadcastChannel: localstorage cannot be used');
}
-
var uuid = randomToken();
+
/**
* eMIs
* contains all messages that have been emitted before
* @type {ObliviousSet}
*/
-
var eMIs = new ObliviousSet(options.localstorage.removeTimeout);
var state = {
channelName: channelName,
uuid: uuid,
eMIs: eMIs // emittedMessagesIds
-
};
+
state.listener = addStorageEventListener(channelName, function (msgObj) {
if (!state.messagesCallback) return; // no listener
-
if (msgObj.uuid === uuid) return; // own message
-
if (!msgObj.token || eMIs.has(msgObj.token)) return; // already emitted
-
if (msgObj.data.time && msgObj.data.time < state.messagesCallbackTime) return; // too old
eMIs.add(msgObj.token);
@@ -125,7 +118,6 @@ export function onMessage(channelState, fn, time) {
export function canBeUsed() {
var ls = getLocalStorage();
if (!ls) return false;
-
try {
var key = '__broadcastchannel_check';
ls.setItem(key, 'works');
@@ -136,18 +128,15 @@ export function canBeUsed() {
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API#Private_Browsing_Incognito_modes
return false;
}
-
return true;
}
export function averageResponseTime() {
var defaultTime = 120;
var userAgent = navigator.userAgent.toLowerCase();
-
if (userAgent.includes('safari') && !userAgent.includes('chrome')) {
// safari is much slower so this time is higher
return defaultTime * 2;
}
-
return defaultTime;
}
export default {
diff --git a/dist/esbrowser/methods/native.js b/dist/esbrowser/methods/native.js
index 6841c45b..6e45b272 100644
--- a/dist/esbrowser/methods/native.js
+++ b/dist/esbrowser/methods/native.js
@@ -6,7 +6,6 @@ export function create(channelName) {
messagesCallback: null,
bc: new BroadcastChannel(channelName),
subFns: [] // subscriberFunctions
-
};
state.bc.onmessage = function (msg) {
@@ -14,7 +13,6 @@ export function create(channelName) {
state.messagesCallback(msg.data);
}
};
-
return state;
}
export function close(channelState) {
@@ -36,12 +34,10 @@ export function canBeUsed() {
if (typeof window === 'undefined') {
return false;
}
-
if (typeof BroadcastChannel === 'function') {
if (BroadcastChannel._pubkey) {
throw new Error('BroadcastChannel: Do not overwrite window.BroadcastChannel with this module, this is not a polyfill');
}
-
return true;
} else {
return false;
diff --git a/dist/esbrowser/methods/node.js b/dist/esbrowser/methods/node.js
index 5b30135d..0f823fad 100644
--- a/dist/esbrowser/methods/node.js
+++ b/dist/esbrowser/methods/node.js
@@ -1,10 +1,10 @@
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
import _regeneratorRuntime from "@babel/runtime/regenerator";
-
/**
* this method is used in nodejs-environments.
* The ipc is handled via sockets and file-writes to the tmp-folder
*/
+
import util from 'util';
import fs from 'fs';
import crypto from 'crypto';
@@ -18,11 +18,11 @@ import { add as unloadAdd } from 'unload';
import { fillOptionsWithDefaults } from '../options.js';
import { randomInt, randomToken, PROMISE_RESOLVED_VOID } from '../util.js';
import { ObliviousSet } from 'oblivious-set';
+
/**
* windows sucks, so we have handle windows-type of socket-paths
* @link https://gist.github.com/domenic/2790533#gistcomment-331356
*/
-
export function cleanPipeName(str) {
if (process.platform === 'win32' && !str.startsWith('\\\\.\\pipe\\')) {
str = str.replace(/^\//, '');
@@ -52,12 +52,12 @@ export function getPaths(channelName) {
* in using the same folders for different channels.
*/
var channelHash = crypto.createHash('sha256').update(channelName).digest('hex');
+
/**
* because the length of socket-paths is limited, we use only the first 20 chars
* and also start with A to ensure we do not start with a number
* @link https://serverfault.com/questions/641347/check-if-a-path-exceeds-maximum-for-unix-domain-socket
*/
-
var channelFolder = 'A' + channelHash.substring(0, 20);
var channelPathBase = path.join(TMP_FOLDER_BASE, channelFolder);
var folderPathReaders = path.join(channelPathBase, 'rdrs');
@@ -70,15 +70,12 @@ export function getPaths(channelName) {
getPathsCache.set(channelName, ret);
return ret;
}
-
return getPathsCache.get(channelName);
}
var ENSURE_BASE_FOLDER_EXISTS_PROMISE = null;
-
function ensureBaseFolderExists() {
return _ensureBaseFolderExists.apply(this, arguments);
}
-
function _ensureBaseFolderExists() {
_ensureBaseFolderExists = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
return _regeneratorRuntime.wrap(function _callee3$(_context3) {
@@ -90,9 +87,7 @@ function _ensureBaseFolderExists() {
return null;
});
}
-
return _context3.abrupt("return", ENSURE_BASE_FOLDER_EXISTS_PROMISE);
-
case 2:
case "end":
return _context3.stop();
@@ -102,15 +97,14 @@ function _ensureBaseFolderExists() {
}));
return _ensureBaseFolderExists.apply(this, arguments);
}
-
export function ensureFoldersExist(_x, _x2) {
return _ensureFoldersExist.apply(this, arguments);
}
+
/**
* removes the tmp-folder
* @return {Promise}
*/
-
function _ensureFoldersExist() {
_ensureFoldersExist = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4(channelName, paths) {
var chmodValue;
@@ -121,13 +115,11 @@ function _ensureFoldersExist() {
paths = paths || getPaths(channelName);
_context4.next = 3;
return ensureBaseFolderExists();
-
case 3:
_context4.next = 5;
return mkdir(paths.channelBase)["catch"](function () {
return null;
});
-
case 5:
_context4.next = 7;
return Promise.all([mkdir(paths.readers)["catch"](function () {
@@ -135,7 +127,6 @@ function _ensureFoldersExist() {
}), mkdir(paths.messages)["catch"](function () {
return null;
})]);
-
case 7:
// set permissions so other users can use the same channel
chmodValue = '777';
@@ -143,7 +134,6 @@ function _ensureFoldersExist() {
return Promise.all([chmod(paths.channelBase, chmodValue), chmod(paths.readers, chmodValue), chmod(paths.messages, chmodValue)])["catch"](function () {
return null;
});
-
case 10:
case "end":
return _context4.stop();
@@ -153,11 +143,9 @@ function _ensureFoldersExist() {
}));
return _ensureFoldersExist.apply(this, arguments);
}
-
export function clearNodeFolder() {
return _clearNodeFolder.apply(this, arguments);
}
-
function _clearNodeFolder() {
_clearNodeFolder = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee5() {
return _regeneratorRuntime.wrap(function _callee5$(_context5) {
@@ -168,18 +156,14 @@ function _clearNodeFolder() {
_context5.next = 2;
break;
}
-
throw new Error('BroadcastChannel.clearNodeFolder(): path is wrong');
-
case 2:
ENSURE_BASE_FOLDER_EXISTS_PROMISE = null;
_context5.next = 5;
return removeDir(TMP_FOLDER_BASE);
-
case 5:
ENSURE_BASE_FOLDER_EXISTS_PROMISE = null;
return _context5.abrupt("return", true);
-
case 7:
case "end":
return _context5.stop();
@@ -189,7 +173,6 @@ function _clearNodeFolder() {
}));
return _clearNodeFolder.apply(this, arguments);
}
-
export function socketPath(channelName, readerUuid, paths) {
paths = paths || getPaths(channelName);
var socketPath = path.join(paths.readers, readerUuid + '.s');
@@ -200,12 +183,12 @@ export function socketInfoPath(channelName, readerUuid, paths) {
var socketPath = path.join(paths.readers, readerUuid + '.json');
return socketPath;
}
+
/**
* Because it is not possible to get all socket-files in a folder,
* when used under fucking windows,
* we have to set a normal file so other readers know our socket exists
*/
-
export function createSocketInfoFile(channelName, readerUuid, paths) {
var pathToFile = socketInfoPath(channelName, readerUuid, paths);
return writeFile(pathToFile, JSON.stringify({
@@ -214,15 +197,14 @@ export function createSocketInfoFile(channelName, readerUuid, paths) {
return pathToFile;
});
}
+
/**
* returns the amount of channel-folders in the tmp-directory
* @return {Promise}
*/
-
export function countChannelFolders() {
return _countChannelFolders.apply(this, arguments);
}
-
function _countChannelFolders() {
_countChannelFolders = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee6() {
var folders;
@@ -232,15 +214,12 @@ function _countChannelFolders() {
case 0:
_context6.next = 2;
return ensureBaseFolderExists();
-
case 2:
_context6.next = 4;
return readdir(TMP_FOLDER_BASE);
-
case 4:
folders = _context6.sent;
return _context6.abrupt("return", folders.length);
-
case 6:
case "end":
return _context6.stop();
@@ -250,7 +229,6 @@ function _countChannelFolders() {
}));
return _countChannelFolders.apply(this, arguments);
}
-
function connectionError(_x3) {
return _connectionError.apply(this, arguments);
}
@@ -258,8 +236,6 @@ function connectionError(_x3) {
* creates the socket-file and subscribes to it
* @return {{emitter: EventEmitter, server: any}}
*/
-
-
function _connectionError() {
_connectionError = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee7(originalError) {
var count, addObj, text, newError;
@@ -269,28 +245,23 @@ function _connectionError() {
case 0:
_context7.next = 2;
return countChannelFolders();
-
case 2:
count = _context7.sent;
-
if (!(count < 30)) {
_context7.next = 5;
break;
}
-
return _context7.abrupt("return", originalError);
-
case 5:
addObj = {};
Object.entries(originalError).forEach(function (_ref3) {
var k = _ref3[0],
- v = _ref3[1];
+ v = _ref3[1];
return addObj[k] = v;
});
text = 'BroadcastChannel.create(): error: ' + 'This might happen if you have created to many channels, ' + 'like when you use BroadcastChannel in unit-tests.' + 'Try using BroadcastChannel.clearNodeFolder() to clear the tmp-folder before each test.' + 'See https://github.com/pubkey/broadcast-channel#clear-tmp-folder';
newError = new Error(text + ': ' + JSON.stringify(addObj, null, 2));
return _context7.abrupt("return", newError);
-
case 10:
case "end":
return _context7.stop();
@@ -300,11 +271,9 @@ function _connectionError() {
}));
return _connectionError.apply(this, arguments);
}
-
export function createSocketEventEmitter(_x4, _x5, _x6) {
return _createSocketEventEmitter.apply(this, arguments);
}
-
function _createSocketEventEmitter() {
_createSocketEventEmitter = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee10(channelName, readerUuid, paths) {
var pathToSocket, emitter, server;
@@ -331,11 +300,9 @@ function _createSocketEventEmitter() {
case 0:
_context8.next = 2;
return connectionError(err);
-
case 2:
useErr = _context8.sent;
reject(useErr);
-
case 4:
case "end":
return _context8.stop();
@@ -343,7 +310,6 @@ function _createSocketEventEmitter() {
}
}, _callee8);
}));
-
return function (_x26) {
return _ref4.apply(this, arguments);
};
@@ -359,19 +325,15 @@ function _createSocketEventEmitter() {
_context9.next = 7;
break;
}
-
_context9.next = 3;
return connectionError(err);
-
case 3:
useErr = _context9.sent;
reject(useErr);
_context9.next = 8;
break;
-
case 7:
resolve(res);
-
case 8:
case "end":
return _context9.stop();
@@ -379,20 +341,17 @@ function _createSocketEventEmitter() {
}
}, _callee9);
}));
-
return function (_x27, _x28) {
return _ref5.apply(this, arguments);
};
}());
});
-
case 5:
return _context10.abrupt("return", {
path: pathToSocket,
emitter: emitter,
server: server
});
-
case 6:
case "end":
return _context10.stop();
@@ -402,16 +361,15 @@ function _createSocketEventEmitter() {
}));
return _createSocketEventEmitter.apply(this, arguments);
}
-
export function openClientConnection(_x7, _x8) {
return _openClientConnection.apply(this, arguments);
}
+
/**
* writes the new message to the file-system
* so other readers can find it
* @return {Promise}
*/
-
function _openClientConnection() {
_openClientConnection = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee11(channelName, readerUuid) {
var pathToSocket, client;
@@ -429,7 +387,6 @@ function _openClientConnection() {
return rej(err);
});
}));
-
case 3:
case "end":
return _context11.stop();
@@ -439,7 +396,6 @@ function _openClientConnection() {
}));
return _openClientConnection.apply(this, arguments);
}
-
export function writeMessage(channelName, readerUuid, messageJson, paths) {
paths = paths || getPaths(channelName);
var time = microSeconds();
@@ -460,15 +416,14 @@ export function writeMessage(channelName, readerUuid, messageJson, paths) {
};
});
}
+
/**
* returns the uuids of all readers
* @return {string[]}
*/
-
export function getReadersUuids(_x9, _x10) {
return _getReadersUuids.apply(this, arguments);
}
-
function _getReadersUuids() {
_getReadersUuids = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee12(channelName, paths) {
var readersPath, files;
@@ -480,7 +435,6 @@ function _getReadersUuids() {
readersPath = paths.readers;
_context12.next = 4;
return readdir(readersPath);
-
case 4:
files = _context12.sent;
return _context12.abrupt("return", files.map(function (file) {
@@ -491,7 +445,6 @@ function _getReadersUuids() {
.map(function (split) {
return split[0];
}));
-
case 6:
case "end":
return _context12.stop();
@@ -501,11 +454,9 @@ function _getReadersUuids() {
}));
return _getReadersUuids.apply(this, arguments);
}
-
export function messagePath(_x11, _x12, _x13, _x14) {
return _messagePath.apply(this, arguments);
}
-
function _messagePath() {
_messagePath = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee13(channelName, time, token, writerUuid) {
var fileName, msgPath;
@@ -516,7 +467,6 @@ function _messagePath() {
fileName = time + '_' + writerUuid + '_' + token + '.json';
msgPath = path.join(getPaths(channelName).messages, fileName);
return _context13.abrupt("return", msgPath);
-
case 3:
case "end":
return _context13.stop();
@@ -526,11 +476,9 @@ function _messagePath() {
}));
return _messagePath.apply(this, arguments);
}
-
export function getAllMessages(_x15, _x16) {
return _getAllMessages.apply(this, arguments);
}
-
function _getAllMessages() {
_getAllMessages = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee14(channelName, paths) {
var messagesPath, files;
@@ -542,7 +490,6 @@ function _getAllMessages() {
messagesPath = paths.messages;
_context14.next = 4;
return readdir(messagesPath);
-
case 4:
files = _context14.sent;
return _context14.abrupt("return", files.map(function (file) {
@@ -555,7 +502,6 @@ function _getAllMessages() {
token: split[2]
};
}));
-
case 6:
case "end":
return _context14.stop();
@@ -565,7 +511,6 @@ function _getAllMessages() {
}));
return _getAllMessages.apply(this, arguments);
}
-
export function getSingleMessage(channelName, msgObj, paths) {
paths = paths || getPaths(channelName);
return {
@@ -583,7 +528,6 @@ export function readMessage(messageObj) {
export function cleanOldMessages(_x17, _x18) {
return _cleanOldMessages.apply(this, arguments);
}
-
function _cleanOldMessages() {
_cleanOldMessages = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee15(messageObjects, ttl) {
var olderThen;
@@ -592,7 +536,6 @@ function _cleanOldMessages() {
switch (_context15.prev = _context15.next) {
case 0:
olderThen = microSeconds() - ttl * 1000; // convert ttl to microseconds
-
_context15.next = 3;
return Promise.all(messageObjects.filter(function (obj) {
return obj.time < olderThen;
@@ -601,7 +544,6 @@ function _cleanOldMessages() {
return null;
});
}));
-
case 3:
case "end":
return _context15.stop();
@@ -611,30 +553,27 @@ function _cleanOldMessages() {
}));
return _cleanOldMessages.apply(this, arguments);
}
-
export var type = 'node';
+
/**
* creates a new channelState
* @return {Promise}
*/
-
export function create(_x19) {
return _create.apply(this, arguments);
}
-
function _create() {
_create = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee16(channelName) {
var options,
- time,
- paths,
- ensureFolderExistsPromise,
- uuid,
- state,
- _yield$Promise$all,
- socketEE,
- infoFilePath,
- _args16 = arguments;
-
+ time,
+ paths,
+ ensureFolderExistsPromise,
+ uuid,
+ state,
+ _yield$Promise$all,
+ socketEE,
+ infoFilePath,
+ _args16 = arguments;
return _regeneratorRuntime.wrap(function _callee16$(_context16) {
while (1) {
switch (_context16.prev = _context16.next) {
@@ -653,7 +592,6 @@ function _create() {
paths: paths,
// contains all messages that have been emitted before
emittedMessagesIds: new ObliviousSet(options.node.ttl * 2),
-
/**
* Used to ensure we do not write too many files at once
* which could throw an error.
@@ -677,18 +615,17 @@ function _create() {
OTHER_INSTANCES[channelName].push(state);
_context16.next = 11;
return ensureFolderExistsPromise;
-
case 11:
_context16.next = 13;
return Promise.all([createSocketEventEmitter(channelName, uuid, paths), createSocketInfoFile(channelName, uuid, paths), refreshReaderClients(state)]);
-
case 13:
_yield$Promise$all = _context16.sent;
socketEE = _yield$Promise$all[0];
infoFilePath = _yield$Promise$all[1];
state.socketEE = socketEE;
- state.infoFilePath = infoFilePath; // when new message comes in, we read it and emit it
+ state.infoFilePath = infoFilePath;
+ // when new message comes in, we read it and emit it
socketEE.emitter.on('data', function (data) {
// if the socket is used fast, it may appear that multiple messages are flushed at once
// so we have to split them before
@@ -705,7 +642,6 @@ function _create() {
});
});
return _context16.abrupt("return", state);
-
case 20:
case "end":
return _context16.stop();
@@ -715,34 +651,29 @@ function _create() {
}));
return _create.apply(this, arguments);
}
-
export function _filterMessage(msgObj, state) {
if (msgObj.senderUuid === state.uuid) return false; // not send by own
-
if (state.emittedMessagesIds.has(msgObj.token)) return false; // not already emitted
-
if (!state.messagesCallback) return false; // no listener
-
if (msgObj.time < state.messagesCallbackTime) return false; // not older then onMessageCallback
-
if (msgObj.time < state.time) return false; // msgObj is older then channel
state.emittedMessagesIds.add(msgObj.token);
return true;
}
+
/**
* when the socket pings, so that we now new messages came,
* run this
*/
-
export function handleMessagePing(_x20, _x21) {
return _handleMessagePing.apply(this, arguments);
}
+
/**
* ensures that the channelState is connected with all other readers
* @return {Promise}
*/
-
function _handleMessagePing() {
_handleMessagePing = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee17(state, msgObj) {
var messages, useMessages;
@@ -754,27 +685,21 @@ function _handleMessagePing() {
_context17.next = 2;
break;
}
-
return _context17.abrupt("return");
-
case 2:
if (msgObj) {
_context17.next = 8;
break;
}
-
_context17.next = 5;
return getAllMessages(state.channelName, state.paths);
-
case 5:
messages = _context17.sent;
_context17.next = 9;
break;
-
case 8:
// get single message
messages = [getSingleMessage(state.channelName, msgObj, state.paths)];
-
case 9:
useMessages = messages.filter(function (msgObj) {
return _filterMessage(msgObj, state);
@@ -782,14 +707,11 @@ function _handleMessagePing() {
return msgObjA.time - msgObjB.time;
}); // sort by time
// if no listener or message, so not do anything
-
if (!(!useMessages.length || !state.messagesCallback)) {
_context17.next = 12;
break;
}
-
return _context17.abrupt("return");
-
case 12:
_context17.next = 14;
return Promise.all(useMessages.map(function (msgObj) {
@@ -797,17 +719,14 @@ function _handleMessagePing() {
return msgObj.content = content;
});
}));
-
case 14:
useMessages.forEach(function (msgObj) {
state.emittedMessagesIds.add(msgObj.token);
-
if (state.messagesCallback) {
// emit to subscribers
state.messagesCallback(msgObj.content.data);
}
});
-
case 15:
case "end":
return _context17.stop();
@@ -817,7 +736,6 @@ function _handleMessagePing() {
}));
return _handleMessagePing.apply(this, arguments);
}
-
export function refreshReaderClients(channelState) {
return getReadersUuids(channelState.channelName, channelState.paths).then(function (otherReaders) {
// remove subscriptions to closed readers
@@ -832,18 +750,14 @@ export function refreshReaderClients(channelState) {
_context.prev = 0;
_context.next = 3;
return channelState.otherReaderClients[readerUuid].destroy();
-
case 3:
_context.next = 7;
break;
-
case 5:
_context.prev = 5;
_context.t0 = _context["catch"](0);
-
case 7:
delete channelState.otherReaderClients[readerUuid];
-
case 8:
case "end":
return _context.stop();
@@ -851,12 +765,12 @@ export function refreshReaderClients(channelState) {
}
}, _callee, null, [[0, 5]]);
}));
-
return function (_x22) {
return _ref.apply(this, arguments);
};
- }()); // add new readers
+ }());
+ // add new readers
return Promise.all(otherReaders.filter(function (readerUuid) {
return readerUuid !== channelState.uuid;
}) // not own
@@ -871,37 +785,29 @@ export function refreshReaderClients(channelState) {
switch (_context2.prev = _context2.next) {
case 0:
_context2.prev = 0;
-
if (!channelState.closed) {
_context2.next = 3;
break;
}
-
return _context2.abrupt("return");
-
case 3:
_context2.prev = 3;
_context2.next = 6;
return openClientConnection(channelState.channelName, readerUuid);
-
case 6:
client = _context2.sent;
channelState.otherReaderClients[readerUuid] = client;
_context2.next = 12;
break;
-
case 10:
_context2.prev = 10;
_context2.t0 = _context2["catch"](3);
-
case 12:
_context2.next = 16;
break;
-
case 14:
_context2.prev = 14;
_context2.t1 = _context2["catch"](0);
-
case 16:
case "end":
return _context2.stop();
@@ -909,28 +815,27 @@ export function refreshReaderClients(channelState) {
}
}, _callee2, null, [[0, 14], [3, 10]]);
}));
-
return function (_x23) {
return _ref2.apply(this, arguments);
};
}()));
});
}
+
/**
* post a message to the other readers
* @return {Promise}
*/
-
export function postMessage(_x24, _x25) {
return _postMessage.apply(this, arguments);
}
+
/**
* When multiple BroadcastChannels with the same name
* are created in a single node-process, we can access them directly and emit messages.
* This might not happen often in production
* but will speed up things when this module is used in unit-tests.
*/
-
function _postMessage() {
_postMessage = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee19(channelState, messageJson) {
var writePromise;
@@ -943,7 +848,6 @@ function _postMessage() {
});
channelState.writeBlockPromise = channelState.writeBlockPromise.then( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee18() {
var _yield$Promise$all2, msgObj, pingStr, writeToReadersPromise;
-
return _regeneratorRuntime.wrap(function _callee18$(_context18) {
while (1) {
switch (_context18.prev = _context18.next) {
@@ -952,11 +856,9 @@ function _postMessage() {
return new Promise(function (res) {
return setTimeout(res, 0);
});
-
case 2:
_context18.next = 4;
return Promise.all([writePromise, refreshReaderClients(channelState)]);
-
case 4:
_yield$Promise$all2 = _context18.sent;
msgObj = _yield$Promise$all2[0];
@@ -975,16 +877,13 @@ function _postMessage() {
* to not waste resources on cleaning up,
* only if random-int matches, we clean up old messages
*/
-
if (randomInt(0, 20) === 0) {
/* await */
getAllMessages(channelState.channelName, channelState.paths).then(function (allMessages) {
return cleanOldMessages(allMessages, channelState.options.node.ttl);
});
}
-
return _context18.abrupt("return", writeToReadersPromise);
-
case 11:
case "end":
return _context18.stop();
@@ -993,7 +892,6 @@ function _postMessage() {
}, _callee18);
})));
return _context19.abrupt("return", channelState.writeBlockPromise);
-
case 3:
case "end":
return _context19.stop();
@@ -1003,13 +901,11 @@ function _postMessage() {
}));
return _postMessage.apply(this, arguments);
}
-
export function emitOverFastPath(state, msgObj, messageJson) {
if (!state.options.node.useFastPath) {
// disabled
return;
}
-
var others = OTHER_INSTANCES[state.channelName].filter(function (s) {
return s !== state;
});
@@ -1030,11 +926,11 @@ export function onMessage(channelState, fn) {
channelState.messagesCallback = fn;
handleMessagePing(channelState);
}
+
/**
* closes the channel
* @return {Promise}
*/
-
export function close(channelState) {
if (channelState.closed) return;
channelState.closed = true;
@@ -1042,28 +938,24 @@ export function close(channelState) {
OTHER_INSTANCES[channelState.channelName] = OTHER_INSTANCES[channelState.channelName].filter(function (o) {
return o !== channelState;
});
-
if (channelState.removeUnload) {
channelState.removeUnload.remove();
}
-
return new Promise(function (res) {
if (channelState.socketEE) channelState.socketEE.emitter.removeAllListeners();
Object.values(channelState.otherReaderClients).forEach(function (client) {
return client.destroy();
});
-
if (channelState.infoFilePath) {
try {
fs.unlinkSync(channelState.infoFilePath);
} catch (err) {}
}
+
/**
* the server get closed lazy because others might still write on it
* and have not found out that the infoFile was deleted
*/
-
-
setTimeout(function () {
channelState.socketEE.server.close();
res();
@@ -1077,13 +969,13 @@ export function canBeUsed() {
return false;
}
}
+
/**
* on node we use a relatively height averageResponseTime,
* because the file-io might be in use.
* Also it is more important that the leader-election is reliable,
* then to have a fast election.
*/
-
export function averageResponseTime() {
return 200;
}
@@ -1091,7 +983,6 @@ export function microSeconds() {
// convert nano to micro seconds
return parseInt(now() / 1000);
}
-
function now() {
return Number(process.hrtime.bigint()); // returns nanoseconds
}
\ No newline at end of file
diff --git a/dist/esbrowser/options.js b/dist/esbrowser/options.js
index fbcc5244..86c7fae3 100644
--- a/dist/esbrowser/options.js
+++ b/dist/esbrowser/options.js
@@ -1,29 +1,32 @@
export function fillOptionsWithDefaults() {
var originalOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- var options = JSON.parse(JSON.stringify(originalOptions)); // main
+ var options = JSON.parse(JSON.stringify(originalOptions));
- if (typeof options.webWorkerSupport === 'undefined') options.webWorkerSupport = true; // indexed-db
-
- if (!options.idb) options.idb = {}; // after this time the messages get deleted
+ // main
+ if (typeof options.webWorkerSupport === 'undefined') options.webWorkerSupport = true;
+ // indexed-db
+ if (!options.idb) options.idb = {};
+ // after this time the messages get deleted
if (!options.idb.ttl) options.idb.ttl = 1000 * 45;
- if (!options.idb.fallbackInterval) options.idb.fallbackInterval = 150; // handles abrupt db onclose events.
-
- if (originalOptions.idb && typeof originalOptions.idb.onclose === 'function') options.idb.onclose = originalOptions.idb.onclose; // localstorage
+ if (!options.idb.fallbackInterval) options.idb.fallbackInterval = 150;
+ // handles abrupt db onclose events.
+ if (originalOptions.idb && typeof originalOptions.idb.onclose === 'function') options.idb.onclose = originalOptions.idb.onclose;
+ // localstorage
if (!options.localstorage) options.localstorage = {};
- if (!options.localstorage.removeTimeout) options.localstorage.removeTimeout = 1000 * 60; // custom methods
+ if (!options.localstorage.removeTimeout) options.localstorage.removeTimeout = 1000 * 60;
- if (originalOptions.methods) options.methods = originalOptions.methods; // node
+ // custom methods
+ if (originalOptions.methods) options.methods = originalOptions.methods;
+ // node
if (!options.node) options.node = {};
if (!options.node.ttl) options.node.ttl = 1000 * 60 * 2; // 2 minutes;
-
/**
* On linux use 'ulimit -Hn' to get the limit of open files.
* On ubuntu this was 4096 for me, so we use half of that as maxParallelWrites default.
*/
-
if (!options.node.maxParallelWrites) options.node.maxParallelWrites = 2048;
if (typeof options.node.useFastPath === 'undefined') options.node.useFastPath = true;
return options;
diff --git a/dist/esbrowser/util.js b/dist/esbrowser/util.js
index 99b7e529..6c9b9b6e 100644
--- a/dist/esbrowser/util.js
+++ b/dist/esbrowser/util.js
@@ -22,15 +22,16 @@ export function sleep(time, resolveWith) {
export function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
+
/**
* https://stackoverflow.com/a/8084248
*/
-
export function randomToken() {
return Math.random().toString(36).substring(2);
}
var lastMs = 0;
var additional = 0;
+
/**
* returns the current time in micro-seconds,
* WARNING: This is a pseudo-function
@@ -38,10 +39,8 @@ var additional = 0;
* This is enough in browsers, and this function will not be used in nodejs.
* The main reason for this hack is to ensure that BroadcastChannel behaves equal to production when it is used in fast-running unit tests.
*/
-
export function microSeconds() {
var ms = new Date().getTime();
-
if (ms === lastMs) {
additional++;
return ms * 1000 + additional;
diff --git a/dist/esnode/broadcast-channel.js b/dist/esnode/broadcast-channel.js
index 09502c09..d62e7a95 100644
--- a/dist/esnode/broadcast-channel.js
+++ b/dist/esnode/broadcast-channel.js
@@ -1,11 +1,11 @@
import { isPromise, PROMISE_RESOLVED_FALSE, PROMISE_RESOLVED_VOID } from './util.js';
import { chooseMethod } from './method-chooser.js';
import { fillOptionsWithDefaults } from './options.js';
+
/**
* Contains all open channels,
* used in tests to ensure everything is closed.
*/
-
export var OPEN_BROADCAST_CHANNELS = new Set();
var lastId = 0;
export var BroadcastChannel = function BroadcastChannel(name, options) {
@@ -13,69 +13,67 @@ export var BroadcastChannel = function BroadcastChannel(name, options) {
this.id = lastId++;
OPEN_BROADCAST_CHANNELS.add(this);
this.name = name;
-
if (ENFORCED_OPTIONS) {
options = ENFORCED_OPTIONS;
}
-
this.options = fillOptionsWithDefaults(options);
- this.method = chooseMethod(this.options); // isListening
+ this.method = chooseMethod(this.options);
+ // isListening
this._iL = false;
+
/**
* _onMessageListener
* setting onmessage twice,
* will overwrite the first listener
*/
-
this._onML = null;
+
/**
* _addEventListeners
*/
-
this._addEL = {
message: [],
internal: []
};
+
/**
* Unsend message promises
* where the sending is still in progress
* @type {Set}
*/
-
this._uMP = new Set();
+
/**
* _beforeClose
* array of promises that will be awaited
* before the channel is closed
*/
-
this._befC = [];
+
/**
* _preparePromise
*/
-
this._prepP = null;
-
_prepareChannel(this);
-}; // STATICS
+};
+
+// STATICS
/**
* used to identify if someone overwrites
* window.BroadcastChannel with this
* See methods/native.js
*/
-
BroadcastChannel._pubkey = true;
+
/**
* clears the tmp-folder if is node
* @return {Promise} true if has run, false if not node
*/
-
export function clearNodeFolder(options) {
options = fillOptionsWithDefaults(options);
var method = chooseMethod(options);
-
if (method.type === 'node') {
return method.clearNodeFolder().then(function () {
return true;
@@ -84,16 +82,17 @@ export function clearNodeFolder(options) {
return PROMISE_RESOLVED_FALSE;
}
}
+
/**
* if set, this method is enforced,
* no mather what the options are
*/
-
var ENFORCED_OPTIONS;
export function enforceOptions(options) {
ENFORCED_OPTIONS = options;
-} // PROTOTYPE
+}
+// PROTOTYPE
BroadcastChannel.prototype = {
postMessage: function postMessage(msg) {
if (this.closed) {
@@ -105,87 +104,77 @@ BroadcastChannel.prototype = {
*/
JSON.stringify(msg));
}
-
return _post(this, 'message', msg);
},
postInternal: function postInternal(msg) {
return _post(this, 'internal', msg);
},
-
set onmessage(fn) {
var time = this.method.microSeconds();
var listenObj = {
time: time,
fn: fn
};
-
_removeListenerObject(this, 'message', this._onML);
-
if (fn && typeof fn === 'function') {
this._onML = listenObj;
-
_addListenerObject(this, 'message', listenObj);
} else {
this._onML = null;
}
},
-
addEventListener: function addEventListener(type, fn) {
var time = this.method.microSeconds();
var listenObj = {
time: time,
fn: fn
};
-
_addListenerObject(this, type, listenObj);
},
removeEventListener: function removeEventListener(type, fn) {
var obj = this._addEL[type].find(function (obj) {
return obj.fn === fn;
});
-
_removeListenerObject(this, type, obj);
},
close: function close() {
var _this = this;
-
if (this.closed) {
return;
}
-
OPEN_BROADCAST_CHANNELS["delete"](this);
this.closed = true;
var awaitPrepare = this._prepP ? this._prepP : PROMISE_RESOLVED_VOID;
this._onML = null;
this._addEL.message = [];
- return awaitPrepare // wait until all current sending are processed
+ return awaitPrepare
+ // wait until all current sending are processed
.then(function () {
return Promise.all(Array.from(_this._uMP));
- }) // run before-close hooks
+ })
+ // run before-close hooks
.then(function () {
return Promise.all(_this._befC.map(function (fn) {
return fn();
}));
- }) // close the channel
+ })
+ // close the channel
.then(function () {
return _this.method.close(_this._state);
});
},
-
get type() {
return this.method.type;
},
-
get isClosed() {
return this.closed;
}
-
};
+
/**
* Post a message over the channel
* @returns {Promise} that resolved when the message sending is done
*/
-
function _post(broadcastChannel, type, msg) {
var time = broadcastChannel.method.microSeconds();
var msgObj = {
@@ -195,25 +184,22 @@ function _post(broadcastChannel, type, msg) {
};
var awaitPrepare = broadcastChannel._prepP ? broadcastChannel._prepP : PROMISE_RESOLVED_VOID;
return awaitPrepare.then(function () {
- var sendPromise = broadcastChannel.method.postMessage(broadcastChannel._state, msgObj); // add/remove to unsend messages list
+ var sendPromise = broadcastChannel.method.postMessage(broadcastChannel._state, msgObj);
+ // add/remove to unsend messages list
broadcastChannel._uMP.add(sendPromise);
-
sendPromise["catch"]().then(function () {
return broadcastChannel._uMP["delete"](sendPromise);
});
return sendPromise;
});
}
-
function _prepareChannel(channel) {
var maybePromise = channel.method.create(channel.name, channel.options);
-
if (isPromise(maybePromise)) {
channel._prepP = maybePromise;
maybePromise.then(function (s) {
// used in tests to simulate slow runtime
-
/*if (channel.options.prepareDelay) {
await new Promise(res => setTimeout(res, this.options.prepareDelay));
}*/
@@ -223,30 +209,25 @@ function _prepareChannel(channel) {
channel._state = maybePromise;
}
}
-
function _hasMessageListeners(channel) {
if (channel._addEL.message.length > 0) return true;
if (channel._addEL.internal.length > 0) return true;
return false;
}
-
function _addListenerObject(channel, type, obj) {
channel._addEL[type].push(obj);
-
_startListening(channel);
}
-
function _removeListenerObject(channel, type, obj) {
channel._addEL[type] = channel._addEL[type].filter(function (o) {
return o !== obj;
});
-
_stopListening(channel);
}
-
function _startListening(channel) {
if (!channel._iL && _hasMessageListeners(channel)) {
// someone is listening, start subscribing
+
var listenerFn = function listenerFn(msgObj) {
channel._addEL[msgObj.type].forEach(function (listenerObject) {
/**
@@ -260,15 +241,12 @@ function _startListening(channel) {
*/
var hundredMsInMicro = 100 * 1000;
var minMessageTime = listenerObject.time - hundredMsInMicro;
-
if (msgObj.time >= minMessageTime) {
listenerObject.fn(msgObj.data);
}
});
};
-
var time = channel.method.microSeconds();
-
if (channel._prepP) {
channel._prepP.then(function () {
channel._iL = true;
@@ -280,7 +258,6 @@ function _startListening(channel) {
}
}
}
-
function _stopListening(channel) {
if (channel._iL && !_hasMessageListeners(channel)) {
// noone is listening, stop subscribing
diff --git a/dist/esnode/browserify.index.js b/dist/esnode/browserify.index.js
index e500d3df..bd935158 100644
--- a/dist/esnode/browserify.index.js
+++ b/dist/esnode/browserify.index.js
@@ -1,5 +1,4 @@
var module = require('./index.es5.js');
-
var BroadcastChannel = module.BroadcastChannel;
var createLeaderElection = module.createLeaderElection;
window['BroadcastChannel2'] = BroadcastChannel;
diff --git a/dist/esnode/index.es5.js b/dist/esnode/index.es5.js
index 4d6b827b..60f0b76e 100644
--- a/dist/esnode/index.es5.js
+++ b/dist/esnode/index.es5.js
@@ -6,6 +6,7 @@
* but
* var BroadcastChannel = require('broadcast-channel');
*/
+
import { BroadcastChannel, createLeaderElection, clearNodeFolder, enforceOptions, beLeader } from './index.js';
module.exports = {
BroadcastChannel: BroadcastChannel,
diff --git a/dist/esnode/leader-election.js b/dist/esnode/leader-election.js
index c8c9cbb4..3b2c615c 100644
--- a/dist/esnode/leader-election.js
+++ b/dist/esnode/leader-election.js
@@ -1,32 +1,27 @@
import { sleep, randomToken, PROMISE_RESOLVED_VOID, PROMISE_RESOLVED_TRUE } from './util.js';
import { add as unloadAdd } from 'unload';
-
var LeaderElection = function LeaderElection(broadcastChannel, options) {
var _this = this;
-
this.broadcastChannel = broadcastChannel;
this._options = options;
this.isLeader = false;
this.hasLeader = false;
this.isDead = false;
this.token = randomToken();
+
/**
* Apply Queue,
* used to ensure we do not run applyOnce()
* in parallel.
*/
+ this._aplQ = PROMISE_RESOLVED_VOID;
+ // amount of unfinished applyOnce() calls
+ this._aplQC = 0;
- this._aplQ = PROMISE_RESOLVED_VOID; // amount of unfinished applyOnce() calls
-
- this._aplQC = 0; // things to clean up
-
+ // things to clean up
this._unl = []; // _unloads
-
this._lstns = []; // _listeners
-
this._dpL = function () {}; // onduplicate listener
-
-
this._dpLC = false; // true when onduplicate called
/**
@@ -34,55 +29,47 @@ var LeaderElection = function LeaderElection(broadcastChannel, options) {
* we still listen to messages to ensure the hasLeader flag
* is set correctly.
*/
-
var hasLeaderListener = function hasLeaderListener(msg) {
if (msg.context === 'leader') {
if (msg.action === 'death') {
_this.hasLeader = false;
}
-
if (msg.action === 'tell') {
_this.hasLeader = true;
}
}
};
-
this.broadcastChannel.addEventListener('internal', hasLeaderListener);
-
this._lstns.push(hasLeaderListener);
};
-
LeaderElection.prototype = {
/**
* Returns true if the instance is leader,
* false if not.
* @async
*/
- applyOnce: function applyOnce( // true if the applyOnce() call came from the fallbackInterval cycle
+ applyOnce: function applyOnce(
+ // true if the applyOnce() call came from the fallbackInterval cycle
isFromFallbackInterval) {
var _this2 = this;
-
if (this.isLeader) {
return sleep(0, true);
}
-
if (this.isDead) {
return sleep(0, false);
}
+
/**
* Already applying more then once,
* -> wait for the apply queue to be finished.
*/
-
-
if (this._aplQC > 1) {
return this._aplQ;
}
+
/**
* Add a new apply-run
*/
-
-
var applyRun = function applyRun() {
/**
* Optimization shortcuts.
@@ -92,7 +79,6 @@ LeaderElection.prototype = {
if (_this2.isLeader) {
return PROMISE_RESOLVED_TRUE;
}
-
var stopCriteria = false;
var stopCriteriaPromiseResolve;
/**
@@ -101,7 +87,6 @@ LeaderElection.prototype = {
* have to await the responseTime when it is already clear
* that the election failed.
*/
-
var stopCriteriaPromise = new Promise(function (res) {
stopCriteriaPromiseResolve = function stopCriteriaPromiseResolve() {
stopCriteria = true;
@@ -109,11 +94,9 @@ LeaderElection.prototype = {
};
});
var recieved = [];
-
var handleMessage = function handleMessage(msg) {
if (msg.context === 'leader' && msg.token != _this2.token) {
recieved.push(msg);
-
if (msg.action === 'apply') {
// other is applying
if (msg.token > _this2.token) {
@@ -124,7 +107,6 @@ LeaderElection.prototype = {
stopCriteriaPromiseResolve();
}
}
-
if (msg.action === 'tell') {
// other is already leader
stopCriteriaPromiseResolve();
@@ -132,8 +114,8 @@ LeaderElection.prototype = {
}
}
};
-
_this2.broadcastChannel.addEventListener('internal', handleMessage);
+
/**
* If the applyOnce() call came from the fallbackInterval,
* we can assume that the election runs in the background and
@@ -144,26 +126,24 @@ LeaderElection.prototype = {
* But also it takes longer which is not a problem because we anyway
* run in the background.
*/
-
-
var waitForAnswerTime = isFromFallbackInterval ? _this2._options.responseTime * 4 : _this2._options.responseTime;
-
var applyPromise = _sendMessage(_this2, 'apply') // send out that this one is applying
.then(function () {
return Promise.race([sleep(waitForAnswerTime), stopCriteriaPromise.then(function () {
return Promise.reject(new Error());
})]);
- }) // send again in case another instance was just created
+ })
+ // send again in case another instance was just created
.then(function () {
return _sendMessage(_this2, 'apply');
- }) // let others time to respond
+ })
+ // let others time to respond
.then(function () {
return Promise.race([sleep(waitForAnswerTime), stopCriteriaPromise.then(function () {
return Promise.reject(new Error());
})]);
})["catch"](function () {}).then(function () {
_this2.broadcastChannel.removeEventListener('internal', handleMessage);
-
if (!stopCriteria) {
// no stop criteria -> own is leader
return beLeader(_this2).then(function () {
@@ -174,10 +154,8 @@ LeaderElection.prototype = {
return false;
}
});
-
return applyPromise;
};
-
this._aplQC = this._aplQC + 1;
this._aplQ = this._aplQ.then(function () {
return applyRun();
@@ -189,82 +167,68 @@ LeaderElection.prototype = {
});
},
awaitLeadership: function awaitLeadership() {
- if (
- /* _awaitLeadershipPromise */
+ if ( /* _awaitLeadershipPromise */
!this._aLP) {
this._aLP = _awaitLeadershipOnce(this);
}
-
return this._aLP;
},
-
set onduplicate(fn) {
this._dpL = fn;
},
-
die: function die() {
var _this3 = this;
-
this._lstns.forEach(function (listener) {
return _this3.broadcastChannel.removeEventListener('internal', listener);
});
-
this._lstns = [];
-
this._unl.forEach(function (uFn) {
return uFn.remove();
});
-
this._unl = [];
-
if (this.isLeader) {
this.hasLeader = false;
this.isLeader = false;
}
-
this.isDead = true;
return _sendMessage(this, 'death');
}
};
+
/**
* @param leaderElector {LeaderElector}
*/
-
function _awaitLeadershipOnce(leaderElector) {
if (leaderElector.isLeader) {
return PROMISE_RESOLVED_VOID;
}
-
return new Promise(function (res) {
var resolved = false;
-
function finish() {
if (resolved) {
return;
}
-
resolved = true;
leaderElector.broadcastChannel.removeEventListener('internal', whenDeathListener);
res(true);
- } // try once now
-
+ }
+ // try once now
leaderElector.applyOnce().then(function () {
if (leaderElector.isLeader) {
finish();
}
});
+
/**
* Try on fallbackInterval
* @recursive
*/
-
var tryOnFallBack = function tryOnFallBack() {
return sleep(leaderElector._options.fallbackInterval).then(function () {
if (leaderElector.isDead || resolved) {
return;
}
-
if (leaderElector.isLeader) {
finish();
} else {
@@ -278,9 +242,9 @@ function _awaitLeadershipOnce(leaderElector) {
}
});
};
+ tryOnFallBack();
- tryOnFallBack(); // try when other leader dies
-
+ // try when other leader dies
var whenDeathListener = function whenDeathListener(msg) {
if (msg.context === 'leader' && msg.action === 'death') {
leaderElector.hasLeader = false;
@@ -291,17 +255,14 @@ function _awaitLeadershipOnce(leaderElector) {
});
}
};
-
leaderElector.broadcastChannel.addEventListener('internal', whenDeathListener);
-
leaderElector._lstns.push(whenDeathListener);
});
}
+
/**
* sends and internal message over the broadcast-channel
*/
-
-
function _sendMessage(leaderElector, action) {
var msgJson = {
context: 'leader',
@@ -310,21 +271,17 @@ function _sendMessage(leaderElector, action) {
};
return leaderElector.broadcastChannel.postInternal(msgJson);
}
-
export function beLeader(leaderElector) {
leaderElector.isLeader = true;
leaderElector.hasLeader = true;
var unloadFn = unloadAdd(function () {
return leaderElector.die();
});
-
leaderElector._unl.push(unloadFn);
-
var isLeaderListener = function isLeaderListener(msg) {
if (msg.context === 'leader' && msg.action === 'apply') {
_sendMessage(leaderElector, 'tell');
}
-
if (msg.context === 'leader' && msg.action === 'tell' && !leaderElector._dpLC) {
/**
* another instance is also leader!
@@ -335,49 +292,35 @@ export function beLeader(leaderElector) {
* @link https://github.com/pubkey/broadcast-channel/issues/385
*/
leaderElector._dpLC = true;
-
leaderElector._dpL(); // message the lib user so the app can handle the problem
-
-
_sendMessage(leaderElector, 'tell'); // ensure other leader also knows the problem
-
}
};
leaderElector.broadcastChannel.addEventListener('internal', isLeaderListener);
-
leaderElector._lstns.push(isLeaderListener);
-
return _sendMessage(leaderElector, 'tell');
}
-
function fillOptionsWithDefaults(options, channel) {
if (!options) options = {};
options = JSON.parse(JSON.stringify(options));
-
if (!options.fallbackInterval) {
options.fallbackInterval = 3000;
}
-
if (!options.responseTime) {
options.responseTime = channel.method.averageResponseTime(channel.options);
}
-
return options;
}
-
export function createLeaderElection(channel, options) {
if (channel._leaderElector) {
throw new Error('BroadcastChannel already has a leader-elector');
}
-
options = fillOptionsWithDefaults(options, channel);
var elector = new LeaderElection(channel, options);
-
channel._befC.push(function () {
return elector.die();
});
-
channel._leaderElector = elector;
return elector;
}
\ No newline at end of file
diff --git a/dist/esnode/method-chooser.js b/dist/esnode/method-chooser.js
index cb4f81cd..aa522d66 100644
--- a/dist/esnode/method-chooser.js
+++ b/dist/esnode/method-chooser.js
@@ -1,40 +1,41 @@
import NativeMethod from './methods/native.js';
import IndexeDbMethod from './methods/indexed-db.js';
import LocalstorageMethod from './methods/localstorage.js';
-import SimulateMethod from './methods/simulate.js'; // the line below will be removed from es5/browser builds
+import SimulateMethod from './methods/simulate.js';
+// the line below will be removed from es5/browser builds
+import * as NodeMethod from './methods/node.js';
-import * as NodeMethod from './methods/node.js'; // order is important
-
-var METHODS = [NativeMethod, // fastest
+// order is important
+var METHODS = [NativeMethod,
+// fastest
IndexeDbMethod, LocalstorageMethod];
export function chooseMethod(options) {
- var chooseMethods = [].concat(options.methods, METHODS).filter(Boolean); // the line below will be removed from es5/browser builds
+ var chooseMethods = [].concat(options.methods, METHODS).filter(Boolean);
- chooseMethods.push(NodeMethod); // directly chosen
+ // the line below will be removed from es5/browser builds
+ chooseMethods.push(NodeMethod);
+ // directly chosen
if (options.type) {
if (options.type === 'simulate') {
// only use simulate-method if directly chosen
return SimulateMethod;
}
-
var ret = chooseMethods.find(function (m) {
return m.type === options.type;
});
if (!ret) throw new Error('method-type ' + options.type + ' not found');else return ret;
}
+
/**
* if no webworker support is needed,
* remove idb from the list so that localstorage is been chosen
*/
-
-
if (!options.webWorkerSupport) {
chooseMethods = chooseMethods.filter(function (m) {
return m.type !== 'idb';
});
}
-
var useMethod = chooseMethods.find(function (method) {
return method.canBeUsed();
});
diff --git a/dist/esnode/methods/indexed-db.js b/dist/esnode/methods/indexed-db.js
index 75f983c0..24727d1a 100644
--- a/dist/esnode/methods/indexed-db.js
+++ b/dist/esnode/methods/indexed-db.js
@@ -6,55 +6,54 @@
* When working on this, ensure to use these performance optimizations:
* @link https://rxdb.info/slow-indexeddb.html
*/
+
import { sleep, randomInt, randomToken, microSeconds as micro, PROMISE_RESOLVED_VOID } from '../util.js';
export var microSeconds = micro;
import { ObliviousSet } from 'oblivious-set';
import { fillOptionsWithDefaults } from '../options.js';
var DB_PREFIX = 'pubkey.broadcast-channel-0-';
var OBJECT_STORE_ID = 'messages';
+
/**
* Use relaxed durability for faster performance on all transactions.
* @link https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/
*/
-
export var TRANSACTION_SETTINGS = {
durability: 'relaxed'
};
export var type = 'idb';
export function getIdb() {
if (typeof indexedDB !== 'undefined') return indexedDB;
-
if (typeof window !== 'undefined') {
if (typeof window.mozIndexedDB !== 'undefined') return window.mozIndexedDB;
if (typeof window.webkitIndexedDB !== 'undefined') return window.webkitIndexedDB;
if (typeof window.msIndexedDB !== 'undefined') return window.msIndexedDB;
}
-
return false;
}
+
/**
* If possible, we should explicitly commit IndexedDB transactions
* for better performance.
* @link https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/
*/
-
export function commitIndexedDBTransaction(tx) {
if (tx.commit) {
tx.commit();
}
}
export function createDatabase(channelName) {
- var IndexedDB = getIdb(); // create table
+ var IndexedDB = getIdb();
+ // create table
var dbName = DB_PREFIX + channelName;
+
/**
* All IndexedDB databases are opened without version
* because it is a bit faster, especially on firefox
* @link http://nparashuram.com/IndexedDB/perf/#Open%20Database%20with%20version
*/
-
var openRequest = IndexedDB.open(dbName);
-
openRequest.onupgradeneeded = function (ev) {
var db = ev.target.result;
db.createObjectStore(OBJECT_STORE_ID, {
@@ -62,23 +61,21 @@ export function createDatabase(channelName) {
autoIncrement: true
});
};
-
var dbPromise = new Promise(function (res, rej) {
openRequest.onerror = function (ev) {
return rej(ev);
};
-
openRequest.onsuccess = function () {
res(openRequest.result);
};
});
return dbPromise;
}
+
/**
* writes the new message to the database
* so other readers can find it
*/
-
export function writeMessage(db, readerUuid, messageJson) {
var time = new Date().getTime();
var writeObject = {
@@ -91,11 +88,9 @@ export function writeMessage(db, readerUuid, messageJson) {
tx.oncomplete = function () {
return res();
};
-
tx.onerror = function (ev) {
return rej(ev);
};
-
var objectStore = tx.objectStore(OBJECT_STORE_ID);
objectStore.add(writeObject);
commitIndexedDBTransaction(tx);
@@ -108,10 +103,9 @@ export function getAllMessages(db) {
return new Promise(function (res) {
objectStore.openCursor().onsuccess = function (ev) {
var cursor = ev.target.result;
-
if (cursor) {
- ret.push(cursor.value); //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
-
+ ret.push(cursor.value);
+ //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor["continue"]();
} else {
commitIndexedDBTransaction(tx);
@@ -125,25 +119,23 @@ export function getMessagesHigherThan(db, lastCursorId) {
var objectStore = tx.objectStore(OBJECT_STORE_ID);
var ret = [];
var keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity);
+
/**
* Optimization shortcut,
* if getAll() can be used, do not use a cursor.
* @link https://rxdb.info/slow-indexeddb.html
*/
-
if (objectStore.getAll) {
var getAllRequest = objectStore.getAll(keyRangeValue);
return new Promise(function (res, rej) {
getAllRequest.onerror = function (err) {
return rej(err);
};
-
getAllRequest.onsuccess = function (e) {
res(e.target.result);
};
});
}
-
function openCursor() {
// Occasionally Safari will fail on IDBKeyRange.bound, this
// catches that error, having it open the cursor to the first
@@ -155,17 +147,13 @@ export function getMessagesHigherThan(db, lastCursorId) {
return objectStore.openCursor();
}
}
-
return new Promise(function (res, rej) {
var openCursorRequest = openCursor();
-
openCursorRequest.onerror = function (err) {
return rej(err);
};
-
openCursorRequest.onsuccess = function (ev) {
var cursor = ev.target.result;
-
if (cursor) {
if (cursor.value.id < lastCursorId + 1) {
cursor["continue"](lastCursorId + 1);
@@ -184,7 +172,6 @@ export function removeMessagesById(channelState, ids) {
if (channelState.closed) {
return Promise.resolve([]);
}
-
var tx = channelState.db.transaction(OBJECT_STORE_ID, 'readwrite', TRANSACTION_SETTINGS);
var objectStore = tx.objectStore(OBJECT_STORE_ID);
return Promise.all(ids.map(function (id) {
@@ -204,13 +191,11 @@ export function getOldMessages(db, ttl) {
return new Promise(function (res) {
objectStore.openCursor().onsuccess = function (ev) {
var cursor = ev.target.result;
-
if (cursor) {
var msgObk = cursor.value;
-
if (msgObk.time < olderThen) {
- ret.push(msgObk); //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
-
+ ret.push(msgObk);
+ //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor["continue"]();
} else {
// no more old messages,
@@ -240,7 +225,6 @@ export function create(channelName, options) {
channelName: channelName,
options: options,
uuid: randomToken(),
-
/**
* emittedMessagesIds
* contains all messages that have been emitted before
@@ -253,30 +237,27 @@ export function create(channelName, options) {
readQueuePromises: [],
db: db
};
+
/**
* Handle abrupt closes that do not originate from db.close().
* This could happen, for example, if the underlying storage is
* removed or if the user clears the database in the browser's
* history preferences.
*/
-
db.onclose = function () {
state.closed = true;
if (options.idb.onclose) options.idb.onclose();
};
+
/**
* if service-workers are used,
* we have no 'storage'-event if they post a message,
* therefore we also have to set an interval
*/
-
-
_readLoop(state);
-
return state;
});
}
-
function _readLoop(state) {
if (state.closed) return;
readNewMessages(state).then(function () {
@@ -285,25 +266,21 @@ function _readLoop(state) {
return _readLoop(state);
});
}
-
function _filterMessage(msgObj, state) {
if (msgObj.uuid === state.uuid) return false; // send by own
-
if (state.eMIs.has(msgObj.id)) return false; // already emitted
-
if (msgObj.data.time < state.messagesCallbackTime) return false; // older then onMessageCallback
-
return true;
}
+
/**
* reads all new messages from the database and emits them
*/
-
-
function readNewMessages(state) {
// channel already closed
- if (state.closed) return PROMISE_RESOLVED_VOID; // if no one is listening, we do not need to scan for new messages
+ if (state.closed) return PROMISE_RESOLVED_VOID;
+ // if no one is listening, we do not need to scan for new messages
if (!state.messagesCallback) return PROMISE_RESOLVED_VOID;
return getMessagesHigherThan(state.db, state.lastCursorId).then(function (newerMessages) {
var useMessages = newerMessages
@@ -311,21 +288,18 @@ function readNewMessages(state) {
* there is a bug in iOS where the msgObj can be undefined some times
* so we filter them out
* @link https://github.com/pubkey/broadcast-channel/issues/19
- */
- .filter(function (msgObj) {
+ */.filter(function (msgObj) {
return !!msgObj;
}).map(function (msgObj) {
if (msgObj.id > state.lastCursorId) {
state.lastCursorId = msgObj.id;
}
-
return msgObj;
}).filter(function (msgObj) {
return _filterMessage(msgObj, state);
}).sort(function (msgObjA, msgObjB) {
return msgObjA.time - msgObjB.time;
}); // sort by time
-
useMessages.forEach(function (msgObj) {
if (state.messagesCallback) {
state.eMIs.add(msgObj.id);
@@ -335,7 +309,6 @@ function readNewMessages(state) {
return PROMISE_RESOLVED_VOID;
});
}
-
export function close(channelState) {
channelState.closed = true;
channelState.db.close();
@@ -358,11 +331,9 @@ export function onMessage(channelState, fn, time) {
}
export function canBeUsed() {
var idb = getIdb();
-
if (!idb) {
return false;
}
-
return true;
}
export function averageResponseTime(options) {
diff --git a/dist/esnode/methods/localstorage.js b/dist/esnode/methods/localstorage.js
index 5a4adcc6..a0bb80e5 100644
--- a/dist/esnode/methods/localstorage.js
+++ b/dist/esnode/methods/localstorage.js
@@ -5,39 +5,39 @@
* @link https://caniuse.com/#feat=namevalue-storage
* @link https://caniuse.com/#feat=indexeddb
*/
+
import { ObliviousSet } from 'oblivious-set';
import { fillOptionsWithDefaults } from '../options.js';
import { sleep, randomToken, microSeconds as micro } from '../util.js';
export var microSeconds = micro;
var KEY_PREFIX = 'pubkey.broadcastChannel-';
export var type = 'localstorage';
+
/**
* copied from crosstab
* @link https://github.com/tejacques/crosstab/blob/master/src/crosstab.js#L32
*/
-
export function getLocalStorage() {
var localStorage;
if (typeof window === 'undefined') return null;
-
try {
localStorage = window.localStorage;
localStorage = window['ie8-eventlistener/storage'] || window.localStorage;
- } catch (e) {// New versions of Firefox throw a Security exception
+ } catch (e) {
+ // New versions of Firefox throw a Security exception
// if cookies are disabled. See
// https://bugzilla.mozilla.org/show_bug.cgi?id=1028153
}
-
return localStorage;
}
export function storageKey(channelName) {
return KEY_PREFIX + channelName;
}
+
/**
* writes the new message to the storage
* and fires the storage-event so other readers can find it
*/
-
export function postMessage(channelState, messageJson) {
return new Promise(function (res) {
sleep().then(function () {
@@ -50,12 +50,12 @@ export function postMessage(channelState, messageJson) {
};
var value = JSON.stringify(writeObj);
getLocalStorage().setItem(key, value);
+
/**
* StorageEvent does not fire the 'storage' event
* in the window that changes the state of the local storage.
* So we fire it manually
*/
-
var ev = document.createEvent('Event');
ev.initEvent('storage', true, true);
ev.key = key;
@@ -67,13 +67,11 @@ export function postMessage(channelState, messageJson) {
}
export function addStorageEventListener(channelName, fn) {
var key = storageKey(channelName);
-
var listener = function listener(ev) {
if (ev.key === key) {
fn(JSON.parse(ev.newValue));
}
};
-
window.addEventListener('storage', listener);
return listener;
}
@@ -82,32 +80,27 @@ export function removeStorageEventListener(listener) {
}
export function create(channelName, options) {
options = fillOptionsWithDefaults(options);
-
if (!canBeUsed()) {
throw new Error('BroadcastChannel: localstorage cannot be used');
}
-
var uuid = randomToken();
+
/**
* eMIs
* contains all messages that have been emitted before
* @type {ObliviousSet}
*/
-
var eMIs = new ObliviousSet(options.localstorage.removeTimeout);
var state = {
channelName: channelName,
uuid: uuid,
eMIs: eMIs // emittedMessagesIds
-
};
+
state.listener = addStorageEventListener(channelName, function (msgObj) {
if (!state.messagesCallback) return; // no listener
-
if (msgObj.uuid === uuid) return; // own message
-
if (!msgObj.token || eMIs.has(msgObj.token)) return; // already emitted
-
if (msgObj.data.time && msgObj.data.time < state.messagesCallbackTime) return; // too old
eMIs.add(msgObj.token);
@@ -125,7 +118,6 @@ export function onMessage(channelState, fn, time) {
export function canBeUsed() {
var ls = getLocalStorage();
if (!ls) return false;
-
try {
var key = '__broadcastchannel_check';
ls.setItem(key, 'works');
@@ -136,18 +128,15 @@ export function canBeUsed() {
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API#Private_Browsing_Incognito_modes
return false;
}
-
return true;
}
export function averageResponseTime() {
var defaultTime = 120;
var userAgent = navigator.userAgent.toLowerCase();
-
if (userAgent.includes('safari') && !userAgent.includes('chrome')) {
// safari is much slower so this time is higher
return defaultTime * 2;
}
-
return defaultTime;
}
export default {
diff --git a/dist/esnode/methods/native.js b/dist/esnode/methods/native.js
index 6841c45b..6e45b272 100644
--- a/dist/esnode/methods/native.js
+++ b/dist/esnode/methods/native.js
@@ -6,7 +6,6 @@ export function create(channelName) {
messagesCallback: null,
bc: new BroadcastChannel(channelName),
subFns: [] // subscriberFunctions
-
};
state.bc.onmessage = function (msg) {
@@ -14,7 +13,6 @@ export function create(channelName) {
state.messagesCallback(msg.data);
}
};
-
return state;
}
export function close(channelState) {
@@ -36,12 +34,10 @@ export function canBeUsed() {
if (typeof window === 'undefined') {
return false;
}
-
if (typeof BroadcastChannel === 'function') {
if (BroadcastChannel._pubkey) {
throw new Error('BroadcastChannel: Do not overwrite window.BroadcastChannel with this module, this is not a polyfill');
}
-
return true;
} else {
return false;
diff --git a/dist/esnode/methods/node.js b/dist/esnode/methods/node.js
index 5b30135d..0f823fad 100644
--- a/dist/esnode/methods/node.js
+++ b/dist/esnode/methods/node.js
@@ -1,10 +1,10 @@
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
import _regeneratorRuntime from "@babel/runtime/regenerator";
-
/**
* this method is used in nodejs-environments.
* The ipc is handled via sockets and file-writes to the tmp-folder
*/
+
import util from 'util';
import fs from 'fs';
import crypto from 'crypto';
@@ -18,11 +18,11 @@ import { add as unloadAdd } from 'unload';
import { fillOptionsWithDefaults } from '../options.js';
import { randomInt, randomToken, PROMISE_RESOLVED_VOID } from '../util.js';
import { ObliviousSet } from 'oblivious-set';
+
/**
* windows sucks, so we have handle windows-type of socket-paths
* @link https://gist.github.com/domenic/2790533#gistcomment-331356
*/
-
export function cleanPipeName(str) {
if (process.platform === 'win32' && !str.startsWith('\\\\.\\pipe\\')) {
str = str.replace(/^\//, '');
@@ -52,12 +52,12 @@ export function getPaths(channelName) {
* in using the same folders for different channels.
*/
var channelHash = crypto.createHash('sha256').update(channelName).digest('hex');
+
/**
* because the length of socket-paths is limited, we use only the first 20 chars
* and also start with A to ensure we do not start with a number
* @link https://serverfault.com/questions/641347/check-if-a-path-exceeds-maximum-for-unix-domain-socket
*/
-
var channelFolder = 'A' + channelHash.substring(0, 20);
var channelPathBase = path.join(TMP_FOLDER_BASE, channelFolder);
var folderPathReaders = path.join(channelPathBase, 'rdrs');
@@ -70,15 +70,12 @@ export function getPaths(channelName) {
getPathsCache.set(channelName, ret);
return ret;
}
-
return getPathsCache.get(channelName);
}
var ENSURE_BASE_FOLDER_EXISTS_PROMISE = null;
-
function ensureBaseFolderExists() {
return _ensureBaseFolderExists.apply(this, arguments);
}
-
function _ensureBaseFolderExists() {
_ensureBaseFolderExists = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
return _regeneratorRuntime.wrap(function _callee3$(_context3) {
@@ -90,9 +87,7 @@ function _ensureBaseFolderExists() {
return null;
});
}
-
return _context3.abrupt("return", ENSURE_BASE_FOLDER_EXISTS_PROMISE);
-
case 2:
case "end":
return _context3.stop();
@@ -102,15 +97,14 @@ function _ensureBaseFolderExists() {
}));
return _ensureBaseFolderExists.apply(this, arguments);
}
-
export function ensureFoldersExist(_x, _x2) {
return _ensureFoldersExist.apply(this, arguments);
}
+
/**
* removes the tmp-folder
* @return {Promise}
*/
-
function _ensureFoldersExist() {
_ensureFoldersExist = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4(channelName, paths) {
var chmodValue;
@@ -121,13 +115,11 @@ function _ensureFoldersExist() {
paths = paths || getPaths(channelName);
_context4.next = 3;
return ensureBaseFolderExists();
-
case 3:
_context4.next = 5;
return mkdir(paths.channelBase)["catch"](function () {
return null;
});
-
case 5:
_context4.next = 7;
return Promise.all([mkdir(paths.readers)["catch"](function () {
@@ -135,7 +127,6 @@ function _ensureFoldersExist() {
}), mkdir(paths.messages)["catch"](function () {
return null;
})]);
-
case 7:
// set permissions so other users can use the same channel
chmodValue = '777';
@@ -143,7 +134,6 @@ function _ensureFoldersExist() {
return Promise.all([chmod(paths.channelBase, chmodValue), chmod(paths.readers, chmodValue), chmod(paths.messages, chmodValue)])["catch"](function () {
return null;
});
-
case 10:
case "end":
return _context4.stop();
@@ -153,11 +143,9 @@ function _ensureFoldersExist() {
}));
return _ensureFoldersExist.apply(this, arguments);
}
-
export function clearNodeFolder() {
return _clearNodeFolder.apply(this, arguments);
}
-
function _clearNodeFolder() {
_clearNodeFolder = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee5() {
return _regeneratorRuntime.wrap(function _callee5$(_context5) {
@@ -168,18 +156,14 @@ function _clearNodeFolder() {
_context5.next = 2;
break;
}
-
throw new Error('BroadcastChannel.clearNodeFolder(): path is wrong');
-
case 2:
ENSURE_BASE_FOLDER_EXISTS_PROMISE = null;
_context5.next = 5;
return removeDir(TMP_FOLDER_BASE);
-
case 5:
ENSURE_BASE_FOLDER_EXISTS_PROMISE = null;
return _context5.abrupt("return", true);
-
case 7:
case "end":
return _context5.stop();
@@ -189,7 +173,6 @@ function _clearNodeFolder() {
}));
return _clearNodeFolder.apply(this, arguments);
}
-
export function socketPath(channelName, readerUuid, paths) {
paths = paths || getPaths(channelName);
var socketPath = path.join(paths.readers, readerUuid + '.s');
@@ -200,12 +183,12 @@ export function socketInfoPath(channelName, readerUuid, paths) {
var socketPath = path.join(paths.readers, readerUuid + '.json');
return socketPath;
}
+
/**
* Because it is not possible to get all socket-files in a folder,
* when used under fucking windows,
* we have to set a normal file so other readers know our socket exists
*/
-
export function createSocketInfoFile(channelName, readerUuid, paths) {
var pathToFile = socketInfoPath(channelName, readerUuid, paths);
return writeFile(pathToFile, JSON.stringify({
@@ -214,15 +197,14 @@ export function createSocketInfoFile(channelName, readerUuid, paths) {
return pathToFile;
});
}
+
/**
* returns the amount of channel-folders in the tmp-directory
* @return {Promise}
*/
-
export function countChannelFolders() {
return _countChannelFolders.apply(this, arguments);
}
-
function _countChannelFolders() {
_countChannelFolders = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee6() {
var folders;
@@ -232,15 +214,12 @@ function _countChannelFolders() {
case 0:
_context6.next = 2;
return ensureBaseFolderExists();
-
case 2:
_context6.next = 4;
return readdir(TMP_FOLDER_BASE);
-
case 4:
folders = _context6.sent;
return _context6.abrupt("return", folders.length);
-
case 6:
case "end":
return _context6.stop();
@@ -250,7 +229,6 @@ function _countChannelFolders() {
}));
return _countChannelFolders.apply(this, arguments);
}
-
function connectionError(_x3) {
return _connectionError.apply(this, arguments);
}
@@ -258,8 +236,6 @@ function connectionError(_x3) {
* creates the socket-file and subscribes to it
* @return {{emitter: EventEmitter, server: any}}
*/
-
-
function _connectionError() {
_connectionError = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee7(originalError) {
var count, addObj, text, newError;
@@ -269,28 +245,23 @@ function _connectionError() {
case 0:
_context7.next = 2;
return countChannelFolders();
-
case 2:
count = _context7.sent;
-
if (!(count < 30)) {
_context7.next = 5;
break;
}
-
return _context7.abrupt("return", originalError);
-
case 5:
addObj = {};
Object.entries(originalError).forEach(function (_ref3) {
var k = _ref3[0],
- v = _ref3[1];
+ v = _ref3[1];
return addObj[k] = v;
});
text = 'BroadcastChannel.create(): error: ' + 'This might happen if you have created to many channels, ' + 'like when you use BroadcastChannel in unit-tests.' + 'Try using BroadcastChannel.clearNodeFolder() to clear the tmp-folder before each test.' + 'See https://github.com/pubkey/broadcast-channel#clear-tmp-folder';
newError = new Error(text + ': ' + JSON.stringify(addObj, null, 2));
return _context7.abrupt("return", newError);
-
case 10:
case "end":
return _context7.stop();
@@ -300,11 +271,9 @@ function _connectionError() {
}));
return _connectionError.apply(this, arguments);
}
-
export function createSocketEventEmitter(_x4, _x5, _x6) {
return _createSocketEventEmitter.apply(this, arguments);
}
-
function _createSocketEventEmitter() {
_createSocketEventEmitter = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee10(channelName, readerUuid, paths) {
var pathToSocket, emitter, server;
@@ -331,11 +300,9 @@ function _createSocketEventEmitter() {
case 0:
_context8.next = 2;
return connectionError(err);
-
case 2:
useErr = _context8.sent;
reject(useErr);
-
case 4:
case "end":
return _context8.stop();
@@ -343,7 +310,6 @@ function _createSocketEventEmitter() {
}
}, _callee8);
}));
-
return function (_x26) {
return _ref4.apply(this, arguments);
};
@@ -359,19 +325,15 @@ function _createSocketEventEmitter() {
_context9.next = 7;
break;
}
-
_context9.next = 3;
return connectionError(err);
-
case 3:
useErr = _context9.sent;
reject(useErr);
_context9.next = 8;
break;
-
case 7:
resolve(res);
-
case 8:
case "end":
return _context9.stop();
@@ -379,20 +341,17 @@ function _createSocketEventEmitter() {
}
}, _callee9);
}));
-
return function (_x27, _x28) {
return _ref5.apply(this, arguments);
};
}());
});
-
case 5:
return _context10.abrupt("return", {
path: pathToSocket,
emitter: emitter,
server: server
});
-
case 6:
case "end":
return _context10.stop();
@@ -402,16 +361,15 @@ function _createSocketEventEmitter() {
}));
return _createSocketEventEmitter.apply(this, arguments);
}
-
export function openClientConnection(_x7, _x8) {
return _openClientConnection.apply(this, arguments);
}
+
/**
* writes the new message to the file-system
* so other readers can find it
* @return {Promise}
*/
-
function _openClientConnection() {
_openClientConnection = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee11(channelName, readerUuid) {
var pathToSocket, client;
@@ -429,7 +387,6 @@ function _openClientConnection() {
return rej(err);
});
}));
-
case 3:
case "end":
return _context11.stop();
@@ -439,7 +396,6 @@ function _openClientConnection() {
}));
return _openClientConnection.apply(this, arguments);
}
-
export function writeMessage(channelName, readerUuid, messageJson, paths) {
paths = paths || getPaths(channelName);
var time = microSeconds();
@@ -460,15 +416,14 @@ export function writeMessage(channelName, readerUuid, messageJson, paths) {
};
});
}
+
/**
* returns the uuids of all readers
* @return {string[]}
*/
-
export function getReadersUuids(_x9, _x10) {
return _getReadersUuids.apply(this, arguments);
}
-
function _getReadersUuids() {
_getReadersUuids = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee12(channelName, paths) {
var readersPath, files;
@@ -480,7 +435,6 @@ function _getReadersUuids() {
readersPath = paths.readers;
_context12.next = 4;
return readdir(readersPath);
-
case 4:
files = _context12.sent;
return _context12.abrupt("return", files.map(function (file) {
@@ -491,7 +445,6 @@ function _getReadersUuids() {
.map(function (split) {
return split[0];
}));
-
case 6:
case "end":
return _context12.stop();
@@ -501,11 +454,9 @@ function _getReadersUuids() {
}));
return _getReadersUuids.apply(this, arguments);
}
-
export function messagePath(_x11, _x12, _x13, _x14) {
return _messagePath.apply(this, arguments);
}
-
function _messagePath() {
_messagePath = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee13(channelName, time, token, writerUuid) {
var fileName, msgPath;
@@ -516,7 +467,6 @@ function _messagePath() {
fileName = time + '_' + writerUuid + '_' + token + '.json';
msgPath = path.join(getPaths(channelName).messages, fileName);
return _context13.abrupt("return", msgPath);
-
case 3:
case "end":
return _context13.stop();
@@ -526,11 +476,9 @@ function _messagePath() {
}));
return _messagePath.apply(this, arguments);
}
-
export function getAllMessages(_x15, _x16) {
return _getAllMessages.apply(this, arguments);
}
-
function _getAllMessages() {
_getAllMessages = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee14(channelName, paths) {
var messagesPath, files;
@@ -542,7 +490,6 @@ function _getAllMessages() {
messagesPath = paths.messages;
_context14.next = 4;
return readdir(messagesPath);
-
case 4:
files = _context14.sent;
return _context14.abrupt("return", files.map(function (file) {
@@ -555,7 +502,6 @@ function _getAllMessages() {
token: split[2]
};
}));
-
case 6:
case "end":
return _context14.stop();
@@ -565,7 +511,6 @@ function _getAllMessages() {
}));
return _getAllMessages.apply(this, arguments);
}
-
export function getSingleMessage(channelName, msgObj, paths) {
paths = paths || getPaths(channelName);
return {
@@ -583,7 +528,6 @@ export function readMessage(messageObj) {
export function cleanOldMessages(_x17, _x18) {
return _cleanOldMessages.apply(this, arguments);
}
-
function _cleanOldMessages() {
_cleanOldMessages = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee15(messageObjects, ttl) {
var olderThen;
@@ -592,7 +536,6 @@ function _cleanOldMessages() {
switch (_context15.prev = _context15.next) {
case 0:
olderThen = microSeconds() - ttl * 1000; // convert ttl to microseconds
-
_context15.next = 3;
return Promise.all(messageObjects.filter(function (obj) {
return obj.time < olderThen;
@@ -601,7 +544,6 @@ function _cleanOldMessages() {
return null;
});
}));
-
case 3:
case "end":
return _context15.stop();
@@ -611,30 +553,27 @@ function _cleanOldMessages() {
}));
return _cleanOldMessages.apply(this, arguments);
}
-
export var type = 'node';
+
/**
* creates a new channelState
* @return {Promise}
*/
-
export function create(_x19) {
return _create.apply(this, arguments);
}
-
function _create() {
_create = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee16(channelName) {
var options,
- time,
- paths,
- ensureFolderExistsPromise,
- uuid,
- state,
- _yield$Promise$all,
- socketEE,
- infoFilePath,
- _args16 = arguments;
-
+ time,
+ paths,
+ ensureFolderExistsPromise,
+ uuid,
+ state,
+ _yield$Promise$all,
+ socketEE,
+ infoFilePath,
+ _args16 = arguments;
return _regeneratorRuntime.wrap(function _callee16$(_context16) {
while (1) {
switch (_context16.prev = _context16.next) {
@@ -653,7 +592,6 @@ function _create() {
paths: paths,
// contains all messages that have been emitted before
emittedMessagesIds: new ObliviousSet(options.node.ttl * 2),
-
/**
* Used to ensure we do not write too many files at once
* which could throw an error.
@@ -677,18 +615,17 @@ function _create() {
OTHER_INSTANCES[channelName].push(state);
_context16.next = 11;
return ensureFolderExistsPromise;
-
case 11:
_context16.next = 13;
return Promise.all([createSocketEventEmitter(channelName, uuid, paths), createSocketInfoFile(channelName, uuid, paths), refreshReaderClients(state)]);
-
case 13:
_yield$Promise$all = _context16.sent;
socketEE = _yield$Promise$all[0];
infoFilePath = _yield$Promise$all[1];
state.socketEE = socketEE;
- state.infoFilePath = infoFilePath; // when new message comes in, we read it and emit it
+ state.infoFilePath = infoFilePath;
+ // when new message comes in, we read it and emit it
socketEE.emitter.on('data', function (data) {
// if the socket is used fast, it may appear that multiple messages are flushed at once
// so we have to split them before
@@ -705,7 +642,6 @@ function _create() {
});
});
return _context16.abrupt("return", state);
-
case 20:
case "end":
return _context16.stop();
@@ -715,34 +651,29 @@ function _create() {
}));
return _create.apply(this, arguments);
}
-
export function _filterMessage(msgObj, state) {
if (msgObj.senderUuid === state.uuid) return false; // not send by own
-
if (state.emittedMessagesIds.has(msgObj.token)) return false; // not already emitted
-
if (!state.messagesCallback) return false; // no listener
-
if (msgObj.time < state.messagesCallbackTime) return false; // not older then onMessageCallback
-
if (msgObj.time < state.time) return false; // msgObj is older then channel
state.emittedMessagesIds.add(msgObj.token);
return true;
}
+
/**
* when the socket pings, so that we now new messages came,
* run this
*/
-
export function handleMessagePing(_x20, _x21) {
return _handleMessagePing.apply(this, arguments);
}
+
/**
* ensures that the channelState is connected with all other readers
* @return {Promise}
*/
-
function _handleMessagePing() {
_handleMessagePing = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee17(state, msgObj) {
var messages, useMessages;
@@ -754,27 +685,21 @@ function _handleMessagePing() {
_context17.next = 2;
break;
}
-
return _context17.abrupt("return");
-
case 2:
if (msgObj) {
_context17.next = 8;
break;
}
-
_context17.next = 5;
return getAllMessages(state.channelName, state.paths);
-
case 5:
messages = _context17.sent;
_context17.next = 9;
break;
-
case 8:
// get single message
messages = [getSingleMessage(state.channelName, msgObj, state.paths)];
-
case 9:
useMessages = messages.filter(function (msgObj) {
return _filterMessage(msgObj, state);
@@ -782,14 +707,11 @@ function _handleMessagePing() {
return msgObjA.time - msgObjB.time;
}); // sort by time
// if no listener or message, so not do anything
-
if (!(!useMessages.length || !state.messagesCallback)) {
_context17.next = 12;
break;
}
-
return _context17.abrupt("return");
-
case 12:
_context17.next = 14;
return Promise.all(useMessages.map(function (msgObj) {
@@ -797,17 +719,14 @@ function _handleMessagePing() {
return msgObj.content = content;
});
}));
-
case 14:
useMessages.forEach(function (msgObj) {
state.emittedMessagesIds.add(msgObj.token);
-
if (state.messagesCallback) {
// emit to subscribers
state.messagesCallback(msgObj.content.data);
}
});
-
case 15:
case "end":
return _context17.stop();
@@ -817,7 +736,6 @@ function _handleMessagePing() {
}));
return _handleMessagePing.apply(this, arguments);
}
-
export function refreshReaderClients(channelState) {
return getReadersUuids(channelState.channelName, channelState.paths).then(function (otherReaders) {
// remove subscriptions to closed readers
@@ -832,18 +750,14 @@ export function refreshReaderClients(channelState) {
_context.prev = 0;
_context.next = 3;
return channelState.otherReaderClients[readerUuid].destroy();
-
case 3:
_context.next = 7;
break;
-
case 5:
_context.prev = 5;
_context.t0 = _context["catch"](0);
-
case 7:
delete channelState.otherReaderClients[readerUuid];
-
case 8:
case "end":
return _context.stop();
@@ -851,12 +765,12 @@ export function refreshReaderClients(channelState) {
}
}, _callee, null, [[0, 5]]);
}));
-
return function (_x22) {
return _ref.apply(this, arguments);
};
- }()); // add new readers
+ }());
+ // add new readers
return Promise.all(otherReaders.filter(function (readerUuid) {
return readerUuid !== channelState.uuid;
}) // not own
@@ -871,37 +785,29 @@ export function refreshReaderClients(channelState) {
switch (_context2.prev = _context2.next) {
case 0:
_context2.prev = 0;
-
if (!channelState.closed) {
_context2.next = 3;
break;
}
-
return _context2.abrupt("return");
-
case 3:
_context2.prev = 3;
_context2.next = 6;
return openClientConnection(channelState.channelName, readerUuid);
-
case 6:
client = _context2.sent;
channelState.otherReaderClients[readerUuid] = client;
_context2.next = 12;
break;
-
case 10:
_context2.prev = 10;
_context2.t0 = _context2["catch"](3);
-
case 12:
_context2.next = 16;
break;
-
case 14:
_context2.prev = 14;
_context2.t1 = _context2["catch"](0);
-
case 16:
case "end":
return _context2.stop();
@@ -909,28 +815,27 @@ export function refreshReaderClients(channelState) {
}
}, _callee2, null, [[0, 14], [3, 10]]);
}));
-
return function (_x23) {
return _ref2.apply(this, arguments);
};
}()));
});
}
+
/**
* post a message to the other readers
* @return {Promise}
*/
-
export function postMessage(_x24, _x25) {
return _postMessage.apply(this, arguments);
}
+
/**
* When multiple BroadcastChannels with the same name
* are created in a single node-process, we can access them directly and emit messages.
* This might not happen often in production
* but will speed up things when this module is used in unit-tests.
*/
-
function _postMessage() {
_postMessage = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee19(channelState, messageJson) {
var writePromise;
@@ -943,7 +848,6 @@ function _postMessage() {
});
channelState.writeBlockPromise = channelState.writeBlockPromise.then( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee18() {
var _yield$Promise$all2, msgObj, pingStr, writeToReadersPromise;
-
return _regeneratorRuntime.wrap(function _callee18$(_context18) {
while (1) {
switch (_context18.prev = _context18.next) {
@@ -952,11 +856,9 @@ function _postMessage() {
return new Promise(function (res) {
return setTimeout(res, 0);
});
-
case 2:
_context18.next = 4;
return Promise.all([writePromise, refreshReaderClients(channelState)]);
-
case 4:
_yield$Promise$all2 = _context18.sent;
msgObj = _yield$Promise$all2[0];
@@ -975,16 +877,13 @@ function _postMessage() {
* to not waste resources on cleaning up,
* only if random-int matches, we clean up old messages
*/
-
if (randomInt(0, 20) === 0) {
/* await */
getAllMessages(channelState.channelName, channelState.paths).then(function (allMessages) {
return cleanOldMessages(allMessages, channelState.options.node.ttl);
});
}
-
return _context18.abrupt("return", writeToReadersPromise);
-
case 11:
case "end":
return _context18.stop();
@@ -993,7 +892,6 @@ function _postMessage() {
}, _callee18);
})));
return _context19.abrupt("return", channelState.writeBlockPromise);
-
case 3:
case "end":
return _context19.stop();
@@ -1003,13 +901,11 @@ function _postMessage() {
}));
return _postMessage.apply(this, arguments);
}
-
export function emitOverFastPath(state, msgObj, messageJson) {
if (!state.options.node.useFastPath) {
// disabled
return;
}
-
var others = OTHER_INSTANCES[state.channelName].filter(function (s) {
return s !== state;
});
@@ -1030,11 +926,11 @@ export function onMessage(channelState, fn) {
channelState.messagesCallback = fn;
handleMessagePing(channelState);
}
+
/**
* closes the channel
* @return {Promise}
*/
-
export function close(channelState) {
if (channelState.closed) return;
channelState.closed = true;
@@ -1042,28 +938,24 @@ export function close(channelState) {
OTHER_INSTANCES[channelState.channelName] = OTHER_INSTANCES[channelState.channelName].filter(function (o) {
return o !== channelState;
});
-
if (channelState.removeUnload) {
channelState.removeUnload.remove();
}
-
return new Promise(function (res) {
if (channelState.socketEE) channelState.socketEE.emitter.removeAllListeners();
Object.values(channelState.otherReaderClients).forEach(function (client) {
return client.destroy();
});
-
if (channelState.infoFilePath) {
try {
fs.unlinkSync(channelState.infoFilePath);
} catch (err) {}
}
+
/**
* the server get closed lazy because others might still write on it
* and have not found out that the infoFile was deleted
*/
-
-
setTimeout(function () {
channelState.socketEE.server.close();
res();
@@ -1077,13 +969,13 @@ export function canBeUsed() {
return false;
}
}
+
/**
* on node we use a relatively height averageResponseTime,
* because the file-io might be in use.
* Also it is more important that the leader-election is reliable,
* then to have a fast election.
*/
-
export function averageResponseTime() {
return 200;
}
@@ -1091,7 +983,6 @@ export function microSeconds() {
// convert nano to micro seconds
return parseInt(now() / 1000);
}
-
function now() {
return Number(process.hrtime.bigint()); // returns nanoseconds
}
\ No newline at end of file
diff --git a/dist/esnode/options.js b/dist/esnode/options.js
index fbcc5244..86c7fae3 100644
--- a/dist/esnode/options.js
+++ b/dist/esnode/options.js
@@ -1,29 +1,32 @@
export function fillOptionsWithDefaults() {
var originalOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- var options = JSON.parse(JSON.stringify(originalOptions)); // main
+ var options = JSON.parse(JSON.stringify(originalOptions));
- if (typeof options.webWorkerSupport === 'undefined') options.webWorkerSupport = true; // indexed-db
-
- if (!options.idb) options.idb = {}; // after this time the messages get deleted
+ // main
+ if (typeof options.webWorkerSupport === 'undefined') options.webWorkerSupport = true;
+ // indexed-db
+ if (!options.idb) options.idb = {};
+ // after this time the messages get deleted
if (!options.idb.ttl) options.idb.ttl = 1000 * 45;
- if (!options.idb.fallbackInterval) options.idb.fallbackInterval = 150; // handles abrupt db onclose events.
-
- if (originalOptions.idb && typeof originalOptions.idb.onclose === 'function') options.idb.onclose = originalOptions.idb.onclose; // localstorage
+ if (!options.idb.fallbackInterval) options.idb.fallbackInterval = 150;
+ // handles abrupt db onclose events.
+ if (originalOptions.idb && typeof originalOptions.idb.onclose === 'function') options.idb.onclose = originalOptions.idb.onclose;
+ // localstorage
if (!options.localstorage) options.localstorage = {};
- if (!options.localstorage.removeTimeout) options.localstorage.removeTimeout = 1000 * 60; // custom methods
+ if (!options.localstorage.removeTimeout) options.localstorage.removeTimeout = 1000 * 60;
- if (originalOptions.methods) options.methods = originalOptions.methods; // node
+ // custom methods
+ if (originalOptions.methods) options.methods = originalOptions.methods;
+ // node
if (!options.node) options.node = {};
if (!options.node.ttl) options.node.ttl = 1000 * 60 * 2; // 2 minutes;
-
/**
* On linux use 'ulimit -Hn' to get the limit of open files.
* On ubuntu this was 4096 for me, so we use half of that as maxParallelWrites default.
*/
-
if (!options.node.maxParallelWrites) options.node.maxParallelWrites = 2048;
if (typeof options.node.useFastPath === 'undefined') options.node.useFastPath = true;
return options;
diff --git a/dist/esnode/util.js b/dist/esnode/util.js
index 99b7e529..6c9b9b6e 100644
--- a/dist/esnode/util.js
+++ b/dist/esnode/util.js
@@ -22,15 +22,16 @@ export function sleep(time, resolveWith) {
export function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
+
/**
* https://stackoverflow.com/a/8084248
*/
-
export function randomToken() {
return Math.random().toString(36).substring(2);
}
var lastMs = 0;
var additional = 0;
+
/**
* returns the current time in micro-seconds,
* WARNING: This is a pseudo-function
@@ -38,10 +39,8 @@ var additional = 0;
* This is enough in browsers, and this function will not be used in nodejs.
* The main reason for this hack is to ensure that BroadcastChannel behaves equal to production when it is used in fast-running unit tests.
*/
-
export function microSeconds() {
var ms = new Date().getTime();
-
if (ms === lastMs) {
additional++;
return ms * 1000 + additional;
diff --git a/dist/lib/broadcast-channel.js b/dist/lib/broadcast-channel.js
index 8f3fc9bf..d8162620 100644
--- a/dist/lib/broadcast-channel.js
+++ b/dist/lib/broadcast-channel.js
@@ -6,13 +6,9 @@ Object.defineProperty(exports, "__esModule", {
exports.OPEN_BROADCAST_CHANNELS = exports.BroadcastChannel = void 0;
exports.clearNodeFolder = clearNodeFolder;
exports.enforceOptions = enforceOptions;
-
var _util = require("./util.js");
-
var _methodChooser = require("./method-chooser.js");
-
var _options = require("./options.js");
-
/**
* Contains all open channels,
* used in tests to ensure everything is closed.
@@ -20,77 +16,73 @@ var _options = require("./options.js");
var OPEN_BROADCAST_CHANNELS = new Set();
exports.OPEN_BROADCAST_CHANNELS = OPEN_BROADCAST_CHANNELS;
var lastId = 0;
-
var BroadcastChannel = function BroadcastChannel(name, options) {
// identifier of the channel to debug stuff
this.id = lastId++;
OPEN_BROADCAST_CHANNELS.add(this);
this.name = name;
-
if (ENFORCED_OPTIONS) {
options = ENFORCED_OPTIONS;
}
-
this.options = (0, _options.fillOptionsWithDefaults)(options);
- this.method = (0, _methodChooser.chooseMethod)(this.options); // isListening
+ this.method = (0, _methodChooser.chooseMethod)(this.options);
+ // isListening
this._iL = false;
+
/**
* _onMessageListener
* setting onmessage twice,
* will overwrite the first listener
*/
-
this._onML = null;
+
/**
* _addEventListeners
*/
-
this._addEL = {
message: [],
internal: []
};
+
/**
* Unsend message promises
* where the sending is still in progress
* @type {Set}
*/
-
this._uMP = new Set();
+
/**
* _beforeClose
* array of promises that will be awaited
* before the channel is closed
*/
-
this._befC = [];
+
/**
* _preparePromise
*/
-
this._prepP = null;
-
_prepareChannel(this);
-}; // STATICS
+};
+
+// STATICS
/**
* used to identify if someone overwrites
* window.BroadcastChannel with this
* See methods/native.js
*/
-
-
exports.BroadcastChannel = BroadcastChannel;
BroadcastChannel._pubkey = true;
+
/**
* clears the tmp-folder if is node
* @return {Promise} true if has run, false if not node
*/
-
function clearNodeFolder(options) {
options = (0, _options.fillOptionsWithDefaults)(options);
var method = (0, _methodChooser.chooseMethod)(options);
-
if (method.type === 'node') {
return method.clearNodeFolder().then(function () {
return true;
@@ -99,19 +91,17 @@ function clearNodeFolder(options) {
return _util.PROMISE_RESOLVED_FALSE;
}
}
+
/**
* if set, this method is enforced,
* no mather what the options are
*/
-
-
var ENFORCED_OPTIONS;
-
function enforceOptions(options) {
ENFORCED_OPTIONS = options;
-} // PROTOTYPE
-
+}
+// PROTOTYPE
BroadcastChannel.prototype = {
postMessage: function postMessage(msg) {
if (this.closed) {
@@ -123,87 +113,77 @@ BroadcastChannel.prototype = {
*/
JSON.stringify(msg));
}
-
return _post(this, 'message', msg);
},
postInternal: function postInternal(msg) {
return _post(this, 'internal', msg);
},
-
set onmessage(fn) {
var time = this.method.microSeconds();
var listenObj = {
time: time,
fn: fn
};
-
_removeListenerObject(this, 'message', this._onML);
-
if (fn && typeof fn === 'function') {
this._onML = listenObj;
-
_addListenerObject(this, 'message', listenObj);
} else {
this._onML = null;
}
},
-
addEventListener: function addEventListener(type, fn) {
var time = this.method.microSeconds();
var listenObj = {
time: time,
fn: fn
};
-
_addListenerObject(this, type, listenObj);
},
removeEventListener: function removeEventListener(type, fn) {
var obj = this._addEL[type].find(function (obj) {
return obj.fn === fn;
});
-
_removeListenerObject(this, type, obj);
},
close: function close() {
var _this = this;
-
if (this.closed) {
return;
}
-
OPEN_BROADCAST_CHANNELS["delete"](this);
this.closed = true;
var awaitPrepare = this._prepP ? this._prepP : _util.PROMISE_RESOLVED_VOID;
this._onML = null;
this._addEL.message = [];
- return awaitPrepare // wait until all current sending are processed
+ return awaitPrepare
+ // wait until all current sending are processed
.then(function () {
return Promise.all(Array.from(_this._uMP));
- }) // run before-close hooks
+ })
+ // run before-close hooks
.then(function () {
return Promise.all(_this._befC.map(function (fn) {
return fn();
}));
- }) // close the channel
+ })
+ // close the channel
.then(function () {
return _this.method.close(_this._state);
});
},
-
get type() {
return this.method.type;
},
-
get isClosed() {
return this.closed;
}
-
};
+
/**
* Post a message over the channel
* @returns {Promise} that resolved when the message sending is done
*/
-
function _post(broadcastChannel, type, msg) {
var time = broadcastChannel.method.microSeconds();
var msgObj = {
@@ -213,25 +193,22 @@ function _post(broadcastChannel, type, msg) {
};
var awaitPrepare = broadcastChannel._prepP ? broadcastChannel._prepP : _util.PROMISE_RESOLVED_VOID;
return awaitPrepare.then(function () {
- var sendPromise = broadcastChannel.method.postMessage(broadcastChannel._state, msgObj); // add/remove to unsend messages list
+ var sendPromise = broadcastChannel.method.postMessage(broadcastChannel._state, msgObj);
+ // add/remove to unsend messages list
broadcastChannel._uMP.add(sendPromise);
-
sendPromise["catch"]().then(function () {
return broadcastChannel._uMP["delete"](sendPromise);
});
return sendPromise;
});
}
-
function _prepareChannel(channel) {
var maybePromise = channel.method.create(channel.name, channel.options);
-
if ((0, _util.isPromise)(maybePromise)) {
channel._prepP = maybePromise;
maybePromise.then(function (s) {
// used in tests to simulate slow runtime
-
/*if (channel.options.prepareDelay) {
await new Promise(res => setTimeout(res, this.options.prepareDelay));
}*/
@@ -241,30 +218,25 @@ function _prepareChannel(channel) {
channel._state = maybePromise;
}
}
-
function _hasMessageListeners(channel) {
if (channel._addEL.message.length > 0) return true;
if (channel._addEL.internal.length > 0) return true;
return false;
}
-
function _addListenerObject(channel, type, obj) {
channel._addEL[type].push(obj);
-
_startListening(channel);
}
-
function _removeListenerObject(channel, type, obj) {
channel._addEL[type] = channel._addEL[type].filter(function (o) {
return o !== obj;
});
-
_stopListening(channel);
}
-
function _startListening(channel) {
if (!channel._iL && _hasMessageListeners(channel)) {
// someone is listening, start subscribing
+
var listenerFn = function listenerFn(msgObj) {
channel._addEL[msgObj.type].forEach(function (listenerObject) {
/**
@@ -278,15 +250,12 @@ function _startListening(channel) {
*/
var hundredMsInMicro = 100 * 1000;
var minMessageTime = listenerObject.time - hundredMsInMicro;
-
if (msgObj.time >= minMessageTime) {
listenerObject.fn(msgObj.data);
}
});
};
-
var time = channel.method.microSeconds();
-
if (channel._prepP) {
channel._prepP.then(function () {
channel._iL = true;
@@ -298,7 +267,6 @@ function _startListening(channel) {
}
}
}
-
function _stopListening(channel) {
if (channel._iL && !_hasMessageListeners(channel)) {
// noone is listening, stop subscribing
diff --git a/dist/lib/browser.js b/dist/lib/browser.js
index bdb4fdcb..f912820e 100644
--- a/dist/lib/browser.js
+++ b/dist/lib/browser.js
@@ -7,13 +7,9 @@ Object.defineProperty(exports, "__esModule", {
exports.OPEN_BROADCAST_CHANNELS = exports.BroadcastChannel = void 0;
exports.clearNodeFolder = clearNodeFolder;
exports.enforceOptions = enforceOptions;
-
var _util = require("./util.js");
-
var _methodChooser = require("./method-chooser.js");
-
var _options = require("./options.js");
-
/**
* Contains all open channels,
* used in tests to ensure everything is closed.
@@ -21,77 +17,73 @@ var _options = require("./options.js");
var OPEN_BROADCAST_CHANNELS = new Set();
exports.OPEN_BROADCAST_CHANNELS = OPEN_BROADCAST_CHANNELS;
var lastId = 0;
-
var BroadcastChannel = function BroadcastChannel(name, options) {
// identifier of the channel to debug stuff
this.id = lastId++;
OPEN_BROADCAST_CHANNELS.add(this);
this.name = name;
-
if (ENFORCED_OPTIONS) {
options = ENFORCED_OPTIONS;
}
-
this.options = (0, _options.fillOptionsWithDefaults)(options);
- this.method = (0, _methodChooser.chooseMethod)(this.options); // isListening
+ this.method = (0, _methodChooser.chooseMethod)(this.options);
+ // isListening
this._iL = false;
+
/**
* _onMessageListener
* setting onmessage twice,
* will overwrite the first listener
*/
-
this._onML = null;
+
/**
* _addEventListeners
*/
-
this._addEL = {
message: [],
internal: []
};
+
/**
* Unsend message promises
* where the sending is still in progress
* @type {Set}
*/
-
this._uMP = new Set();
+
/**
* _beforeClose
* array of promises that will be awaited
* before the channel is closed
*/
-
this._befC = [];
+
/**
* _preparePromise
*/
-
this._prepP = null;
-
_prepareChannel(this);
-}; // STATICS
+};
+
+// STATICS
/**
* used to identify if someone overwrites
* window.BroadcastChannel with this
* See methods/native.js
*/
-
-
exports.BroadcastChannel = BroadcastChannel;
BroadcastChannel._pubkey = true;
+
/**
* clears the tmp-folder if is node
* @return {Promise} true if has run, false if not node
*/
-
function clearNodeFolder(options) {
options = (0, _options.fillOptionsWithDefaults)(options);
var method = (0, _methodChooser.chooseMethod)(options);
-
if (method.type === 'node') {
return method.clearNodeFolder().then(function () {
return true;
@@ -100,19 +92,17 @@ function clearNodeFolder(options) {
return _util.PROMISE_RESOLVED_FALSE;
}
}
+
/**
* if set, this method is enforced,
* no mather what the options are
*/
-
-
var ENFORCED_OPTIONS;
-
function enforceOptions(options) {
ENFORCED_OPTIONS = options;
-} // PROTOTYPE
-
+}
+// PROTOTYPE
BroadcastChannel.prototype = {
postMessage: function postMessage(msg) {
if (this.closed) {
@@ -124,87 +114,77 @@ BroadcastChannel.prototype = {
*/
JSON.stringify(msg));
}
-
return _post(this, 'message', msg);
},
postInternal: function postInternal(msg) {
return _post(this, 'internal', msg);
},
-
set onmessage(fn) {
var time = this.method.microSeconds();
var listenObj = {
time: time,
fn: fn
};
-
_removeListenerObject(this, 'message', this._onML);
-
if (fn && typeof fn === 'function') {
this._onML = listenObj;
-
_addListenerObject(this, 'message', listenObj);
} else {
this._onML = null;
}
},
-
addEventListener: function addEventListener(type, fn) {
var time = this.method.microSeconds();
var listenObj = {
time: time,
fn: fn
};
-
_addListenerObject(this, type, listenObj);
},
removeEventListener: function removeEventListener(type, fn) {
var obj = this._addEL[type].find(function (obj) {
return obj.fn === fn;
});
-
_removeListenerObject(this, type, obj);
},
close: function close() {
var _this = this;
-
if (this.closed) {
return;
}
-
OPEN_BROADCAST_CHANNELS["delete"](this);
this.closed = true;
var awaitPrepare = this._prepP ? this._prepP : _util.PROMISE_RESOLVED_VOID;
this._onML = null;
this._addEL.message = [];
- return awaitPrepare // wait until all current sending are processed
+ return awaitPrepare
+ // wait until all current sending are processed
.then(function () {
return Promise.all(Array.from(_this._uMP));
- }) // run before-close hooks
+ })
+ // run before-close hooks
.then(function () {
return Promise.all(_this._befC.map(function (fn) {
return fn();
}));
- }) // close the channel
+ })
+ // close the channel
.then(function () {
return _this.method.close(_this._state);
});
},
-
get type() {
return this.method.type;
},
-
get isClosed() {
return this.closed;
}
-
};
+
/**
* Post a message over the channel
* @returns {Promise} that resolved when the message sending is done
*/
-
function _post(broadcastChannel, type, msg) {
var time = broadcastChannel.method.microSeconds();
var msgObj = {
@@ -214,25 +194,22 @@ function _post(broadcastChannel, type, msg) {
};
var awaitPrepare = broadcastChannel._prepP ? broadcastChannel._prepP : _util.PROMISE_RESOLVED_VOID;
return awaitPrepare.then(function () {
- var sendPromise = broadcastChannel.method.postMessage(broadcastChannel._state, msgObj); // add/remove to unsend messages list
+ var sendPromise = broadcastChannel.method.postMessage(broadcastChannel._state, msgObj);
+ // add/remove to unsend messages list
broadcastChannel._uMP.add(sendPromise);
-
sendPromise["catch"]().then(function () {
return broadcastChannel._uMP["delete"](sendPromise);
});
return sendPromise;
});
}
-
function _prepareChannel(channel) {
var maybePromise = channel.method.create(channel.name, channel.options);
-
if ((0, _util.isPromise)(maybePromise)) {
channel._prepP = maybePromise;
maybePromise.then(function (s) {
// used in tests to simulate slow runtime
-
/*if (channel.options.prepareDelay) {
await new Promise(res => setTimeout(res, this.options.prepareDelay));
}*/
@@ -242,30 +219,25 @@ function _prepareChannel(channel) {
channel._state = maybePromise;
}
}
-
function _hasMessageListeners(channel) {
if (channel._addEL.message.length > 0) return true;
if (channel._addEL.internal.length > 0) return true;
return false;
}
-
function _addListenerObject(channel, type, obj) {
channel._addEL[type].push(obj);
-
_startListening(channel);
}
-
function _removeListenerObject(channel, type, obj) {
channel._addEL[type] = channel._addEL[type].filter(function (o) {
return o !== obj;
});
-
_stopListening(channel);
}
-
function _startListening(channel) {
if (!channel._iL && _hasMessageListeners(channel)) {
// someone is listening, start subscribing
+
var listenerFn = function listenerFn(msgObj) {
channel._addEL[msgObj.type].forEach(function (listenerObject) {
/**
@@ -279,15 +251,12 @@ function _startListening(channel) {
*/
var hundredMsInMicro = 100 * 1000;
var minMessageTime = listenerObject.time - hundredMsInMicro;
-
if (msgObj.time >= minMessageTime) {
listenerObject.fn(msgObj.data);
}
});
};
-
var time = channel.method.microSeconds();
-
if (channel._prepP) {
channel._prepP.then(function () {
channel._iL = true;
@@ -299,7 +268,6 @@ function _startListening(channel) {
}
}
}
-
function _stopListening(channel) {
if (channel._iL && !_hasMessageListeners(channel)) {
// noone is listening, stop subscribing
@@ -312,7 +280,6 @@ function _stopListening(channel) {
"use strict";
var _module = require('./index.es5.js');
-
var BroadcastChannel = _module.BroadcastChannel;
var createLeaderElection = _module.createLeaderElection;
window['BroadcastChannel2'] = BroadcastChannel;
@@ -321,7 +288,6 @@ window['createLeaderElection'] = createLeaderElection;
"use strict";
var _index = require("./index.js");
-
/**
* because babel can only export on default-attribute,
* we use this for the non-module-build
@@ -330,6 +296,7 @@ var _index = require("./index.js");
* but
* var BroadcastChannel = require('broadcast-channel');
*/
+
module.exports = {
BroadcastChannel: _index.BroadcastChannel,
createLeaderElection: _index.createLeaderElection,
@@ -379,9 +346,7 @@ Object.defineProperty(exports, "enforceOptions", {
return _broadcastChannel.enforceOptions;
}
});
-
var _broadcastChannel = require("./broadcast-channel.js");
-
var _leaderElection = require("./leader-election.js");
},{"./broadcast-channel.js":1,"./leader-election.js":5}],5:[function(require,module,exports){
"use strict";
@@ -391,37 +356,30 @@ Object.defineProperty(exports, "__esModule", {
});
exports.beLeader = beLeader;
exports.createLeaderElection = createLeaderElection;
-
var _util = require("./util.js");
-
var _unload = require("unload");
-
var LeaderElection = function LeaderElection(broadcastChannel, options) {
var _this = this;
-
this.broadcastChannel = broadcastChannel;
this._options = options;
this.isLeader = false;
this.hasLeader = false;
this.isDead = false;
this.token = (0, _util.randomToken)();
+
/**
* Apply Queue,
* used to ensure we do not run applyOnce()
* in parallel.
*/
+ this._aplQ = _util.PROMISE_RESOLVED_VOID;
+ // amount of unfinished applyOnce() calls
+ this._aplQC = 0;
- this._aplQ = _util.PROMISE_RESOLVED_VOID; // amount of unfinished applyOnce() calls
-
- this._aplQC = 0; // things to clean up
-
+ // things to clean up
this._unl = []; // _unloads
-
this._lstns = []; // _listeners
-
this._dpL = function () {}; // onduplicate listener
-
-
this._dpLC = false; // true when onduplicate called
/**
@@ -429,55 +387,47 @@ var LeaderElection = function LeaderElection(broadcastChannel, options) {
* we still listen to messages to ensure the hasLeader flag
* is set correctly.
*/
-
var hasLeaderListener = function hasLeaderListener(msg) {
if (msg.context === 'leader') {
if (msg.action === 'death') {
_this.hasLeader = false;
}
-
if (msg.action === 'tell') {
_this.hasLeader = true;
}
}
};
-
this.broadcastChannel.addEventListener('internal', hasLeaderListener);
-
this._lstns.push(hasLeaderListener);
};
-
LeaderElection.prototype = {
/**
* Returns true if the instance is leader,
* false if not.
* @async
*/
- applyOnce: function applyOnce( // true if the applyOnce() call came from the fallbackInterval cycle
+ applyOnce: function applyOnce(
+ // true if the applyOnce() call came from the fallbackInterval cycle
isFromFallbackInterval) {
var _this2 = this;
-
if (this.isLeader) {
return (0, _util.sleep)(0, true);
}
-
if (this.isDead) {
return (0, _util.sleep)(0, false);
}
+
/**
* Already applying more then once,
* -> wait for the apply queue to be finished.
*/
-
-
if (this._aplQC > 1) {
return this._aplQ;
}
+
/**
* Add a new apply-run
*/
-
-
var applyRun = function applyRun() {
/**
* Optimization shortcuts.
@@ -487,7 +437,6 @@ LeaderElection.prototype = {
if (_this2.isLeader) {
return _util.PROMISE_RESOLVED_TRUE;
}
-
var stopCriteria = false;
var stopCriteriaPromiseResolve;
/**
@@ -496,7 +445,6 @@ LeaderElection.prototype = {
* have to await the responseTime when it is already clear
* that the election failed.
*/
-
var stopCriteriaPromise = new Promise(function (res) {
stopCriteriaPromiseResolve = function stopCriteriaPromiseResolve() {
stopCriteria = true;
@@ -504,11 +452,9 @@ LeaderElection.prototype = {
};
});
var recieved = [];
-
var handleMessage = function handleMessage(msg) {
if (msg.context === 'leader' && msg.token != _this2.token) {
recieved.push(msg);
-
if (msg.action === 'apply') {
// other is applying
if (msg.token > _this2.token) {
@@ -519,7 +465,6 @@ LeaderElection.prototype = {
stopCriteriaPromiseResolve();
}
}
-
if (msg.action === 'tell') {
// other is already leader
stopCriteriaPromiseResolve();
@@ -527,8 +472,8 @@ LeaderElection.prototype = {
}
}
};
-
_this2.broadcastChannel.addEventListener('internal', handleMessage);
+
/**
* If the applyOnce() call came from the fallbackInterval,
* we can assume that the election runs in the background and
@@ -539,26 +484,24 @@ LeaderElection.prototype = {
* But also it takes longer which is not a problem because we anyway
* run in the background.
*/
-
-
var waitForAnswerTime = isFromFallbackInterval ? _this2._options.responseTime * 4 : _this2._options.responseTime;
-
var applyPromise = _sendMessage(_this2, 'apply') // send out that this one is applying
.then(function () {
return Promise.race([(0, _util.sleep)(waitForAnswerTime), stopCriteriaPromise.then(function () {
return Promise.reject(new Error());
})]);
- }) // send again in case another instance was just created
+ })
+ // send again in case another instance was just created
.then(function () {
return _sendMessage(_this2, 'apply');
- }) // let others time to respond
+ })
+ // let others time to respond
.then(function () {
return Promise.race([(0, _util.sleep)(waitForAnswerTime), stopCriteriaPromise.then(function () {
return Promise.reject(new Error());
})]);
})["catch"](function () {}).then(function () {
_this2.broadcastChannel.removeEventListener('internal', handleMessage);
-
if (!stopCriteria) {
// no stop criteria -> own is leader
return beLeader(_this2).then(function () {
@@ -569,10 +512,8 @@ LeaderElection.prototype = {
return false;
}
});
-
return applyPromise;
};
-
this._aplQC = this._aplQC + 1;
this._aplQ = this._aplQ.then(function () {
return applyRun();
@@ -584,82 +525,68 @@ LeaderElection.prototype = {
});
},
awaitLeadership: function awaitLeadership() {
- if (
- /* _awaitLeadershipPromise */
+ if ( /* _awaitLeadershipPromise */
!this._aLP) {
this._aLP = _awaitLeadershipOnce(this);
}
-
return this._aLP;
},
-
set onduplicate(fn) {
this._dpL = fn;
},
-
die: function die() {
var _this3 = this;
-
this._lstns.forEach(function (listener) {
return _this3.broadcastChannel.removeEventListener('internal', listener);
});
-
this._lstns = [];
-
this._unl.forEach(function (uFn) {
return uFn.remove();
});
-
this._unl = [];
-
if (this.isLeader) {
this.hasLeader = false;
this.isLeader = false;
}
-
this.isDead = true;
return _sendMessage(this, 'death');
}
};
+
/**
* @param leaderElector {LeaderElector}
*/
-
function _awaitLeadershipOnce(leaderElector) {
if (leaderElector.isLeader) {
return _util.PROMISE_RESOLVED_VOID;
}
-
return new Promise(function (res) {
var resolved = false;
-
function finish() {
if (resolved) {
return;
}
-
resolved = true;
leaderElector.broadcastChannel.removeEventListener('internal', whenDeathListener);
res(true);
- } // try once now
-
+ }
+ // try once now
leaderElector.applyOnce().then(function () {
if (leaderElector.isLeader) {
finish();
}
});
+
/**
* Try on fallbackInterval
* @recursive
*/
-
var tryOnFallBack = function tryOnFallBack() {
return (0, _util.sleep)(leaderElector._options.fallbackInterval).then(function () {
if (leaderElector.isDead || resolved) {
return;
}
-
if (leaderElector.isLeader) {
finish();
} else {
@@ -673,9 +600,9 @@ function _awaitLeadershipOnce(leaderElector) {
}
});
};
+ tryOnFallBack();
- tryOnFallBack(); // try when other leader dies
-
+ // try when other leader dies
var whenDeathListener = function whenDeathListener(msg) {
if (msg.context === 'leader' && msg.action === 'death') {
leaderElector.hasLeader = false;
@@ -686,17 +613,14 @@ function _awaitLeadershipOnce(leaderElector) {
});
}
};
-
leaderElector.broadcastChannel.addEventListener('internal', whenDeathListener);
-
leaderElector._lstns.push(whenDeathListener);
});
}
+
/**
* sends and internal message over the broadcast-channel
*/
-
-
function _sendMessage(leaderElector, action) {
var msgJson = {
context: 'leader',
@@ -705,21 +629,17 @@ function _sendMessage(leaderElector, action) {
};
return leaderElector.broadcastChannel.postInternal(msgJson);
}
-
function beLeader(leaderElector) {
leaderElector.isLeader = true;
leaderElector.hasLeader = true;
var unloadFn = (0, _unload.add)(function () {
return leaderElector.die();
});
-
leaderElector._unl.push(unloadFn);
-
var isLeaderListener = function isLeaderListener(msg) {
if (msg.context === 'leader' && msg.action === 'apply') {
_sendMessage(leaderElector, 'tell');
}
-
if (msg.context === 'leader' && msg.action === 'tell' && !leaderElector._dpLC) {
/**
* another instance is also leader!
@@ -730,49 +650,35 @@ function beLeader(leaderElector) {
* @link https://github.com/pubkey/broadcast-channel/issues/385
*/
leaderElector._dpLC = true;
-
leaderElector._dpL(); // message the lib user so the app can handle the problem
-
-
_sendMessage(leaderElector, 'tell'); // ensure other leader also knows the problem
-
}
};
leaderElector.broadcastChannel.addEventListener('internal', isLeaderListener);
-
leaderElector._lstns.push(isLeaderListener);
-
return _sendMessage(leaderElector, 'tell');
}
-
function fillOptionsWithDefaults(options, channel) {
if (!options) options = {};
options = JSON.parse(JSON.stringify(options));
-
if (!options.fallbackInterval) {
options.fallbackInterval = 3000;
}
-
if (!options.responseTime) {
options.responseTime = channel.method.averageResponseTime(channel.options);
}
-
return options;
}
-
function createLeaderElection(channel, options) {
if (channel._leaderElector) {
throw new Error('BroadcastChannel already has a leader-elector');
}
-
options = fillOptionsWithDefaults(options, channel);
var elector = new LeaderElection(channel, options);
-
channel._befC.push(function () {
return elector.die();
});
-
channel._leaderElector = elector;
return elector;
}
@@ -780,59 +686,49 @@ function createLeaderElection(channel, options) {
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
-
var _typeof = require("@babel/runtime/helpers/typeof");
-
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.chooseMethod = chooseMethod;
-
var _native = _interopRequireDefault(require("./methods/native.js"));
-
var _indexedDb = _interopRequireDefault(require("./methods/indexed-db.js"));
-
var _localstorage = _interopRequireDefault(require("./methods/localstorage.js"));
-
var _simulate = _interopRequireDefault(require("./methods/simulate.js"));
-
-
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
-
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
-
// the line below will be removed from es5/browser builds
+
// order is important
-var METHODS = [_native["default"], // fastest
+var METHODS = [_native["default"],
+// fastest
_indexedDb["default"], _localstorage["default"]];
-
function chooseMethod(options) {
- var chooseMethods = [].concat(options.methods, METHODS).filter(Boolean); // the line below will be removed from es5/browser builds
+ var chooseMethods = [].concat(options.methods, METHODS).filter(Boolean);
+ // the line below will be removed from es5/browser builds
+ // directly chosen
if (options.type) {
if (options.type === 'simulate') {
// only use simulate-method if directly chosen
return _simulate["default"];
}
-
var ret = chooseMethods.find(function (m) {
return m.type === options.type;
});
if (!ret) throw new Error('method-type ' + options.type + ' not found');else return ret;
}
+
/**
* if no webworker support is needed,
* remove idb from the list so that localstorage is been chosen
*/
-
-
if (!options.webWorkerSupport) {
chooseMethods = chooseMethods.filter(function (m) {
return m.type !== 'idb';
});
}
-
var useMethod = chooseMethods.find(function (method) {
return method.canBeUsed();
});
@@ -865,13 +761,9 @@ exports.postMessage = postMessage;
exports.removeMessagesById = removeMessagesById;
exports.type = void 0;
exports.writeMessage = writeMessage;
-
var _util = require("../util.js");
-
var _obliviousSet = require("oblivious-set");
-
var _options = require("../options.js");
-
/**
* this method uses indexeddb to store the messages
* There is currently no observerAPI for idb
@@ -880,58 +772,54 @@ var _options = require("../options.js");
* When working on this, ensure to use these performance optimizations:
* @link https://rxdb.info/slow-indexeddb.html
*/
+
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var DB_PREFIX = 'pubkey.broadcast-channel-0-';
var OBJECT_STORE_ID = 'messages';
+
/**
* Use relaxed durability for faster performance on all transactions.
* @link https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/
*/
-
var TRANSACTION_SETTINGS = {
durability: 'relaxed'
};
exports.TRANSACTION_SETTINGS = TRANSACTION_SETTINGS;
var type = 'idb';
exports.type = type;
-
function getIdb() {
if (typeof indexedDB !== 'undefined') return indexedDB;
-
if (typeof window !== 'undefined') {
if (typeof window.mozIndexedDB !== 'undefined') return window.mozIndexedDB;
if (typeof window.webkitIndexedDB !== 'undefined') return window.webkitIndexedDB;
if (typeof window.msIndexedDB !== 'undefined') return window.msIndexedDB;
}
-
return false;
}
+
/**
* If possible, we should explicitly commit IndexedDB transactions
* for better performance.
* @link https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/
*/
-
-
function commitIndexedDBTransaction(tx) {
if (tx.commit) {
tx.commit();
}
}
-
function createDatabase(channelName) {
- var IndexedDB = getIdb(); // create table
+ var IndexedDB = getIdb();
+ // create table
var dbName = DB_PREFIX + channelName;
+
/**
* All IndexedDB databases are opened without version
* because it is a bit faster, especially on firefox
* @link http://nparashuram.com/IndexedDB/perf/#Open%20Database%20with%20version
*/
-
var openRequest = IndexedDB.open(dbName);
-
openRequest.onupgradeneeded = function (ev) {
var db = ev.target.result;
db.createObjectStore(OBJECT_STORE_ID, {
@@ -939,24 +827,21 @@ function createDatabase(channelName) {
autoIncrement: true
});
};
-
var dbPromise = new Promise(function (res, rej) {
openRequest.onerror = function (ev) {
return rej(ev);
};
-
openRequest.onsuccess = function () {
res(openRequest.result);
};
});
return dbPromise;
}
+
/**
* writes the new message to the database
* so other readers can find it
*/
-
-
function writeMessage(db, readerUuid, messageJson) {
var time = new Date().getTime();
var writeObject = {
@@ -969,17 +854,14 @@ function writeMessage(db, readerUuid, messageJson) {
tx.oncomplete = function () {
return res();
};
-
tx.onerror = function (ev) {
return rej(ev);
};
-
var objectStore = tx.objectStore(OBJECT_STORE_ID);
objectStore.add(writeObject);
commitIndexedDBTransaction(tx);
});
}
-
function getAllMessages(db) {
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS);
var objectStore = tx.objectStore(OBJECT_STORE_ID);
@@ -987,10 +869,9 @@ function getAllMessages(db) {
return new Promise(function (res) {
objectStore.openCursor().onsuccess = function (ev) {
var cursor = ev.target.result;
-
if (cursor) {
- ret.push(cursor.value); //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
-
+ ret.push(cursor.value);
+ //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor["continue"]();
} else {
commitIndexedDBTransaction(tx);
@@ -999,31 +880,28 @@ function getAllMessages(db) {
};
});
}
-
function getMessagesHigherThan(db, lastCursorId) {
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS);
var objectStore = tx.objectStore(OBJECT_STORE_ID);
var ret = [];
var keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity);
+
/**
* Optimization shortcut,
* if getAll() can be used, do not use a cursor.
* @link https://rxdb.info/slow-indexeddb.html
*/
-
if (objectStore.getAll) {
var getAllRequest = objectStore.getAll(keyRangeValue);
return new Promise(function (res, rej) {
getAllRequest.onerror = function (err) {
return rej(err);
};
-
getAllRequest.onsuccess = function (e) {
res(e.target.result);
};
});
}
-
function openCursor() {
// Occasionally Safari will fail on IDBKeyRange.bound, this
// catches that error, having it open the cursor to the first
@@ -1035,17 +913,13 @@ function getMessagesHigherThan(db, lastCursorId) {
return objectStore.openCursor();
}
}
-
return new Promise(function (res, rej) {
var openCursorRequest = openCursor();
-
openCursorRequest.onerror = function (err) {
return rej(err);
};
-
openCursorRequest.onsuccess = function (ev) {
var cursor = ev.target.result;
-
if (cursor) {
if (cursor.value.id < lastCursorId + 1) {
cursor["continue"](lastCursorId + 1);
@@ -1060,12 +934,10 @@ function getMessagesHigherThan(db, lastCursorId) {
};
});
}
-
function removeMessagesById(channelState, ids) {
if (channelState.closed) {
return Promise.resolve([]);
}
-
var tx = channelState.db.transaction(OBJECT_STORE_ID, 'readwrite', TRANSACTION_SETTINGS);
var objectStore = tx.objectStore(OBJECT_STORE_ID);
return Promise.all(ids.map(function (id) {
@@ -1077,7 +949,6 @@ function removeMessagesById(channelState, ids) {
});
}));
}
-
function getOldMessages(db, ttl) {
var olderThen = new Date().getTime() - ttl;
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS);
@@ -1086,13 +957,11 @@ function getOldMessages(db, ttl) {
return new Promise(function (res) {
objectStore.openCursor().onsuccess = function (ev) {
var cursor = ev.target.result;
-
if (cursor) {
var msgObk = cursor.value;
-
if (msgObk.time < olderThen) {
- ret.push(msgObk); //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
-
+ ret.push(msgObk);
+ //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor["continue"]();
} else {
// no more old messages,
@@ -1106,7 +975,6 @@ function getOldMessages(db, ttl) {
};
});
}
-
function cleanOldMessages(channelState) {
return getOldMessages(channelState.db, channelState.options.idb.ttl).then(function (tooOld) {
return removeMessagesById(channelState, tooOld.map(function (msg) {
@@ -1114,7 +982,6 @@ function cleanOldMessages(channelState) {
}));
});
}
-
function create(channelName, options) {
options = (0, _options.fillOptionsWithDefaults)(options);
return createDatabase(channelName).then(function (db) {
@@ -1124,7 +991,6 @@ function create(channelName, options) {
channelName: channelName,
options: options,
uuid: (0, _util.randomToken)(),
-
/**
* emittedMessagesIds
* contains all messages that have been emitted before
@@ -1137,30 +1003,27 @@ function create(channelName, options) {
readQueuePromises: [],
db: db
};
+
/**
* Handle abrupt closes that do not originate from db.close().
* This could happen, for example, if the underlying storage is
* removed or if the user clears the database in the browser's
* history preferences.
*/
-
db.onclose = function () {
state.closed = true;
if (options.idb.onclose) options.idb.onclose();
};
+
/**
* if service-workers are used,
* we have no 'storage'-event if they post a message,
* therefore we also have to set an interval
*/
-
-
_readLoop(state);
-
return state;
});
}
-
function _readLoop(state) {
if (state.closed) return;
readNewMessages(state).then(function () {
@@ -1169,25 +1032,21 @@ function _readLoop(state) {
return _readLoop(state);
});
}
-
function _filterMessage(msgObj, state) {
if (msgObj.uuid === state.uuid) return false; // send by own
-
if (state.eMIs.has(msgObj.id)) return false; // already emitted
-
if (msgObj.data.time < state.messagesCallbackTime) return false; // older then onMessageCallback
-
return true;
}
+
/**
* reads all new messages from the database and emits them
*/
-
-
function readNewMessages(state) {
// channel already closed
- if (state.closed) return _util.PROMISE_RESOLVED_VOID; // if no one is listening, we do not need to scan for new messages
+ if (state.closed) return _util.PROMISE_RESOLVED_VOID;
+ // if no one is listening, we do not need to scan for new messages
if (!state.messagesCallback) return _util.PROMISE_RESOLVED_VOID;
return getMessagesHigherThan(state.db, state.lastCursorId).then(function (newerMessages) {
var useMessages = newerMessages
@@ -1195,21 +1054,18 @@ function readNewMessages(state) {
* there is a bug in iOS where the msgObj can be undefined some times
* so we filter them out
* @link https://github.com/pubkey/broadcast-channel/issues/19
- */
- .filter(function (msgObj) {
+ */.filter(function (msgObj) {
return !!msgObj;
}).map(function (msgObj) {
if (msgObj.id > state.lastCursorId) {
state.lastCursorId = msgObj.id;
}
-
return msgObj;
}).filter(function (msgObj) {
return _filterMessage(msgObj, state);
}).sort(function (msgObjA, msgObjB) {
return msgObjA.time - msgObjB.time;
}); // sort by time
-
useMessages.forEach(function (msgObj) {
if (state.messagesCallback) {
state.eMIs.add(msgObj.id);
@@ -1219,12 +1075,10 @@ function readNewMessages(state) {
return _util.PROMISE_RESOLVED_VOID;
});
}
-
function close(channelState) {
channelState.closed = true;
channelState.db.close();
}
-
function postMessage(channelState, messageJson) {
channelState.writeBlockPromise = channelState.writeBlockPromise.then(function () {
return writeMessage(channelState.db, channelState.uuid, messageJson);
@@ -1236,27 +1090,21 @@ function postMessage(channelState, messageJson) {
});
return channelState.writeBlockPromise;
}
-
function onMessage(channelState, fn, time) {
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
readNewMessages(channelState);
}
-
function canBeUsed() {
var idb = getIdb();
-
if (!idb) {
return false;
}
-
return true;
}
-
function averageResponseTime(options) {
return options.idb.fallbackInterval * 2;
}
-
var _default = {
create: create,
close: close,
@@ -1287,13 +1135,9 @@ exports.postMessage = postMessage;
exports.removeStorageEventListener = removeStorageEventListener;
exports.storageKey = storageKey;
exports.type = void 0;
-
var _obliviousSet = require("oblivious-set");
-
var _options = require("../options.js");
-
var _util = require("../util.js");
-
/**
* A localStorage-only method which uses localstorage and its 'storage'-event
* This does not work inside of webworkers because they have no access to locastorage
@@ -1301,41 +1145,38 @@ var _util = require("../util.js");
* @link https://caniuse.com/#feat=namevalue-storage
* @link https://caniuse.com/#feat=indexeddb
*/
+
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var KEY_PREFIX = 'pubkey.broadcastChannel-';
var type = 'localstorage';
+
/**
* copied from crosstab
* @link https://github.com/tejacques/crosstab/blob/master/src/crosstab.js#L32
*/
-
exports.type = type;
-
function getLocalStorage() {
var localStorage;
if (typeof window === 'undefined') return null;
-
try {
localStorage = window.localStorage;
localStorage = window['ie8-eventlistener/storage'] || window.localStorage;
- } catch (e) {// New versions of Firefox throw a Security exception
+ } catch (e) {
+ // New versions of Firefox throw a Security exception
// if cookies are disabled. See
// https://bugzilla.mozilla.org/show_bug.cgi?id=1028153
}
-
return localStorage;
}
-
function storageKey(channelName) {
return KEY_PREFIX + channelName;
}
+
/**
* writes the new message to the storage
* and fires the storage-event so other readers can find it
*/
-
-
function postMessage(channelState, messageJson) {
return new Promise(function (res) {
(0, _util.sleep)().then(function () {
@@ -1348,12 +1189,12 @@ function postMessage(channelState, messageJson) {
};
var value = JSON.stringify(writeObj);
getLocalStorage().setItem(key, value);
+
/**
* StorageEvent does not fire the 'storage' event
* in the window that changes the state of the local storage.
* So we fire it manually
*/
-
var ev = document.createEvent('Event');
ev.initEvent('storage', true, true);
ev.key = key;
@@ -1363,52 +1204,42 @@ function postMessage(channelState, messageJson) {
});
});
}
-
function addStorageEventListener(channelName, fn) {
var key = storageKey(channelName);
-
var listener = function listener(ev) {
if (ev.key === key) {
fn(JSON.parse(ev.newValue));
}
};
-
window.addEventListener('storage', listener);
return listener;
}
-
function removeStorageEventListener(listener) {
window.removeEventListener('storage', listener);
}
-
function create(channelName, options) {
options = (0, _options.fillOptionsWithDefaults)(options);
-
if (!canBeUsed()) {
throw new Error('BroadcastChannel: localstorage cannot be used');
}
-
var uuid = (0, _util.randomToken)();
+
/**
* eMIs
* contains all messages that have been emitted before
* @type {ObliviousSet}
*/
-
var eMIs = new _obliviousSet.ObliviousSet(options.localstorage.removeTimeout);
var state = {
channelName: channelName,
uuid: uuid,
eMIs: eMIs // emittedMessagesIds
-
};
+
state.listener = addStorageEventListener(channelName, function (msgObj) {
if (!state.messagesCallback) return; // no listener
-
if (msgObj.uuid === uuid) return; // own message
-
if (!msgObj.token || eMIs.has(msgObj.token)) return; // already emitted
-
if (msgObj.data.time && msgObj.data.time < state.messagesCallbackTime) return; // too old
eMIs.add(msgObj.token);
@@ -1416,20 +1247,16 @@ function create(channelName, options) {
});
return state;
}
-
function close(channelState) {
removeStorageEventListener(channelState.listener);
}
-
function onMessage(channelState, fn, time) {
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
}
-
function canBeUsed() {
var ls = getLocalStorage();
if (!ls) return false;
-
try {
var key = '__broadcastchannel_check';
ls.setItem(key, 'works');
@@ -1440,22 +1267,17 @@ function canBeUsed() {
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API#Private_Browsing_Incognito_modes
return false;
}
-
return true;
}
-
function averageResponseTime() {
var defaultTime = 120;
var userAgent = navigator.userAgent.toLowerCase();
-
if (userAgent.includes('safari') && !userAgent.includes('chrome')) {
// safari is much slower so this time is higher
return defaultTime * 2;
}
-
return defaultTime;
}
-
var _default = {
create: create,
close: close,
@@ -1481,20 +1303,16 @@ exports.microSeconds = exports["default"] = void 0;
exports.onMessage = onMessage;
exports.postMessage = postMessage;
exports.type = void 0;
-
var _util = require("../util.js");
-
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var type = 'native';
exports.type = type;
-
function create(channelName) {
var state = {
messagesCallback: null,
bc: new BroadcastChannel(channelName),
subFns: [] // subscriberFunctions
-
};
state.bc.onmessage = function (msg) {
@@ -1502,15 +1320,12 @@ function create(channelName) {
state.messagesCallback(msg.data);
}
};
-
return state;
}
-
function close(channelState) {
channelState.bc.close();
channelState.subFns = [];
}
-
function postMessage(channelState, messageJson) {
try {
channelState.bc.postMessage(messageJson, false);
@@ -1519,31 +1334,25 @@ function postMessage(channelState, messageJson) {
return Promise.reject(err);
}
}
-
function onMessage(channelState, fn) {
channelState.messagesCallback = fn;
}
-
function canBeUsed() {
if (typeof window === 'undefined') {
return false;
}
-
if (typeof BroadcastChannel === 'function') {
if (BroadcastChannel._pubkey) {
throw new Error('BroadcastChannel: Do not overwrite window.BroadcastChannel with this module, this is not a polyfill');
}
-
return true;
} else {
return false;
}
}
-
function averageResponseTime() {
return 150;
}
-
var _default = {
create: create,
close: close,
@@ -1569,15 +1378,12 @@ exports.microSeconds = exports["default"] = void 0;
exports.onMessage = onMessage;
exports.postMessage = postMessage;
exports.type = void 0;
-
var _util = require("../util.js");
-
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var type = 'simulate';
exports.type = type;
var SIMULATE_CHANNELS = new Set();
-
function create(channelName) {
var state = {
name: channelName,
@@ -1586,11 +1392,9 @@ function create(channelName) {
SIMULATE_CHANNELS.add(state);
return state;
}
-
function close(channelState) {
SIMULATE_CHANNELS["delete"](channelState);
}
-
function postMessage(channelState, messageJson) {
return new Promise(function (res) {
return setTimeout(function () {
@@ -1608,19 +1412,15 @@ function postMessage(channelState, messageJson) {
}, 5);
});
}
-
function onMessage(channelState, fn) {
channelState.messagesCallback = fn;
}
-
function canBeUsed() {
return true;
}
-
function averageResponseTime() {
return 5;
}
-
var _default = {
create: create,
close: close,
@@ -1639,33 +1439,35 @@ Object.defineProperty(exports, "__esModule", {
value: true
});
exports.fillOptionsWithDefaults = fillOptionsWithDefaults;
-
function fillOptionsWithDefaults() {
var originalOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- var options = JSON.parse(JSON.stringify(originalOptions)); // main
-
- if (typeof options.webWorkerSupport === 'undefined') options.webWorkerSupport = true; // indexed-db
+ var options = JSON.parse(JSON.stringify(originalOptions));
- if (!options.idb) options.idb = {}; // after this time the messages get deleted
+ // main
+ if (typeof options.webWorkerSupport === 'undefined') options.webWorkerSupport = true;
+ // indexed-db
+ if (!options.idb) options.idb = {};
+ // after this time the messages get deleted
if (!options.idb.ttl) options.idb.ttl = 1000 * 45;
- if (!options.idb.fallbackInterval) options.idb.fallbackInterval = 150; // handles abrupt db onclose events.
-
- if (originalOptions.idb && typeof originalOptions.idb.onclose === 'function') options.idb.onclose = originalOptions.idb.onclose; // localstorage
+ if (!options.idb.fallbackInterval) options.idb.fallbackInterval = 150;
+ // handles abrupt db onclose events.
+ if (originalOptions.idb && typeof originalOptions.idb.onclose === 'function') options.idb.onclose = originalOptions.idb.onclose;
+ // localstorage
if (!options.localstorage) options.localstorage = {};
- if (!options.localstorage.removeTimeout) options.localstorage.removeTimeout = 1000 * 60; // custom methods
+ if (!options.localstorage.removeTimeout) options.localstorage.removeTimeout = 1000 * 60;
- if (originalOptions.methods) options.methods = originalOptions.methods; // node
+ // custom methods
+ if (originalOptions.methods) options.methods = originalOptions.methods;
+ // node
if (!options.node) options.node = {};
if (!options.node.ttl) options.node.ttl = 1000 * 60 * 2; // 2 minutes;
-
/**
* On linux use 'ulimit -Hn' to get the limit of open files.
* On ubuntu this was 4096 for me, so we use half of that as maxParallelWrites default.
*/
-
if (!options.node.maxParallelWrites) options.node.maxParallelWrites = 2048;
if (typeof options.node.useFastPath === 'undefined') options.node.useFastPath = true;
return options;
@@ -1682,7 +1484,6 @@ exports.microSeconds = microSeconds;
exports.randomInt = randomInt;
exports.randomToken = randomToken;
exports.sleep = sleep;
-
/**
* returns true if the given object is a promise
*/
@@ -1693,14 +1494,12 @@ function isPromise(obj) {
return false;
}
}
-
var PROMISE_RESOLVED_FALSE = Promise.resolve(false);
exports.PROMISE_RESOLVED_FALSE = PROMISE_RESOLVED_FALSE;
var PROMISE_RESOLVED_TRUE = Promise.resolve(true);
exports.PROMISE_RESOLVED_TRUE = PROMISE_RESOLVED_TRUE;
var PROMISE_RESOLVED_VOID = Promise.resolve();
exports.PROMISE_RESOLVED_VOID = PROMISE_RESOLVED_VOID;
-
function sleep(time, resolveWith) {
if (!time) time = 0;
return new Promise(function (res) {
@@ -1709,21 +1508,19 @@ function sleep(time, resolveWith) {
}, time);
});
}
-
function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
+
/**
* https://stackoverflow.com/a/8084248
*/
-
-
function randomToken() {
return Math.random().toString(36).substring(2);
}
-
var lastMs = 0;
var additional = 0;
+
/**
* returns the current time in micro-seconds,
* WARNING: This is a pseudo-function
@@ -1731,10 +1528,8 @@ var additional = 0;
* This is enough in browsers, and this function will not be used in nodejs.
* The main reason for this hack is to ensure that BroadcastChannel behaves equal to production when it is used in fast-running unit tests.
*/
-
function microSeconds() {
var ms = new Date().getTime();
-
if (ms === lastMs) {
additional++;
return ms * 1000 + additional;
@@ -1750,7 +1545,6 @@ function _interopRequireDefault(obj) {
"default": obj
};
}
-
module.exports = _interopRequireDefault, module.exports.__esModule = true, module.exports["default"] = module.exports;
},{}],14:[function(require,module,exports){
function _typeof(obj) {
@@ -1762,7 +1556,6 @@ function _typeof(obj) {
return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
}, module.exports.__esModule = true, module.exports["default"] = module.exports), _typeof(obj);
}
-
module.exports = _typeof, module.exports.__esModule = true, module.exports["default"] = module.exports;
},{}],15:[function(require,module,exports){
diff --git a/dist/lib/browser.min.js b/dist/lib/browser.min.js
index 0890b041..479b0a6e 100644
--- a/dist/lib/browser.min.js
+++ b/dist/lib/browser.min.js
@@ -1 +1 @@
-!function o(r,i,s){function a(t,e){if(!i[t]){if(!r[t]){var n="function"==typeof require&&require;if(!e&&n)return n(t,!0);if(u)return u(t,!0);throw(e=new Error("Cannot find module '"+t+"'")).code="MODULE_NOT_FOUND",e}n=i[t]={exports:{}},r[t][0].call(n.exports,function(e){return a(r[t][1][e]||e)},n,n.exports,o,r,i,s)}return i[t].exports}for(var u="function"==typeof require&&require,e=0;e=t&&e.fn(n.data)})},r=i.method.microSeconds(),i._prepP?i._prepP.then(function(){i._iL=!0,i.method.onMessage(i._state,o,r)}):(i._iL=!0,i.method.onMessage(i._state,o,r)))}function h(e,t,n){e._addEL[t]=e._addEL[t].filter(function(e){return e!==n});t=e;t._iL&&!l(t)&&(t._iL=!1,e=t.method.microSeconds(),t.method.onMessage(t._state,null,e))}(n.BroadcastChannel=o)._pubkey=!0,o.prototype={postMessage:function(e){if(this.closed)throw new Error("BroadcastChannel.postMessage(): Cannot post message after channel has closed "+JSON.stringify(e));return d(this,"message",e)},postInternal:function(e){return d(this,"internal",e)},set onmessage(e){var t={time:this.method.microSeconds(),fn:e};h(this,"message",this._onML),e&&"function"==typeof e?(this._onML=t,f(this,"message",t)):this._onML=null},addEventListener:function(e,t){var n=this.method.microSeconds();f(this,e,{time:n,fn:t})},removeEventListener:function(e,t){var n=this._addEL[e].find(function(e){return e.fn===t});h(this,e,n)},close:function(){var e,t=this;if(!this.closed)return u.delete(this),this.closed=!0,e=this._prepP||i.PROMISE_RESOLVED_VOID,this._onML=null,this._addEL.message=[],e.then(function(){return Promise.all(Array.from(t._uMP))}).then(function(){return Promise.all(t._befC.map(function(e){return e()}))}).then(function(){return t.method.close(t._state)})},get type(){return this.method.type},get isClosed(){return this.closed}}},{"./method-chooser.js":6,"./options.js":11,"./util.js":12}],2:[function(e,t,n){"use strict";var e=e("./index.es5.js"),o=e.BroadcastChannel,e=e.createLeaderElection;window.BroadcastChannel2=o,window.createLeaderElection=e},{"./index.es5.js":3}],3:[function(e,t,n){"use strict";e=e("./index.js");t.exports={BroadcastChannel:e.BroadcastChannel,createLeaderElection:e.createLeaderElection,clearNodeFolder:e.clearNodeFolder,enforceOptions:e.enforceOptions,beLeader:e.beLeader}},{"./index.js":4}],4:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),Object.defineProperty(n,"BroadcastChannel",{enumerable:!0,get:function(){return o.BroadcastChannel}}),Object.defineProperty(n,"OPEN_BROADCAST_CHANNELS",{enumerable:!0,get:function(){return o.OPEN_BROADCAST_CHANNELS}}),Object.defineProperty(n,"beLeader",{enumerable:!0,get:function(){return r.beLeader}}),Object.defineProperty(n,"clearNodeFolder",{enumerable:!0,get:function(){return o.clearNodeFolder}}),Object.defineProperty(n,"createLeaderElection",{enumerable:!0,get:function(){return r.createLeaderElection}}),Object.defineProperty(n,"enforceOptions",{enumerable:!0,get:function(){return o.enforceOptions}});var o=e("./broadcast-channel.js"),r=e("./leader-election.js")},{"./broadcast-channel.js":1,"./leader-election.js":5}],5:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.beLeader=d,n.createLeaderElection=function(e,t){if(e._leaderElector)throw new Error("BroadcastChannel already has a leader-elector");t=function(e,t){e=e||{};(e=JSON.parse(JSON.stringify(e))).fallbackInterval||(e.fallbackInterval=3e3);e.responseTime||(e.responseTime=t.method.averageResponseTime(t.options));return e}(t,e);var n=new r(e,t);return e._befC.push(function(){return n.die()}),e._leaderElector=n};var u=e("./util.js"),o=e("unload"),r=function(e,t){function n(e){"leader"===e.context&&("death"===e.action&&(o.hasLeader=!1),"tell"===e.action&&(o.hasLeader=!0))}var o=this;this.broadcastChannel=e,this._options=t,this.isLeader=!1,this.hasLeader=!1,this.isDead=!1,this.token=(0,u.randomToken)(),this._aplQ=u.PROMISE_RESOLVED_VOID,this._aplQC=0,this._unl=[],this._lstns=[],this._dpL=function(){},this._dpLC=!1;this.broadcastChannel.addEventListener("internal",n),this._lstns.push(n)};function c(e,t){t={context:"leader",action:t,token:e.token};return e.broadcastChannel.postInternal(t)}function d(t){t.isLeader=!0,t.hasLeader=!0;function e(e){"leader"===e.context&&"apply"===e.action&&c(t,"tell"),"leader"!==e.context||"tell"!==e.action||t._dpLC||(t._dpLC=!0,t._dpL(),c(t,"tell"))}var n=(0,o.add)(function(){return t.die()});t._unl.push(n);return t.broadcastChannel.addEventListener("internal",e),t._lstns.push(e),c(t,"tell")}r.prototype={applyOnce:function(s){var a=this;return this.isLeader?(0,u.sleep)(0,!0):this.isDead?(0,u.sleep)(0,!1):1a.token&&n(),"tell"===e.action&&(n(),a.hasLeader=!0))}),i=s?4*a._options.responseTime:a._options.responseTime,c(a,"apply").then(function(){return Promise.race([(0,u.sleep)(i),e.then(function(){return Promise.reject(new Error)})])}).then(function(){return c(a,"apply")}).then(function(){return Promise.race([(0,u.sleep)(i),e.then(function(){return Promise.reject(new Error)})])}).catch(function(){}).then(function(){return a.broadcastChannel.removeEventListener("internal",r),!t&&d(a).then(function(){return!0})}));var t,n,e,o,r,i}).then(function(){a._aplQC=a._aplQC-1}),this._aplQ.then(function(){return a.isLeader}))},awaitLeadership:function(){return this._aLP||(this._aLP=function(r){if(r.isLeader)return u.PROMISE_RESOLVED_VOID;return new Promise(function(e){var t=!1;function n(){t||(t=!0,r.broadcastChannel.removeEventListener("internal",o),e(!0))}r.applyOnce().then(function(){r.isLeader&&n()});(function e(){return(0,u.sleep)(r._options.fallbackInterval).then(function(){if(!r.isDead&&!t)return r.isLeader?void n():r.applyOnce(!0).then(function(){(r.isLeader?n:e)()})})})();var o=function(e){"leader"===e.context&&"death"===e.action&&(r.hasLeader=!1,r.applyOnce().then(function(){r.isLeader&&n()}))};r.broadcastChannel.addEventListener("internal",o),r._lstns.push(o)})}(this)),this._aLP},set onduplicate(e){this._dpL=e},die:function(){var t=this;return this._lstns.forEach(function(e){return t.broadcastChannel.removeEventListener("internal",e)}),this._lstns=[],this._unl.forEach(function(e){return e.remove()}),this._unl=[],this.isLeader&&(this.hasLeader=!1,this.isLeader=!1),this.isDead=!0,c(this,"death")}}},{"./util.js":12,unload:19}],6:[function(e,t,n){"use strict";var o=e("@babel/runtime/helpers/interopRequireDefault"),n=(e("@babel/runtime/helpers/typeof"),Object.defineProperty(n,"__esModule",{value:!0}),n.chooseMethod=function(t){var e=[].concat(t.methods,a).filter(Boolean);if(t.type){if("simulate"===t.type)return s.default;var n=e.find(function(e){return e.type===t.type});if(n)return n;throw new Error("method-type "+t.type+" not found")}t.webWorkerSupport||(e=e.filter(function(e){return"idb"!==e.type}));n=e.find(function(e){return e.canBeUsed()});{if(n)return n;throw new Error("No useable method found in "+JSON.stringify(a.map(function(e){return e.type})))}},o(e("./methods/native.js"))),r=o(e("./methods/indexed-db.js")),i=o(e("./methods/localstorage.js")),s=o(e("./methods/simulate.js"));var a=[n.default,r.default,i.default]},{"./methods/indexed-db.js":7,"./methods/localstorage.js":8,"./methods/native.js":9,"./methods/simulate.js":10,"@babel/runtime/helpers/interopRequireDefault":13,"@babel/runtime/helpers/typeof":14}],7:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.TRANSACTION_SETTINGS=void 0,n.averageResponseTime=w,n.canBeUsed=S,n.cleanOldMessages=v,n.close=g,n.commitIndexedDBTransaction=l,n.create=b,n.createDatabase=u,n.default=void 0,n.getAllMessages=function(e){var n=e.transaction(c,"readonly",d),o=n.objectStore(c),r=[];return new Promise(function(t){o.openCursor().onsuccess=function(e){e=e.target.result;e?(r.push(e.value),e.continue()):(l(n),t(r))}})},n.getIdb=a,n.getMessagesHigherThan=h,n.getOldMessages=m,n.microSeconds=void 0,n.onMessage=y,n.postMessage=E,n.removeMessagesById=p,n.type=void 0,n.writeMessage=f;var r=e("../util.js"),i=e("oblivious-set"),s=e("../options.js"),e=r.microSeconds,o=(n.microSeconds=e,"pubkey.broadcast-channel-0-"),c="messages",d={durability:"relaxed"};n.TRANSACTION_SETTINGS=d;function a(){if("undefined"!=typeof indexedDB)return indexedDB;if("undefined"!=typeof window){if(void 0!==window.mozIndexedDB)return window.mozIndexedDB;if(void 0!==window.webkitIndexedDB)return window.webkitIndexedDB;if(void 0!==window.msIndexedDB)return window.msIndexedDB}return!1}function l(e){e.commit&&e.commit()}function u(e){var n=a().open(o+e);return n.onupgradeneeded=function(e){e.target.result.createObjectStore(c,{keyPath:"id",autoIncrement:!0})},new Promise(function(e,t){n.onerror=function(e){return t(e)},n.onsuccess=function(){e(n.result)}})}function f(e,t,n){var o={uuid:t,time:(new Date).getTime(),data:n},r=e.transaction([c],"readwrite",d);return new Promise(function(e,t){r.oncomplete=function(){return e()},r.onerror=function(e){return t(e)},r.objectStore(c).add(o),l(r)})}function h(e,o){var r,i=e.transaction(c,"readonly",d),s=i.objectStore(c),a=[],u=IDBKeyRange.bound(o+1,1/0);return s.getAll?(r=s.getAll(u),new Promise(function(t,n){r.onerror=function(e){return n(e)},r.onsuccess=function(e){t(e.target.result)}})):new Promise(function(t,n){var e=function(){try{return u=IDBKeyRange.bound(o+1,1/0),s.openCursor(u)}catch(e){return s.openCursor()}}();e.onerror=function(e){return n(e)},e.onsuccess=function(e){e=e.target.result;e?e.value.idn.lastCursorId&&(n.lastCursorId=e.id),e}).filter(function(e){return t=n,(e=e).uuid!==t.uuid&&(!t.eMIs.has(e.id)&&!(e.data.time=t&&e.fn(n.data)})},r=i.method.microSeconds(),i._prepP?i._prepP.then(function(){i._iL=!0,i.method.onMessage(i._state,o,r)}):(i._iL=!0,i.method.onMessage(i._state,o,r)))}function h(e,t,n){e._addEL[t]=e._addEL[t].filter(function(e){return e!==n});t=e;t._iL&&!l(t)&&(t._iL=!1,e=t.method.microSeconds(),t.method.onMessage(t._state,null,e))}(n.BroadcastChannel=o)._pubkey=!0,o.prototype={postMessage:function(e){if(this.closed)throw new Error("BroadcastChannel.postMessage(): Cannot post message after channel has closed "+JSON.stringify(e));return d(this,"message",e)},postInternal:function(e){return d(this,"internal",e)},set onmessage(e){var t={time:this.method.microSeconds(),fn:e};h(this,"message",this._onML),e&&"function"==typeof e?(this._onML=t,f(this,"message",t)):this._onML=null},addEventListener:function(e,t){var n=this.method.microSeconds();f(this,e,{time:n,fn:t})},removeEventListener:function(e,t){var n=this._addEL[e].find(function(e){return e.fn===t});h(this,e,n)},close:function(){var e,t=this;if(!this.closed)return u.delete(this),this.closed=!0,e=this._prepP||i.PROMISE_RESOLVED_VOID,this._onML=null,this._addEL.message=[],e.then(function(){return Promise.all(Array.from(t._uMP))}).then(function(){return Promise.all(t._befC.map(function(e){return e()}))}).then(function(){return t.method.close(t._state)})},get type(){return this.method.type},get isClosed(){return this.closed}}},{"./method-chooser.js":6,"./options.js":11,"./util.js":12}],2:[function(e,t,n){"use strict";var e=e("./index.es5.js"),o=e.BroadcastChannel,e=e.createLeaderElection;window.BroadcastChannel2=o,window.createLeaderElection=e},{"./index.es5.js":3}],3:[function(e,t,n){"use strict";e=e("./index.js");t.exports={BroadcastChannel:e.BroadcastChannel,createLeaderElection:e.createLeaderElection,clearNodeFolder:e.clearNodeFolder,enforceOptions:e.enforceOptions,beLeader:e.beLeader}},{"./index.js":4}],4:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),Object.defineProperty(n,"BroadcastChannel",{enumerable:!0,get:function(){return o.BroadcastChannel}}),Object.defineProperty(n,"OPEN_BROADCAST_CHANNELS",{enumerable:!0,get:function(){return o.OPEN_BROADCAST_CHANNELS}}),Object.defineProperty(n,"beLeader",{enumerable:!0,get:function(){return r.beLeader}}),Object.defineProperty(n,"clearNodeFolder",{enumerable:!0,get:function(){return o.clearNodeFolder}}),Object.defineProperty(n,"createLeaderElection",{enumerable:!0,get:function(){return r.createLeaderElection}}),Object.defineProperty(n,"enforceOptions",{enumerable:!0,get:function(){return o.enforceOptions}});var o=e("./broadcast-channel.js"),r=e("./leader-election.js")},{"./broadcast-channel.js":1,"./leader-election.js":5}],5:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.beLeader=d,n.createLeaderElection=function(e,t){if(e._leaderElector)throw new Error("BroadcastChannel already has a leader-elector");t=function(e,t){e=e||{};(e=JSON.parse(JSON.stringify(e))).fallbackInterval||(e.fallbackInterval=3e3);e.responseTime||(e.responseTime=t.method.averageResponseTime(t.options));return e}(t,e);var n=new r(e,t);return e._befC.push(function(){return n.die()}),e._leaderElector=n};var u=e("./util.js"),o=e("unload"),r=function(e,t){function n(e){"leader"===e.context&&("death"===e.action&&(o.hasLeader=!1),"tell"===e.action)&&(o.hasLeader=!0)}var o=this;this.broadcastChannel=e,this._options=t,this.isLeader=!1,this.hasLeader=!1,this.isDead=!1,this.token=(0,u.randomToken)(),this._aplQ=u.PROMISE_RESOLVED_VOID,this._aplQC=0,this._unl=[],this._lstns=[],this._dpL=function(){},this._dpLC=!1;this.broadcastChannel.addEventListener("internal",n),this._lstns.push(n)};function c(e,t){t={context:"leader",action:t,token:e.token};return e.broadcastChannel.postInternal(t)}function d(t){t.isLeader=!0,t.hasLeader=!0;function e(e){"leader"===e.context&&"apply"===e.action&&c(t,"tell"),"leader"!==e.context||"tell"!==e.action||t._dpLC||(t._dpLC=!0,t._dpL(),c(t,"tell"))}var n=(0,o.add)(function(){return t.die()});t._unl.push(n);return t.broadcastChannel.addEventListener("internal",e),t._lstns.push(e),c(t,"tell")}r.prototype={applyOnce:function(s){var a=this;return this.isLeader?(0,u.sleep)(0,!0):this.isDead?(0,u.sleep)(0,!1):1a.token&&n(),"tell"===e.action)&&(n(),a.hasLeader=!0)}),i=s?4*a._options.responseTime:a._options.responseTime,c(a,"apply").then(function(){return Promise.race([(0,u.sleep)(i),e.then(function(){return Promise.reject(new Error)})])}).then(function(){return c(a,"apply")}).then(function(){return Promise.race([(0,u.sleep)(i),e.then(function(){return Promise.reject(new Error)})])}).catch(function(){}).then(function(){return a.broadcastChannel.removeEventListener("internal",r),!t&&d(a).then(function(){return!0})}));var t,n,e,o,r,i}).then(function(){a._aplQC=a._aplQC-1}),this._aplQ.then(function(){return a.isLeader}))},awaitLeadership:function(){return this._aLP||(this._aLP=function(r){if(r.isLeader)return u.PROMISE_RESOLVED_VOID;return new Promise(function(e){var t=!1;function n(){t||(t=!0,r.broadcastChannel.removeEventListener("internal",o),e(!0))}r.applyOnce().then(function(){r.isLeader&&n()});(function e(){return(0,u.sleep)(r._options.fallbackInterval).then(function(){if(!r.isDead&&!t)return r.isLeader?void n():r.applyOnce(!0).then(function(){(r.isLeader?n:e)()})})})();var o=function(e){"leader"===e.context&&"death"===e.action&&(r.hasLeader=!1,r.applyOnce().then(function(){r.isLeader&&n()}))};r.broadcastChannel.addEventListener("internal",o),r._lstns.push(o)})}(this)),this._aLP},set onduplicate(e){this._dpL=e},die:function(){var t=this;return this._lstns.forEach(function(e){return t.broadcastChannel.removeEventListener("internal",e)}),this._lstns=[],this._unl.forEach(function(e){return e.remove()}),this._unl=[],this.isLeader&&(this.hasLeader=!1,this.isLeader=!1),this.isDead=!0,c(this,"death")}}},{"./util.js":12,unload:19}],6:[function(e,t,n){"use strict";var o=e("@babel/runtime/helpers/interopRequireDefault"),n=(e("@babel/runtime/helpers/typeof"),Object.defineProperty(n,"__esModule",{value:!0}),n.chooseMethod=function(t){var e=[].concat(t.methods,a).filter(Boolean);if(t.type){if("simulate"===t.type)return s.default;var n=e.find(function(e){return e.type===t.type});if(n)return n;throw new Error("method-type "+t.type+" not found")}t.webWorkerSupport||(e=e.filter(function(e){return"idb"!==e.type}));n=e.find(function(e){return e.canBeUsed()});{if(n)return n;throw new Error("No useable method found in "+JSON.stringify(a.map(function(e){return e.type})))}},o(e("./methods/native.js"))),r=o(e("./methods/indexed-db.js")),i=o(e("./methods/localstorage.js")),s=o(e("./methods/simulate.js"));var a=[n.default,r.default,i.default]},{"./methods/indexed-db.js":7,"./methods/localstorage.js":8,"./methods/native.js":9,"./methods/simulate.js":10,"@babel/runtime/helpers/interopRequireDefault":13,"@babel/runtime/helpers/typeof":14}],7:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.TRANSACTION_SETTINGS=void 0,n.averageResponseTime=w,n.canBeUsed=S,n.cleanOldMessages=v,n.close=g,n.commitIndexedDBTransaction=l,n.create=b,n.createDatabase=u,n.default=void 0,n.getAllMessages=function(e){var n=e.transaction(c,"readonly",d),o=n.objectStore(c),r=[];return new Promise(function(t){o.openCursor().onsuccess=function(e){e=e.target.result;e?(r.push(e.value),e.continue()):(l(n),t(r))}})},n.getIdb=a,n.getMessagesHigherThan=h,n.getOldMessages=m,n.microSeconds=void 0,n.onMessage=y,n.postMessage=E,n.removeMessagesById=p,n.type=void 0,n.writeMessage=f;var r=e("../util.js"),i=e("oblivious-set"),s=e("../options.js"),e=r.microSeconds,o=(n.microSeconds=e,"pubkey.broadcast-channel-0-"),c="messages",d={durability:"relaxed"};n.TRANSACTION_SETTINGS=d;function a(){if("undefined"!=typeof indexedDB)return indexedDB;if("undefined"!=typeof window){if(void 0!==window.mozIndexedDB)return window.mozIndexedDB;if(void 0!==window.webkitIndexedDB)return window.webkitIndexedDB;if(void 0!==window.msIndexedDB)return window.msIndexedDB}return!1}function l(e){e.commit&&e.commit()}function u(e){var n=a().open(o+e);return n.onupgradeneeded=function(e){e.target.result.createObjectStore(c,{keyPath:"id",autoIncrement:!0})},new Promise(function(e,t){n.onerror=function(e){return t(e)},n.onsuccess=function(){e(n.result)}})}function f(e,t,n){var o={uuid:t,time:(new Date).getTime(),data:n},r=e.transaction([c],"readwrite",d);return new Promise(function(e,t){r.oncomplete=function(){return e()},r.onerror=function(e){return t(e)},r.objectStore(c).add(o),l(r)})}function h(e,o){var r,i=e.transaction(c,"readonly",d),s=i.objectStore(c),a=[],u=IDBKeyRange.bound(o+1,1/0);return s.getAll?(r=s.getAll(u),new Promise(function(t,n){r.onerror=function(e){return n(e)},r.onsuccess=function(e){t(e.target.result)}})):new Promise(function(t,n){var e=function(){try{return u=IDBKeyRange.bound(o+1,1/0),s.openCursor(u)}catch(e){return s.openCursor()}}();e.onerror=function(e){return n(e)},e.onsuccess=function(e){e=e.target.result;e?e.value.idn.lastCursorId&&(n.lastCursorId=e.id),e}).filter(function(e){return t=n,(e=e).uuid!==t.uuid&&!(t.eMIs.has(e.id)||e.data.time wait for the apply queue to be finished.
*/
-
-
if (this._aplQC > 1) {
return this._aplQ;
}
+
/**
* Add a new apply-run
*/
-
-
var applyRun = function applyRun() {
/**
* Optimization shortcuts.
@@ -101,7 +86,6 @@ LeaderElection.prototype = {
if (_this2.isLeader) {
return _util.PROMISE_RESOLVED_TRUE;
}
-
var stopCriteria = false;
var stopCriteriaPromiseResolve;
/**
@@ -110,7 +94,6 @@ LeaderElection.prototype = {
* have to await the responseTime when it is already clear
* that the election failed.
*/
-
var stopCriteriaPromise = new Promise(function (res) {
stopCriteriaPromiseResolve = function stopCriteriaPromiseResolve() {
stopCriteria = true;
@@ -118,11 +101,9 @@ LeaderElection.prototype = {
};
});
var recieved = [];
-
var handleMessage = function handleMessage(msg) {
if (msg.context === 'leader' && msg.token != _this2.token) {
recieved.push(msg);
-
if (msg.action === 'apply') {
// other is applying
if (msg.token > _this2.token) {
@@ -133,7 +114,6 @@ LeaderElection.prototype = {
stopCriteriaPromiseResolve();
}
}
-
if (msg.action === 'tell') {
// other is already leader
stopCriteriaPromiseResolve();
@@ -141,8 +121,8 @@ LeaderElection.prototype = {
}
}
};
-
_this2.broadcastChannel.addEventListener('internal', handleMessage);
+
/**
* If the applyOnce() call came from the fallbackInterval,
* we can assume that the election runs in the background and
@@ -153,26 +133,24 @@ LeaderElection.prototype = {
* But also it takes longer which is not a problem because we anyway
* run in the background.
*/
-
-
var waitForAnswerTime = isFromFallbackInterval ? _this2._options.responseTime * 4 : _this2._options.responseTime;
-
var applyPromise = _sendMessage(_this2, 'apply') // send out that this one is applying
.then(function () {
return Promise.race([(0, _util.sleep)(waitForAnswerTime), stopCriteriaPromise.then(function () {
return Promise.reject(new Error());
})]);
- }) // send again in case another instance was just created
+ })
+ // send again in case another instance was just created
.then(function () {
return _sendMessage(_this2, 'apply');
- }) // let others time to respond
+ })
+ // let others time to respond
.then(function () {
return Promise.race([(0, _util.sleep)(waitForAnswerTime), stopCriteriaPromise.then(function () {
return Promise.reject(new Error());
})]);
})["catch"](function () {}).then(function () {
_this2.broadcastChannel.removeEventListener('internal', handleMessage);
-
if (!stopCriteria) {
// no stop criteria -> own is leader
return beLeader(_this2).then(function () {
@@ -183,10 +161,8 @@ LeaderElection.prototype = {
return false;
}
});
-
return applyPromise;
};
-
this._aplQC = this._aplQC + 1;
this._aplQ = this._aplQ.then(function () {
return applyRun();
@@ -198,82 +174,68 @@ LeaderElection.prototype = {
});
},
awaitLeadership: function awaitLeadership() {
- if (
- /* _awaitLeadershipPromise */
+ if ( /* _awaitLeadershipPromise */
!this._aLP) {
this._aLP = _awaitLeadershipOnce(this);
}
-
return this._aLP;
},
-
set onduplicate(fn) {
this._dpL = fn;
},
-
die: function die() {
var _this3 = this;
-
this._lstns.forEach(function (listener) {
return _this3.broadcastChannel.removeEventListener('internal', listener);
});
-
this._lstns = [];
-
this._unl.forEach(function (uFn) {
return uFn.remove();
});
-
this._unl = [];
-
if (this.isLeader) {
this.hasLeader = false;
this.isLeader = false;
}
-
this.isDead = true;
return _sendMessage(this, 'death');
}
};
+
/**
* @param leaderElector {LeaderElector}
*/
-
function _awaitLeadershipOnce(leaderElector) {
if (leaderElector.isLeader) {
return _util.PROMISE_RESOLVED_VOID;
}
-
return new Promise(function (res) {
var resolved = false;
-
function finish() {
if (resolved) {
return;
}
-
resolved = true;
leaderElector.broadcastChannel.removeEventListener('internal', whenDeathListener);
res(true);
- } // try once now
-
+ }
+ // try once now
leaderElector.applyOnce().then(function () {
if (leaderElector.isLeader) {
finish();
}
});
+
/**
* Try on fallbackInterval
* @recursive
*/
-
var tryOnFallBack = function tryOnFallBack() {
return (0, _util.sleep)(leaderElector._options.fallbackInterval).then(function () {
if (leaderElector.isDead || resolved) {
return;
}
-
if (leaderElector.isLeader) {
finish();
} else {
@@ -287,9 +249,9 @@ function _awaitLeadershipOnce(leaderElector) {
}
});
};
+ tryOnFallBack();
- tryOnFallBack(); // try when other leader dies
-
+ // try when other leader dies
var whenDeathListener = function whenDeathListener(msg) {
if (msg.context === 'leader' && msg.action === 'death') {
leaderElector.hasLeader = false;
@@ -300,17 +262,14 @@ function _awaitLeadershipOnce(leaderElector) {
});
}
};
-
leaderElector.broadcastChannel.addEventListener('internal', whenDeathListener);
-
leaderElector._lstns.push(whenDeathListener);
});
}
+
/**
* sends and internal message over the broadcast-channel
*/
-
-
function _sendMessage(leaderElector, action) {
var msgJson = {
context: 'leader',
@@ -319,21 +278,17 @@ function _sendMessage(leaderElector, action) {
};
return leaderElector.broadcastChannel.postInternal(msgJson);
}
-
function beLeader(leaderElector) {
leaderElector.isLeader = true;
leaderElector.hasLeader = true;
var unloadFn = (0, _unload.add)(function () {
return leaderElector.die();
});
-
leaderElector._unl.push(unloadFn);
-
var isLeaderListener = function isLeaderListener(msg) {
if (msg.context === 'leader' && msg.action === 'apply') {
_sendMessage(leaderElector, 'tell');
}
-
if (msg.context === 'leader' && msg.action === 'tell' && !leaderElector._dpLC) {
/**
* another instance is also leader!
@@ -344,49 +299,35 @@ function beLeader(leaderElector) {
* @link https://github.com/pubkey/broadcast-channel/issues/385
*/
leaderElector._dpLC = true;
-
leaderElector._dpL(); // message the lib user so the app can handle the problem
-
-
_sendMessage(leaderElector, 'tell'); // ensure other leader also knows the problem
-
}
};
leaderElector.broadcastChannel.addEventListener('internal', isLeaderListener);
-
leaderElector._lstns.push(isLeaderListener);
-
return _sendMessage(leaderElector, 'tell');
}
-
function fillOptionsWithDefaults(options, channel) {
if (!options) options = {};
options = JSON.parse(JSON.stringify(options));
-
if (!options.fallbackInterval) {
options.fallbackInterval = 3000;
}
-
if (!options.responseTime) {
options.responseTime = channel.method.averageResponseTime(channel.options);
}
-
return options;
}
-
function createLeaderElection(channel, options) {
if (channel._leaderElector) {
throw new Error('BroadcastChannel already has a leader-elector');
}
-
options = fillOptionsWithDefaults(options, channel);
var elector = new LeaderElection(channel, options);
-
channel._befC.push(function () {
return elector.die();
});
-
channel._leaderElector = elector;
return elector;
}
\ No newline at end of file
diff --git a/dist/lib/method-chooser.js b/dist/lib/method-chooser.js
index 26cd096f..6b7dd32f 100644
--- a/dist/lib/method-chooser.js
+++ b/dist/lib/method-chooser.js
@@ -1,59 +1,49 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
-
var _typeof = require("@babel/runtime/helpers/typeof");
-
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.chooseMethod = chooseMethod;
-
var _native = _interopRequireDefault(require("./methods/native.js"));
-
var _indexedDb = _interopRequireDefault(require("./methods/indexed-db.js"));
-
var _localstorage = _interopRequireDefault(require("./methods/localstorage.js"));
-
var _simulate = _interopRequireDefault(require("./methods/simulate.js"));
-
-
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
-
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
-
// the line below will be removed from es5/browser builds
+
// order is important
-var METHODS = [_native["default"], // fastest
+var METHODS = [_native["default"],
+// fastest
_indexedDb["default"], _localstorage["default"]];
-
function chooseMethod(options) {
- var chooseMethods = [].concat(options.methods, METHODS).filter(Boolean); // the line below will be removed from es5/browser builds
+ var chooseMethods = [].concat(options.methods, METHODS).filter(Boolean);
+ // the line below will be removed from es5/browser builds
+ // directly chosen
if (options.type) {
if (options.type === 'simulate') {
// only use simulate-method if directly chosen
return _simulate["default"];
}
-
var ret = chooseMethods.find(function (m) {
return m.type === options.type;
});
if (!ret) throw new Error('method-type ' + options.type + ' not found');else return ret;
}
+
/**
* if no webworker support is needed,
* remove idb from the list so that localstorage is been chosen
*/
-
-
if (!options.webWorkerSupport) {
chooseMethods = chooseMethods.filter(function (m) {
return m.type !== 'idb';
});
}
-
var useMethod = chooseMethods.find(function (method) {
return method.canBeUsed();
});
diff --git a/dist/lib/methods/indexed-db.js b/dist/lib/methods/indexed-db.js
index dc38ebe8..b3b21767 100644
--- a/dist/lib/methods/indexed-db.js
+++ b/dist/lib/methods/indexed-db.js
@@ -22,13 +22,9 @@ exports.postMessage = postMessage;
exports.removeMessagesById = removeMessagesById;
exports.type = void 0;
exports.writeMessage = writeMessage;
-
var _util = require("../util.js");
-
var _obliviousSet = require("oblivious-set");
-
var _options = require("../options.js");
-
/**
* this method uses indexeddb to store the messages
* There is currently no observerAPI for idb
@@ -37,58 +33,54 @@ var _options = require("../options.js");
* When working on this, ensure to use these performance optimizations:
* @link https://rxdb.info/slow-indexeddb.html
*/
+
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var DB_PREFIX = 'pubkey.broadcast-channel-0-';
var OBJECT_STORE_ID = 'messages';
+
/**
* Use relaxed durability for faster performance on all transactions.
* @link https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/
*/
-
var TRANSACTION_SETTINGS = {
durability: 'relaxed'
};
exports.TRANSACTION_SETTINGS = TRANSACTION_SETTINGS;
var type = 'idb';
exports.type = type;
-
function getIdb() {
if (typeof indexedDB !== 'undefined') return indexedDB;
-
if (typeof window !== 'undefined') {
if (typeof window.mozIndexedDB !== 'undefined') return window.mozIndexedDB;
if (typeof window.webkitIndexedDB !== 'undefined') return window.webkitIndexedDB;
if (typeof window.msIndexedDB !== 'undefined') return window.msIndexedDB;
}
-
return false;
}
+
/**
* If possible, we should explicitly commit IndexedDB transactions
* for better performance.
* @link https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/
*/
-
-
function commitIndexedDBTransaction(tx) {
if (tx.commit) {
tx.commit();
}
}
-
function createDatabase(channelName) {
- var IndexedDB = getIdb(); // create table
+ var IndexedDB = getIdb();
+ // create table
var dbName = DB_PREFIX + channelName;
+
/**
* All IndexedDB databases are opened without version
* because it is a bit faster, especially on firefox
* @link http://nparashuram.com/IndexedDB/perf/#Open%20Database%20with%20version
*/
-
var openRequest = IndexedDB.open(dbName);
-
openRequest.onupgradeneeded = function (ev) {
var db = ev.target.result;
db.createObjectStore(OBJECT_STORE_ID, {
@@ -96,24 +88,21 @@ function createDatabase(channelName) {
autoIncrement: true
});
};
-
var dbPromise = new Promise(function (res, rej) {
openRequest.onerror = function (ev) {
return rej(ev);
};
-
openRequest.onsuccess = function () {
res(openRequest.result);
};
});
return dbPromise;
}
+
/**
* writes the new message to the database
* so other readers can find it
*/
-
-
function writeMessage(db, readerUuid, messageJson) {
var time = new Date().getTime();
var writeObject = {
@@ -126,17 +115,14 @@ function writeMessage(db, readerUuid, messageJson) {
tx.oncomplete = function () {
return res();
};
-
tx.onerror = function (ev) {
return rej(ev);
};
-
var objectStore = tx.objectStore(OBJECT_STORE_ID);
objectStore.add(writeObject);
commitIndexedDBTransaction(tx);
});
}
-
function getAllMessages(db) {
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS);
var objectStore = tx.objectStore(OBJECT_STORE_ID);
@@ -144,10 +130,9 @@ function getAllMessages(db) {
return new Promise(function (res) {
objectStore.openCursor().onsuccess = function (ev) {
var cursor = ev.target.result;
-
if (cursor) {
- ret.push(cursor.value); //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
-
+ ret.push(cursor.value);
+ //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor["continue"]();
} else {
commitIndexedDBTransaction(tx);
@@ -156,31 +141,28 @@ function getAllMessages(db) {
};
});
}
-
function getMessagesHigherThan(db, lastCursorId) {
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS);
var objectStore = tx.objectStore(OBJECT_STORE_ID);
var ret = [];
var keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity);
+
/**
* Optimization shortcut,
* if getAll() can be used, do not use a cursor.
* @link https://rxdb.info/slow-indexeddb.html
*/
-
if (objectStore.getAll) {
var getAllRequest = objectStore.getAll(keyRangeValue);
return new Promise(function (res, rej) {
getAllRequest.onerror = function (err) {
return rej(err);
};
-
getAllRequest.onsuccess = function (e) {
res(e.target.result);
};
});
}
-
function openCursor() {
// Occasionally Safari will fail on IDBKeyRange.bound, this
// catches that error, having it open the cursor to the first
@@ -192,17 +174,13 @@ function getMessagesHigherThan(db, lastCursorId) {
return objectStore.openCursor();
}
}
-
return new Promise(function (res, rej) {
var openCursorRequest = openCursor();
-
openCursorRequest.onerror = function (err) {
return rej(err);
};
-
openCursorRequest.onsuccess = function (ev) {
var cursor = ev.target.result;
-
if (cursor) {
if (cursor.value.id < lastCursorId + 1) {
cursor["continue"](lastCursorId + 1);
@@ -217,12 +195,10 @@ function getMessagesHigherThan(db, lastCursorId) {
};
});
}
-
function removeMessagesById(channelState, ids) {
if (channelState.closed) {
return Promise.resolve([]);
}
-
var tx = channelState.db.transaction(OBJECT_STORE_ID, 'readwrite', TRANSACTION_SETTINGS);
var objectStore = tx.objectStore(OBJECT_STORE_ID);
return Promise.all(ids.map(function (id) {
@@ -234,7 +210,6 @@ function removeMessagesById(channelState, ids) {
});
}));
}
-
function getOldMessages(db, ttl) {
var olderThen = new Date().getTime() - ttl;
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS);
@@ -243,13 +218,11 @@ function getOldMessages(db, ttl) {
return new Promise(function (res) {
objectStore.openCursor().onsuccess = function (ev) {
var cursor = ev.target.result;
-
if (cursor) {
var msgObk = cursor.value;
-
if (msgObk.time < olderThen) {
- ret.push(msgObk); //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
-
+ ret.push(msgObk);
+ //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor["continue"]();
} else {
// no more old messages,
@@ -263,7 +236,6 @@ function getOldMessages(db, ttl) {
};
});
}
-
function cleanOldMessages(channelState) {
return getOldMessages(channelState.db, channelState.options.idb.ttl).then(function (tooOld) {
return removeMessagesById(channelState, tooOld.map(function (msg) {
@@ -271,7 +243,6 @@ function cleanOldMessages(channelState) {
}));
});
}
-
function create(channelName, options) {
options = (0, _options.fillOptionsWithDefaults)(options);
return createDatabase(channelName).then(function (db) {
@@ -281,7 +252,6 @@ function create(channelName, options) {
channelName: channelName,
options: options,
uuid: (0, _util.randomToken)(),
-
/**
* emittedMessagesIds
* contains all messages that have been emitted before
@@ -294,30 +264,27 @@ function create(channelName, options) {
readQueuePromises: [],
db: db
};
+
/**
* Handle abrupt closes that do not originate from db.close().
* This could happen, for example, if the underlying storage is
* removed or if the user clears the database in the browser's
* history preferences.
*/
-
db.onclose = function () {
state.closed = true;
if (options.idb.onclose) options.idb.onclose();
};
+
/**
* if service-workers are used,
* we have no 'storage'-event if they post a message,
* therefore we also have to set an interval
*/
-
-
_readLoop(state);
-
return state;
});
}
-
function _readLoop(state) {
if (state.closed) return;
readNewMessages(state).then(function () {
@@ -326,25 +293,21 @@ function _readLoop(state) {
return _readLoop(state);
});
}
-
function _filterMessage(msgObj, state) {
if (msgObj.uuid === state.uuid) return false; // send by own
-
if (state.eMIs.has(msgObj.id)) return false; // already emitted
-
if (msgObj.data.time < state.messagesCallbackTime) return false; // older then onMessageCallback
-
return true;
}
+
/**
* reads all new messages from the database and emits them
*/
-
-
function readNewMessages(state) {
// channel already closed
- if (state.closed) return _util.PROMISE_RESOLVED_VOID; // if no one is listening, we do not need to scan for new messages
+ if (state.closed) return _util.PROMISE_RESOLVED_VOID;
+ // if no one is listening, we do not need to scan for new messages
if (!state.messagesCallback) return _util.PROMISE_RESOLVED_VOID;
return getMessagesHigherThan(state.db, state.lastCursorId).then(function (newerMessages) {
var useMessages = newerMessages
@@ -352,21 +315,18 @@ function readNewMessages(state) {
* there is a bug in iOS where the msgObj can be undefined some times
* so we filter them out
* @link https://github.com/pubkey/broadcast-channel/issues/19
- */
- .filter(function (msgObj) {
+ */.filter(function (msgObj) {
return !!msgObj;
}).map(function (msgObj) {
if (msgObj.id > state.lastCursorId) {
state.lastCursorId = msgObj.id;
}
-
return msgObj;
}).filter(function (msgObj) {
return _filterMessage(msgObj, state);
}).sort(function (msgObjA, msgObjB) {
return msgObjA.time - msgObjB.time;
}); // sort by time
-
useMessages.forEach(function (msgObj) {
if (state.messagesCallback) {
state.eMIs.add(msgObj.id);
@@ -376,12 +336,10 @@ function readNewMessages(state) {
return _util.PROMISE_RESOLVED_VOID;
});
}
-
function close(channelState) {
channelState.closed = true;
channelState.db.close();
}
-
function postMessage(channelState, messageJson) {
channelState.writeBlockPromise = channelState.writeBlockPromise.then(function () {
return writeMessage(channelState.db, channelState.uuid, messageJson);
@@ -393,27 +351,21 @@ function postMessage(channelState, messageJson) {
});
return channelState.writeBlockPromise;
}
-
function onMessage(channelState, fn, time) {
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
readNewMessages(channelState);
}
-
function canBeUsed() {
var idb = getIdb();
-
if (!idb) {
return false;
}
-
return true;
}
-
function averageResponseTime(options) {
return options.idb.fallbackInterval * 2;
}
-
var _default = {
create: create,
close: close,
diff --git a/dist/lib/methods/localstorage.js b/dist/lib/methods/localstorage.js
index 1f308a9f..0a3d58bb 100644
--- a/dist/lib/methods/localstorage.js
+++ b/dist/lib/methods/localstorage.js
@@ -16,13 +16,9 @@ exports.postMessage = postMessage;
exports.removeStorageEventListener = removeStorageEventListener;
exports.storageKey = storageKey;
exports.type = void 0;
-
var _obliviousSet = require("oblivious-set");
-
var _options = require("../options.js");
-
var _util = require("../util.js");
-
/**
* A localStorage-only method which uses localstorage and its 'storage'-event
* This does not work inside of webworkers because they have no access to locastorage
@@ -30,41 +26,38 @@ var _util = require("../util.js");
* @link https://caniuse.com/#feat=namevalue-storage
* @link https://caniuse.com/#feat=indexeddb
*/
+
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var KEY_PREFIX = 'pubkey.broadcastChannel-';
var type = 'localstorage';
+
/**
* copied from crosstab
* @link https://github.com/tejacques/crosstab/blob/master/src/crosstab.js#L32
*/
-
exports.type = type;
-
function getLocalStorage() {
var localStorage;
if (typeof window === 'undefined') return null;
-
try {
localStorage = window.localStorage;
localStorage = window['ie8-eventlistener/storage'] || window.localStorage;
- } catch (e) {// New versions of Firefox throw a Security exception
+ } catch (e) {
+ // New versions of Firefox throw a Security exception
// if cookies are disabled. See
// https://bugzilla.mozilla.org/show_bug.cgi?id=1028153
}
-
return localStorage;
}
-
function storageKey(channelName) {
return KEY_PREFIX + channelName;
}
+
/**
* writes the new message to the storage
* and fires the storage-event so other readers can find it
*/
-
-
function postMessage(channelState, messageJson) {
return new Promise(function (res) {
(0, _util.sleep)().then(function () {
@@ -77,12 +70,12 @@ function postMessage(channelState, messageJson) {
};
var value = JSON.stringify(writeObj);
getLocalStorage().setItem(key, value);
+
/**
* StorageEvent does not fire the 'storage' event
* in the window that changes the state of the local storage.
* So we fire it manually
*/
-
var ev = document.createEvent('Event');
ev.initEvent('storage', true, true);
ev.key = key;
@@ -92,52 +85,42 @@ function postMessage(channelState, messageJson) {
});
});
}
-
function addStorageEventListener(channelName, fn) {
var key = storageKey(channelName);
-
var listener = function listener(ev) {
if (ev.key === key) {
fn(JSON.parse(ev.newValue));
}
};
-
window.addEventListener('storage', listener);
return listener;
}
-
function removeStorageEventListener(listener) {
window.removeEventListener('storage', listener);
}
-
function create(channelName, options) {
options = (0, _options.fillOptionsWithDefaults)(options);
-
if (!canBeUsed()) {
throw new Error('BroadcastChannel: localstorage cannot be used');
}
-
var uuid = (0, _util.randomToken)();
+
/**
* eMIs
* contains all messages that have been emitted before
* @type {ObliviousSet}
*/
-
var eMIs = new _obliviousSet.ObliviousSet(options.localstorage.removeTimeout);
var state = {
channelName: channelName,
uuid: uuid,
eMIs: eMIs // emittedMessagesIds
-
};
+
state.listener = addStorageEventListener(channelName, function (msgObj) {
if (!state.messagesCallback) return; // no listener
-
if (msgObj.uuid === uuid) return; // own message
-
if (!msgObj.token || eMIs.has(msgObj.token)) return; // already emitted
-
if (msgObj.data.time && msgObj.data.time < state.messagesCallbackTime) return; // too old
eMIs.add(msgObj.token);
@@ -145,20 +128,16 @@ function create(channelName, options) {
});
return state;
}
-
function close(channelState) {
removeStorageEventListener(channelState.listener);
}
-
function onMessage(channelState, fn, time) {
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
}
-
function canBeUsed() {
var ls = getLocalStorage();
if (!ls) return false;
-
try {
var key = '__broadcastchannel_check';
ls.setItem(key, 'works');
@@ -169,22 +148,17 @@ function canBeUsed() {
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API#Private_Browsing_Incognito_modes
return false;
}
-
return true;
}
-
function averageResponseTime() {
var defaultTime = 120;
var userAgent = navigator.userAgent.toLowerCase();
-
if (userAgent.includes('safari') && !userAgent.includes('chrome')) {
// safari is much slower so this time is higher
return defaultTime * 2;
}
-
return defaultTime;
}
-
var _default = {
create: create,
close: close,
diff --git a/dist/lib/methods/native.js b/dist/lib/methods/native.js
index 8118f760..cabcfb3e 100644
--- a/dist/lib/methods/native.js
+++ b/dist/lib/methods/native.js
@@ -11,20 +11,16 @@ exports.microSeconds = exports["default"] = void 0;
exports.onMessage = onMessage;
exports.postMessage = postMessage;
exports.type = void 0;
-
var _util = require("../util.js");
-
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var type = 'native';
exports.type = type;
-
function create(channelName) {
var state = {
messagesCallback: null,
bc: new BroadcastChannel(channelName),
subFns: [] // subscriberFunctions
-
};
state.bc.onmessage = function (msg) {
@@ -32,15 +28,12 @@ function create(channelName) {
state.messagesCallback(msg.data);
}
};
-
return state;
}
-
function close(channelState) {
channelState.bc.close();
channelState.subFns = [];
}
-
function postMessage(channelState, messageJson) {
try {
channelState.bc.postMessage(messageJson, false);
@@ -49,31 +42,25 @@ function postMessage(channelState, messageJson) {
return Promise.reject(err);
}
}
-
function onMessage(channelState, fn) {
channelState.messagesCallback = fn;
}
-
function canBeUsed() {
if (typeof window === 'undefined') {
return false;
}
-
if (typeof BroadcastChannel === 'function') {
if (BroadcastChannel._pubkey) {
throw new Error('BroadcastChannel: Do not overwrite window.BroadcastChannel with this module, this is not a polyfill');
}
-
return true;
} else {
return false;
}
}
-
function averageResponseTime() {
return 150;
}
-
var _default = {
create: create,
close: close,
diff --git a/dist/lib/methods/node.js b/dist/lib/methods/node.js
index a3aa3c7e..76d38bc5 100644
--- a/dist/lib/methods/node.js
+++ b/dist/lib/methods/node.js
@@ -1,7 +1,6 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
-
Object.defineProperty(exports, "__esModule", {
value: true
});
@@ -35,37 +34,21 @@ exports.socketInfoPath = socketInfoPath;
exports.socketPath = socketPath;
exports.type = void 0;
exports.writeMessage = writeMessage;
-
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
-
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
-
var _util = _interopRequireDefault(require("util"));
-
var _fs = _interopRequireDefault(require("fs"));
-
var _crypto = _interopRequireDefault(require("crypto"));
-
var _os = _interopRequireDefault(require("os"));
-
var _events = _interopRequireDefault(require("events"));
-
var _net = _interopRequireDefault(require("net"));
-
var _path = _interopRequireDefault(require("path"));
-
var _rimraf = _interopRequireDefault(require("rimraf"));
-
var _pQueue = _interopRequireDefault(require("p-queue"));
-
var _unload = require("unload");
-
var _options = require("../options.js");
-
var _util2 = require("../util.js");
-
var _obliviousSet = require("oblivious-set");
-
/**
* this method is used in nodejs-environments.
* The ipc is handled via sockets and file-writes to the tmp-folder
@@ -84,29 +67,18 @@ function cleanPipeName(str) {
return str;
}
}
-
var mkdir = _util["default"].promisify(_fs["default"].mkdir);
-
var writeFile = _util["default"].promisify(_fs["default"].writeFile);
-
var readFile = _util["default"].promisify(_fs["default"].readFile);
-
var unlink = _util["default"].promisify(_fs["default"].unlink);
-
var readdir = _util["default"].promisify(_fs["default"].readdir);
-
var chmod = _util["default"].promisify(_fs["default"].chmod);
-
var removeDir = _util["default"].promisify(_rimraf["default"]);
-
var OTHER_INSTANCES = {};
var TMP_FOLDER_NAME = 'pubkey.bc';
-
var TMP_FOLDER_BASE = _path["default"].join(_os["default"].tmpdir(), TMP_FOLDER_NAME);
-
exports.TMP_FOLDER_BASE = TMP_FOLDER_BASE;
var getPathsCache = new Map();
-
function getPaths(channelName) {
if (!getPathsCache.has(channelName)) {
/**
@@ -116,21 +88,16 @@ function getPaths(channelName) {
* in using the same folders for different channels.
*/
var channelHash = _crypto["default"].createHash('sha256').update(channelName).digest('hex');
+
/**
* because the length of socket-paths is limited, we use only the first 20 chars
* and also start with A to ensure we do not start with a number
* @link https://serverfault.com/questions/641347/check-if-a-path-exceeds-maximum-for-unix-domain-socket
*/
-
-
var channelFolder = 'A' + channelHash.substring(0, 20);
-
var channelPathBase = _path["default"].join(TMP_FOLDER_BASE, channelFolder);
-
var folderPathReaders = _path["default"].join(channelPathBase, 'rdrs');
-
var folderPathMessages = _path["default"].join(channelPathBase, 'msgs');
-
var ret = {
channelBase: channelPathBase,
readers: folderPathReaders,
@@ -139,16 +106,12 @@ function getPaths(channelName) {
getPathsCache.set(channelName, ret);
return ret;
}
-
return getPathsCache.get(channelName);
}
-
var ENSURE_BASE_FOLDER_EXISTS_PROMISE = null;
-
function ensureBaseFolderExists() {
return _ensureBaseFolderExists.apply(this, arguments);
}
-
function _ensureBaseFolderExists() {
_ensureBaseFolderExists = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee3() {
return _regenerator["default"].wrap(function _callee3$(_context3) {
@@ -160,9 +123,7 @@ function _ensureBaseFolderExists() {
return null;
});
}
-
return _context3.abrupt("return", ENSURE_BASE_FOLDER_EXISTS_PROMISE);
-
case 2:
case "end":
return _context3.stop();
@@ -172,7 +133,6 @@ function _ensureBaseFolderExists() {
}));
return _ensureBaseFolderExists.apply(this, arguments);
}
-
function ensureFoldersExist(_x, _x2) {
return _ensureFoldersExist.apply(this, arguments);
}
@@ -180,8 +140,6 @@ function ensureFoldersExist(_x, _x2) {
* removes the tmp-folder
* @return {Promise}
*/
-
-
function _ensureFoldersExist() {
_ensureFoldersExist = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee4(channelName, paths) {
var chmodValue;
@@ -192,13 +150,11 @@ function _ensureFoldersExist() {
paths = paths || getPaths(channelName);
_context4.next = 3;
return ensureBaseFolderExists();
-
case 3:
_context4.next = 5;
return mkdir(paths.channelBase)["catch"](function () {
return null;
});
-
case 5:
_context4.next = 7;
return Promise.all([mkdir(paths.readers)["catch"](function () {
@@ -206,7 +162,6 @@ function _ensureFoldersExist() {
}), mkdir(paths.messages)["catch"](function () {
return null;
})]);
-
case 7:
// set permissions so other users can use the same channel
chmodValue = '777';
@@ -214,7 +169,6 @@ function _ensureFoldersExist() {
return Promise.all([chmod(paths.channelBase, chmodValue), chmod(paths.readers, chmodValue), chmod(paths.messages, chmodValue)])["catch"](function () {
return null;
});
-
case 10:
case "end":
return _context4.stop();
@@ -224,11 +178,9 @@ function _ensureFoldersExist() {
}));
return _ensureFoldersExist.apply(this, arguments);
}
-
function clearNodeFolder() {
return _clearNodeFolder.apply(this, arguments);
}
-
function _clearNodeFolder() {
_clearNodeFolder = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee5() {
return _regenerator["default"].wrap(function _callee5$(_context5) {
@@ -239,18 +191,14 @@ function _clearNodeFolder() {
_context5.next = 2;
break;
}
-
throw new Error('BroadcastChannel.clearNodeFolder(): path is wrong');
-
case 2:
ENSURE_BASE_FOLDER_EXISTS_PROMISE = null;
_context5.next = 5;
return removeDir(TMP_FOLDER_BASE);
-
case 5:
ENSURE_BASE_FOLDER_EXISTS_PROMISE = null;
return _context5.abrupt("return", true);
-
case 7:
case "end":
return _context5.stop();
@@ -260,29 +208,22 @@ function _clearNodeFolder() {
}));
return _clearNodeFolder.apply(this, arguments);
}
-
function socketPath(channelName, readerUuid, paths) {
paths = paths || getPaths(channelName);
-
var socketPath = _path["default"].join(paths.readers, readerUuid + '.s');
-
return cleanPipeName(socketPath);
}
-
function socketInfoPath(channelName, readerUuid, paths) {
paths = paths || getPaths(channelName);
-
var socketPath = _path["default"].join(paths.readers, readerUuid + '.json');
-
return socketPath;
}
+
/**
* Because it is not possible to get all socket-files in a folder,
* when used under fucking windows,
* we have to set a normal file so other readers know our socket exists
*/
-
-
function createSocketInfoFile(channelName, readerUuid, paths) {
var pathToFile = socketInfoPath(channelName, readerUuid, paths);
return writeFile(pathToFile, JSON.stringify({
@@ -291,16 +232,14 @@ function createSocketInfoFile(channelName, readerUuid, paths) {
return pathToFile;
});
}
+
/**
* returns the amount of channel-folders in the tmp-directory
* @return {Promise}
*/
-
-
function countChannelFolders() {
return _countChannelFolders.apply(this, arguments);
}
-
function _countChannelFolders() {
_countChannelFolders = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee6() {
var folders;
@@ -310,15 +249,12 @@ function _countChannelFolders() {
case 0:
_context6.next = 2;
return ensureBaseFolderExists();
-
case 2:
_context6.next = 4;
return readdir(TMP_FOLDER_BASE);
-
case 4:
folders = _context6.sent;
return _context6.abrupt("return", folders.length);
-
case 6:
case "end":
return _context6.stop();
@@ -328,7 +264,6 @@ function _countChannelFolders() {
}));
return _countChannelFolders.apply(this, arguments);
}
-
function connectionError(_x3) {
return _connectionError.apply(this, arguments);
}
@@ -336,8 +271,6 @@ function connectionError(_x3) {
* creates the socket-file and subscribes to it
* @return {{emitter: EventEmitter, server: any}}
*/
-
-
function _connectionError() {
_connectionError = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee7(originalError) {
var count, addObj, text, newError;
@@ -347,28 +280,23 @@ function _connectionError() {
case 0:
_context7.next = 2;
return countChannelFolders();
-
case 2:
count = _context7.sent;
-
if (!(count < 30)) {
_context7.next = 5;
break;
}
-
return _context7.abrupt("return", originalError);
-
case 5:
addObj = {};
Object.entries(originalError).forEach(function (_ref3) {
var k = _ref3[0],
- v = _ref3[1];
+ v = _ref3[1];
return addObj[k] = v;
});
text = 'BroadcastChannel.create(): error: ' + 'This might happen if you have created to many channels, ' + 'like when you use BroadcastChannel in unit-tests.' + 'Try using BroadcastChannel.clearNodeFolder() to clear the tmp-folder before each test.' + 'See https://github.com/pubkey/broadcast-channel#clear-tmp-folder';
newError = new Error(text + ': ' + JSON.stringify(addObj, null, 2));
return _context7.abrupt("return", newError);
-
case 10:
case "end":
return _context7.stop();
@@ -378,11 +306,9 @@ function _connectionError() {
}));
return _connectionError.apply(this, arguments);
}
-
function createSocketEventEmitter(_x4, _x5, _x6) {
return _createSocketEventEmitter.apply(this, arguments);
}
-
function _createSocketEventEmitter() {
_createSocketEventEmitter = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee10(channelName, readerUuid, paths) {
var pathToSocket, emitter, server;
@@ -409,11 +335,9 @@ function _createSocketEventEmitter() {
case 0:
_context8.next = 2;
return connectionError(err);
-
case 2:
useErr = _context8.sent;
reject(useErr);
-
case 4:
case "end":
return _context8.stop();
@@ -421,7 +345,6 @@ function _createSocketEventEmitter() {
}
}, _callee8);
}));
-
return function (_x26) {
return _ref4.apply(this, arguments);
};
@@ -437,19 +360,15 @@ function _createSocketEventEmitter() {
_context9.next = 7;
break;
}
-
_context9.next = 3;
return connectionError(err);
-
case 3:
useErr = _context9.sent;
reject(useErr);
_context9.next = 8;
break;
-
case 7:
resolve(res);
-
case 8:
case "end":
return _context9.stop();
@@ -457,20 +376,17 @@ function _createSocketEventEmitter() {
}
}, _callee9);
}));
-
return function (_x27, _x28) {
return _ref5.apply(this, arguments);
};
}());
});
-
case 5:
return _context10.abrupt("return", {
path: pathToSocket,
emitter: emitter,
server: server
});
-
case 6:
case "end":
return _context10.stop();
@@ -480,7 +396,6 @@ function _createSocketEventEmitter() {
}));
return _createSocketEventEmitter.apply(this, arguments);
}
-
function openClientConnection(_x7, _x8) {
return _openClientConnection.apply(this, arguments);
}
@@ -489,8 +404,6 @@ function openClientConnection(_x7, _x8) {
* so other readers can find it
* @return {Promise}
*/
-
-
function _openClientConnection() {
_openClientConnection = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee11(channelName, readerUuid) {
var pathToSocket, client;
@@ -508,7 +421,6 @@ function _openClientConnection() {
return rej(err);
});
}));
-
case 3:
case "end":
return _context11.stop();
@@ -518,7 +430,6 @@ function _openClientConnection() {
}));
return _openClientConnection.apply(this, arguments);
}
-
function writeMessage(channelName, readerUuid, messageJson, paths) {
paths = paths || getPaths(channelName);
var time = microSeconds();
@@ -529,9 +440,7 @@ function writeMessage(channelName, readerUuid, messageJson, paths) {
};
var token = (0, _util2.randomToken)();
var fileName = time + '_' + readerUuid + '_' + token + '.json';
-
var msgPath = _path["default"].join(paths.messages, fileName);
-
return writeFile(msgPath, JSON.stringify(writeObject)).then(function () {
return {
time: time,
@@ -541,16 +450,14 @@ function writeMessage(channelName, readerUuid, messageJson, paths) {
};
});
}
+
/**
* returns the uuids of all readers
* @return {string[]}
*/
-
-
function getReadersUuids(_x9, _x10) {
return _getReadersUuids.apply(this, arguments);
}
-
function _getReadersUuids() {
_getReadersUuids = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee12(channelName, paths) {
var readersPath, files;
@@ -562,7 +469,6 @@ function _getReadersUuids() {
readersPath = paths.readers;
_context12.next = 4;
return readdir(readersPath);
-
case 4:
files = _context12.sent;
return _context12.abrupt("return", files.map(function (file) {
@@ -573,7 +479,6 @@ function _getReadersUuids() {
.map(function (split) {
return split[0];
}));
-
case 6:
case "end":
return _context12.stop();
@@ -583,11 +488,9 @@ function _getReadersUuids() {
}));
return _getReadersUuids.apply(this, arguments);
}
-
function messagePath(_x11, _x12, _x13, _x14) {
return _messagePath.apply(this, arguments);
}
-
function _messagePath() {
_messagePath = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee13(channelName, time, token, writerUuid) {
var fileName, msgPath;
@@ -598,7 +501,6 @@ function _messagePath() {
fileName = time + '_' + writerUuid + '_' + token + '.json';
msgPath = _path["default"].join(getPaths(channelName).messages, fileName);
return _context13.abrupt("return", msgPath);
-
case 3:
case "end":
return _context13.stop();
@@ -608,11 +510,9 @@ function _messagePath() {
}));
return _messagePath.apply(this, arguments);
}
-
function getAllMessages(_x15, _x16) {
return _getAllMessages.apply(this, arguments);
}
-
function _getAllMessages() {
_getAllMessages = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee14(channelName, paths) {
var messagesPath, files;
@@ -624,7 +524,6 @@ function _getAllMessages() {
messagesPath = paths.messages;
_context14.next = 4;
return readdir(messagesPath);
-
case 4:
files = _context14.sent;
return _context14.abrupt("return", files.map(function (file) {
@@ -637,7 +536,6 @@ function _getAllMessages() {
token: split[2]
};
}));
-
case 6:
case "end":
return _context14.stop();
@@ -647,7 +545,6 @@ function _getAllMessages() {
}));
return _getAllMessages.apply(this, arguments);
}
-
function getSingleMessage(channelName, msgObj, paths) {
paths = paths || getPaths(channelName);
return {
@@ -657,17 +554,14 @@ function getSingleMessage(channelName, msgObj, paths) {
token: msgObj.to
};
}
-
function readMessage(messageObj) {
return readFile(messageObj.path, 'utf8').then(function (content) {
return JSON.parse(content);
});
}
-
function cleanOldMessages(_x17, _x18) {
return _cleanOldMessages.apply(this, arguments);
}
-
function _cleanOldMessages() {
_cleanOldMessages = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee15(messageObjects, ttl) {
var olderThen;
@@ -676,7 +570,6 @@ function _cleanOldMessages() {
switch (_context15.prev = _context15.next) {
case 0:
olderThen = microSeconds() - ttl * 1000; // convert ttl to microseconds
-
_context15.next = 3;
return Promise.all(messageObjects.filter(function (obj) {
return obj.time < olderThen;
@@ -685,7 +578,6 @@ function _cleanOldMessages() {
return null;
});
}));
-
case 3:
case "end":
return _context15.stop();
@@ -695,32 +587,28 @@ function _cleanOldMessages() {
}));
return _cleanOldMessages.apply(this, arguments);
}
-
var type = 'node';
+
/**
* creates a new channelState
* @return {Promise}
*/
-
exports.type = type;
-
function create(_x19) {
return _create.apply(this, arguments);
}
-
function _create() {
_create = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee16(channelName) {
var options,
- time,
- paths,
- ensureFolderExistsPromise,
- uuid,
- state,
- _yield$Promise$all,
- socketEE,
- infoFilePath,
- _args16 = arguments;
-
+ time,
+ paths,
+ ensureFolderExistsPromise,
+ uuid,
+ state,
+ _yield$Promise$all,
+ socketEE,
+ infoFilePath,
+ _args16 = arguments;
return _regenerator["default"].wrap(function _callee16$(_context16) {
while (1) {
switch (_context16.prev = _context16.next) {
@@ -739,7 +627,6 @@ function _create() {
paths: paths,
// contains all messages that have been emitted before
emittedMessagesIds: new _obliviousSet.ObliviousSet(options.node.ttl * 2),
-
/**
* Used to ensure we do not write too many files at once
* which could throw an error.
@@ -763,18 +650,17 @@ function _create() {
OTHER_INSTANCES[channelName].push(state);
_context16.next = 11;
return ensureFolderExistsPromise;
-
case 11:
_context16.next = 13;
return Promise.all([createSocketEventEmitter(channelName, uuid, paths), createSocketInfoFile(channelName, uuid, paths), refreshReaderClients(state)]);
-
case 13:
_yield$Promise$all = _context16.sent;
socketEE = _yield$Promise$all[0];
infoFilePath = _yield$Promise$all[1];
state.socketEE = socketEE;
- state.infoFilePath = infoFilePath; // when new message comes in, we read it and emit it
+ state.infoFilePath = infoFilePath;
+ // when new message comes in, we read it and emit it
socketEE.emitter.on('data', function (data) {
// if the socket is used fast, it may appear that multiple messages are flushed at once
// so we have to split them before
@@ -791,7 +677,6 @@ function _create() {
});
});
return _context16.abrupt("return", state);
-
case 20:
case "end":
return _context16.stop();
@@ -801,27 +686,21 @@ function _create() {
}));
return _create.apply(this, arguments);
}
-
function _filterMessage(msgObj, state) {
if (msgObj.senderUuid === state.uuid) return false; // not send by own
-
if (state.emittedMessagesIds.has(msgObj.token)) return false; // not already emitted
-
if (!state.messagesCallback) return false; // no listener
-
if (msgObj.time < state.messagesCallbackTime) return false; // not older then onMessageCallback
-
if (msgObj.time < state.time) return false; // msgObj is older then channel
state.emittedMessagesIds.add(msgObj.token);
return true;
}
+
/**
* when the socket pings, so that we now new messages came,
* run this
*/
-
-
function handleMessagePing(_x20, _x21) {
return _handleMessagePing.apply(this, arguments);
}
@@ -829,8 +708,6 @@ function handleMessagePing(_x20, _x21) {
* ensures that the channelState is connected with all other readers
* @return {Promise}
*/
-
-
function _handleMessagePing() {
_handleMessagePing = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee17(state, msgObj) {
var messages, useMessages;
@@ -842,27 +719,21 @@ function _handleMessagePing() {
_context17.next = 2;
break;
}
-
return _context17.abrupt("return");
-
case 2:
if (msgObj) {
_context17.next = 8;
break;
}
-
_context17.next = 5;
return getAllMessages(state.channelName, state.paths);
-
case 5:
messages = _context17.sent;
_context17.next = 9;
break;
-
case 8:
// get single message
messages = [getSingleMessage(state.channelName, msgObj, state.paths)];
-
case 9:
useMessages = messages.filter(function (msgObj) {
return _filterMessage(msgObj, state);
@@ -870,14 +741,11 @@ function _handleMessagePing() {
return msgObjA.time - msgObjB.time;
}); // sort by time
// if no listener or message, so not do anything
-
if (!(!useMessages.length || !state.messagesCallback)) {
_context17.next = 12;
break;
}
-
return _context17.abrupt("return");
-
case 12:
_context17.next = 14;
return Promise.all(useMessages.map(function (msgObj) {
@@ -885,17 +753,14 @@ function _handleMessagePing() {
return msgObj.content = content;
});
}));
-
case 14:
useMessages.forEach(function (msgObj) {
state.emittedMessagesIds.add(msgObj.token);
-
if (state.messagesCallback) {
// emit to subscribers
state.messagesCallback(msgObj.content.data);
}
});
-
case 15:
case "end":
return _context17.stop();
@@ -905,7 +770,6 @@ function _handleMessagePing() {
}));
return _handleMessagePing.apply(this, arguments);
}
-
function refreshReaderClients(channelState) {
return getReadersUuids(channelState.channelName, channelState.paths).then(function (otherReaders) {
// remove subscriptions to closed readers
@@ -920,18 +784,14 @@ function refreshReaderClients(channelState) {
_context.prev = 0;
_context.next = 3;
return channelState.otherReaderClients[readerUuid].destroy();
-
case 3:
_context.next = 7;
break;
-
case 5:
_context.prev = 5;
_context.t0 = _context["catch"](0);
-
case 7:
delete channelState.otherReaderClients[readerUuid];
-
case 8:
case "end":
return _context.stop();
@@ -939,12 +799,12 @@ function refreshReaderClients(channelState) {
}
}, _callee, null, [[0, 5]]);
}));
-
return function (_x22) {
return _ref.apply(this, arguments);
};
- }()); // add new readers
+ }());
+ // add new readers
return Promise.all(otherReaders.filter(function (readerUuid) {
return readerUuid !== channelState.uuid;
}) // not own
@@ -959,37 +819,29 @@ function refreshReaderClients(channelState) {
switch (_context2.prev = _context2.next) {
case 0:
_context2.prev = 0;
-
if (!channelState.closed) {
_context2.next = 3;
break;
}
-
return _context2.abrupt("return");
-
case 3:
_context2.prev = 3;
_context2.next = 6;
return openClientConnection(channelState.channelName, readerUuid);
-
case 6:
client = _context2.sent;
channelState.otherReaderClients[readerUuid] = client;
_context2.next = 12;
break;
-
case 10:
_context2.prev = 10;
_context2.t0 = _context2["catch"](3);
-
case 12:
_context2.next = 16;
break;
-
case 14:
_context2.prev = 14;
_context2.t1 = _context2["catch"](0);
-
case 16:
case "end":
return _context2.stop();
@@ -997,19 +849,17 @@ function refreshReaderClients(channelState) {
}
}, _callee2, null, [[0, 14], [3, 10]]);
}));
-
return function (_x23) {
return _ref2.apply(this, arguments);
};
}()));
});
}
+
/**
* post a message to the other readers
* @return {Promise}
*/
-
-
function postMessage(_x24, _x25) {
return _postMessage.apply(this, arguments);
}
@@ -1019,8 +869,6 @@ function postMessage(_x24, _x25) {
* This might not happen often in production
* but will speed up things when this module is used in unit-tests.
*/
-
-
function _postMessage() {
_postMessage = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee19(channelState, messageJson) {
var writePromise;
@@ -1033,7 +881,6 @@ function _postMessage() {
});
channelState.writeBlockPromise = channelState.writeBlockPromise.then( /*#__PURE__*/(0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee18() {
var _yield$Promise$all2, msgObj, pingStr, writeToReadersPromise;
-
return _regenerator["default"].wrap(function _callee18$(_context18) {
while (1) {
switch (_context18.prev = _context18.next) {
@@ -1042,11 +889,9 @@ function _postMessage() {
return new Promise(function (res) {
return setTimeout(res, 0);
});
-
case 2:
_context18.next = 4;
return Promise.all([writePromise, refreshReaderClients(channelState)]);
-
case 4:
_yield$Promise$all2 = _context18.sent;
msgObj = _yield$Promise$all2[0];
@@ -1065,16 +910,13 @@ function _postMessage() {
* to not waste resources on cleaning up,
* only if random-int matches, we clean up old messages
*/
-
if ((0, _util2.randomInt)(0, 20) === 0) {
/* await */
getAllMessages(channelState.channelName, channelState.paths).then(function (allMessages) {
return cleanOldMessages(allMessages, channelState.options.node.ttl);
});
}
-
return _context18.abrupt("return", writeToReadersPromise);
-
case 11:
case "end":
return _context18.stop();
@@ -1083,7 +925,6 @@ function _postMessage() {
}, _callee18);
})));
return _context19.abrupt("return", channelState.writeBlockPromise);
-
case 3:
case "end":
return _context19.stop();
@@ -1093,13 +934,11 @@ function _postMessage() {
}));
return _postMessage.apply(this, arguments);
}
-
function emitOverFastPath(state, msgObj, messageJson) {
if (!state.options.node.useFastPath) {
// disabled
return;
}
-
var others = OTHER_INSTANCES[state.channelName].filter(function (s) {
return s !== state;
});
@@ -1114,19 +953,17 @@ function emitOverFastPath(state, msgObj, messageJson) {
otherState.messagesCallback(messageJson);
});
}
-
function onMessage(channelState, fn) {
var time = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : microSeconds();
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
handleMessagePing(channelState);
}
+
/**
* closes the channel
* @return {Promise}
*/
-
-
function close(channelState) {
if (channelState.closed) return;
channelState.closed = true;
@@ -1134,35 +971,30 @@ function close(channelState) {
OTHER_INSTANCES[channelState.channelName] = OTHER_INSTANCES[channelState.channelName].filter(function (o) {
return o !== channelState;
});
-
if (channelState.removeUnload) {
channelState.removeUnload.remove();
}
-
return new Promise(function (res) {
if (channelState.socketEE) channelState.socketEE.emitter.removeAllListeners();
Object.values(channelState.otherReaderClients).forEach(function (client) {
return client.destroy();
});
-
if (channelState.infoFilePath) {
try {
_fs["default"].unlinkSync(channelState.infoFilePath);
} catch (err) {}
}
+
/**
* the server get closed lazy because others might still write on it
* and have not found out that the infoFile was deleted
*/
-
-
setTimeout(function () {
channelState.socketEE.server.close();
res();
}, 200);
});
}
-
function canBeUsed() {
if (typeof _fs["default"].mkdir === 'function') {
return true;
@@ -1170,23 +1002,20 @@ function canBeUsed() {
return false;
}
}
+
/**
* on node we use a relatively height averageResponseTime,
* because the file-io might be in use.
* Also it is more important that the leader-election is reliable,
* then to have a fast election.
*/
-
-
function averageResponseTime() {
return 200;
}
-
function microSeconds() {
// convert nano to micro seconds
return parseInt(now() / 1000);
}
-
function now() {
return Number(process.hrtime.bigint()); // returns nanoseconds
}
\ No newline at end of file
diff --git a/dist/lib/methods/simulate.js b/dist/lib/methods/simulate.js
index f0ce13c5..46d5cfde 100644
--- a/dist/lib/methods/simulate.js
+++ b/dist/lib/methods/simulate.js
@@ -11,15 +11,12 @@ exports.microSeconds = exports["default"] = void 0;
exports.onMessage = onMessage;
exports.postMessage = postMessage;
exports.type = void 0;
-
var _util = require("../util.js");
-
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var type = 'simulate';
exports.type = type;
var SIMULATE_CHANNELS = new Set();
-
function create(channelName) {
var state = {
name: channelName,
@@ -28,11 +25,9 @@ function create(channelName) {
SIMULATE_CHANNELS.add(state);
return state;
}
-
function close(channelState) {
SIMULATE_CHANNELS["delete"](channelState);
}
-
function postMessage(channelState, messageJson) {
return new Promise(function (res) {
return setTimeout(function () {
@@ -50,19 +45,15 @@ function postMessage(channelState, messageJson) {
}, 5);
});
}
-
function onMessage(channelState, fn) {
channelState.messagesCallback = fn;
}
-
function canBeUsed() {
return true;
}
-
function averageResponseTime() {
return 5;
}
-
var _default = {
create: create,
close: close,
diff --git a/dist/lib/options.js b/dist/lib/options.js
index c8435340..36c0e4e8 100644
--- a/dist/lib/options.js
+++ b/dist/lib/options.js
@@ -4,33 +4,35 @@ Object.defineProperty(exports, "__esModule", {
value: true
});
exports.fillOptionsWithDefaults = fillOptionsWithDefaults;
-
function fillOptionsWithDefaults() {
var originalOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- var options = JSON.parse(JSON.stringify(originalOptions)); // main
-
- if (typeof options.webWorkerSupport === 'undefined') options.webWorkerSupport = true; // indexed-db
+ var options = JSON.parse(JSON.stringify(originalOptions));
- if (!options.idb) options.idb = {}; // after this time the messages get deleted
+ // main
+ if (typeof options.webWorkerSupport === 'undefined') options.webWorkerSupport = true;
+ // indexed-db
+ if (!options.idb) options.idb = {};
+ // after this time the messages get deleted
if (!options.idb.ttl) options.idb.ttl = 1000 * 45;
- if (!options.idb.fallbackInterval) options.idb.fallbackInterval = 150; // handles abrupt db onclose events.
-
- if (originalOptions.idb && typeof originalOptions.idb.onclose === 'function') options.idb.onclose = originalOptions.idb.onclose; // localstorage
+ if (!options.idb.fallbackInterval) options.idb.fallbackInterval = 150;
+ // handles abrupt db onclose events.
+ if (originalOptions.idb && typeof originalOptions.idb.onclose === 'function') options.idb.onclose = originalOptions.idb.onclose;
+ // localstorage
if (!options.localstorage) options.localstorage = {};
- if (!options.localstorage.removeTimeout) options.localstorage.removeTimeout = 1000 * 60; // custom methods
+ if (!options.localstorage.removeTimeout) options.localstorage.removeTimeout = 1000 * 60;
- if (originalOptions.methods) options.methods = originalOptions.methods; // node
+ // custom methods
+ if (originalOptions.methods) options.methods = originalOptions.methods;
+ // node
if (!options.node) options.node = {};
if (!options.node.ttl) options.node.ttl = 1000 * 60 * 2; // 2 minutes;
-
/**
* On linux use 'ulimit -Hn' to get the limit of open files.
* On ubuntu this was 4096 for me, so we use half of that as maxParallelWrites default.
*/
-
if (!options.node.maxParallelWrites) options.node.maxParallelWrites = 2048;
if (typeof options.node.useFastPath === 'undefined') options.node.useFastPath = true;
return options;
diff --git a/dist/lib/util.js b/dist/lib/util.js
index bf51ea5e..c63716c9 100644
--- a/dist/lib/util.js
+++ b/dist/lib/util.js
@@ -9,7 +9,6 @@ exports.microSeconds = microSeconds;
exports.randomInt = randomInt;
exports.randomToken = randomToken;
exports.sleep = sleep;
-
/**
* returns true if the given object is a promise
*/
@@ -20,14 +19,12 @@ function isPromise(obj) {
return false;
}
}
-
var PROMISE_RESOLVED_FALSE = Promise.resolve(false);
exports.PROMISE_RESOLVED_FALSE = PROMISE_RESOLVED_FALSE;
var PROMISE_RESOLVED_TRUE = Promise.resolve(true);
exports.PROMISE_RESOLVED_TRUE = PROMISE_RESOLVED_TRUE;
var PROMISE_RESOLVED_VOID = Promise.resolve();
exports.PROMISE_RESOLVED_VOID = PROMISE_RESOLVED_VOID;
-
function sleep(time, resolveWith) {
if (!time) time = 0;
return new Promise(function (res) {
@@ -36,21 +33,19 @@ function sleep(time, resolveWith) {
}, time);
});
}
-
function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
+
/**
* https://stackoverflow.com/a/8084248
*/
-
-
function randomToken() {
return Math.random().toString(36).substring(2);
}
-
var lastMs = 0;
var additional = 0;
+
/**
* returns the current time in micro-seconds,
* WARNING: This is a pseudo-function
@@ -58,10 +53,8 @@ var additional = 0;
* This is enough in browsers, and this function will not be used in nodejs.
* The main reason for this hack is to ensure that BroadcastChannel behaves equal to production when it is used in fast-running unit tests.
*/
-
function microSeconds() {
var ms = new Date().getTime();
-
if (ms === lastMs) {
additional++;
return ms * 1000 + additional;
diff --git a/docs/e2e.js b/docs/e2e.js
index 71a6a640..19884333 100644
--- a/docs/e2e.js
+++ b/docs/e2e.js
@@ -7,13 +7,9 @@ Object.defineProperty(exports, "__esModule", {
exports.OPEN_BROADCAST_CHANNELS = exports.BroadcastChannel = void 0;
exports.clearNodeFolder = clearNodeFolder;
exports.enforceOptions = enforceOptions;
-
var _util = require("./util.js");
-
var _methodChooser = require("./method-chooser.js");
-
var _options = require("./options.js");
-
/**
* Contains all open channels,
* used in tests to ensure everything is closed.
@@ -21,77 +17,73 @@ var _options = require("./options.js");
var OPEN_BROADCAST_CHANNELS = new Set();
exports.OPEN_BROADCAST_CHANNELS = OPEN_BROADCAST_CHANNELS;
var lastId = 0;
-
var BroadcastChannel = function BroadcastChannel(name, options) {
// identifier of the channel to debug stuff
this.id = lastId++;
OPEN_BROADCAST_CHANNELS.add(this);
this.name = name;
-
if (ENFORCED_OPTIONS) {
options = ENFORCED_OPTIONS;
}
-
this.options = (0, _options.fillOptionsWithDefaults)(options);
- this.method = (0, _methodChooser.chooseMethod)(this.options); // isListening
+ this.method = (0, _methodChooser.chooseMethod)(this.options);
+ // isListening
this._iL = false;
+
/**
* _onMessageListener
* setting onmessage twice,
* will overwrite the first listener
*/
-
this._onML = null;
+
/**
* _addEventListeners
*/
-
this._addEL = {
message: [],
internal: []
};
+
/**
* Unsend message promises
* where the sending is still in progress
* @type {Set}
*/
-
this._uMP = new Set();
+
/**
* _beforeClose
* array of promises that will be awaited
* before the channel is closed
*/
-
this._befC = [];
+
/**
* _preparePromise
*/
-
this._prepP = null;
-
_prepareChannel(this);
-}; // STATICS
+};
+
+// STATICS
/**
* used to identify if someone overwrites
* window.BroadcastChannel with this
* See methods/native.js
*/
-
-
exports.BroadcastChannel = BroadcastChannel;
BroadcastChannel._pubkey = true;
+
/**
* clears the tmp-folder if is node
* @return {Promise} true if has run, false if not node
*/
-
function clearNodeFolder(options) {
options = (0, _options.fillOptionsWithDefaults)(options);
var method = (0, _methodChooser.chooseMethod)(options);
-
if (method.type === 'node') {
return method.clearNodeFolder().then(function () {
return true;
@@ -100,19 +92,17 @@ function clearNodeFolder(options) {
return _util.PROMISE_RESOLVED_FALSE;
}
}
+
/**
* if set, this method is enforced,
* no mather what the options are
*/
-
-
var ENFORCED_OPTIONS;
-
function enforceOptions(options) {
ENFORCED_OPTIONS = options;
-} // PROTOTYPE
-
+}
+// PROTOTYPE
BroadcastChannel.prototype = {
postMessage: function postMessage(msg) {
if (this.closed) {
@@ -124,87 +114,77 @@ BroadcastChannel.prototype = {
*/
JSON.stringify(msg));
}
-
return _post(this, 'message', msg);
},
postInternal: function postInternal(msg) {
return _post(this, 'internal', msg);
},
-
set onmessage(fn) {
var time = this.method.microSeconds();
var listenObj = {
time: time,
fn: fn
};
-
_removeListenerObject(this, 'message', this._onML);
-
if (fn && typeof fn === 'function') {
this._onML = listenObj;
-
_addListenerObject(this, 'message', listenObj);
} else {
this._onML = null;
}
},
-
addEventListener: function addEventListener(type, fn) {
var time = this.method.microSeconds();
var listenObj = {
time: time,
fn: fn
};
-
_addListenerObject(this, type, listenObj);
},
removeEventListener: function removeEventListener(type, fn) {
var obj = this._addEL[type].find(function (obj) {
return obj.fn === fn;
});
-
_removeListenerObject(this, type, obj);
},
close: function close() {
var _this = this;
-
if (this.closed) {
return;
}
-
OPEN_BROADCAST_CHANNELS["delete"](this);
this.closed = true;
var awaitPrepare = this._prepP ? this._prepP : _util.PROMISE_RESOLVED_VOID;
this._onML = null;
this._addEL.message = [];
- return awaitPrepare // wait until all current sending are processed
+ return awaitPrepare
+ // wait until all current sending are processed
.then(function () {
return Promise.all(Array.from(_this._uMP));
- }) // run before-close hooks
+ })
+ // run before-close hooks
.then(function () {
return Promise.all(_this._befC.map(function (fn) {
return fn();
}));
- }) // close the channel
+ })
+ // close the channel
.then(function () {
return _this.method.close(_this._state);
});
},
-
get type() {
return this.method.type;
},
-
get isClosed() {
return this.closed;
}
-
};
+
/**
* Post a message over the channel
* @returns {Promise} that resolved when the message sending is done
*/
-
function _post(broadcastChannel, type, msg) {
var time = broadcastChannel.method.microSeconds();
var msgObj = {
@@ -214,25 +194,22 @@ function _post(broadcastChannel, type, msg) {
};
var awaitPrepare = broadcastChannel._prepP ? broadcastChannel._prepP : _util.PROMISE_RESOLVED_VOID;
return awaitPrepare.then(function () {
- var sendPromise = broadcastChannel.method.postMessage(broadcastChannel._state, msgObj); // add/remove to unsend messages list
+ var sendPromise = broadcastChannel.method.postMessage(broadcastChannel._state, msgObj);
+ // add/remove to unsend messages list
broadcastChannel._uMP.add(sendPromise);
-
sendPromise["catch"]().then(function () {
return broadcastChannel._uMP["delete"](sendPromise);
});
return sendPromise;
});
}
-
function _prepareChannel(channel) {
var maybePromise = channel.method.create(channel.name, channel.options);
-
if ((0, _util.isPromise)(maybePromise)) {
channel._prepP = maybePromise;
maybePromise.then(function (s) {
// used in tests to simulate slow runtime
-
/*if (channel.options.prepareDelay) {
await new Promise(res => setTimeout(res, this.options.prepareDelay));
}*/
@@ -242,30 +219,25 @@ function _prepareChannel(channel) {
channel._state = maybePromise;
}
}
-
function _hasMessageListeners(channel) {
if (channel._addEL.message.length > 0) return true;
if (channel._addEL.internal.length > 0) return true;
return false;
}
-
function _addListenerObject(channel, type, obj) {
channel._addEL[type].push(obj);
-
_startListening(channel);
}
-
function _removeListenerObject(channel, type, obj) {
channel._addEL[type] = channel._addEL[type].filter(function (o) {
return o !== obj;
});
-
_stopListening(channel);
}
-
function _startListening(channel) {
if (!channel._iL && _hasMessageListeners(channel)) {
// someone is listening, start subscribing
+
var listenerFn = function listenerFn(msgObj) {
channel._addEL[msgObj.type].forEach(function (listenerObject) {
/**
@@ -279,15 +251,12 @@ function _startListening(channel) {
*/
var hundredMsInMicro = 100 * 1000;
var minMessageTime = listenerObject.time - hundredMsInMicro;
-
if (msgObj.time >= minMessageTime) {
listenerObject.fn(msgObj.data);
}
});
};
-
var time = channel.method.microSeconds();
-
if (channel._prepP) {
channel._prepP.then(function () {
channel._iL = true;
@@ -299,7 +268,6 @@ function _startListening(channel) {
}
}
}
-
function _stopListening(channel) {
if (channel._iL && !_hasMessageListeners(channel)) {
// noone is listening, stop subscribing
@@ -312,7 +280,6 @@ function _stopListening(channel) {
"use strict";
var _index = require("./index.js");
-
/**
* because babel can only export on default-attribute,
* we use this for the non-module-build
@@ -321,6 +288,7 @@ var _index = require("./index.js");
* but
* var BroadcastChannel = require('broadcast-channel');
*/
+
module.exports = {
BroadcastChannel: _index.BroadcastChannel,
createLeaderElection: _index.createLeaderElection,
@@ -370,9 +338,7 @@ Object.defineProperty(exports, "enforceOptions", {
return _broadcastChannel.enforceOptions;
}
});
-
var _broadcastChannel = require("./broadcast-channel.js");
-
var _leaderElection = require("./leader-election.js");
},{"./broadcast-channel.js":1,"./leader-election.js":4}],4:[function(require,module,exports){
"use strict";
@@ -382,37 +348,30 @@ Object.defineProperty(exports, "__esModule", {
});
exports.beLeader = beLeader;
exports.createLeaderElection = createLeaderElection;
-
var _util = require("./util.js");
-
var _unload = require("unload");
-
var LeaderElection = function LeaderElection(broadcastChannel, options) {
var _this = this;
-
this.broadcastChannel = broadcastChannel;
this._options = options;
this.isLeader = false;
this.hasLeader = false;
this.isDead = false;
this.token = (0, _util.randomToken)();
+
/**
* Apply Queue,
* used to ensure we do not run applyOnce()
* in parallel.
*/
+ this._aplQ = _util.PROMISE_RESOLVED_VOID;
+ // amount of unfinished applyOnce() calls
+ this._aplQC = 0;
- this._aplQ = _util.PROMISE_RESOLVED_VOID; // amount of unfinished applyOnce() calls
-
- this._aplQC = 0; // things to clean up
-
+ // things to clean up
this._unl = []; // _unloads
-
this._lstns = []; // _listeners
-
this._dpL = function () {}; // onduplicate listener
-
-
this._dpLC = false; // true when onduplicate called
/**
@@ -420,55 +379,47 @@ var LeaderElection = function LeaderElection(broadcastChannel, options) {
* we still listen to messages to ensure the hasLeader flag
* is set correctly.
*/
-
var hasLeaderListener = function hasLeaderListener(msg) {
if (msg.context === 'leader') {
if (msg.action === 'death') {
_this.hasLeader = false;
}
-
if (msg.action === 'tell') {
_this.hasLeader = true;
}
}
};
-
this.broadcastChannel.addEventListener('internal', hasLeaderListener);
-
this._lstns.push(hasLeaderListener);
};
-
LeaderElection.prototype = {
/**
* Returns true if the instance is leader,
* false if not.
* @async
*/
- applyOnce: function applyOnce( // true if the applyOnce() call came from the fallbackInterval cycle
+ applyOnce: function applyOnce(
+ // true if the applyOnce() call came from the fallbackInterval cycle
isFromFallbackInterval) {
var _this2 = this;
-
if (this.isLeader) {
return (0, _util.sleep)(0, true);
}
-
if (this.isDead) {
return (0, _util.sleep)(0, false);
}
+
/**
* Already applying more then once,
* -> wait for the apply queue to be finished.
*/
-
-
if (this._aplQC > 1) {
return this._aplQ;
}
+
/**
* Add a new apply-run
*/
-
-
var applyRun = function applyRun() {
/**
* Optimization shortcuts.
@@ -478,7 +429,6 @@ LeaderElection.prototype = {
if (_this2.isLeader) {
return _util.PROMISE_RESOLVED_TRUE;
}
-
var stopCriteria = false;
var stopCriteriaPromiseResolve;
/**
@@ -487,7 +437,6 @@ LeaderElection.prototype = {
* have to await the responseTime when it is already clear
* that the election failed.
*/
-
var stopCriteriaPromise = new Promise(function (res) {
stopCriteriaPromiseResolve = function stopCriteriaPromiseResolve() {
stopCriteria = true;
@@ -495,11 +444,9 @@ LeaderElection.prototype = {
};
});
var recieved = [];
-
var handleMessage = function handleMessage(msg) {
if (msg.context === 'leader' && msg.token != _this2.token) {
recieved.push(msg);
-
if (msg.action === 'apply') {
// other is applying
if (msg.token > _this2.token) {
@@ -510,7 +457,6 @@ LeaderElection.prototype = {
stopCriteriaPromiseResolve();
}
}
-
if (msg.action === 'tell') {
// other is already leader
stopCriteriaPromiseResolve();
@@ -518,8 +464,8 @@ LeaderElection.prototype = {
}
}
};
-
_this2.broadcastChannel.addEventListener('internal', handleMessage);
+
/**
* If the applyOnce() call came from the fallbackInterval,
* we can assume that the election runs in the background and
@@ -530,26 +476,24 @@ LeaderElection.prototype = {
* But also it takes longer which is not a problem because we anyway
* run in the background.
*/
-
-
var waitForAnswerTime = isFromFallbackInterval ? _this2._options.responseTime * 4 : _this2._options.responseTime;
-
var applyPromise = _sendMessage(_this2, 'apply') // send out that this one is applying
.then(function () {
return Promise.race([(0, _util.sleep)(waitForAnswerTime), stopCriteriaPromise.then(function () {
return Promise.reject(new Error());
})]);
- }) // send again in case another instance was just created
+ })
+ // send again in case another instance was just created
.then(function () {
return _sendMessage(_this2, 'apply');
- }) // let others time to respond
+ })
+ // let others time to respond
.then(function () {
return Promise.race([(0, _util.sleep)(waitForAnswerTime), stopCriteriaPromise.then(function () {
return Promise.reject(new Error());
})]);
})["catch"](function () {}).then(function () {
_this2.broadcastChannel.removeEventListener('internal', handleMessage);
-
if (!stopCriteria) {
// no stop criteria -> own is leader
return beLeader(_this2).then(function () {
@@ -560,10 +504,8 @@ LeaderElection.prototype = {
return false;
}
});
-
return applyPromise;
};
-
this._aplQC = this._aplQC + 1;
this._aplQ = this._aplQ.then(function () {
return applyRun();
@@ -575,82 +517,68 @@ LeaderElection.prototype = {
});
},
awaitLeadership: function awaitLeadership() {
- if (
- /* _awaitLeadershipPromise */
+ if ( /* _awaitLeadershipPromise */
!this._aLP) {
this._aLP = _awaitLeadershipOnce(this);
}
-
return this._aLP;
},
-
set onduplicate(fn) {
this._dpL = fn;
},
-
die: function die() {
var _this3 = this;
-
this._lstns.forEach(function (listener) {
return _this3.broadcastChannel.removeEventListener('internal', listener);
});
-
this._lstns = [];
-
this._unl.forEach(function (uFn) {
return uFn.remove();
});
-
this._unl = [];
-
if (this.isLeader) {
this.hasLeader = false;
this.isLeader = false;
}
-
this.isDead = true;
return _sendMessage(this, 'death');
}
};
+
/**
* @param leaderElector {LeaderElector}
*/
-
function _awaitLeadershipOnce(leaderElector) {
if (leaderElector.isLeader) {
return _util.PROMISE_RESOLVED_VOID;
}
-
return new Promise(function (res) {
var resolved = false;
-
function finish() {
if (resolved) {
return;
}
-
resolved = true;
leaderElector.broadcastChannel.removeEventListener('internal', whenDeathListener);
res(true);
- } // try once now
-
+ }
+ // try once now
leaderElector.applyOnce().then(function () {
if (leaderElector.isLeader) {
finish();
}
});
+
/**
* Try on fallbackInterval
* @recursive
*/
-
var tryOnFallBack = function tryOnFallBack() {
return (0, _util.sleep)(leaderElector._options.fallbackInterval).then(function () {
if (leaderElector.isDead || resolved) {
return;
}
-
if (leaderElector.isLeader) {
finish();
} else {
@@ -664,9 +592,9 @@ function _awaitLeadershipOnce(leaderElector) {
}
});
};
+ tryOnFallBack();
- tryOnFallBack(); // try when other leader dies
-
+ // try when other leader dies
var whenDeathListener = function whenDeathListener(msg) {
if (msg.context === 'leader' && msg.action === 'death') {
leaderElector.hasLeader = false;
@@ -677,17 +605,14 @@ function _awaitLeadershipOnce(leaderElector) {
});
}
};
-
leaderElector.broadcastChannel.addEventListener('internal', whenDeathListener);
-
leaderElector._lstns.push(whenDeathListener);
});
}
+
/**
* sends and internal message over the broadcast-channel
*/
-
-
function _sendMessage(leaderElector, action) {
var msgJson = {
context: 'leader',
@@ -696,21 +621,17 @@ function _sendMessage(leaderElector, action) {
};
return leaderElector.broadcastChannel.postInternal(msgJson);
}
-
function beLeader(leaderElector) {
leaderElector.isLeader = true;
leaderElector.hasLeader = true;
var unloadFn = (0, _unload.add)(function () {
return leaderElector.die();
});
-
leaderElector._unl.push(unloadFn);
-
var isLeaderListener = function isLeaderListener(msg) {
if (msg.context === 'leader' && msg.action === 'apply') {
_sendMessage(leaderElector, 'tell');
}
-
if (msg.context === 'leader' && msg.action === 'tell' && !leaderElector._dpLC) {
/**
* another instance is also leader!
@@ -721,49 +642,35 @@ function beLeader(leaderElector) {
* @link https://github.com/pubkey/broadcast-channel/issues/385
*/
leaderElector._dpLC = true;
-
leaderElector._dpL(); // message the lib user so the app can handle the problem
-
-
_sendMessage(leaderElector, 'tell'); // ensure other leader also knows the problem
-
}
};
leaderElector.broadcastChannel.addEventListener('internal', isLeaderListener);
-
leaderElector._lstns.push(isLeaderListener);
-
return _sendMessage(leaderElector, 'tell');
}
-
function fillOptionsWithDefaults(options, channel) {
if (!options) options = {};
options = JSON.parse(JSON.stringify(options));
-
if (!options.fallbackInterval) {
options.fallbackInterval = 3000;
}
-
if (!options.responseTime) {
options.responseTime = channel.method.averageResponseTime(channel.options);
}
-
return options;
}
-
function createLeaderElection(channel, options) {
if (channel._leaderElector) {
throw new Error('BroadcastChannel already has a leader-elector');
}
-
options = fillOptionsWithDefaults(options, channel);
var elector = new LeaderElection(channel, options);
-
channel._befC.push(function () {
return elector.die();
});
-
channel._leaderElector = elector;
return elector;
}
@@ -771,59 +678,49 @@ function createLeaderElection(channel, options) {
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
-
var _typeof = require("@babel/runtime/helpers/typeof");
-
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.chooseMethod = chooseMethod;
-
var _native = _interopRequireDefault(require("./methods/native.js"));
-
var _indexedDb = _interopRequireDefault(require("./methods/indexed-db.js"));
-
var _localstorage = _interopRequireDefault(require("./methods/localstorage.js"));
-
var _simulate = _interopRequireDefault(require("./methods/simulate.js"));
-
-
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
-
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
-
// the line below will be removed from es5/browser builds
+
// order is important
-var METHODS = [_native["default"], // fastest
+var METHODS = [_native["default"],
+// fastest
_indexedDb["default"], _localstorage["default"]];
-
function chooseMethod(options) {
- var chooseMethods = [].concat(options.methods, METHODS).filter(Boolean); // the line below will be removed from es5/browser builds
+ var chooseMethods = [].concat(options.methods, METHODS).filter(Boolean);
+ // the line below will be removed from es5/browser builds
+ // directly chosen
if (options.type) {
if (options.type === 'simulate') {
// only use simulate-method if directly chosen
return _simulate["default"];
}
-
var ret = chooseMethods.find(function (m) {
return m.type === options.type;
});
if (!ret) throw new Error('method-type ' + options.type + ' not found');else return ret;
}
+
/**
* if no webworker support is needed,
* remove idb from the list so that localstorage is been chosen
*/
-
-
if (!options.webWorkerSupport) {
chooseMethods = chooseMethods.filter(function (m) {
return m.type !== 'idb';
});
}
-
var useMethod = chooseMethods.find(function (method) {
return method.canBeUsed();
});
@@ -856,13 +753,9 @@ exports.postMessage = postMessage;
exports.removeMessagesById = removeMessagesById;
exports.type = void 0;
exports.writeMessage = writeMessage;
-
var _util = require("../util.js");
-
var _obliviousSet = require("oblivious-set");
-
var _options = require("../options.js");
-
/**
* this method uses indexeddb to store the messages
* There is currently no observerAPI for idb
@@ -871,58 +764,54 @@ var _options = require("../options.js");
* When working on this, ensure to use these performance optimizations:
* @link https://rxdb.info/slow-indexeddb.html
*/
+
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var DB_PREFIX = 'pubkey.broadcast-channel-0-';
var OBJECT_STORE_ID = 'messages';
+
/**
* Use relaxed durability for faster performance on all transactions.
* @link https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/
*/
-
var TRANSACTION_SETTINGS = {
durability: 'relaxed'
};
exports.TRANSACTION_SETTINGS = TRANSACTION_SETTINGS;
var type = 'idb';
exports.type = type;
-
function getIdb() {
if (typeof indexedDB !== 'undefined') return indexedDB;
-
if (typeof window !== 'undefined') {
if (typeof window.mozIndexedDB !== 'undefined') return window.mozIndexedDB;
if (typeof window.webkitIndexedDB !== 'undefined') return window.webkitIndexedDB;
if (typeof window.msIndexedDB !== 'undefined') return window.msIndexedDB;
}
-
return false;
}
+
/**
* If possible, we should explicitly commit IndexedDB transactions
* for better performance.
* @link https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/
*/
-
-
function commitIndexedDBTransaction(tx) {
if (tx.commit) {
tx.commit();
}
}
-
function createDatabase(channelName) {
- var IndexedDB = getIdb(); // create table
+ var IndexedDB = getIdb();
+ // create table
var dbName = DB_PREFIX + channelName;
+
/**
* All IndexedDB databases are opened without version
* because it is a bit faster, especially on firefox
* @link http://nparashuram.com/IndexedDB/perf/#Open%20Database%20with%20version
*/
-
var openRequest = IndexedDB.open(dbName);
-
openRequest.onupgradeneeded = function (ev) {
var db = ev.target.result;
db.createObjectStore(OBJECT_STORE_ID, {
@@ -930,24 +819,21 @@ function createDatabase(channelName) {
autoIncrement: true
});
};
-
var dbPromise = new Promise(function (res, rej) {
openRequest.onerror = function (ev) {
return rej(ev);
};
-
openRequest.onsuccess = function () {
res(openRequest.result);
};
});
return dbPromise;
}
+
/**
* writes the new message to the database
* so other readers can find it
*/
-
-
function writeMessage(db, readerUuid, messageJson) {
var time = new Date().getTime();
var writeObject = {
@@ -960,17 +846,14 @@ function writeMessage(db, readerUuid, messageJson) {
tx.oncomplete = function () {
return res();
};
-
tx.onerror = function (ev) {
return rej(ev);
};
-
var objectStore = tx.objectStore(OBJECT_STORE_ID);
objectStore.add(writeObject);
commitIndexedDBTransaction(tx);
});
}
-
function getAllMessages(db) {
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS);
var objectStore = tx.objectStore(OBJECT_STORE_ID);
@@ -978,10 +861,9 @@ function getAllMessages(db) {
return new Promise(function (res) {
objectStore.openCursor().onsuccess = function (ev) {
var cursor = ev.target.result;
-
if (cursor) {
- ret.push(cursor.value); //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
-
+ ret.push(cursor.value);
+ //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor["continue"]();
} else {
commitIndexedDBTransaction(tx);
@@ -990,31 +872,28 @@ function getAllMessages(db) {
};
});
}
-
function getMessagesHigherThan(db, lastCursorId) {
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS);
var objectStore = tx.objectStore(OBJECT_STORE_ID);
var ret = [];
var keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity);
+
/**
* Optimization shortcut,
* if getAll() can be used, do not use a cursor.
* @link https://rxdb.info/slow-indexeddb.html
*/
-
if (objectStore.getAll) {
var getAllRequest = objectStore.getAll(keyRangeValue);
return new Promise(function (res, rej) {
getAllRequest.onerror = function (err) {
return rej(err);
};
-
getAllRequest.onsuccess = function (e) {
res(e.target.result);
};
});
}
-
function openCursor() {
// Occasionally Safari will fail on IDBKeyRange.bound, this
// catches that error, having it open the cursor to the first
@@ -1026,17 +905,13 @@ function getMessagesHigherThan(db, lastCursorId) {
return objectStore.openCursor();
}
}
-
return new Promise(function (res, rej) {
var openCursorRequest = openCursor();
-
openCursorRequest.onerror = function (err) {
return rej(err);
};
-
openCursorRequest.onsuccess = function (ev) {
var cursor = ev.target.result;
-
if (cursor) {
if (cursor.value.id < lastCursorId + 1) {
cursor["continue"](lastCursorId + 1);
@@ -1051,12 +926,10 @@ function getMessagesHigherThan(db, lastCursorId) {
};
});
}
-
function removeMessagesById(channelState, ids) {
if (channelState.closed) {
return Promise.resolve([]);
}
-
var tx = channelState.db.transaction(OBJECT_STORE_ID, 'readwrite', TRANSACTION_SETTINGS);
var objectStore = tx.objectStore(OBJECT_STORE_ID);
return Promise.all(ids.map(function (id) {
@@ -1068,7 +941,6 @@ function removeMessagesById(channelState, ids) {
});
}));
}
-
function getOldMessages(db, ttl) {
var olderThen = new Date().getTime() - ttl;
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS);
@@ -1077,13 +949,11 @@ function getOldMessages(db, ttl) {
return new Promise(function (res) {
objectStore.openCursor().onsuccess = function (ev) {
var cursor = ev.target.result;
-
if (cursor) {
var msgObk = cursor.value;
-
if (msgObk.time < olderThen) {
- ret.push(msgObk); //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
-
+ ret.push(msgObk);
+ //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor["continue"]();
} else {
// no more old messages,
@@ -1097,7 +967,6 @@ function getOldMessages(db, ttl) {
};
});
}
-
function cleanOldMessages(channelState) {
return getOldMessages(channelState.db, channelState.options.idb.ttl).then(function (tooOld) {
return removeMessagesById(channelState, tooOld.map(function (msg) {
@@ -1105,7 +974,6 @@ function cleanOldMessages(channelState) {
}));
});
}
-
function create(channelName, options) {
options = (0, _options.fillOptionsWithDefaults)(options);
return createDatabase(channelName).then(function (db) {
@@ -1115,7 +983,6 @@ function create(channelName, options) {
channelName: channelName,
options: options,
uuid: (0, _util.randomToken)(),
-
/**
* emittedMessagesIds
* contains all messages that have been emitted before
@@ -1128,30 +995,27 @@ function create(channelName, options) {
readQueuePromises: [],
db: db
};
+
/**
* Handle abrupt closes that do not originate from db.close().
* This could happen, for example, if the underlying storage is
* removed or if the user clears the database in the browser's
* history preferences.
*/
-
db.onclose = function () {
state.closed = true;
if (options.idb.onclose) options.idb.onclose();
};
+
/**
* if service-workers are used,
* we have no 'storage'-event if they post a message,
* therefore we also have to set an interval
*/
-
-
_readLoop(state);
-
return state;
});
}
-
function _readLoop(state) {
if (state.closed) return;
readNewMessages(state).then(function () {
@@ -1160,25 +1024,21 @@ function _readLoop(state) {
return _readLoop(state);
});
}
-
function _filterMessage(msgObj, state) {
if (msgObj.uuid === state.uuid) return false; // send by own
-
if (state.eMIs.has(msgObj.id)) return false; // already emitted
-
if (msgObj.data.time < state.messagesCallbackTime) return false; // older then onMessageCallback
-
return true;
}
+
/**
* reads all new messages from the database and emits them
*/
-
-
function readNewMessages(state) {
// channel already closed
- if (state.closed) return _util.PROMISE_RESOLVED_VOID; // if no one is listening, we do not need to scan for new messages
+ if (state.closed) return _util.PROMISE_RESOLVED_VOID;
+ // if no one is listening, we do not need to scan for new messages
if (!state.messagesCallback) return _util.PROMISE_RESOLVED_VOID;
return getMessagesHigherThan(state.db, state.lastCursorId).then(function (newerMessages) {
var useMessages = newerMessages
@@ -1186,21 +1046,18 @@ function readNewMessages(state) {
* there is a bug in iOS where the msgObj can be undefined some times
* so we filter them out
* @link https://github.com/pubkey/broadcast-channel/issues/19
- */
- .filter(function (msgObj) {
+ */.filter(function (msgObj) {
return !!msgObj;
}).map(function (msgObj) {
if (msgObj.id > state.lastCursorId) {
state.lastCursorId = msgObj.id;
}
-
return msgObj;
}).filter(function (msgObj) {
return _filterMessage(msgObj, state);
}).sort(function (msgObjA, msgObjB) {
return msgObjA.time - msgObjB.time;
}); // sort by time
-
useMessages.forEach(function (msgObj) {
if (state.messagesCallback) {
state.eMIs.add(msgObj.id);
@@ -1210,12 +1067,10 @@ function readNewMessages(state) {
return _util.PROMISE_RESOLVED_VOID;
});
}
-
function close(channelState) {
channelState.closed = true;
channelState.db.close();
}
-
function postMessage(channelState, messageJson) {
channelState.writeBlockPromise = channelState.writeBlockPromise.then(function () {
return writeMessage(channelState.db, channelState.uuid, messageJson);
@@ -1227,27 +1082,21 @@ function postMessage(channelState, messageJson) {
});
return channelState.writeBlockPromise;
}
-
function onMessage(channelState, fn, time) {
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
readNewMessages(channelState);
}
-
function canBeUsed() {
var idb = getIdb();
-
if (!idb) {
return false;
}
-
return true;
}
-
function averageResponseTime(options) {
return options.idb.fallbackInterval * 2;
}
-
var _default = {
create: create,
close: close,
@@ -1278,13 +1127,9 @@ exports.postMessage = postMessage;
exports.removeStorageEventListener = removeStorageEventListener;
exports.storageKey = storageKey;
exports.type = void 0;
-
var _obliviousSet = require("oblivious-set");
-
var _options = require("../options.js");
-
var _util = require("../util.js");
-
/**
* A localStorage-only method which uses localstorage and its 'storage'-event
* This does not work inside of webworkers because they have no access to locastorage
@@ -1292,41 +1137,38 @@ var _util = require("../util.js");
* @link https://caniuse.com/#feat=namevalue-storage
* @link https://caniuse.com/#feat=indexeddb
*/
+
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var KEY_PREFIX = 'pubkey.broadcastChannel-';
var type = 'localstorage';
+
/**
* copied from crosstab
* @link https://github.com/tejacques/crosstab/blob/master/src/crosstab.js#L32
*/
-
exports.type = type;
-
function getLocalStorage() {
var localStorage;
if (typeof window === 'undefined') return null;
-
try {
localStorage = window.localStorage;
localStorage = window['ie8-eventlistener/storage'] || window.localStorage;
- } catch (e) {// New versions of Firefox throw a Security exception
+ } catch (e) {
+ // New versions of Firefox throw a Security exception
// if cookies are disabled. See
// https://bugzilla.mozilla.org/show_bug.cgi?id=1028153
}
-
return localStorage;
}
-
function storageKey(channelName) {
return KEY_PREFIX + channelName;
}
+
/**
* writes the new message to the storage
* and fires the storage-event so other readers can find it
*/
-
-
function postMessage(channelState, messageJson) {
return new Promise(function (res) {
(0, _util.sleep)().then(function () {
@@ -1339,12 +1181,12 @@ function postMessage(channelState, messageJson) {
};
var value = JSON.stringify(writeObj);
getLocalStorage().setItem(key, value);
+
/**
* StorageEvent does not fire the 'storage' event
* in the window that changes the state of the local storage.
* So we fire it manually
*/
-
var ev = document.createEvent('Event');
ev.initEvent('storage', true, true);
ev.key = key;
@@ -1354,52 +1196,42 @@ function postMessage(channelState, messageJson) {
});
});
}
-
function addStorageEventListener(channelName, fn) {
var key = storageKey(channelName);
-
var listener = function listener(ev) {
if (ev.key === key) {
fn(JSON.parse(ev.newValue));
}
};
-
window.addEventListener('storage', listener);
return listener;
}
-
function removeStorageEventListener(listener) {
window.removeEventListener('storage', listener);
}
-
function create(channelName, options) {
options = (0, _options.fillOptionsWithDefaults)(options);
-
if (!canBeUsed()) {
throw new Error('BroadcastChannel: localstorage cannot be used');
}
-
var uuid = (0, _util.randomToken)();
+
/**
* eMIs
* contains all messages that have been emitted before
* @type {ObliviousSet}
*/
-
var eMIs = new _obliviousSet.ObliviousSet(options.localstorage.removeTimeout);
var state = {
channelName: channelName,
uuid: uuid,
eMIs: eMIs // emittedMessagesIds
-
};
+
state.listener = addStorageEventListener(channelName, function (msgObj) {
if (!state.messagesCallback) return; // no listener
-
if (msgObj.uuid === uuid) return; // own message
-
if (!msgObj.token || eMIs.has(msgObj.token)) return; // already emitted
-
if (msgObj.data.time && msgObj.data.time < state.messagesCallbackTime) return; // too old
eMIs.add(msgObj.token);
@@ -1407,20 +1239,16 @@ function create(channelName, options) {
});
return state;
}
-
function close(channelState) {
removeStorageEventListener(channelState.listener);
}
-
function onMessage(channelState, fn, time) {
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
}
-
function canBeUsed() {
var ls = getLocalStorage();
if (!ls) return false;
-
try {
var key = '__broadcastchannel_check';
ls.setItem(key, 'works');
@@ -1431,22 +1259,17 @@ function canBeUsed() {
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API#Private_Browsing_Incognito_modes
return false;
}
-
return true;
}
-
function averageResponseTime() {
var defaultTime = 120;
var userAgent = navigator.userAgent.toLowerCase();
-
if (userAgent.includes('safari') && !userAgent.includes('chrome')) {
// safari is much slower so this time is higher
return defaultTime * 2;
}
-
return defaultTime;
}
-
var _default = {
create: create,
close: close,
@@ -1472,20 +1295,16 @@ exports.microSeconds = exports["default"] = void 0;
exports.onMessage = onMessage;
exports.postMessage = postMessage;
exports.type = void 0;
-
var _util = require("../util.js");
-
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var type = 'native';
exports.type = type;
-
function create(channelName) {
var state = {
messagesCallback: null,
bc: new BroadcastChannel(channelName),
subFns: [] // subscriberFunctions
-
};
state.bc.onmessage = function (msg) {
@@ -1493,15 +1312,12 @@ function create(channelName) {
state.messagesCallback(msg.data);
}
};
-
return state;
}
-
function close(channelState) {
channelState.bc.close();
channelState.subFns = [];
}
-
function postMessage(channelState, messageJson) {
try {
channelState.bc.postMessage(messageJson, false);
@@ -1510,31 +1326,25 @@ function postMessage(channelState, messageJson) {
return Promise.reject(err);
}
}
-
function onMessage(channelState, fn) {
channelState.messagesCallback = fn;
}
-
function canBeUsed() {
if (typeof window === 'undefined') {
return false;
}
-
if (typeof BroadcastChannel === 'function') {
if (BroadcastChannel._pubkey) {
throw new Error('BroadcastChannel: Do not overwrite window.BroadcastChannel with this module, this is not a polyfill');
}
-
return true;
} else {
return false;
}
}
-
function averageResponseTime() {
return 150;
}
-
var _default = {
create: create,
close: close,
@@ -1560,15 +1370,12 @@ exports.microSeconds = exports["default"] = void 0;
exports.onMessage = onMessage;
exports.postMessage = postMessage;
exports.type = void 0;
-
var _util = require("../util.js");
-
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var type = 'simulate';
exports.type = type;
var SIMULATE_CHANNELS = new Set();
-
function create(channelName) {
var state = {
name: channelName,
@@ -1577,11 +1384,9 @@ function create(channelName) {
SIMULATE_CHANNELS.add(state);
return state;
}
-
function close(channelState) {
SIMULATE_CHANNELS["delete"](channelState);
}
-
function postMessage(channelState, messageJson) {
return new Promise(function (res) {
return setTimeout(function () {
@@ -1599,19 +1404,15 @@ function postMessage(channelState, messageJson) {
}, 5);
});
}
-
function onMessage(channelState, fn) {
channelState.messagesCallback = fn;
}
-
function canBeUsed() {
return true;
}
-
function averageResponseTime() {
return 5;
}
-
var _default = {
create: create,
close: close,
@@ -1630,33 +1431,35 @@ Object.defineProperty(exports, "__esModule", {
value: true
});
exports.fillOptionsWithDefaults = fillOptionsWithDefaults;
-
function fillOptionsWithDefaults() {
var originalOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- var options = JSON.parse(JSON.stringify(originalOptions)); // main
+ var options = JSON.parse(JSON.stringify(originalOptions));
- if (typeof options.webWorkerSupport === 'undefined') options.webWorkerSupport = true; // indexed-db
-
- if (!options.idb) options.idb = {}; // after this time the messages get deleted
+ // main
+ if (typeof options.webWorkerSupport === 'undefined') options.webWorkerSupport = true;
+ // indexed-db
+ if (!options.idb) options.idb = {};
+ // after this time the messages get deleted
if (!options.idb.ttl) options.idb.ttl = 1000 * 45;
- if (!options.idb.fallbackInterval) options.idb.fallbackInterval = 150; // handles abrupt db onclose events.
-
- if (originalOptions.idb && typeof originalOptions.idb.onclose === 'function') options.idb.onclose = originalOptions.idb.onclose; // localstorage
+ if (!options.idb.fallbackInterval) options.idb.fallbackInterval = 150;
+ // handles abrupt db onclose events.
+ if (originalOptions.idb && typeof originalOptions.idb.onclose === 'function') options.idb.onclose = originalOptions.idb.onclose;
+ // localstorage
if (!options.localstorage) options.localstorage = {};
- if (!options.localstorage.removeTimeout) options.localstorage.removeTimeout = 1000 * 60; // custom methods
+ if (!options.localstorage.removeTimeout) options.localstorage.removeTimeout = 1000 * 60;
- if (originalOptions.methods) options.methods = originalOptions.methods; // node
+ // custom methods
+ if (originalOptions.methods) options.methods = originalOptions.methods;
+ // node
if (!options.node) options.node = {};
if (!options.node.ttl) options.node.ttl = 1000 * 60 * 2; // 2 minutes;
-
/**
* On linux use 'ulimit -Hn' to get the limit of open files.
* On ubuntu this was 4096 for me, so we use half of that as maxParallelWrites default.
*/
-
if (!options.node.maxParallelWrites) options.node.maxParallelWrites = 2048;
if (typeof options.node.useFastPath === 'undefined') options.node.useFastPath = true;
return options;
@@ -1673,7 +1476,6 @@ exports.microSeconds = microSeconds;
exports.randomInt = randomInt;
exports.randomToken = randomToken;
exports.sleep = sleep;
-
/**
* returns true if the given object is a promise
*/
@@ -1684,14 +1486,12 @@ function isPromise(obj) {
return false;
}
}
-
var PROMISE_RESOLVED_FALSE = Promise.resolve(false);
exports.PROMISE_RESOLVED_FALSE = PROMISE_RESOLVED_FALSE;
var PROMISE_RESOLVED_TRUE = Promise.resolve(true);
exports.PROMISE_RESOLVED_TRUE = PROMISE_RESOLVED_TRUE;
var PROMISE_RESOLVED_VOID = Promise.resolve();
exports.PROMISE_RESOLVED_VOID = PROMISE_RESOLVED_VOID;
-
function sleep(time, resolveWith) {
if (!time) time = 0;
return new Promise(function (res) {
@@ -1700,21 +1500,19 @@ function sleep(time, resolveWith) {
}, time);
});
}
-
function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
+
/**
* https://stackoverflow.com/a/8084248
*/
-
-
function randomToken() {
return Math.random().toString(36).substring(2);
}
-
var lastMs = 0;
var additional = 0;
+
/**
* returns the current time in micro-seconds,
* WARNING: This is a pseudo-function
@@ -1722,10 +1520,8 @@ var additional = 0;
* This is enough in browsers, and this function will not be used in nodejs.
* The main reason for this hack is to ensure that BroadcastChannel behaves equal to production when it is used in fast-running unit tests.
*/
-
function microSeconds() {
var ms = new Date().getTime();
-
if (ms === lastMs) {
additional++;
return ms * 1000 + additional;
@@ -1788,34 +1584,28 @@ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
reject(error);
return;
}
-
if (info.done) {
resolve(value);
} else {
Promise.resolve(value).then(_next, _throw);
}
}
-
function _asyncToGenerator(fn) {
return function () {
var self = this,
- args = arguments;
+ args = arguments;
return new Promise(function (resolve, reject) {
var gen = fn.apply(self, args);
-
function _next(value) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
}
-
function _throw(err) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
}
-
_next(undefined);
});
};
}
-
module.exports = _asyncToGenerator, module.exports.__esModule = true, module.exports["default"] = module.exports;
},{}],15:[function(require,module,exports){
function _interopRequireDefault(obj) {
@@ -1823,26 +1613,24 @@ function _interopRequireDefault(obj) {
"default": obj
};
}
-
module.exports = _interopRequireDefault, module.exports.__esModule = true, module.exports["default"] = module.exports;
},{}],16:[function(require,module,exports){
var _typeof = require("./typeof.js")["default"];
-
function _regeneratorRuntime() {
- "use strict";
- /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
-
+ "use strict"; /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
module.exports = _regeneratorRuntime = function _regeneratorRuntime() {
return exports;
}, module.exports.__esModule = true, module.exports["default"] = module.exports;
var exports = {},
- Op = Object.prototype,
- hasOwn = Op.hasOwnProperty,
- $Symbol = "function" == typeof Symbol ? Symbol : {},
- iteratorSymbol = $Symbol.iterator || "@@iterator",
- asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator",
- toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag";
-
+ Op = Object.prototype,
+ hasOwn = Op.hasOwnProperty,
+ defineProperty = Object.defineProperty || function (obj, key, desc) {
+ obj[key] = desc.value;
+ },
+ $Symbol = "function" == typeof Symbol ? Symbol : {},
+ iteratorSymbol = $Symbol.iterator || "@@iterator",
+ asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator",
+ toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag";
function define(obj, key, value) {
return Object.defineProperty(obj, key, {
value: value,
@@ -1851,7 +1639,6 @@ function _regeneratorRuntime() {
writable: !0
}), obj[key];
}
-
try {
define({}, "");
} catch (err) {
@@ -1859,54 +1646,14 @@ function _regeneratorRuntime() {
return obj[key] = value;
};
}
-
function wrap(innerFn, outerFn, self, tryLocsList) {
var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator,
- generator = Object.create(protoGenerator.prototype),
- context = new Context(tryLocsList || []);
- return generator._invoke = function (innerFn, self, context) {
- var state = "suspendedStart";
- return function (method, arg) {
- if ("executing" === state) throw new Error("Generator is already running");
-
- if ("completed" === state) {
- if ("throw" === method) throw arg;
- return doneResult();
- }
-
- for (context.method = method, context.arg = arg;;) {
- var delegate = context.delegate;
-
- if (delegate) {
- var delegateResult = maybeInvokeDelegate(delegate, context);
-
- if (delegateResult) {
- if (delegateResult === ContinueSentinel) continue;
- return delegateResult;
- }
- }
-
- if ("next" === context.method) context.sent = context._sent = context.arg;else if ("throw" === context.method) {
- if ("suspendedStart" === state) throw state = "completed", context.arg;
- context.dispatchException(context.arg);
- } else "return" === context.method && context.abrupt("return", context.arg);
- state = "executing";
- var record = tryCatch(innerFn, self, context);
-
- if ("normal" === record.type) {
- if (state = context.done ? "completed" : "suspendedYield", record.arg === ContinueSentinel) continue;
- return {
- value: record.arg,
- done: context.done
- };
- }
-
- "throw" === record.type && (state = "completed", context.method = "throw", context.arg = record.arg);
- }
- };
- }(innerFn, self, context), generator;
+ generator = Object.create(protoGenerator.prototype),
+ context = new Context(tryLocsList || []);
+ return defineProperty(generator, "_invoke", {
+ value: makeInvokeMethod(innerFn, self, context)
+ }), generator;
}
-
function tryCatch(fn, obj, arg) {
try {
return {
@@ -1920,25 +1667,19 @@ function _regeneratorRuntime() {
};
}
}
-
exports.wrap = wrap;
var ContinueSentinel = {};
-
function Generator() {}
-
function GeneratorFunction() {}
-
function GeneratorFunctionPrototype() {}
-
var IteratorPrototype = {};
define(IteratorPrototype, iteratorSymbol, function () {
return this;
});
var getProto = Object.getPrototypeOf,
- NativeIteratorPrototype = getProto && getProto(getProto(values([])));
+ NativeIteratorPrototype = getProto && getProto(getProto(values([])));
NativeIteratorPrototype && NativeIteratorPrototype !== Op && hasOwn.call(NativeIteratorPrototype, iteratorSymbol) && (IteratorPrototype = NativeIteratorPrototype);
var Gp = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(IteratorPrototype);
-
function defineIteratorMethods(prototype) {
["next", "throw", "return"].forEach(function (method) {
define(prototype, method, function (arg) {
@@ -1946,14 +1687,12 @@ function _regeneratorRuntime() {
});
});
}
-
function AsyncIterator(generator, PromiseImpl) {
function invoke(method, arg, resolve, reject) {
var record = tryCatch(generator[method], generator, arg);
-
if ("throw" !== record.type) {
var result = record.arg,
- value = result.value;
+ value = result.value;
return value && "object" == _typeof(value) && hasOwn.call(value, "__await") ? PromiseImpl.resolve(value.__await).then(function (value) {
invoke("next", value, resolve, reject);
}, function (err) {
@@ -1964,92 +1703,116 @@ function _regeneratorRuntime() {
return invoke("throw", error, resolve, reject);
});
}
-
reject(record.arg);
}
-
var previousPromise;
-
- this._invoke = function (method, arg) {
- function callInvokeWithMethodAndArg() {
- return new PromiseImpl(function (resolve, reject) {
- invoke(method, arg, resolve, reject);
- });
+ defineProperty(this, "_invoke", {
+ value: function value(method, arg) {
+ function callInvokeWithMethodAndArg() {
+ return new PromiseImpl(function (resolve, reject) {
+ invoke(method, arg, resolve, reject);
+ });
+ }
+ return previousPromise = previousPromise ? previousPromise.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg();
+ }
+ });
+ }
+ function makeInvokeMethod(innerFn, self, context) {
+ var state = "suspendedStart";
+ return function (method, arg) {
+ if ("executing" === state) throw new Error("Generator is already running");
+ if ("completed" === state) {
+ if ("throw" === method) throw arg;
+ return doneResult();
+ }
+ for (context.method = method, context.arg = arg;;) {
+ var delegate = context.delegate;
+ if (delegate) {
+ var delegateResult = maybeInvokeDelegate(delegate, context);
+ if (delegateResult) {
+ if (delegateResult === ContinueSentinel) continue;
+ return delegateResult;
+ }
+ }
+ if ("next" === context.method) context.sent = context._sent = context.arg;else if ("throw" === context.method) {
+ if ("suspendedStart" === state) throw state = "completed", context.arg;
+ context.dispatchException(context.arg);
+ } else "return" === context.method && context.abrupt("return", context.arg);
+ state = "executing";
+ var record = tryCatch(innerFn, self, context);
+ if ("normal" === record.type) {
+ if (state = context.done ? "completed" : "suspendedYield", record.arg === ContinueSentinel) continue;
+ return {
+ value: record.arg,
+ done: context.done
+ };
+ }
+ "throw" === record.type && (state = "completed", context.method = "throw", context.arg = record.arg);
}
-
- return previousPromise = previousPromise ? previousPromise.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg();
};
}
-
function maybeInvokeDelegate(delegate, context) {
var method = delegate.iterator[context.method];
-
if (undefined === method) {
if (context.delegate = null, "throw" === context.method) {
if (delegate.iterator["return"] && (context.method = "return", context.arg = undefined, maybeInvokeDelegate(delegate, context), "throw" === context.method)) return ContinueSentinel;
context.method = "throw", context.arg = new TypeError("The iterator does not provide a 'throw' method");
}
-
return ContinueSentinel;
}
-
var record = tryCatch(method, delegate.iterator, context.arg);
if ("throw" === record.type) return context.method = "throw", context.arg = record.arg, context.delegate = null, ContinueSentinel;
var info = record.arg;
return info ? info.done ? (context[delegate.resultName] = info.value, context.next = delegate.nextLoc, "return" !== context.method && (context.method = "next", context.arg = undefined), context.delegate = null, ContinueSentinel) : info : (context.method = "throw", context.arg = new TypeError("iterator result is not an object"), context.delegate = null, ContinueSentinel);
}
-
function pushTryEntry(locs) {
var entry = {
tryLoc: locs[0]
};
1 in locs && (entry.catchLoc = locs[1]), 2 in locs && (entry.finallyLoc = locs[2], entry.afterLoc = locs[3]), this.tryEntries.push(entry);
}
-
function resetTryEntry(entry) {
var record = entry.completion || {};
record.type = "normal", delete record.arg, entry.completion = record;
}
-
function Context(tryLocsList) {
this.tryEntries = [{
tryLoc: "root"
}], tryLocsList.forEach(pushTryEntry, this), this.reset(!0);
}
-
function values(iterable) {
if (iterable) {
var iteratorMethod = iterable[iteratorSymbol];
if (iteratorMethod) return iteratorMethod.call(iterable);
if ("function" == typeof iterable.next) return iterable;
-
if (!isNaN(iterable.length)) {
var i = -1,
- next = function next() {
- for (; ++i < iterable.length;) {
- if (hasOwn.call(iterable, i)) return next.value = iterable[i], next.done = !1, next;
- }
-
- return next.value = undefined, next.done = !0, next;
- };
-
+ next = function next() {
+ for (; ++i < iterable.length;) {
+ if (hasOwn.call(iterable, i)) return next.value = iterable[i], next.done = !1, next;
+ }
+ return next.value = undefined, next.done = !0, next;
+ };
return next.next = next;
}
}
-
return {
next: doneResult
};
}
-
function doneResult() {
return {
value: undefined,
done: !0
};
}
-
- return GeneratorFunction.prototype = GeneratorFunctionPrototype, define(Gp, "constructor", GeneratorFunctionPrototype), define(GeneratorFunctionPrototype, "constructor", GeneratorFunction), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, toStringTagSymbol, "GeneratorFunction"), exports.isGeneratorFunction = function (genFun) {
+ return GeneratorFunction.prototype = GeneratorFunctionPrototype, defineProperty(Gp, "constructor", {
+ value: GeneratorFunctionPrototype,
+ configurable: !0
+ }), defineProperty(GeneratorFunctionPrototype, "constructor", {
+ value: GeneratorFunction,
+ configurable: !0
+ }), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, toStringTagSymbol, "GeneratorFunction"), exports.isGeneratorFunction = function (genFun) {
var ctor = "function" == typeof genFun && genFun.constructor;
return !!ctor && (ctor === GeneratorFunction || "GeneratorFunction" === (ctor.displayName || ctor.name));
}, exports.mark = function (genFun) {
@@ -2070,19 +1833,17 @@ function _regeneratorRuntime() {
return this;
}), define(Gp, "toString", function () {
return "[object Generator]";
- }), exports.keys = function (object) {
- var keys = [];
-
+ }), exports.keys = function (val) {
+ var object = Object(val),
+ keys = [];
for (var key in object) {
keys.push(key);
}
-
return keys.reverse(), function next() {
for (; keys.length;) {
var key = keys.pop();
if (key in object) return next.value = key, next.done = !1, next;
}
-
return next.done = !0, next;
};
}, exports.values = values, Context.prototype = {
@@ -2101,20 +1862,16 @@ function _regeneratorRuntime() {
dispatchException: function dispatchException(exception) {
if (this.done) throw exception;
var context = this;
-
function handle(loc, caught) {
return record.type = "throw", record.arg = exception, context.next = loc, caught && (context.method = "next", context.arg = undefined), !!caught;
}
-
for (var i = this.tryEntries.length - 1; i >= 0; --i) {
var entry = this.tryEntries[i],
- record = entry.completion;
+ record = entry.completion;
if ("root" === entry.tryLoc) return handle("end");
-
if (entry.tryLoc <= this.prev) {
var hasCatch = hasOwn.call(entry, "catchLoc"),
- hasFinally = hasOwn.call(entry, "finallyLoc");
-
+ hasFinally = hasOwn.call(entry, "finallyLoc");
if (hasCatch && hasFinally) {
if (this.prev < entry.catchLoc) return handle(entry.catchLoc, !0);
if (this.prev < entry.finallyLoc) return handle(entry.finallyLoc);
@@ -2130,13 +1887,11 @@ function _regeneratorRuntime() {
abrupt: function abrupt(type, arg) {
for (var i = this.tryEntries.length - 1; i >= 0; --i) {
var entry = this.tryEntries[i];
-
if (entry.tryLoc <= this.prev && hasOwn.call(entry, "finallyLoc") && this.prev < entry.finallyLoc) {
var finallyEntry = entry;
break;
}
}
-
finallyEntry && ("break" === type || "continue" === type) && finallyEntry.tryLoc <= arg && arg <= finallyEntry.finallyLoc && (finallyEntry = null);
var record = finallyEntry ? finallyEntry.completion : {};
return record.type = type, record.arg = arg, finallyEntry ? (this.method = "next", this.next = finallyEntry.finallyLoc, ContinueSentinel) : this.complete(record);
@@ -2154,19 +1909,15 @@ function _regeneratorRuntime() {
"catch": function _catch(tryLoc) {
for (var i = this.tryEntries.length - 1; i >= 0; --i) {
var entry = this.tryEntries[i];
-
if (entry.tryLoc === tryLoc) {
var record = entry.completion;
-
if ("throw" === record.type) {
var thrown = record.arg;
resetTryEntry(entry);
}
-
return thrown;
}
}
-
throw new Error("illegal catch attempt");
},
delegateYield: function delegateYield(iterable, resultName, nextLoc) {
@@ -2178,7 +1929,6 @@ function _regeneratorRuntime() {
}
}, exports;
}
-
module.exports = _regeneratorRuntime, module.exports.__esModule = true, module.exports["default"] = module.exports;
},{"./typeof.js":17}],17:[function(require,module,exports){
function _typeof(obj) {
@@ -2190,7 +1940,6 @@ function _typeof(obj) {
return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
}, module.exports.__esModule = true, module.exports["default"] = module.exports), _typeof(obj);
}
-
module.exports = _typeof, module.exports.__esModule = true, module.exports["default"] = module.exports;
},{}],18:[function(require,module,exports){
// TODO(Babel 8): Remove this file.
@@ -11875,6 +11624,7 @@ var runtime = (function (exports) {
var Op = Object.prototype;
var hasOwn = Op.hasOwnProperty;
+ var defineProperty = Object.defineProperty || function (obj, key, desc) { obj[key] = desc.value; };
var undefined; // More compressible than void 0.
var $Symbol = typeof Symbol === "function" ? Symbol : {};
var iteratorSymbol = $Symbol.iterator || "@@iterator";
@@ -11907,7 +11657,7 @@ var runtime = (function (exports) {
// The ._invoke method unifies the implementations of the .next,
// .throw, and .return methods.
- generator._invoke = makeInvokeMethod(innerFn, self, context);
+ defineProperty(generator, "_invoke", { value: makeInvokeMethod(innerFn, self, context) });
return generator;
}
@@ -11968,8 +11718,12 @@ var runtime = (function (exports) {
var Gp = GeneratorFunctionPrototype.prototype =
Generator.prototype = Object.create(IteratorPrototype);
GeneratorFunction.prototype = GeneratorFunctionPrototype;
- define(Gp, "constructor", GeneratorFunctionPrototype);
- define(GeneratorFunctionPrototype, "constructor", GeneratorFunction);
+ defineProperty(Gp, "constructor", { value: GeneratorFunctionPrototype, configurable: true });
+ defineProperty(
+ GeneratorFunctionPrototype,
+ "constructor",
+ { value: GeneratorFunction, configurable: true }
+ );
GeneratorFunction.displayName = define(
GeneratorFunctionPrototype,
toStringTagSymbol,
@@ -12079,7 +11833,7 @@ var runtime = (function (exports) {
// Define the unified helper method that is used to implement .next,
// .throw, and .return (see defineIteratorMethods).
- this._invoke = enqueue;
+ defineProperty(this, "_invoke", { value: enqueue });
}
defineIteratorMethods(AsyncIterator.prototype);
@@ -12317,7 +12071,8 @@ var runtime = (function (exports) {
this.reset(true);
}
- exports.keys = function(object) {
+ exports.keys = function(val) {
+ var object = Object(val);
var keys = [];
for (var key in object) {
keys.push(key);
@@ -12727,28 +12482,20 @@ function getSize() {
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
-
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
-
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
-
var _util = require("./util.js");
-
/* eslint-disable */
-
/**
* used in docs/e2e.html
*/
require('@babel/polyfill');
-
var _require = require('../../'),
- BroadcastChannel = _require.BroadcastChannel;
-
+ BroadcastChannel = _require.BroadcastChannel;
var _require2 = require('async-test-util'),
- wait = _require2.wait,
- randomNumber = _require2.randomNumber,
- randomBoolean = _require2.randomBoolean;
-
+ wait = _require2.wait,
+ randomNumber = _require2.randomNumber,
+ randomBoolean = _require2.randomBoolean;
function run() {
console.log('run()');
console.log('navigator.userAgent: ' + navigator.userAgent);
@@ -12756,21 +12503,20 @@ function run() {
if (!methodType || methodType === '' || methodType === 'default') methodType = undefined;
console.log('methodType: ' + methodType);
var autoStart = (0, _util.getParameterByName)('autoStart');
- console.log('autoStart: ' + autoStart); // set select-input
+ console.log('autoStart: ' + autoStart);
+ // set select-input
var selectEl = document.getElementById('method-type-select');
-
selectEl.onchange = function (ev) {
var newValue = selectEl.value;
var newUrl = location.origin + location.pathname + '?methodType=' + newValue;
location = newUrl;
};
-
if (methodType) {
selectEl.value = methodType;
- } // do not increase this too much because it will cause a timeout in the CI
-
+ }
+ // do not increase this too much because it will cause a timeout in the CI
var TEST_MESSAGES = 25;
var body = document.getElementById('body');
var msgContainer = document.getElementById('messages');
@@ -12785,23 +12531,21 @@ function run() {
type: methodType
});
document.getElementById('method').innerHTML = channel.type;
+
/**
* to measure the speed, we:
* 1. send message
* 2. wait until iframe and worker answers
* 3. repeat from 1. for TEST_MESSAGES times
*/
-
var messagesSend = 0;
var answerPool = {};
var useWorker = false;
-
function gotAllAnswers(answerPool) {
if (!answerPool.iframe) return false;
if (useWorker && !answerPool.worker) return false;
return true;
}
-
window.startBroadcastChannel = /*#__PURE__*/(0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee() {
var rand, worker;
return _regenerator["default"].wrap(function _callee$(_context) {
@@ -12811,12 +12555,10 @@ function run() {
console.log('window.startBroadcastChannel()');
stateContainer.innerHTML = 'running..';
rand = new Date().getTime();
-
channel.onmessage = function (msg) {
answerPool[msg.from] = msg;
var textnode = document.createTextNode(JSON.stringify(msg) + '');
msgContainer.appendChild(textnode);
-
if (gotAllAnswers(answerPool)) {
answerPool = {}; // reset
@@ -12839,9 +12581,9 @@ function run() {
});
}
}
- }; // load iframe
-
+ };
+ // load iframe
iframeEl.src = './iframe.html?channelName=' + channel.name + '&methodType=' + channel.type + '&t=' + rand;
_context.next = 7;
return new Promise(function (res) {
@@ -12849,22 +12591,19 @@ function run() {
return res();
};
});
-
case 7:
- console.log('main: Iframe has loaded'); // spawn web-worker if possible
+ console.log('main: Iframe has loaded');
+ // spawn web-worker if possible
if (!(channel.type !== 'localstorage' && typeof window.Worker === 'function')) {
_context.next = 14;
break;
}
-
useWorker = true;
worker = new Worker('worker.js?t=' + rand);
-
worker.onerror = function (event) {
console.error('worker: ' + event.message + " (" + event.filename + ":" + event.lineno + ")");
};
-
_context.next = 14;
return new Promise(function (res) {
worker.addEventListener('message', function (e) {
@@ -12882,7 +12621,6 @@ function run() {
}
});
});
-
case 14:
console.log('========== START SENDING MESSAGES ' + channel.type);
startTime = new Date().getTime();
@@ -12891,15 +12629,15 @@ function run() {
step: 0
});
console.log('main: message send (0)');
-
case 18:
case "end":
return _context.stop();
}
}
}, _callee);
- })); // LEADER-ELECTION
+ }));
+ // LEADER-ELECTION
window.startLeaderElection = /*#__PURE__*/(0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee2() {
var FRAMES_COUNT, rand, frameSrc, leaderIframes, leaderFramesCache, amountTime;
return _regenerator["default"].wrap(function _callee2$(_context2) {
@@ -12912,14 +12650,12 @@ function run() {
rand = new Date().getTime();
frameSrc = './leader-iframe.html?channelName=' + channel.name + '&methodType=' + channel.type + '&t=' + rand;
leaderIframes = document.getElementById('leader-iframes'); // create iframes
-
leaderFramesCache = new Array(FRAMES_COUNT).fill(0).map(function () {
var ifrm = document.createElement('iframe');
ifrm.setAttribute('src', frameSrc);
leaderIframes.appendChild(ifrm);
return ifrm;
}); // wait until all iframes have loaded
-
_context2.next = 9;
return Promise.all(leaderFramesCache.map(function (iframe) {
return new Promise(function (res) {
@@ -12928,34 +12664,29 @@ function run() {
};
});
}));
-
case 9:
startTime = new Date().getTime();
+
/**
* remove the leader-iframe until no iframe is left
*/
-
case 10:
if (!(leaderFramesCache.length > 0)) {
_context2.next = 16;
break;
}
-
_context2.next = 13;
return removeLeaderIframe(leaderFramesCache);
-
case 13:
leaderFramesCache = _context2.sent;
_context2.next = 10;
break;
-
case 16:
// done
body.style.backgroundColor = 'green';
stateContainer.innerHTML = 'SUCCESS';
amountTime = new Date().getTime() - startTime;
document.getElementById('time-amount').innerHTML = amountTime + 'ms';
-
case 20:
case "end":
return _context2.stop();
@@ -12963,7 +12694,6 @@ function run() {
}
}, _callee2);
}));
-
var removeLeaderIframe = /*#__PURE__*/function () {
var _ref3 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee3(leaderFramesCache) {
var leaders;
@@ -12975,29 +12705,24 @@ function run() {
var boxText = frame.contentDocument.getElementById('box').innerHTML;
return boxText === 'Leader';
});
-
if (!(leaders.length === 0)) {
_context3.next = 3;
break;
}
-
return _context3.abrupt("return", new Promise(function (res) {
return setTimeout(function () {
res(leaderFramesCache);
}, 50);
}));
-
case 3:
if (leaders.length > 1) {
console.error('LeaderElection: There is more then one leader!');
- } // remove iframe
-
-
+ }
+ // remove iframe
leaders[0].parentNode.removeChild(leaders[0]);
return _context3.abrupt("return", leaderFramesCache.filter(function (f) {
return f !== leaders[0];
}));
-
case 6:
case "end":
return _context3.stop();
@@ -13005,13 +12730,12 @@ function run() {
}
}, _callee3);
}));
-
return function removeLeaderIframe(_x) {
return _ref3.apply(this, arguments);
};
- }(); // Worker test
-
+ }();
+ // Worker test
window.startWorkerTest = /*#__PURE__*/(0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee5() {
var worker, t, perRun, k, done, amountTime;
return _regenerator["default"].wrap(function _callee5$(_context5) {
@@ -13019,20 +12743,18 @@ function run() {
switch (_context5.prev = _context5.next) {
case 0:
console.log('window.startWorkerTest()');
- stateContainer.innerHTML = 'running..'; // spawn web-worker
+ stateContainer.innerHTML = 'running..';
+ // spawn web-worker
if (!(channel.type !== 'localstorage' && typeof window.Worker === 'function')) {
_context5.next = 8;
break;
}
-
useWorker = true;
worker = new Worker('worker.js?t=' + new Date().getTime());
-
worker.onerror = function (event) {
console.error('worker: ' + event.message + " (" + event.filename + ":" + event.lineno + ")");
};
-
_context5.next = 8;
return new Promise(function (res) {
worker.addEventListener('message', function (e) {
@@ -13050,7 +12772,6 @@ function run() {
}
});
});
-
case 8:
console.log('========== START SENDING MESSAGES ' + channel.type);
startTime = new Date().getTime();
@@ -13058,13 +12779,11 @@ function run() {
perRun = 100;
k = 0;
done = 0;
-
case 14:
if (!(t > 0)) {
_context5.next = 20;
break;
}
-
t--;
_context5.next = 18;
return Promise.all(new Array(perRun).fill(0).map( /*#__PURE__*/(0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee4() {
@@ -13077,10 +12796,8 @@ function run() {
_context4.next = 3;
break;
}
-
_context4.next = 3;
return wait(randomNumber(10, 150));
-
case 3:
msgId = 'worker-test-' + startTime + '-' + k++;
waitForResponsePromise = new Promise(function (res) {
@@ -13094,7 +12811,6 @@ function run() {
res();
}
};
-
channel.addEventListener('message', listener);
});
channel.postMessage({
@@ -13113,7 +12829,6 @@ function run() {
throw new Error(errorMessage);
}
});
-
case 8:
case "end":
return _context4.stop();
@@ -13121,17 +12836,14 @@ function run() {
}
}, _callee4);
}))));
-
case 18:
_context5.next = 14;
break;
-
case 20:
body.style.backgroundColor = 'green';
stateContainer.innerHTML = 'SUCCESS';
amountTime = new Date().getTime() - startTime;
document.getElementById('time-amount').innerHTML = amountTime + 'ms';
-
case 24:
case "end":
return _context5.stop();
@@ -13139,14 +12851,11 @@ function run() {
}
}, _callee5);
}));
-
if (autoStart && autoStart !== '') {
window[autoStart]();
}
}
-
;
-
try {
run();
} catch (error) {
@@ -13160,8 +12869,8 @@ Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getParameterByName = getParameterByName;
-
/* eslint no-useless-escape: "off" */
+
// https://stackoverflow.com/a/901144/3443137
function getParameterByName(name, url) {
if (!url) url = window.location.href;
diff --git a/docs/iframe.js b/docs/iframe.js
index 3dc97c16..c1dff4a7 100644
--- a/docs/iframe.js
+++ b/docs/iframe.js
@@ -7,13 +7,9 @@ Object.defineProperty(exports, "__esModule", {
exports.OPEN_BROADCAST_CHANNELS = exports.BroadcastChannel = void 0;
exports.clearNodeFolder = clearNodeFolder;
exports.enforceOptions = enforceOptions;
-
var _util = require("./util.js");
-
var _methodChooser = require("./method-chooser.js");
-
var _options = require("./options.js");
-
/**
* Contains all open channels,
* used in tests to ensure everything is closed.
@@ -21,77 +17,73 @@ var _options = require("./options.js");
var OPEN_BROADCAST_CHANNELS = new Set();
exports.OPEN_BROADCAST_CHANNELS = OPEN_BROADCAST_CHANNELS;
var lastId = 0;
-
var BroadcastChannel = function BroadcastChannel(name, options) {
// identifier of the channel to debug stuff
this.id = lastId++;
OPEN_BROADCAST_CHANNELS.add(this);
this.name = name;
-
if (ENFORCED_OPTIONS) {
options = ENFORCED_OPTIONS;
}
-
this.options = (0, _options.fillOptionsWithDefaults)(options);
- this.method = (0, _methodChooser.chooseMethod)(this.options); // isListening
+ this.method = (0, _methodChooser.chooseMethod)(this.options);
+ // isListening
this._iL = false;
+
/**
* _onMessageListener
* setting onmessage twice,
* will overwrite the first listener
*/
-
this._onML = null;
+
/**
* _addEventListeners
*/
-
this._addEL = {
message: [],
internal: []
};
+
/**
* Unsend message promises
* where the sending is still in progress
* @type {Set}
*/
-
this._uMP = new Set();
+
/**
* _beforeClose
* array of promises that will be awaited
* before the channel is closed
*/
-
this._befC = [];
+
/**
* _preparePromise
*/
-
this._prepP = null;
-
_prepareChannel(this);
-}; // STATICS
+};
+
+// STATICS
/**
* used to identify if someone overwrites
* window.BroadcastChannel with this
* See methods/native.js
*/
-
-
exports.BroadcastChannel = BroadcastChannel;
BroadcastChannel._pubkey = true;
+
/**
* clears the tmp-folder if is node
* @return {Promise} true if has run, false if not node
*/
-
function clearNodeFolder(options) {
options = (0, _options.fillOptionsWithDefaults)(options);
var method = (0, _methodChooser.chooseMethod)(options);
-
if (method.type === 'node') {
return method.clearNodeFolder().then(function () {
return true;
@@ -100,19 +92,17 @@ function clearNodeFolder(options) {
return _util.PROMISE_RESOLVED_FALSE;
}
}
+
/**
* if set, this method is enforced,
* no mather what the options are
*/
-
-
var ENFORCED_OPTIONS;
-
function enforceOptions(options) {
ENFORCED_OPTIONS = options;
-} // PROTOTYPE
-
+}
+// PROTOTYPE
BroadcastChannel.prototype = {
postMessage: function postMessage(msg) {
if (this.closed) {
@@ -124,87 +114,77 @@ BroadcastChannel.prototype = {
*/
JSON.stringify(msg));
}
-
return _post(this, 'message', msg);
},
postInternal: function postInternal(msg) {
return _post(this, 'internal', msg);
},
-
set onmessage(fn) {
var time = this.method.microSeconds();
var listenObj = {
time: time,
fn: fn
};
-
_removeListenerObject(this, 'message', this._onML);
-
if (fn && typeof fn === 'function') {
this._onML = listenObj;
-
_addListenerObject(this, 'message', listenObj);
} else {
this._onML = null;
}
},
-
addEventListener: function addEventListener(type, fn) {
var time = this.method.microSeconds();
var listenObj = {
time: time,
fn: fn
};
-
_addListenerObject(this, type, listenObj);
},
removeEventListener: function removeEventListener(type, fn) {
var obj = this._addEL[type].find(function (obj) {
return obj.fn === fn;
});
-
_removeListenerObject(this, type, obj);
},
close: function close() {
var _this = this;
-
if (this.closed) {
return;
}
-
OPEN_BROADCAST_CHANNELS["delete"](this);
this.closed = true;
var awaitPrepare = this._prepP ? this._prepP : _util.PROMISE_RESOLVED_VOID;
this._onML = null;
this._addEL.message = [];
- return awaitPrepare // wait until all current sending are processed
+ return awaitPrepare
+ // wait until all current sending are processed
.then(function () {
return Promise.all(Array.from(_this._uMP));
- }) // run before-close hooks
+ })
+ // run before-close hooks
.then(function () {
return Promise.all(_this._befC.map(function (fn) {
return fn();
}));
- }) // close the channel
+ })
+ // close the channel
.then(function () {
return _this.method.close(_this._state);
});
},
-
get type() {
return this.method.type;
},
-
get isClosed() {
return this.closed;
}
-
};
+
/**
* Post a message over the channel
* @returns {Promise} that resolved when the message sending is done
*/
-
function _post(broadcastChannel, type, msg) {
var time = broadcastChannel.method.microSeconds();
var msgObj = {
@@ -214,25 +194,22 @@ function _post(broadcastChannel, type, msg) {
};
var awaitPrepare = broadcastChannel._prepP ? broadcastChannel._prepP : _util.PROMISE_RESOLVED_VOID;
return awaitPrepare.then(function () {
- var sendPromise = broadcastChannel.method.postMessage(broadcastChannel._state, msgObj); // add/remove to unsend messages list
+ var sendPromise = broadcastChannel.method.postMessage(broadcastChannel._state, msgObj);
+ // add/remove to unsend messages list
broadcastChannel._uMP.add(sendPromise);
-
sendPromise["catch"]().then(function () {
return broadcastChannel._uMP["delete"](sendPromise);
});
return sendPromise;
});
}
-
function _prepareChannel(channel) {
var maybePromise = channel.method.create(channel.name, channel.options);
-
if ((0, _util.isPromise)(maybePromise)) {
channel._prepP = maybePromise;
maybePromise.then(function (s) {
// used in tests to simulate slow runtime
-
/*if (channel.options.prepareDelay) {
await new Promise(res => setTimeout(res, this.options.prepareDelay));
}*/
@@ -242,30 +219,25 @@ function _prepareChannel(channel) {
channel._state = maybePromise;
}
}
-
function _hasMessageListeners(channel) {
if (channel._addEL.message.length > 0) return true;
if (channel._addEL.internal.length > 0) return true;
return false;
}
-
function _addListenerObject(channel, type, obj) {
channel._addEL[type].push(obj);
-
_startListening(channel);
}
-
function _removeListenerObject(channel, type, obj) {
channel._addEL[type] = channel._addEL[type].filter(function (o) {
return o !== obj;
});
-
_stopListening(channel);
}
-
function _startListening(channel) {
if (!channel._iL && _hasMessageListeners(channel)) {
// someone is listening, start subscribing
+
var listenerFn = function listenerFn(msgObj) {
channel._addEL[msgObj.type].forEach(function (listenerObject) {
/**
@@ -279,15 +251,12 @@ function _startListening(channel) {
*/
var hundredMsInMicro = 100 * 1000;
var minMessageTime = listenerObject.time - hundredMsInMicro;
-
if (msgObj.time >= minMessageTime) {
listenerObject.fn(msgObj.data);
}
});
};
-
var time = channel.method.microSeconds();
-
if (channel._prepP) {
channel._prepP.then(function () {
channel._iL = true;
@@ -299,7 +268,6 @@ function _startListening(channel) {
}
}
}
-
function _stopListening(channel) {
if (channel._iL && !_hasMessageListeners(channel)) {
// noone is listening, stop subscribing
@@ -312,7 +280,6 @@ function _stopListening(channel) {
"use strict";
var _index = require("./index.js");
-
/**
* because babel can only export on default-attribute,
* we use this for the non-module-build
@@ -321,6 +288,7 @@ var _index = require("./index.js");
* but
* var BroadcastChannel = require('broadcast-channel');
*/
+
module.exports = {
BroadcastChannel: _index.BroadcastChannel,
createLeaderElection: _index.createLeaderElection,
@@ -370,9 +338,7 @@ Object.defineProperty(exports, "enforceOptions", {
return _broadcastChannel.enforceOptions;
}
});
-
var _broadcastChannel = require("./broadcast-channel.js");
-
var _leaderElection = require("./leader-election.js");
},{"./broadcast-channel.js":1,"./leader-election.js":4}],4:[function(require,module,exports){
"use strict";
@@ -382,37 +348,30 @@ Object.defineProperty(exports, "__esModule", {
});
exports.beLeader = beLeader;
exports.createLeaderElection = createLeaderElection;
-
var _util = require("./util.js");
-
var _unload = require("unload");
-
var LeaderElection = function LeaderElection(broadcastChannel, options) {
var _this = this;
-
this.broadcastChannel = broadcastChannel;
this._options = options;
this.isLeader = false;
this.hasLeader = false;
this.isDead = false;
this.token = (0, _util.randomToken)();
+
/**
* Apply Queue,
* used to ensure we do not run applyOnce()
* in parallel.
*/
+ this._aplQ = _util.PROMISE_RESOLVED_VOID;
+ // amount of unfinished applyOnce() calls
+ this._aplQC = 0;
- this._aplQ = _util.PROMISE_RESOLVED_VOID; // amount of unfinished applyOnce() calls
-
- this._aplQC = 0; // things to clean up
-
+ // things to clean up
this._unl = []; // _unloads
-
this._lstns = []; // _listeners
-
this._dpL = function () {}; // onduplicate listener
-
-
this._dpLC = false; // true when onduplicate called
/**
@@ -420,55 +379,47 @@ var LeaderElection = function LeaderElection(broadcastChannel, options) {
* we still listen to messages to ensure the hasLeader flag
* is set correctly.
*/
-
var hasLeaderListener = function hasLeaderListener(msg) {
if (msg.context === 'leader') {
if (msg.action === 'death') {
_this.hasLeader = false;
}
-
if (msg.action === 'tell') {
_this.hasLeader = true;
}
}
};
-
this.broadcastChannel.addEventListener('internal', hasLeaderListener);
-
this._lstns.push(hasLeaderListener);
};
-
LeaderElection.prototype = {
/**
* Returns true if the instance is leader,
* false if not.
* @async
*/
- applyOnce: function applyOnce( // true if the applyOnce() call came from the fallbackInterval cycle
+ applyOnce: function applyOnce(
+ // true if the applyOnce() call came from the fallbackInterval cycle
isFromFallbackInterval) {
var _this2 = this;
-
if (this.isLeader) {
return (0, _util.sleep)(0, true);
}
-
if (this.isDead) {
return (0, _util.sleep)(0, false);
}
+
/**
* Already applying more then once,
* -> wait for the apply queue to be finished.
*/
-
-
if (this._aplQC > 1) {
return this._aplQ;
}
+
/**
* Add a new apply-run
*/
-
-
var applyRun = function applyRun() {
/**
* Optimization shortcuts.
@@ -478,7 +429,6 @@ LeaderElection.prototype = {
if (_this2.isLeader) {
return _util.PROMISE_RESOLVED_TRUE;
}
-
var stopCriteria = false;
var stopCriteriaPromiseResolve;
/**
@@ -487,7 +437,6 @@ LeaderElection.prototype = {
* have to await the responseTime when it is already clear
* that the election failed.
*/
-
var stopCriteriaPromise = new Promise(function (res) {
stopCriteriaPromiseResolve = function stopCriteriaPromiseResolve() {
stopCriteria = true;
@@ -495,11 +444,9 @@ LeaderElection.prototype = {
};
});
var recieved = [];
-
var handleMessage = function handleMessage(msg) {
if (msg.context === 'leader' && msg.token != _this2.token) {
recieved.push(msg);
-
if (msg.action === 'apply') {
// other is applying
if (msg.token > _this2.token) {
@@ -510,7 +457,6 @@ LeaderElection.prototype = {
stopCriteriaPromiseResolve();
}
}
-
if (msg.action === 'tell') {
// other is already leader
stopCriteriaPromiseResolve();
@@ -518,8 +464,8 @@ LeaderElection.prototype = {
}
}
};
-
_this2.broadcastChannel.addEventListener('internal', handleMessage);
+
/**
* If the applyOnce() call came from the fallbackInterval,
* we can assume that the election runs in the background and
@@ -530,26 +476,24 @@ LeaderElection.prototype = {
* But also it takes longer which is not a problem because we anyway
* run in the background.
*/
-
-
var waitForAnswerTime = isFromFallbackInterval ? _this2._options.responseTime * 4 : _this2._options.responseTime;
-
var applyPromise = _sendMessage(_this2, 'apply') // send out that this one is applying
.then(function () {
return Promise.race([(0, _util.sleep)(waitForAnswerTime), stopCriteriaPromise.then(function () {
return Promise.reject(new Error());
})]);
- }) // send again in case another instance was just created
+ })
+ // send again in case another instance was just created
.then(function () {
return _sendMessage(_this2, 'apply');
- }) // let others time to respond
+ })
+ // let others time to respond
.then(function () {
return Promise.race([(0, _util.sleep)(waitForAnswerTime), stopCriteriaPromise.then(function () {
return Promise.reject(new Error());
})]);
})["catch"](function () {}).then(function () {
_this2.broadcastChannel.removeEventListener('internal', handleMessage);
-
if (!stopCriteria) {
// no stop criteria -> own is leader
return beLeader(_this2).then(function () {
@@ -560,10 +504,8 @@ LeaderElection.prototype = {
return false;
}
});
-
return applyPromise;
};
-
this._aplQC = this._aplQC + 1;
this._aplQ = this._aplQ.then(function () {
return applyRun();
@@ -575,82 +517,68 @@ LeaderElection.prototype = {
});
},
awaitLeadership: function awaitLeadership() {
- if (
- /* _awaitLeadershipPromise */
+ if ( /* _awaitLeadershipPromise */
!this._aLP) {
this._aLP = _awaitLeadershipOnce(this);
}
-
return this._aLP;
},
-
set onduplicate(fn) {
this._dpL = fn;
},
-
die: function die() {
var _this3 = this;
-
this._lstns.forEach(function (listener) {
return _this3.broadcastChannel.removeEventListener('internal', listener);
});
-
this._lstns = [];
-
this._unl.forEach(function (uFn) {
return uFn.remove();
});
-
this._unl = [];
-
if (this.isLeader) {
this.hasLeader = false;
this.isLeader = false;
}
-
this.isDead = true;
return _sendMessage(this, 'death');
}
};
+
/**
* @param leaderElector {LeaderElector}
*/
-
function _awaitLeadershipOnce(leaderElector) {
if (leaderElector.isLeader) {
return _util.PROMISE_RESOLVED_VOID;
}
-
return new Promise(function (res) {
var resolved = false;
-
function finish() {
if (resolved) {
return;
}
-
resolved = true;
leaderElector.broadcastChannel.removeEventListener('internal', whenDeathListener);
res(true);
- } // try once now
-
+ }
+ // try once now
leaderElector.applyOnce().then(function () {
if (leaderElector.isLeader) {
finish();
}
});
+
/**
* Try on fallbackInterval
* @recursive
*/
-
var tryOnFallBack = function tryOnFallBack() {
return (0, _util.sleep)(leaderElector._options.fallbackInterval).then(function () {
if (leaderElector.isDead || resolved) {
return;
}
-
if (leaderElector.isLeader) {
finish();
} else {
@@ -664,9 +592,9 @@ function _awaitLeadershipOnce(leaderElector) {
}
});
};
+ tryOnFallBack();
- tryOnFallBack(); // try when other leader dies
-
+ // try when other leader dies
var whenDeathListener = function whenDeathListener(msg) {
if (msg.context === 'leader' && msg.action === 'death') {
leaderElector.hasLeader = false;
@@ -677,17 +605,14 @@ function _awaitLeadershipOnce(leaderElector) {
});
}
};
-
leaderElector.broadcastChannel.addEventListener('internal', whenDeathListener);
-
leaderElector._lstns.push(whenDeathListener);
});
}
+
/**
* sends and internal message over the broadcast-channel
*/
-
-
function _sendMessage(leaderElector, action) {
var msgJson = {
context: 'leader',
@@ -696,21 +621,17 @@ function _sendMessage(leaderElector, action) {
};
return leaderElector.broadcastChannel.postInternal(msgJson);
}
-
function beLeader(leaderElector) {
leaderElector.isLeader = true;
leaderElector.hasLeader = true;
var unloadFn = (0, _unload.add)(function () {
return leaderElector.die();
});
-
leaderElector._unl.push(unloadFn);
-
var isLeaderListener = function isLeaderListener(msg) {
if (msg.context === 'leader' && msg.action === 'apply') {
_sendMessage(leaderElector, 'tell');
}
-
if (msg.context === 'leader' && msg.action === 'tell' && !leaderElector._dpLC) {
/**
* another instance is also leader!
@@ -721,49 +642,35 @@ function beLeader(leaderElector) {
* @link https://github.com/pubkey/broadcast-channel/issues/385
*/
leaderElector._dpLC = true;
-
leaderElector._dpL(); // message the lib user so the app can handle the problem
-
-
_sendMessage(leaderElector, 'tell'); // ensure other leader also knows the problem
-
}
};
leaderElector.broadcastChannel.addEventListener('internal', isLeaderListener);
-
leaderElector._lstns.push(isLeaderListener);
-
return _sendMessage(leaderElector, 'tell');
}
-
function fillOptionsWithDefaults(options, channel) {
if (!options) options = {};
options = JSON.parse(JSON.stringify(options));
-
if (!options.fallbackInterval) {
options.fallbackInterval = 3000;
}
-
if (!options.responseTime) {
options.responseTime = channel.method.averageResponseTime(channel.options);
}
-
return options;
}
-
function createLeaderElection(channel, options) {
if (channel._leaderElector) {
throw new Error('BroadcastChannel already has a leader-elector');
}
-
options = fillOptionsWithDefaults(options, channel);
var elector = new LeaderElection(channel, options);
-
channel._befC.push(function () {
return elector.die();
});
-
channel._leaderElector = elector;
return elector;
}
@@ -771,59 +678,49 @@ function createLeaderElection(channel, options) {
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
-
var _typeof = require("@babel/runtime/helpers/typeof");
-
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.chooseMethod = chooseMethod;
-
var _native = _interopRequireDefault(require("./methods/native.js"));
-
var _indexedDb = _interopRequireDefault(require("./methods/indexed-db.js"));
-
var _localstorage = _interopRequireDefault(require("./methods/localstorage.js"));
-
var _simulate = _interopRequireDefault(require("./methods/simulate.js"));
-
-
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
-
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
-
// the line below will be removed from es5/browser builds
+
// order is important
-var METHODS = [_native["default"], // fastest
+var METHODS = [_native["default"],
+// fastest
_indexedDb["default"], _localstorage["default"]];
-
function chooseMethod(options) {
- var chooseMethods = [].concat(options.methods, METHODS).filter(Boolean); // the line below will be removed from es5/browser builds
+ var chooseMethods = [].concat(options.methods, METHODS).filter(Boolean);
+ // the line below will be removed from es5/browser builds
+ // directly chosen
if (options.type) {
if (options.type === 'simulate') {
// only use simulate-method if directly chosen
return _simulate["default"];
}
-
var ret = chooseMethods.find(function (m) {
return m.type === options.type;
});
if (!ret) throw new Error('method-type ' + options.type + ' not found');else return ret;
}
+
/**
* if no webworker support is needed,
* remove idb from the list so that localstorage is been chosen
*/
-
-
if (!options.webWorkerSupport) {
chooseMethods = chooseMethods.filter(function (m) {
return m.type !== 'idb';
});
}
-
var useMethod = chooseMethods.find(function (method) {
return method.canBeUsed();
});
@@ -856,13 +753,9 @@ exports.postMessage = postMessage;
exports.removeMessagesById = removeMessagesById;
exports.type = void 0;
exports.writeMessage = writeMessage;
-
var _util = require("../util.js");
-
var _obliviousSet = require("oblivious-set");
-
var _options = require("../options.js");
-
/**
* this method uses indexeddb to store the messages
* There is currently no observerAPI for idb
@@ -871,58 +764,54 @@ var _options = require("../options.js");
* When working on this, ensure to use these performance optimizations:
* @link https://rxdb.info/slow-indexeddb.html
*/
+
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var DB_PREFIX = 'pubkey.broadcast-channel-0-';
var OBJECT_STORE_ID = 'messages';
+
/**
* Use relaxed durability for faster performance on all transactions.
* @link https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/
*/
-
var TRANSACTION_SETTINGS = {
durability: 'relaxed'
};
exports.TRANSACTION_SETTINGS = TRANSACTION_SETTINGS;
var type = 'idb';
exports.type = type;
-
function getIdb() {
if (typeof indexedDB !== 'undefined') return indexedDB;
-
if (typeof window !== 'undefined') {
if (typeof window.mozIndexedDB !== 'undefined') return window.mozIndexedDB;
if (typeof window.webkitIndexedDB !== 'undefined') return window.webkitIndexedDB;
if (typeof window.msIndexedDB !== 'undefined') return window.msIndexedDB;
}
-
return false;
}
+
/**
* If possible, we should explicitly commit IndexedDB transactions
* for better performance.
* @link https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/
*/
-
-
function commitIndexedDBTransaction(tx) {
if (tx.commit) {
tx.commit();
}
}
-
function createDatabase(channelName) {
- var IndexedDB = getIdb(); // create table
+ var IndexedDB = getIdb();
+ // create table
var dbName = DB_PREFIX + channelName;
+
/**
* All IndexedDB databases are opened without version
* because it is a bit faster, especially on firefox
* @link http://nparashuram.com/IndexedDB/perf/#Open%20Database%20with%20version
*/
-
var openRequest = IndexedDB.open(dbName);
-
openRequest.onupgradeneeded = function (ev) {
var db = ev.target.result;
db.createObjectStore(OBJECT_STORE_ID, {
@@ -930,24 +819,21 @@ function createDatabase(channelName) {
autoIncrement: true
});
};
-
var dbPromise = new Promise(function (res, rej) {
openRequest.onerror = function (ev) {
return rej(ev);
};
-
openRequest.onsuccess = function () {
res(openRequest.result);
};
});
return dbPromise;
}
+
/**
* writes the new message to the database
* so other readers can find it
*/
-
-
function writeMessage(db, readerUuid, messageJson) {
var time = new Date().getTime();
var writeObject = {
@@ -960,17 +846,14 @@ function writeMessage(db, readerUuid, messageJson) {
tx.oncomplete = function () {
return res();
};
-
tx.onerror = function (ev) {
return rej(ev);
};
-
var objectStore = tx.objectStore(OBJECT_STORE_ID);
objectStore.add(writeObject);
commitIndexedDBTransaction(tx);
});
}
-
function getAllMessages(db) {
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS);
var objectStore = tx.objectStore(OBJECT_STORE_ID);
@@ -978,10 +861,9 @@ function getAllMessages(db) {
return new Promise(function (res) {
objectStore.openCursor().onsuccess = function (ev) {
var cursor = ev.target.result;
-
if (cursor) {
- ret.push(cursor.value); //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
-
+ ret.push(cursor.value);
+ //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor["continue"]();
} else {
commitIndexedDBTransaction(tx);
@@ -990,31 +872,28 @@ function getAllMessages(db) {
};
});
}
-
function getMessagesHigherThan(db, lastCursorId) {
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS);
var objectStore = tx.objectStore(OBJECT_STORE_ID);
var ret = [];
var keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity);
+
/**
* Optimization shortcut,
* if getAll() can be used, do not use a cursor.
* @link https://rxdb.info/slow-indexeddb.html
*/
-
if (objectStore.getAll) {
var getAllRequest = objectStore.getAll(keyRangeValue);
return new Promise(function (res, rej) {
getAllRequest.onerror = function (err) {
return rej(err);
};
-
getAllRequest.onsuccess = function (e) {
res(e.target.result);
};
});
}
-
function openCursor() {
// Occasionally Safari will fail on IDBKeyRange.bound, this
// catches that error, having it open the cursor to the first
@@ -1026,17 +905,13 @@ function getMessagesHigherThan(db, lastCursorId) {
return objectStore.openCursor();
}
}
-
return new Promise(function (res, rej) {
var openCursorRequest = openCursor();
-
openCursorRequest.onerror = function (err) {
return rej(err);
};
-
openCursorRequest.onsuccess = function (ev) {
var cursor = ev.target.result;
-
if (cursor) {
if (cursor.value.id < lastCursorId + 1) {
cursor["continue"](lastCursorId + 1);
@@ -1051,12 +926,10 @@ function getMessagesHigherThan(db, lastCursorId) {
};
});
}
-
function removeMessagesById(channelState, ids) {
if (channelState.closed) {
return Promise.resolve([]);
}
-
var tx = channelState.db.transaction(OBJECT_STORE_ID, 'readwrite', TRANSACTION_SETTINGS);
var objectStore = tx.objectStore(OBJECT_STORE_ID);
return Promise.all(ids.map(function (id) {
@@ -1068,7 +941,6 @@ function removeMessagesById(channelState, ids) {
});
}));
}
-
function getOldMessages(db, ttl) {
var olderThen = new Date().getTime() - ttl;
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS);
@@ -1077,13 +949,11 @@ function getOldMessages(db, ttl) {
return new Promise(function (res) {
objectStore.openCursor().onsuccess = function (ev) {
var cursor = ev.target.result;
-
if (cursor) {
var msgObk = cursor.value;
-
if (msgObk.time < olderThen) {
- ret.push(msgObk); //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
-
+ ret.push(msgObk);
+ //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor["continue"]();
} else {
// no more old messages,
@@ -1097,7 +967,6 @@ function getOldMessages(db, ttl) {
};
});
}
-
function cleanOldMessages(channelState) {
return getOldMessages(channelState.db, channelState.options.idb.ttl).then(function (tooOld) {
return removeMessagesById(channelState, tooOld.map(function (msg) {
@@ -1105,7 +974,6 @@ function cleanOldMessages(channelState) {
}));
});
}
-
function create(channelName, options) {
options = (0, _options.fillOptionsWithDefaults)(options);
return createDatabase(channelName).then(function (db) {
@@ -1115,7 +983,6 @@ function create(channelName, options) {
channelName: channelName,
options: options,
uuid: (0, _util.randomToken)(),
-
/**
* emittedMessagesIds
* contains all messages that have been emitted before
@@ -1128,30 +995,27 @@ function create(channelName, options) {
readQueuePromises: [],
db: db
};
+
/**
* Handle abrupt closes that do not originate from db.close().
* This could happen, for example, if the underlying storage is
* removed or if the user clears the database in the browser's
* history preferences.
*/
-
db.onclose = function () {
state.closed = true;
if (options.idb.onclose) options.idb.onclose();
};
+
/**
* if service-workers are used,
* we have no 'storage'-event if they post a message,
* therefore we also have to set an interval
*/
-
-
_readLoop(state);
-
return state;
});
}
-
function _readLoop(state) {
if (state.closed) return;
readNewMessages(state).then(function () {
@@ -1160,25 +1024,21 @@ function _readLoop(state) {
return _readLoop(state);
});
}
-
function _filterMessage(msgObj, state) {
if (msgObj.uuid === state.uuid) return false; // send by own
-
if (state.eMIs.has(msgObj.id)) return false; // already emitted
-
if (msgObj.data.time < state.messagesCallbackTime) return false; // older then onMessageCallback
-
return true;
}
+
/**
* reads all new messages from the database and emits them
*/
-
-
function readNewMessages(state) {
// channel already closed
- if (state.closed) return _util.PROMISE_RESOLVED_VOID; // if no one is listening, we do not need to scan for new messages
+ if (state.closed) return _util.PROMISE_RESOLVED_VOID;
+ // if no one is listening, we do not need to scan for new messages
if (!state.messagesCallback) return _util.PROMISE_RESOLVED_VOID;
return getMessagesHigherThan(state.db, state.lastCursorId).then(function (newerMessages) {
var useMessages = newerMessages
@@ -1186,21 +1046,18 @@ function readNewMessages(state) {
* there is a bug in iOS where the msgObj can be undefined some times
* so we filter them out
* @link https://github.com/pubkey/broadcast-channel/issues/19
- */
- .filter(function (msgObj) {
+ */.filter(function (msgObj) {
return !!msgObj;
}).map(function (msgObj) {
if (msgObj.id > state.lastCursorId) {
state.lastCursorId = msgObj.id;
}
-
return msgObj;
}).filter(function (msgObj) {
return _filterMessage(msgObj, state);
}).sort(function (msgObjA, msgObjB) {
return msgObjA.time - msgObjB.time;
}); // sort by time
-
useMessages.forEach(function (msgObj) {
if (state.messagesCallback) {
state.eMIs.add(msgObj.id);
@@ -1210,12 +1067,10 @@ function readNewMessages(state) {
return _util.PROMISE_RESOLVED_VOID;
});
}
-
function close(channelState) {
channelState.closed = true;
channelState.db.close();
}
-
function postMessage(channelState, messageJson) {
channelState.writeBlockPromise = channelState.writeBlockPromise.then(function () {
return writeMessage(channelState.db, channelState.uuid, messageJson);
@@ -1227,27 +1082,21 @@ function postMessage(channelState, messageJson) {
});
return channelState.writeBlockPromise;
}
-
function onMessage(channelState, fn, time) {
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
readNewMessages(channelState);
}
-
function canBeUsed() {
var idb = getIdb();
-
if (!idb) {
return false;
}
-
return true;
}
-
function averageResponseTime(options) {
return options.idb.fallbackInterval * 2;
}
-
var _default = {
create: create,
close: close,
@@ -1278,13 +1127,9 @@ exports.postMessage = postMessage;
exports.removeStorageEventListener = removeStorageEventListener;
exports.storageKey = storageKey;
exports.type = void 0;
-
var _obliviousSet = require("oblivious-set");
-
var _options = require("../options.js");
-
var _util = require("../util.js");
-
/**
* A localStorage-only method which uses localstorage and its 'storage'-event
* This does not work inside of webworkers because they have no access to locastorage
@@ -1292,41 +1137,38 @@ var _util = require("../util.js");
* @link https://caniuse.com/#feat=namevalue-storage
* @link https://caniuse.com/#feat=indexeddb
*/
+
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var KEY_PREFIX = 'pubkey.broadcastChannel-';
var type = 'localstorage';
+
/**
* copied from crosstab
* @link https://github.com/tejacques/crosstab/blob/master/src/crosstab.js#L32
*/
-
exports.type = type;
-
function getLocalStorage() {
var localStorage;
if (typeof window === 'undefined') return null;
-
try {
localStorage = window.localStorage;
localStorage = window['ie8-eventlistener/storage'] || window.localStorage;
- } catch (e) {// New versions of Firefox throw a Security exception
+ } catch (e) {
+ // New versions of Firefox throw a Security exception
// if cookies are disabled. See
// https://bugzilla.mozilla.org/show_bug.cgi?id=1028153
}
-
return localStorage;
}
-
function storageKey(channelName) {
return KEY_PREFIX + channelName;
}
+
/**
* writes the new message to the storage
* and fires the storage-event so other readers can find it
*/
-
-
function postMessage(channelState, messageJson) {
return new Promise(function (res) {
(0, _util.sleep)().then(function () {
@@ -1339,12 +1181,12 @@ function postMessage(channelState, messageJson) {
};
var value = JSON.stringify(writeObj);
getLocalStorage().setItem(key, value);
+
/**
* StorageEvent does not fire the 'storage' event
* in the window that changes the state of the local storage.
* So we fire it manually
*/
-
var ev = document.createEvent('Event');
ev.initEvent('storage', true, true);
ev.key = key;
@@ -1354,52 +1196,42 @@ function postMessage(channelState, messageJson) {
});
});
}
-
function addStorageEventListener(channelName, fn) {
var key = storageKey(channelName);
-
var listener = function listener(ev) {
if (ev.key === key) {
fn(JSON.parse(ev.newValue));
}
};
-
window.addEventListener('storage', listener);
return listener;
}
-
function removeStorageEventListener(listener) {
window.removeEventListener('storage', listener);
}
-
function create(channelName, options) {
options = (0, _options.fillOptionsWithDefaults)(options);
-
if (!canBeUsed()) {
throw new Error('BroadcastChannel: localstorage cannot be used');
}
-
var uuid = (0, _util.randomToken)();
+
/**
* eMIs
* contains all messages that have been emitted before
* @type {ObliviousSet}
*/
-
var eMIs = new _obliviousSet.ObliviousSet(options.localstorage.removeTimeout);
var state = {
channelName: channelName,
uuid: uuid,
eMIs: eMIs // emittedMessagesIds
-
};
+
state.listener = addStorageEventListener(channelName, function (msgObj) {
if (!state.messagesCallback) return; // no listener
-
if (msgObj.uuid === uuid) return; // own message
-
if (!msgObj.token || eMIs.has(msgObj.token)) return; // already emitted
-
if (msgObj.data.time && msgObj.data.time < state.messagesCallbackTime) return; // too old
eMIs.add(msgObj.token);
@@ -1407,20 +1239,16 @@ function create(channelName, options) {
});
return state;
}
-
function close(channelState) {
removeStorageEventListener(channelState.listener);
}
-
function onMessage(channelState, fn, time) {
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
}
-
function canBeUsed() {
var ls = getLocalStorage();
if (!ls) return false;
-
try {
var key = '__broadcastchannel_check';
ls.setItem(key, 'works');
@@ -1431,22 +1259,17 @@ function canBeUsed() {
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API#Private_Browsing_Incognito_modes
return false;
}
-
return true;
}
-
function averageResponseTime() {
var defaultTime = 120;
var userAgent = navigator.userAgent.toLowerCase();
-
if (userAgent.includes('safari') && !userAgent.includes('chrome')) {
// safari is much slower so this time is higher
return defaultTime * 2;
}
-
return defaultTime;
}
-
var _default = {
create: create,
close: close,
@@ -1472,20 +1295,16 @@ exports.microSeconds = exports["default"] = void 0;
exports.onMessage = onMessage;
exports.postMessage = postMessage;
exports.type = void 0;
-
var _util = require("../util.js");
-
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var type = 'native';
exports.type = type;
-
function create(channelName) {
var state = {
messagesCallback: null,
bc: new BroadcastChannel(channelName),
subFns: [] // subscriberFunctions
-
};
state.bc.onmessage = function (msg) {
@@ -1493,15 +1312,12 @@ function create(channelName) {
state.messagesCallback(msg.data);
}
};
-
return state;
}
-
function close(channelState) {
channelState.bc.close();
channelState.subFns = [];
}
-
function postMessage(channelState, messageJson) {
try {
channelState.bc.postMessage(messageJson, false);
@@ -1510,31 +1326,25 @@ function postMessage(channelState, messageJson) {
return Promise.reject(err);
}
}
-
function onMessage(channelState, fn) {
channelState.messagesCallback = fn;
}
-
function canBeUsed() {
if (typeof window === 'undefined') {
return false;
}
-
if (typeof BroadcastChannel === 'function') {
if (BroadcastChannel._pubkey) {
throw new Error('BroadcastChannel: Do not overwrite window.BroadcastChannel with this module, this is not a polyfill');
}
-
return true;
} else {
return false;
}
}
-
function averageResponseTime() {
return 150;
}
-
var _default = {
create: create,
close: close,
@@ -1560,15 +1370,12 @@ exports.microSeconds = exports["default"] = void 0;
exports.onMessage = onMessage;
exports.postMessage = postMessage;
exports.type = void 0;
-
var _util = require("../util.js");
-
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var type = 'simulate';
exports.type = type;
var SIMULATE_CHANNELS = new Set();
-
function create(channelName) {
var state = {
name: channelName,
@@ -1577,11 +1384,9 @@ function create(channelName) {
SIMULATE_CHANNELS.add(state);
return state;
}
-
function close(channelState) {
SIMULATE_CHANNELS["delete"](channelState);
}
-
function postMessage(channelState, messageJson) {
return new Promise(function (res) {
return setTimeout(function () {
@@ -1599,19 +1404,15 @@ function postMessage(channelState, messageJson) {
}, 5);
});
}
-
function onMessage(channelState, fn) {
channelState.messagesCallback = fn;
}
-
function canBeUsed() {
return true;
}
-
function averageResponseTime() {
return 5;
}
-
var _default = {
create: create,
close: close,
@@ -1630,33 +1431,35 @@ Object.defineProperty(exports, "__esModule", {
value: true
});
exports.fillOptionsWithDefaults = fillOptionsWithDefaults;
-
function fillOptionsWithDefaults() {
var originalOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- var options = JSON.parse(JSON.stringify(originalOptions)); // main
-
- if (typeof options.webWorkerSupport === 'undefined') options.webWorkerSupport = true; // indexed-db
+ var options = JSON.parse(JSON.stringify(originalOptions));
- if (!options.idb) options.idb = {}; // after this time the messages get deleted
+ // main
+ if (typeof options.webWorkerSupport === 'undefined') options.webWorkerSupport = true;
+ // indexed-db
+ if (!options.idb) options.idb = {};
+ // after this time the messages get deleted
if (!options.idb.ttl) options.idb.ttl = 1000 * 45;
- if (!options.idb.fallbackInterval) options.idb.fallbackInterval = 150; // handles abrupt db onclose events.
-
- if (originalOptions.idb && typeof originalOptions.idb.onclose === 'function') options.idb.onclose = originalOptions.idb.onclose; // localstorage
+ if (!options.idb.fallbackInterval) options.idb.fallbackInterval = 150;
+ // handles abrupt db onclose events.
+ if (originalOptions.idb && typeof originalOptions.idb.onclose === 'function') options.idb.onclose = originalOptions.idb.onclose;
+ // localstorage
if (!options.localstorage) options.localstorage = {};
- if (!options.localstorage.removeTimeout) options.localstorage.removeTimeout = 1000 * 60; // custom methods
+ if (!options.localstorage.removeTimeout) options.localstorage.removeTimeout = 1000 * 60;
- if (originalOptions.methods) options.methods = originalOptions.methods; // node
+ // custom methods
+ if (originalOptions.methods) options.methods = originalOptions.methods;
+ // node
if (!options.node) options.node = {};
if (!options.node.ttl) options.node.ttl = 1000 * 60 * 2; // 2 minutes;
-
/**
* On linux use 'ulimit -Hn' to get the limit of open files.
* On ubuntu this was 4096 for me, so we use half of that as maxParallelWrites default.
*/
-
if (!options.node.maxParallelWrites) options.node.maxParallelWrites = 2048;
if (typeof options.node.useFastPath === 'undefined') options.node.useFastPath = true;
return options;
@@ -1673,7 +1476,6 @@ exports.microSeconds = microSeconds;
exports.randomInt = randomInt;
exports.randomToken = randomToken;
exports.sleep = sleep;
-
/**
* returns true if the given object is a promise
*/
@@ -1684,14 +1486,12 @@ function isPromise(obj) {
return false;
}
}
-
var PROMISE_RESOLVED_FALSE = Promise.resolve(false);
exports.PROMISE_RESOLVED_FALSE = PROMISE_RESOLVED_FALSE;
var PROMISE_RESOLVED_TRUE = Promise.resolve(true);
exports.PROMISE_RESOLVED_TRUE = PROMISE_RESOLVED_TRUE;
var PROMISE_RESOLVED_VOID = Promise.resolve();
exports.PROMISE_RESOLVED_VOID = PROMISE_RESOLVED_VOID;
-
function sleep(time, resolveWith) {
if (!time) time = 0;
return new Promise(function (res) {
@@ -1700,21 +1500,19 @@ function sleep(time, resolveWith) {
}, time);
});
}
-
function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
+
/**
* https://stackoverflow.com/a/8084248
*/
-
-
function randomToken() {
return Math.random().toString(36).substring(2);
}
-
var lastMs = 0;
var additional = 0;
+
/**
* returns the current time in micro-seconds,
* WARNING: This is a pseudo-function
@@ -1722,10 +1520,8 @@ var additional = 0;
* This is enough in browsers, and this function will not be used in nodejs.
* The main reason for this hack is to ensure that BroadcastChannel behaves equal to production when it is used in fast-running unit tests.
*/
-
function microSeconds() {
var ms = new Date().getTime();
-
if (ms === lastMs) {
additional++;
return ms * 1000 + additional;
@@ -1785,7 +1581,6 @@ function _interopRequireDefault(obj) {
"default": obj
};
}
-
module.exports = _interopRequireDefault, module.exports.__esModule = true, module.exports["default"] = module.exports;
},{}],15:[function(require,module,exports){
function _typeof(obj) {
@@ -1797,7 +1592,6 @@ function _typeof(obj) {
return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
}, module.exports.__esModule = true, module.exports["default"] = module.exports), _typeof(obj);
}
-
module.exports = _typeof, module.exports.__esModule = true, module.exports["default"] = module.exports;
},{}],16:[function(require,module,exports){
@@ -8323,6 +8117,7 @@ var runtime = (function (exports) {
var Op = Object.prototype;
var hasOwn = Op.hasOwnProperty;
+ var defineProperty = Object.defineProperty || function (obj, key, desc) { obj[key] = desc.value; };
var undefined; // More compressible than void 0.
var $Symbol = typeof Symbol === "function" ? Symbol : {};
var iteratorSymbol = $Symbol.iterator || "@@iterator";
@@ -8355,7 +8150,7 @@ var runtime = (function (exports) {
// The ._invoke method unifies the implementations of the .next,
// .throw, and .return methods.
- generator._invoke = makeInvokeMethod(innerFn, self, context);
+ defineProperty(generator, "_invoke", { value: makeInvokeMethod(innerFn, self, context) });
return generator;
}
@@ -8416,8 +8211,12 @@ var runtime = (function (exports) {
var Gp = GeneratorFunctionPrototype.prototype =
Generator.prototype = Object.create(IteratorPrototype);
GeneratorFunction.prototype = GeneratorFunctionPrototype;
- define(Gp, "constructor", GeneratorFunctionPrototype);
- define(GeneratorFunctionPrototype, "constructor", GeneratorFunction);
+ defineProperty(Gp, "constructor", { value: GeneratorFunctionPrototype, configurable: true });
+ defineProperty(
+ GeneratorFunctionPrototype,
+ "constructor",
+ { value: GeneratorFunction, configurable: true }
+ );
GeneratorFunction.displayName = define(
GeneratorFunctionPrototype,
toStringTagSymbol,
@@ -8527,7 +8326,7 @@ var runtime = (function (exports) {
// Define the unified helper method that is used to implement .next,
// .throw, and .return (see defineIteratorMethods).
- this._invoke = enqueue;
+ defineProperty(this, "_invoke", { value: enqueue });
}
defineIteratorMethods(AsyncIterator.prototype);
@@ -8765,7 +8564,8 @@ var runtime = (function (exports) {
this.reset(true);
}
- exports.keys = function(object) {
+ exports.keys = function(val) {
+ var object = Object(val);
var keys = [];
for (var key in object) {
keys.push(key);
@@ -9175,45 +8975,36 @@ function getSize() {
"use strict";
var _util = require("./util.js");
-
/* eslint-disable */
-
/**
* used in docs/iframe.html
*/
require('@babel/polyfill');
-
var msgContainer = document.getElementById('messages');
-
var _require = require('../../'),
- BroadcastChannel = _require.BroadcastChannel;
-
+ BroadcastChannel = _require.BroadcastChannel;
var channelName = (0, _util.getParameterByName)('channelName');
-var methodType = (0, _util.getParameterByName)('methodType'); // overwrite console.log
+var methodType = (0, _util.getParameterByName)('methodType');
+// overwrite console.log
var logBefore = console.log;
-
console.log = function (str) {
logBefore('iframe: ' + str);
};
-
function logToDom(str) {
var textnode = document.createTextNode(str);
var lineBreak = document.createElement('br');
msgContainer.appendChild(textnode);
msgContainer.appendChild(lineBreak);
}
-
var channel = new BroadcastChannel(channelName, {
type: methodType
});
logToDom('created channel with type ' + methodType);
-
channel.onmessage = function (msg) {
logToDom('message:');
logToDom('recieved message(' + msg.step + ') from ' + msg.from + ': ');
logToDom(JSON.stringify(msg));
-
if (!msg.answer) {
logToDom('answer back(' + msg.step + ')');
channel.postMessage({
@@ -9230,8 +9021,8 @@ Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getParameterByName = getParameterByName;
-
/* eslint no-useless-escape: "off" */
+
// https://stackoverflow.com/a/901144/3443137
function getParameterByName(name, url) {
if (!url) url = window.location.href;
diff --git a/docs/index.js b/docs/index.js
index 1d8f631e..755551db 100644
--- a/docs/index.js
+++ b/docs/index.js
@@ -7,13 +7,9 @@ Object.defineProperty(exports, "__esModule", {
exports.OPEN_BROADCAST_CHANNELS = exports.BroadcastChannel = void 0;
exports.clearNodeFolder = clearNodeFolder;
exports.enforceOptions = enforceOptions;
-
var _util = require("./util.js");
-
var _methodChooser = require("./method-chooser.js");
-
var _options = require("./options.js");
-
/**
* Contains all open channels,
* used in tests to ensure everything is closed.
@@ -21,77 +17,73 @@ var _options = require("./options.js");
var OPEN_BROADCAST_CHANNELS = new Set();
exports.OPEN_BROADCAST_CHANNELS = OPEN_BROADCAST_CHANNELS;
var lastId = 0;
-
var BroadcastChannel = function BroadcastChannel(name, options) {
// identifier of the channel to debug stuff
this.id = lastId++;
OPEN_BROADCAST_CHANNELS.add(this);
this.name = name;
-
if (ENFORCED_OPTIONS) {
options = ENFORCED_OPTIONS;
}
-
this.options = (0, _options.fillOptionsWithDefaults)(options);
- this.method = (0, _methodChooser.chooseMethod)(this.options); // isListening
+ this.method = (0, _methodChooser.chooseMethod)(this.options);
+ // isListening
this._iL = false;
+
/**
* _onMessageListener
* setting onmessage twice,
* will overwrite the first listener
*/
-
this._onML = null;
+
/**
* _addEventListeners
*/
-
this._addEL = {
message: [],
internal: []
};
+
/**
* Unsend message promises
* where the sending is still in progress
* @type {Set}
*/
-
this._uMP = new Set();
+
/**
* _beforeClose
* array of promises that will be awaited
* before the channel is closed
*/
-
this._befC = [];
+
/**
* _preparePromise
*/
-
this._prepP = null;
-
_prepareChannel(this);
-}; // STATICS
+};
+
+// STATICS
/**
* used to identify if someone overwrites
* window.BroadcastChannel with this
* See methods/native.js
*/
-
-
exports.BroadcastChannel = BroadcastChannel;
BroadcastChannel._pubkey = true;
+
/**
* clears the tmp-folder if is node
* @return {Promise} true if has run, false if not node
*/
-
function clearNodeFolder(options) {
options = (0, _options.fillOptionsWithDefaults)(options);
var method = (0, _methodChooser.chooseMethod)(options);
-
if (method.type === 'node') {
return method.clearNodeFolder().then(function () {
return true;
@@ -100,19 +92,17 @@ function clearNodeFolder(options) {
return _util.PROMISE_RESOLVED_FALSE;
}
}
+
/**
* if set, this method is enforced,
* no mather what the options are
*/
-
-
var ENFORCED_OPTIONS;
-
function enforceOptions(options) {
ENFORCED_OPTIONS = options;
-} // PROTOTYPE
-
+}
+// PROTOTYPE
BroadcastChannel.prototype = {
postMessage: function postMessage(msg) {
if (this.closed) {
@@ -124,87 +114,77 @@ BroadcastChannel.prototype = {
*/
JSON.stringify(msg));
}
-
return _post(this, 'message', msg);
},
postInternal: function postInternal(msg) {
return _post(this, 'internal', msg);
},
-
set onmessage(fn) {
var time = this.method.microSeconds();
var listenObj = {
time: time,
fn: fn
};
-
_removeListenerObject(this, 'message', this._onML);
-
if (fn && typeof fn === 'function') {
this._onML = listenObj;
-
_addListenerObject(this, 'message', listenObj);
} else {
this._onML = null;
}
},
-
addEventListener: function addEventListener(type, fn) {
var time = this.method.microSeconds();
var listenObj = {
time: time,
fn: fn
};
-
_addListenerObject(this, type, listenObj);
},
removeEventListener: function removeEventListener(type, fn) {
var obj = this._addEL[type].find(function (obj) {
return obj.fn === fn;
});
-
_removeListenerObject(this, type, obj);
},
close: function close() {
var _this = this;
-
if (this.closed) {
return;
}
-
OPEN_BROADCAST_CHANNELS["delete"](this);
this.closed = true;
var awaitPrepare = this._prepP ? this._prepP : _util.PROMISE_RESOLVED_VOID;
this._onML = null;
this._addEL.message = [];
- return awaitPrepare // wait until all current sending are processed
+ return awaitPrepare
+ // wait until all current sending are processed
.then(function () {
return Promise.all(Array.from(_this._uMP));
- }) // run before-close hooks
+ })
+ // run before-close hooks
.then(function () {
return Promise.all(_this._befC.map(function (fn) {
return fn();
}));
- }) // close the channel
+ })
+ // close the channel
.then(function () {
return _this.method.close(_this._state);
});
},
-
get type() {
return this.method.type;
},
-
get isClosed() {
return this.closed;
}
-
};
+
/**
* Post a message over the channel
* @returns {Promise} that resolved when the message sending is done
*/
-
function _post(broadcastChannel, type, msg) {
var time = broadcastChannel.method.microSeconds();
var msgObj = {
@@ -214,25 +194,22 @@ function _post(broadcastChannel, type, msg) {
};
var awaitPrepare = broadcastChannel._prepP ? broadcastChannel._prepP : _util.PROMISE_RESOLVED_VOID;
return awaitPrepare.then(function () {
- var sendPromise = broadcastChannel.method.postMessage(broadcastChannel._state, msgObj); // add/remove to unsend messages list
+ var sendPromise = broadcastChannel.method.postMessage(broadcastChannel._state, msgObj);
+ // add/remove to unsend messages list
broadcastChannel._uMP.add(sendPromise);
-
sendPromise["catch"]().then(function () {
return broadcastChannel._uMP["delete"](sendPromise);
});
return sendPromise;
});
}
-
function _prepareChannel(channel) {
var maybePromise = channel.method.create(channel.name, channel.options);
-
if ((0, _util.isPromise)(maybePromise)) {
channel._prepP = maybePromise;
maybePromise.then(function (s) {
// used in tests to simulate slow runtime
-
/*if (channel.options.prepareDelay) {
await new Promise(res => setTimeout(res, this.options.prepareDelay));
}*/
@@ -242,30 +219,25 @@ function _prepareChannel(channel) {
channel._state = maybePromise;
}
}
-
function _hasMessageListeners(channel) {
if (channel._addEL.message.length > 0) return true;
if (channel._addEL.internal.length > 0) return true;
return false;
}
-
function _addListenerObject(channel, type, obj) {
channel._addEL[type].push(obj);
-
_startListening(channel);
}
-
function _removeListenerObject(channel, type, obj) {
channel._addEL[type] = channel._addEL[type].filter(function (o) {
return o !== obj;
});
-
_stopListening(channel);
}
-
function _startListening(channel) {
if (!channel._iL && _hasMessageListeners(channel)) {
// someone is listening, start subscribing
+
var listenerFn = function listenerFn(msgObj) {
channel._addEL[msgObj.type].forEach(function (listenerObject) {
/**
@@ -279,15 +251,12 @@ function _startListening(channel) {
*/
var hundredMsInMicro = 100 * 1000;
var minMessageTime = listenerObject.time - hundredMsInMicro;
-
if (msgObj.time >= minMessageTime) {
listenerObject.fn(msgObj.data);
}
});
};
-
var time = channel.method.microSeconds();
-
if (channel._prepP) {
channel._prepP.then(function () {
channel._iL = true;
@@ -299,7 +268,6 @@ function _startListening(channel) {
}
}
}
-
function _stopListening(channel) {
if (channel._iL && !_hasMessageListeners(channel)) {
// noone is listening, stop subscribing
@@ -312,7 +280,6 @@ function _stopListening(channel) {
"use strict";
var _index = require("./index.js");
-
/**
* because babel can only export on default-attribute,
* we use this for the non-module-build
@@ -321,6 +288,7 @@ var _index = require("./index.js");
* but
* var BroadcastChannel = require('broadcast-channel');
*/
+
module.exports = {
BroadcastChannel: _index.BroadcastChannel,
createLeaderElection: _index.createLeaderElection,
@@ -370,9 +338,7 @@ Object.defineProperty(exports, "enforceOptions", {
return _broadcastChannel.enforceOptions;
}
});
-
var _broadcastChannel = require("./broadcast-channel.js");
-
var _leaderElection = require("./leader-election.js");
},{"./broadcast-channel.js":1,"./leader-election.js":4}],4:[function(require,module,exports){
"use strict";
@@ -382,37 +348,30 @@ Object.defineProperty(exports, "__esModule", {
});
exports.beLeader = beLeader;
exports.createLeaderElection = createLeaderElection;
-
var _util = require("./util.js");
-
var _unload = require("unload");
-
var LeaderElection = function LeaderElection(broadcastChannel, options) {
var _this = this;
-
this.broadcastChannel = broadcastChannel;
this._options = options;
this.isLeader = false;
this.hasLeader = false;
this.isDead = false;
this.token = (0, _util.randomToken)();
+
/**
* Apply Queue,
* used to ensure we do not run applyOnce()
* in parallel.
*/
+ this._aplQ = _util.PROMISE_RESOLVED_VOID;
+ // amount of unfinished applyOnce() calls
+ this._aplQC = 0;
- this._aplQ = _util.PROMISE_RESOLVED_VOID; // amount of unfinished applyOnce() calls
-
- this._aplQC = 0; // things to clean up
-
+ // things to clean up
this._unl = []; // _unloads
-
this._lstns = []; // _listeners
-
this._dpL = function () {}; // onduplicate listener
-
-
this._dpLC = false; // true when onduplicate called
/**
@@ -420,55 +379,47 @@ var LeaderElection = function LeaderElection(broadcastChannel, options) {
* we still listen to messages to ensure the hasLeader flag
* is set correctly.
*/
-
var hasLeaderListener = function hasLeaderListener(msg) {
if (msg.context === 'leader') {
if (msg.action === 'death') {
_this.hasLeader = false;
}
-
if (msg.action === 'tell') {
_this.hasLeader = true;
}
}
};
-
this.broadcastChannel.addEventListener('internal', hasLeaderListener);
-
this._lstns.push(hasLeaderListener);
};
-
LeaderElection.prototype = {
/**
* Returns true if the instance is leader,
* false if not.
* @async
*/
- applyOnce: function applyOnce( // true if the applyOnce() call came from the fallbackInterval cycle
+ applyOnce: function applyOnce(
+ // true if the applyOnce() call came from the fallbackInterval cycle
isFromFallbackInterval) {
var _this2 = this;
-
if (this.isLeader) {
return (0, _util.sleep)(0, true);
}
-
if (this.isDead) {
return (0, _util.sleep)(0, false);
}
+
/**
* Already applying more then once,
* -> wait for the apply queue to be finished.
*/
-
-
if (this._aplQC > 1) {
return this._aplQ;
}
+
/**
* Add a new apply-run
*/
-
-
var applyRun = function applyRun() {
/**
* Optimization shortcuts.
@@ -478,7 +429,6 @@ LeaderElection.prototype = {
if (_this2.isLeader) {
return _util.PROMISE_RESOLVED_TRUE;
}
-
var stopCriteria = false;
var stopCriteriaPromiseResolve;
/**
@@ -487,7 +437,6 @@ LeaderElection.prototype = {
* have to await the responseTime when it is already clear
* that the election failed.
*/
-
var stopCriteriaPromise = new Promise(function (res) {
stopCriteriaPromiseResolve = function stopCriteriaPromiseResolve() {
stopCriteria = true;
@@ -495,11 +444,9 @@ LeaderElection.prototype = {
};
});
var recieved = [];
-
var handleMessage = function handleMessage(msg) {
if (msg.context === 'leader' && msg.token != _this2.token) {
recieved.push(msg);
-
if (msg.action === 'apply') {
// other is applying
if (msg.token > _this2.token) {
@@ -510,7 +457,6 @@ LeaderElection.prototype = {
stopCriteriaPromiseResolve();
}
}
-
if (msg.action === 'tell') {
// other is already leader
stopCriteriaPromiseResolve();
@@ -518,8 +464,8 @@ LeaderElection.prototype = {
}
}
};
-
_this2.broadcastChannel.addEventListener('internal', handleMessage);
+
/**
* If the applyOnce() call came from the fallbackInterval,
* we can assume that the election runs in the background and
@@ -530,26 +476,24 @@ LeaderElection.prototype = {
* But also it takes longer which is not a problem because we anyway
* run in the background.
*/
-
-
var waitForAnswerTime = isFromFallbackInterval ? _this2._options.responseTime * 4 : _this2._options.responseTime;
-
var applyPromise = _sendMessage(_this2, 'apply') // send out that this one is applying
.then(function () {
return Promise.race([(0, _util.sleep)(waitForAnswerTime), stopCriteriaPromise.then(function () {
return Promise.reject(new Error());
})]);
- }) // send again in case another instance was just created
+ })
+ // send again in case another instance was just created
.then(function () {
return _sendMessage(_this2, 'apply');
- }) // let others time to respond
+ })
+ // let others time to respond
.then(function () {
return Promise.race([(0, _util.sleep)(waitForAnswerTime), stopCriteriaPromise.then(function () {
return Promise.reject(new Error());
})]);
})["catch"](function () {}).then(function () {
_this2.broadcastChannel.removeEventListener('internal', handleMessage);
-
if (!stopCriteria) {
// no stop criteria -> own is leader
return beLeader(_this2).then(function () {
@@ -560,10 +504,8 @@ LeaderElection.prototype = {
return false;
}
});
-
return applyPromise;
};
-
this._aplQC = this._aplQC + 1;
this._aplQ = this._aplQ.then(function () {
return applyRun();
@@ -575,82 +517,68 @@ LeaderElection.prototype = {
});
},
awaitLeadership: function awaitLeadership() {
- if (
- /* _awaitLeadershipPromise */
+ if ( /* _awaitLeadershipPromise */
!this._aLP) {
this._aLP = _awaitLeadershipOnce(this);
}
-
return this._aLP;
},
-
set onduplicate(fn) {
this._dpL = fn;
},
-
die: function die() {
var _this3 = this;
-
this._lstns.forEach(function (listener) {
return _this3.broadcastChannel.removeEventListener('internal', listener);
});
-
this._lstns = [];
-
this._unl.forEach(function (uFn) {
return uFn.remove();
});
-
this._unl = [];
-
if (this.isLeader) {
this.hasLeader = false;
this.isLeader = false;
}
-
this.isDead = true;
return _sendMessage(this, 'death');
}
};
+
/**
* @param leaderElector {LeaderElector}
*/
-
function _awaitLeadershipOnce(leaderElector) {
if (leaderElector.isLeader) {
return _util.PROMISE_RESOLVED_VOID;
}
-
return new Promise(function (res) {
var resolved = false;
-
function finish() {
if (resolved) {
return;
}
-
resolved = true;
leaderElector.broadcastChannel.removeEventListener('internal', whenDeathListener);
res(true);
- } // try once now
-
+ }
+ // try once now
leaderElector.applyOnce().then(function () {
if (leaderElector.isLeader) {
finish();
}
});
+
/**
* Try on fallbackInterval
* @recursive
*/
-
var tryOnFallBack = function tryOnFallBack() {
return (0, _util.sleep)(leaderElector._options.fallbackInterval).then(function () {
if (leaderElector.isDead || resolved) {
return;
}
-
if (leaderElector.isLeader) {
finish();
} else {
@@ -664,9 +592,9 @@ function _awaitLeadershipOnce(leaderElector) {
}
});
};
+ tryOnFallBack();
- tryOnFallBack(); // try when other leader dies
-
+ // try when other leader dies
var whenDeathListener = function whenDeathListener(msg) {
if (msg.context === 'leader' && msg.action === 'death') {
leaderElector.hasLeader = false;
@@ -677,17 +605,14 @@ function _awaitLeadershipOnce(leaderElector) {
});
}
};
-
leaderElector.broadcastChannel.addEventListener('internal', whenDeathListener);
-
leaderElector._lstns.push(whenDeathListener);
});
}
+
/**
* sends and internal message over the broadcast-channel
*/
-
-
function _sendMessage(leaderElector, action) {
var msgJson = {
context: 'leader',
@@ -696,21 +621,17 @@ function _sendMessage(leaderElector, action) {
};
return leaderElector.broadcastChannel.postInternal(msgJson);
}
-
function beLeader(leaderElector) {
leaderElector.isLeader = true;
leaderElector.hasLeader = true;
var unloadFn = (0, _unload.add)(function () {
return leaderElector.die();
});
-
leaderElector._unl.push(unloadFn);
-
var isLeaderListener = function isLeaderListener(msg) {
if (msg.context === 'leader' && msg.action === 'apply') {
_sendMessage(leaderElector, 'tell');
}
-
if (msg.context === 'leader' && msg.action === 'tell' && !leaderElector._dpLC) {
/**
* another instance is also leader!
@@ -721,49 +642,35 @@ function beLeader(leaderElector) {
* @link https://github.com/pubkey/broadcast-channel/issues/385
*/
leaderElector._dpLC = true;
-
leaderElector._dpL(); // message the lib user so the app can handle the problem
-
-
_sendMessage(leaderElector, 'tell'); // ensure other leader also knows the problem
-
}
};
leaderElector.broadcastChannel.addEventListener('internal', isLeaderListener);
-
leaderElector._lstns.push(isLeaderListener);
-
return _sendMessage(leaderElector, 'tell');
}
-
function fillOptionsWithDefaults(options, channel) {
if (!options) options = {};
options = JSON.parse(JSON.stringify(options));
-
if (!options.fallbackInterval) {
options.fallbackInterval = 3000;
}
-
if (!options.responseTime) {
options.responseTime = channel.method.averageResponseTime(channel.options);
}
-
return options;
}
-
function createLeaderElection(channel, options) {
if (channel._leaderElector) {
throw new Error('BroadcastChannel already has a leader-elector');
}
-
options = fillOptionsWithDefaults(options, channel);
var elector = new LeaderElection(channel, options);
-
channel._befC.push(function () {
return elector.die();
});
-
channel._leaderElector = elector;
return elector;
}
@@ -771,59 +678,49 @@ function createLeaderElection(channel, options) {
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
-
var _typeof = require("@babel/runtime/helpers/typeof");
-
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.chooseMethod = chooseMethod;
-
var _native = _interopRequireDefault(require("./methods/native.js"));
-
var _indexedDb = _interopRequireDefault(require("./methods/indexed-db.js"));
-
var _localstorage = _interopRequireDefault(require("./methods/localstorage.js"));
-
var _simulate = _interopRequireDefault(require("./methods/simulate.js"));
-
-
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
-
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
-
// the line below will be removed from es5/browser builds
+
// order is important
-var METHODS = [_native["default"], // fastest
+var METHODS = [_native["default"],
+// fastest
_indexedDb["default"], _localstorage["default"]];
-
function chooseMethod(options) {
- var chooseMethods = [].concat(options.methods, METHODS).filter(Boolean); // the line below will be removed from es5/browser builds
+ var chooseMethods = [].concat(options.methods, METHODS).filter(Boolean);
+ // the line below will be removed from es5/browser builds
+ // directly chosen
if (options.type) {
if (options.type === 'simulate') {
// only use simulate-method if directly chosen
return _simulate["default"];
}
-
var ret = chooseMethods.find(function (m) {
return m.type === options.type;
});
if (!ret) throw new Error('method-type ' + options.type + ' not found');else return ret;
}
+
/**
* if no webworker support is needed,
* remove idb from the list so that localstorage is been chosen
*/
-
-
if (!options.webWorkerSupport) {
chooseMethods = chooseMethods.filter(function (m) {
return m.type !== 'idb';
});
}
-
var useMethod = chooseMethods.find(function (method) {
return method.canBeUsed();
});
@@ -856,13 +753,9 @@ exports.postMessage = postMessage;
exports.removeMessagesById = removeMessagesById;
exports.type = void 0;
exports.writeMessage = writeMessage;
-
var _util = require("../util.js");
-
var _obliviousSet = require("oblivious-set");
-
var _options = require("../options.js");
-
/**
* this method uses indexeddb to store the messages
* There is currently no observerAPI for idb
@@ -871,58 +764,54 @@ var _options = require("../options.js");
* When working on this, ensure to use these performance optimizations:
* @link https://rxdb.info/slow-indexeddb.html
*/
+
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var DB_PREFIX = 'pubkey.broadcast-channel-0-';
var OBJECT_STORE_ID = 'messages';
+
/**
* Use relaxed durability for faster performance on all transactions.
* @link https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/
*/
-
var TRANSACTION_SETTINGS = {
durability: 'relaxed'
};
exports.TRANSACTION_SETTINGS = TRANSACTION_SETTINGS;
var type = 'idb';
exports.type = type;
-
function getIdb() {
if (typeof indexedDB !== 'undefined') return indexedDB;
-
if (typeof window !== 'undefined') {
if (typeof window.mozIndexedDB !== 'undefined') return window.mozIndexedDB;
if (typeof window.webkitIndexedDB !== 'undefined') return window.webkitIndexedDB;
if (typeof window.msIndexedDB !== 'undefined') return window.msIndexedDB;
}
-
return false;
}
+
/**
* If possible, we should explicitly commit IndexedDB transactions
* for better performance.
* @link https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/
*/
-
-
function commitIndexedDBTransaction(tx) {
if (tx.commit) {
tx.commit();
}
}
-
function createDatabase(channelName) {
- var IndexedDB = getIdb(); // create table
+ var IndexedDB = getIdb();
+ // create table
var dbName = DB_PREFIX + channelName;
+
/**
* All IndexedDB databases are opened without version
* because it is a bit faster, especially on firefox
* @link http://nparashuram.com/IndexedDB/perf/#Open%20Database%20with%20version
*/
-
var openRequest = IndexedDB.open(dbName);
-
openRequest.onupgradeneeded = function (ev) {
var db = ev.target.result;
db.createObjectStore(OBJECT_STORE_ID, {
@@ -930,24 +819,21 @@ function createDatabase(channelName) {
autoIncrement: true
});
};
-
var dbPromise = new Promise(function (res, rej) {
openRequest.onerror = function (ev) {
return rej(ev);
};
-
openRequest.onsuccess = function () {
res(openRequest.result);
};
});
return dbPromise;
}
+
/**
* writes the new message to the database
* so other readers can find it
*/
-
-
function writeMessage(db, readerUuid, messageJson) {
var time = new Date().getTime();
var writeObject = {
@@ -960,17 +846,14 @@ function writeMessage(db, readerUuid, messageJson) {
tx.oncomplete = function () {
return res();
};
-
tx.onerror = function (ev) {
return rej(ev);
};
-
var objectStore = tx.objectStore(OBJECT_STORE_ID);
objectStore.add(writeObject);
commitIndexedDBTransaction(tx);
});
}
-
function getAllMessages(db) {
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS);
var objectStore = tx.objectStore(OBJECT_STORE_ID);
@@ -978,10 +861,9 @@ function getAllMessages(db) {
return new Promise(function (res) {
objectStore.openCursor().onsuccess = function (ev) {
var cursor = ev.target.result;
-
if (cursor) {
- ret.push(cursor.value); //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
-
+ ret.push(cursor.value);
+ //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor["continue"]();
} else {
commitIndexedDBTransaction(tx);
@@ -990,31 +872,28 @@ function getAllMessages(db) {
};
});
}
-
function getMessagesHigherThan(db, lastCursorId) {
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS);
var objectStore = tx.objectStore(OBJECT_STORE_ID);
var ret = [];
var keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity);
+
/**
* Optimization shortcut,
* if getAll() can be used, do not use a cursor.
* @link https://rxdb.info/slow-indexeddb.html
*/
-
if (objectStore.getAll) {
var getAllRequest = objectStore.getAll(keyRangeValue);
return new Promise(function (res, rej) {
getAllRequest.onerror = function (err) {
return rej(err);
};
-
getAllRequest.onsuccess = function (e) {
res(e.target.result);
};
});
}
-
function openCursor() {
// Occasionally Safari will fail on IDBKeyRange.bound, this
// catches that error, having it open the cursor to the first
@@ -1026,17 +905,13 @@ function getMessagesHigherThan(db, lastCursorId) {
return objectStore.openCursor();
}
}
-
return new Promise(function (res, rej) {
var openCursorRequest = openCursor();
-
openCursorRequest.onerror = function (err) {
return rej(err);
};
-
openCursorRequest.onsuccess = function (ev) {
var cursor = ev.target.result;
-
if (cursor) {
if (cursor.value.id < lastCursorId + 1) {
cursor["continue"](lastCursorId + 1);
@@ -1051,12 +926,10 @@ function getMessagesHigherThan(db, lastCursorId) {
};
});
}
-
function removeMessagesById(channelState, ids) {
if (channelState.closed) {
return Promise.resolve([]);
}
-
var tx = channelState.db.transaction(OBJECT_STORE_ID, 'readwrite', TRANSACTION_SETTINGS);
var objectStore = tx.objectStore(OBJECT_STORE_ID);
return Promise.all(ids.map(function (id) {
@@ -1068,7 +941,6 @@ function removeMessagesById(channelState, ids) {
});
}));
}
-
function getOldMessages(db, ttl) {
var olderThen = new Date().getTime() - ttl;
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS);
@@ -1077,13 +949,11 @@ function getOldMessages(db, ttl) {
return new Promise(function (res) {
objectStore.openCursor().onsuccess = function (ev) {
var cursor = ev.target.result;
-
if (cursor) {
var msgObk = cursor.value;
-
if (msgObk.time < olderThen) {
- ret.push(msgObk); //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
-
+ ret.push(msgObk);
+ //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor["continue"]();
} else {
// no more old messages,
@@ -1097,7 +967,6 @@ function getOldMessages(db, ttl) {
};
});
}
-
function cleanOldMessages(channelState) {
return getOldMessages(channelState.db, channelState.options.idb.ttl).then(function (tooOld) {
return removeMessagesById(channelState, tooOld.map(function (msg) {
@@ -1105,7 +974,6 @@ function cleanOldMessages(channelState) {
}));
});
}
-
function create(channelName, options) {
options = (0, _options.fillOptionsWithDefaults)(options);
return createDatabase(channelName).then(function (db) {
@@ -1115,7 +983,6 @@ function create(channelName, options) {
channelName: channelName,
options: options,
uuid: (0, _util.randomToken)(),
-
/**
* emittedMessagesIds
* contains all messages that have been emitted before
@@ -1128,30 +995,27 @@ function create(channelName, options) {
readQueuePromises: [],
db: db
};
+
/**
* Handle abrupt closes that do not originate from db.close().
* This could happen, for example, if the underlying storage is
* removed or if the user clears the database in the browser's
* history preferences.
*/
-
db.onclose = function () {
state.closed = true;
if (options.idb.onclose) options.idb.onclose();
};
+
/**
* if service-workers are used,
* we have no 'storage'-event if they post a message,
* therefore we also have to set an interval
*/
-
-
_readLoop(state);
-
return state;
});
}
-
function _readLoop(state) {
if (state.closed) return;
readNewMessages(state).then(function () {
@@ -1160,25 +1024,21 @@ function _readLoop(state) {
return _readLoop(state);
});
}
-
function _filterMessage(msgObj, state) {
if (msgObj.uuid === state.uuid) return false; // send by own
-
if (state.eMIs.has(msgObj.id)) return false; // already emitted
-
if (msgObj.data.time < state.messagesCallbackTime) return false; // older then onMessageCallback
-
return true;
}
+
/**
* reads all new messages from the database and emits them
*/
-
-
function readNewMessages(state) {
// channel already closed
- if (state.closed) return _util.PROMISE_RESOLVED_VOID; // if no one is listening, we do not need to scan for new messages
+ if (state.closed) return _util.PROMISE_RESOLVED_VOID;
+ // if no one is listening, we do not need to scan for new messages
if (!state.messagesCallback) return _util.PROMISE_RESOLVED_VOID;
return getMessagesHigherThan(state.db, state.lastCursorId).then(function (newerMessages) {
var useMessages = newerMessages
@@ -1186,21 +1046,18 @@ function readNewMessages(state) {
* there is a bug in iOS where the msgObj can be undefined some times
* so we filter them out
* @link https://github.com/pubkey/broadcast-channel/issues/19
- */
- .filter(function (msgObj) {
+ */.filter(function (msgObj) {
return !!msgObj;
}).map(function (msgObj) {
if (msgObj.id > state.lastCursorId) {
state.lastCursorId = msgObj.id;
}
-
return msgObj;
}).filter(function (msgObj) {
return _filterMessage(msgObj, state);
}).sort(function (msgObjA, msgObjB) {
return msgObjA.time - msgObjB.time;
}); // sort by time
-
useMessages.forEach(function (msgObj) {
if (state.messagesCallback) {
state.eMIs.add(msgObj.id);
@@ -1210,12 +1067,10 @@ function readNewMessages(state) {
return _util.PROMISE_RESOLVED_VOID;
});
}
-
function close(channelState) {
channelState.closed = true;
channelState.db.close();
}
-
function postMessage(channelState, messageJson) {
channelState.writeBlockPromise = channelState.writeBlockPromise.then(function () {
return writeMessage(channelState.db, channelState.uuid, messageJson);
@@ -1227,27 +1082,21 @@ function postMessage(channelState, messageJson) {
});
return channelState.writeBlockPromise;
}
-
function onMessage(channelState, fn, time) {
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
readNewMessages(channelState);
}
-
function canBeUsed() {
var idb = getIdb();
-
if (!idb) {
return false;
}
-
return true;
}
-
function averageResponseTime(options) {
return options.idb.fallbackInterval * 2;
}
-
var _default = {
create: create,
close: close,
@@ -1278,13 +1127,9 @@ exports.postMessage = postMessage;
exports.removeStorageEventListener = removeStorageEventListener;
exports.storageKey = storageKey;
exports.type = void 0;
-
var _obliviousSet = require("oblivious-set");
-
var _options = require("../options.js");
-
var _util = require("../util.js");
-
/**
* A localStorage-only method which uses localstorage and its 'storage'-event
* This does not work inside of webworkers because they have no access to locastorage
@@ -1292,41 +1137,38 @@ var _util = require("../util.js");
* @link https://caniuse.com/#feat=namevalue-storage
* @link https://caniuse.com/#feat=indexeddb
*/
+
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var KEY_PREFIX = 'pubkey.broadcastChannel-';
var type = 'localstorage';
+
/**
* copied from crosstab
* @link https://github.com/tejacques/crosstab/blob/master/src/crosstab.js#L32
*/
-
exports.type = type;
-
function getLocalStorage() {
var localStorage;
if (typeof window === 'undefined') return null;
-
try {
localStorage = window.localStorage;
localStorage = window['ie8-eventlistener/storage'] || window.localStorage;
- } catch (e) {// New versions of Firefox throw a Security exception
+ } catch (e) {
+ // New versions of Firefox throw a Security exception
// if cookies are disabled. See
// https://bugzilla.mozilla.org/show_bug.cgi?id=1028153
}
-
return localStorage;
}
-
function storageKey(channelName) {
return KEY_PREFIX + channelName;
}
+
/**
* writes the new message to the storage
* and fires the storage-event so other readers can find it
*/
-
-
function postMessage(channelState, messageJson) {
return new Promise(function (res) {
(0, _util.sleep)().then(function () {
@@ -1339,12 +1181,12 @@ function postMessage(channelState, messageJson) {
};
var value = JSON.stringify(writeObj);
getLocalStorage().setItem(key, value);
+
/**
* StorageEvent does not fire the 'storage' event
* in the window that changes the state of the local storage.
* So we fire it manually
*/
-
var ev = document.createEvent('Event');
ev.initEvent('storage', true, true);
ev.key = key;
@@ -1354,52 +1196,42 @@ function postMessage(channelState, messageJson) {
});
});
}
-
function addStorageEventListener(channelName, fn) {
var key = storageKey(channelName);
-
var listener = function listener(ev) {
if (ev.key === key) {
fn(JSON.parse(ev.newValue));
}
};
-
window.addEventListener('storage', listener);
return listener;
}
-
function removeStorageEventListener(listener) {
window.removeEventListener('storage', listener);
}
-
function create(channelName, options) {
options = (0, _options.fillOptionsWithDefaults)(options);
-
if (!canBeUsed()) {
throw new Error('BroadcastChannel: localstorage cannot be used');
}
-
var uuid = (0, _util.randomToken)();
+
/**
* eMIs
* contains all messages that have been emitted before
* @type {ObliviousSet}
*/
-
var eMIs = new _obliviousSet.ObliviousSet(options.localstorage.removeTimeout);
var state = {
channelName: channelName,
uuid: uuid,
eMIs: eMIs // emittedMessagesIds
-
};
+
state.listener = addStorageEventListener(channelName, function (msgObj) {
if (!state.messagesCallback) return; // no listener
-
if (msgObj.uuid === uuid) return; // own message
-
if (!msgObj.token || eMIs.has(msgObj.token)) return; // already emitted
-
if (msgObj.data.time && msgObj.data.time < state.messagesCallbackTime) return; // too old
eMIs.add(msgObj.token);
@@ -1407,20 +1239,16 @@ function create(channelName, options) {
});
return state;
}
-
function close(channelState) {
removeStorageEventListener(channelState.listener);
}
-
function onMessage(channelState, fn, time) {
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
}
-
function canBeUsed() {
var ls = getLocalStorage();
if (!ls) return false;
-
try {
var key = '__broadcastchannel_check';
ls.setItem(key, 'works');
@@ -1431,22 +1259,17 @@ function canBeUsed() {
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API#Private_Browsing_Incognito_modes
return false;
}
-
return true;
}
-
function averageResponseTime() {
var defaultTime = 120;
var userAgent = navigator.userAgent.toLowerCase();
-
if (userAgent.includes('safari') && !userAgent.includes('chrome')) {
// safari is much slower so this time is higher
return defaultTime * 2;
}
-
return defaultTime;
}
-
var _default = {
create: create,
close: close,
@@ -1472,20 +1295,16 @@ exports.microSeconds = exports["default"] = void 0;
exports.onMessage = onMessage;
exports.postMessage = postMessage;
exports.type = void 0;
-
var _util = require("../util.js");
-
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var type = 'native';
exports.type = type;
-
function create(channelName) {
var state = {
messagesCallback: null,
bc: new BroadcastChannel(channelName),
subFns: [] // subscriberFunctions
-
};
state.bc.onmessage = function (msg) {
@@ -1493,15 +1312,12 @@ function create(channelName) {
state.messagesCallback(msg.data);
}
};
-
return state;
}
-
function close(channelState) {
channelState.bc.close();
channelState.subFns = [];
}
-
function postMessage(channelState, messageJson) {
try {
channelState.bc.postMessage(messageJson, false);
@@ -1510,31 +1326,25 @@ function postMessage(channelState, messageJson) {
return Promise.reject(err);
}
}
-
function onMessage(channelState, fn) {
channelState.messagesCallback = fn;
}
-
function canBeUsed() {
if (typeof window === 'undefined') {
return false;
}
-
if (typeof BroadcastChannel === 'function') {
if (BroadcastChannel._pubkey) {
throw new Error('BroadcastChannel: Do not overwrite window.BroadcastChannel with this module, this is not a polyfill');
}
-
return true;
} else {
return false;
}
}
-
function averageResponseTime() {
return 150;
}
-
var _default = {
create: create,
close: close,
@@ -1560,15 +1370,12 @@ exports.microSeconds = exports["default"] = void 0;
exports.onMessage = onMessage;
exports.postMessage = postMessage;
exports.type = void 0;
-
var _util = require("../util.js");
-
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var type = 'simulate';
exports.type = type;
var SIMULATE_CHANNELS = new Set();
-
function create(channelName) {
var state = {
name: channelName,
@@ -1577,11 +1384,9 @@ function create(channelName) {
SIMULATE_CHANNELS.add(state);
return state;
}
-
function close(channelState) {
SIMULATE_CHANNELS["delete"](channelState);
}
-
function postMessage(channelState, messageJson) {
return new Promise(function (res) {
return setTimeout(function () {
@@ -1599,19 +1404,15 @@ function postMessage(channelState, messageJson) {
}, 5);
});
}
-
function onMessage(channelState, fn) {
channelState.messagesCallback = fn;
}
-
function canBeUsed() {
return true;
}
-
function averageResponseTime() {
return 5;
}
-
var _default = {
create: create,
close: close,
@@ -1630,33 +1431,35 @@ Object.defineProperty(exports, "__esModule", {
value: true
});
exports.fillOptionsWithDefaults = fillOptionsWithDefaults;
-
function fillOptionsWithDefaults() {
var originalOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- var options = JSON.parse(JSON.stringify(originalOptions)); // main
-
- if (typeof options.webWorkerSupport === 'undefined') options.webWorkerSupport = true; // indexed-db
+ var options = JSON.parse(JSON.stringify(originalOptions));
- if (!options.idb) options.idb = {}; // after this time the messages get deleted
+ // main
+ if (typeof options.webWorkerSupport === 'undefined') options.webWorkerSupport = true;
+ // indexed-db
+ if (!options.idb) options.idb = {};
+ // after this time the messages get deleted
if (!options.idb.ttl) options.idb.ttl = 1000 * 45;
- if (!options.idb.fallbackInterval) options.idb.fallbackInterval = 150; // handles abrupt db onclose events.
-
- if (originalOptions.idb && typeof originalOptions.idb.onclose === 'function') options.idb.onclose = originalOptions.idb.onclose; // localstorage
+ if (!options.idb.fallbackInterval) options.idb.fallbackInterval = 150;
+ // handles abrupt db onclose events.
+ if (originalOptions.idb && typeof originalOptions.idb.onclose === 'function') options.idb.onclose = originalOptions.idb.onclose;
+ // localstorage
if (!options.localstorage) options.localstorage = {};
- if (!options.localstorage.removeTimeout) options.localstorage.removeTimeout = 1000 * 60; // custom methods
+ if (!options.localstorage.removeTimeout) options.localstorage.removeTimeout = 1000 * 60;
- if (originalOptions.methods) options.methods = originalOptions.methods; // node
+ // custom methods
+ if (originalOptions.methods) options.methods = originalOptions.methods;
+ // node
if (!options.node) options.node = {};
if (!options.node.ttl) options.node.ttl = 1000 * 60 * 2; // 2 minutes;
-
/**
* On linux use 'ulimit -Hn' to get the limit of open files.
* On ubuntu this was 4096 for me, so we use half of that as maxParallelWrites default.
*/
-
if (!options.node.maxParallelWrites) options.node.maxParallelWrites = 2048;
if (typeof options.node.useFastPath === 'undefined') options.node.useFastPath = true;
return options;
@@ -1673,7 +1476,6 @@ exports.microSeconds = microSeconds;
exports.randomInt = randomInt;
exports.randomToken = randomToken;
exports.sleep = sleep;
-
/**
* returns true if the given object is a promise
*/
@@ -1684,14 +1486,12 @@ function isPromise(obj) {
return false;
}
}
-
var PROMISE_RESOLVED_FALSE = Promise.resolve(false);
exports.PROMISE_RESOLVED_FALSE = PROMISE_RESOLVED_FALSE;
var PROMISE_RESOLVED_TRUE = Promise.resolve(true);
exports.PROMISE_RESOLVED_TRUE = PROMISE_RESOLVED_TRUE;
var PROMISE_RESOLVED_VOID = Promise.resolve();
exports.PROMISE_RESOLVED_VOID = PROMISE_RESOLVED_VOID;
-
function sleep(time, resolveWith) {
if (!time) time = 0;
return new Promise(function (res) {
@@ -1700,21 +1500,19 @@ function sleep(time, resolveWith) {
}, time);
});
}
-
function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
+
/**
* https://stackoverflow.com/a/8084248
*/
-
-
function randomToken() {
return Math.random().toString(36).substring(2);
}
-
var lastMs = 0;
var additional = 0;
+
/**
* returns the current time in micro-seconds,
* WARNING: This is a pseudo-function
@@ -1722,10 +1520,8 @@ var additional = 0;
* This is enough in browsers, and this function will not be used in nodejs.
* The main reason for this hack is to ensure that BroadcastChannel behaves equal to production when it is used in fast-running unit tests.
*/
-
function microSeconds() {
var ms = new Date().getTime();
-
if (ms === lastMs) {
additional++;
return ms * 1000 + additional;
@@ -1785,7 +1581,6 @@ function _interopRequireDefault(obj) {
"default": obj
};
}
-
module.exports = _interopRequireDefault, module.exports.__esModule = true, module.exports["default"] = module.exports;
},{}],15:[function(require,module,exports){
function _typeof(obj) {
@@ -1797,7 +1592,6 @@ function _typeof(obj) {
return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
}, module.exports.__esModule = true, module.exports["default"] = module.exports), _typeof(obj);
}
-
module.exports = _typeof, module.exports.__esModule = true, module.exports["default"] = module.exports;
},{}],16:[function(require,module,exports){
@@ -8323,6 +8117,7 @@ var runtime = (function (exports) {
var Op = Object.prototype;
var hasOwn = Op.hasOwnProperty;
+ var defineProperty = Object.defineProperty || function (obj, key, desc) { obj[key] = desc.value; };
var undefined; // More compressible than void 0.
var $Symbol = typeof Symbol === "function" ? Symbol : {};
var iteratorSymbol = $Symbol.iterator || "@@iterator";
@@ -8355,7 +8150,7 @@ var runtime = (function (exports) {
// The ._invoke method unifies the implementations of the .next,
// .throw, and .return methods.
- generator._invoke = makeInvokeMethod(innerFn, self, context);
+ defineProperty(generator, "_invoke", { value: makeInvokeMethod(innerFn, self, context) });
return generator;
}
@@ -8416,8 +8211,12 @@ var runtime = (function (exports) {
var Gp = GeneratorFunctionPrototype.prototype =
Generator.prototype = Object.create(IteratorPrototype);
GeneratorFunction.prototype = GeneratorFunctionPrototype;
- define(Gp, "constructor", GeneratorFunctionPrototype);
- define(GeneratorFunctionPrototype, "constructor", GeneratorFunction);
+ defineProperty(Gp, "constructor", { value: GeneratorFunctionPrototype, configurable: true });
+ defineProperty(
+ GeneratorFunctionPrototype,
+ "constructor",
+ { value: GeneratorFunction, configurable: true }
+ );
GeneratorFunction.displayName = define(
GeneratorFunctionPrototype,
toStringTagSymbol,
@@ -8527,7 +8326,7 @@ var runtime = (function (exports) {
// Define the unified helper method that is used to implement .next,
// .throw, and .return (see defineIteratorMethods).
- this._invoke = enqueue;
+ defineProperty(this, "_invoke", { value: enqueue });
}
defineIteratorMethods(AsyncIterator.prototype);
@@ -8765,7 +8564,8 @@ var runtime = (function (exports) {
this.reset(true);
}
- exports.keys = function(object) {
+ exports.keys = function(val) {
+ var object = Object(val);
var keys = [];
for (var key in object) {
keys.push(key);
@@ -9175,19 +8975,17 @@ function getSize() {
"use strict";
/* eslint-disable */
-
/**
* used in docs/index.html
*/
require('@babel/polyfill');
-
var _require = require('../../'),
- BroadcastChannel = _require.BroadcastChannel,
- createLeaderElection = _require.createLeaderElection;
-
+ BroadcastChannel = _require.BroadcastChannel,
+ createLeaderElection = _require.createLeaderElection;
var channelName = 'demo';
-var channel = new BroadcastChannel(channelName); // leader election
+var channel = new BroadcastChannel(channelName);
+// leader election
var leaderElector = createLeaderElection(channel);
leaderElector.awaitLeadership().then(function () {
console.log('is leader');
@@ -9196,11 +8994,9 @@ leaderElector.awaitLeadership().then(function () {
var messageInput = document.getElementById('message-input');
var submitButton = document.getElementById('submit-button');
var messagesBox = document.getElementById('messages');
-
messageInput.onkeyup = function () {
if (messageInput.value !== '') submitButton.disabled = false;else submitButton.disabled = true;
};
-
submitButton.onclick = function () {
if (submitButton.disabled) return;else {
console.log('postMessage ' + messageInput.value);
@@ -9209,14 +9005,12 @@ submitButton.onclick = function () {
messageInput.value = '';
}
};
-
function addTextToMessageBox(text) {
var textnode = document.createTextNode(text);
var lineBreak = document.createElement('br');
messagesBox.appendChild(textnode);
messagesBox.appendChild(lineBreak);
}
-
channel.onmessage = function (message) {
console.dir('recieved message: ' + message);
addTextToMessageBox('recieved: ' + message);
diff --git a/docs/leader-iframe.js b/docs/leader-iframe.js
index 71abfcbe..8a4fecfd 100644
--- a/docs/leader-iframe.js
+++ b/docs/leader-iframe.js
@@ -7,13 +7,9 @@ Object.defineProperty(exports, "__esModule", {
exports.OPEN_BROADCAST_CHANNELS = exports.BroadcastChannel = void 0;
exports.clearNodeFolder = clearNodeFolder;
exports.enforceOptions = enforceOptions;
-
var _util = require("./util.js");
-
var _methodChooser = require("./method-chooser.js");
-
var _options = require("./options.js");
-
/**
* Contains all open channels,
* used in tests to ensure everything is closed.
@@ -21,77 +17,73 @@ var _options = require("./options.js");
var OPEN_BROADCAST_CHANNELS = new Set();
exports.OPEN_BROADCAST_CHANNELS = OPEN_BROADCAST_CHANNELS;
var lastId = 0;
-
var BroadcastChannel = function BroadcastChannel(name, options) {
// identifier of the channel to debug stuff
this.id = lastId++;
OPEN_BROADCAST_CHANNELS.add(this);
this.name = name;
-
if (ENFORCED_OPTIONS) {
options = ENFORCED_OPTIONS;
}
-
this.options = (0, _options.fillOptionsWithDefaults)(options);
- this.method = (0, _methodChooser.chooseMethod)(this.options); // isListening
+ this.method = (0, _methodChooser.chooseMethod)(this.options);
+ // isListening
this._iL = false;
+
/**
* _onMessageListener
* setting onmessage twice,
* will overwrite the first listener
*/
-
this._onML = null;
+
/**
* _addEventListeners
*/
-
this._addEL = {
message: [],
internal: []
};
+
/**
* Unsend message promises
* where the sending is still in progress
* @type {Set}
*/
-
this._uMP = new Set();
+
/**
* _beforeClose
* array of promises that will be awaited
* before the channel is closed
*/
-
this._befC = [];
+
/**
* _preparePromise
*/
-
this._prepP = null;
-
_prepareChannel(this);
-}; // STATICS
+};
+
+// STATICS
/**
* used to identify if someone overwrites
* window.BroadcastChannel with this
* See methods/native.js
*/
-
-
exports.BroadcastChannel = BroadcastChannel;
BroadcastChannel._pubkey = true;
+
/**
* clears the tmp-folder if is node
* @return {Promise} true if has run, false if not node
*/
-
function clearNodeFolder(options) {
options = (0, _options.fillOptionsWithDefaults)(options);
var method = (0, _methodChooser.chooseMethod)(options);
-
if (method.type === 'node') {
return method.clearNodeFolder().then(function () {
return true;
@@ -100,19 +92,17 @@ function clearNodeFolder(options) {
return _util.PROMISE_RESOLVED_FALSE;
}
}
+
/**
* if set, this method is enforced,
* no mather what the options are
*/
-
-
var ENFORCED_OPTIONS;
-
function enforceOptions(options) {
ENFORCED_OPTIONS = options;
-} // PROTOTYPE
-
+}
+// PROTOTYPE
BroadcastChannel.prototype = {
postMessage: function postMessage(msg) {
if (this.closed) {
@@ -124,87 +114,77 @@ BroadcastChannel.prototype = {
*/
JSON.stringify(msg));
}
-
return _post(this, 'message', msg);
},
postInternal: function postInternal(msg) {
return _post(this, 'internal', msg);
},
-
set onmessage(fn) {
var time = this.method.microSeconds();
var listenObj = {
time: time,
fn: fn
};
-
_removeListenerObject(this, 'message', this._onML);
-
if (fn && typeof fn === 'function') {
this._onML = listenObj;
-
_addListenerObject(this, 'message', listenObj);
} else {
this._onML = null;
}
},
-
addEventListener: function addEventListener(type, fn) {
var time = this.method.microSeconds();
var listenObj = {
time: time,
fn: fn
};
-
_addListenerObject(this, type, listenObj);
},
removeEventListener: function removeEventListener(type, fn) {
var obj = this._addEL[type].find(function (obj) {
return obj.fn === fn;
});
-
_removeListenerObject(this, type, obj);
},
close: function close() {
var _this = this;
-
if (this.closed) {
return;
}
-
OPEN_BROADCAST_CHANNELS["delete"](this);
this.closed = true;
var awaitPrepare = this._prepP ? this._prepP : _util.PROMISE_RESOLVED_VOID;
this._onML = null;
this._addEL.message = [];
- return awaitPrepare // wait until all current sending are processed
+ return awaitPrepare
+ // wait until all current sending are processed
.then(function () {
return Promise.all(Array.from(_this._uMP));
- }) // run before-close hooks
+ })
+ // run before-close hooks
.then(function () {
return Promise.all(_this._befC.map(function (fn) {
return fn();
}));
- }) // close the channel
+ })
+ // close the channel
.then(function () {
return _this.method.close(_this._state);
});
},
-
get type() {
return this.method.type;
},
-
get isClosed() {
return this.closed;
}
-
};
+
/**
* Post a message over the channel
* @returns {Promise} that resolved when the message sending is done
*/
-
function _post(broadcastChannel, type, msg) {
var time = broadcastChannel.method.microSeconds();
var msgObj = {
@@ -214,25 +194,22 @@ function _post(broadcastChannel, type, msg) {
};
var awaitPrepare = broadcastChannel._prepP ? broadcastChannel._prepP : _util.PROMISE_RESOLVED_VOID;
return awaitPrepare.then(function () {
- var sendPromise = broadcastChannel.method.postMessage(broadcastChannel._state, msgObj); // add/remove to unsend messages list
+ var sendPromise = broadcastChannel.method.postMessage(broadcastChannel._state, msgObj);
+ // add/remove to unsend messages list
broadcastChannel._uMP.add(sendPromise);
-
sendPromise["catch"]().then(function () {
return broadcastChannel._uMP["delete"](sendPromise);
});
return sendPromise;
});
}
-
function _prepareChannel(channel) {
var maybePromise = channel.method.create(channel.name, channel.options);
-
if ((0, _util.isPromise)(maybePromise)) {
channel._prepP = maybePromise;
maybePromise.then(function (s) {
// used in tests to simulate slow runtime
-
/*if (channel.options.prepareDelay) {
await new Promise(res => setTimeout(res, this.options.prepareDelay));
}*/
@@ -242,30 +219,25 @@ function _prepareChannel(channel) {
channel._state = maybePromise;
}
}
-
function _hasMessageListeners(channel) {
if (channel._addEL.message.length > 0) return true;
if (channel._addEL.internal.length > 0) return true;
return false;
}
-
function _addListenerObject(channel, type, obj) {
channel._addEL[type].push(obj);
-
_startListening(channel);
}
-
function _removeListenerObject(channel, type, obj) {
channel._addEL[type] = channel._addEL[type].filter(function (o) {
return o !== obj;
});
-
_stopListening(channel);
}
-
function _startListening(channel) {
if (!channel._iL && _hasMessageListeners(channel)) {
// someone is listening, start subscribing
+
var listenerFn = function listenerFn(msgObj) {
channel._addEL[msgObj.type].forEach(function (listenerObject) {
/**
@@ -279,15 +251,12 @@ function _startListening(channel) {
*/
var hundredMsInMicro = 100 * 1000;
var minMessageTime = listenerObject.time - hundredMsInMicro;
-
if (msgObj.time >= minMessageTime) {
listenerObject.fn(msgObj.data);
}
});
};
-
var time = channel.method.microSeconds();
-
if (channel._prepP) {
channel._prepP.then(function () {
channel._iL = true;
@@ -299,7 +268,6 @@ function _startListening(channel) {
}
}
}
-
function _stopListening(channel) {
if (channel._iL && !_hasMessageListeners(channel)) {
// noone is listening, stop subscribing
@@ -312,7 +280,6 @@ function _stopListening(channel) {
"use strict";
var _index = require("./index.js");
-
/**
* because babel can only export on default-attribute,
* we use this for the non-module-build
@@ -321,6 +288,7 @@ var _index = require("./index.js");
* but
* var BroadcastChannel = require('broadcast-channel');
*/
+
module.exports = {
BroadcastChannel: _index.BroadcastChannel,
createLeaderElection: _index.createLeaderElection,
@@ -370,9 +338,7 @@ Object.defineProperty(exports, "enforceOptions", {
return _broadcastChannel.enforceOptions;
}
});
-
var _broadcastChannel = require("./broadcast-channel.js");
-
var _leaderElection = require("./leader-election.js");
},{"./broadcast-channel.js":1,"./leader-election.js":4}],4:[function(require,module,exports){
"use strict";
@@ -382,37 +348,30 @@ Object.defineProperty(exports, "__esModule", {
});
exports.beLeader = beLeader;
exports.createLeaderElection = createLeaderElection;
-
var _util = require("./util.js");
-
var _unload = require("unload");
-
var LeaderElection = function LeaderElection(broadcastChannel, options) {
var _this = this;
-
this.broadcastChannel = broadcastChannel;
this._options = options;
this.isLeader = false;
this.hasLeader = false;
this.isDead = false;
this.token = (0, _util.randomToken)();
+
/**
* Apply Queue,
* used to ensure we do not run applyOnce()
* in parallel.
*/
+ this._aplQ = _util.PROMISE_RESOLVED_VOID;
+ // amount of unfinished applyOnce() calls
+ this._aplQC = 0;
- this._aplQ = _util.PROMISE_RESOLVED_VOID; // amount of unfinished applyOnce() calls
-
- this._aplQC = 0; // things to clean up
-
+ // things to clean up
this._unl = []; // _unloads
-
this._lstns = []; // _listeners
-
this._dpL = function () {}; // onduplicate listener
-
-
this._dpLC = false; // true when onduplicate called
/**
@@ -420,55 +379,47 @@ var LeaderElection = function LeaderElection(broadcastChannel, options) {
* we still listen to messages to ensure the hasLeader flag
* is set correctly.
*/
-
var hasLeaderListener = function hasLeaderListener(msg) {
if (msg.context === 'leader') {
if (msg.action === 'death') {
_this.hasLeader = false;
}
-
if (msg.action === 'tell') {
_this.hasLeader = true;
}
}
};
-
this.broadcastChannel.addEventListener('internal', hasLeaderListener);
-
this._lstns.push(hasLeaderListener);
};
-
LeaderElection.prototype = {
/**
* Returns true if the instance is leader,
* false if not.
* @async
*/
- applyOnce: function applyOnce( // true if the applyOnce() call came from the fallbackInterval cycle
+ applyOnce: function applyOnce(
+ // true if the applyOnce() call came from the fallbackInterval cycle
isFromFallbackInterval) {
var _this2 = this;
-
if (this.isLeader) {
return (0, _util.sleep)(0, true);
}
-
if (this.isDead) {
return (0, _util.sleep)(0, false);
}
+
/**
* Already applying more then once,
* -> wait for the apply queue to be finished.
*/
-
-
if (this._aplQC > 1) {
return this._aplQ;
}
+
/**
* Add a new apply-run
*/
-
-
var applyRun = function applyRun() {
/**
* Optimization shortcuts.
@@ -478,7 +429,6 @@ LeaderElection.prototype = {
if (_this2.isLeader) {
return _util.PROMISE_RESOLVED_TRUE;
}
-
var stopCriteria = false;
var stopCriteriaPromiseResolve;
/**
@@ -487,7 +437,6 @@ LeaderElection.prototype = {
* have to await the responseTime when it is already clear
* that the election failed.
*/
-
var stopCriteriaPromise = new Promise(function (res) {
stopCriteriaPromiseResolve = function stopCriteriaPromiseResolve() {
stopCriteria = true;
@@ -495,11 +444,9 @@ LeaderElection.prototype = {
};
});
var recieved = [];
-
var handleMessage = function handleMessage(msg) {
if (msg.context === 'leader' && msg.token != _this2.token) {
recieved.push(msg);
-
if (msg.action === 'apply') {
// other is applying
if (msg.token > _this2.token) {
@@ -510,7 +457,6 @@ LeaderElection.prototype = {
stopCriteriaPromiseResolve();
}
}
-
if (msg.action === 'tell') {
// other is already leader
stopCriteriaPromiseResolve();
@@ -518,8 +464,8 @@ LeaderElection.prototype = {
}
}
};
-
_this2.broadcastChannel.addEventListener('internal', handleMessage);
+
/**
* If the applyOnce() call came from the fallbackInterval,
* we can assume that the election runs in the background and
@@ -530,26 +476,24 @@ LeaderElection.prototype = {
* But also it takes longer which is not a problem because we anyway
* run in the background.
*/
-
-
var waitForAnswerTime = isFromFallbackInterval ? _this2._options.responseTime * 4 : _this2._options.responseTime;
-
var applyPromise = _sendMessage(_this2, 'apply') // send out that this one is applying
.then(function () {
return Promise.race([(0, _util.sleep)(waitForAnswerTime), stopCriteriaPromise.then(function () {
return Promise.reject(new Error());
})]);
- }) // send again in case another instance was just created
+ })
+ // send again in case another instance was just created
.then(function () {
return _sendMessage(_this2, 'apply');
- }) // let others time to respond
+ })
+ // let others time to respond
.then(function () {
return Promise.race([(0, _util.sleep)(waitForAnswerTime), stopCriteriaPromise.then(function () {
return Promise.reject(new Error());
})]);
})["catch"](function () {}).then(function () {
_this2.broadcastChannel.removeEventListener('internal', handleMessage);
-
if (!stopCriteria) {
// no stop criteria -> own is leader
return beLeader(_this2).then(function () {
@@ -560,10 +504,8 @@ LeaderElection.prototype = {
return false;
}
});
-
return applyPromise;
};
-
this._aplQC = this._aplQC + 1;
this._aplQ = this._aplQ.then(function () {
return applyRun();
@@ -575,82 +517,68 @@ LeaderElection.prototype = {
});
},
awaitLeadership: function awaitLeadership() {
- if (
- /* _awaitLeadershipPromise */
+ if ( /* _awaitLeadershipPromise */
!this._aLP) {
this._aLP = _awaitLeadershipOnce(this);
}
-
return this._aLP;
},
-
set onduplicate(fn) {
this._dpL = fn;
},
-
die: function die() {
var _this3 = this;
-
this._lstns.forEach(function (listener) {
return _this3.broadcastChannel.removeEventListener('internal', listener);
});
-
this._lstns = [];
-
this._unl.forEach(function (uFn) {
return uFn.remove();
});
-
this._unl = [];
-
if (this.isLeader) {
this.hasLeader = false;
this.isLeader = false;
}
-
this.isDead = true;
return _sendMessage(this, 'death');
}
};
+
/**
* @param leaderElector {LeaderElector}
*/
-
function _awaitLeadershipOnce(leaderElector) {
if (leaderElector.isLeader) {
return _util.PROMISE_RESOLVED_VOID;
}
-
return new Promise(function (res) {
var resolved = false;
-
function finish() {
if (resolved) {
return;
}
-
resolved = true;
leaderElector.broadcastChannel.removeEventListener('internal', whenDeathListener);
res(true);
- } // try once now
-
+ }
+ // try once now
leaderElector.applyOnce().then(function () {
if (leaderElector.isLeader) {
finish();
}
});
+
/**
* Try on fallbackInterval
* @recursive
*/
-
var tryOnFallBack = function tryOnFallBack() {
return (0, _util.sleep)(leaderElector._options.fallbackInterval).then(function () {
if (leaderElector.isDead || resolved) {
return;
}
-
if (leaderElector.isLeader) {
finish();
} else {
@@ -664,9 +592,9 @@ function _awaitLeadershipOnce(leaderElector) {
}
});
};
+ tryOnFallBack();
- tryOnFallBack(); // try when other leader dies
-
+ // try when other leader dies
var whenDeathListener = function whenDeathListener(msg) {
if (msg.context === 'leader' && msg.action === 'death') {
leaderElector.hasLeader = false;
@@ -677,17 +605,14 @@ function _awaitLeadershipOnce(leaderElector) {
});
}
};
-
leaderElector.broadcastChannel.addEventListener('internal', whenDeathListener);
-
leaderElector._lstns.push(whenDeathListener);
});
}
+
/**
* sends and internal message over the broadcast-channel
*/
-
-
function _sendMessage(leaderElector, action) {
var msgJson = {
context: 'leader',
@@ -696,21 +621,17 @@ function _sendMessage(leaderElector, action) {
};
return leaderElector.broadcastChannel.postInternal(msgJson);
}
-
function beLeader(leaderElector) {
leaderElector.isLeader = true;
leaderElector.hasLeader = true;
var unloadFn = (0, _unload.add)(function () {
return leaderElector.die();
});
-
leaderElector._unl.push(unloadFn);
-
var isLeaderListener = function isLeaderListener(msg) {
if (msg.context === 'leader' && msg.action === 'apply') {
_sendMessage(leaderElector, 'tell');
}
-
if (msg.context === 'leader' && msg.action === 'tell' && !leaderElector._dpLC) {
/**
* another instance is also leader!
@@ -721,49 +642,35 @@ function beLeader(leaderElector) {
* @link https://github.com/pubkey/broadcast-channel/issues/385
*/
leaderElector._dpLC = true;
-
leaderElector._dpL(); // message the lib user so the app can handle the problem
-
-
_sendMessage(leaderElector, 'tell'); // ensure other leader also knows the problem
-
}
};
leaderElector.broadcastChannel.addEventListener('internal', isLeaderListener);
-
leaderElector._lstns.push(isLeaderListener);
-
return _sendMessage(leaderElector, 'tell');
}
-
function fillOptionsWithDefaults(options, channel) {
if (!options) options = {};
options = JSON.parse(JSON.stringify(options));
-
if (!options.fallbackInterval) {
options.fallbackInterval = 3000;
}
-
if (!options.responseTime) {
options.responseTime = channel.method.averageResponseTime(channel.options);
}
-
return options;
}
-
function createLeaderElection(channel, options) {
if (channel._leaderElector) {
throw new Error('BroadcastChannel already has a leader-elector');
}
-
options = fillOptionsWithDefaults(options, channel);
var elector = new LeaderElection(channel, options);
-
channel._befC.push(function () {
return elector.die();
});
-
channel._leaderElector = elector;
return elector;
}
@@ -771,59 +678,49 @@ function createLeaderElection(channel, options) {
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
-
var _typeof = require("@babel/runtime/helpers/typeof");
-
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.chooseMethod = chooseMethod;
-
var _native = _interopRequireDefault(require("./methods/native.js"));
-
var _indexedDb = _interopRequireDefault(require("./methods/indexed-db.js"));
-
var _localstorage = _interopRequireDefault(require("./methods/localstorage.js"));
-
var _simulate = _interopRequireDefault(require("./methods/simulate.js"));
-
-
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
-
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
-
// the line below will be removed from es5/browser builds
+
// order is important
-var METHODS = [_native["default"], // fastest
+var METHODS = [_native["default"],
+// fastest
_indexedDb["default"], _localstorage["default"]];
-
function chooseMethod(options) {
- var chooseMethods = [].concat(options.methods, METHODS).filter(Boolean); // the line below will be removed from es5/browser builds
+ var chooseMethods = [].concat(options.methods, METHODS).filter(Boolean);
+ // the line below will be removed from es5/browser builds
+ // directly chosen
if (options.type) {
if (options.type === 'simulate') {
// only use simulate-method if directly chosen
return _simulate["default"];
}
-
var ret = chooseMethods.find(function (m) {
return m.type === options.type;
});
if (!ret) throw new Error('method-type ' + options.type + ' not found');else return ret;
}
+
/**
* if no webworker support is needed,
* remove idb from the list so that localstorage is been chosen
*/
-
-
if (!options.webWorkerSupport) {
chooseMethods = chooseMethods.filter(function (m) {
return m.type !== 'idb';
});
}
-
var useMethod = chooseMethods.find(function (method) {
return method.canBeUsed();
});
@@ -856,13 +753,9 @@ exports.postMessage = postMessage;
exports.removeMessagesById = removeMessagesById;
exports.type = void 0;
exports.writeMessage = writeMessage;
-
var _util = require("../util.js");
-
var _obliviousSet = require("oblivious-set");
-
var _options = require("../options.js");
-
/**
* this method uses indexeddb to store the messages
* There is currently no observerAPI for idb
@@ -871,58 +764,54 @@ var _options = require("../options.js");
* When working on this, ensure to use these performance optimizations:
* @link https://rxdb.info/slow-indexeddb.html
*/
+
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var DB_PREFIX = 'pubkey.broadcast-channel-0-';
var OBJECT_STORE_ID = 'messages';
+
/**
* Use relaxed durability for faster performance on all transactions.
* @link https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/
*/
-
var TRANSACTION_SETTINGS = {
durability: 'relaxed'
};
exports.TRANSACTION_SETTINGS = TRANSACTION_SETTINGS;
var type = 'idb';
exports.type = type;
-
function getIdb() {
if (typeof indexedDB !== 'undefined') return indexedDB;
-
if (typeof window !== 'undefined') {
if (typeof window.mozIndexedDB !== 'undefined') return window.mozIndexedDB;
if (typeof window.webkitIndexedDB !== 'undefined') return window.webkitIndexedDB;
if (typeof window.msIndexedDB !== 'undefined') return window.msIndexedDB;
}
-
return false;
}
+
/**
* If possible, we should explicitly commit IndexedDB transactions
* for better performance.
* @link https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/
*/
-
-
function commitIndexedDBTransaction(tx) {
if (tx.commit) {
tx.commit();
}
}
-
function createDatabase(channelName) {
- var IndexedDB = getIdb(); // create table
+ var IndexedDB = getIdb();
+ // create table
var dbName = DB_PREFIX + channelName;
+
/**
* All IndexedDB databases are opened without version
* because it is a bit faster, especially on firefox
* @link http://nparashuram.com/IndexedDB/perf/#Open%20Database%20with%20version
*/
-
var openRequest = IndexedDB.open(dbName);
-
openRequest.onupgradeneeded = function (ev) {
var db = ev.target.result;
db.createObjectStore(OBJECT_STORE_ID, {
@@ -930,24 +819,21 @@ function createDatabase(channelName) {
autoIncrement: true
});
};
-
var dbPromise = new Promise(function (res, rej) {
openRequest.onerror = function (ev) {
return rej(ev);
};
-
openRequest.onsuccess = function () {
res(openRequest.result);
};
});
return dbPromise;
}
+
/**
* writes the new message to the database
* so other readers can find it
*/
-
-
function writeMessage(db, readerUuid, messageJson) {
var time = new Date().getTime();
var writeObject = {
@@ -960,17 +846,14 @@ function writeMessage(db, readerUuid, messageJson) {
tx.oncomplete = function () {
return res();
};
-
tx.onerror = function (ev) {
return rej(ev);
};
-
var objectStore = tx.objectStore(OBJECT_STORE_ID);
objectStore.add(writeObject);
commitIndexedDBTransaction(tx);
});
}
-
function getAllMessages(db) {
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS);
var objectStore = tx.objectStore(OBJECT_STORE_ID);
@@ -978,10 +861,9 @@ function getAllMessages(db) {
return new Promise(function (res) {
objectStore.openCursor().onsuccess = function (ev) {
var cursor = ev.target.result;
-
if (cursor) {
- ret.push(cursor.value); //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
-
+ ret.push(cursor.value);
+ //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor["continue"]();
} else {
commitIndexedDBTransaction(tx);
@@ -990,31 +872,28 @@ function getAllMessages(db) {
};
});
}
-
function getMessagesHigherThan(db, lastCursorId) {
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS);
var objectStore = tx.objectStore(OBJECT_STORE_ID);
var ret = [];
var keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity);
+
/**
* Optimization shortcut,
* if getAll() can be used, do not use a cursor.
* @link https://rxdb.info/slow-indexeddb.html
*/
-
if (objectStore.getAll) {
var getAllRequest = objectStore.getAll(keyRangeValue);
return new Promise(function (res, rej) {
getAllRequest.onerror = function (err) {
return rej(err);
};
-
getAllRequest.onsuccess = function (e) {
res(e.target.result);
};
});
}
-
function openCursor() {
// Occasionally Safari will fail on IDBKeyRange.bound, this
// catches that error, having it open the cursor to the first
@@ -1026,17 +905,13 @@ function getMessagesHigherThan(db, lastCursorId) {
return objectStore.openCursor();
}
}
-
return new Promise(function (res, rej) {
var openCursorRequest = openCursor();
-
openCursorRequest.onerror = function (err) {
return rej(err);
};
-
openCursorRequest.onsuccess = function (ev) {
var cursor = ev.target.result;
-
if (cursor) {
if (cursor.value.id < lastCursorId + 1) {
cursor["continue"](lastCursorId + 1);
@@ -1051,12 +926,10 @@ function getMessagesHigherThan(db, lastCursorId) {
};
});
}
-
function removeMessagesById(channelState, ids) {
if (channelState.closed) {
return Promise.resolve([]);
}
-
var tx = channelState.db.transaction(OBJECT_STORE_ID, 'readwrite', TRANSACTION_SETTINGS);
var objectStore = tx.objectStore(OBJECT_STORE_ID);
return Promise.all(ids.map(function (id) {
@@ -1068,7 +941,6 @@ function removeMessagesById(channelState, ids) {
});
}));
}
-
function getOldMessages(db, ttl) {
var olderThen = new Date().getTime() - ttl;
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS);
@@ -1077,13 +949,11 @@ function getOldMessages(db, ttl) {
return new Promise(function (res) {
objectStore.openCursor().onsuccess = function (ev) {
var cursor = ev.target.result;
-
if (cursor) {
var msgObk = cursor.value;
-
if (msgObk.time < olderThen) {
- ret.push(msgObk); //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
-
+ ret.push(msgObk);
+ //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor["continue"]();
} else {
// no more old messages,
@@ -1097,7 +967,6 @@ function getOldMessages(db, ttl) {
};
});
}
-
function cleanOldMessages(channelState) {
return getOldMessages(channelState.db, channelState.options.idb.ttl).then(function (tooOld) {
return removeMessagesById(channelState, tooOld.map(function (msg) {
@@ -1105,7 +974,6 @@ function cleanOldMessages(channelState) {
}));
});
}
-
function create(channelName, options) {
options = (0, _options.fillOptionsWithDefaults)(options);
return createDatabase(channelName).then(function (db) {
@@ -1115,7 +983,6 @@ function create(channelName, options) {
channelName: channelName,
options: options,
uuid: (0, _util.randomToken)(),
-
/**
* emittedMessagesIds
* contains all messages that have been emitted before
@@ -1128,30 +995,27 @@ function create(channelName, options) {
readQueuePromises: [],
db: db
};
+
/**
* Handle abrupt closes that do not originate from db.close().
* This could happen, for example, if the underlying storage is
* removed or if the user clears the database in the browser's
* history preferences.
*/
-
db.onclose = function () {
state.closed = true;
if (options.idb.onclose) options.idb.onclose();
};
+
/**
* if service-workers are used,
* we have no 'storage'-event if they post a message,
* therefore we also have to set an interval
*/
-
-
_readLoop(state);
-
return state;
});
}
-
function _readLoop(state) {
if (state.closed) return;
readNewMessages(state).then(function () {
@@ -1160,25 +1024,21 @@ function _readLoop(state) {
return _readLoop(state);
});
}
-
function _filterMessage(msgObj, state) {
if (msgObj.uuid === state.uuid) return false; // send by own
-
if (state.eMIs.has(msgObj.id)) return false; // already emitted
-
if (msgObj.data.time < state.messagesCallbackTime) return false; // older then onMessageCallback
-
return true;
}
+
/**
* reads all new messages from the database and emits them
*/
-
-
function readNewMessages(state) {
// channel already closed
- if (state.closed) return _util.PROMISE_RESOLVED_VOID; // if no one is listening, we do not need to scan for new messages
+ if (state.closed) return _util.PROMISE_RESOLVED_VOID;
+ // if no one is listening, we do not need to scan for new messages
if (!state.messagesCallback) return _util.PROMISE_RESOLVED_VOID;
return getMessagesHigherThan(state.db, state.lastCursorId).then(function (newerMessages) {
var useMessages = newerMessages
@@ -1186,21 +1046,18 @@ function readNewMessages(state) {
* there is a bug in iOS where the msgObj can be undefined some times
* so we filter them out
* @link https://github.com/pubkey/broadcast-channel/issues/19
- */
- .filter(function (msgObj) {
+ */.filter(function (msgObj) {
return !!msgObj;
}).map(function (msgObj) {
if (msgObj.id > state.lastCursorId) {
state.lastCursorId = msgObj.id;
}
-
return msgObj;
}).filter(function (msgObj) {
return _filterMessage(msgObj, state);
}).sort(function (msgObjA, msgObjB) {
return msgObjA.time - msgObjB.time;
}); // sort by time
-
useMessages.forEach(function (msgObj) {
if (state.messagesCallback) {
state.eMIs.add(msgObj.id);
@@ -1210,12 +1067,10 @@ function readNewMessages(state) {
return _util.PROMISE_RESOLVED_VOID;
});
}
-
function close(channelState) {
channelState.closed = true;
channelState.db.close();
}
-
function postMessage(channelState, messageJson) {
channelState.writeBlockPromise = channelState.writeBlockPromise.then(function () {
return writeMessage(channelState.db, channelState.uuid, messageJson);
@@ -1227,27 +1082,21 @@ function postMessage(channelState, messageJson) {
});
return channelState.writeBlockPromise;
}
-
function onMessage(channelState, fn, time) {
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
readNewMessages(channelState);
}
-
function canBeUsed() {
var idb = getIdb();
-
if (!idb) {
return false;
}
-
return true;
}
-
function averageResponseTime(options) {
return options.idb.fallbackInterval * 2;
}
-
var _default = {
create: create,
close: close,
@@ -1278,13 +1127,9 @@ exports.postMessage = postMessage;
exports.removeStorageEventListener = removeStorageEventListener;
exports.storageKey = storageKey;
exports.type = void 0;
-
var _obliviousSet = require("oblivious-set");
-
var _options = require("../options.js");
-
var _util = require("../util.js");
-
/**
* A localStorage-only method which uses localstorage and its 'storage'-event
* This does not work inside of webworkers because they have no access to locastorage
@@ -1292,41 +1137,38 @@ var _util = require("../util.js");
* @link https://caniuse.com/#feat=namevalue-storage
* @link https://caniuse.com/#feat=indexeddb
*/
+
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var KEY_PREFIX = 'pubkey.broadcastChannel-';
var type = 'localstorage';
+
/**
* copied from crosstab
* @link https://github.com/tejacques/crosstab/blob/master/src/crosstab.js#L32
*/
-
exports.type = type;
-
function getLocalStorage() {
var localStorage;
if (typeof window === 'undefined') return null;
-
try {
localStorage = window.localStorage;
localStorage = window['ie8-eventlistener/storage'] || window.localStorage;
- } catch (e) {// New versions of Firefox throw a Security exception
+ } catch (e) {
+ // New versions of Firefox throw a Security exception
// if cookies are disabled. See
// https://bugzilla.mozilla.org/show_bug.cgi?id=1028153
}
-
return localStorage;
}
-
function storageKey(channelName) {
return KEY_PREFIX + channelName;
}
+
/**
* writes the new message to the storage
* and fires the storage-event so other readers can find it
*/
-
-
function postMessage(channelState, messageJson) {
return new Promise(function (res) {
(0, _util.sleep)().then(function () {
@@ -1339,12 +1181,12 @@ function postMessage(channelState, messageJson) {
};
var value = JSON.stringify(writeObj);
getLocalStorage().setItem(key, value);
+
/**
* StorageEvent does not fire the 'storage' event
* in the window that changes the state of the local storage.
* So we fire it manually
*/
-
var ev = document.createEvent('Event');
ev.initEvent('storage', true, true);
ev.key = key;
@@ -1354,52 +1196,42 @@ function postMessage(channelState, messageJson) {
});
});
}
-
function addStorageEventListener(channelName, fn) {
var key = storageKey(channelName);
-
var listener = function listener(ev) {
if (ev.key === key) {
fn(JSON.parse(ev.newValue));
}
};
-
window.addEventListener('storage', listener);
return listener;
}
-
function removeStorageEventListener(listener) {
window.removeEventListener('storage', listener);
}
-
function create(channelName, options) {
options = (0, _options.fillOptionsWithDefaults)(options);
-
if (!canBeUsed()) {
throw new Error('BroadcastChannel: localstorage cannot be used');
}
-
var uuid = (0, _util.randomToken)();
+
/**
* eMIs
* contains all messages that have been emitted before
* @type {ObliviousSet}
*/
-
var eMIs = new _obliviousSet.ObliviousSet(options.localstorage.removeTimeout);
var state = {
channelName: channelName,
uuid: uuid,
eMIs: eMIs // emittedMessagesIds
-
};
+
state.listener = addStorageEventListener(channelName, function (msgObj) {
if (!state.messagesCallback) return; // no listener
-
if (msgObj.uuid === uuid) return; // own message
-
if (!msgObj.token || eMIs.has(msgObj.token)) return; // already emitted
-
if (msgObj.data.time && msgObj.data.time < state.messagesCallbackTime) return; // too old
eMIs.add(msgObj.token);
@@ -1407,20 +1239,16 @@ function create(channelName, options) {
});
return state;
}
-
function close(channelState) {
removeStorageEventListener(channelState.listener);
}
-
function onMessage(channelState, fn, time) {
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
}
-
function canBeUsed() {
var ls = getLocalStorage();
if (!ls) return false;
-
try {
var key = '__broadcastchannel_check';
ls.setItem(key, 'works');
@@ -1431,22 +1259,17 @@ function canBeUsed() {
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API#Private_Browsing_Incognito_modes
return false;
}
-
return true;
}
-
function averageResponseTime() {
var defaultTime = 120;
var userAgent = navigator.userAgent.toLowerCase();
-
if (userAgent.includes('safari') && !userAgent.includes('chrome')) {
// safari is much slower so this time is higher
return defaultTime * 2;
}
-
return defaultTime;
}
-
var _default = {
create: create,
close: close,
@@ -1472,20 +1295,16 @@ exports.microSeconds = exports["default"] = void 0;
exports.onMessage = onMessage;
exports.postMessage = postMessage;
exports.type = void 0;
-
var _util = require("../util.js");
-
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var type = 'native';
exports.type = type;
-
function create(channelName) {
var state = {
messagesCallback: null,
bc: new BroadcastChannel(channelName),
subFns: [] // subscriberFunctions
-
};
state.bc.onmessage = function (msg) {
@@ -1493,15 +1312,12 @@ function create(channelName) {
state.messagesCallback(msg.data);
}
};
-
return state;
}
-
function close(channelState) {
channelState.bc.close();
channelState.subFns = [];
}
-
function postMessage(channelState, messageJson) {
try {
channelState.bc.postMessage(messageJson, false);
@@ -1510,31 +1326,25 @@ function postMessage(channelState, messageJson) {
return Promise.reject(err);
}
}
-
function onMessage(channelState, fn) {
channelState.messagesCallback = fn;
}
-
function canBeUsed() {
if (typeof window === 'undefined') {
return false;
}
-
if (typeof BroadcastChannel === 'function') {
if (BroadcastChannel._pubkey) {
throw new Error('BroadcastChannel: Do not overwrite window.BroadcastChannel with this module, this is not a polyfill');
}
-
return true;
} else {
return false;
}
}
-
function averageResponseTime() {
return 150;
}
-
var _default = {
create: create,
close: close,
@@ -1560,15 +1370,12 @@ exports.microSeconds = exports["default"] = void 0;
exports.onMessage = onMessage;
exports.postMessage = postMessage;
exports.type = void 0;
-
var _util = require("../util.js");
-
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var type = 'simulate';
exports.type = type;
var SIMULATE_CHANNELS = new Set();
-
function create(channelName) {
var state = {
name: channelName,
@@ -1577,11 +1384,9 @@ function create(channelName) {
SIMULATE_CHANNELS.add(state);
return state;
}
-
function close(channelState) {
SIMULATE_CHANNELS["delete"](channelState);
}
-
function postMessage(channelState, messageJson) {
return new Promise(function (res) {
return setTimeout(function () {
@@ -1599,19 +1404,15 @@ function postMessage(channelState, messageJson) {
}, 5);
});
}
-
function onMessage(channelState, fn) {
channelState.messagesCallback = fn;
}
-
function canBeUsed() {
return true;
}
-
function averageResponseTime() {
return 5;
}
-
var _default = {
create: create,
close: close,
@@ -1630,33 +1431,35 @@ Object.defineProperty(exports, "__esModule", {
value: true
});
exports.fillOptionsWithDefaults = fillOptionsWithDefaults;
-
function fillOptionsWithDefaults() {
var originalOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- var options = JSON.parse(JSON.stringify(originalOptions)); // main
-
- if (typeof options.webWorkerSupport === 'undefined') options.webWorkerSupport = true; // indexed-db
+ var options = JSON.parse(JSON.stringify(originalOptions));
- if (!options.idb) options.idb = {}; // after this time the messages get deleted
+ // main
+ if (typeof options.webWorkerSupport === 'undefined') options.webWorkerSupport = true;
+ // indexed-db
+ if (!options.idb) options.idb = {};
+ // after this time the messages get deleted
if (!options.idb.ttl) options.idb.ttl = 1000 * 45;
- if (!options.idb.fallbackInterval) options.idb.fallbackInterval = 150; // handles abrupt db onclose events.
-
- if (originalOptions.idb && typeof originalOptions.idb.onclose === 'function') options.idb.onclose = originalOptions.idb.onclose; // localstorage
+ if (!options.idb.fallbackInterval) options.idb.fallbackInterval = 150;
+ // handles abrupt db onclose events.
+ if (originalOptions.idb && typeof originalOptions.idb.onclose === 'function') options.idb.onclose = originalOptions.idb.onclose;
+ // localstorage
if (!options.localstorage) options.localstorage = {};
- if (!options.localstorage.removeTimeout) options.localstorage.removeTimeout = 1000 * 60; // custom methods
+ if (!options.localstorage.removeTimeout) options.localstorage.removeTimeout = 1000 * 60;
- if (originalOptions.methods) options.methods = originalOptions.methods; // node
+ // custom methods
+ if (originalOptions.methods) options.methods = originalOptions.methods;
+ // node
if (!options.node) options.node = {};
if (!options.node.ttl) options.node.ttl = 1000 * 60 * 2; // 2 minutes;
-
/**
* On linux use 'ulimit -Hn' to get the limit of open files.
* On ubuntu this was 4096 for me, so we use half of that as maxParallelWrites default.
*/
-
if (!options.node.maxParallelWrites) options.node.maxParallelWrites = 2048;
if (typeof options.node.useFastPath === 'undefined') options.node.useFastPath = true;
return options;
@@ -1673,7 +1476,6 @@ exports.microSeconds = microSeconds;
exports.randomInt = randomInt;
exports.randomToken = randomToken;
exports.sleep = sleep;
-
/**
* returns true if the given object is a promise
*/
@@ -1684,14 +1486,12 @@ function isPromise(obj) {
return false;
}
}
-
var PROMISE_RESOLVED_FALSE = Promise.resolve(false);
exports.PROMISE_RESOLVED_FALSE = PROMISE_RESOLVED_FALSE;
var PROMISE_RESOLVED_TRUE = Promise.resolve(true);
exports.PROMISE_RESOLVED_TRUE = PROMISE_RESOLVED_TRUE;
var PROMISE_RESOLVED_VOID = Promise.resolve();
exports.PROMISE_RESOLVED_VOID = PROMISE_RESOLVED_VOID;
-
function sleep(time, resolveWith) {
if (!time) time = 0;
return new Promise(function (res) {
@@ -1700,21 +1500,19 @@ function sleep(time, resolveWith) {
}, time);
});
}
-
function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
+
/**
* https://stackoverflow.com/a/8084248
*/
-
-
function randomToken() {
return Math.random().toString(36).substring(2);
}
-
var lastMs = 0;
var additional = 0;
+
/**
* returns the current time in micro-seconds,
* WARNING: This is a pseudo-function
@@ -1722,10 +1520,8 @@ var additional = 0;
* This is enough in browsers, and this function will not be used in nodejs.
* The main reason for this hack is to ensure that BroadcastChannel behaves equal to production when it is used in fast-running unit tests.
*/
-
function microSeconds() {
var ms = new Date().getTime();
-
if (ms === lastMs) {
additional++;
return ms * 1000 + additional;
@@ -1785,7 +1581,6 @@ function _interopRequireDefault(obj) {
"default": obj
};
}
-
module.exports = _interopRequireDefault, module.exports.__esModule = true, module.exports["default"] = module.exports;
},{}],15:[function(require,module,exports){
function _typeof(obj) {
@@ -1797,7 +1592,6 @@ function _typeof(obj) {
return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
}, module.exports.__esModule = true, module.exports["default"] = module.exports), _typeof(obj);
}
-
module.exports = _typeof, module.exports.__esModule = true, module.exports["default"] = module.exports;
},{}],16:[function(require,module,exports){
@@ -8323,6 +8117,7 @@ var runtime = (function (exports) {
var Op = Object.prototype;
var hasOwn = Op.hasOwnProperty;
+ var defineProperty = Object.defineProperty || function (obj, key, desc) { obj[key] = desc.value; };
var undefined; // More compressible than void 0.
var $Symbol = typeof Symbol === "function" ? Symbol : {};
var iteratorSymbol = $Symbol.iterator || "@@iterator";
@@ -8355,7 +8150,7 @@ var runtime = (function (exports) {
// The ._invoke method unifies the implementations of the .next,
// .throw, and .return methods.
- generator._invoke = makeInvokeMethod(innerFn, self, context);
+ defineProperty(generator, "_invoke", { value: makeInvokeMethod(innerFn, self, context) });
return generator;
}
@@ -8416,8 +8211,12 @@ var runtime = (function (exports) {
var Gp = GeneratorFunctionPrototype.prototype =
Generator.prototype = Object.create(IteratorPrototype);
GeneratorFunction.prototype = GeneratorFunctionPrototype;
- define(Gp, "constructor", GeneratorFunctionPrototype);
- define(GeneratorFunctionPrototype, "constructor", GeneratorFunction);
+ defineProperty(Gp, "constructor", { value: GeneratorFunctionPrototype, configurable: true });
+ defineProperty(
+ GeneratorFunctionPrototype,
+ "constructor",
+ { value: GeneratorFunction, configurable: true }
+ );
GeneratorFunction.displayName = define(
GeneratorFunctionPrototype,
toStringTagSymbol,
@@ -8527,7 +8326,7 @@ var runtime = (function (exports) {
// Define the unified helper method that is used to implement .next,
// .throw, and .return (see defineIteratorMethods).
- this._invoke = enqueue;
+ defineProperty(this, "_invoke", { value: enqueue });
}
defineIteratorMethods(AsyncIterator.prototype);
@@ -8765,7 +8564,8 @@ var runtime = (function (exports) {
this.reset(true);
}
- exports.keys = function(object) {
+ exports.keys = function(val) {
+ var object = Object(val);
var keys = [];
for (var key in object) {
keys.push(key);
@@ -9175,30 +8975,26 @@ function getSize() {
"use strict";
var _util = require("./util.js");
-
/* eslint-disable */
-
/**
* this isframe is used to test the leader-election
* in the e2e tests and the demo-page
* used in docs/leader-iframe.html
*/
-require('@babel/polyfill');
+require('@babel/polyfill');
var _require = require('../../'),
- BroadcastChannel = _require.BroadcastChannel,
- createLeaderElection = _require.createLeaderElection;
-
+ BroadcastChannel = _require.BroadcastChannel,
+ createLeaderElection = _require.createLeaderElection;
var channelName = (0, _util.getParameterByName)('channelName');
var methodType = (0, _util.getParameterByName)('methodType');
-var boxEl = document.getElementById('box'); // overwrite console.log
+var boxEl = document.getElementById('box');
+// overwrite console.log
var logBefore = console.log;
-
console.log = function (str) {
logBefore('iframe: ' + str);
};
-
var channel = new BroadcastChannel(channelName, {
type: methodType
});
@@ -9217,8 +9013,8 @@ Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getParameterByName = getParameterByName;
-
/* eslint no-useless-escape: "off" */
+
// https://stackoverflow.com/a/901144/3443137
function getParameterByName(name, url) {
if (!url) url = window.location.href;
diff --git a/docs/worker.js b/docs/worker.js
index 7601c48d..e2483a4e 100644
--- a/docs/worker.js
+++ b/docs/worker.js
@@ -7,13 +7,9 @@ Object.defineProperty(exports, "__esModule", {
exports.OPEN_BROADCAST_CHANNELS = exports.BroadcastChannel = void 0;
exports.clearNodeFolder = clearNodeFolder;
exports.enforceOptions = enforceOptions;
-
var _util = require("./util.js");
-
var _methodChooser = require("./method-chooser.js");
-
var _options = require("./options.js");
-
/**
* Contains all open channels,
* used in tests to ensure everything is closed.
@@ -21,77 +17,73 @@ var _options = require("./options.js");
var OPEN_BROADCAST_CHANNELS = new Set();
exports.OPEN_BROADCAST_CHANNELS = OPEN_BROADCAST_CHANNELS;
var lastId = 0;
-
var BroadcastChannel = function BroadcastChannel(name, options) {
// identifier of the channel to debug stuff
this.id = lastId++;
OPEN_BROADCAST_CHANNELS.add(this);
this.name = name;
-
if (ENFORCED_OPTIONS) {
options = ENFORCED_OPTIONS;
}
-
this.options = (0, _options.fillOptionsWithDefaults)(options);
- this.method = (0, _methodChooser.chooseMethod)(this.options); // isListening
+ this.method = (0, _methodChooser.chooseMethod)(this.options);
+ // isListening
this._iL = false;
+
/**
* _onMessageListener
* setting onmessage twice,
* will overwrite the first listener
*/
-
this._onML = null;
+
/**
* _addEventListeners
*/
-
this._addEL = {
message: [],
internal: []
};
+
/**
* Unsend message promises
* where the sending is still in progress
* @type {Set}
*/
-
this._uMP = new Set();
+
/**
* _beforeClose
* array of promises that will be awaited
* before the channel is closed
*/
-
this._befC = [];
+
/**
* _preparePromise
*/
-
this._prepP = null;
-
_prepareChannel(this);
-}; // STATICS
+};
+
+// STATICS
/**
* used to identify if someone overwrites
* window.BroadcastChannel with this
* See methods/native.js
*/
-
-
exports.BroadcastChannel = BroadcastChannel;
BroadcastChannel._pubkey = true;
+
/**
* clears the tmp-folder if is node
* @return {Promise} true if has run, false if not node
*/
-
function clearNodeFolder(options) {
options = (0, _options.fillOptionsWithDefaults)(options);
var method = (0, _methodChooser.chooseMethod)(options);
-
if (method.type === 'node') {
return method.clearNodeFolder().then(function () {
return true;
@@ -100,19 +92,17 @@ function clearNodeFolder(options) {
return _util.PROMISE_RESOLVED_FALSE;
}
}
+
/**
* if set, this method is enforced,
* no mather what the options are
*/
-
-
var ENFORCED_OPTIONS;
-
function enforceOptions(options) {
ENFORCED_OPTIONS = options;
-} // PROTOTYPE
-
+}
+// PROTOTYPE
BroadcastChannel.prototype = {
postMessage: function postMessage(msg) {
if (this.closed) {
@@ -124,87 +114,77 @@ BroadcastChannel.prototype = {
*/
JSON.stringify(msg));
}
-
return _post(this, 'message', msg);
},
postInternal: function postInternal(msg) {
return _post(this, 'internal', msg);
},
-
set onmessage(fn) {
var time = this.method.microSeconds();
var listenObj = {
time: time,
fn: fn
};
-
_removeListenerObject(this, 'message', this._onML);
-
if (fn && typeof fn === 'function') {
this._onML = listenObj;
-
_addListenerObject(this, 'message', listenObj);
} else {
this._onML = null;
}
},
-
addEventListener: function addEventListener(type, fn) {
var time = this.method.microSeconds();
var listenObj = {
time: time,
fn: fn
};
-
_addListenerObject(this, type, listenObj);
},
removeEventListener: function removeEventListener(type, fn) {
var obj = this._addEL[type].find(function (obj) {
return obj.fn === fn;
});
-
_removeListenerObject(this, type, obj);
},
close: function close() {
var _this = this;
-
if (this.closed) {
return;
}
-
OPEN_BROADCAST_CHANNELS["delete"](this);
this.closed = true;
var awaitPrepare = this._prepP ? this._prepP : _util.PROMISE_RESOLVED_VOID;
this._onML = null;
this._addEL.message = [];
- return awaitPrepare // wait until all current sending are processed
+ return awaitPrepare
+ // wait until all current sending are processed
.then(function () {
return Promise.all(Array.from(_this._uMP));
- }) // run before-close hooks
+ })
+ // run before-close hooks
.then(function () {
return Promise.all(_this._befC.map(function (fn) {
return fn();
}));
- }) // close the channel
+ })
+ // close the channel
.then(function () {
return _this.method.close(_this._state);
});
},
-
get type() {
return this.method.type;
},
-
get isClosed() {
return this.closed;
}
-
};
+
/**
* Post a message over the channel
* @returns {Promise} that resolved when the message sending is done
*/
-
function _post(broadcastChannel, type, msg) {
var time = broadcastChannel.method.microSeconds();
var msgObj = {
@@ -214,25 +194,22 @@ function _post(broadcastChannel, type, msg) {
};
var awaitPrepare = broadcastChannel._prepP ? broadcastChannel._prepP : _util.PROMISE_RESOLVED_VOID;
return awaitPrepare.then(function () {
- var sendPromise = broadcastChannel.method.postMessage(broadcastChannel._state, msgObj); // add/remove to unsend messages list
+ var sendPromise = broadcastChannel.method.postMessage(broadcastChannel._state, msgObj);
+ // add/remove to unsend messages list
broadcastChannel._uMP.add(sendPromise);
-
sendPromise["catch"]().then(function () {
return broadcastChannel._uMP["delete"](sendPromise);
});
return sendPromise;
});
}
-
function _prepareChannel(channel) {
var maybePromise = channel.method.create(channel.name, channel.options);
-
if ((0, _util.isPromise)(maybePromise)) {
channel._prepP = maybePromise;
maybePromise.then(function (s) {
// used in tests to simulate slow runtime
-
/*if (channel.options.prepareDelay) {
await new Promise(res => setTimeout(res, this.options.prepareDelay));
}*/
@@ -242,30 +219,25 @@ function _prepareChannel(channel) {
channel._state = maybePromise;
}
}
-
function _hasMessageListeners(channel) {
if (channel._addEL.message.length > 0) return true;
if (channel._addEL.internal.length > 0) return true;
return false;
}
-
function _addListenerObject(channel, type, obj) {
channel._addEL[type].push(obj);
-
_startListening(channel);
}
-
function _removeListenerObject(channel, type, obj) {
channel._addEL[type] = channel._addEL[type].filter(function (o) {
return o !== obj;
});
-
_stopListening(channel);
}
-
function _startListening(channel) {
if (!channel._iL && _hasMessageListeners(channel)) {
// someone is listening, start subscribing
+
var listenerFn = function listenerFn(msgObj) {
channel._addEL[msgObj.type].forEach(function (listenerObject) {
/**
@@ -279,15 +251,12 @@ function _startListening(channel) {
*/
var hundredMsInMicro = 100 * 1000;
var minMessageTime = listenerObject.time - hundredMsInMicro;
-
if (msgObj.time >= minMessageTime) {
listenerObject.fn(msgObj.data);
}
});
};
-
var time = channel.method.microSeconds();
-
if (channel._prepP) {
channel._prepP.then(function () {
channel._iL = true;
@@ -299,7 +268,6 @@ function _startListening(channel) {
}
}
}
-
function _stopListening(channel) {
if (channel._iL && !_hasMessageListeners(channel)) {
// noone is listening, stop subscribing
@@ -312,7 +280,6 @@ function _stopListening(channel) {
"use strict";
var _index = require("./index.js");
-
/**
* because babel can only export on default-attribute,
* we use this for the non-module-build
@@ -321,6 +288,7 @@ var _index = require("./index.js");
* but
* var BroadcastChannel = require('broadcast-channel');
*/
+
module.exports = {
BroadcastChannel: _index.BroadcastChannel,
createLeaderElection: _index.createLeaderElection,
@@ -370,9 +338,7 @@ Object.defineProperty(exports, "enforceOptions", {
return _broadcastChannel.enforceOptions;
}
});
-
var _broadcastChannel = require("./broadcast-channel.js");
-
var _leaderElection = require("./leader-election.js");
},{"./broadcast-channel.js":1,"./leader-election.js":4}],4:[function(require,module,exports){
"use strict";
@@ -382,37 +348,30 @@ Object.defineProperty(exports, "__esModule", {
});
exports.beLeader = beLeader;
exports.createLeaderElection = createLeaderElection;
-
var _util = require("./util.js");
-
var _unload = require("unload");
-
var LeaderElection = function LeaderElection(broadcastChannel, options) {
var _this = this;
-
this.broadcastChannel = broadcastChannel;
this._options = options;
this.isLeader = false;
this.hasLeader = false;
this.isDead = false;
this.token = (0, _util.randomToken)();
+
/**
* Apply Queue,
* used to ensure we do not run applyOnce()
* in parallel.
*/
+ this._aplQ = _util.PROMISE_RESOLVED_VOID;
+ // amount of unfinished applyOnce() calls
+ this._aplQC = 0;
- this._aplQ = _util.PROMISE_RESOLVED_VOID; // amount of unfinished applyOnce() calls
-
- this._aplQC = 0; // things to clean up
-
+ // things to clean up
this._unl = []; // _unloads
-
this._lstns = []; // _listeners
-
this._dpL = function () {}; // onduplicate listener
-
-
this._dpLC = false; // true when onduplicate called
/**
@@ -420,55 +379,47 @@ var LeaderElection = function LeaderElection(broadcastChannel, options) {
* we still listen to messages to ensure the hasLeader flag
* is set correctly.
*/
-
var hasLeaderListener = function hasLeaderListener(msg) {
if (msg.context === 'leader') {
if (msg.action === 'death') {
_this.hasLeader = false;
}
-
if (msg.action === 'tell') {
_this.hasLeader = true;
}
}
};
-
this.broadcastChannel.addEventListener('internal', hasLeaderListener);
-
this._lstns.push(hasLeaderListener);
};
-
LeaderElection.prototype = {
/**
* Returns true if the instance is leader,
* false if not.
* @async
*/
- applyOnce: function applyOnce( // true if the applyOnce() call came from the fallbackInterval cycle
+ applyOnce: function applyOnce(
+ // true if the applyOnce() call came from the fallbackInterval cycle
isFromFallbackInterval) {
var _this2 = this;
-
if (this.isLeader) {
return (0, _util.sleep)(0, true);
}
-
if (this.isDead) {
return (0, _util.sleep)(0, false);
}
+
/**
* Already applying more then once,
* -> wait for the apply queue to be finished.
*/
-
-
if (this._aplQC > 1) {
return this._aplQ;
}
+
/**
* Add a new apply-run
*/
-
-
var applyRun = function applyRun() {
/**
* Optimization shortcuts.
@@ -478,7 +429,6 @@ LeaderElection.prototype = {
if (_this2.isLeader) {
return _util.PROMISE_RESOLVED_TRUE;
}
-
var stopCriteria = false;
var stopCriteriaPromiseResolve;
/**
@@ -487,7 +437,6 @@ LeaderElection.prototype = {
* have to await the responseTime when it is already clear
* that the election failed.
*/
-
var stopCriteriaPromise = new Promise(function (res) {
stopCriteriaPromiseResolve = function stopCriteriaPromiseResolve() {
stopCriteria = true;
@@ -495,11 +444,9 @@ LeaderElection.prototype = {
};
});
var recieved = [];
-
var handleMessage = function handleMessage(msg) {
if (msg.context === 'leader' && msg.token != _this2.token) {
recieved.push(msg);
-
if (msg.action === 'apply') {
// other is applying
if (msg.token > _this2.token) {
@@ -510,7 +457,6 @@ LeaderElection.prototype = {
stopCriteriaPromiseResolve();
}
}
-
if (msg.action === 'tell') {
// other is already leader
stopCriteriaPromiseResolve();
@@ -518,8 +464,8 @@ LeaderElection.prototype = {
}
}
};
-
_this2.broadcastChannel.addEventListener('internal', handleMessage);
+
/**
* If the applyOnce() call came from the fallbackInterval,
* we can assume that the election runs in the background and
@@ -530,26 +476,24 @@ LeaderElection.prototype = {
* But also it takes longer which is not a problem because we anyway
* run in the background.
*/
-
-
var waitForAnswerTime = isFromFallbackInterval ? _this2._options.responseTime * 4 : _this2._options.responseTime;
-
var applyPromise = _sendMessage(_this2, 'apply') // send out that this one is applying
.then(function () {
return Promise.race([(0, _util.sleep)(waitForAnswerTime), stopCriteriaPromise.then(function () {
return Promise.reject(new Error());
})]);
- }) // send again in case another instance was just created
+ })
+ // send again in case another instance was just created
.then(function () {
return _sendMessage(_this2, 'apply');
- }) // let others time to respond
+ })
+ // let others time to respond
.then(function () {
return Promise.race([(0, _util.sleep)(waitForAnswerTime), stopCriteriaPromise.then(function () {
return Promise.reject(new Error());
})]);
})["catch"](function () {}).then(function () {
_this2.broadcastChannel.removeEventListener('internal', handleMessage);
-
if (!stopCriteria) {
// no stop criteria -> own is leader
return beLeader(_this2).then(function () {
@@ -560,10 +504,8 @@ LeaderElection.prototype = {
return false;
}
});
-
return applyPromise;
};
-
this._aplQC = this._aplQC + 1;
this._aplQ = this._aplQ.then(function () {
return applyRun();
@@ -575,82 +517,68 @@ LeaderElection.prototype = {
});
},
awaitLeadership: function awaitLeadership() {
- if (
- /* _awaitLeadershipPromise */
+ if ( /* _awaitLeadershipPromise */
!this._aLP) {
this._aLP = _awaitLeadershipOnce(this);
}
-
return this._aLP;
},
-
set onduplicate(fn) {
this._dpL = fn;
},
-
die: function die() {
var _this3 = this;
-
this._lstns.forEach(function (listener) {
return _this3.broadcastChannel.removeEventListener('internal', listener);
});
-
this._lstns = [];
-
this._unl.forEach(function (uFn) {
return uFn.remove();
});
-
this._unl = [];
-
if (this.isLeader) {
this.hasLeader = false;
this.isLeader = false;
}
-
this.isDead = true;
return _sendMessage(this, 'death');
}
};
+
/**
* @param leaderElector {LeaderElector}
*/
-
function _awaitLeadershipOnce(leaderElector) {
if (leaderElector.isLeader) {
return _util.PROMISE_RESOLVED_VOID;
}
-
return new Promise(function (res) {
var resolved = false;
-
function finish() {
if (resolved) {
return;
}
-
resolved = true;
leaderElector.broadcastChannel.removeEventListener('internal', whenDeathListener);
res(true);
- } // try once now
-
+ }
+ // try once now
leaderElector.applyOnce().then(function () {
if (leaderElector.isLeader) {
finish();
}
});
+
/**
* Try on fallbackInterval
* @recursive
*/
-
var tryOnFallBack = function tryOnFallBack() {
return (0, _util.sleep)(leaderElector._options.fallbackInterval).then(function () {
if (leaderElector.isDead || resolved) {
return;
}
-
if (leaderElector.isLeader) {
finish();
} else {
@@ -664,9 +592,9 @@ function _awaitLeadershipOnce(leaderElector) {
}
});
};
+ tryOnFallBack();
- tryOnFallBack(); // try when other leader dies
-
+ // try when other leader dies
var whenDeathListener = function whenDeathListener(msg) {
if (msg.context === 'leader' && msg.action === 'death') {
leaderElector.hasLeader = false;
@@ -677,17 +605,14 @@ function _awaitLeadershipOnce(leaderElector) {
});
}
};
-
leaderElector.broadcastChannel.addEventListener('internal', whenDeathListener);
-
leaderElector._lstns.push(whenDeathListener);
});
}
+
/**
* sends and internal message over the broadcast-channel
*/
-
-
function _sendMessage(leaderElector, action) {
var msgJson = {
context: 'leader',
@@ -696,21 +621,17 @@ function _sendMessage(leaderElector, action) {
};
return leaderElector.broadcastChannel.postInternal(msgJson);
}
-
function beLeader(leaderElector) {
leaderElector.isLeader = true;
leaderElector.hasLeader = true;
var unloadFn = (0, _unload.add)(function () {
return leaderElector.die();
});
-
leaderElector._unl.push(unloadFn);
-
var isLeaderListener = function isLeaderListener(msg) {
if (msg.context === 'leader' && msg.action === 'apply') {
_sendMessage(leaderElector, 'tell');
}
-
if (msg.context === 'leader' && msg.action === 'tell' && !leaderElector._dpLC) {
/**
* another instance is also leader!
@@ -721,49 +642,35 @@ function beLeader(leaderElector) {
* @link https://github.com/pubkey/broadcast-channel/issues/385
*/
leaderElector._dpLC = true;
-
leaderElector._dpL(); // message the lib user so the app can handle the problem
-
-
_sendMessage(leaderElector, 'tell'); // ensure other leader also knows the problem
-
}
};
leaderElector.broadcastChannel.addEventListener('internal', isLeaderListener);
-
leaderElector._lstns.push(isLeaderListener);
-
return _sendMessage(leaderElector, 'tell');
}
-
function fillOptionsWithDefaults(options, channel) {
if (!options) options = {};
options = JSON.parse(JSON.stringify(options));
-
if (!options.fallbackInterval) {
options.fallbackInterval = 3000;
}
-
if (!options.responseTime) {
options.responseTime = channel.method.averageResponseTime(channel.options);
}
-
return options;
}
-
function createLeaderElection(channel, options) {
if (channel._leaderElector) {
throw new Error('BroadcastChannel already has a leader-elector');
}
-
options = fillOptionsWithDefaults(options, channel);
var elector = new LeaderElection(channel, options);
-
channel._befC.push(function () {
return elector.die();
});
-
channel._leaderElector = elector;
return elector;
}
@@ -771,59 +678,49 @@ function createLeaderElection(channel, options) {
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
-
var _typeof = require("@babel/runtime/helpers/typeof");
-
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.chooseMethod = chooseMethod;
-
var _native = _interopRequireDefault(require("./methods/native.js"));
-
var _indexedDb = _interopRequireDefault(require("./methods/indexed-db.js"));
-
var _localstorage = _interopRequireDefault(require("./methods/localstorage.js"));
-
var _simulate = _interopRequireDefault(require("./methods/simulate.js"));
-
-
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
-
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
-
// the line below will be removed from es5/browser builds
+
// order is important
-var METHODS = [_native["default"], // fastest
+var METHODS = [_native["default"],
+// fastest
_indexedDb["default"], _localstorage["default"]];
-
function chooseMethod(options) {
- var chooseMethods = [].concat(options.methods, METHODS).filter(Boolean); // the line below will be removed from es5/browser builds
+ var chooseMethods = [].concat(options.methods, METHODS).filter(Boolean);
+ // the line below will be removed from es5/browser builds
+ // directly chosen
if (options.type) {
if (options.type === 'simulate') {
// only use simulate-method if directly chosen
return _simulate["default"];
}
-
var ret = chooseMethods.find(function (m) {
return m.type === options.type;
});
if (!ret) throw new Error('method-type ' + options.type + ' not found');else return ret;
}
+
/**
* if no webworker support is needed,
* remove idb from the list so that localstorage is been chosen
*/
-
-
if (!options.webWorkerSupport) {
chooseMethods = chooseMethods.filter(function (m) {
return m.type !== 'idb';
});
}
-
var useMethod = chooseMethods.find(function (method) {
return method.canBeUsed();
});
@@ -856,13 +753,9 @@ exports.postMessage = postMessage;
exports.removeMessagesById = removeMessagesById;
exports.type = void 0;
exports.writeMessage = writeMessage;
-
var _util = require("../util.js");
-
var _obliviousSet = require("oblivious-set");
-
var _options = require("../options.js");
-
/**
* this method uses indexeddb to store the messages
* There is currently no observerAPI for idb
@@ -871,58 +764,54 @@ var _options = require("../options.js");
* When working on this, ensure to use these performance optimizations:
* @link https://rxdb.info/slow-indexeddb.html
*/
+
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var DB_PREFIX = 'pubkey.broadcast-channel-0-';
var OBJECT_STORE_ID = 'messages';
+
/**
* Use relaxed durability for faster performance on all transactions.
* @link https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/
*/
-
var TRANSACTION_SETTINGS = {
durability: 'relaxed'
};
exports.TRANSACTION_SETTINGS = TRANSACTION_SETTINGS;
var type = 'idb';
exports.type = type;
-
function getIdb() {
if (typeof indexedDB !== 'undefined') return indexedDB;
-
if (typeof window !== 'undefined') {
if (typeof window.mozIndexedDB !== 'undefined') return window.mozIndexedDB;
if (typeof window.webkitIndexedDB !== 'undefined') return window.webkitIndexedDB;
if (typeof window.msIndexedDB !== 'undefined') return window.msIndexedDB;
}
-
return false;
}
+
/**
* If possible, we should explicitly commit IndexedDB transactions
* for better performance.
* @link https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/
*/
-
-
function commitIndexedDBTransaction(tx) {
if (tx.commit) {
tx.commit();
}
}
-
function createDatabase(channelName) {
- var IndexedDB = getIdb(); // create table
+ var IndexedDB = getIdb();
+ // create table
var dbName = DB_PREFIX + channelName;
+
/**
* All IndexedDB databases are opened without version
* because it is a bit faster, especially on firefox
* @link http://nparashuram.com/IndexedDB/perf/#Open%20Database%20with%20version
*/
-
var openRequest = IndexedDB.open(dbName);
-
openRequest.onupgradeneeded = function (ev) {
var db = ev.target.result;
db.createObjectStore(OBJECT_STORE_ID, {
@@ -930,24 +819,21 @@ function createDatabase(channelName) {
autoIncrement: true
});
};
-
var dbPromise = new Promise(function (res, rej) {
openRequest.onerror = function (ev) {
return rej(ev);
};
-
openRequest.onsuccess = function () {
res(openRequest.result);
};
});
return dbPromise;
}
+
/**
* writes the new message to the database
* so other readers can find it
*/
-
-
function writeMessage(db, readerUuid, messageJson) {
var time = new Date().getTime();
var writeObject = {
@@ -960,17 +846,14 @@ function writeMessage(db, readerUuid, messageJson) {
tx.oncomplete = function () {
return res();
};
-
tx.onerror = function (ev) {
return rej(ev);
};
-
var objectStore = tx.objectStore(OBJECT_STORE_ID);
objectStore.add(writeObject);
commitIndexedDBTransaction(tx);
});
}
-
function getAllMessages(db) {
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS);
var objectStore = tx.objectStore(OBJECT_STORE_ID);
@@ -978,10 +861,9 @@ function getAllMessages(db) {
return new Promise(function (res) {
objectStore.openCursor().onsuccess = function (ev) {
var cursor = ev.target.result;
-
if (cursor) {
- ret.push(cursor.value); //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
-
+ ret.push(cursor.value);
+ //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor["continue"]();
} else {
commitIndexedDBTransaction(tx);
@@ -990,31 +872,28 @@ function getAllMessages(db) {
};
});
}
-
function getMessagesHigherThan(db, lastCursorId) {
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS);
var objectStore = tx.objectStore(OBJECT_STORE_ID);
var ret = [];
var keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity);
+
/**
* Optimization shortcut,
* if getAll() can be used, do not use a cursor.
* @link https://rxdb.info/slow-indexeddb.html
*/
-
if (objectStore.getAll) {
var getAllRequest = objectStore.getAll(keyRangeValue);
return new Promise(function (res, rej) {
getAllRequest.onerror = function (err) {
return rej(err);
};
-
getAllRequest.onsuccess = function (e) {
res(e.target.result);
};
});
}
-
function openCursor() {
// Occasionally Safari will fail on IDBKeyRange.bound, this
// catches that error, having it open the cursor to the first
@@ -1026,17 +905,13 @@ function getMessagesHigherThan(db, lastCursorId) {
return objectStore.openCursor();
}
}
-
return new Promise(function (res, rej) {
var openCursorRequest = openCursor();
-
openCursorRequest.onerror = function (err) {
return rej(err);
};
-
openCursorRequest.onsuccess = function (ev) {
var cursor = ev.target.result;
-
if (cursor) {
if (cursor.value.id < lastCursorId + 1) {
cursor["continue"](lastCursorId + 1);
@@ -1051,12 +926,10 @@ function getMessagesHigherThan(db, lastCursorId) {
};
});
}
-
function removeMessagesById(channelState, ids) {
if (channelState.closed) {
return Promise.resolve([]);
}
-
var tx = channelState.db.transaction(OBJECT_STORE_ID, 'readwrite', TRANSACTION_SETTINGS);
var objectStore = tx.objectStore(OBJECT_STORE_ID);
return Promise.all(ids.map(function (id) {
@@ -1068,7 +941,6 @@ function removeMessagesById(channelState, ids) {
});
}));
}
-
function getOldMessages(db, ttl) {
var olderThen = new Date().getTime() - ttl;
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS);
@@ -1077,13 +949,11 @@ function getOldMessages(db, ttl) {
return new Promise(function (res) {
objectStore.openCursor().onsuccess = function (ev) {
var cursor = ev.target.result;
-
if (cursor) {
var msgObk = cursor.value;
-
if (msgObk.time < olderThen) {
- ret.push(msgObk); //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
-
+ ret.push(msgObk);
+ //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor["continue"]();
} else {
// no more old messages,
@@ -1097,7 +967,6 @@ function getOldMessages(db, ttl) {
};
});
}
-
function cleanOldMessages(channelState) {
return getOldMessages(channelState.db, channelState.options.idb.ttl).then(function (tooOld) {
return removeMessagesById(channelState, tooOld.map(function (msg) {
@@ -1105,7 +974,6 @@ function cleanOldMessages(channelState) {
}));
});
}
-
function create(channelName, options) {
options = (0, _options.fillOptionsWithDefaults)(options);
return createDatabase(channelName).then(function (db) {
@@ -1115,7 +983,6 @@ function create(channelName, options) {
channelName: channelName,
options: options,
uuid: (0, _util.randomToken)(),
-
/**
* emittedMessagesIds
* contains all messages that have been emitted before
@@ -1128,30 +995,27 @@ function create(channelName, options) {
readQueuePromises: [],
db: db
};
+
/**
* Handle abrupt closes that do not originate from db.close().
* This could happen, for example, if the underlying storage is
* removed or if the user clears the database in the browser's
* history preferences.
*/
-
db.onclose = function () {
state.closed = true;
if (options.idb.onclose) options.idb.onclose();
};
+
/**
* if service-workers are used,
* we have no 'storage'-event if they post a message,
* therefore we also have to set an interval
*/
-
-
_readLoop(state);
-
return state;
});
}
-
function _readLoop(state) {
if (state.closed) return;
readNewMessages(state).then(function () {
@@ -1160,25 +1024,21 @@ function _readLoop(state) {
return _readLoop(state);
});
}
-
function _filterMessage(msgObj, state) {
if (msgObj.uuid === state.uuid) return false; // send by own
-
if (state.eMIs.has(msgObj.id)) return false; // already emitted
-
if (msgObj.data.time < state.messagesCallbackTime) return false; // older then onMessageCallback
-
return true;
}
+
/**
* reads all new messages from the database and emits them
*/
-
-
function readNewMessages(state) {
// channel already closed
- if (state.closed) return _util.PROMISE_RESOLVED_VOID; // if no one is listening, we do not need to scan for new messages
+ if (state.closed) return _util.PROMISE_RESOLVED_VOID;
+ // if no one is listening, we do not need to scan for new messages
if (!state.messagesCallback) return _util.PROMISE_RESOLVED_VOID;
return getMessagesHigherThan(state.db, state.lastCursorId).then(function (newerMessages) {
var useMessages = newerMessages
@@ -1186,21 +1046,18 @@ function readNewMessages(state) {
* there is a bug in iOS where the msgObj can be undefined some times
* so we filter them out
* @link https://github.com/pubkey/broadcast-channel/issues/19
- */
- .filter(function (msgObj) {
+ */.filter(function (msgObj) {
return !!msgObj;
}).map(function (msgObj) {
if (msgObj.id > state.lastCursorId) {
state.lastCursorId = msgObj.id;
}
-
return msgObj;
}).filter(function (msgObj) {
return _filterMessage(msgObj, state);
}).sort(function (msgObjA, msgObjB) {
return msgObjA.time - msgObjB.time;
}); // sort by time
-
useMessages.forEach(function (msgObj) {
if (state.messagesCallback) {
state.eMIs.add(msgObj.id);
@@ -1210,12 +1067,10 @@ function readNewMessages(state) {
return _util.PROMISE_RESOLVED_VOID;
});
}
-
function close(channelState) {
channelState.closed = true;
channelState.db.close();
}
-
function postMessage(channelState, messageJson) {
channelState.writeBlockPromise = channelState.writeBlockPromise.then(function () {
return writeMessage(channelState.db, channelState.uuid, messageJson);
@@ -1227,27 +1082,21 @@ function postMessage(channelState, messageJson) {
});
return channelState.writeBlockPromise;
}
-
function onMessage(channelState, fn, time) {
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
readNewMessages(channelState);
}
-
function canBeUsed() {
var idb = getIdb();
-
if (!idb) {
return false;
}
-
return true;
}
-
function averageResponseTime(options) {
return options.idb.fallbackInterval * 2;
}
-
var _default = {
create: create,
close: close,
@@ -1278,13 +1127,9 @@ exports.postMessage = postMessage;
exports.removeStorageEventListener = removeStorageEventListener;
exports.storageKey = storageKey;
exports.type = void 0;
-
var _obliviousSet = require("oblivious-set");
-
var _options = require("../options.js");
-
var _util = require("../util.js");
-
/**
* A localStorage-only method which uses localstorage and its 'storage'-event
* This does not work inside of webworkers because they have no access to locastorage
@@ -1292,41 +1137,38 @@ var _util = require("../util.js");
* @link https://caniuse.com/#feat=namevalue-storage
* @link https://caniuse.com/#feat=indexeddb
*/
+
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var KEY_PREFIX = 'pubkey.broadcastChannel-';
var type = 'localstorage';
+
/**
* copied from crosstab
* @link https://github.com/tejacques/crosstab/blob/master/src/crosstab.js#L32
*/
-
exports.type = type;
-
function getLocalStorage() {
var localStorage;
if (typeof window === 'undefined') return null;
-
try {
localStorage = window.localStorage;
localStorage = window['ie8-eventlistener/storage'] || window.localStorage;
- } catch (e) {// New versions of Firefox throw a Security exception
+ } catch (e) {
+ // New versions of Firefox throw a Security exception
// if cookies are disabled. See
// https://bugzilla.mozilla.org/show_bug.cgi?id=1028153
}
-
return localStorage;
}
-
function storageKey(channelName) {
return KEY_PREFIX + channelName;
}
+
/**
* writes the new message to the storage
* and fires the storage-event so other readers can find it
*/
-
-
function postMessage(channelState, messageJson) {
return new Promise(function (res) {
(0, _util.sleep)().then(function () {
@@ -1339,12 +1181,12 @@ function postMessage(channelState, messageJson) {
};
var value = JSON.stringify(writeObj);
getLocalStorage().setItem(key, value);
+
/**
* StorageEvent does not fire the 'storage' event
* in the window that changes the state of the local storage.
* So we fire it manually
*/
-
var ev = document.createEvent('Event');
ev.initEvent('storage', true, true);
ev.key = key;
@@ -1354,52 +1196,42 @@ function postMessage(channelState, messageJson) {
});
});
}
-
function addStorageEventListener(channelName, fn) {
var key = storageKey(channelName);
-
var listener = function listener(ev) {
if (ev.key === key) {
fn(JSON.parse(ev.newValue));
}
};
-
window.addEventListener('storage', listener);
return listener;
}
-
function removeStorageEventListener(listener) {
window.removeEventListener('storage', listener);
}
-
function create(channelName, options) {
options = (0, _options.fillOptionsWithDefaults)(options);
-
if (!canBeUsed()) {
throw new Error('BroadcastChannel: localstorage cannot be used');
}
-
var uuid = (0, _util.randomToken)();
+
/**
* eMIs
* contains all messages that have been emitted before
* @type {ObliviousSet}
*/
-
var eMIs = new _obliviousSet.ObliviousSet(options.localstorage.removeTimeout);
var state = {
channelName: channelName,
uuid: uuid,
eMIs: eMIs // emittedMessagesIds
-
};
+
state.listener = addStorageEventListener(channelName, function (msgObj) {
if (!state.messagesCallback) return; // no listener
-
if (msgObj.uuid === uuid) return; // own message
-
if (!msgObj.token || eMIs.has(msgObj.token)) return; // already emitted
-
if (msgObj.data.time && msgObj.data.time < state.messagesCallbackTime) return; // too old
eMIs.add(msgObj.token);
@@ -1407,20 +1239,16 @@ function create(channelName, options) {
});
return state;
}
-
function close(channelState) {
removeStorageEventListener(channelState.listener);
}
-
function onMessage(channelState, fn, time) {
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
}
-
function canBeUsed() {
var ls = getLocalStorage();
if (!ls) return false;
-
try {
var key = '__broadcastchannel_check';
ls.setItem(key, 'works');
@@ -1431,22 +1259,17 @@ function canBeUsed() {
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API#Private_Browsing_Incognito_modes
return false;
}
-
return true;
}
-
function averageResponseTime() {
var defaultTime = 120;
var userAgent = navigator.userAgent.toLowerCase();
-
if (userAgent.includes('safari') && !userAgent.includes('chrome')) {
// safari is much slower so this time is higher
return defaultTime * 2;
}
-
return defaultTime;
}
-
var _default = {
create: create,
close: close,
@@ -1472,20 +1295,16 @@ exports.microSeconds = exports["default"] = void 0;
exports.onMessage = onMessage;
exports.postMessage = postMessage;
exports.type = void 0;
-
var _util = require("../util.js");
-
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var type = 'native';
exports.type = type;
-
function create(channelName) {
var state = {
messagesCallback: null,
bc: new BroadcastChannel(channelName),
subFns: [] // subscriberFunctions
-
};
state.bc.onmessage = function (msg) {
@@ -1493,15 +1312,12 @@ function create(channelName) {
state.messagesCallback(msg.data);
}
};
-
return state;
}
-
function close(channelState) {
channelState.bc.close();
channelState.subFns = [];
}
-
function postMessage(channelState, messageJson) {
try {
channelState.bc.postMessage(messageJson, false);
@@ -1510,31 +1326,25 @@ function postMessage(channelState, messageJson) {
return Promise.reject(err);
}
}
-
function onMessage(channelState, fn) {
channelState.messagesCallback = fn;
}
-
function canBeUsed() {
if (typeof window === 'undefined') {
return false;
}
-
if (typeof BroadcastChannel === 'function') {
if (BroadcastChannel._pubkey) {
throw new Error('BroadcastChannel: Do not overwrite window.BroadcastChannel with this module, this is not a polyfill');
}
-
return true;
} else {
return false;
}
}
-
function averageResponseTime() {
return 150;
}
-
var _default = {
create: create,
close: close,
@@ -1560,15 +1370,12 @@ exports.microSeconds = exports["default"] = void 0;
exports.onMessage = onMessage;
exports.postMessage = postMessage;
exports.type = void 0;
-
var _util = require("../util.js");
-
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var type = 'simulate';
exports.type = type;
var SIMULATE_CHANNELS = new Set();
-
function create(channelName) {
var state = {
name: channelName,
@@ -1577,11 +1384,9 @@ function create(channelName) {
SIMULATE_CHANNELS.add(state);
return state;
}
-
function close(channelState) {
SIMULATE_CHANNELS["delete"](channelState);
}
-
function postMessage(channelState, messageJson) {
return new Promise(function (res) {
return setTimeout(function () {
@@ -1599,19 +1404,15 @@ function postMessage(channelState, messageJson) {
}, 5);
});
}
-
function onMessage(channelState, fn) {
channelState.messagesCallback = fn;
}
-
function canBeUsed() {
return true;
}
-
function averageResponseTime() {
return 5;
}
-
var _default = {
create: create,
close: close,
@@ -1630,33 +1431,35 @@ Object.defineProperty(exports, "__esModule", {
value: true
});
exports.fillOptionsWithDefaults = fillOptionsWithDefaults;
-
function fillOptionsWithDefaults() {
var originalOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- var options = JSON.parse(JSON.stringify(originalOptions)); // main
+ var options = JSON.parse(JSON.stringify(originalOptions));
- if (typeof options.webWorkerSupport === 'undefined') options.webWorkerSupport = true; // indexed-db
-
- if (!options.idb) options.idb = {}; // after this time the messages get deleted
+ // main
+ if (typeof options.webWorkerSupport === 'undefined') options.webWorkerSupport = true;
+ // indexed-db
+ if (!options.idb) options.idb = {};
+ // after this time the messages get deleted
if (!options.idb.ttl) options.idb.ttl = 1000 * 45;
- if (!options.idb.fallbackInterval) options.idb.fallbackInterval = 150; // handles abrupt db onclose events.
-
- if (originalOptions.idb && typeof originalOptions.idb.onclose === 'function') options.idb.onclose = originalOptions.idb.onclose; // localstorage
+ if (!options.idb.fallbackInterval) options.idb.fallbackInterval = 150;
+ // handles abrupt db onclose events.
+ if (originalOptions.idb && typeof originalOptions.idb.onclose === 'function') options.idb.onclose = originalOptions.idb.onclose;
+ // localstorage
if (!options.localstorage) options.localstorage = {};
- if (!options.localstorage.removeTimeout) options.localstorage.removeTimeout = 1000 * 60; // custom methods
+ if (!options.localstorage.removeTimeout) options.localstorage.removeTimeout = 1000 * 60;
- if (originalOptions.methods) options.methods = originalOptions.methods; // node
+ // custom methods
+ if (originalOptions.methods) options.methods = originalOptions.methods;
+ // node
if (!options.node) options.node = {};
if (!options.node.ttl) options.node.ttl = 1000 * 60 * 2; // 2 minutes;
-
/**
* On linux use 'ulimit -Hn' to get the limit of open files.
* On ubuntu this was 4096 for me, so we use half of that as maxParallelWrites default.
*/
-
if (!options.node.maxParallelWrites) options.node.maxParallelWrites = 2048;
if (typeof options.node.useFastPath === 'undefined') options.node.useFastPath = true;
return options;
@@ -1673,7 +1476,6 @@ exports.microSeconds = microSeconds;
exports.randomInt = randomInt;
exports.randomToken = randomToken;
exports.sleep = sleep;
-
/**
* returns true if the given object is a promise
*/
@@ -1684,14 +1486,12 @@ function isPromise(obj) {
return false;
}
}
-
var PROMISE_RESOLVED_FALSE = Promise.resolve(false);
exports.PROMISE_RESOLVED_FALSE = PROMISE_RESOLVED_FALSE;
var PROMISE_RESOLVED_TRUE = Promise.resolve(true);
exports.PROMISE_RESOLVED_TRUE = PROMISE_RESOLVED_TRUE;
var PROMISE_RESOLVED_VOID = Promise.resolve();
exports.PROMISE_RESOLVED_VOID = PROMISE_RESOLVED_VOID;
-
function sleep(time, resolveWith) {
if (!time) time = 0;
return new Promise(function (res) {
@@ -1700,21 +1500,19 @@ function sleep(time, resolveWith) {
}, time);
});
}
-
function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
+
/**
* https://stackoverflow.com/a/8084248
*/
-
-
function randomToken() {
return Math.random().toString(36).substring(2);
}
-
var lastMs = 0;
var additional = 0;
+
/**
* returns the current time in micro-seconds,
* WARNING: This is a pseudo-function
@@ -1722,10 +1520,8 @@ var additional = 0;
* This is enough in browsers, and this function will not be used in nodejs.
* The main reason for this hack is to ensure that BroadcastChannel behaves equal to production when it is used in fast-running unit tests.
*/
-
function microSeconds() {
var ms = new Date().getTime();
-
if (ms === lastMs) {
additional++;
return ms * 1000 + additional;
@@ -1785,7 +1581,6 @@ function _interopRequireDefault(obj) {
"default": obj
};
}
-
module.exports = _interopRequireDefault, module.exports.__esModule = true, module.exports["default"] = module.exports;
},{}],15:[function(require,module,exports){
function _typeof(obj) {
@@ -1797,7 +1592,6 @@ function _typeof(obj) {
return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
}, module.exports.__esModule = true, module.exports["default"] = module.exports), _typeof(obj);
}
-
module.exports = _typeof, module.exports.__esModule = true, module.exports["default"] = module.exports;
},{}],16:[function(require,module,exports){
'use strict';
@@ -11465,6 +11259,7 @@ var runtime = (function (exports) {
var Op = Object.prototype;
var hasOwn = Op.hasOwnProperty;
+ var defineProperty = Object.defineProperty || function (obj, key, desc) { obj[key] = desc.value; };
var undefined; // More compressible than void 0.
var $Symbol = typeof Symbol === "function" ? Symbol : {};
var iteratorSymbol = $Symbol.iterator || "@@iterator";
@@ -11497,7 +11292,7 @@ var runtime = (function (exports) {
// The ._invoke method unifies the implementations of the .next,
// .throw, and .return methods.
- generator._invoke = makeInvokeMethod(innerFn, self, context);
+ defineProperty(generator, "_invoke", { value: makeInvokeMethod(innerFn, self, context) });
return generator;
}
@@ -11558,8 +11353,12 @@ var runtime = (function (exports) {
var Gp = GeneratorFunctionPrototype.prototype =
Generator.prototype = Object.create(IteratorPrototype);
GeneratorFunction.prototype = GeneratorFunctionPrototype;
- define(Gp, "constructor", GeneratorFunctionPrototype);
- define(GeneratorFunctionPrototype, "constructor", GeneratorFunction);
+ defineProperty(Gp, "constructor", { value: GeneratorFunctionPrototype, configurable: true });
+ defineProperty(
+ GeneratorFunctionPrototype,
+ "constructor",
+ { value: GeneratorFunction, configurable: true }
+ );
GeneratorFunction.displayName = define(
GeneratorFunctionPrototype,
toStringTagSymbol,
@@ -11669,7 +11468,7 @@ var runtime = (function (exports) {
// Define the unified helper method that is used to implement .next,
// .throw, and .return (see defineIteratorMethods).
- this._invoke = enqueue;
+ defineProperty(this, "_invoke", { value: enqueue });
}
defineIteratorMethods(AsyncIterator.prototype);
@@ -11907,7 +11706,8 @@ var runtime = (function (exports) {
this.reset(true);
}
- exports.keys = function(object) {
+ exports.keys = function(val) {
+ var object = Object(val);
var keys = [];
for (var key in object) {
keys.push(key);
@@ -12317,49 +12117,45 @@ function getSize() {
"use strict";
/* eslint-disable */
-
/**
* used in the test-docs as web-worker
*/
require('@babel/polyfill');
-
var _require = require('../../'),
- BroadcastChannel = _require.BroadcastChannel;
-
+ BroadcastChannel = _require.BroadcastChannel;
var _require2 = require('async-test-util'),
- randomNumber = _require2.randomNumber,
- randomBoolean = _require2.randomBoolean,
- wait = _require2.wait;
-
-var resolved = Promise.resolve(); // overwrite console.log
+ randomNumber = _require2.randomNumber,
+ randomBoolean = _require2.randomBoolean,
+ wait = _require2.wait;
+var resolved = Promise.resolve();
+// overwrite console.log
try {
- var logBefore = console.log; // console.log = function (str) { logBefore('worker: ' + str); }
-} catch (err) {// does not work in IE11
+ var logBefore = console.log;
+ // console.log = function (str) { logBefore('worker: ' + str); }
+} catch (err) {
+ // does not work in IE11
}
+
/**
* because shitware microsoft-edge sucks, the worker
* when initialisation is done,
* we have to set a interval here.
*/
-
-
setInterval(function () {}, 10 * 1000);
var channel;
self.addEventListener('message', function (e) {
var data = e.data;
-
switch (data.cmd) {
case 'start':
console.log('Worker started');
console.log(JSON.stringify(data.msg));
channel = new BroadcastChannel(data.msg.channelName, {
type: data.msg.methodType
- }); // console.log('Worker channel-uuid: ' + channel._state.uuid);
-
+ });
+ // console.log('Worker channel-uuid: ' + channel._state.uuid);
channel.onmessage = function (msg) {
console.log('recieved message(' + msg.step + ') from ' + msg.from + ': ' + JSON.stringify(msg));
-
if (!msg.answer) {
/**
* Wait a random amount of time to simulate 'normal' usage
@@ -12377,21 +12173,16 @@ self.addEventListener('message', function (e) {
});
}
};
-
self.postMessage('WORKER STARTED: ');
break;
-
case 'stop':
self.postMessage('WORKER STOPPED: ' + data.msg + '. (buttons will no longer work)');
channel.close();
self.close(); // Terminates the worker.
-
break;
-
default:
self.postMessage('Unknown command: ' + data.msg);
}
-
;
}, false);
},{"../../":2,"@babel/polyfill":12,"async-test-util":19}]},{},[352]);
diff --git a/package.json b/package.json
index 16d25509..940e1300 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "broadcast-channel",
- "version": "4.18.0",
+ "version": "4.18.1",
"description": "A BroadcastChannel that works in New Browsers, Old Browsers, WebWorkers and NodeJs",
"exports": {
".": {