Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

broadcast-channel

Package Overview
Dependencies
Maintainers
1
Versions
98
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

broadcast-channel - npm Package Compare versions

Comparing version 2.1.0 to 2.1.1

babel.config.js

1

dist/es/browserify.index.js
var BroadcastChannel = require('./index.es5.js');
var LeaderElection = require('./leader-election/index.es5.js');

@@ -3,0 +4,0 @@

2

dist/es/index.es5.js

@@ -9,5 +9,3 @@ /**

*/
import BroadcastChannel from './index.js';
module.exports = BroadcastChannel;
import { isPromise } from './util.js';
import { chooseMethod } from './method-chooser.js';
import { fillOptionsWithDefaults } from './options.js';
var BroadcastChannel = function BroadcastChannel(name, options) {
this.name = name;
this.options = fillOptionsWithDefaults(options);
this.method = chooseMethod(this.options);
this.name = name;
this.options = fillOptionsWithDefaults(options);
this.method = chooseMethod(this.options); // isListening
this._isListening = false;
this._iL = false;
/**
* _onMessageListener
* setting onmessage twice,
* will overwrite the first listener
*/
/**
* setting onmessage twice,
* will overwrite the first listener
*/
this._onMessageListener = null;
this._onML = null;
/**
* _addEventListeners
*/
this._addEventListeners = {
message: [],
internal: []
};
this._addEL = {
message: [],
internal: []
};
/**
* _beforeClose
* array of promises that will be awaited
* before the channel is closed
*/
/**
* array of promises that will be awaited
* before the channel is closed
*/
this._beforeClose = [];
this._befC = [];
/**
* _preparePromise
*/
this._preparePromise = null;
_prepareChannel(this);
};
this._prepP = null;
// STATICS
_prepareChannel(this);
}; // STATICS

