197 lines
5.2 KiB
JavaScript
197 lines
5.2 KiB
JavaScript
"use strict";
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
exports.getLocalStorage = getLocalStorage;
|
|
exports.storageKey = storageKey;
|
|
exports.postMessage = postMessage;
|
|
exports.addStorageEventListener = addStorageEventListener;
|
|
exports.removeStorageEventListener = removeStorageEventListener;
|
|
exports.create = create;
|
|
exports.close = close;
|
|
exports.onMessage = onMessage;
|
|
exports.canBeUsed = canBeUsed;
|
|
exports.averageResponseTime = averageResponseTime;
|
|
exports["default"] = exports.type = exports.microSeconds = void 0;
|
|
|
|
var _obliviousSet = require("oblivious-set");
|
|
|
|
var _options = require("../options");
|
|
|
|
var _util = require("../util");
|
|
|
|
/**
|
|
* A localStorage-only method which uses localstorage and its 'storage'-event
|
|
* This does not work inside of webworkers because they have no access to locastorage
|
|
* This is basically implemented to support IE9 or your grandmothers toaster.
|
|
* @link https://caniuse.com/#feat=namevalue-storage
|
|
* @link https://caniuse.com/#feat=indexeddb
|
|
*/
|
|
var microSeconds = _util.microSeconds;
|
|
exports.microSeconds = microSeconds;
|
|
var KEY_PREFIX = 'pubkey.broadcastChannel-';
|
|
var type = 'localstorage';
|
|
/**
|
|
* copied from crosstab
|
|
* @link https://github.com/tejacques/crosstab/blob/master/src/crosstab.js#L32
|
|
*/
|
|
|
|
exports.type = type;
|
|
|
|
function getLocalStorage() {
|
|
var localStorage;
|
|
if (typeof window === 'undefined') return null;
|
|
|
|
try {
|
|
localStorage = window.localStorage;
|
|
localStorage = window['ie8-eventlistener/storage'] || window.localStorage;
|
|
} catch (e) {// New versions of Firefox throw a Security exception
|
|
// if cookies are disabled. See
|
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=1028153
|
|
}
|
|
|
|
return localStorage;
|
|
}
|
|
|
|
function storageKey(channelName) {
|
|
return KEY_PREFIX + channelName;
|
|
}
|
|
/**
|
|
* writes the new message to the storage
|
|
* and fires the storage-event so other readers can find it
|
|
*/
|
|
|
|
|
|
function postMessage(channelState, messageJson) {
|
|
return new Promise(function (res) {
|
|
(0, _util.sleep)().then(function () {
|
|
var key = storageKey(channelState.channelName);
|
|
var writeObj = {
|
|
token: (0, _util.randomToken)(),
|
|
time: new Date().getTime(),
|
|
data: messageJson,
|
|
uuid: channelState.uuid
|
|
};
|
|
var value = JSON.stringify(writeObj);
|
|
getLocalStorage().setItem(key, value);
|
|
/**
|
|
* StorageEvent does not fire the 'storage' event
|
|
* in the window that changes the state of the local storage.
|
|
* So we fire it manually
|
|
*/
|
|
|
|
var ev = document.createEvent('Event');
|
|
ev.initEvent('storage', true, true);
|
|
ev.key = key;
|
|
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;
|
|
}
|
|
|
|
function removeStorageEventListener(listener) {
|
|
window.removeEventListener('storage', listener);
|
|
}
|
|
|
|
function create(channelName, options) {
|
|
options = (0, _options.fillOptionsWithDefaults)(options);
|
|
|
|
if (!canBeUsed()) {
|
|
throw new Error('BroadcastChannel: localstorage cannot be used');
|
|
}
|
|
|
|
var uuid = (0, _util.randomToken)();
|
|
/**
|
|
* eMIs
|
|
* contains all messages that have been emitted before
|
|
* @type {ObliviousSet}
|
|
*/
|
|
|
|
var eMIs = new _obliviousSet.ObliviousSet(options.localstorage.removeTimeout);
|
|
var state = {
|
|
channelName: channelName,
|
|
uuid: uuid,
|
|
eMIs: eMIs // emittedMessagesIds
|
|
|
|
};
|
|
state.listener = addStorageEventListener(channelName, function (msgObj) {
|
|
if (!state.messagesCallback) return; // no listener
|
|
|
|
if (msgObj.uuid === uuid) return; // own message
|
|
|
|
if (!msgObj.token || eMIs.has(msgObj.token)) return; // already emitted
|
|
|
|
if (msgObj.data.time && msgObj.data.time < state.messagesCallbackTime) return; // too old
|
|
|
|
eMIs.add(msgObj.token);
|
|
state.messagesCallback(msgObj.data);
|
|
});
|
|
return state;
|
|
}
|
|
|
|
function close(channelState) {
|
|
removeStorageEventListener(channelState.listener);
|
|
}
|
|
|
|
function onMessage(channelState, fn, time) {
|
|
channelState.messagesCallbackTime = time;
|
|
channelState.messagesCallback = fn;
|
|
}
|
|
|
|
function canBeUsed() {
|
|
if (_util.isNode) return false;
|
|
var ls = getLocalStorage();
|
|
if (!ls) return false;
|
|
|
|
try {
|
|
var key = '__broadcastchannel_check';
|
|
ls.setItem(key, 'works');
|
|
ls.removeItem(key);
|
|
} catch (e) {
|
|
// Safari 10 in private mode will not allow write access to local
|
|
// storage and fail with a QuotaExceededError. See
|
|
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API#Private_Browsing_Incognito_modes
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
function averageResponseTime() {
|
|
var defaultTime = 120;
|
|
var userAgent = navigator.userAgent.toLowerCase();
|
|
|
|
if (userAgent.includes('safari') && !userAgent.includes('chrome')) {
|
|
// safari is much slower so this time is higher
|
|
return defaultTime * 2;
|
|
}
|
|
|
|
return defaultTime;
|
|
}
|
|
|
|
var _default = {
|
|
create: create,
|
|
close: close,
|
|
onMessage: onMessage,
|
|
postMessage: postMessage,
|
|
canBeUsed: canBeUsed,
|
|
type: type,
|
|
averageResponseTime: averageResponseTime,
|
|
microSeconds: microSeconds
|
|
};
|
|
exports["default"] = _default; |