@@ -42,4 +47,5 @@ /**

*/
BroadcastChannel._pubkey = true;
/**

@@ -49,162 +55,171 @@ * clears the tmp-folder if is node

*/
BroadcastChannel.clearNodeFolder = function (options) {
options = fillOptionsWithDefaults(options);
var method = chooseMethod(options);
if (method.type === 'node') {
return method.clearNodeFolder().then(function () {
return true;
});
} else {
return Promise.resolve(false);
}
};
options = fillOptionsWithDefaults(options);
var method = chooseMethod(options);
// PROTOTYPE
if (method.type === 'node') {
return method.clearNodeFolder().then(function () {
return true;
});
} else {
return Promise.resolve(false);
}
}; // PROTOTYPE
BroadcastChannel.prototype = {
_post: function _post(type, msg) {
var _this = this;
postMessage: function postMessage(msg) {
if (this.closed) {
throw new Error('BroadcastChannel.postMessage(): ' + 'Cannot post message after channel has closed');
}
var time = this.method.microSeconds();
var msgObj = {
time: time,
type: type,
data: msg
};
return _post(this, 'message', msg);
},
postInternal: function postInternal(msg) {
return _post(this, 'internal', msg);
},
var awaitPrepare = this._preparePromise ? this._preparePromise : Promise.resolve();
return awaitPrepare.then(function () {
return _this.method.postMessage(_this._state, msgObj);
});
},
postMessage: function postMessage(msg) {
if (this.closed) {
throw new Error('BroadcastChannel.postMessage(): ' + 'Cannot post message after channel has closed');
}
return this._post('message', msg);
},
postInternal: function postInternal(msg) {
return this._post('internal', msg);
},
set onmessage(fn) {
var time = this.method.microSeconds();
var listenObj = {
time: time,
fn: fn
};
set onmessage(fn) {
var time = this.method.microSeconds();
var listenObj = {
time: time,
fn: fn
};
_removeListenerObject(this, 'message', this._onMessageListener);
if (fn && typeof fn === 'function') {
this._onMessageListener = listenObj;
_addListenerObject(this, 'message', listenObj);
} else {
this._onMessageListener = null;
}
},
_removeListenerObject(this, 'message', this._onML);
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._addEventListeners[type].find(function (obj) {
return obj.fn === fn;
});
_removeListenerObject(this, type, obj);
},
close: function close() {
var _this2 = this;
if (fn && typeof fn === 'function') {
this._onML = listenObj;
if (this.closed) return;
this.closed = true;
var awaitPrepare = this._preparePromise ? this._preparePromise : Promise.resolve();
_addListenerObject(this, 'message', listenObj);
} else {
this._onML = null;
}
},
this._onMessageListener = null;
this._addEventListeners.message = [];
addEventListener: function addEventListener(type, fn) {
var time = this.method.microSeconds();
var listenObj = {
time: time,
fn: fn
};
return awaitPrepare.then(function () {
return Promise.all(_this2._beforeClose.map(function (fn) {
return fn();
}));
}).then(function () {
return _this2.method.close(_this2._state);
});
},
_addListenerObject(this, type, listenObj);
},
removeEventListener: function removeEventListener(type, fn) {
var obj = this._addEL[type].find(function (obj) {
return obj.fn === fn;
});
get type() {
return this.method.type;
}
_removeListenerObject(this, type, obj);
},
close: function close() {
var _this = this;
if (this.closed) return;
this.closed = true;
var awaitPrepare = this._prepP ? this._prepP : Promise.resolve();
this._onML = null;
this._addEL.message = [];
return awaitPrepare.then(function () {
return Promise.all(_this._befC.map(function (fn) {
return fn();
}));
}).then(function () {
return _this.method.close(_this._state);
});
},
get type() {
return this.method.type;
}
};
function _post(broadcastChannel, type, msg) {
var time = broadcastChannel.method.microSeconds();
var msgObj = {
time: time,
type: type,
data: msg
};
var awaitPrepare = broadcastChannel._prepP ? broadcastChannel._prepP : Promise.resolve();
return awaitPrepare.then(function () {
return broadcastChannel.method.postMessage(broadcastChannel._state, msgObj);
});
}
function _prepareChannel(channel) {
var maybePromise = channel.method.create(channel.name, channel.options);
if (isPromise(maybePromise)) {
channel._preparePromise = 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));
}*/
channel._state = s;
});
} else {
channel._state = maybePromise;
}
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));
}*/
channel._state = s;
});
} else {
channel._state = maybePromise;
}
}
function _hasMessageListeners(channel) {
if (channel._addEventListeners.message.length > 0) return true;
if (channel._addEventListeners.internal.length > 0) return true;
return false;
if (channel._addEL.message.length > 0) return true;
if (channel._addEL.internal.length > 0) return true;
return false;
}
function _addListenerObject(channel, type, obj) {
channel._addEventListeners[type].push(obj);
_startListening(channel);
channel._addEL[type].push(obj);
_startListening(channel);
}
function _removeListenerObject(channel, type, obj) {
channel._addEventListeners[type] = channel._addEventListeners[type].filter(function (o) {
return o !== obj;
});
_stopListening(channel);
channel._addEL[type] = channel._addEL[type].filter(function (o) {
return o !== obj;
});
_stopListening(channel);
}
function _startListening(channel) {
if (!channel._isListening && _hasMessageListeners(channel)) {
// someone is listening, start subscribing
if (!channel._iL && _hasMessageListeners(channel)) {
// someone is listening, start subscribing
var listenerFn = function listenerFn(msgObj) {
channel._addEL[msgObj.type].forEach(function (obj) {
if (msgObj.time >= obj.time) {
obj.fn(msgObj.data);
}
});
};
var listenerFn = function listenerFn(msgObj) {
channel._addEventListeners[msgObj.type].forEach(function (obj) {
if (msgObj.time >= obj.time) {
obj.fn(msgObj.data);
}
});
};
var time = channel.method.microSeconds();
var time = channel.method.microSeconds();
if (channel._preparePromise) {
channel._preparePromise.then(function () {
channel._isListening = true;
channel.method.onMessage(channel._state, listenerFn, time);
});
} else {
channel._isListening = true;
channel.method.onMessage(channel._state, listenerFn, time);
}
if (channel._prepP) {
channel._prepP.then(function () {
channel._iL = true;
channel.method.onMessage(channel._state, listenerFn, time);
});
} else {
channel._iL = true;
channel.method.onMessage(channel._state, listenerFn, time);
}
}
}
function _stopListening(channel) {
if (channel._isListening && !_hasMessageListeners(channel)) {
// noone is listening, stop subscribing
channel._isListening = false;
var time = channel.method.microSeconds();
channel.method.onMessage(channel._state, null, time);
}
if (channel._iL && !_hasMessageListeners(channel)) {
// noone is listening, stop subscribing
channel._iL = false;
var time = channel.method.microSeconds();
channel.method.onMessage(channel._state, null, time);
}
}
export default BroadcastChannel;

@@ -5,5 +5,3 @@ /**

*/
import LeaderElection from './index.js';
module.exports = LeaderElection;
import { sleep, randomToken } from '../util.js';
import unload from 'unload';
var LeaderElection = function LeaderElection(channel, options) {
this._channel = channel;
this._options = options;
this._channel = channel;
this._options = options;
this.isLeader = false;
this.isDead = false;
this.token = randomToken(10);
this._isApl = false; // _isApplying
this.isLeader = false;
this.isDead = false;
this.token = randomToken(10);
this._reApply = false; // things to clean up
this._isApplying = false;
this._reApply = false;
this._unl = []; // _unloads
// things to clean up
this._unloads = [];
this._listeners = [];
this._intervals = [];
this._lstns = []; // _listeners
this._invs = []; // _intervals
};
LeaderElection.prototype = {
applyOnce: function applyOnce() {
var _this = this;
applyOnce: function applyOnce() {
var _this = this;
if (this.isLeader) return Promise.resolve(false);
if (this.isDead) return Promise.resolve(false);
if (this.isLeader) return Promise.resolve(false);
if (this.isDead) return Promise.resolve(false); // do nothing if already running
// do nothing if already running
if (this._isApplying) {
this._reApply = true;
return Promise.resolve(false);
if (this._isApl) {
this._reApply = true;
return Promise.resolve(false);
}
this._isApl = true;
var stopCriteria = false;
var recieved = [];
var handleMessage = function handleMessage(msg) {
if (msg.context === 'leader' && msg.token != _this.token) {
recieved.push(msg);
if (msg.action === 'apply') {
// other is applying
if (msg.token > _this.token) {
// other has higher token, stop applying
stopCriteria = true;
}
}
this._isApplying = true;
var stopCriteria = false;
var recieved = [];
if (msg.action === 'tell') {
// other is already leader
stopCriteria = true;
}
}
};
var handleMessage = function handleMessage(msg) {
if (msg.context === 'leader' && msg.token != _this.token) {
recieved.push(msg);
this._channel.addEventListener('internal', handleMessage);
if (msg.action === 'apply') {
// other is applying
if (msg.token > _this.token) {
// other has higher token, stop applying
stopCriteria = true;
}
}
var ret = _sendMessage(this, 'apply') // send out that this one is applying
.then(function () {
return sleep(_this._options.responseTime);
}) // let others time to respond
.then(function () {
if (stopCriteria) return Promise.reject(new Error());else return _sendMessage(_this, 'apply');
}).then(function () {
return sleep(_this._options.responseTime);
}) // let others time to respond
.then(function () {
if (stopCriteria) return Promise.reject(new Error());else return _sendMessage(_this);
}).then(function () {
return _beLeader(_this);
}) // no one disagreed -> this one is now leader
.then(function () {
return true;
})["catch"](function () {
return false;
}) // apply not successfull
.then(function (success) {
_this._channel.removeEventListener('internal', handleMessage);
if (msg.action === 'tell') {
// other is already leader
stopCriteria = true;
}
}
};
this._channel.addEventListener('internal', handleMessage);
_this._isApl = false;
var ret = this._sendMessage('apply') // send out that this one is applying
.then(function () {
return sleep(_this._options.responseTime);
}) // let others time to respond
.then(function () {
if (stopCriteria) return Promise.reject(new Error());else return _this._sendMessage('apply');
}).then(function () {
return sleep(_this._options.responseTime);
}) // let others time to respond
.then(function () {
if (stopCriteria) return Promise.reject(new Error());else return _this._sendMessage();
}).then(function () {
return _this._beLeader();
}) // no one disagreed -> this one is now leader
.then(function () {
return true;
})['catch'](function () {
return false;
}) // apply not successfull
.then(function (success) {
_this._channel.removeEventListener('internal', handleMessage);
_this._isApplying = false;
if (!success && _this._reApply) {
_this._reApply = false;
return _this.applyOnce();
} else return success;
});
return ret;
},
_awaitLeadershipOnce: function _awaitLeadershipOnce() {
var _this2 = this;
if (!success && _this._reApply) {
_this._reApply = false;
return _this.applyOnce();
} else return success;
});
if (this.isLeader) return Promise.resolve();
return ret;
},
awaitLeadership: function awaitLeadership() {
if (!this._awaitLeadershipPromise) {
this._awaitLeadershipPromise = _awaitLeadershipOnce(this);
}
return new Promise(function (res) {
var resolved = false;
return this._awaitLeadershipPromise;
},
die: function die() {
var _this2 = this;
var finish = function finish() {
if (resolved) return;
resolved = true;
clearInterval(interval);
_this2._channel.removeEventListener('internal', whenDeathListener);
res(true);
};
if (this.isDead) return;
this.isDead = true;
// try once now
_this2.applyOnce().then(function () {
if (_this2.isLeader) finish();
});
this._lstns.forEach(function (listener) {
return _this2._channel.removeEventListener('internal', listener);
});
// try on fallbackInterval
var interval = setInterval(function () {
_this2.applyOnce().then(function () {
if (_this2.isLeader) finish();
});
}, _this2._options.fallbackInterval);
_this2._intervals.push(interval);
this._invs.forEach(function (interval) {
return clearInterval(interval);
});
// try when other leader dies
var whenDeathListener = function whenDeathListener(msg) {
if (msg.context === 'leader' && msg.action === 'death') {
_this2.applyOnce().then(function () {
if (_this2.isLeader) finish();
});
}
};
_this2._channel.addEventListener('internal', whenDeathListener);
_this2._listeners.push(whenDeathListener);
});
},
awaitLeadership: function awaitLeadership() {
if (!this._awaitLeadershipPromise) {
this._awaitLeadershipPromise = this._awaitLeadershipOnce();
}
return this._awaitLeadershipPromise;
},
die: function die() {
var _this3 = this;
this._unl.forEach(function (uFn) {
uFn.remove();
});
if (this.isDead) return;
this.isDead = true;
return _sendMessage(this, 'death');
}
};
this._listeners.forEach(function (listener) {
return _this3._channel.removeEventListener('internal', listener);
});
this._intervals.forEach(function (interval) {
return clearInterval(interval);
});
this._unloads.forEach(function (uFn) {
uFn.remove();
});
return this._sendMessage('death');
},
function _awaitLeadershipOnce(leaderElector) {
if (leaderElector.isLeader) return Promise.resolve();
return new Promise(function (res) {
var resolved = false;
var finish = function finish() {
if (resolved) return;
resolved = true;
clearInterval(interval);
/**
* sends and internal message over the broadcast-channel
*/
_sendMessage: function _sendMessage(action) {
var msgJson = {
context: 'leader',
action: action,
token: this.token
};
return this._channel.postInternal(msgJson);
},
_beLeader: function _beLeader() {
var _this4 = this;
leaderElector._channel.removeEventListener('internal', whenDeathListener);
this.isLeader = true;
var unloadFn = unload.add(function () {
return _this4.die();
res(true);
}; // try once now
leaderElector.applyOnce().then(function () {
if (leaderElector.isLeader) finish();
}); // try on fallbackInterval
var interval = setInterval(function () {
leaderElector.applyOnce().then(function () {
if (leaderElector.isLeader) finish();
});
}, leaderElector._options.fallbackInterval);
leaderElector._invs.push(interval); // try when other leader dies
var whenDeathListener = function whenDeathListener(msg) {
if (msg.context === 'leader' && msg.action === 'death') {
leaderElector.applyOnce().then(function () {
if (leaderElector.isLeader) finish();
});
this._unloads.push(unloadFn);
}
};
var isLeaderListener = function isLeaderListener(msg) {
if (msg.context === 'leader' && msg.action === 'apply') {
_this4._sendMessage('tell');
}
};
this._channel.addEventListener('internal', isLeaderListener);
this._listeners.push(isLeaderListener);
return this._sendMessage('tell');
leaderElector._channel.addEventListener('internal', whenDeathListener);
leaderElector._lstns.push(whenDeathListener);
});
}
/**
* sends and internal message over the broadcast-channel
*/
function _sendMessage(leaderElector, action) {
var msgJson = {
context: 'leader',
action: action,
token: leaderElector.token
};
return leaderElector._channel.postInternal(msgJson);
}
function _beLeader(leaderElector) {
leaderElector.isLeader = true;
var unloadFn = 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');
}
};
};
leaderElector._channel.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) options = {};
options = JSON.parse(JSON.stringify(options));
if (!options.fallbackInterval) {
options.fallbackInterval = 3000;
}
if (!options.fallbackInterval) {
options.fallbackInterval = 3000;
}
if (!options.responseTime) {
options.responseTime = channel.method.averageResponseTime(channel.options);
}
if (!options.responseTime) {
options.responseTime = channel.method.averageResponseTime(channel.options);
}
return options;
return options;
}
export function create(channel, options) {
if (channel._leaderElector) {
throw new Error('BroadcastChannel already has a leader-elector');
}
if (channel._leaderElector) {
throw new Error('BroadcastChannel already has a leader-elector');
}
options = fillOptionsWithDefaults(options, channel);
var elector = new LeaderElection(channel, options);
channel._beforeClose.push(function () {
return elector.die();
});
options = fillOptionsWithDefaults(options, channel);
var elector = new LeaderElection(channel, options);
channel._leaderElector = elector;
return elector;
channel._befC.push(function () {
return elector.die();
});
channel._leaderElector = elector;
return elector;
}
export default {
create: create
create: create
};
import isNode from 'detect-node';
import NativeMethod from './methods/native.js';
import IndexeDbMethod from './methods/indexed-db.js';
import LocalstorageMethod from './methods/localstorage.js';
import LocalstorageMethod from './methods/localstorage.js'; // order is important
// order is important
var METHODS = [NativeMethod, // fastest
IndexeDbMethod, LocalstorageMethod];
var REQUIRE_FUN = require;
/**

@@ -17,42 +13,43 @@ * The NodeMethod is loaded lazy

*/
if (isNode) {
/**
* we use the non-transpiled code for nodejs
* because it runs faster
*/
var NodeMethod = REQUIRE_FUN('../../src/methods/node.js');
/**
* this will be false for webpackbuilds
* which will shim the node-method with an empty object {}
*/
/**
* we use the non-transpiled code for nodejs
* because it runs faster
*/
var NodeMethod = REQUIRE_FUN('../../src/methods/node.js');
/**
* this will be false for webpackbuilds
* which will shim the node-method with an empty object {}
*/
if (typeof NodeMethod.canBeUsed === 'function') {
METHODS.push(NodeMethod);
}
if (typeof NodeMethod.canBeUsed === 'function') {
METHODS.push(NodeMethod);
}
}
export function chooseMethod(options) {
// directly chosen
if (options.type) {
var ret = METHODS.find(function (m) {
return m.type === options.type;
});
if (!ret) throw new Error('method-type ' + options.type + ' not found');else return ret;
}
// directly chosen
if (options.type) {
var ret = METHODS.find(function (m) {
return m.type === options.type;
});
if (!ret) throw new Error('method-type ' + options.type + ' not found');else return ret;
}
var chooseMethods = METHODS;
if (!options.webWorkerSupport && !isNode) {
// prefer localstorage over idb when no webworker-support needed
chooseMethods = METHODS.filter(function (m) {
return m.type !== 'idb';
});
}
var chooseMethods = METHODS;
var useMethod = chooseMethods.find(function (method) {
return method.canBeUsed();
if (!options.webWorkerSupport && !isNode) {
// prefer localstorage over idb when no webworker-support needed
chooseMethods = METHODS.filter(function (m) {
return m.type !== 'idb';
});
if (!useMethod) throw new Error('No useable methode found:' + JSON.stringify(METHODS.map(function (m) {
return m.type;
})));else return useMethod;
}
var useMethod = chooseMethods.find(function (method) {
return method.canBeUsed();
});
if (!useMethod) throw new Error('No useable methode found:' + JSON.stringify(METHODS.map(function (m) {
return m.type;
})));else return useMethod;
}

@@ -6,52 +6,42 @@ /**

*/
import isNode from 'detect-node';
import { sleep, randomInt, randomToken, microSeconds as micro } from '../util.js';
export var microSeconds = micro;
import ObliviousSet from '../oblivious-set';
import { fillOptionsWithDefaults } from '../options';
var DB_PREFIX = 'pubkey.broadcast-channel-0-';
var OBJECT_STORE_ID = 'messages';
export var type = 'idb';
export function getIdb() {
if (typeof indexedDB !== 'undefined') return indexedDB;
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 (typeof indexedDB !== 'undefined') return indexedDB;
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;
}
export function createDatabase(channelName) {
var IndexedDB = getIdb();
var IndexedDB = getIdb(); // create table
// create table
var dbName = DB_PREFIX + channelName;
var openRequest = IndexedDB.open(dbName, 1);
var dbName = DB_PREFIX + channelName;
var openRequest = IndexedDB.open(dbName, 1);
openRequest.onupgradeneeded = function (ev) {
var db = ev.target.result;
db.createObjectStore(OBJECT_STORE_ID, {
keyPath: 'id',
autoIncrement: true
});
};
var dbPromise = new Promise(function (res, rej) {
openRequest.onerror = function (ev) {
return rej(ev);
};
openRequest.onsuccess = function () {
res(openRequest.result);
};
openRequest.onupgradeneeded = function (ev) {
var db = ev.target.result;
db.createObjectStore(OBJECT_STORE_ID, {
keyPath: 'id',
autoIncrement: true
});
};
return dbPromise;
var dbPromise = new Promise(function (res, rej) {
openRequest.onerror = function (ev) {
return rej(ev);
};
openRequest.onsuccess = function () {
res(openRequest.result);
};
});
return dbPromise;
}
/**

@@ -61,229 +51,219 @@ * writes the new message to the database

*/
export function writeMessage(db, readerUuid, messageJson) {
var time = new Date().getTime();
var writeObject = {
uuid: readerUuid,
time: time,
data: messageJson
var time = new Date().getTime();
var writeObject = {
uuid: readerUuid,
time: time,
data: messageJson
};
var transaction = db.transaction([OBJECT_STORE_ID], 'readwrite');
return new Promise(function (res, rej) {
transaction.oncomplete = function () {
return res();
};
var transaction = db.transaction([OBJECT_STORE_ID], 'readwrite');
transaction.onerror = function (ev) {
return rej(ev);
};
return new Promise(function (res, rej) {
transaction.oncomplete = function () {
return res();
};
transaction.onerror = function (ev) {
return rej(ev);
};
var objectStore = transaction.objectStore(OBJECT_STORE_ID);
objectStore.add(writeObject);
});
var objectStore = transaction.objectStore(OBJECT_STORE_ID);
objectStore.add(writeObject);
});
}
export function getAllMessages(db) {
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID);
var ret = [];
return new Promise(function (res) {
objectStore.openCursor().onsuccess = function (ev) {
var cursor = ev.target.result;
export function getAllMessages(db) {
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID);
var ret = [];
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);
cursor['continue']();
} else {
res(ret);
}
};
});
if (cursor) {
ret.push(cursor.value); //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor["continue"]();
} else {
res(ret);
}
};
});
}
export function getMessagesHigherThen(db, lastCursorId) {
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID);
var ret = [];
var keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity);
return new Promise(function (res) {
objectStore.openCursor(keyRangeValue).onsuccess = function (ev) {
var cursor = ev.target.result;
export function getMessagesHigherThen(db, lastCursorId) {
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID);
var ret = [];
var keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity);
return new Promise(function (res) {
objectStore.openCursor(keyRangeValue).onsuccess = function (ev) {
var cursor = ev.target.result;
if (cursor) {
ret.push(cursor.value);
//alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor['continue']();
} else {
res(ret);
}
};
});
if (cursor) {
ret.push(cursor.value); //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor["continue"]();
} else {
res(ret);
}
};
});
}
export function removeMessageById(db, id) {
var request = db.transaction([OBJECT_STORE_ID], 'readwrite').objectStore(OBJECT_STORE_ID)['delete'](id);
return new Promise(function (res) {
request.onsuccess = function () {
return res();
};
});
var request = db.transaction([OBJECT_STORE_ID], 'readwrite').objectStore(OBJECT_STORE_ID)["delete"](id);
return new Promise(function (res) {
request.onsuccess = function () {
return res();
};
});
}
export function getOldMessages(db, ttl) {
var olderThen = new Date().getTime() - ttl;
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID);
var ret = [];
return new Promise(function (res) {
objectStore.openCursor().onsuccess = function (ev) {
var cursor = ev.target.result;
export function getOldMessages(db, ttl) {
var olderThen = new Date().getTime() - ttl;
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID);
var ret = [];
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);
cursor['continue']();
} else {
// no more old messages,
res(ret);
return;
}
} else {
res(ret);
}
};
});
if (cursor) {
var msgObk = cursor.value;
if (msgObk.time < olderThen) {
ret.push(msgObk); //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor["continue"]();
} else {
// no more old messages,
res(ret);
return;
}
} else {
res(ret);
}
};
});
}
export function cleanOldMessages(db, ttl) {
return getOldMessages(db, ttl).then(function (tooOld) {
return Promise.all(tooOld.map(function (msgObj) {
return removeMessageById(db, msgObj.id);
}));
});
return getOldMessages(db, ttl).then(function (tooOld) {
return Promise.all(tooOld.map(function (msgObj) {
return removeMessageById(db, msgObj.id);
}));
});
}
export function create(channelName, options) {
options = fillOptionsWithDefaults(options);
options = fillOptionsWithDefaults(options);
var uuid = randomToken(10);
return createDatabase(channelName).then(function (db) {
var state = {
closed: false,
lastCursorId: 0,
channelName: channelName,
options: options,
uuid: uuid,
// contains all messages that have been emitted before
emittedMessagesIds: new ObliviousSet(options.idb.ttl * 2),
// ensures we do not read messages in parrallel
writeBlockPromise: Promise.resolve(),
messagesCallback: null,
readQueuePromises: [],
db: db
};
/**
* if service-workers are used,
* we have no 'storage'-event if they post a message,
* therefore we also have to set an interval
*/
var uuid = randomToken(10);
_readLoop(state);
return createDatabase(channelName).then(function (db) {
var state = {
closed: false,
lastCursorId: 0,
channelName: channelName,
options: options,
uuid: uuid,
// contains all messages that have been emitted before
emittedMessagesIds: new ObliviousSet(options.idb.ttl * 2),
// ensures we do not read messages in parrallel
writeBlockPromise: Promise.resolve(),
messagesCallback: null,
readQueuePromises: [],
db: db
};
/**
* 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;
});
return state;
});
}
function _readLoop(state) {
if (state.closed) return;
return readNewMessages(state).then(function () {
return sleep(state.options.idb.fallbackInterval);
}).then(function () {
return _readLoop(state);
});
if (state.closed) return;
return readNewMessages(state).then(function () {
return sleep(state.options.idb.fallbackInterval);
}).then(function () {
return _readLoop(state);
});
}
function _filterMessage(msgObj, state) {
if (msgObj.uuid === state.uuid) return false; // send by own
if (state.emittedMessagesIds.has(msgObj.id)) return false; // already emitted
if (msgObj.data.time < state.messagesCallbackTime) return false; // older then onMessageCallback
return true;
if (msgObj.uuid === state.uuid) return false; // send by own
if (state.emittedMessagesIds.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.resolve(); // if no one is listening, we do not need to scan for new messages
// channel already closed
if (state.closed) return Promise.resolve();
if (!state.messagesCallback) return Promise.resolve();
return getMessagesHigherThen(state.db, state.lastCursorId).then(function (newerMessages) {
var useMessages = newerMessages.map(function (msgObj) {
if (msgObj.id > state.lastCursorId) {
state.lastCursorId = msgObj.id;
}
// if no one is listening, we do not need to scan for new messages
if (!state.messagesCallback) return Promise.resolve();
return msgObj;
}).filter(function (msgObj) {
return _filterMessage(msgObj, state);
}).sort(function (msgObjA, msgObjB) {
return msgObjA.time - msgObjB.time;
}); // sort by time
return getMessagesHigherThen(state.db, state.lastCursorId).then(function (newerMessages) {
var useMessages = newerMessages.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.emittedMessagesIds.add(msgObj.id);
state.messagesCallback(msgObj.data);
}
});
return Promise.resolve();
useMessages.forEach(function (msgObj) {
if (state.messagesCallback) {
state.emittedMessagesIds.add(msgObj.id);
state.messagesCallback(msgObj.data);
}
});
return Promise.resolve();
});
}
export function close(channelState) {
channelState.closed = true;
channelState.db.close();
channelState.closed = true;
channelState.db.close();
}
export function postMessage(channelState, messageJson) {
channelState.writeBlockPromise = channelState.writeBlockPromise.then(function () {
return writeMessage(channelState.db, channelState.uuid, messageJson);
}).then(function () {
if (randomInt(0, 10) === 0) {
/* await (do not await) */cleanOldMessages(channelState.db, channelState.options.idb.ttl);
}
});
return channelState.writeBlockPromise;
channelState.writeBlockPromise = channelState.writeBlockPromise.then(function () {
return writeMessage(channelState.db, channelState.uuid, messageJson);
}).then(function () {
if (randomInt(0, 10) === 0) {
/* await (do not await) */
cleanOldMessages(channelState.db, channelState.options.idb.ttl);
}
});
return channelState.writeBlockPromise;
}
export function onMessage(channelState, fn, time) {
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
readNewMessages(channelState);
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
readNewMessages(channelState);
}
export function canBeUsed() {
if (isNode) return false;
var idb = getIdb();
if (!idb) return false;
return true;
if (isNode) return false;
var idb = getIdb();
if (!idb) return false;
return true;
}
export function averageResponseTime(options) {
return options.idb.fallbackInterval * 2;
return options.idb.fallbackInterval * 2;
}
export default {
create: create,
close: close,
onMessage: onMessage,
postMessage: postMessage,
canBeUsed: canBeUsed,
type: type,
averageResponseTime: averageResponseTime,
microSeconds: microSeconds
create: create,
close: close,
onMessage: onMessage,
postMessage: postMessage,
canBeUsed: canBeUsed,
type: type,
averageResponseTime: averageResponseTime,
microSeconds: microSeconds
};

@@ -8,15 +8,9 @@ /**

*/
import isNode from 'detect-node';
import ObliviousSet from '../oblivious-set';
import { fillOptionsWithDefaults } from '../options';
import { sleep, randomToken, microSeconds as micro } from '../util';
export var microSeconds = micro;
var KEY_PREFIX = 'pubkey.broadcastChannel-';
export var type = 'localstorage';
/**

@@ -26,20 +20,20 @@ * copied from crosstab

*/
export function getLocalStorage() {
var localStorage = void 0;
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
// if cookies are disabled. See
// https://bugzilla.mozilla.org/show_bug.cgi?id=1028153
}
return localStorage;
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
// if cookies are disabled. See
// https://bugzilla.mozilla.org/show_bug.cgi?id=1028153
}
return localStorage;
}
export function storageKey(channelName) {
return KEY_PREFIX + channelName;
return KEY_PREFIX + channelName;
}
/**

@@ -49,108 +43,102 @@ * writes the new message to the storage

*/
export function postMessage(channelState, messageJson) {
return new Promise(function (res) {
sleep().then(function () {
var key = storageKey(channelState.channelName);
var writeObj = {
token: randomToken(10),
time: new Date().getTime(),
data: messageJson,
uuid: channelState.uuid
};
var value = JSON.stringify(writeObj);
localStorage.setItem(key, value);
return new Promise(function (res) {
sleep().then(function () {
var key = storageKey(channelState.channelName);
var writeObj = {
token: randomToken(10),
time: new Date().getTime(),
data: messageJson,
uuid: channelState.uuid
};
var value = JSON.stringify(writeObj);
localStorage.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
*/
/**
* 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;
ev.newValue = value;
window.dispatchEvent(ev);
res();
});
var ev = document.createEvent('Event');
ev.initEvent('storage', true, true);
ev.key = key;
ev.newValue = value;
window.dispatchEvent(ev);
res();
});
});
}
export function addStorageEventListener(channelName, fn) {
var key = storageKey(channelName);
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;
var listener = function listener(ev) {
if (ev.key === key) {
fn(JSON.parse(ev.newValue));
}
};
window.addEventListener('storage', listener);
return listener;
}
export function removeStorageEventListener(listener) {
window.removeEventListener('storage', listener);
window.removeEventListener('storage', listener);
}
export function create(channelName, options) {
options = fillOptionsWithDefaults(options);
if (!canBeUsed()) {
throw new Error('BroadcastChannel: localstorage cannot be used');
}
options = fillOptionsWithDefaults(options);
var startTime = new Date().getTime();
var uuid = randomToken(10);
if (!canBeUsed()) {
throw new Error('BroadcastChannel: localstorage cannot be used');
}
// contains all messages that have been emitted before
var emittedMessagesIds = new ObliviousSet(options.localstorage.removeTimeout);
var startTime = new Date().getTime();
var uuid = randomToken(10); // contains all messages that have been emitted before
var state = {
startTime: startTime,
channelName: channelName,
options: options,
uuid: uuid,
emittedMessagesIds: emittedMessagesIds
};
var emittedMessagesIds = new ObliviousSet(options.localstorage.removeTimeout);
var state = {
startTime: startTime,
channelName: channelName,
options: options,
uuid: uuid,
emittedMessagesIds: emittedMessagesIds
};
state.listener = addStorageEventListener(channelName, function (msgObj) {
if (!state.messagesCallback) return; // no listener
state.listener = addStorageEventListener(channelName, function (msgObj) {
if (!state.messagesCallback) return; // no listener
if (msgObj.uuid === uuid) return; // own message
if (!msgObj.token || emittedMessagesIds.has(msgObj.token)) return; // already emitted
if (msgObj.data.time && msgObj.data.time < state.messagesCallbackTime) return; // too old
if (msgObj.uuid === uuid) return; // own message
emittedMessagesIds.add(msgObj.token);
state.messagesCallback(msgObj.data);
});
if (!msgObj.token || emittedMessagesIds.has(msgObj.token)) return; // already emitted
return state;
if (msgObj.data.time && msgObj.data.time < state.messagesCallbackTime) return; // too old
emittedMessagesIds.add(msgObj.token);
state.messagesCallback(msgObj.data);
});
return state;
}
export function close(channelState) {
removeStorageEventListener(channelState.listener);
removeStorageEventListener(channelState.listener);
}
export function onMessage(channelState, fn, time) {
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
}
export function canBeUsed() {
if (isNode) return false;
var ls = getLocalStorage();
if (!ls) return false;
return true;
if (isNode) return false;
var ls = getLocalStorage();
if (!ls) return false;
return true;
}
export function averageResponseTime() {
return 120;
return 120;
}
export default {
create: create,
close: close,
onMessage: onMessage,
postMessage: postMessage,
canBeUsed: canBeUsed,
type: type,
averageResponseTime: averageResponseTime,
microSeconds: microSeconds
create: create,
close: close,
onMessage: onMessage,
postMessage: postMessage,
canBeUsed: canBeUsed,
type: type,
averageResponseTime: averageResponseTime,
microSeconds: microSeconds
};
import isNode from 'detect-node';
import { randomToken, microSeconds as micro } from '../util';
export var microSeconds = micro;
export var type = 'native';
export function create(channelName, options) {
if (!options) options = {};
var state = {
uuid: randomToken(10),
channelName: channelName,
options: options,
messagesCallback: null,
bc: new BroadcastChannel(channelName),
subscriberFunctions: []
};
if (!options) options = {};
var state = {
uuid: randomToken(10),
channelName: channelName,
options: options,
messagesCallback: null,
bc: new BroadcastChannel(channelName),
subscriberFunctions: []
};
state.bc.onmessage = function (msg) {
if (state.messagesCallback) {
state.messagesCallback(msg.data);
}
};
state.bc.onmessage = function (msg) {
if (state.messagesCallback) {
state.messagesCallback(msg.data);
}
};
return state;
return state;
}
export function close(channelState) {
channelState.bc.close();
channelState.subscriberFunctions = [];
channelState.bc.close();
channelState.subscriberFunctions = [];
}
export function postMessage(channelState, messageJson) {
channelState.bc.postMessage(messageJson, false);
channelState.bc.postMessage(messageJson, false);
}
export function onMessage(channelState, fn, time) {
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
}
export function canBeUsed() {
/**
* in the electron-renderer, isNode will be true even if we are in browser-context
* so we also check if window is undefined
*/
if (isNode && typeof window === 'undefined') return false;
/**
* in the electron-renderer, isNode will be true even if we are in browser-context
* so we also check if window is undefined
*/
if (isNode && 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');
}
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;
return true;
} else return false;
}
export function averageResponseTime() {
return 100;
return 100;
}
export default {
create: create,
close: close,
onMessage: onMessage,
postMessage: postMessage,
canBeUsed: canBeUsed,
type: type,
averageResponseTime: averageResponseTime,
microSeconds: microSeconds
create: create,
close: close,
onMessage: onMessage,
postMessage: postMessage,
canBeUsed: canBeUsed,
type: type,
averageResponseTime: averageResponseTime,
microSeconds: microSeconds
};

@@ -1,743 +0,786 @@

import _regeneratorRuntime from 'babel-runtime/regenerator';
import _asyncToGenerator from 'babel-runtime/helpers/asyncToGenerator';
import _regeneratorRuntime from "@babel/runtime/regenerator";
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
var ensureFoldersExist = function () {
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(channelName, paths) {
return _regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
paths = paths || getPaths(channelName);
/**
* this method is used in nodejs-environments.
* The ipc is handled via sockets and file-writes to the tmp-folder
*/
var util = require('util');
if (!ENSURE_BASE_FOLDER_EXISTS_PROMISE) {
ENSURE_BASE_FOLDER_EXISTS_PROMISE = mkdir(paths.base)['catch'](function () {
return null;
});
}
_context.next = 4;
return ENSURE_BASE_FOLDER_EXISTS_PROMISE;
var fs = require('fs');
case 4:
_context.next = 6;
return mkdir(paths.channelBase)['catch'](function () {
return null;
});
var os = require('os');
case 6:
_context.next = 8;
return Promise.all([mkdir(paths.readers)['catch'](function () {
return null;
}), mkdir(paths.messages)['catch'](function () {
return null;
})]);
var events = require('events');
case 8:
case 'end':
return _context.stop();
}
}
}, _callee, this);
}));
var net = require('net');
return function ensureFoldersExist(_x, _x2) {
return _ref.apply(this, arguments);
};
}();
var path = require('path');
/**
* removes the tmp-folder
* @return {Promise<true>}
*/
var micro = require('nano-time');
var rimraf = require('rimraf');
var clearNodeFolder = function () {
var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
var paths, removePath;
return _regeneratorRuntime.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
paths = getPaths('foobar');
removePath = paths.base;
var sha3_224 = require('js-sha3').sha3_224;
if (!(!removePath || removePath === '' || removePath === '/')) {
_context2.next = 4;
break;
}
var isNode = require('detect-node');
throw new Error('BroadcastChannel.clearNodeFolder(): path is wrong');
var unload = require('unload');
case 4:
ENSURE_BASE_FOLDER_EXISTS_PROMISE = null;
_context2.next = 7;
return removeDir(paths.base);
var fillOptionsWithDefaults = require('../../dist/lib/options.js').fillOptionsWithDefaults;
case 7:
ENSURE_BASE_FOLDER_EXISTS_PROMISE = null;
return _context2.abrupt('return', true);
var ownUtil = require('../../dist/lib/util.js');
case 9:
case 'end':
return _context2.stop();
}
}
}, _callee2, this);
}));
var randomInt = ownUtil.randomInt;
var randomToken = ownUtil.randomToken;
return function clearNodeFolder() {
return _ref2.apply(this, arguments);
};
}();
var ObliviousSet = require('../../dist/lib/oblivious-set')["default"];
/**
* creates the socket-file and subscribes to it
* @return {{emitter: EventEmitter, server: any}}
* windows sucks, so we have handle windows-type of socket-paths
* @link https://gist.github.com/domenic/2790533#gistcomment-331356
*/
var createSocketEventEmitter = function () {
var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3(channelName, readerUuid, paths) {
var pathToSocket, emitter, server;
return _regeneratorRuntime.wrap(function _callee3$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
pathToSocket = socketPath(channelName, readerUuid, paths);
emitter = new events.EventEmitter();
server = net.createServer(function (stream) {
stream.on('end', function () {});
stream.on('data', function (msg) {
emitter.emit('data', msg.toString());
});
});
_context3.next = 5;
return new Promise(function (resolve, reject) {
server.listen(pathToSocket, function (err, res) {
if (err) reject(err);else resolve(res);
});
});
case 5:
return _context3.abrupt('return', {
path: pathToSocket,
emitter: emitter,
server: server
});
case 6:
case 'end':
return _context3.stop();
}
}
}, _callee3, this);
}));
function cleanPipeName(str) {
if (process.platform === 'win32' && !str.startsWith('\\\\.\\pipe\\')) {
str = str.replace(/^\//, '');
str = str.replace(/\//g, '-');
return '\\\\.\\pipe\\' + str;
} else {
return str;
}
}
return function createSocketEventEmitter(_x3, _x4, _x5) {
return _ref3.apply(this, arguments);
};
}();
var mkdir = util.promisify(fs.mkdir);
var writeFile = util.promisify(fs.writeFile);
var readFile = util.promisify(fs.readFile);
var unlink = util.promisify(fs.unlink);
var readdir = util.promisify(fs.readdir);
var removeDir = util.promisify(rimraf);
var OTHER_INSTANCES = {};
var TMP_FOLDER_NAME = 'pubkey.bc';
var TMP_FOLDER_BASE = path.join(os.tmpdir(), TMP_FOLDER_NAME);
var getPathsCache = new Map();
var openClientConnection = function () {
var _ref4 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4(channelName, readerUuid) {
var pathToSocket, client;
return _regeneratorRuntime.wrap(function _callee4$(_context4) {
while (1) {
switch (_context4.prev = _context4.next) {
case 0:
pathToSocket = socketPath(channelName, readerUuid);
client = new net.Socket();
_context4.next = 4;
return new Promise(function (res) {
client.connect(pathToSocket, res);
});
function getPaths(channelName) {
if (!getPathsCache.has(channelName)) {
var channelHash = sha3_224(channelName); // use hash incase of strange characters
case 4:
return _context4.abrupt('return', client);
/**
* because the lenght 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
*/
case 5:
case 'end':
return _context4.stop();
}
}
}, _callee4, this);
}));
return function openClientConnection(_x6, _x7) {
return _ref4.apply(this, arguments);
var channelFolder = 'A' + channelHash.substring(0, 20);
var channelPathBase = path.join(TMP_FOLDER_BASE, channelFolder);
var folderPathReaders = path.join(channelPathBase, 'rdrs');
var folderPathMessages = path.join(channelPathBase, 'messages');
var ret = {
base: TMP_FOLDER_BASE,
channelBase: channelPathBase,
readers: folderPathReaders,
messages: folderPathMessages
};
}();
getPathsCache.set(channelName, ret);
return ret;
}
/**
* writes the new message to the file-system
* so other readers can find it
* @return {Promise}
*/
return getPathsCache.get(channelName);
}
var ENSURE_BASE_FOLDER_EXISTS_PROMISE = null;
function ensureFoldersExist(_x, _x2) {
return _ensureFoldersExist.apply(this, arguments);
}
/**
* returns the uuids of all readers
* @return {string[]}
* removes the tmp-folder
* @return {Promise<true>}
*/
var getReadersUuids = function () {
var _ref5 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee5(channelName, paths) {
var readersPath, files;
return _regeneratorRuntime.wrap(function _callee5$(_context5) {
while (1) {
switch (_context5.prev = _context5.next) {
case 0:
paths = paths || getPaths(channelName);
readersPath = paths.readers;
_context5.next = 4;
return readdir(readersPath);
case 4:
files = _context5.sent;
return _context5.abrupt('return', files.map(function (file) {
return file.split('.');
}).filter(function (split) {
return split[1] === 'json';
}) // do not scan .socket-files
.map(function (split) {
return split[0];
}));
case 6:
case 'end':
return _context5.stop();
}
function _ensureFoldersExist() {
_ensureFoldersExist = _asyncToGenerator(
/*#__PURE__*/
_regeneratorRuntime.mark(function _callee4(channelName, paths) {
return _regeneratorRuntime.wrap(function _callee4$(_context4) {
while (1) {
switch (_context4.prev = _context4.next) {
case 0:
paths = paths || getPaths(channelName);
if (!ENSURE_BASE_FOLDER_EXISTS_PROMISE) {
ENSURE_BASE_FOLDER_EXISTS_PROMISE = mkdir(paths.base)["catch"](function () {
return null;
});
}
}, _callee5, this);
}));
return function getReadersUuids(_x8, _x9) {
return _ref5.apply(this, arguments);
};
}();
_context4.next = 4;
return ENSURE_BASE_FOLDER_EXISTS_PROMISE;
var messagePath = function () {
var _ref6 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee6(channelName, time, token, writerUuid) {
var fileName, msgPath;
return _regeneratorRuntime.wrap(function _callee6$(_context6) {
while (1) {
switch (_context6.prev = _context6.next) {
case 0:
fileName = time + '_' + writerUuid + '_' + token + '.json';
msgPath = path.join(getPaths(channelName).messages, fileName);
return _context6.abrupt('return', msgPath);
case 4:
_context4.next = 6;
return mkdir(paths.channelBase)["catch"](function () {
return null;
});
case 3:
case 'end':
return _context6.stop();
}
}
}, _callee6, this);
}));
case 6:
_context4.next = 8;
return Promise.all([mkdir(paths.readers)["catch"](function () {
return null;
}), mkdir(paths.messages)["catch"](function () {
return null;
})]);
return function messagePath(_x10, _x11, _x12, _x13) {
return _ref6.apply(this, arguments);
};
}();
case 8:
case "end":
return _context4.stop();
}
}
}, _callee4, this);
}));
return _ensureFoldersExist.apply(this, arguments);
}
var getAllMessages = function () {
var _ref7 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee7(channelName, paths) {
var messagesPath, files;
return _regeneratorRuntime.wrap(function _callee7$(_context7) {
while (1) {
switch (_context7.prev = _context7.next) {
case 0:
paths = paths || getPaths(channelName);
messagesPath = paths.messages;
_context7.next = 4;
return readdir(messagesPath);
function clearNodeFolder() {
return _clearNodeFolder.apply(this, arguments);
}
case 4:
files = _context7.sent;
return _context7.abrupt('return', files.map(function (file) {
var fileName = file.split('.')[0];
var split = fileName.split('_');
function _clearNodeFolder() {
_clearNodeFolder = _asyncToGenerator(
/*#__PURE__*/
_regeneratorRuntime.mark(function _callee5() {
var paths, removePath;
return _regeneratorRuntime.wrap(function _callee5$(_context5) {
while (1) {
switch (_context5.prev = _context5.next) {
case 0:
paths = getPaths('foobar');
removePath = paths.base;
return {
path: path.join(messagesPath, file),
time: parseInt(split[0]),
senderUuid: split[1],
token: split[2]
};
}));
case 6:
case 'end':
return _context7.stop();
}
if (!(!removePath || removePath === '' || removePath === '/')) {
_context5.next = 4;
break;
}
}, _callee7, this);
}));
return function getAllMessages(_x14, _x15) {
return _ref7.apply(this, arguments);
};
}();
throw new Error('BroadcastChannel.clearNodeFolder(): path is wrong');
var cleanOldMessages = function () {
var _ref8 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee8(messageObjects, ttl) {
var olderThen;
return _regeneratorRuntime.wrap(function _callee8$(_context8) {
while (1) {
switch (_context8.prev = _context8.next) {
case 0:
olderThen = Date.now() - ttl;
_context8.next = 3;
return Promise.all(messageObjects.filter(function (obj) {
return obj.time / 1000 < olderThen;
}).map(function (obj) {
return unlink(obj.path)['catch'](function () {
return null;
});
}));
case 4:
ENSURE_BASE_FOLDER_EXISTS_PROMISE = null;
_context5.next = 7;
return removeDir(paths.base);
case 3:
case 'end':
return _context8.stop();
}
}
}, _callee8, this);
}));
case 7:
ENSURE_BASE_FOLDER_EXISTS_PROMISE = null;
return _context5.abrupt("return", true);
return function cleanOldMessages(_x16, _x17) {
return _ref8.apply(this, arguments);
};
}();
case 9:
case "end":
return _context5.stop();
}
}
}, _callee5, this);
}));
return _clearNodeFolder.apply(this, arguments);
}
function socketPath(channelName, readerUuid, paths) {
paths = paths || getPaths(channelName);
var socketPath = path.join(paths.readers, readerUuid + '.s');
return cleanPipeName(socketPath);
}
function socketInfoPath(channelName, readerUuid, paths) {
paths = paths || getPaths(channelName);
var socketPath = path.join(paths.readers, readerUuid + '.json');
return socketPath;
}
/**
* creates a new channelState
* @return {Promise<any>}
* 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
*/
var create = function () {
var _ref9 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee9(channelName) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var time, paths, ensureFolderExistsPromise, uuid, state, _ref10, socketEE, infoFilePath;
return _regeneratorRuntime.wrap(function _callee9$(_context9) {
while (1) {
switch (_context9.prev = _context9.next) {
case 0:
options = fillOptionsWithDefaults(options);
time = microSeconds();
paths = getPaths(channelName);
ensureFolderExistsPromise = ensureFoldersExist(channelName, paths);
uuid = randomToken(10);
state = {
time: time,
channelName: channelName,
options: options,
uuid: uuid,
paths: paths,
// contains all messages that have been emitted before
emittedMessagesIds: new ObliviousSet(options.node.ttl * 2),
messagesCallbackTime: null,
messagesCallback: null,
// ensures we do not read messages in parrallel
writeBlockPromise: Promise.resolve(),
otherReaderClients: {},
// ensure if process crashes, everything is cleaned up
removeUnload: unload.add(function () {
return close(state);
}),
closed: false
};
function createSocketInfoFile(channelName, readerUuid, paths) {
var pathToFile = socketInfoPath(channelName, readerUuid, paths);
return writeFile(pathToFile, JSON.stringify({
time: microSeconds()
})).then(function () {
return pathToFile;
});
}
/**
* creates the socket-file and subscribes to it
* @return {{emitter: EventEmitter, server: any}}
*/
if (!OTHER_INSTANCES[channelName]) OTHER_INSTANCES[channelName] = [];
OTHER_INSTANCES[channelName].push(state);
function createSocketEventEmitter(_x3, _x4, _x5) {
return _createSocketEventEmitter.apply(this, arguments);
}
_context9.next = 10;
return ensureFolderExistsPromise;
function _createSocketEventEmitter() {
_createSocketEventEmitter = _asyncToGenerator(
/*#__PURE__*/
_regeneratorRuntime.mark(function _callee6(channelName, readerUuid, paths) {
var pathToSocket, emitter, server;
return _regeneratorRuntime.wrap(function _callee6$(_context6) {
while (1) {
switch (_context6.prev = _context6.next) {
case 0:
pathToSocket = socketPath(channelName, readerUuid, paths);
emitter = new events.EventEmitter();
server = net.createServer(function (stream) {
stream.on('end', function () {});
stream.on('data', function (msg) {
emitter.emit('data', msg.toString());
});
});
_context6.next = 5;
return new Promise(function (resolve, reject) {
server.listen(pathToSocket, function (err, res) {
if (err) reject(err);else resolve(res);
});
});
case 10:
_context9.next = 12;
return Promise.all([createSocketEventEmitter(channelName, uuid, paths), createSocketInfoFile(channelName, uuid, paths), refreshReaderClients(state)]);
case 5:
return _context6.abrupt("return", {
path: pathToSocket,
emitter: emitter,
server: server
});
case 12:
_ref10 = _context9.sent;
socketEE = _ref10[0];
infoFilePath = _ref10[1];
case 6:
case "end":
return _context6.stop();
}
}
}, _callee6, this);
}));
return _createSocketEventEmitter.apply(this, arguments);
}
state.socketEE = socketEE;
state.infoFilePath = infoFilePath;
function openClientConnection(_x6, _x7) {
return _openClientConnection.apply(this, arguments);
}
/**
* writes the new message to the file-system
* so other readers can find it
* @return {Promise}
*/
// 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
var singleOnes = data.split('|');
singleOnes.filter(function (single) {
return single !== '';
}).forEach(function (single) {
try {
var obj = JSON.parse(single);
handleMessagePing(state, obj);
} catch (err) {
throw new Error('could not parse data: ' + single);
}
});
});
function _openClientConnection() {
_openClientConnection = _asyncToGenerator(
/*#__PURE__*/
_regeneratorRuntime.mark(function _callee7(channelName, readerUuid) {
var pathToSocket, client;
return _regeneratorRuntime.wrap(function _callee7$(_context7) {
while (1) {
switch (_context7.prev = _context7.next) {
case 0:
pathToSocket = socketPath(channelName, readerUuid);
client = new net.Socket();
_context7.next = 4;
return new Promise(function (res) {
client.connect(pathToSocket, res);
});
return _context9.abrupt('return', state);
case 4:
return _context7.abrupt("return", client);
case 19:
case 'end':
return _context9.stop();
}
}
}, _callee9, this);
}));
case 5:
case "end":
return _context7.stop();
}
}
}, _callee7, this);
}));
return _openClientConnection.apply(this, arguments);
}
return function create(_x18) {
return _ref9.apply(this, arguments);
function writeMessage(channelName, readerUuid, messageJson, paths) {
paths = paths || getPaths(channelName);
var time = microSeconds();
var writeObject = {
uuid: readerUuid,
time: time,
data: messageJson
};
var token = randomToken(12);
var fileName = time + '_' + readerUuid + '_' + token + '.json';
var msgPath = path.join(paths.messages, fileName);
return writeFile(msgPath, JSON.stringify(writeObject)).then(function () {
return {
time: time,
uuid: readerUuid,
token: token,
path: msgPath
};
}();
});
}
/**
* when the socket pings, so that we now new messages came,
* run this
* returns the uuids of all readers
* @return {string[]}
*/
var handleMessagePing = function () {
var _ref11 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee10(state, msgObj) {
var messages, useMessages;
return _regeneratorRuntime.wrap(function _callee10$(_context10) {
while (1) {
switch (_context10.prev = _context10.next) {
case 0:
if (state.messagesCallback) {
_context10.next = 2;
break;
}
return _context10.abrupt('return');
case 2:
messages = void 0;
function getReadersUuids(_x8, _x9) {
return _getReadersUuids.apply(this, arguments);
}
if (msgObj) {
_context10.next = 9;
break;
}
function _getReadersUuids() {
_getReadersUuids = _asyncToGenerator(
/*#__PURE__*/
_regeneratorRuntime.mark(function _callee8(channelName, paths) {
var readersPath, files;
return _regeneratorRuntime.wrap(function _callee8$(_context8) {
while (1) {
switch (_context8.prev = _context8.next) {
case 0:
paths = paths || getPaths(channelName);
readersPath = paths.readers;
_context8.next = 4;
return readdir(readersPath);
_context10.next = 6;
return getAllMessages(state.channelName, state.paths);
case 4:
files = _context8.sent;
return _context8.abrupt("return", files.map(function (file) {
return file.split('.');
}).filter(function (split) {
return split[1] === 'json';
}) // do not scan .socket-files
.map(function (split) {
return split[0];
}));
case 6:
messages = _context10.sent;
_context10.next = 10;
break;
case 6:
case "end":
return _context8.stop();
}
}
}, _callee8, this);
}));
return _getReadersUuids.apply(this, arguments);
}
case 9:
// get single message
messages = [getSingleMessage(state.channelName, msgObj, state.paths)];
function messagePath(_x10, _x11, _x12, _x13) {
return _messagePath.apply(this, arguments);
}
case 10:
useMessages = messages.filter(function (msgObj) {
return _filterMessage(msgObj, state);
}).sort(function (msgObjA, msgObjB) {
return msgObjA.time - msgObjB.time;
}); // sort by time
function _messagePath() {
_messagePath = _asyncToGenerator(
/*#__PURE__*/
_regeneratorRuntime.mark(function _callee9(channelName, time, token, writerUuid) {
var fileName, msgPath;
return _regeneratorRuntime.wrap(function _callee9$(_context9) {
while (1) {
switch (_context9.prev = _context9.next) {
case 0:
fileName = time + '_' + writerUuid + '_' + token + '.json';
msgPath = path.join(getPaths(channelName).messages, fileName);
return _context9.abrupt("return", msgPath);
case 3:
case "end":
return _context9.stop();
}
}
}, _callee9, this);
}));
return _messagePath.apply(this, arguments);
}
// if no listener or message, so not do anything
function getAllMessages(_x14, _x15) {
return _getAllMessages.apply(this, arguments);
}
if (!(!useMessages.length || !state.messagesCallback)) {
_context10.next = 13;
break;
}
function _getAllMessages() {
_getAllMessages = _asyncToGenerator(
/*#__PURE__*/
_regeneratorRuntime.mark(function _callee10(channelName, paths) {
var messagesPath, files;
return _regeneratorRuntime.wrap(function _callee10$(_context10) {
while (1) {
switch (_context10.prev = _context10.next) {
case 0:
paths = paths || getPaths(channelName);
messagesPath = paths.messages;
_context10.next = 4;
return readdir(messagesPath);
return _context10.abrupt('return');
case 4:
files = _context10.sent;
return _context10.abrupt("return", files.map(function (file) {
var fileName = file.split('.')[0];
var split = fileName.split('_');
return {
path: path.join(messagesPath, file),
time: parseInt(split[0]),
senderUuid: split[1],
token: split[2]
};
}));
case 13:
_context10.next = 15;
return Promise.all(useMessages.map(function (msgObj) {
return readMessage(msgObj).then(function (content) {
return msgObj.content = content;
});
}));
case 6:
case "end":
return _context10.stop();
}
}
}, _callee10, this);
}));
return _getAllMessages.apply(this, arguments);
}
case 15:
function getSingleMessage(channelName, msgObj, paths) {
paths = paths || getPaths(channelName);
return {
path: path.join(paths.messages, msgObj.t + '_' + msgObj.u + '_' + msgObj.to + '.json'),
time: msgObj.t,
senderUuid: msgObj.u,
token: msgObj.to
};
}
useMessages.forEach(function (msgObj) {
state.emittedMessagesIds.add(msgObj.token);
function readMessage(messageObj) {
return readFile(messageObj.path, 'utf8').then(function (content) {
return JSON.parse(content);
});
}
if (state.messagesCallback) {
// emit to subscribers
state.messagesCallback(msgObj.content.data);
}
});
function cleanOldMessages(_x16, _x17) {
return _cleanOldMessages.apply(this, arguments);
}
case 16:
case 'end':
return _context10.stop();
}
}
}, _callee10, this);
}));
function _cleanOldMessages() {
_cleanOldMessages = _asyncToGenerator(
/*#__PURE__*/
_regeneratorRuntime.mark(function _callee11(messageObjects, ttl) {
var olderThen;
return _regeneratorRuntime.wrap(function _callee11$(_context11) {
while (1) {
switch (_context11.prev = _context11.next) {
case 0:
olderThen = Date.now() - ttl;
_context11.next = 3;
return Promise.all(messageObjects.filter(function (obj) {
return obj.time / 1000 < olderThen;
}).map(function (obj) {
return unlink(obj.path)["catch"](function () {
return null;
});
}));
return function handleMessagePing(_x20, _x21) {
return _ref11.apply(this, arguments);
};
}();
case 3:
case "end":
return _context11.stop();
}
}
}, _callee11, this);
}));
return _cleanOldMessages.apply(this, arguments);
}
var type = 'node';
/**
* ensures that the channelState is connected with all other readers
* @return {Promise<void>}
* creates a new channelState
* @return {Promise<any>}
*/
function create(_x18) {
return _create.apply(this, arguments);
}
/**
* this method is used in nodejs-environments.
* The ipc is handled via sockets and file-writes to the tmp-folder
*/
function _create() {
_create = _asyncToGenerator(
/*#__PURE__*/
_regeneratorRuntime.mark(function _callee12(channelName) {
var options,
time,
paths,
ensureFolderExistsPromise,
uuid,
state,
_ref5,
socketEE,
infoFilePath,
_args12 = arguments;
var util = require('util');
var fs = require('fs');
var os = require('os');
var events = require('events');
var net = require('net');
var path = require('path');
var micro = require('nano-time');
var rimraf = require('rimraf');
var sha3_224 = require('js-sha3').sha3_224;
var isNode = require('detect-node');
var unload = require('unload');
return _regeneratorRuntime.wrap(function _callee12$(_context12) {
while (1) {
switch (_context12.prev = _context12.next) {
case 0:
options = _args12.length > 1 && _args12[1] !== undefined ? _args12[1] : {};
options = fillOptionsWithDefaults(options);
time = microSeconds();
paths = getPaths(channelName);
ensureFolderExistsPromise = ensureFoldersExist(channelName, paths);
uuid = randomToken(10);
state = {
time: time,
channelName: channelName,
options: options,
uuid: uuid,
paths: paths,
// contains all messages that have been emitted before
emittedMessagesIds: new ObliviousSet(options.node.ttl * 2),
messagesCallbackTime: null,
messagesCallback: null,
// ensures we do not read messages in parrallel
writeBlockPromise: Promise.resolve(),
otherReaderClients: {},
// ensure if process crashes, everything is cleaned up
removeUnload: unload.add(function () {
return close(state);
}),
closed: false
};
if (!OTHER_INSTANCES[channelName]) OTHER_INSTANCES[channelName] = [];
OTHER_INSTANCES[channelName].push(state);
_context12.next = 11;
return ensureFolderExistsPromise;
var fillOptionsWithDefaults = require('../../dist/lib/options.js').fillOptionsWithDefaults;
var ownUtil = require('../../dist/lib/util.js');
var randomInt = ownUtil.randomInt;
var randomToken = ownUtil.randomToken;
var ObliviousSet = require('../../dist/lib/oblivious-set')['default'];
case 11:
_context12.next = 13;
return Promise.all([createSocketEventEmitter(channelName, uuid, paths), createSocketInfoFile(channelName, uuid, paths), refreshReaderClients(state)]);
/**
* windows sucks, so we have handle windows-type of socket-paths
* @link https://gist.github.com/domenic/2790533#gistcomment-331356
*/
function cleanPipeName(str) {
if (process.platform === 'win32' && !str.startsWith('\\\\.\\pipe\\')) {
str = str.replace(/^\//, '');
str = str.replace(/\//g, '-');
return '\\\\.\\pipe\\' + str;
} else {
return str;
}
}
case 13:
_ref5 = _context12.sent;
socketEE = _ref5[0];
infoFilePath = _ref5[1];
state.socketEE = socketEE;
state.infoFilePath = infoFilePath; // when new message comes in, we read it and emit it
var mkdir = util.promisify(fs.mkdir);
var writeFile = util.promisify(fs.writeFile);
var readFile = util.promisify(fs.readFile);
var unlink = util.promisify(fs.unlink);
var readdir = util.promisify(fs.readdir);
var removeDir = util.promisify(rimraf);
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
var singleOnes = data.split('|');
singleOnes.filter(function (single) {
return single !== '';
}).forEach(function (single) {
try {
var obj = JSON.parse(single);
handleMessagePing(state, obj);
} catch (err) {
throw new Error('could not parse data: ' + single);
}
});
});
return _context12.abrupt("return", state);
var OTHER_INSTANCES = {};
var TMP_FOLDER_NAME = 'pubkey.bc';
var TMP_FOLDER_BASE = path.join(os.tmpdir(), TMP_FOLDER_NAME);
var getPathsCache = new Map();
case 20:
case "end":
return _context12.stop();
}
}
}, _callee12, this);
}));
return _create.apply(this, arguments);
}
function getPaths(channelName) {
if (!getPathsCache.has(channelName)) {
var channelHash = sha3_224(channelName); // use hash incase of strange characters
/**
* because the lenght 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);
function _filterMessage(msgObj, state) {
if (msgObj.senderUuid === state.uuid) return false; // not send by own
var channelPathBase = path.join(TMP_FOLDER_BASE, channelFolder);
var folderPathReaders = path.join(channelPathBase, 'rdrs');
var folderPathMessages = path.join(channelPathBase, 'messages');
if (state.emittedMessagesIds.has(msgObj.token)) return false; // not already emitted
var ret = {
base: TMP_FOLDER_BASE,
channelBase: channelPathBase,
readers: folderPathReaders,
messages: folderPathMessages
};
getPathsCache.set(channelName, ret);
return ret;
}
return getPathsCache.get(channelName);
}
if (!state.messagesCallback) return false; // no listener
var ENSURE_BASE_FOLDER_EXISTS_PROMISE = null;
if (msgObj.time < state.messagesCallbackTime) return false; // not older then onMessageCallback
if (msgObj.time < state.time) return false; // msgObj is older then channel
function socketPath(channelName, readerUuid, paths) {
paths = paths || getPaths(channelName);
var socketPath = path.join(paths.readers, readerUuid + '.s');
return cleanPipeName(socketPath);
state.emittedMessagesIds.add(msgObj.token);
return true;
}
/**
* when the socket pings, so that we now new messages came,
* run this
*/
function socketInfoPath(channelName, readerUuid, paths) {
paths = paths || getPaths(channelName);
var socketPath = path.join(paths.readers, readerUuid + '.json');
return socketPath;
function handleMessagePing(_x19, _x20) {
return _handleMessagePing.apply(this, arguments);
}
/**
* 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
* ensures that the channelState is connected with all other readers
* @return {Promise<void>}
*/
function createSocketInfoFile(channelName, readerUuid, paths) {
var pathToFile = socketInfoPath(channelName, readerUuid, paths);
return writeFile(pathToFile, JSON.stringify({
time: microSeconds()
})).then(function () {
return pathToFile;
});
}function writeMessage(channelName, readerUuid, messageJson, paths) {
paths = paths || getPaths(channelName);
var time = microSeconds();
var writeObject = {
uuid: readerUuid,
time: time,
data: messageJson
};
var token = randomToken(12);
var fileName = time + '_' + readerUuid + '_' + token + '.json';
var msgPath = path.join(paths.messages, fileName);
function _handleMessagePing() {
_handleMessagePing = _asyncToGenerator(
/*#__PURE__*/
_regeneratorRuntime.mark(function _callee13(state, msgObj) {
var messages, useMessages;
return _regeneratorRuntime.wrap(function _callee13$(_context13) {
while (1) {
switch (_context13.prev = _context13.next) {
case 0:
if (state.messagesCallback) {
_context13.next = 2;
break;
}
return writeFile(msgPath, JSON.stringify(writeObject)).then(function () {
return {
time: time,
uuid: readerUuid,
token: token,
path: msgPath
};
});
}
return _context13.abrupt("return");
function getSingleMessage(channelName, msgObj, paths) {
paths = paths || getPaths(channelName);
case 2:
if (msgObj) {
_context13.next = 8;
break;
}
return {
path: path.join(paths.messages, msgObj.t + '_' + msgObj.u + '_' + msgObj.to + '.json'),
time: msgObj.t,
senderUuid: msgObj.u,
token: msgObj.to
};
}
_context13.next = 5;
return getAllMessages(state.channelName, state.paths);
function readMessage(messageObj) {
return readFile(messageObj.path, 'utf8').then(function (content) {
return JSON.parse(content);
});
}
case 5:
messages = _context13.sent;
_context13.next = 9;
break;
var type = 'node';
case 8:
// get single message
messages = [getSingleMessage(state.channelName, msgObj, state.paths)];
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
case 9:
useMessages = messages.filter(function (msgObj) {
return _filterMessage(msgObj, state);
}).sort(function (msgObjA, msgObjB) {
return msgObjA.time - msgObjB.time;
}); // sort by time
// if no listener or message, so not do anything
state.emittedMessagesIds.add(msgObj.token);
return true;
}function refreshReaderClients(channelState) {
var _this = this;
if (!(!useMessages.length || !state.messagesCallback)) {
_context13.next = 12;
break;
}
return getReadersUuids(channelState.channelName, channelState.paths).then(function (otherReaders) {
// remove subscriptions to closed readers
Object.keys(channelState.otherReaderClients).filter(function (readerUuid) {
return !otherReaders.includes(readerUuid);
}).forEach(function () {
var _ref12 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee11(readerUuid) {
return _regeneratorRuntime.wrap(function _callee11$(_context11) {
while (1) {
switch (_context11.prev = _context11.next) {
case 0:
_context11.prev = 0;
_context11.next = 3;
return channelState.otherReaderClients[readerUuid].destroy();
return _context13.abrupt("return");
case 3:
_context11.next = 7;
break;
case 12:
_context13.next = 14;
return Promise.all(useMessages.map(function (msgObj) {
return readMessage(msgObj).then(function (content) {
return msgObj.content = content;
});
}));
case 5:
_context11.prev = 5;
_context11.t0 = _context11['catch'](0);
case 14:
useMessages.forEach(function (msgObj) {
state.emittedMessagesIds.add(msgObj.token);
case 7:
delete channelState.otherReaderClients[readerUuid];
if (state.messagesCallback) {
// emit to subscribers
state.messagesCallback(msgObj.content.data);
}
});
case 8:
case 'end':
return _context11.stop();
}
}
}, _callee11, _this, [[0, 5]]);
}));
case 15:
case "end":
return _context13.stop();
}
}
}, _callee13, this);
}));
return _handleMessagePing.apply(this, arguments);
}
return function (_x22) {
return _ref12.apply(this, arguments);
};
}());
function refreshReaderClients(channelState) {
return getReadersUuids(channelState.channelName, channelState.paths).then(function (otherReaders) {
// remove subscriptions to closed readers
Object.keys(channelState.otherReaderClients).filter(function (readerUuid) {
return !otherReaders.includes(readerUuid);
}).forEach(
/*#__PURE__*/
function () {
var _ref = _asyncToGenerator(
/*#__PURE__*/
_regeneratorRuntime.mark(function _callee(readerUuid) {
return _regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_context.prev = 0;
_context.next = 3;
return channelState.otherReaderClients[readerUuid].destroy();
// add new readers
return Promise.all(otherReaders.filter(function (readerUuid) {
return readerUuid !== channelState.uuid;
}) // not own
.filter(function (readerUuid) {
return !channelState.otherReaderClients[readerUuid];
}) // not already has client
.map(function () {
var _ref13 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee12(readerUuid) {
var client;
return _regeneratorRuntime.wrap(function _callee12$(_context12) {
while (1) {
switch (_context12.prev = _context12.next) {
case 0:
_context12.prev = 0;
case 3:
_context.next = 7;
break;
if (!channelState.closed) {
_context12.next = 3;
break;
}
case 5:
_context.prev = 5;
_context.t0 = _context["catch"](0);
return _context12.abrupt('return');
case 7:
delete channelState.otherReaderClients[readerUuid];
case 3:
_context12.next = 5;
return openClientConnection(channelState.channelName, readerUuid);
case 8:
case "end":
return _context.stop();
}
}
}, _callee, this, [[0, 5]]);
}));
case 5:
client = _context12.sent;
return function (_x21) {
return _ref.apply(this, arguments);
};
}()); // add new readers
channelState.otherReaderClients[readerUuid] = client;
_context12.next = 11;
break;
return Promise.all(otherReaders.filter(function (readerUuid) {
return readerUuid !== channelState.uuid;
}) // not own
.filter(function (readerUuid) {
return !channelState.otherReaderClients[readerUuid];
}) // not already has client
.map(
/*#__PURE__*/
function () {
var _ref2 = _asyncToGenerator(
/*#__PURE__*/
_regeneratorRuntime.mark(function _callee2(readerUuid) {
var client;
return _regeneratorRuntime.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
_context2.prev = 0;
case 9:
_context12.prev = 9;
_context12.t0 = _context12['catch'](0);
if (!channelState.closed) {
_context2.next = 3;
break;
}
case 11:
case 'end':
return _context12.stop();
}
}
}, _callee12, _this, [[0, 9]]);
}));
return _context2.abrupt("return");
return function (_x23) {
return _ref13.apply(this, arguments);
};
}()
// this might throw if the other channel is closed at the same time when this one is running refresh
// so we do not throw an error
));
});
case 3:
_context2.next = 5;
return openClientConnection(channelState.channelName, readerUuid);
case 5:
client = _context2.sent;
channelState.otherReaderClients[readerUuid] = client;
_context2.next = 11;
break;
case 9:
_context2.prev = 9;
_context2.t0 = _context2["catch"](0);
case 11:
case "end":
return _context2.stop();
}
}
}, _callee2, this, [[0, 9]]);
}));
return function (_x22) {
return _ref2.apply(this, arguments);
};
}()));
});
}
/**

@@ -747,63 +790,63 @@ * post a message to the other readers

*/
function postMessage(channelState, messageJson) {
var _this2 = this;
var writePromise = writeMessage(channelState.channelName, channelState.uuid, messageJson, channelState.paths);
channelState.writeBlockPromise = channelState.writeBlockPromise.then(_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee13() {
var _ref15, msgObj, pingStr, writeToReadersPromise;
return _regeneratorRuntime.wrap(function _callee13$(_context13) {
while (1) {
switch (_context13.prev = _context13.next) {
case 0:
_context13.next = 2;
return new Promise(function (res) {
return setTimeout(res, 0);
});
function postMessage(channelState, messageJson) {
var writePromise = writeMessage(channelState.channelName, channelState.uuid, messageJson, channelState.paths);
channelState.writeBlockPromise = channelState.writeBlockPromise.then(
/*#__PURE__*/
_asyncToGenerator(
/*#__PURE__*/
_regeneratorRuntime.mark(function _callee3() {
var _ref4, msgObj, pingStr, writeToReadersPromise;
case 2:
_context13.next = 4;
return Promise.all([writePromise, refreshReaderClients(channelState)]);
return _regeneratorRuntime.wrap(function _callee3$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
_context3.next = 2;
return new Promise(function (res) {
return setTimeout(res, 0);
});
case 4:
_ref15 = _context13.sent;
msgObj = _ref15[0];
case 2:
_context3.next = 4;
return Promise.all([writePromise, refreshReaderClients(channelState)]);
emitOverFastPath(channelState, msgObj, messageJson);
pingStr = '{"t":' + msgObj.time + ',"u":"' + msgObj.uuid + '","to":"' + msgObj.token + '"}|';
writeToReadersPromise = Promise.all(Object.values(channelState.otherReaderClients).filter(function (client) {
return client.writable;
}) // client might have closed in between
.map(function (client) {
return new Promise(function (res) {
client.write(pingStr, res);
});
}));
case 4:
_ref4 = _context3.sent;
msgObj = _ref4[0];
emitOverFastPath(channelState, msgObj, messageJson);
pingStr = '{"t":' + msgObj.time + ',"u":"' + msgObj.uuid + '","to":"' + msgObj.token + '"}|';
writeToReadersPromise = Promise.all(Object.values(channelState.otherReaderClients).filter(function (client) {
return client.writable;
}) // client might have closed in between
.map(function (client) {
return new Promise(function (res) {
client.write(pingStr, res);
});
}));
/**
* clean up old messages
* to not waste resources on cleaning up,
* only if random-int matches, we clean up old messages
*/
/**
* clean up old messages
* 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);
});
}
if (randomInt(0, 20) === 0) {
/* await */
getAllMessages(channelState.channelName, channelState.paths).then(function (allMessages) {
return cleanOldMessages(allMessages, channelState.options.node.ttl);
});
}
return _context3.abrupt("return", writeToReadersPromise);
return _context13.abrupt('return', writeToReadersPromise);
case 11:
case 'end':
return _context13.stop();
}
}
}, _callee13, _this2);
})));
return channelState.writeBlockPromise;
case 11:
case "end":
return _context3.stop();
}
}
}, _callee3, this);
})));
return channelState.writeBlockPromise;
}
/**

@@ -815,101 +858,99 @@ * When multiple BroadcastChannels with the same name

*/
function emitOverFastPath(state, msgObj, messageJson) {
if (!state.options.node.useFastPath) return; // disabled
var others = OTHER_INSTANCES[state.channelName].filter(function (s) {
return s !== state;
});
if (!state.options.node.useFastPath) return; // disabled
var checkObj = {
time: msgObj.time,
senderUuid: msgObj.uuid,
token: msgObj.token
};
others.filter(function (otherState) {
return _filterMessage(checkObj, otherState);
}).forEach(function (otherState) {
otherState.messagesCallback(messageJson);
});
var others = OTHER_INSTANCES[state.channelName].filter(function (s) {
return s !== state;
});
var checkObj = {
time: msgObj.time,
senderUuid: msgObj.uuid,
token: msgObj.token
};
others.filter(function (otherState) {
return _filterMessage(checkObj, otherState);
}).forEach(function (otherState) {
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);
var time = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : microSeconds();
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
handleMessagePing(channelState);
}
function close(channelState) {
if (channelState.closed) return;
channelState.closed = true;
channelState.emittedMessagesIds.clear();
OTHER_INSTANCES[channelState.channelName] = OTHER_INSTANCES[channelState.channelName].filter(function (o) {
return o !== channelState;
});
if (channelState.closed) return;
channelState.closed = true;
channelState.emittedMessagesIds.clear();
OTHER_INSTANCES[channelState.channelName] = OTHER_INSTANCES[channelState.channelName].filter(function (o) {
return o !== channelState;
});
if (channelState.removeUnload) {
channelState.removeUnload.remove();
}
if (channelState.removeUnload) {
channelState.removeUnload.remove();
}
/**
* the server get closed lazy because others might still write on it
* and have not found out that the infoFile was deleted
*/
/**
* the server get closed lazy because others might still write on it
* and have not found out that the infoFile was deleted
*/
setTimeout(function () {
return channelState.socketEE.server.close();
}, 200);
channelState.socketEE.emitter.removeAllListeners();
Object.values(channelState.otherReaderClients).forEach(function (client) {
return client.destroy();
});
unlink(channelState.infoFilePath)['catch'](function () {
return null;
});
setTimeout(function () {
return channelState.socketEE.server.close();
}, 200);
channelState.socketEE.emitter.removeAllListeners();
Object.values(channelState.otherReaderClients).forEach(function (client) {
return client.destroy();
});
unlink(channelState.infoFilePath)["catch"](function () {
return null;
});
}
function canBeUsed() {
return isNode;
return isNode;
}
function averageResponseTime() {
return 50;
return 50;
}
function microSeconds() {
return parseInt(micro.microseconds());
return parseInt(micro.microseconds());
}
module.exports = {
cleanPipeName: cleanPipeName,
getPaths: getPaths,
ensureFoldersExist: ensureFoldersExist,
clearNodeFolder: clearNodeFolder,
socketPath: socketPath,
socketInfoPath: socketInfoPath,
createSocketInfoFile: createSocketInfoFile,
createSocketEventEmitter: createSocketEventEmitter,
openClientConnection: openClientConnection,
writeMessage: writeMessage,
getReadersUuids: getReadersUuids,
messagePath: messagePath,
getAllMessages: getAllMessages,
getSingleMessage: getSingleMessage,
readMessage: readMessage,
cleanOldMessages: cleanOldMessages,
type: type,
create: create,
_filterMessage: _filterMessage,
handleMessagePing: handleMessagePing,
refreshReaderClients: refreshReaderClients,
postMessage: postMessage,
emitOverFastPath: emitOverFastPath,
onMessage: onMessage,
close: close,
canBeUsed: canBeUsed,
averageResponseTime: averageResponseTime,
microSeconds: microSeconds
cleanPipeName: cleanPipeName,
getPaths: getPaths,
ensureFoldersExist: ensureFoldersExist,
clearNodeFolder: clearNodeFolder,
socketPath: socketPath,
socketInfoPath: socketInfoPath,
createSocketInfoFile: createSocketInfoFile,
createSocketEventEmitter: createSocketEventEmitter,
openClientConnection: openClientConnection,
writeMessage: writeMessage,
getReadersUuids: getReadersUuids,
messagePath: messagePath,
getAllMessages: getAllMessages,
getSingleMessage: getSingleMessage,
readMessage: readMessage,
cleanOldMessages: cleanOldMessages,
type: type,
create: create,
_filterMessage: _filterMessage,
handleMessagePing: handleMessagePing,
refreshReaderClients: refreshReaderClients,
postMessage: postMessage,
emitOverFastPath: emitOverFastPath,
onMessage: onMessage,
close: close,
canBeUsed: canBeUsed,
averageResponseTime: averageResponseTime,
microSeconds: microSeconds
};

@@ -5,44 +5,45 @@ /**

*/
var ObliviousSet = function ObliviousSet(ttl) {
this.ttl = ttl;
this.set = new Set();
this.timeMap = new Map();
this.has = this.set.has.bind(this.set);
this.ttl = ttl;
this.set = new Set();
this.timeMap = new Map();
this.has = this.set.has.bind(this.set);
};
ObliviousSet.prototype = {
_removeTooOldValues: function _removeTooOldValues() {
var olderThen = now() - this.ttl;
var iterator = this.set[Symbol.iterator]();
_removeTooOldValues: function _removeTooOldValues() {
var olderThen = now() - this.ttl;
var iterator = this.set[Symbol.iterator]();
while (true) {
var value = iterator.next().value;
if (!value) return; // no more elements
var time = this.timeMap.get(value);
if (time < olderThen) {
this.timeMap["delete"](value);
this.set["delete"](value);
} else {
// we reached a value that is not old enough
return;
}
}
},
add: function add(value) {
this.timeMap.set(value, now());
this.set.add(value);
this._removeTooOldValues();
},
clear: function clear() {
this.set.clear();
this.timeMap.clear();
while (true) {
var value = iterator.next().value;
if (!value) return; // no more elements
var time = this.timeMap.get(value);
if (time < olderThen) {
this.timeMap["delete"](value);
this.set["delete"](value);
} else {
// we reached a value that is not old enough
return;
}
}
},
add: function add(value) {
this.timeMap.set(value, now());
this.set.add(value);
this._removeTooOldValues();
},
clear: function clear() {
this.set.clear();
this.timeMap.clear();
}
};
function now() {
return new Date().getTime();
return new Date().getTime();
}
export default ObliviousSet;
export function fillOptionsWithDefaults(options) {
if (!options) options = {};
options = JSON.parse(JSON.stringify(options));
if (!options) options = {};
options = JSON.parse(JSON.stringify(options)); // main
// main
if (typeof options.webWorkerSupport === 'undefined') options.webWorkerSupport = true;
if (typeof options.webWorkerSupport === 'undefined') options.webWorkerSupport = true; // indexed-db
// 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;
if (!options.idb) options.idb = {}; // after this time the messages get deleted
// localstorage
if (!options.localstorage) options.localstorage = {};
if (!options.localstorage.removeTimeout) options.localstorage.removeTimeout = 1000 * 60;
if (!options.idb.ttl) options.idb.ttl = 1000 * 45;
if (!options.idb.fallbackInterval) options.idb.fallbackInterval = 150; // localstorage
// node
if (!options.node) options.node = {};
if (!options.node.ttl) options.node.ttl = 1000 * 60 * 2; // 2 minutes;
if (typeof options.node.useFastPath === 'undefined') options.node.useFastPath = true;
if (!options.localstorage) options.localstorage = {};
if (!options.localstorage.removeTimeout) options.localstorage.removeTimeout = 1000 * 60; // node
return options;
if (!options.node) options.node = {};
if (!options.node.ttl) options.node.ttl = 1000 * 60 * 2; // 2 minutes;
if (typeof options.node.useFastPath === 'undefined') options.node.useFastPath = true;
return options;
}

@@ -5,36 +5,34 @@ /**

export function isPromise(obj) {
if (obj && typeof obj.then === 'function') {
return true;
} else {
return false;
}
if (obj && typeof obj.then === 'function') {
return true;
} else {
return false;
}
}
export function sleep(time) {
if (!time) time = 0;
return new Promise(function (res) {
return setTimeout(res, time);
});
if (!time) time = 0;
return new Promise(function (res) {
return setTimeout(res, time);
});
}
export function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
return Math.floor(Math.random() * (max - min + 1) + min);
}
/**
* https://stackoverflow.com/a/1349426/3443137
*/
export function randomToken(length) {
if (!length) length = 5;
var text = '';
var possible = 'abcdefghijklmnopqrstuvwxzy0123456789';
if (!length) length = 5;
var text = '';
var possible = 'abcdefghijklmnopqrstuvwxzy0123456789';
for (var i = 0; i < length; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}return text;
for (var i = 0; i < length; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}
var lastMs = 0;
var additional = 0;
/**

@@ -47,12 +45,14 @@ * returns the current time in micro-seconds,

*/
export function microSeconds() {
var ms = new Date().getTime();
if (ms === lastMs) {
additional++;
return ms * 1000 + additional;
} else {
lastMs = ms;
additional = 0;
return ms * 1000;
}
var ms = new Date().getTime();
if (ms === lastMs) {
additional++;
return ms * 1000 + additional;
} else {
lastMs = ms;
additional = 0;
return ms * 1000;
}
}

@@ -1,4 +0,5 @@

'use strict';
"use strict";
var BroadcastChannel = require('./index.es5.js');
var LeaderElection = require('./leader-election/index.es5.js');

@@ -5,0 +6,0 @@

@@ -1,16 +0,15 @@

'use strict';
"use strict";
var _index = require('./index.js');
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _index2 = _interopRequireDefault(_index);
var _index = _interopRequireDefault(require("./index.js"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
module.exports = _index2['default']; /**
* because babel can only export on default-attribute,
* we use this for the non-module-build
* this ensures that users do not have to use
* var BroadcastChannel = require('broadcast-channel').default;
* but
* var BroadcastChannel = require('broadcast-channel');
*/
/**
* because babel can only export on default-attribute,
* we use this for the non-module-build
* this ensures that users do not have to use
* var BroadcastChannel = require('broadcast-channel').default;
* but
* var BroadcastChannel = require('broadcast-channel');
*/
module.exports = _index["default"];

@@ -1,42 +0,50 @@

'use strict';
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
value: true
});
exports["default"] = void 0;
var _util = require('./util.js');
var _util = require("./util.js");
var _methodChooser = require('./method-chooser.js');
var _methodChooser = require("./method-chooser.js");
var _options = require('./options.js');
var _options = require("./options.js");
var BroadcastChannel = function BroadcastChannel(name, options) {
this.name = name;
this.options = (0, _options.fillOptionsWithDefaults)(options);
this.method = (0, _methodChooser.chooseMethod)(this.options);
this.name = name;
this.options = (0, _options.fillOptionsWithDefaults)(options);
this.method = (0, _methodChooser.chooseMethod)(this.options); // isListening
this._isListening = false;
this._iL = false;
/**
* _onMessageListener
* setting onmessage twice,
* will overwrite the first listener
*/
/**
* setting onmessage twice,
* will overwrite the first listener
*/
this._onMessageListener = null;
this._onML = null;
/**
* _addEventListeners
*/
this._addEventListeners = {
message: [],
internal: []
};
this._addEL = {
message: [],
internal: []
};
/**
* _beforeClose
* array of promises that will be awaited
* before the channel is closed
*/
/**
* array of promises that will be awaited
* before the channel is closed
*/
this._beforeClose = [];
this._befC = [];
/**
* _preparePromise
*/
this._preparePromise = null;
_prepareChannel(this);
};
this._prepP = null;
// STATICS
_prepareChannel(this);
}; // STATICS

@@ -48,4 +56,5 @@ /**

*/
BroadcastChannel._pubkey = true;
/**

@@ -55,162 +64,172 @@ * clears the tmp-folder if is node

*/
BroadcastChannel.clearNodeFolder = function (options) {
options = (0, _options.fillOptionsWithDefaults)(options);
var method = (0, _methodChooser.chooseMethod)(options);
if (method.type === 'node') {
return method.clearNodeFolder().then(function () {
return true;
});
} else {
return Promise.resolve(false);
}
};
options = (0, _options.fillOptionsWithDefaults)(options);
var method = (0, _methodChooser.chooseMethod)(options);
// PROTOTYPE
if (method.type === 'node') {
return method.clearNodeFolder().then(function () {
return true;
});
} else {
return Promise.resolve(false);
}
}; // PROTOTYPE
BroadcastChannel.prototype = {
_post: function _post(type, msg) {
var _this = this;
postMessage: function postMessage(msg) {
if (this.closed) {
throw new Error('BroadcastChannel.postMessage(): ' + 'Cannot post message after channel has closed');
}
var time = this.method.microSeconds();
var msgObj = {
time: time,
type: type,
data: msg
};
return _post(this, 'message', msg);
},
postInternal: function postInternal(msg) {
return _post(this, 'internal', msg);
},
var awaitPrepare = this._preparePromise ? this._preparePromise : Promise.resolve();
return awaitPrepare.then(function () {
return _this.method.postMessage(_this._state, msgObj);
});
},
postMessage: function postMessage(msg) {
if (this.closed) {
throw new Error('BroadcastChannel.postMessage(): ' + 'Cannot post message after channel has closed');
}
return this._post('message', msg);
},
postInternal: function postInternal(msg) {
return this._post('internal', msg);
},
set onmessage(fn) {
var time = this.method.microSeconds();
var listenObj = {
time: time,
fn: fn
};
set onmessage(fn) {
var time = this.method.microSeconds();
var listenObj = {
time: time,
fn: fn
};
_removeListenerObject(this, 'message', this._onMessageListener);
if (fn && typeof fn === 'function') {
this._onMessageListener = listenObj;
_addListenerObject(this, 'message', listenObj);
} else {
this._onMessageListener = null;
}
},
_removeListenerObject(this, 'message', this._onML);
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._addEventListeners[type].find(function (obj) {
return obj.fn === fn;
});
_removeListenerObject(this, type, obj);
},
close: function close() {
var _this2 = this;
if (fn && typeof fn === 'function') {
this._onML = listenObj;
if (this.closed) return;
this.closed = true;
var awaitPrepare = this._preparePromise ? this._preparePromise : Promise.resolve();
_addListenerObject(this, 'message', listenObj);
} else {
this._onML = null;
}
},
this._onMessageListener = null;
this._addEventListeners.message = [];
addEventListener: function addEventListener(type, fn) {
var time = this.method.microSeconds();
var listenObj = {
time: time,
fn: fn
};
return awaitPrepare.then(function () {
return Promise.all(_this2._beforeClose.map(function (fn) {
return fn();
}));
}).then(function () {
return _this2.method.close(_this2._state);
});
},
_addListenerObject(this, type, listenObj);
},
removeEventListener: function removeEventListener(type, fn) {
var obj = this._addEL[type].find(function (obj) {
return obj.fn === fn;
});
get type() {
return this.method.type;
}
_removeListenerObject(this, type, obj);
},
close: function close() {
var _this = this;
if (this.closed) return;
this.closed = true;
var awaitPrepare = this._prepP ? this._prepP : Promise.resolve();
this._onML = null;
this._addEL.message = [];
return awaitPrepare.then(function () {
return Promise.all(_this._befC.map(function (fn) {
return fn();
}));
}).then(function () {
return _this.method.close(_this._state);
});
},
get type() {
return this.method.type;
}
};
function _post(broadcastChannel, type, msg) {
var time = broadcastChannel.method.microSeconds();
var msgObj = {
time: time,
type: type,
data: msg
};
var awaitPrepare = broadcastChannel._prepP ? broadcastChannel._prepP : Promise.resolve();
return awaitPrepare.then(function () {
return broadcastChannel.method.postMessage(broadcastChannel._state, msgObj);
});
}
function _prepareChannel(channel) {
var maybePromise = channel.method.create(channel.name, channel.options);
if ((0, _util.isPromise)(maybePromise)) {
channel._preparePromise = 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));
}*/
channel._state = s;
});
} else {
channel._state = maybePromise;
}
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));
}*/
channel._state = s;
});
} else {
channel._state = maybePromise;
}
}
function _hasMessageListeners(channel) {
if (channel._addEventListeners.message.length > 0) return true;
if (channel._addEventListeners.internal.length > 0) return true;
return false;
if (channel._addEL.message.length > 0) return true;
if (channel._addEL.internal.length > 0) return true;
return false;
}
function _addListenerObject(channel, type, obj) {
channel._addEventListeners[type].push(obj);
_startListening(channel);
channel._addEL[type].push(obj);
_startListening(channel);
}
function _removeListenerObject(channel, type, obj) {
channel._addEventListeners[type] = channel._addEventListeners[type].filter(function (o) {
return o !== obj;
});
_stopListening(channel);
channel._addEL[type] = channel._addEL[type].filter(function (o) {
return o !== obj;
});
_stopListening(channel);
}
function _startListening(channel) {
if (!channel._isListening && _hasMessageListeners(channel)) {
// someone is listening, start subscribing
if (!channel._iL && _hasMessageListeners(channel)) {
// someone is listening, start subscribing
var listenerFn = function listenerFn(msgObj) {
channel._addEL[msgObj.type].forEach(function (obj) {
if (msgObj.time >= obj.time) {
obj.fn(msgObj.data);
}
});
};
var listenerFn = function listenerFn(msgObj) {
channel._addEventListeners[msgObj.type].forEach(function (obj) {
if (msgObj.time >= obj.time) {
obj.fn(msgObj.data);
}
});
};
var time = channel.method.microSeconds();
var time = channel.method.microSeconds();
if (channel._preparePromise) {
channel._preparePromise.then(function () {
channel._isListening = true;
channel.method.onMessage(channel._state, listenerFn, time);
});
} else {
channel._isListening = true;
channel.method.onMessage(channel._state, listenerFn, time);
}
if (channel._prepP) {
channel._prepP.then(function () {
channel._iL = true;
channel.method.onMessage(channel._state, listenerFn, time);
});
} else {
channel._iL = true;
channel.method.onMessage(channel._state, listenerFn, time);
}
}
}
function _stopListening(channel) {
if (channel._isListening && !_hasMessageListeners(channel)) {
// noone is listening, stop subscribing
channel._isListening = false;
var time = channel.method.microSeconds();
channel.method.onMessage(channel._state, null, time);
}
if (channel._iL && !_hasMessageListeners(channel)) {
// noone is listening, stop subscribing
channel._iL = false;
var time = channel.method.microSeconds();
channel.method.onMessage(channel._state, null, time);
}
}
exports['default'] = BroadcastChannel;
var _default = BroadcastChannel;
exports["default"] = _default;

@@ -1,12 +0,11 @@

'use strict';
"use strict";
var _index = require('./index.js');
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _index2 = _interopRequireDefault(_index);
var _index = _interopRequireDefault(require("./index.js"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
module.exports = _index2['default']; /**
* because babel can only export on default-attribute,
* we use this for the non-module-build
*/
/**
* because babel can only export on default-attribute,
* we use this for the non-module-build
*/
module.exports = _index["default"];

@@ -1,228 +0,242 @@

'use strict';
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
value: true
});
exports.create = create;
exports["default"] = void 0;
var _util = require('../util.js');
var _util = require("../util.js");
var _unload = require('unload');
var _unload = _interopRequireDefault(require("unload"));
var _unload2 = _interopRequireDefault(_unload);
var LeaderElection = function LeaderElection(channel, options) {
this._channel = channel;
this._options = options;
this.isLeader = false;
this.isDead = false;
this.token = (0, _util.randomToken)(10);
this._isApl = false; // _isApplying
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
this._reApply = false; // things to clean up
var LeaderElection = function LeaderElection(channel, options) {
this._channel = channel;
this._options = options;
this._unl = []; // _unloads
this.isLeader = false;
this.isDead = false;
this.token = (0, _util.randomToken)(10);
this._lstns = []; // _listeners
this._isApplying = false;
this._reApply = false;
// things to clean up
this._unloads = [];
this._listeners = [];
this._intervals = [];
this._invs = []; // _intervals
};
LeaderElection.prototype = {
applyOnce: function applyOnce() {
var _this = this;
applyOnce: function applyOnce() {
var _this = this;
if (this.isLeader) return Promise.resolve(false);
if (this.isDead) return Promise.resolve(false);
if (this.isLeader) return Promise.resolve(false);
if (this.isDead) return Promise.resolve(false); // do nothing if already running
// do nothing if already running
if (this._isApplying) {
this._reApply = true;
return Promise.resolve(false);
if (this._isApl) {
this._reApply = true;
return Promise.resolve(false);
}
this._isApl = true;
var stopCriteria = false;
var recieved = [];
var handleMessage = function handleMessage(msg) {
if (msg.context === 'leader' && msg.token != _this.token) {
recieved.push(msg);
if (msg.action === 'apply') {
// other is applying
if (msg.token > _this.token) {
// other has higher token, stop applying
stopCriteria = true;
}
}
this._isApplying = true;
var stopCriteria = false;
var recieved = [];
if (msg.action === 'tell') {
// other is already leader
stopCriteria = true;
}
}
};
var handleMessage = function handleMessage(msg) {
if (msg.context === 'leader' && msg.token != _this.token) {
recieved.push(msg);
this._channel.addEventListener('internal', handleMessage);
if (msg.action === 'apply') {
// other is applying
if (msg.token > _this.token) {
// other has higher token, stop applying
stopCriteria = true;
}
}
var ret = _sendMessage(this, 'apply') // send out that this one is applying
.then(function () {
return (0, _util.sleep)(_this._options.responseTime);
}) // let others time to respond
.then(function () {
if (stopCriteria) return Promise.reject(new Error());else return _sendMessage(_this, 'apply');
}).then(function () {
return (0, _util.sleep)(_this._options.responseTime);
}) // let others time to respond
.then(function () {
if (stopCriteria) return Promise.reject(new Error());else return _sendMessage(_this);
}).then(function () {
return _beLeader(_this);
}) // no one disagreed -> this one is now leader
.then(function () {
return true;
})["catch"](function () {
return false;
}) // apply not successfull
.then(function (success) {
_this._channel.removeEventListener('internal', handleMessage);
if (msg.action === 'tell') {
// other is already leader
stopCriteria = true;
}
}
};
this._channel.addEventListener('internal', handleMessage);
_this._isApl = false;
var ret = this._sendMessage('apply') // send out that this one is applying
.then(function () {
return (0, _util.sleep)(_this._options.responseTime);
}) // let others time to respond
.then(function () {
if (stopCriteria) return Promise.reject(new Error());else return _this._sendMessage('apply');
}).then(function () {
return (0, _util.sleep)(_this._options.responseTime);
}) // let others time to respond
.then(function () {
if (stopCriteria) return Promise.reject(new Error());else return _this._sendMessage();
}).then(function () {
return _this._beLeader();
}) // no one disagreed -> this one is now leader
.then(function () {
return true;
})['catch'](function () {
return false;
}) // apply not successfull
.then(function (success) {
_this._channel.removeEventListener('internal', handleMessage);
_this._isApplying = false;
if (!success && _this._reApply) {
_this._reApply = false;
return _this.applyOnce();
} else return success;
});
return ret;
},
_awaitLeadershipOnce: function _awaitLeadershipOnce() {
var _this2 = this;
if (!success && _this._reApply) {
_this._reApply = false;
return _this.applyOnce();
} else return success;
});
if (this.isLeader) return Promise.resolve();
return ret;
},
awaitLeadership: function awaitLeadership() {
if (!this._awaitLeadershipPromise) {
this._awaitLeadershipPromise = _awaitLeadershipOnce(this);
}
return new Promise(function (res) {
var resolved = false;
return this._awaitLeadershipPromise;
},
die: function die() {
var _this2 = this;
var finish = function finish() {
if (resolved) return;
resolved = true;
clearInterval(interval);
_this2._channel.removeEventListener('internal', whenDeathListener);
res(true);
};
if (this.isDead) return;
this.isDead = true;
// try once now
_this2.applyOnce().then(function () {
if (_this2.isLeader) finish();
});
this._lstns.forEach(function (listener) {
return _this2._channel.removeEventListener('internal', listener);
});
// try on fallbackInterval
var interval = setInterval(function () {
_this2.applyOnce().then(function () {
if (_this2.isLeader) finish();
});
}, _this2._options.fallbackInterval);
_this2._intervals.push(interval);
this._invs.forEach(function (interval) {
return clearInterval(interval);
});
// try when other leader dies
var whenDeathListener = function whenDeathListener(msg) {
if (msg.context === 'leader' && msg.action === 'death') {
_this2.applyOnce().then(function () {
if (_this2.isLeader) finish();
});
}
};
_this2._channel.addEventListener('internal', whenDeathListener);
_this2._listeners.push(whenDeathListener);
});
},
awaitLeadership: function awaitLeadership() {
if (!this._awaitLeadershipPromise) {
this._awaitLeadershipPromise = this._awaitLeadershipOnce();
}
return this._awaitLeadershipPromise;
},
die: function die() {
var _this3 = this;
this._unl.forEach(function (uFn) {
uFn.remove();
});
if (this.isDead) return;
this.isDead = true;
return _sendMessage(this, 'death');
}
};
this._listeners.forEach(function (listener) {
return _this3._channel.removeEventListener('internal', listener);
});
this._intervals.forEach(function (interval) {
return clearInterval(interval);
});
this._unloads.forEach(function (uFn) {
uFn.remove();
});
return this._sendMessage('death');
},
function _awaitLeadershipOnce(leaderElector) {
if (leaderElector.isLeader) return Promise.resolve();
return new Promise(function (res) {
var resolved = false;
var finish = function finish() {
if (resolved) return;
resolved = true;
clearInterval(interval);
/**
* sends and internal message over the broadcast-channel
*/
_sendMessage: function _sendMessage(action) {
var msgJson = {
context: 'leader',
action: action,
token: this.token
};
return this._channel.postInternal(msgJson);
},
_beLeader: function _beLeader() {
var _this4 = this;
leaderElector._channel.removeEventListener('internal', whenDeathListener);
this.isLeader = true;
var unloadFn = _unload2['default'].add(function () {
return _this4.die();
res(true);
}; // try once now
leaderElector.applyOnce().then(function () {
if (leaderElector.isLeader) finish();
}); // try on fallbackInterval
var interval = setInterval(function () {
leaderElector.applyOnce().then(function () {
if (leaderElector.isLeader) finish();
});
}, leaderElector._options.fallbackInterval);
leaderElector._invs.push(interval); // try when other leader dies
var whenDeathListener = function whenDeathListener(msg) {
if (msg.context === 'leader' && msg.action === 'death') {
leaderElector.applyOnce().then(function () {
if (leaderElector.isLeader) finish();
});
this._unloads.push(unloadFn);
}
};
var isLeaderListener = function isLeaderListener(msg) {
if (msg.context === 'leader' && msg.action === 'apply') {
_this4._sendMessage('tell');
}
};
this._channel.addEventListener('internal', isLeaderListener);
this._listeners.push(isLeaderListener);
return this._sendMessage('tell');
leaderElector._channel.addEventListener('internal', whenDeathListener);
leaderElector._lstns.push(whenDeathListener);
});
}
/**
* sends and internal message over the broadcast-channel
*/
function _sendMessage(leaderElector, action) {
var msgJson = {
context: 'leader',
action: action,
token: leaderElector.token
};
return leaderElector._channel.postInternal(msgJson);
}
function _beLeader(leaderElector) {
leaderElector.isLeader = true;
var unloadFn = _unload["default"].add(function () {
return leaderElector.die();
});
leaderElector._unl.push(unloadFn);
var isLeaderListener = function isLeaderListener(msg) {
if (msg.context === 'leader' && msg.action === 'apply') {
_sendMessage(leaderElector, 'tell');
}
};
};
leaderElector._channel.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) options = {};
options = JSON.parse(JSON.stringify(options));
if (!options.fallbackInterval) {
options.fallbackInterval = 3000;
}
if (!options.fallbackInterval) {
options.fallbackInterval = 3000;
}
if (!options.responseTime) {
options.responseTime = channel.method.averageResponseTime(channel.options);
}
if (!options.responseTime) {
options.responseTime = channel.method.averageResponseTime(channel.options);
}
return options;
return options;
}
function create(channel, options) {
if (channel._leaderElector) {
throw new Error('BroadcastChannel already has a leader-elector');
}
if (channel._leaderElector) {
throw new Error('BroadcastChannel already has a leader-elector');
}
options = fillOptionsWithDefaults(options, channel);
var elector = new LeaderElection(channel, options);
channel._beforeClose.push(function () {
return elector.die();
});
options = fillOptionsWithDefaults(options, channel);
var elector = new LeaderElection(channel, options);
channel._leaderElector = elector;
return elector;
channel._befC.push(function () {
return elector.die();
});
channel._leaderElector = elector;
return elector;
}
exports['default'] = {
create: create
};
var _default = {
create: create
};
exports["default"] = _default;

@@ -1,32 +0,22 @@

'use strict';
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
value: true
});
exports.chooseMethod = chooseMethod;
var _detectNode = require('detect-node');
var _detectNode = _interopRequireDefault(require("detect-node"));
var _detectNode2 = _interopRequireDefault(_detectNode);
var _native = _interopRequireDefault(require("./methods/native.js"));
var _native = require('./methods/native.js');
var _indexedDb = _interopRequireDefault(require("./methods/indexed-db.js"));
var _native2 = _interopRequireDefault(_native);
var _localstorage = _interopRequireDefault(require("./methods/localstorage.js"));
var _indexedDb = require('./methods/indexed-db.js');
var _indexedDb2 = _interopRequireDefault(_indexedDb);
var _localstorage = require('./methods/localstorage.js');
var _localstorage2 = _interopRequireDefault(_localstorage);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
// order is important
var METHODS = [_native2['default'], // fastest
_indexedDb2['default'], _localstorage2['default']];
var METHODS = [_native["default"], // fastest
_indexedDb["default"], _localstorage["default"]];
var REQUIRE_FUN = require;
/**

@@ -36,42 +26,43 @@ * The NodeMethod is loaded lazy

*/
if (_detectNode2['default']) {
/**
* we use the non-transpiled code for nodejs
* because it runs faster
*/
var NodeMethod = REQUIRE_FUN('../../src/methods/node.js');
if (_detectNode["default"]) {
/**
* we use the non-transpiled code for nodejs
* because it runs faster
*/
var NodeMethod = REQUIRE_FUN('../../src/methods/node.js');
/**
* this will be false for webpackbuilds
* which will shim the node-method with an empty object {}
*/
/**
* this will be false for webpackbuilds
* which will shim the node-method with an empty object {}
*/
if (typeof NodeMethod.canBeUsed === 'function') {
METHODS.push(NodeMethod);
}
if (typeof NodeMethod.canBeUsed === 'function') {
METHODS.push(NodeMethod);
}
}
function chooseMethod(options) {
// directly chosen
if (options.type) {
var ret = METHODS.find(function (m) {
return m.type === options.type;
});
if (!ret) throw new Error('method-type ' + options.type + ' not found');else return ret;
}
// directly chosen
if (options.type) {
var ret = METHODS.find(function (m) {
return m.type === options.type;
});
if (!ret) throw new Error('method-type ' + options.type + ' not found');else return ret;
}
var chooseMethods = METHODS;
if (!options.webWorkerSupport && !_detectNode2['default']) {
// prefer localstorage over idb when no webworker-support needed
chooseMethods = METHODS.filter(function (m) {
return m.type !== 'idb';
});
}
var chooseMethods = METHODS;
var useMethod = chooseMethods.find(function (method) {
return method.canBeUsed();
if (!options.webWorkerSupport && !_detectNode["default"]) {
// prefer localstorage over idb when no webworker-support needed
chooseMethods = METHODS.filter(function (m) {
return m.type !== 'idb';
});
if (!useMethod) throw new Error('No useable methode found:' + JSON.stringify(METHODS.map(function (m) {
return m.type;
})));else return useMethod;
}
var useMethod = chooseMethods.find(function (method) {
return method.canBeUsed();
});
if (!useMethod) throw new Error('No useable methode found:' + JSON.stringify(METHODS.map(function (m) {
return m.type;
})));else return useMethod;
}

@@ -1,7 +0,8 @@

'use strict';
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
value: true
});
exports.type = exports.microSeconds = undefined;
exports.getIdb = getIdb;

@@ -21,17 +22,12 @@ exports.createDatabase = createDatabase;

exports.averageResponseTime = averageResponseTime;
exports["default"] = exports.type = exports.microSeconds = void 0;
var _detectNode = require('detect-node');
var _detectNode = _interopRequireDefault(require("detect-node"));
var _detectNode2 = _interopRequireDefault(_detectNode);
var _util = require("../util.js");
var _util = require('../util.js');
var _obliviousSet = _interopRequireDefault(require("../oblivious-set"));
var _obliviousSet = require('../oblivious-set');
var _options = require("../options");
var _obliviousSet2 = _interopRequireDefault(_obliviousSet);
var _options = require('../options');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
/**

@@ -42,46 +38,42 @@ * this method uses indexeddb to store the messages

*/
var microSeconds = exports.microSeconds = _util.microSeconds;
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var DB_PREFIX = 'pubkey.broadcast-channel-0-';
var OBJECT_STORE_ID = 'messages';
var type = 'idb';
exports.type = type;
var type = exports.type = 'idb';
function getIdb() {
if (typeof indexedDB !== 'undefined') return indexedDB;
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 (typeof indexedDB !== 'undefined') return indexedDB;
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;
}
function createDatabase(channelName) {
var IndexedDB = getIdb();
var IndexedDB = getIdb(); // create table
// create table
var dbName = DB_PREFIX + channelName;
var openRequest = IndexedDB.open(dbName, 1);
var dbName = DB_PREFIX + channelName;
var openRequest = IndexedDB.open(dbName, 1);
openRequest.onupgradeneeded = function (ev) {
var db = ev.target.result;
db.createObjectStore(OBJECT_STORE_ID, {
keyPath: 'id',
autoIncrement: true
});
};
var dbPromise = new Promise(function (res, rej) {
openRequest.onerror = function (ev) {
return rej(ev);
};
openRequest.onsuccess = function () {
res(openRequest.result);
};
openRequest.onupgradeneeded = function (ev) {
var db = ev.target.result;
db.createObjectStore(OBJECT_STORE_ID, {
keyPath: 'id',
autoIncrement: true
});
};
return dbPromise;
var dbPromise = new Promise(function (res, rej) {
openRequest.onerror = function (ev) {
return rej(ev);
};
openRequest.onsuccess = function () {
res(openRequest.result);
};
});
return dbPromise;
}
/**

@@ -91,229 +83,232 @@ * writes the new message to the database

*/
function writeMessage(db, readerUuid, messageJson) {
var time = new Date().getTime();
var writeObject = {
uuid: readerUuid,
time: time,
data: messageJson
var time = new Date().getTime();
var writeObject = {
uuid: readerUuid,
time: time,
data: messageJson
};
var transaction = db.transaction([OBJECT_STORE_ID], 'readwrite');
return new Promise(function (res, rej) {
transaction.oncomplete = function () {
return res();
};
var transaction = db.transaction([OBJECT_STORE_ID], 'readwrite');
transaction.onerror = function (ev) {
return rej(ev);
};
return new Promise(function (res, rej) {
transaction.oncomplete = function () {
return res();
};
transaction.onerror = function (ev) {
return rej(ev);
};
var objectStore = transaction.objectStore(OBJECT_STORE_ID);
objectStore.add(writeObject);
});
var objectStore = transaction.objectStore(OBJECT_STORE_ID);
objectStore.add(writeObject);
});
}
function getAllMessages(db) {
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID);
var ret = [];
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);
cursor['continue']();
} else {
res(ret);
}
};
});
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID);
var ret = [];
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);
cursor["continue"]();
} else {
res(ret);
}
};
});
}
function getMessagesHigherThen(db, lastCursorId) {
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID);
var ret = [];
var keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity);
return new Promise(function (res) {
objectStore.openCursor(keyRangeValue).onsuccess = function (ev) {
var cursor = ev.target.result;
if (cursor) {
ret.push(cursor.value);
//alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor['continue']();
} else {
res(ret);
}
};
});
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID);
var ret = [];
var keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity);
return new Promise(function (res) {
objectStore.openCursor(keyRangeValue).onsuccess = function (ev) {
var cursor = ev.target.result;
if (cursor) {
ret.push(cursor.value); //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor["continue"]();
} else {
res(ret);
}
};
});
}
function removeMessageById(db, id) {
var request = db.transaction([OBJECT_STORE_ID], 'readwrite').objectStore(OBJECT_STORE_ID)['delete'](id);
return new Promise(function (res) {
request.onsuccess = function () {
return res();
};
});
var request = db.transaction([OBJECT_STORE_ID], 'readwrite').objectStore(OBJECT_STORE_ID)["delete"](id);
return new Promise(function (res) {
request.onsuccess = function () {
return res();
};
});
}
function getOldMessages(db, ttl) {
var olderThen = new Date().getTime() - ttl;
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID);
var ret = [];
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);
cursor['continue']();
} else {
// no more old messages,
res(ret);
return;
}
} else {
res(ret);
}
};
});
var olderThen = new Date().getTime() - ttl;
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID);
var ret = [];
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);
cursor["continue"]();
} else {
// no more old messages,
res(ret);
return;
}
} else {
res(ret);
}
};
});
}
function cleanOldMessages(db, ttl) {
return getOldMessages(db, ttl).then(function (tooOld) {
return Promise.all(tooOld.map(function (msgObj) {
return removeMessageById(db, msgObj.id);
}));
});
return getOldMessages(db, ttl).then(function (tooOld) {
return Promise.all(tooOld.map(function (msgObj) {
return removeMessageById(db, msgObj.id);
}));
});
}
function create(channelName, options) {
options = (0, _options.fillOptionsWithDefaults)(options);
options = (0, _options.fillOptionsWithDefaults)(options);
var uuid = (0, _util.randomToken)(10);
return createDatabase(channelName).then(function (db) {
var state = {
closed: false,
lastCursorId: 0,
channelName: channelName,
options: options,
uuid: uuid,
// contains all messages that have been emitted before
emittedMessagesIds: new _obliviousSet["default"](options.idb.ttl * 2),
// ensures we do not read messages in parrallel
writeBlockPromise: Promise.resolve(),
messagesCallback: null,
readQueuePromises: [],
db: db
};
/**
* if service-workers are used,
* we have no 'storage'-event if they post a message,
* therefore we also have to set an interval
*/
var uuid = (0, _util.randomToken)(10);
_readLoop(state);
return createDatabase(channelName).then(function (db) {
var state = {
closed: false,
lastCursorId: 0,
channelName: channelName,
options: options,
uuid: uuid,
// contains all messages that have been emitted before
emittedMessagesIds: new _obliviousSet2['default'](options.idb.ttl * 2),
// ensures we do not read messages in parrallel
writeBlockPromise: Promise.resolve(),
messagesCallback: null,
readQueuePromises: [],
db: db
};
/**
* 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;
});
return state;
});
}
function _readLoop(state) {
if (state.closed) return;
return readNewMessages(state).then(function () {
return (0, _util.sleep)(state.options.idb.fallbackInterval);
}).then(function () {
return _readLoop(state);
});
if (state.closed) return;
return readNewMessages(state).then(function () {
return (0, _util.sleep)(state.options.idb.fallbackInterval);
}).then(function () {
return _readLoop(state);
});
}
function _filterMessage(msgObj, state) {
if (msgObj.uuid === state.uuid) return false; // send by own
if (state.emittedMessagesIds.has(msgObj.id)) return false; // already emitted
if (msgObj.data.time < state.messagesCallbackTime) return false; // older then onMessageCallback
return true;
if (msgObj.uuid === state.uuid) return false; // send by own
if (state.emittedMessagesIds.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.resolve(); // if no one is listening, we do not need to scan for new messages
// channel already closed
if (state.closed) return Promise.resolve();
if (!state.messagesCallback) return Promise.resolve();
return getMessagesHigherThen(state.db, state.lastCursorId).then(function (newerMessages) {
var useMessages = newerMessages.map(function (msgObj) {
if (msgObj.id > state.lastCursorId) {
state.lastCursorId = msgObj.id;
}
// if no one is listening, we do not need to scan for new messages
if (!state.messagesCallback) return Promise.resolve();
return msgObj;
}).filter(function (msgObj) {
return _filterMessage(msgObj, state);
}).sort(function (msgObjA, msgObjB) {
return msgObjA.time - msgObjB.time;
}); // sort by time
return getMessagesHigherThen(state.db, state.lastCursorId).then(function (newerMessages) {
var useMessages = newerMessages.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.emittedMessagesIds.add(msgObj.id);
state.messagesCallback(msgObj.data);
}
});
return Promise.resolve();
useMessages.forEach(function (msgObj) {
if (state.messagesCallback) {
state.emittedMessagesIds.add(msgObj.id);
state.messagesCallback(msgObj.data);
}
});
return Promise.resolve();
});
}
function close(channelState) {
channelState.closed = true;
channelState.db.close();
channelState.closed = true;
channelState.db.close();
}
function postMessage(channelState, messageJson) {
channelState.writeBlockPromise = channelState.writeBlockPromise.then(function () {
return writeMessage(channelState.db, channelState.uuid, messageJson);
}).then(function () {
if ((0, _util.randomInt)(0, 10) === 0) {
/* await (do not await) */cleanOldMessages(channelState.db, channelState.options.idb.ttl);
}
});
return channelState.writeBlockPromise;
channelState.writeBlockPromise = channelState.writeBlockPromise.then(function () {
return writeMessage(channelState.db, channelState.uuid, messageJson);
}).then(function () {
if ((0, _util.randomInt)(0, 10) === 0) {
/* await (do not await) */
cleanOldMessages(channelState.db, channelState.options.idb.ttl);
}
});
return channelState.writeBlockPromise;
}
function onMessage(channelState, fn, time) {
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
readNewMessages(channelState);
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
readNewMessages(channelState);
}
function canBeUsed() {
if (_detectNode2['default']) return false;
var idb = getIdb();
if (!idb) return false;
return true;
if (_detectNode["default"]) return false;
var idb = getIdb();
if (!idb) return false;
return true;
}
function averageResponseTime(options) {
return options.idb.fallbackInterval * 2;
return options.idb.fallbackInterval * 2;
}
exports['default'] = {
create: create,
close: close,
onMessage: onMessage,
postMessage: postMessage,
canBeUsed: canBeUsed,
type: type,
averageResponseTime: averageResponseTime,
microSeconds: microSeconds
};
var _default = {
create: create,
close: close,
onMessage: onMessage,
postMessage: postMessage,
canBeUsed: canBeUsed,
type: type,
averageResponseTime: averageResponseTime,
microSeconds: microSeconds
};
exports["default"] = _default;

@@ -1,7 +0,8 @@

'use strict';
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
value: true
});
exports.type = exports.microSeconds = undefined;
exports.getLocalStorage = getLocalStorage;

@@ -17,17 +18,12 @@ exports.storageKey = storageKey;

exports.averageResponseTime = averageResponseTime;
exports["default"] = exports.type = exports.microSeconds = void 0;
var _detectNode = require('detect-node');
var _detectNode = _interopRequireDefault(require("detect-node"));
var _detectNode2 = _interopRequireDefault(_detectNode);
var _obliviousSet = _interopRequireDefault(require("../oblivious-set"));
var _obliviousSet = require('../oblivious-set');
var _options = require("../options");
var _obliviousSet2 = _interopRequireDefault(_obliviousSet);
var _util = require("../util");
var _options = require('../options');
var _util = require('../util');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
/**

@@ -40,8 +36,6 @@ * A localStorage-only method which uses localstorage and its 'storage'-event

*/
var microSeconds = exports.microSeconds = _util.microSeconds;
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var KEY_PREFIX = 'pubkey.broadcastChannel-';
var type = exports.type = 'localstorage';
var type = 'localstorage';
/**

@@ -51,20 +45,23 @@ * copied from crosstab

*/
exports.type = type;
function getLocalStorage() {
var localStorage = void 0;
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
// if cookies are disabled. See
// https://bugzilla.mozilla.org/show_bug.cgi?id=1028153
}
return localStorage;
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
// if cookies are disabled. See
// https://bugzilla.mozilla.org/show_bug.cgi?id=1028153
}
return localStorage;
}
function storageKey(channelName) {
return KEY_PREFIX + channelName;
return KEY_PREFIX + channelName;
}
/**

@@ -74,108 +71,112 @@ * writes the new message to the storage

*/
function postMessage(channelState, messageJson) {
return new Promise(function (res) {
(0, _util.sleep)().then(function () {
var key = storageKey(channelState.channelName);
var writeObj = {
token: (0, _util.randomToken)(10),
time: new Date().getTime(),
data: messageJson,
uuid: channelState.uuid
};
var value = JSON.stringify(writeObj);
localStorage.setItem(key, value);
return new Promise(function (res) {
(0, _util.sleep)().then(function () {
var key = storageKey(channelState.channelName);
var writeObj = {
token: (0, _util.randomToken)(10),
time: new Date().getTime(),
data: messageJson,
uuid: channelState.uuid
};
var value = JSON.stringify(writeObj);
localStorage.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
*/
/**
* 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;
ev.newValue = value;
window.dispatchEvent(ev);
res();
});
var ev = document.createEvent('Event');
ev.initEvent('storage', true, true);
ev.key = key;
ev.newValue = value;
window.dispatchEvent(ev);
res();
});
});
}
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;
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);
window.removeEventListener('storage', listener);
}
function create(channelName, options) {
options = (0, _options.fillOptionsWithDefaults)(options);
if (!canBeUsed()) {
throw new Error('BroadcastChannel: localstorage cannot be used');
}
options = (0, _options.fillOptionsWithDefaults)(options);
var startTime = new Date().getTime();
var uuid = (0, _util.randomToken)(10);
if (!canBeUsed()) {
throw new Error('BroadcastChannel: localstorage cannot be used');
}
// contains all messages that have been emitted before
var emittedMessagesIds = new _obliviousSet2['default'](options.localstorage.removeTimeout);
var startTime = new Date().getTime();
var uuid = (0, _util.randomToken)(10); // contains all messages that have been emitted before
var state = {
startTime: startTime,
channelName: channelName,
options: options,
uuid: uuid,
emittedMessagesIds: emittedMessagesIds
};
var emittedMessagesIds = new _obliviousSet["default"](options.localstorage.removeTimeout);
var state = {
startTime: startTime,
channelName: channelName,
options: options,
uuid: uuid,
emittedMessagesIds: emittedMessagesIds
};
state.listener = addStorageEventListener(channelName, function (msgObj) {
if (!state.messagesCallback) return; // no listener
state.listener = addStorageEventListener(channelName, function (msgObj) {
if (!state.messagesCallback) return; // no listener
if (msgObj.uuid === uuid) return; // own message
if (!msgObj.token || emittedMessagesIds.has(msgObj.token)) return; // already emitted
if (msgObj.data.time && msgObj.data.time < state.messagesCallbackTime) return; // too old
if (msgObj.uuid === uuid) return; // own message
emittedMessagesIds.add(msgObj.token);
state.messagesCallback(msgObj.data);
});
if (!msgObj.token || emittedMessagesIds.has(msgObj.token)) return; // already emitted
return state;
if (msgObj.data.time && msgObj.data.time < state.messagesCallbackTime) return; // too old
emittedMessagesIds.add(msgObj.token);
state.messagesCallback(msgObj.data);
});
return state;
}
function close(channelState) {
removeStorageEventListener(channelState.listener);
removeStorageEventListener(channelState.listener);
}
function onMessage(channelState, fn, time) {
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
}
function canBeUsed() {
if (_detectNode2['default']) return false;
var ls = getLocalStorage();
if (!ls) return false;
return true;
if (_detectNode["default"]) return false;
var ls = getLocalStorage();
if (!ls) return false;
return true;
}
function averageResponseTime() {
return 120;
return 120;
}
exports['default'] = {
create: create,
close: close,
onMessage: onMessage,
postMessage: postMessage,
canBeUsed: canBeUsed,
type: type,
averageResponseTime: averageResponseTime,
microSeconds: microSeconds
};
var _default = {
create: create,
close: close,
onMessage: onMessage,
postMessage: postMessage,
canBeUsed: canBeUsed,
type: type,
averageResponseTime: averageResponseTime,
microSeconds: microSeconds
};
exports["default"] = _default;

@@ -1,7 +0,8 @@

'use strict';
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
value: true
});
exports.type = exports.microSeconds = undefined;
exports.create = create;

@@ -13,78 +14,77 @@ exports.close = close;

exports.averageResponseTime = averageResponseTime;
exports["default"] = exports.type = exports.microSeconds = void 0;
var _detectNode = require('detect-node');
var _detectNode = _interopRequireDefault(require("detect-node"));
var _detectNode2 = _interopRequireDefault(_detectNode);
var _util = require("../util");
var _util = require('../util');
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var type = 'native';
exports.type = type;
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
var microSeconds = exports.microSeconds = _util.microSeconds;
var type = exports.type = 'native';
function create(channelName, options) {
if (!options) options = {};
var state = {
uuid: (0, _util.randomToken)(10),
channelName: channelName,
options: options,
messagesCallback: null,
bc: new BroadcastChannel(channelName),
subscriberFunctions: []
};
if (!options) options = {};
var state = {
uuid: (0, _util.randomToken)(10),
channelName: channelName,
options: options,
messagesCallback: null,
bc: new BroadcastChannel(channelName),
subscriberFunctions: []
};
state.bc.onmessage = function (msg) {
if (state.messagesCallback) {
state.messagesCallback(msg.data);
}
};
state.bc.onmessage = function (msg) {
if (state.messagesCallback) {
state.messagesCallback(msg.data);
}
};
return state;
return state;
}
function close(channelState) {
channelState.bc.close();
channelState.subscriberFunctions = [];
channelState.bc.close();
channelState.subscriberFunctions = [];
}
function postMessage(channelState, messageJson) {
channelState.bc.postMessage(messageJson, false);
channelState.bc.postMessage(messageJson, false);
}
function onMessage(channelState, fn, time) {
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
}
function canBeUsed() {
/**
* in the electron-renderer, isNode will be true even if we are in browser-context
* so we also check if window is undefined
*/
if (_detectNode["default"] && typeof window === 'undefined') return false;
/**
* in the electron-renderer, isNode will be true even if we are in browser-context
* so we also check if window is undefined
*/
if (_detectNode2['default'] && 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');
}
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;
return true;
} else return false;
}
function averageResponseTime() {
return 100;
return 100;
}
exports['default'] = {
create: create,
close: close,
onMessage: onMessage,
postMessage: postMessage,
canBeUsed: canBeUsed,
type: type,
averageResponseTime: averageResponseTime,
microSeconds: microSeconds
};
var _default = {
create: create,
close: close,
onMessage: onMessage,
postMessage: postMessage,
canBeUsed: canBeUsed,
type: type,
averageResponseTime: averageResponseTime,
microSeconds: microSeconds
};
exports["default"] = _default;

@@ -1,757 +0,791 @@

'use strict';
"use strict";
var _slicedToArray2 = require('babel-runtime/helpers/slicedToArray');
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _slicedToArray3 = _interopRequireDefault(_slicedToArray2);
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
var _regenerator = require('babel-runtime/regenerator');
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
var _regenerator2 = _interopRequireDefault(_regenerator);
/**
* this method is used in nodejs-environments.
* The ipc is handled via sockets and file-writes to the tmp-folder
*/
var util = require('util');
var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator');
var fs = require('fs');
var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);
var os = require('os');
var ensureFoldersExist = function () {
var _ref = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee(channelName, paths) {
return _regenerator2['default'].wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
paths = paths || getPaths(channelName);
var events = require('events');
if (!ENSURE_BASE_FOLDER_EXISTS_PROMISE) {
ENSURE_BASE_FOLDER_EXISTS_PROMISE = mkdir(paths.base)['catch'](function () {
return null;
});
}
_context.next = 4;
return ENSURE_BASE_FOLDER_EXISTS_PROMISE;
var net = require('net');
case 4:
_context.next = 6;
return mkdir(paths.channelBase)['catch'](function () {
return null;
});
var path = require('path');
case 6:
_context.next = 8;
return Promise.all([mkdir(paths.readers)['catch'](function () {
return null;
}), mkdir(paths.messages)['catch'](function () {
return null;
})]);
var micro = require('nano-time');
case 8:
case 'end':
return _context.stop();
}
}
}, _callee, this);
}));
var rimraf = require('rimraf');
return function ensureFoldersExist(_x, _x2) {
return _ref.apply(this, arguments);
};
}();
var sha3_224 = require('js-sha3').sha3_224;
/**
* removes the tmp-folder
* @return {Promise<true>}
*/
var isNode = require('detect-node');
var unload = require('unload');
var clearNodeFolder = function () {
var _ref2 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee2() {
var paths, removePath;
return _regenerator2['default'].wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
paths = getPaths('foobar');
removePath = paths.base;
var fillOptionsWithDefaults = require('../../dist/lib/options.js').fillOptionsWithDefaults;
if (!(!removePath || removePath === '' || removePath === '/')) {
_context2.next = 4;
break;
}
var ownUtil = require('../../dist/lib/util.js');
throw new Error('BroadcastChannel.clearNodeFolder(): path is wrong');
var randomInt = ownUtil.randomInt;
var randomToken = ownUtil.randomToken;
case 4:
ENSURE_BASE_FOLDER_EXISTS_PROMISE = null;
_context2.next = 7;
return removeDir(paths.base);
case 7:
ENSURE_BASE_FOLDER_EXISTS_PROMISE = null;
return _context2.abrupt('return', true);
case 9:
case 'end':
return _context2.stop();
}
}
}, _callee2, this);
}));
return function clearNodeFolder() {
return _ref2.apply(this, arguments);
};
}();
var ObliviousSet = require('../../dist/lib/oblivious-set')["default"];
/**
* creates the socket-file and subscribes to it
* @return {{emitter: EventEmitter, server: any}}
* windows sucks, so we have handle windows-type of socket-paths
* @link https://gist.github.com/domenic/2790533#gistcomment-331356
*/
var createSocketEventEmitter = function () {
var _ref3 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee3(channelName, readerUuid, paths) {
var pathToSocket, emitter, server;
return _regenerator2['default'].wrap(function _callee3$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
pathToSocket = socketPath(channelName, readerUuid, paths);
emitter = new events.EventEmitter();
server = net.createServer(function (stream) {
stream.on('end', function () {});
stream.on('data', function (msg) {
emitter.emit('data', msg.toString());
});
});
_context3.next = 5;
return new Promise(function (resolve, reject) {
server.listen(pathToSocket, function (err, res) {
if (err) reject(err);else resolve(res);
});
});
case 5:
return _context3.abrupt('return', {
path: pathToSocket,
emitter: emitter,
server: server
});
case 6:
case 'end':
return _context3.stop();
}
}
}, _callee3, this);
}));
function cleanPipeName(str) {
if (process.platform === 'win32' && !str.startsWith('\\\\.\\pipe\\')) {
str = str.replace(/^\//, '');
str = str.replace(/\//g, '-');
return '\\\\.\\pipe\\' + str;
} else {
return str;
}
}
return function createSocketEventEmitter(_x3, _x4, _x5) {
return _ref3.apply(this, arguments);
};
}();
var mkdir = util.promisify(fs.mkdir);
var writeFile = util.promisify(fs.writeFile);
var readFile = util.promisify(fs.readFile);
var unlink = util.promisify(fs.unlink);
var readdir = util.promisify(fs.readdir);
var removeDir = util.promisify(rimraf);
var OTHER_INSTANCES = {};
var TMP_FOLDER_NAME = 'pubkey.bc';
var TMP_FOLDER_BASE = path.join(os.tmpdir(), TMP_FOLDER_NAME);
var getPathsCache = new Map();
var openClientConnection = function () {
var _ref4 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee4(channelName, readerUuid) {
var pathToSocket, client;
return _regenerator2['default'].wrap(function _callee4$(_context4) {
while (1) {
switch (_context4.prev = _context4.next) {
case 0:
pathToSocket = socketPath(channelName, readerUuid);
client = new net.Socket();
_context4.next = 4;
return new Promise(function (res) {
client.connect(pathToSocket, res);
});
function getPaths(channelName) {
if (!getPathsCache.has(channelName)) {
var channelHash = sha3_224(channelName); // use hash incase of strange characters
case 4:
return _context4.abrupt('return', client);
/**
* because the lenght 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
*/
case 5:
case 'end':
return _context4.stop();
}
}
}, _callee4, this);
}));
return function openClientConnection(_x6, _x7) {
return _ref4.apply(this, arguments);
var channelFolder = 'A' + channelHash.substring(0, 20);
var channelPathBase = path.join(TMP_FOLDER_BASE, channelFolder);
var folderPathReaders = path.join(channelPathBase, 'rdrs');
var folderPathMessages = path.join(channelPathBase, 'messages');
var ret = {
base: TMP_FOLDER_BASE,
channelBase: channelPathBase,
readers: folderPathReaders,
messages: folderPathMessages
};
}();
getPathsCache.set(channelName, ret);
return ret;
}
/**
* writes the new message to the file-system
* so other readers can find it
* @return {Promise}
*/
return getPathsCache.get(channelName);
}
var ENSURE_BASE_FOLDER_EXISTS_PROMISE = null;
function ensureFoldersExist(_x, _x2) {
return _ensureFoldersExist.apply(this, arguments);
}
/**
* returns the uuids of all readers
* @return {string[]}
* removes the tmp-folder
* @return {Promise<true>}
*/
var getReadersUuids = function () {
var _ref5 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee5(channelName, paths) {
var readersPath, files;
return _regenerator2['default'].wrap(function _callee5$(_context5) {
while (1) {
switch (_context5.prev = _context5.next) {
case 0:
paths = paths || getPaths(channelName);
readersPath = paths.readers;
_context5.next = 4;
return readdir(readersPath);
case 4:
files = _context5.sent;
return _context5.abrupt('return', files.map(function (file) {
return file.split('.');
}).filter(function (split) {
return split[1] === 'json';
}) // do not scan .socket-files
.map(function (split) {
return split[0];
}));
case 6:
case 'end':
return _context5.stop();
}
function _ensureFoldersExist() {
_ensureFoldersExist = (0, _asyncToGenerator2["default"])(
/*#__PURE__*/
_regenerator["default"].mark(function _callee4(channelName, paths) {
return _regenerator["default"].wrap(function _callee4$(_context4) {
while (1) {
switch (_context4.prev = _context4.next) {
case 0:
paths = paths || getPaths(channelName);
if (!ENSURE_BASE_FOLDER_EXISTS_PROMISE) {
ENSURE_BASE_FOLDER_EXISTS_PROMISE = mkdir(paths.base)["catch"](function () {
return null;
});
}
}, _callee5, this);
}));
return function getReadersUuids(_x8, _x9) {
return _ref5.apply(this, arguments);
};
}();
_context4.next = 4;
return ENSURE_BASE_FOLDER_EXISTS_PROMISE;
var messagePath = function () {
var _ref6 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee6(channelName, time, token, writerUuid) {
var fileName, msgPath;
return _regenerator2['default'].wrap(function _callee6$(_context6) {
while (1) {
switch (_context6.prev = _context6.next) {
case 0:
fileName = time + '_' + writerUuid + '_' + token + '.json';
msgPath = path.join(getPaths(channelName).messages, fileName);
return _context6.abrupt('return', msgPath);
case 4:
_context4.next = 6;
return mkdir(paths.channelBase)["catch"](function () {
return null;
});
case 3:
case 'end':
return _context6.stop();
}
}
}, _callee6, this);
}));
case 6:
_context4.next = 8;
return Promise.all([mkdir(paths.readers)["catch"](function () {
return null;
}), mkdir(paths.messages)["catch"](function () {
return null;
})]);
return function messagePath(_x10, _x11, _x12, _x13) {
return _ref6.apply(this, arguments);
};
}();
case 8:
case "end":
return _context4.stop();
}
}
}, _callee4, this);
}));
return _ensureFoldersExist.apply(this, arguments);
}
var getAllMessages = function () {
var _ref7 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee7(channelName, paths) {
var messagesPath, files;
return _regenerator2['default'].wrap(function _callee7$(_context7) {
while (1) {
switch (_context7.prev = _context7.next) {
case 0:
paths = paths || getPaths(channelName);
messagesPath = paths.messages;
_context7.next = 4;
return readdir(messagesPath);
function clearNodeFolder() {
return _clearNodeFolder.apply(this, arguments);
}
case 4:
files = _context7.sent;
return _context7.abrupt('return', files.map(function (file) {
var fileName = file.split('.')[0];
var split = fileName.split('_');
function _clearNodeFolder() {
_clearNodeFolder = (0, _asyncToGenerator2["default"])(
/*#__PURE__*/
_regenerator["default"].mark(function _callee5() {
var paths, removePath;
return _regenerator["default"].wrap(function _callee5$(_context5) {
while (1) {
switch (_context5.prev = _context5.next) {
case 0:
paths = getPaths('foobar');
removePath = paths.base;
return {
path: path.join(messagesPath, file),
time: parseInt(split[0]),
senderUuid: split[1],
token: split[2]
};
}));
case 6:
case 'end':
return _context7.stop();
}
if (!(!removePath || removePath === '' || removePath === '/')) {
_context5.next = 4;
break;
}
}, _callee7, this);
}));
return function getAllMessages(_x14, _x15) {
return _ref7.apply(this, arguments);
};
}();
throw new Error('BroadcastChannel.clearNodeFolder(): path is wrong');
var cleanOldMessages = function () {
var _ref8 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee8(messageObjects, ttl) {
var olderThen;
return _regenerator2['default'].wrap(function _callee8$(_context8) {
while (1) {
switch (_context8.prev = _context8.next) {
case 0:
olderThen = Date.now() - ttl;
_context8.next = 3;
return Promise.all(messageObjects.filter(function (obj) {
return obj.time / 1000 < olderThen;
}).map(function (obj) {
return unlink(obj.path)['catch'](function () {
return null;
});
}));
case 4:
ENSURE_BASE_FOLDER_EXISTS_PROMISE = null;
_context5.next = 7;
return removeDir(paths.base);
case 3:
case 'end':
return _context8.stop();
}
}
}, _callee8, this);
}));
case 7:
ENSURE_BASE_FOLDER_EXISTS_PROMISE = null;
return _context5.abrupt("return", true);
return function cleanOldMessages(_x16, _x17) {
return _ref8.apply(this, arguments);
};
}();
case 9:
case "end":
return _context5.stop();
}
}
}, _callee5, this);
}));
return _clearNodeFolder.apply(this, arguments);
}
function socketPath(channelName, readerUuid, paths) {
paths = paths || getPaths(channelName);
var socketPath = path.join(paths.readers, readerUuid + '.s');
return cleanPipeName(socketPath);
}
function socketInfoPath(channelName, readerUuid, paths) {
paths = paths || getPaths(channelName);
var socketPath = path.join(paths.readers, readerUuid + '.json');
return socketPath;
}
/**
* creates a new channelState
* @return {Promise<any>}
* 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
*/
var create = function () {
var _ref9 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee9(channelName) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var time, paths, ensureFolderExistsPromise, uuid, state, _ref10, _ref11, socketEE, infoFilePath;
return _regenerator2['default'].wrap(function _callee9$(_context9) {
while (1) {
switch (_context9.prev = _context9.next) {
case 0:
options = fillOptionsWithDefaults(options);
time = microSeconds();
paths = getPaths(channelName);
ensureFolderExistsPromise = ensureFoldersExist(channelName, paths);
uuid = randomToken(10);
state = {
time: time,
channelName: channelName,
options: options,
uuid: uuid,
paths: paths,
// contains all messages that have been emitted before
emittedMessagesIds: new ObliviousSet(options.node.ttl * 2),
messagesCallbackTime: null,
messagesCallback: null,
// ensures we do not read messages in parrallel
writeBlockPromise: Promise.resolve(),
otherReaderClients: {},
// ensure if process crashes, everything is cleaned up
removeUnload: unload.add(function () {
return close(state);
}),
closed: false
};
function createSocketInfoFile(channelName, readerUuid, paths) {
var pathToFile = socketInfoPath(channelName, readerUuid, paths);
return writeFile(pathToFile, JSON.stringify({
time: microSeconds()
})).then(function () {
return pathToFile;
});
}
/**
* creates the socket-file and subscribes to it
* @return {{emitter: EventEmitter, server: any}}
*/
if (!OTHER_INSTANCES[channelName]) OTHER_INSTANCES[channelName] = [];
OTHER_INSTANCES[channelName].push(state);
function createSocketEventEmitter(_x3, _x4, _x5) {
return _createSocketEventEmitter.apply(this, arguments);
}
_context9.next = 10;
return ensureFolderExistsPromise;
function _createSocketEventEmitter() {
_createSocketEventEmitter = (0, _asyncToGenerator2["default"])(
/*#__PURE__*/
_regenerator["default"].mark(function _callee6(channelName, readerUuid, paths) {
var pathToSocket, emitter, server;
return _regenerator["default"].wrap(function _callee6$(_context6) {
while (1) {
switch (_context6.prev = _context6.next) {
case 0:
pathToSocket = socketPath(channelName, readerUuid, paths);
emitter = new events.EventEmitter();
server = net.createServer(function (stream) {
stream.on('end', function () {});
stream.on('data', function (msg) {
emitter.emit('data', msg.toString());
});
});
_context6.next = 5;
return new Promise(function (resolve, reject) {
server.listen(pathToSocket, function (err, res) {
if (err) reject(err);else resolve(res);
});
});
case 10:
_context9.next = 12;
return Promise.all([createSocketEventEmitter(channelName, uuid, paths), createSocketInfoFile(channelName, uuid, paths), refreshReaderClients(state)]);
case 5:
return _context6.abrupt("return", {
path: pathToSocket,
emitter: emitter,
server: server
});
case 12:
_ref10 = _context9.sent;
_ref11 = (0, _slicedToArray3['default'])(_ref10, 2);
socketEE = _ref11[0];
infoFilePath = _ref11[1];
case 6:
case "end":
return _context6.stop();
}
}
}, _callee6, this);
}));
return _createSocketEventEmitter.apply(this, arguments);
}
state.socketEE = socketEE;
state.infoFilePath = infoFilePath;
function openClientConnection(_x6, _x7) {
return _openClientConnection.apply(this, arguments);
}
/**
* writes the new message to the file-system
* so other readers can find it
* @return {Promise}
*/
// 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
var singleOnes = data.split('|');
singleOnes.filter(function (single) {
return single !== '';
}).forEach(function (single) {
try {
var obj = JSON.parse(single);
handleMessagePing(state, obj);
} catch (err) {
throw new Error('could not parse data: ' + single);
}
});
});
function _openClientConnection() {
_openClientConnection = (0, _asyncToGenerator2["default"])(
/*#__PURE__*/
_regenerator["default"].mark(function _callee7(channelName, readerUuid) {
var pathToSocket, client;
return _regenerator["default"].wrap(function _callee7$(_context7) {
while (1) {
switch (_context7.prev = _context7.next) {
case 0:
pathToSocket = socketPath(channelName, readerUuid);
client = new net.Socket();
_context7.next = 4;
return new Promise(function (res) {
client.connect(pathToSocket, res);
});
return _context9.abrupt('return', state);
case 4:
return _context7.abrupt("return", client);
case 20:
case 'end':
return _context9.stop();
}
}
}, _callee9, this);
}));
case 5:
case "end":
return _context7.stop();
}
}
}, _callee7, this);
}));
return _openClientConnection.apply(this, arguments);
}
return function create(_x19) {
return _ref9.apply(this, arguments);
function writeMessage(channelName, readerUuid, messageJson, paths) {
paths = paths || getPaths(channelName);
var time = microSeconds();
var writeObject = {
uuid: readerUuid,
time: time,
data: messageJson
};
var token = randomToken(12);
var fileName = time + '_' + readerUuid + '_' + token + '.json';
var msgPath = path.join(paths.messages, fileName);
return writeFile(msgPath, JSON.stringify(writeObject)).then(function () {
return {
time: time,
uuid: readerUuid,
token: token,
path: msgPath
};
}();
});
}
/**
* when the socket pings, so that we now new messages came,
* run this
* returns the uuids of all readers
* @return {string[]}
*/
var handleMessagePing = function () {
var _ref12 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee10(state, msgObj) {
var messages, useMessages;
return _regenerator2['default'].wrap(function _callee10$(_context10) {
while (1) {
switch (_context10.prev = _context10.next) {
case 0:
if (state.messagesCallback) {
_context10.next = 2;
break;
}
return _context10.abrupt('return');
case 2:
messages = void 0;
function getReadersUuids(_x8, _x9) {
return _getReadersUuids.apply(this, arguments);
}
if (msgObj) {
_context10.next = 9;
break;
}
function _getReadersUuids() {
_getReadersUuids = (0, _asyncToGenerator2["default"])(
/*#__PURE__*/
_regenerator["default"].mark(function _callee8(channelName, paths) {
var readersPath, files;
return _regenerator["default"].wrap(function _callee8$(_context8) {
while (1) {
switch (_context8.prev = _context8.next) {
case 0:
paths = paths || getPaths(channelName);
readersPath = paths.readers;
_context8.next = 4;
return readdir(readersPath);
_context10.next = 6;
return getAllMessages(state.channelName, state.paths);
case 4:
files = _context8.sent;
return _context8.abrupt("return", files.map(function (file) {
return file.split('.');
}).filter(function (split) {
return split[1] === 'json';
}) // do not scan .socket-files
.map(function (split) {
return split[0];
}));
case 6:
messages = _context10.sent;
_context10.next = 10;
break;
case 6:
case "end":
return _context8.stop();
}
}
}, _callee8, this);
}));
return _getReadersUuids.apply(this, arguments);
}
case 9:
// get single message
messages = [getSingleMessage(state.channelName, msgObj, state.paths)];
function messagePath(_x10, _x11, _x12, _x13) {
return _messagePath.apply(this, arguments);
}
case 10:
useMessages = messages.filter(function (msgObj) {
return _filterMessage(msgObj, state);
}).sort(function (msgObjA, msgObjB) {
return msgObjA.time - msgObjB.time;
}); // sort by time
function _messagePath() {
_messagePath = (0, _asyncToGenerator2["default"])(
/*#__PURE__*/
_regenerator["default"].mark(function _callee9(channelName, time, token, writerUuid) {
var fileName, msgPath;
return _regenerator["default"].wrap(function _callee9$(_context9) {
while (1) {
switch (_context9.prev = _context9.next) {
case 0:
fileName = time + '_' + writerUuid + '_' + token + '.json';
msgPath = path.join(getPaths(channelName).messages, fileName);
return _context9.abrupt("return", msgPath);
case 3:
case "end":
return _context9.stop();
}
}
}, _callee9, this);
}));
return _messagePath.apply(this, arguments);
}
// if no listener or message, so not do anything
function getAllMessages(_x14, _x15) {
return _getAllMessages.apply(this, arguments);
}
if (!(!useMessages.length || !state.messagesCallback)) {
_context10.next = 13;
break;
}
function _getAllMessages() {
_getAllMessages = (0, _asyncToGenerator2["default"])(
/*#__PURE__*/
_regenerator["default"].mark(function _callee10(channelName, paths) {
var messagesPath, files;
return _regenerator["default"].wrap(function _callee10$(_context10) {
while (1) {
switch (_context10.prev = _context10.next) {
case 0:
paths = paths || getPaths(channelName);
messagesPath = paths.messages;
_context10.next = 4;
return readdir(messagesPath);
return _context10.abrupt('return');
case 4:
files = _context10.sent;
return _context10.abrupt("return", files.map(function (file) {
var fileName = file.split('.')[0];
var split = fileName.split('_');
return {
path: path.join(messagesPath, file),
time: parseInt(split[0]),
senderUuid: split[1],
token: split[2]
};
}));
case 13:
_context10.next = 15;
return Promise.all(useMessages.map(function (msgObj) {
return readMessage(msgObj).then(function (content) {
return msgObj.content = content;
});
}));
case 6:
case "end":
return _context10.stop();
}
}
}, _callee10, this);
}));
return _getAllMessages.apply(this, arguments);
}
case 15:
function getSingleMessage(channelName, msgObj, paths) {
paths = paths || getPaths(channelName);
return {
path: path.join(paths.messages, msgObj.t + '_' + msgObj.u + '_' + msgObj.to + '.json'),
time: msgObj.t,
senderUuid: msgObj.u,
token: msgObj.to
};
}
useMessages.forEach(function (msgObj) {
state.emittedMessagesIds.add(msgObj.token);
function readMessage(messageObj) {
return readFile(messageObj.path, 'utf8').then(function (content) {
return JSON.parse(content);
});
}
if (state.messagesCallback) {
// emit to subscribers
state.messagesCallback(msgObj.content.data);
}
});
function cleanOldMessages(_x16, _x17) {
return _cleanOldMessages.apply(this, arguments);
}
case 16:
case 'end':
return _context10.stop();
}
}
}, _callee10, this);
}));
function _cleanOldMessages() {
_cleanOldMessages = (0, _asyncToGenerator2["default"])(
/*#__PURE__*/
_regenerator["default"].mark(function _callee11(messageObjects, ttl) {
var olderThen;
return _regenerator["default"].wrap(function _callee11$(_context11) {
while (1) {
switch (_context11.prev = _context11.next) {
case 0:
olderThen = Date.now() - ttl;
_context11.next = 3;
return Promise.all(messageObjects.filter(function (obj) {
return obj.time / 1000 < olderThen;
}).map(function (obj) {
return unlink(obj.path)["catch"](function () {
return null;
});
}));
return function handleMessagePing(_x20, _x21) {
return _ref12.apply(this, arguments);
};
}();
case 3:
case "end":
return _context11.stop();
}
}
}, _callee11, this);
}));
return _cleanOldMessages.apply(this, arguments);
}
var type = 'node';
/**
* ensures that the channelState is connected with all other readers
* @return {Promise<void>}
* creates a new channelState
* @return {Promise<any>}
*/
function create(_x18) {
return _create.apply(this, arguments);
}
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
function _create() {
_create = (0, _asyncToGenerator2["default"])(
/*#__PURE__*/
_regenerator["default"].mark(function _callee12(channelName) {
var options,
time,
paths,
ensureFolderExistsPromise,
uuid,
state,
_ref5,
socketEE,
infoFilePath,
_args12 = arguments;
/**
* this method is used in nodejs-environments.
* The ipc is handled via sockets and file-writes to the tmp-folder
*/
return _regenerator["default"].wrap(function _callee12$(_context12) {
while (1) {
switch (_context12.prev = _context12.next) {
case 0:
options = _args12.length > 1 && _args12[1] !== undefined ? _args12[1] : {};
options = fillOptionsWithDefaults(options);
time = microSeconds();
paths = getPaths(channelName);
ensureFolderExistsPromise = ensureFoldersExist(channelName, paths);
uuid = randomToken(10);
state = {
time: time,
channelName: channelName,
options: options,
uuid: uuid,
paths: paths,
// contains all messages that have been emitted before
emittedMessagesIds: new ObliviousSet(options.node.ttl * 2),
messagesCallbackTime: null,
messagesCallback: null,
// ensures we do not read messages in parrallel
writeBlockPromise: Promise.resolve(),
otherReaderClients: {},
// ensure if process crashes, everything is cleaned up
removeUnload: unload.add(function () {
return close(state);
}),
closed: false
};
if (!OTHER_INSTANCES[channelName]) OTHER_INSTANCES[channelName] = [];
OTHER_INSTANCES[channelName].push(state);
_context12.next = 11;
return ensureFolderExistsPromise;
var util = require('util');
var fs = require('fs');
var os = require('os');
var events = require('events');
var net = require('net');
var path = require('path');
var micro = require('nano-time');
var rimraf = require('rimraf');
var sha3_224 = require('js-sha3').sha3_224;
var isNode = require('detect-node');
var unload = require('unload');
case 11:
_context12.next = 13;
return Promise.all([createSocketEventEmitter(channelName, uuid, paths), createSocketInfoFile(channelName, uuid, paths), refreshReaderClients(state)]);
var fillOptionsWithDefaults = require('../../dist/lib/options.js').fillOptionsWithDefaults;
var ownUtil = require('../../dist/lib/util.js');
var randomInt = ownUtil.randomInt;
var randomToken = ownUtil.randomToken;
var ObliviousSet = require('../../dist/lib/oblivious-set')['default'];
case 13:
_ref5 = _context12.sent;
socketEE = _ref5[0];
infoFilePath = _ref5[1];
state.socketEE = socketEE;
state.infoFilePath = infoFilePath; // when new message comes in, we read it and emit it
/**
* windows sucks, so we have handle windows-type of socket-paths
* @link https://gist.github.com/domenic/2790533#gistcomment-331356
*/
function cleanPipeName(str) {
if (process.platform === 'win32' && !str.startsWith('\\\\.\\pipe\\')) {
str = str.replace(/^\//, '');
str = str.replace(/\//g, '-');
return '\\\\.\\pipe\\' + str;
} else {
return str;
}
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
var singleOnes = data.split('|');
singleOnes.filter(function (single) {
return single !== '';
}).forEach(function (single) {
try {
var obj = JSON.parse(single);
handleMessagePing(state, obj);
} catch (err) {
throw new Error('could not parse data: ' + single);
}
});
});
return _context12.abrupt("return", state);
case 20:
case "end":
return _context12.stop();
}
}
}, _callee12, this);
}));
return _create.apply(this, arguments);
}
var mkdir = util.promisify(fs.mkdir);
var writeFile = util.promisify(fs.writeFile);
var readFile = util.promisify(fs.readFile);
var unlink = util.promisify(fs.unlink);
var readdir = util.promisify(fs.readdir);
var removeDir = util.promisify(rimraf);
function _filterMessage(msgObj, state) {
if (msgObj.senderUuid === state.uuid) return false; // not send by own
var OTHER_INSTANCES = {};
var TMP_FOLDER_NAME = 'pubkey.bc';
var TMP_FOLDER_BASE = path.join(os.tmpdir(), TMP_FOLDER_NAME);
var getPathsCache = new Map();
if (state.emittedMessagesIds.has(msgObj.token)) return false; // not already emitted
function getPaths(channelName) {
if (!getPathsCache.has(channelName)) {
var channelHash = sha3_224(channelName); // use hash incase of strange characters
/**
* because the lenght 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);
if (!state.messagesCallback) return false; // no listener
var channelPathBase = path.join(TMP_FOLDER_BASE, channelFolder);
var folderPathReaders = path.join(channelPathBase, 'rdrs');
var folderPathMessages = path.join(channelPathBase, 'messages');
if (msgObj.time < state.messagesCallbackTime) return false; // not older then onMessageCallback
var ret = {
base: TMP_FOLDER_BASE,
channelBase: channelPathBase,
readers: folderPathReaders,
messages: folderPathMessages
};
getPathsCache.set(channelName, ret);
return ret;
}
return getPathsCache.get(channelName);
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
*/
var ENSURE_BASE_FOLDER_EXISTS_PROMISE = null;
function socketPath(channelName, readerUuid, paths) {
paths = paths || getPaths(channelName);
var socketPath = path.join(paths.readers, readerUuid + '.s');
return cleanPipeName(socketPath);
function handleMessagePing(_x19, _x20) {
return _handleMessagePing.apply(this, arguments);
}
function socketInfoPath(channelName, readerUuid, paths) {
paths = paths || getPaths(channelName);
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
* ensures that the channelState is connected with all other readers
* @return {Promise<void>}
*/
function createSocketInfoFile(channelName, readerUuid, paths) {
var pathToFile = socketInfoPath(channelName, readerUuid, paths);
return writeFile(pathToFile, JSON.stringify({
time: microSeconds()
})).then(function () {
return pathToFile;
});
}function writeMessage(channelName, readerUuid, messageJson, paths) {
paths = paths || getPaths(channelName);
var time = microSeconds();
var writeObject = {
uuid: readerUuid,
time: time,
data: messageJson
};
var token = randomToken(12);
var fileName = time + '_' + readerUuid + '_' + token + '.json';
var msgPath = path.join(paths.messages, fileName);
function _handleMessagePing() {
_handleMessagePing = (0, _asyncToGenerator2["default"])(
/*#__PURE__*/
_regenerator["default"].mark(function _callee13(state, msgObj) {
var messages, useMessages;
return _regenerator["default"].wrap(function _callee13$(_context13) {
while (1) {
switch (_context13.prev = _context13.next) {
case 0:
if (state.messagesCallback) {
_context13.next = 2;
break;
}
return writeFile(msgPath, JSON.stringify(writeObject)).then(function () {
return {
time: time,
uuid: readerUuid,
token: token,
path: msgPath
};
});
}
return _context13.abrupt("return");
function getSingleMessage(channelName, msgObj, paths) {
paths = paths || getPaths(channelName);
case 2:
if (msgObj) {
_context13.next = 8;
break;
}
return {
path: path.join(paths.messages, msgObj.t + '_' + msgObj.u + '_' + msgObj.to + '.json'),
time: msgObj.t,
senderUuid: msgObj.u,
token: msgObj.to
};
}
_context13.next = 5;
return getAllMessages(state.channelName, state.paths);
function readMessage(messageObj) {
return readFile(messageObj.path, 'utf8').then(function (content) {
return JSON.parse(content);
});
}
case 5:
messages = _context13.sent;
_context13.next = 9;
break;
var type = 'node';
case 8:
// get single message
messages = [getSingleMessage(state.channelName, msgObj, state.paths)];
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
case 9:
useMessages = messages.filter(function (msgObj) {
return _filterMessage(msgObj, state);
}).sort(function (msgObjA, msgObjB) {
return msgObjA.time - msgObjB.time;
}); // sort by time
// if no listener or message, so not do anything
state.emittedMessagesIds.add(msgObj.token);
return true;
}function refreshReaderClients(channelState) {
var _this = this;
if (!(!useMessages.length || !state.messagesCallback)) {
_context13.next = 12;
break;
}
return getReadersUuids(channelState.channelName, channelState.paths).then(function (otherReaders) {
// remove subscriptions to closed readers
Object.keys(channelState.otherReaderClients).filter(function (readerUuid) {
return !otherReaders.includes(readerUuid);
}).forEach(function () {
var _ref13 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee11(readerUuid) {
return _regenerator2['default'].wrap(function _callee11$(_context11) {
while (1) {
switch (_context11.prev = _context11.next) {
case 0:
_context11.prev = 0;
_context11.next = 3;
return channelState.otherReaderClients[readerUuid].destroy();
return _context13.abrupt("return");
case 3:
_context11.next = 7;
break;
case 12:
_context13.next = 14;
return Promise.all(useMessages.map(function (msgObj) {
return readMessage(msgObj).then(function (content) {
return msgObj.content = content;
});
}));
case 5:
_context11.prev = 5;
_context11.t0 = _context11['catch'](0);
case 14:
useMessages.forEach(function (msgObj) {
state.emittedMessagesIds.add(msgObj.token);
case 7:
delete channelState.otherReaderClients[readerUuid];
if (state.messagesCallback) {
// emit to subscribers
state.messagesCallback(msgObj.content.data);
}
});
case 8:
case 'end':
return _context11.stop();
}
}
}, _callee11, _this, [[0, 5]]);
}));
case 15:
case "end":
return _context13.stop();
}
}
}, _callee13, this);
}));
return _handleMessagePing.apply(this, arguments);
}
return function (_x22) {
return _ref13.apply(this, arguments);
};
}());
function refreshReaderClients(channelState) {
return getReadersUuids(channelState.channelName, channelState.paths).then(function (otherReaders) {
// remove subscriptions to closed readers
Object.keys(channelState.otherReaderClients).filter(function (readerUuid) {
return !otherReaders.includes(readerUuid);
}).forEach(
/*#__PURE__*/
function () {
var _ref = (0, _asyncToGenerator2["default"])(
/*#__PURE__*/
_regenerator["default"].mark(function _callee(readerUuid) {
return _regenerator["default"].wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_context.prev = 0;
_context.next = 3;
return channelState.otherReaderClients[readerUuid].destroy();
// add new readers
return Promise.all(otherReaders.filter(function (readerUuid) {
return readerUuid !== channelState.uuid;
}) // not own
.filter(function (readerUuid) {
return !channelState.otherReaderClients[readerUuid];
}) // not already has client
.map(function () {
var _ref14 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee12(readerUuid) {
var client;
return _regenerator2['default'].wrap(function _callee12$(_context12) {
while (1) {
switch (_context12.prev = _context12.next) {
case 0:
_context12.prev = 0;
case 3:
_context.next = 7;
break;
if (!channelState.closed) {
_context12.next = 3;
break;
}
case 5:
_context.prev = 5;
_context.t0 = _context["catch"](0);
return _context12.abrupt('return');
case 7:
delete channelState.otherReaderClients[readerUuid];
case 3:
_context12.next = 5;
return openClientConnection(channelState.channelName, readerUuid);
case 8:
case "end":
return _context.stop();
}
}
}, _callee, this, [[0, 5]]);
}));
case 5:
client = _context12.sent;
return function (_x21) {
return _ref.apply(this, arguments);
};
}()); // add new readers
channelState.otherReaderClients[readerUuid] = client;
_context12.next = 11;
break;
return Promise.all(otherReaders.filter(function (readerUuid) {
return readerUuid !== channelState.uuid;
}) // not own
.filter(function (readerUuid) {
return !channelState.otherReaderClients[readerUuid];
}) // not already has client
.map(
/*#__PURE__*/
function () {
var _ref2 = (0, _asyncToGenerator2["default"])(
/*#__PURE__*/
_regenerator["default"].mark(function _callee2(readerUuid) {
var client;
return _regenerator["default"].wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
_context2.prev = 0;
case 9:
_context12.prev = 9;
_context12.t0 = _context12['catch'](0);
if (!channelState.closed) {
_context2.next = 3;
break;
}
case 11:
case 'end':
return _context12.stop();
}
}
}, _callee12, _this, [[0, 9]]);
}));
return _context2.abrupt("return");
return function (_x23) {
return _ref14.apply(this, arguments);
};
}()
// this might throw if the other channel is closed at the same time when this one is running refresh
// so we do not throw an error
));
});
case 3:
_context2.next = 5;
return openClientConnection(channelState.channelName, readerUuid);
case 5:
client = _context2.sent;
channelState.otherReaderClients[readerUuid] = client;
_context2.next = 11;
break;
case 9:
_context2.prev = 9;
_context2.t0 = _context2["catch"](0);
case 11:
case "end":
return _context2.stop();
}
}
}, _callee2, this, [[0, 9]]);
}));
return function (_x22) {
return _ref2.apply(this, arguments);
};
}()));
});
}
/**

@@ -761,64 +795,63 @@ * post a message to the other readers

*/
function postMessage(channelState, messageJson) {
var _this2 = this;
var writePromise = writeMessage(channelState.channelName, channelState.uuid, messageJson, channelState.paths);
channelState.writeBlockPromise = channelState.writeBlockPromise.then((0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee13() {
var _ref16, _ref17, msgObj, pingStr, writeToReadersPromise;
return _regenerator2['default'].wrap(function _callee13$(_context13) {
while (1) {
switch (_context13.prev = _context13.next) {
case 0:
_context13.next = 2;
return new Promise(function (res) {
return setTimeout(res, 0);
});
function postMessage(channelState, messageJson) {
var writePromise = writeMessage(channelState.channelName, channelState.uuid, messageJson, channelState.paths);
channelState.writeBlockPromise = channelState.writeBlockPromise.then(
/*#__PURE__*/
(0, _asyncToGenerator2["default"])(
/*#__PURE__*/
_regenerator["default"].mark(function _callee3() {
var _ref4, msgObj, pingStr, writeToReadersPromise;
case 2:
_context13.next = 4;
return Promise.all([writePromise, refreshReaderClients(channelState)]);
return _regenerator["default"].wrap(function _callee3$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
_context3.next = 2;
return new Promise(function (res) {
return setTimeout(res, 0);
});
case 4:
_ref16 = _context13.sent;
_ref17 = (0, _slicedToArray3['default'])(_ref16, 1);
msgObj = _ref17[0];
case 2:
_context3.next = 4;
return Promise.all([writePromise, refreshReaderClients(channelState)]);
emitOverFastPath(channelState, msgObj, messageJson);
pingStr = '{"t":' + msgObj.time + ',"u":"' + msgObj.uuid + '","to":"' + msgObj.token + '"}|';
writeToReadersPromise = Promise.all(Object.values(channelState.otherReaderClients).filter(function (client) {
return client.writable;
}) // client might have closed in between
.map(function (client) {
return new Promise(function (res) {
client.write(pingStr, res);
});
}));
case 4:
_ref4 = _context3.sent;
msgObj = _ref4[0];
emitOverFastPath(channelState, msgObj, messageJson);
pingStr = '{"t":' + msgObj.time + ',"u":"' + msgObj.uuid + '","to":"' + msgObj.token + '"}|';
writeToReadersPromise = Promise.all(Object.values(channelState.otherReaderClients).filter(function (client) {
return client.writable;
}) // client might have closed in between
.map(function (client) {
return new Promise(function (res) {
client.write(pingStr, res);
});
}));
/**
* clean up old messages
* to not waste resources on cleaning up,
* only if random-int matches, we clean up old messages
*/
/**
* clean up old messages
* 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);
});
}
if (randomInt(0, 20) === 0) {
/* await */
getAllMessages(channelState.channelName, channelState.paths).then(function (allMessages) {
return cleanOldMessages(allMessages, channelState.options.node.ttl);
});
}
return _context3.abrupt("return", writeToReadersPromise);
return _context13.abrupt('return', writeToReadersPromise);
case 12:
case 'end':
return _context13.stop();
}
}
}, _callee13, _this2);
})));
return channelState.writeBlockPromise;
case 11:
case "end":
return _context3.stop();
}
}
}, _callee3, this);
})));
return channelState.writeBlockPromise;
}
/**

@@ -830,101 +863,99 @@ * When multiple BroadcastChannels with the same name

*/
function emitOverFastPath(state, msgObj, messageJson) {
if (!state.options.node.useFastPath) return; // disabled
var others = OTHER_INSTANCES[state.channelName].filter(function (s) {
return s !== state;
});
if (!state.options.node.useFastPath) return; // disabled
var checkObj = {
time: msgObj.time,
senderUuid: msgObj.uuid,
token: msgObj.token
};
others.filter(function (otherState) {
return _filterMessage(checkObj, otherState);
}).forEach(function (otherState) {
otherState.messagesCallback(messageJson);
});
var others = OTHER_INSTANCES[state.channelName].filter(function (s) {
return s !== state;
});
var checkObj = {
time: msgObj.time,
senderUuid: msgObj.uuid,
token: msgObj.token
};
others.filter(function (otherState) {
return _filterMessage(checkObj, otherState);
}).forEach(function (otherState) {
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);
var time = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : microSeconds();
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
handleMessagePing(channelState);
}
function close(channelState) {
if (channelState.closed) return;
channelState.closed = true;
channelState.emittedMessagesIds.clear();
OTHER_INSTANCES[channelState.channelName] = OTHER_INSTANCES[channelState.channelName].filter(function (o) {
return o !== channelState;
});
if (channelState.closed) return;
channelState.closed = true;
channelState.emittedMessagesIds.clear();
OTHER_INSTANCES[channelState.channelName] = OTHER_INSTANCES[channelState.channelName].filter(function (o) {
return o !== channelState;
});
if (channelState.removeUnload) {
channelState.removeUnload.remove();
}
if (channelState.removeUnload) {
channelState.removeUnload.remove();
}
/**
* the server get closed lazy because others might still write on it
* and have not found out that the infoFile was deleted
*/
/**
* the server get closed lazy because others might still write on it
* and have not found out that the infoFile was deleted
*/
setTimeout(function () {
return channelState.socketEE.server.close();
}, 200);
channelState.socketEE.emitter.removeAllListeners();
Object.values(channelState.otherReaderClients).forEach(function (client) {
return client.destroy();
});
unlink(channelState.infoFilePath)['catch'](function () {
return null;
});
setTimeout(function () {
return channelState.socketEE.server.close();
}, 200);
channelState.socketEE.emitter.removeAllListeners();
Object.values(channelState.otherReaderClients).forEach(function (client) {
return client.destroy();
});
unlink(channelState.infoFilePath)["catch"](function () {
return null;
});
}
function canBeUsed() {
return isNode;
return isNode;
}
function averageResponseTime() {
return 50;
return 50;
}
function microSeconds() {
return parseInt(micro.microseconds());
return parseInt(micro.microseconds());
}
module.exports = {
cleanPipeName: cleanPipeName,
getPaths: getPaths,
ensureFoldersExist: ensureFoldersExist,
clearNodeFolder: clearNodeFolder,
socketPath: socketPath,
socketInfoPath: socketInfoPath,
createSocketInfoFile: createSocketInfoFile,
createSocketEventEmitter: createSocketEventEmitter,
openClientConnection: openClientConnection,
writeMessage: writeMessage,
getReadersUuids: getReadersUuids,
messagePath: messagePath,
getAllMessages: getAllMessages,
getSingleMessage: getSingleMessage,
readMessage: readMessage,
cleanOldMessages: cleanOldMessages,
type: type,
create: create,
_filterMessage: _filterMessage,
handleMessagePing: handleMessagePing,
refreshReaderClients: refreshReaderClients,
postMessage: postMessage,
emitOverFastPath: emitOverFastPath,
onMessage: onMessage,
close: close,
canBeUsed: canBeUsed,
averageResponseTime: averageResponseTime,
microSeconds: microSeconds
cleanPipeName: cleanPipeName,
getPaths: getPaths,
ensureFoldersExist: ensureFoldersExist,
clearNodeFolder: clearNodeFolder,
socketPath: socketPath,
socketInfoPath: socketInfoPath,
createSocketInfoFile: createSocketInfoFile,
createSocketEventEmitter: createSocketEventEmitter,
openClientConnection: openClientConnection,
writeMessage: writeMessage,
getReadersUuids: getReadersUuids,
messagePath: messagePath,
getAllMessages: getAllMessages,
getSingleMessage: getSingleMessage,
readMessage: readMessage,
cleanOldMessages: cleanOldMessages,
type: type,
create: create,
_filterMessage: _filterMessage,
handleMessagePing: handleMessagePing,
refreshReaderClients: refreshReaderClients,
postMessage: postMessage,
emitOverFastPath: emitOverFastPath,
onMessage: onMessage,
close: close,
canBeUsed: canBeUsed,
averageResponseTime: averageResponseTime,
microSeconds: microSeconds
};
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
value: true
});
exports["default"] = void 0;
/**

@@ -10,44 +12,46 @@ *

*/
var ObliviousSet = function ObliviousSet(ttl) {
this.ttl = ttl;
this.set = new Set();
this.timeMap = new Map();
this.has = this.set.has.bind(this.set);
this.ttl = ttl;
this.set = new Set();
this.timeMap = new Map();
this.has = this.set.has.bind(this.set);
};
ObliviousSet.prototype = {
_removeTooOldValues: function _removeTooOldValues() {
var olderThen = now() - this.ttl;
var iterator = this.set[Symbol.iterator]();
_removeTooOldValues: function _removeTooOldValues() {
var olderThen = now() - this.ttl;
var iterator = this.set[Symbol.iterator]();
while (true) {
var value = iterator.next().value;
if (!value) return; // no more elements
var time = this.timeMap.get(value);
if (time < olderThen) {
this.timeMap["delete"](value);
this.set["delete"](value);
} else {
// we reached a value that is not old enough
return;
}
}
},
add: function add(value) {
this.timeMap.set(value, now());
this.set.add(value);
this._removeTooOldValues();
},
clear: function clear() {
this.set.clear();
this.timeMap.clear();
while (true) {
var value = iterator.next().value;
if (!value) return; // no more elements
var time = this.timeMap.get(value);
if (time < olderThen) {
this.timeMap["delete"](value);
this.set["delete"](value);
} else {
// we reached a value that is not old enough
return;
}
}
},
add: function add(value) {
this.timeMap.set(value, now());
this.set.add(value);
this._removeTooOldValues();
},
clear: function clear() {
this.set.clear();
this.timeMap.clear();
}
};
function now() {
return new Date().getTime();
return new Date().getTime();
}
exports["default"] = ObliviousSet;
var _default = ObliviousSet;
exports["default"] = _default;

@@ -1,30 +0,27 @@

'use strict';
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
value: true
});
exports.fillOptionsWithDefaults = fillOptionsWithDefaults;
function fillOptionsWithDefaults(options) {
if (!options) options = {};
options = JSON.parse(JSON.stringify(options));
if (!options) options = {};
options = JSON.parse(JSON.stringify(options)); // main
// main
if (typeof options.webWorkerSupport === 'undefined') options.webWorkerSupport = true;
if (typeof options.webWorkerSupport === 'undefined') options.webWorkerSupport = true; // indexed-db
// 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;
if (!options.idb) options.idb = {}; // after this time the messages get deleted
// localstorage
if (!options.localstorage) options.localstorage = {};
if (!options.localstorage.removeTimeout) options.localstorage.removeTimeout = 1000 * 60;
if (!options.idb.ttl) options.idb.ttl = 1000 * 45;
if (!options.idb.fallbackInterval) options.idb.fallbackInterval = 150; // localstorage
// node
if (!options.node) options.node = {};
if (!options.node.ttl) options.node.ttl = 1000 * 60 * 2; // 2 minutes;
if (typeof options.node.useFastPath === 'undefined') options.node.useFastPath = true;
if (!options.localstorage) options.localstorage = {};
if (!options.localstorage.removeTimeout) options.localstorage.removeTimeout = 1000 * 60; // node
return options;
if (!options.node) options.node = {};
if (!options.node.ttl) options.node.ttl = 1000 * 60 * 2; // 2 minutes;
if (typeof options.node.useFastPath === 'undefined') options.node.useFastPath = true;
return options;
}

@@ -1,5 +0,5 @@

'use strict';
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
value: true
});

@@ -11,2 +11,3 @@ exports.isPromise = isPromise;

exports.microSeconds = microSeconds;
/**

@@ -16,31 +17,34 @@ * returns true if the given object is a promise

function isPromise(obj) {
if (obj && typeof obj.then === 'function') {
return true;
} else {
return false;
}
if (obj && typeof obj.then === 'function') {
return true;
} else {
return false;
}
}
function sleep(time) {
if (!time) time = 0;
return new Promise(function (res) {
return setTimeout(res, time);
});
if (!time) time = 0;
return new Promise(function (res) {
return setTimeout(res, time);
});
}
function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
return Math.floor(Math.random() * (max - min + 1) + min);
}
/**
* https://stackoverflow.com/a/1349426/3443137
*/
function randomToken(length) {
if (!length) length = 5;
var text = '';
var possible = 'abcdefghijklmnopqrstuvwxzy0123456789';
if (!length) length = 5;
var text = '';
var possible = 'abcdefghijklmnopqrstuvwxzy0123456789';
for (var i = 0; i < length; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}return text;
for (var i = 0; i < length; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}

@@ -50,3 +54,2 @@

var additional = 0;
/**

@@ -59,12 +62,14 @@ * returns the current time in micro-seconds,

*/
function microSeconds() {
var ms = new Date().getTime();
if (ms === lastMs) {
additional++;
return ms * 1000 + additional;
} else {
lastMs = ms;
additional = 0;
return ms * 1000;
}
var ms = new Date().getTime();
if (ms === lastMs) {
additional++;
return ms * 1000 + additional;
} else {
lastMs = ms;
additional = 0;
return ms * 1000;
}
}
{
"name": "broadcast-channel",
"version": "2.1.0",
"version": "2.1.1",
"description": "A BroadcastChannel implementation that works with new browsers, older browsers and Node.js",

@@ -46,4 +46,4 @@ "homepage": "https://github.com/pubkey/broadcast-channel#readme",

"build:es6": "rimraf -rf dist/es && cross-env NODE_ENV=es6 babel src --out-dir dist/es",
"build:es5": "cross-env NODE_ENV=es5 node node_modules/babel-cli/bin/babel.js src --out-dir dist/lib",
"build:test": "cross-env NODE_ENV=es5 node node_modules/babel-cli/bin/babel.js test --out-dir test_tmp",
"build:es5": "cross-env NODE_ENV=es5 babel src --out-dir dist/lib",
"build:test": "cross-env NODE_ENV=es5 babel test --out-dir test_tmp",
"build:browser": "browserify test_tmp/scripts/index.js > docs/index.js",

@@ -62,3 +62,3 @@ "build:worker": "browserify test_tmp/scripts/worker.js > docs/worker.js",

"dependencies": {
"babel-runtime": "6.26.0",
"@babel/runtime": "7.0.0",
"custom-idle-queue": "2.0.1",

@@ -73,26 +73,15 @@ "detect-node": "2.0.4",

"devDependencies": {
"@babel/cli": "7.0.0",
"@babel/core": "7.0.0",
"@babel/types": "7.0.0-beta.51",
"@babel/plugin-check-constants": "7.0.0-beta.38",
"@babel/plugin-proposal-object-rest-spread": "7.0.0",
"@babel/plugin-transform-member-expression-literals": "7.0.0",
"@babel/plugin-transform-property-literals": "7.0.0",
"@babel/plugin-transform-runtime": "7.0.0",
"@babel/polyfill": "7.0.0",
"@babel/preset-env": "7.0.0",
"@babel/types": "7.0.0",
"@types/core-js": "2.5.0",
"assert": "1.4.1",
"async-test-util": "1.6.1",
"babel-cli": "6.26.0",
"babel-core": "6.26.3",
"babel-loader": "8.0.2",
"babel-plugin-transform-async-to-generator": "6.24.1",
"babel-plugin-transform-class-properties": "6.24.1",
"babel-plugin-transform-es2015-block-scoping": "6.26.0",
"babel-plugin-transform-es2015-constants": "6.1.4",
"babel-plugin-transform-es3-member-expression-literals": "6.22.0",
"babel-plugin-transform-es3-property-literals": "6.22.0",
"babel-plugin-transform-object-rest-spread": "6.26.0",
"babel-plugin-transform-regenerator": "6.26.0",
"babel-plugin-transform-runtime": "6.23.0",
"babel-polyfill": "6.26.0",
"babel-preset-es2015": "6.24.1",
"babel-preset-es2015-native-modules": "6.9.4",
"babel-preset-es2015-rollup": "3.0.0",
"babel-preset-es2016": "6.24.1",
"babel-preset-es2017": "6.24.1",
"babel-preset-latest": "6.24.1",
"browserify": "16.2.2",

@@ -103,3 +92,3 @@ "child-process-promise": "2.2.1",

"convert-hrtime": "2.0.0",
"copyfiles": "2.0.0",
"copyfiles": "2.1.0",
"cross-env": "5.2.0",

@@ -126,3 +115,3 @@ "eslint": "5.5.0",

"random-token": "0.0.8",
"testcafe": "0.21.1",
"testcafe": "0.22.0",
"testcafe-hammerhead": "14.2.6",

@@ -129,0 +118,0 @@ "ts-node": "7.0.1",

@@ -20,11 +20,16 @@ import {

this._isListening = false;
// isListening
this._iL = false;
/**
* _onMessageListener
* setting onmessage twice,
* will overwrite the first listener
*/
this._onMessageListener = null;
this._onML = null;
this._addEventListeners = {
/**
* _addEventListeners
*/
this._addEL = {
message: [],

@@ -35,8 +40,12 @@ internal: []

/**
* _beforeClose
* array of promises that will be awaited
* before the channel is closed
*/
this._beforeClose = [];
this._befC = [];
this._preparePromise = null;
/**
* _preparePromise
*/
this._prepP = null;
_prepareChannel(this);

@@ -70,18 +79,2 @@ };

BroadcastChannel.prototype = {
_post(type, msg) {
const time = this.method.microSeconds();
const msgObj = {
time,
type,
data: msg
};
const awaitPrepare = this._preparePromise ? this._preparePromise : Promise.resolve();
return awaitPrepare.then(() => {
return this.method.postMessage(
this._state,
msgObj
);
});
},
postMessage(msg) {

@@ -94,6 +87,6 @@ if (this.closed) {

}
return this._post('message', msg);
return _post(this, 'message', msg);
},
postInternal(msg) {
return this._post('internal', msg);
return _post(this, 'internal', msg);
},

@@ -106,8 +99,8 @@ set onmessage(fn) {

};
_removeListenerObject(this, 'message', this._onMessageListener);
_removeListenerObject(this, 'message', this._onML);
if (fn && typeof fn === 'function') {
this._onMessageListener = listenObj;
this._onML = listenObj;
_addListenerObject(this, 'message', listenObj);
} else {
this._onMessageListener = null;
this._onML = null;
}

@@ -125,3 +118,3 @@ },

removeEventListener(type, fn) {
const obj = this._addEventListeners[type].find(obj => obj.fn === fn);
const obj = this._addEL[type].find(obj => obj.fn === fn);
_removeListenerObject(this, type, obj);

@@ -133,9 +126,9 @@ },

this.closed = true;
const awaitPrepare = this._preparePromise ? this._preparePromise : Promise.resolve();
const awaitPrepare = this._prepP ? this._prepP : Promise.resolve();
this._onMessageListener = null;
this._addEventListeners.message = [];
this._onML = null;
this._addEL.message = [];
return awaitPrepare
.then(() => Promise.all(this._beforeClose.map(fn => fn())))
.then(() => Promise.all(this._befC.map(fn => fn())))
.then(() => {

@@ -152,6 +145,24 @@ return this.method.close(

function _post(broadcastChannel, type, msg) {
const time = broadcastChannel.method.microSeconds();
const msgObj = {
time,
type,
data: msg
};
const awaitPrepare = broadcastChannel._prepP ? broadcastChannel._prepP : Promise.resolve();
return awaitPrepare.then(() => {
return broadcastChannel.method.postMessage(
broadcastChannel._state,
msgObj
);
});
}
function _prepareChannel(channel) {
const maybePromise = channel.method.create(channel.name, channel.options);
if (isPromise(maybePromise)) {
channel._preparePromise = maybePromise;
channel._prepP = maybePromise;
maybePromise.then(s => {

@@ -171,4 +182,4 @@ // used in tests to simulate slow runtime

function _hasMessageListeners(channel) {
if (channel._addEventListeners.message.length > 0) return true;
if (channel._addEventListeners.internal.length > 0) return true;
if (channel._addEL.message.length > 0) return true;
if (channel._addEL.internal.length > 0) return true;
return false;

@@ -178,3 +189,3 @@ }

function _addListenerObject(channel, type, obj) {
channel._addEventListeners[type].push(obj);
channel._addEL[type].push(obj);
_startListening(channel);

@@ -184,3 +195,3 @@ }

function _removeListenerObject(channel, type, obj) {
channel._addEventListeners[type] = channel._addEventListeners[type].filter(o => o !== obj);
channel._addEL[type] = channel._addEL[type].filter(o => o !== obj);
_stopListening(channel);

@@ -190,7 +201,7 @@ }

function _startListening(channel) {
if (!channel._isListening && _hasMessageListeners(channel)) {
if (!channel._iL && _hasMessageListeners(channel)) {
// someone is listening, start subscribing
const listenerFn = msgObj => {
channel._addEventListeners[msgObj.type].forEach(obj => {
channel._addEL[msgObj.type].forEach(obj => {
if (msgObj.time >= obj.time) {

@@ -203,5 +214,5 @@ obj.fn(msgObj.data);

const time = channel.method.microSeconds();
if (channel._preparePromise) {
channel._preparePromise.then(() => {
channel._isListening = true;
if (channel._prepP) {
channel._prepP.then(() => {
channel._iL = true;
channel.method.onMessage(

@@ -214,3 +225,3 @@ channel._state,

} else {
channel._isListening = true;
channel._iL = true;
channel.method.onMessage(

@@ -226,5 +237,5 @@ channel._state,

function _stopListening(channel) {
if (channel._isListening && !_hasMessageListeners(channel)) {
if (channel._iL && !_hasMessageListeners(channel)) {
// noone is listening, stop subscribing
channel._isListening = false;
channel._iL = false;
const time = channel.method.microSeconds();

@@ -231,0 +242,0 @@ channel.method.onMessage(

@@ -8,3 +8,3 @@ import {

const LeaderElection = function (channel, options) {
const LeaderElection = function(channel, options) {
this._channel = channel;

@@ -17,13 +17,12 @@ this._options = options;

this._isApplying = false;
this._isApl = false; // _isApplying
this._reApply = false;
// things to clean up
this._unloads = [];
this._listeners = [];
this._intervals = [];
this._unl = []; // _unloads
this._lstns = []; // _listeners
this._invs = []; // _intervals
};
LeaderElection.prototype = {
applyOnce() {

@@ -34,7 +33,7 @@ if (this.isLeader) return Promise.resolve(false);

// do nothing if already running
if (this._isApplying) {
if (this._isApl) {
this._reApply = true;
return Promise.resolve(false);
}
this._isApplying = true;
this._isApl = true;

@@ -66,7 +65,7 @@ let stopCriteria = false;

const ret = this._sendMessage('apply') // send out that this one is applying
const ret = _sendMessage(this, 'apply') // send out that this one is applying
.then(() => sleep(this._options.responseTime)) // let others time to respond
.then(() => {
if (stopCriteria) return Promise.reject(new Error());
else return this._sendMessage('apply');
else return _sendMessage(this, 'apply');
})

@@ -76,5 +75,5 @@ .then(() => sleep(this._options.responseTime)) // let others time to respond

if (stopCriteria) return Promise.reject(new Error());
else return this._sendMessage();
else return _sendMessage(this);
})
.then(() => this._beLeader()) // no one disagreed -> this one is now leader
.then(() => _beLeader(this)) // no one disagreed -> this one is now leader
.then(() => true)

@@ -84,3 +83,3 @@ .catch(() => false) // apply not successfull

this._channel.removeEventListener('internal', handleMessage);
this._isApplying = false;
this._isApl = false;
if (!success && this._reApply) {

@@ -94,45 +93,5 @@ this._reApply = false;

_awaitLeadershipOnce() {
if (this.isLeader) return Promise.resolve();
return new Promise((res) => {
let resolved = false;
const finish = () => {
if (resolved) return;
resolved = true;
clearInterval(interval);
this._channel.removeEventListener('internal', whenDeathListener);
res(true);
};
// try once now
this.applyOnce().then(() => {
if (this.isLeader) finish();
});
// try on fallbackInterval
const interval = setInterval(() => {
this.applyOnce().then(() => {
if (this.isLeader) finish();
});
}, this._options.fallbackInterval);
this._intervals.push(interval);
// try when other leader dies
const whenDeathListener = msg => {
if (msg.context === 'leader' && msg.action === 'death') {
this.applyOnce().then(() => {
if (this.isLeader) finish();
});
}
};
this._channel.addEventListener('internal', whenDeathListener);
this._listeners.push(whenDeathListener);
});
},
awaitLeadership() {
if (!this._awaitLeadershipPromise) {
this._awaitLeadershipPromise = this._awaitLeadershipOnce();
this._awaitLeadershipPromise = _awaitLeadershipOnce(this);
}

@@ -146,38 +105,79 @@ return this._awaitLeadershipPromise;

this._listeners.forEach(listener => this._channel.removeEventListener('internal', listener));
this._intervals.forEach(interval => clearInterval(interval));
this._unloads.forEach(uFn => {
this._lstns.forEach(listener => this._channel.removeEventListener('internal', listener));
this._invs.forEach(interval => clearInterval(interval));
this._unl.forEach(uFn => {
uFn.remove();
});
return this._sendMessage('death');
},
return _sendMessage(this, 'death');
}
};
/**
* sends and internal message over the broadcast-channel
*/
_sendMessage(action) {
const msgJson = {
context: 'leader',
action,
token: this.token
function _awaitLeadershipOnce(leaderElector) {
if (leaderElector.isLeader) return Promise.resolve();
return new Promise((res) => {
let resolved = false;
const finish = () => {
if (resolved) return;
resolved = true;
clearInterval(interval);
leaderElector._channel.removeEventListener('internal', whenDeathListener);
res(true);
};
return this._channel.postInternal(msgJson);
},
_beLeader() {
this.isLeader = true;
const unloadFn = unload.add(() => this.die());
this._unloads.push(unloadFn);
// try once now
leaderElector.applyOnce().then(() => {
if (leaderElector.isLeader) finish();
});
const isLeaderListener = msg => {
if (msg.context === 'leader' && msg.action === 'apply') {
this._sendMessage('tell');
// try on fallbackInterval
const interval = setInterval(() => {
leaderElector.applyOnce().then(() => {
if (leaderElector.isLeader) finish();
});
}, leaderElector._options.fallbackInterval);
leaderElector._invs.push(interval);
// try when other leader dies
const whenDeathListener = msg => {
if (msg.context === 'leader' && msg.action === 'death') {
leaderElector.applyOnce().then(() => {
if (leaderElector.isLeader) finish();
});
}
};
this._channel.addEventListener('internal', isLeaderListener);
this._listeners.push(isLeaderListener);
return this._sendMessage('tell');
}
};
leaderElector._channel.addEventListener('internal', whenDeathListener);
leaderElector._lstns.push(whenDeathListener);
});
}
/**
* sends and internal message over the broadcast-channel
*/
function _sendMessage(leaderElector, action) {
const msgJson = {
context: 'leader',
action,
token: leaderElector.token
};
return leaderElector._channel.postInternal(msgJson);
}
function _beLeader(leaderElector) {
leaderElector.isLeader = true;
const unloadFn = unload.add(() => leaderElector.die());
leaderElector._unl.push(unloadFn);
const isLeaderListener = msg => {
if (msg.context === 'leader' && msg.action === 'apply') {
_sendMessage(leaderElector, 'tell');
}
};
leaderElector._channel.addEventListener('internal', isLeaderListener);
leaderElector._lstns.push(isLeaderListener);
return _sendMessage(leaderElector, 'tell');
}
function fillOptionsWithDefaults(options, channel) {

@@ -205,3 +205,3 @@ if (!options) options = {};

const elector = new LeaderElection(channel, options);
channel._beforeClose.push(() => elector.die());
channel._befC.push(() => elector.die());

@@ -215,2 +215,2 @@ channel._leaderElector = elector;

create
};
};
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc