broadcast-channel
Advanced tools
Comparing version 0.0.1 to 1.0.0
@@ -1,4 +0,3 @@ | ||
require('babel-polyfill'); | ||
var BroadcastChannel = require('./index.js'); | ||
window['BroadcastChannel2'] = BroadcastChannel; |
@@ -1,5 +0,1 @@ | ||
import _regeneratorRuntime from 'babel-runtime/regenerator'; | ||
import _asyncToGenerator from 'babel-runtime/helpers/asyncToGenerator'; | ||
import _classCallCheck from 'babel-runtime/helpers/classCallCheck'; | ||
import _createClass from 'babel-runtime/helpers/createClass'; | ||
import { isPromise } from './util.js'; | ||
@@ -11,8 +7,7 @@ | ||
var BroadcastChannel = function () { | ||
function BroadcastChannel(name) { | ||
module.exports = function () { | ||
var BroadcastChannel = function BroadcastChannel(name) { | ||
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
_classCallCheck(this, BroadcastChannel); | ||
this.name = name; | ||
@@ -24,129 +19,47 @@ this.options = fillOptionsWithDefaults(options); | ||
this._prepare(); | ||
} | ||
BroadcastChannel.prototype._prepare = function _prepare() { | ||
var _this = this; | ||
var maybePromise = this.method.create(this.name, this.options); | ||
if (isPromise(maybePromise)) { | ||
this._preparePromise = maybePromise; | ||
maybePromise.then(function () { | ||
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(s) { | ||
return _regeneratorRuntime.wrap(function _callee$(_context) { | ||
while (1) { | ||
switch (_context.prev = _context.next) { | ||
case 0: | ||
// used in tests to simulate slow runtime | ||
if (_this.options.prepareDelay) { | ||
// await new Promise(res => setTimeout(res, this.options.prepareDelay)); | ||
} | ||
_this._state = s; | ||
case 2: | ||
case 'end': | ||
return _context.stop(); | ||
} | ||
} | ||
}, _callee, _this); | ||
})); | ||
return function (_x2) { | ||
return _ref.apply(this, arguments); | ||
}; | ||
}()); | ||
} else { | ||
this._state = maybePromise; | ||
} | ||
}; | ||
BroadcastChannel.prototype.postMessage = function () { | ||
var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(msg) { | ||
var msgObj; | ||
return _regeneratorRuntime.wrap(function _callee2$(_context2) { | ||
while (1) { | ||
switch (_context2.prev = _context2.next) { | ||
case 0: | ||
msgObj = { | ||
time: new Date().getTime(), | ||
data: msg | ||
}; | ||
BroadcastChannel.prototype = { | ||
_prepare: function _prepare() { | ||
var _this = this; | ||
if (!this.closed) { | ||
_context2.next = 3; | ||
break; | ||
} | ||
throw new Error('BroadcastChannel.postMessage(): ' + 'Cannot post message after channel has closed'); | ||
case 3: | ||
if (!this._preparePromise) { | ||
_context2.next = 6; | ||
break; | ||
} | ||
_context2.next = 6; | ||
return this._preparePromise; | ||
case 6: | ||
return _context2.abrupt('return', this.method.postMessage(this._state, msgObj)); | ||
case 7: | ||
case 'end': | ||
return _context2.stop(); | ||
var maybePromise = this.method.create(this.name, this.options); | ||
if (isPromise(maybePromise)) { | ||
this._preparePromise = maybePromise; | ||
maybePromise.then(function (s) { | ||
// used in tests to simulate slow runtime | ||
if (_this.options.prepareDelay) { | ||
// await new Promise(res => setTimeout(res, this.options.prepareDelay)); | ||
} | ||
} | ||
}, _callee2, this); | ||
})); | ||
_this._state = s; | ||
}); | ||
} else { | ||
this._state = maybePromise; | ||
} | ||
}, | ||
postMessage: function postMessage(msg) { | ||
var _this2 = this; | ||
function postMessage(_x3) { | ||
return _ref2.apply(this, arguments); | ||
} | ||
var msgObj = { | ||
time: new Date().getTime(), | ||
data: msg | ||
}; | ||
return postMessage; | ||
}(); | ||
if (this.closed) { | ||
throw new Error('BroadcastChannel.postMessage(): ' + 'Cannot post message after channel has closed'); | ||
} | ||
BroadcastChannel.prototype.close = function () { | ||
var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3() { | ||
return _regeneratorRuntime.wrap(function _callee3$(_context3) { | ||
while (1) { | ||
switch (_context3.prev = _context3.next) { | ||
case 0: | ||
this.closed = true; | ||
var awaitPrepare = this._preparePromise ? this._preparePromise : Promise.resolve(); | ||
return awaitPrepare.then(function () { | ||
return _this2.method.postMessage(_this2._state, msgObj); | ||
}); | ||
}, | ||
if (!this._preparePromise) { | ||
_context3.next = 4; | ||
break; | ||
} | ||
set onmessage(fn) { | ||
var _this3 = this; | ||
_context3.next = 4; | ||
return this._preparePromise; | ||
case 4: | ||
_context3.next = 6; | ||
return this.method.close(this._state); | ||
case 6: | ||
case 'end': | ||
return _context3.stop(); | ||
} | ||
} | ||
}, _callee3, this); | ||
})); | ||
function close() { | ||
return _ref3.apply(this, arguments); | ||
} | ||
return close; | ||
}(); | ||
_createClass(BroadcastChannel, [{ | ||
key: 'onmessage', | ||
set: function set(fn) { | ||
var _this2 = this; | ||
var time = new Date().getTime() - 5; | ||
if (this._preparePromise) { | ||
this._preparePromise.then(function () { | ||
_this2.method.onMessage(_this2._state, messageHandler(fn, time), time); | ||
_this3.method.onMessage(_this3._state, messageHandler(fn, time), time); | ||
}); | ||
@@ -156,24 +69,27 @@ } else { | ||
} | ||
} | ||
}, { | ||
key: 'type', | ||
get: function get() { | ||
return this.method.type; | ||
} | ||
}]); | ||
}, | ||
close: function close() { | ||
var _this4 = this; | ||
return BroadcastChannel; | ||
}(); | ||
this.closed = true; | ||
var awaitPrepare = this._preparePromise ? this._preparePromise : Promise.resolve(); | ||
return awaitPrepare.then(function () { | ||
return _this4.method.close(_this4._state); | ||
}); | ||
}, | ||
; | ||
function messageHandler(fn, minTime) { | ||
return function (msgObj) { | ||
if (msgObj.time >= minTime) { | ||
fn(msgObj.data); | ||
get type() { | ||
return this.method.type; | ||
} | ||
}; | ||
} | ||
export default BroadcastChannel; | ||
module.exports = BroadcastChannel; | ||
function messageHandler(fn, minTime) { | ||
return function (msgObj) { | ||
if (msgObj.time >= minTime) { | ||
fn(msgObj.data); | ||
} | ||
}; | ||
}; | ||
return BroadcastChannel; | ||
}(); |
@@ -1,7 +0,6 @@ | ||
import _JSON$stringify from 'babel-runtime/core-js/json/stringify'; | ||
import isNode from 'detect-node'; | ||
var isNode = require('detect-node'); | ||
import * as NativeMethod from './methods/native.js'; | ||
import * as IndexeDbMethod from './methods/indexed-db.js'; | ||
import * as LocalstorageMethod from './methods/localstorage.js'; | ||
var NativeMethod = require('./methods/native.js'); | ||
var IndexeDbMethod = require('./methods/indexed-db.js'); | ||
var LocalstorageMethod = require('./methods/localstorage.js'); | ||
@@ -12,2 +11,4 @@ // order is important | ||
var REQUIRE_FUN = require; | ||
/** | ||
@@ -18,3 +19,3 @@ * The NodeMethod is loaded lazy | ||
if (isNode) { | ||
var NodeMethod = require('./methods/node.js'); | ||
var NodeMethod = REQUIRE_FUN('./methods/node.js'); | ||
METHODS.push(NodeMethod); | ||
@@ -43,5 +44,5 @@ } | ||
}); | ||
if (!useMethod) throw new Error('No useable methode found:' + _JSON$stringify(METHODS.map(function (m) { | ||
if (!useMethod) throw new Error('No useable methode found:' + JSON.stringify(METHODS.map(function (m) { | ||
return m.type; | ||
})));else return useMethod; | ||
} |
@@ -1,6 +0,1 @@ | ||
import _getIterator from 'babel-runtime/core-js/get-iterator'; | ||
import _Set from 'babel-runtime/core-js/set'; | ||
import _regeneratorRuntime from 'babel-runtime/regenerator'; | ||
import _Promise from 'babel-runtime/core-js/promise'; | ||
import _asyncToGenerator from 'babel-runtime/helpers/asyncToGenerator'; | ||
/** | ||
@@ -14,7 +9,9 @@ * this method uses indexeddb to store the messages | ||
import isNode from 'detect-node'; | ||
import randomToken from 'random-token'; | ||
import randomInt from 'random-int'; | ||
import IdleQueue from 'custom-idle-queue'; | ||
var isNode = require('detect-node'); | ||
var randomToken = require('random-token'); | ||
var randomInt = require('random-int'); | ||
var IdleQueue = require('custom-idle-queue'); | ||
import { sleep } from '../util.js'; | ||
import { fillOptionsWithDefaults } from '../options'; | ||
@@ -36,50 +33,28 @@ | ||
export var createDatabase = function () { | ||
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(channelName) { | ||
var IndexedDB, dbName, openRequest, db; | ||
return _regeneratorRuntime.wrap(function _callee$(_context) { | ||
while (1) { | ||
switch (_context.prev = _context.next) { | ||
case 0: | ||
IndexedDB = getIdb(); | ||
export function createDatabase(channelName) { | ||
var IndexedDB = getIdb(); | ||
// create table | ||
// create table | ||
var dbName = DB_PREFIX + channelName; | ||
var openRequest = IndexedDB.open(dbName, 1); | ||
dbName = DB_PREFIX + channelName; | ||
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); | ||
}; | ||
}); | ||
return dbPromise; | ||
} | ||
openRequest.onupgradeneeded = function (ev) { | ||
var db = ev.target.result; | ||
db.createObjectStore(OBJECT_STORE_ID, { | ||
keyPath: 'id', | ||
autoIncrement: true | ||
}); | ||
}; | ||
_context.next = 6; | ||
return new _Promise(function (res, rej) { | ||
openRequest.onerror = function (ev) { | ||
return rej(ev); | ||
}; | ||
openRequest.onsuccess = function () { | ||
res(openRequest.result); | ||
}; | ||
}); | ||
case 6: | ||
db = _context.sent; | ||
return _context.abrupt('return', db); | ||
case 8: | ||
case 'end': | ||
return _context.stop(); | ||
} | ||
} | ||
}, _callee, this); | ||
})); | ||
return function createDatabase(_x) { | ||
return _ref.apply(this, arguments); | ||
}; | ||
}(); | ||
/** | ||
@@ -89,298 +64,145 @@ * writes the new message to the database | ||
*/ | ||
export var writeMessage = function () { | ||
var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(db, readerUuid, messageJson) { | ||
var time, writeObject, transaction; | ||
return _regeneratorRuntime.wrap(function _callee2$(_context2) { | ||
while (1) { | ||
switch (_context2.prev = _context2.next) { | ||
case 0: | ||
time = new Date().getTime(); | ||
writeObject = { | ||
uuid: readerUuid, | ||
time: time, | ||
data: messageJson | ||
}; | ||
transaction = db.transaction([OBJECT_STORE_ID], 'readwrite'); | ||
return _context2.abrupt('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); | ||
})); | ||
case 4: | ||
case 'end': | ||
return _context2.stop(); | ||
} | ||
} | ||
}, _callee2, this); | ||
})); | ||
return function writeMessage(_x2, _x3, _x4) { | ||
return _ref2.apply(this, arguments); | ||
export function writeMessage(db, readerUuid, messageJson) { | ||
var time = new Date().getTime(); | ||
var writeObject = { | ||
uuid: readerUuid, | ||
time: time, | ||
data: messageJson | ||
}; | ||
}(); | ||
export var getAllMessages = function () { | ||
var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3(db) { | ||
var objectStore, ret; | ||
return _regeneratorRuntime.wrap(function _callee3$(_context3) { | ||
while (1) { | ||
switch (_context3.prev = _context3.next) { | ||
case 0: | ||
objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID); | ||
ret = []; | ||
return _context3.abrupt('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 transaction = db.transaction([OBJECT_STORE_ID], 'readwrite'); | ||
case 3: | ||
case 'end': | ||
return _context3.stop(); | ||
} | ||
} | ||
}, _callee3, this); | ||
})); | ||
return new Promise(function (res, rej) { | ||
transaction.oncomplete = function () { | ||
return res(); | ||
}; | ||
transaction.onerror = function (ev) { | ||
return rej(ev); | ||
}; | ||
return function getAllMessages(_x5) { | ||
return _ref3.apply(this, arguments); | ||
}; | ||
}(); | ||
var objectStore = transaction.objectStore(OBJECT_STORE_ID); | ||
objectStore.add(writeObject); | ||
}); | ||
} | ||
export var getMessagesHigherThen = function () { | ||
var _ref4 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4(db, lastCursorId) { | ||
var objectStore, ret, keyRangeValue; | ||
return _regeneratorRuntime.wrap(function _callee4$(_context4) { | ||
while (1) { | ||
switch (_context4.prev = _context4.next) { | ||
case 0: | ||
objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID); | ||
ret = []; | ||
keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity); | ||
return _context4.abrupt('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); | ||
} | ||
}; | ||
})); | ||
case 4: | ||
case 'end': | ||
return _context4.stop(); | ||
} | ||
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); | ||
} | ||
}, _callee4, this); | ||
})); | ||
}; | ||
}); | ||
} | ||
return function getMessagesHigherThen(_x6, _x7) { | ||
return _ref4.apply(this, arguments); | ||
}; | ||
}(); | ||
export var removeMessageById = function () { | ||
var _ref5 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee5(db, id) { | ||
var request; | ||
return _regeneratorRuntime.wrap(function _callee5$(_context5) { | ||
while (1) { | ||
switch (_context5.prev = _context5.next) { | ||
case 0: | ||
request = db.transaction([OBJECT_STORE_ID], 'readwrite').objectStore(OBJECT_STORE_ID)['delete'](id); | ||
return _context5.abrupt('return', new _Promise(function (res) { | ||
request.onsuccess = function () { | ||
return res(); | ||
}; | ||
})); | ||
case 2: | ||
case 'end': | ||
return _context5.stop(); | ||
} | ||
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); | ||
} | ||
}, _callee5, this); | ||
})); | ||
}; | ||
}); | ||
} | ||
return function removeMessageById(_x8, _x9) { | ||
return _ref5.apply(this, arguments); | ||
}; | ||
}(); | ||
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(); | ||
}; | ||
}); | ||
} | ||
export var getOldMessages = function () { | ||
var _ref6 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee6(db, ttl) { | ||
var olderThen, objectStore, ret; | ||
return _regeneratorRuntime.wrap(function _callee6$(_context6) { | ||
while (1) { | ||
switch (_context6.prev = _context6.next) { | ||
case 0: | ||
olderThen = new Date().getTime() - ttl; | ||
objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID); | ||
ret = []; | ||
return _context6.abrupt('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); | ||
} | ||
}; | ||
})); | ||
case 4: | ||
case 'end': | ||
return _context6.stop(); | ||
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); | ||
} | ||
}, _callee6, this); | ||
})); | ||
}; | ||
}); | ||
} | ||
return function getOldMessages(_x10, _x11) { | ||
return _ref6.apply(this, arguments); | ||
}; | ||
}(); | ||
export function cleanOldMessages(db, ttl) { | ||
return getOldMessages(db, ttl).then(function (tooOld) { | ||
return Promise.all(tooOld.map(function (msgObj) { | ||
return removeMessageById(db, msgObj.id); | ||
})); | ||
}); | ||
} | ||
export var cleanOldMessages = function () { | ||
var _ref7 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee7(db, ttl) { | ||
var tooOld; | ||
return _regeneratorRuntime.wrap(function _callee7$(_context7) { | ||
while (1) { | ||
switch (_context7.prev = _context7.next) { | ||
case 0: | ||
_context7.next = 2; | ||
return getOldMessages(db, ttl); | ||
export function create(channelName, options) { | ||
options = fillOptionsWithDefaults(options); | ||
case 2: | ||
tooOld = _context7.sent; | ||
return _context7.abrupt('return', _Promise.all(tooOld.map(function (msgObj) { | ||
return removeMessageById(db, msgObj.id); | ||
}))); | ||
var uuid = randomToken(10); | ||
case 4: | ||
case 'end': | ||
return _context7.stop(); | ||
} | ||
} | ||
}, _callee7, this); | ||
})); | ||
// ensures we do not read messages in parrallel | ||
var readQueue = new IdleQueue(1); | ||
return function cleanOldMessages(_x12, _x13) { | ||
return _ref7.apply(this, arguments); | ||
}; | ||
}(); | ||
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 Set(), | ||
messagesCallback: null, | ||
readQueue: readQueue, | ||
db: db | ||
}; | ||
export var create = function () { | ||
var _ref8 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee9(channelName) { | ||
var _this = this; | ||
/** | ||
* 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); | ||
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
var uuid, readQueue, db, state; | ||
return _regeneratorRuntime.wrap(function _callee9$(_context9) { | ||
while (1) { | ||
switch (_context9.prev = _context9.next) { | ||
case 0: | ||
options = fillOptionsWithDefaults(options); | ||
return state; | ||
}); | ||
} | ||
uuid = randomToken(10); | ||
function _readLoop(state) { | ||
if (state.closed) return; | ||
// ensures we do not read messages in parrallel | ||
return handleMessagePing(state).then(function () { | ||
return sleep(state.options.idb.fallbackInterval); | ||
}).then(function () { | ||
return _readLoop(state); | ||
}); | ||
} | ||
readQueue = new IdleQueue(1); | ||
_context9.next = 5; | ||
return createDatabase(channelName); | ||
case 5: | ||
db = _context9.sent; | ||
state = { | ||
closed: false, | ||
lastCursorId: 0, | ||
channelName: channelName, | ||
options: options, | ||
uuid: uuid, | ||
// contains all messages that have been emitted before | ||
emittedMessagesIds: new _Set(), | ||
messagesCallback: null, | ||
readQueue: readQueue, | ||
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 | ||
*/ | ||
_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee8() { | ||
return _regeneratorRuntime.wrap(function _callee8$(_context8) { | ||
while (1) { | ||
switch (_context8.prev = _context8.next) { | ||
case 0: | ||
if (!(state.closed === false)) { | ||
_context8.next = 7; | ||
break; | ||
} | ||
_context8.next = 3; | ||
return handleMessagePing(state); | ||
case 3: | ||
_context8.next = 5; | ||
return new _Promise(function (res) { | ||
return setTimeout(res, state.options.idb.fallbackInterval); | ||
}); | ||
case 5: | ||
_context8.next = 0; | ||
break; | ||
case 7: | ||
case 'end': | ||
return _context8.stop(); | ||
} | ||
} | ||
}, _callee8, _this); | ||
}))(); | ||
return _context9.abrupt('return', state); | ||
case 9: | ||
case 'end': | ||
return _context9.stop(); | ||
} | ||
} | ||
}, _callee9, this); | ||
})); | ||
return function create(_x14) { | ||
return _ref8.apply(this, arguments); | ||
}; | ||
}(); | ||
/** | ||
@@ -390,119 +212,56 @@ * when the storage-event pings, so that we now new messages came, | ||
*/ | ||
export var handleMessagePing = function () { | ||
var _ref10 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee11(state) { | ||
var _this2 = this; | ||
export function handleMessagePing(state) { | ||
/** | ||
* when there are no listener, we do nothing | ||
*/ | ||
if (!state.messagesCallback) return Promise.resolve(); | ||
return _regeneratorRuntime.wrap(function _callee11$(_context11) { | ||
while (1) { | ||
switch (_context11.prev = _context11.next) { | ||
case 0: | ||
if (state.messagesCallback) { | ||
_context11.next = 2; | ||
break; | ||
} | ||
/** | ||
* if we have 2 or more read-tasks in the queue, | ||
* we do not have to set more | ||
*/ | ||
if (state.readQueue._idleCalls.size > 1) return Promise.resolve(); | ||
return _context11.abrupt('return'); | ||
return state.readQueue.requestIdlePromise().then(function () { | ||
return state.readQueue.wrapCall(function () { | ||
return _handleMessagePingInner(state); | ||
}); | ||
}); | ||
} | ||
case 2: | ||
if (!(state.readQueue._idleCalls.size > 1)) { | ||
_context11.next = 4; | ||
break; | ||
} | ||
function _handleMessagePingInner(state) { | ||
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 msgObj.uuid !== state.uuid; | ||
}) // not send by own | ||
.filter(function (msgObj) { | ||
return !state.emittedMessagesIds.has(msgObj.id); | ||
}) // not already emitted | ||
.filter(function (msgObj) { | ||
return msgObj.time >= state.messagesCallbackTime; | ||
}) // not older then onMessageCallback | ||
.sort(function (msgObjA, msgObjB) { | ||
return msgObjA.time - msgObjB.time; | ||
}); // sort by time | ||
return _context11.abrupt('return'); | ||
case 4: | ||
_context11.next = 6; | ||
return state.readQueue.requestIdlePromise(); | ||
useMessages.forEach(function (msgObj) { | ||
if (state.messagesCallback) { | ||
state.emittedMessagesIds.add(msgObj.id); | ||
setTimeout(function () { | ||
return state.emittedMessagesIds['delete'](msgObj.id); | ||
}, state.options.idb.ttl * 2); | ||
case 6: | ||
_context11.next = 8; | ||
return state.readQueue.wrapCall(_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee10() { | ||
var newerMessages, useMessages, _loop, _iterator, _isArray, _i, _ref12, _ret; | ||
return _regeneratorRuntime.wrap(function _callee10$(_context10) { | ||
while (1) { | ||
switch (_context10.prev = _context10.next) { | ||
case 0: | ||
_context10.next = 2; | ||
return getMessagesHigherThen(state.db, state.lastCursorId); | ||
case 2: | ||
newerMessages = _context10.sent; | ||
useMessages = newerMessages.map(function (msgObj) { | ||
if (msgObj.id > state.lastCursorId) { | ||
state.lastCursorId = msgObj.id; | ||
} | ||
return msgObj; | ||
}).filter(function (msgObj) { | ||
return msgObj.uuid !== state.uuid; | ||
}) // not send by own | ||
.filter(function (msgObj) { | ||
return !state.emittedMessagesIds.has(msgObj.id); | ||
}) // not already emitted | ||
.filter(function (msgObj) { | ||
return msgObj.time >= state.messagesCallbackTime; | ||
}) // not older then onMessageCallback | ||
.sort(function (msgObjA, msgObjB) { | ||
return msgObjA.time - msgObjB.time; | ||
}); // sort by time | ||
_loop = function _loop() { | ||
if (_isArray) { | ||
if (_i >= _iterator.length) return 'break'; | ||
_ref12 = _iterator[_i++]; | ||
} else { | ||
_i = _iterator.next(); | ||
if (_i.done) return 'break'; | ||
_ref12 = _i.value; | ||
} | ||
var msgObj = _ref12; | ||
if (state.messagesCallback) { | ||
state.emittedMessagesIds.add(msgObj.id); | ||
setTimeout(function () { | ||
return state.emittedMessagesIds['delete'](msgObj.id); | ||
}, state.options.idb.ttl * 2); | ||
state.messagesCallback(msgObj.data); | ||
} | ||
}; | ||
_iterator = useMessages, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator); | ||
case 6: | ||
_ret = _loop(); | ||
if (!(_ret === 'break')) { | ||
_context10.next = 9; | ||
break; | ||
} | ||
return _context10.abrupt('break', 11); | ||
case 9: | ||
_context10.next = 6; | ||
break; | ||
case 11: | ||
case 'end': | ||
return _context10.stop(); | ||
} | ||
} | ||
}, _callee10, _this2); | ||
}))); | ||
case 8: | ||
case 'end': | ||
return _context11.stop(); | ||
} | ||
state.messagesCallback(msgObj.data); | ||
} | ||
}, _callee11, this); | ||
})); | ||
}); | ||
return function handleMessagePing(_x16) { | ||
return _ref10.apply(this, arguments); | ||
}; | ||
}(); | ||
return Promise.resolve(); | ||
}); | ||
} | ||
@@ -515,30 +274,10 @@ export function close(channelState) { | ||
export var postMessage = function () { | ||
var _ref13 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee12(channelState, messageJson) { | ||
return _regeneratorRuntime.wrap(function _callee12$(_context12) { | ||
while (1) { | ||
switch (_context12.prev = _context12.next) { | ||
case 0: | ||
_context12.next = 2; | ||
return writeMessage(channelState.db, channelState.uuid, messageJson); | ||
export function postMessage(channelState, messageJson) { | ||
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); | ||
} | ||
}); | ||
} | ||
case 2: | ||
if (randomInt(0, 10) === 0) { | ||
/* await (do not await) */cleanOldMessages(channelState.db, channelState.options.idb.ttl); | ||
} | ||
case 3: | ||
case 'end': | ||
return _context12.stop(); | ||
} | ||
} | ||
}, _callee12, this); | ||
})); | ||
return function postMessage(_x17, _x18) { | ||
return _ref13.apply(this, arguments); | ||
}; | ||
}(); | ||
export function onMessage(channelState, fn, time) { | ||
@@ -545,0 +284,0 @@ channelState.messagesCallbackTime = time; |
@@ -1,6 +0,1 @@ | ||
import _Set from 'babel-runtime/core-js/set'; | ||
import _regeneratorRuntime from 'babel-runtime/regenerator'; | ||
import _JSON$stringify from 'babel-runtime/core-js/json/stringify'; | ||
import _Promise from 'babel-runtime/core-js/promise'; | ||
import _asyncToGenerator from 'babel-runtime/helpers/asyncToGenerator'; | ||
/** | ||
@@ -14,8 +9,9 @@ * A localStorage-only method which uses localstorage and its 'storage'-event | ||
import isNode from 'detect-node'; | ||
import randomToken from 'random-token'; | ||
import IdleQueue from 'custom-idle-queue'; | ||
var isNode = require('detect-node'); | ||
var randomToken = require('random-token'); | ||
import { fillOptionsWithDefaults } from '../options'; | ||
import { sleep } from '../util'; | ||
var KEY_PREFIX = 'pubkey.broadcastChannel-'; | ||
@@ -50,51 +46,31 @@ export var type = 'localstorage'; | ||
*/ | ||
export var postMessage = function () { | ||
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(channelState, messageJson) { | ||
var key, writeObj, value, ev; | ||
return _regeneratorRuntime.wrap(function _callee$(_context) { | ||
while (1) { | ||
switch (_context.prev = _context.next) { | ||
case 0: | ||
_context.next = 2; | ||
return new _Promise(function (res) { | ||
return setTimeout(res, 0); | ||
}); | ||
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); | ||
case 2: | ||
key = storageKey(channelState.channelName); | ||
writeObj = { | ||
token: randomToken(10), | ||
time: new Date().getTime(), | ||
data: messageJson, | ||
uuid: channelState.uuid | ||
}; | ||
value = _JSON$stringify(writeObj); | ||
/** | ||
* 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); | ||
localStorage.setItem(key, value); | ||
res(); | ||
}); | ||
}); | ||
} | ||
/** | ||
* StorageEvent does not fire the 'storage' event | ||
* in the window that changes the state of the local storage. | ||
* So we fire it manually | ||
*/ | ||
ev = document.createEvent('Event'); | ||
ev.initEvent('storage', true, true); | ||
ev.key = key; | ||
ev.newValue = value; | ||
window.dispatchEvent(ev); | ||
case 11: | ||
case 'end': | ||
return _context.stop(); | ||
} | ||
} | ||
}, _callee, this); | ||
})); | ||
return function postMessage(_x, _x2) { | ||
return _ref.apply(this, arguments); | ||
}; | ||
}(); | ||
export function addStorageEventListener(channelName, fn) { | ||
@@ -114,7 +90,3 @@ var key = storageKey(channelName); | ||
export function create(channelName) { | ||
var _this = this; | ||
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
export function create(channelName, options) { | ||
options = fillOptionsWithDefaults(options); | ||
@@ -129,6 +101,4 @@ if (!canBeUsed()) { | ||
// contains all messages that have been emitted before | ||
var emittedMessagesIds = new _Set(); | ||
var emittedMessagesIds = new Set(); | ||
var writeQueue = new IdleQueue(1); | ||
var state = { | ||
@@ -139,65 +109,18 @@ startTime: startTime, | ||
uuid: uuid, | ||
emittedMessagesIds: emittedMessagesIds, | ||
writeQueue: writeQueue | ||
emittedMessagesIds: emittedMessagesIds | ||
}; | ||
state.listener = addStorageEventListener(channelName, function () { | ||
var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(msgObj) { | ||
return _regeneratorRuntime.wrap(function _callee2$(_context2) { | ||
while (1) { | ||
switch (_context2.prev = _context2.next) { | ||
case 0: | ||
if (state.messagesCallback) { | ||
_context2.next = 2; | ||
break; | ||
} | ||
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.time && msgObj.time < state.messagesCallbackTime) return; // too old | ||
return _context2.abrupt('return'); | ||
emittedMessagesIds.add(msgObj.token); | ||
setTimeout(function () { | ||
return emittedMessagesIds['delete'](msgObj.token); | ||
}, options.localstorage.removeTimeout); | ||
state.messagesCallback(msgObj.data); | ||
}); | ||
case 2: | ||
if (!(msgObj.uuid === uuid)) { | ||
_context2.next = 4; | ||
break; | ||
} | ||
return _context2.abrupt('return'); | ||
case 4: | ||
if (!(!msgObj.token || emittedMessagesIds.has(msgObj.token))) { | ||
_context2.next = 6; | ||
break; | ||
} | ||
return _context2.abrupt('return'); | ||
case 6: | ||
if (!(msgObj.time && msgObj.time < state.messagesCallbackTime)) { | ||
_context2.next = 8; | ||
break; | ||
} | ||
return _context2.abrupt('return'); | ||
case 8: | ||
// too old | ||
emittedMessagesIds.add(msgObj.token); | ||
setTimeout(function () { | ||
return emittedMessagesIds['delete'](msgObj.token); | ||
}, options.localstorage.removeTimeout); | ||
state.messagesCallback(msgObj.data); | ||
case 11: | ||
case 'end': | ||
return _context2.stop(); | ||
} | ||
} | ||
}, _callee2, _this); | ||
})); | ||
return function (_x4) { | ||
return _ref2.apply(this, arguments); | ||
}; | ||
}()); | ||
return state; | ||
@@ -208,3 +131,2 @@ } | ||
removeStorageEventListener(channelState.listener); | ||
channelState.writeQueue.clear(); | ||
} | ||
@@ -211,0 +133,0 @@ |
@@ -1,8 +0,7 @@ | ||
import isNode from 'detect-node'; | ||
var isNode = require('detect-node'); | ||
export var type = 'native'; | ||
export function create(channelName) { | ||
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
export function create(channelName, options) { | ||
if (!options) options = {}; | ||
var state = { | ||
@@ -9,0 +8,0 @@ channelName: channelName, |
@@ -1,8 +0,2 @@ | ||
import _Object$values from 'babel-runtime/core-js/object/values'; | ||
import _Object$keys from 'babel-runtime/core-js/object/keys'; | ||
import _getIterator from 'babel-runtime/core-js/get-iterator'; | ||
import _Set from 'babel-runtime/core-js/set'; | ||
import _JSON$stringify from 'babel-runtime/core-js/json/stringify'; | ||
import _regeneratorRuntime from 'babel-runtime/regenerator'; | ||
import _Promise from 'babel-runtime/core-js/promise'; | ||
import _asyncToGenerator from 'babel-runtime/helpers/asyncToGenerator'; | ||
@@ -75,3 +69,3 @@ /** | ||
case 5: | ||
_context.t0 = _Promise; | ||
_context.t0 = Promise; | ||
_context.next = 8; | ||
@@ -139,3 +133,3 @@ return mkdir(paths.readers)['catch'](function () { | ||
_context2.next = 5; | ||
return writeFile(pathToFile, _JSON$stringify({ | ||
return writeFile(pathToFile, JSON.stringify({ | ||
time: new Date().getTime() | ||
@@ -185,3 +179,3 @@ })); | ||
_context3.next = 5; | ||
return new _Promise(function (res) { | ||
return new Promise(function (res) { | ||
server.listen(pathToSocket, function () { | ||
@@ -226,3 +220,3 @@ res(); | ||
_context4.next = 4; | ||
return new _Promise(function (res) { | ||
return new Promise(function (res) { | ||
client.connect(pathToSocket, res); | ||
@@ -268,3 +262,3 @@ }); | ||
_context5.next = 7; | ||
return writeFile(msgPath, _JSON$stringify(writeObject)); | ||
return writeFile(msgPath, JSON.stringify(writeObject)); | ||
@@ -440,3 +434,3 @@ case 7: | ||
_context10.next = 3; | ||
return _Promise.all(messageObjects.filter(function (obj) { | ||
return Promise.all(messageObjects.filter(function (obj) { | ||
return obj.time < olderThen; | ||
@@ -484,3 +478,3 @@ }).map(function (obj) { | ||
_context12.next = 6; | ||
return _Promise.all([getReadersUuids(channelName), createSocketEventEmitter(channelName, uuid), createSocketInfoFile(channelName, uuid)]); | ||
return Promise.all([getReadersUuids(channelName), createSocketEventEmitter(channelName, uuid), createSocketInfoFile(channelName, uuid)]); | ||
@@ -494,3 +488,3 @@ case 6: | ||
_context12.next = 13; | ||
return _Promise.all(otherReaderUuids.filter(function (readerUuid) { | ||
return Promise.all(otherReaderUuids.filter(function (readerUuid) { | ||
return readerUuid !== uuid; | ||
@@ -538,3 +532,3 @@ }) // not own | ||
// contains all messages that have been emitted before | ||
emittedMessagesIds: new _Set(), | ||
emittedMessagesIds: new Set(), | ||
messagesCallbackTime: null, | ||
@@ -708,3 +702,3 @@ messagesCallback: null, | ||
}); | ||
_iterator = useMessages, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator); | ||
_iterator = useMessages, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator](); | ||
@@ -766,3 +760,3 @@ case 12: | ||
// remove subscriptions to closed readers | ||
_Object$keys(channelState.otherReaderClients).filter(function (readerUuid) { | ||
Object.keys(channelState.otherReaderClients).filter(function (readerUuid) { | ||
return !otherReaders.includes(readerUuid); | ||
@@ -775,3 +769,3 @@ }).forEach(function (readerUuid) { | ||
_context17.next = 6; | ||
return _Promise.all(otherReaders.filter(function (readerUuid) { | ||
return Promise.all(otherReaders.filter(function (readerUuid) { | ||
return readerUuid !== channelState.uuid; | ||
@@ -863,4 +857,4 @@ }) // not own | ||
_context18.next = 8; | ||
return _Promise.all(_Object$values(channelState.otherReaderClients).map(function (client) { | ||
return client.write(_JSON$stringify(pingObj)); | ||
return Promise.all(Object.values(channelState.otherReaderClients).map(function (client) { | ||
return client.write(JSON.stringify(pingObj)); | ||
})); | ||
@@ -932,3 +926,3 @@ | ||
_Object$values(channelState.otherReaderClients).forEach(function (client) { | ||
Object.values(channelState.otherReaderClients).forEach(function (client) { | ||
return client.destroy(); | ||
@@ -935,0 +929,0 @@ }); |
@@ -1,5 +0,4 @@ | ||
import clone from 'clone'; | ||
export function fillOptionsWithDefaults(options) { | ||
options = clone(options); | ||
if (!options) options = {}; | ||
options = JSON.parse(JSON.stringify(options)); | ||
@@ -6,0 +5,0 @@ // main |
@@ -24,2 +24,9 @@ /** | ||
} | ||
}; | ||
}; | ||
export function sleep(time) { | ||
if (!time) time = 0; | ||
return new Promise(function (res) { | ||
return setTimeout(res, time); | ||
}); | ||
} |
'use strict'; | ||
require('babel-polyfill'); | ||
var BroadcastChannel = require('./index.js'); | ||
window['BroadcastChannel2'] = BroadcastChannel; |
'use strict'; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
var _regenerator = require('babel-runtime/regenerator'); | ||
var _regenerator2 = _interopRequireDefault(_regenerator); | ||
var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator'); | ||
var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2); | ||
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); | ||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); | ||
var _createClass2 = require('babel-runtime/helpers/createClass'); | ||
var _createClass3 = _interopRequireDefault(_createClass2); | ||
var _util = require('./util.js'); | ||
@@ -29,8 +9,6 @@ | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
module.exports = function () { | ||
var BroadcastChannel = function () { | ||
function BroadcastChannel(name) { | ||
var BroadcastChannel = function BroadcastChannel(name) { | ||
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
(0, _classCallCheck3['default'])(this, BroadcastChannel); | ||
@@ -43,7 +21,6 @@ this.name = name; | ||
this._prepare(); | ||
} | ||
}; | ||
(0, _createClass3['default'])(BroadcastChannel, [{ | ||
key: '_prepare', | ||
value: function _prepare() { | ||
BroadcastChannel.prototype = { | ||
_prepare: function _prepare() { | ||
var _this = this; | ||
@@ -54,122 +31,38 @@ | ||
this._preparePromise = maybePromise; | ||
maybePromise.then(function () { | ||
var _ref = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee(s) { | ||
return _regenerator2['default'].wrap(function _callee$(_context) { | ||
while (1) { | ||
switch (_context.prev = _context.next) { | ||
case 0: | ||
// used in tests to simulate slow runtime | ||
if (_this.options.prepareDelay) { | ||
// await new Promise(res => setTimeout(res, this.options.prepareDelay)); | ||
} | ||
_this._state = s; | ||
case 2: | ||
case 'end': | ||
return _context.stop(); | ||
} | ||
} | ||
}, _callee, _this); | ||
})); | ||
return function (_x2) { | ||
return _ref.apply(this, arguments); | ||
}; | ||
}()); | ||
maybePromise.then(function (s) { | ||
// used in tests to simulate slow runtime | ||
if (_this.options.prepareDelay) { | ||
// await new Promise(res => setTimeout(res, this.options.prepareDelay)); | ||
} | ||
_this._state = s; | ||
}); | ||
} else { | ||
this._state = maybePromise; | ||
} | ||
} | ||
}, { | ||
key: 'postMessage', | ||
value: function () { | ||
var _ref2 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee2(msg) { | ||
var msgObj; | ||
return _regenerator2['default'].wrap(function _callee2$(_context2) { | ||
while (1) { | ||
switch (_context2.prev = _context2.next) { | ||
case 0: | ||
msgObj = { | ||
time: new Date().getTime(), | ||
data: msg | ||
}; | ||
}, | ||
postMessage: function postMessage(msg) { | ||
var _this2 = this; | ||
if (!this.closed) { | ||
_context2.next = 3; | ||
break; | ||
} | ||
var msgObj = { | ||
time: new Date().getTime(), | ||
data: msg | ||
}; | ||
throw new Error('BroadcastChannel.postMessage(): ' + 'Cannot post message after channel has closed'); | ||
case 3: | ||
if (!this._preparePromise) { | ||
_context2.next = 6; | ||
break; | ||
} | ||
_context2.next = 6; | ||
return this._preparePromise; | ||
case 6: | ||
return _context2.abrupt('return', this.method.postMessage(this._state, msgObj)); | ||
case 7: | ||
case 'end': | ||
return _context2.stop(); | ||
} | ||
} | ||
}, _callee2, this); | ||
})); | ||
function postMessage(_x3) { | ||
return _ref2.apply(this, arguments); | ||
if (this.closed) { | ||
throw new Error('BroadcastChannel.postMessage(): ' + 'Cannot post message after channel has closed'); | ||
} | ||
return postMessage; | ||
}() | ||
}, { | ||
key: 'close', | ||
value: function () { | ||
var _ref3 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee3() { | ||
return _regenerator2['default'].wrap(function _callee3$(_context3) { | ||
while (1) { | ||
switch (_context3.prev = _context3.next) { | ||
case 0: | ||
this.closed = true; | ||
var awaitPrepare = this._preparePromise ? this._preparePromise : Promise.resolve(); | ||
return awaitPrepare.then(function () { | ||
return _this2.method.postMessage(_this2._state, msgObj); | ||
}); | ||
}, | ||
if (!this._preparePromise) { | ||
_context3.next = 4; | ||
break; | ||
} | ||
set onmessage(fn) { | ||
var _this3 = this; | ||
_context3.next = 4; | ||
return this._preparePromise; | ||
case 4: | ||
_context3.next = 6; | ||
return this.method.close(this._state); | ||
case 6: | ||
case 'end': | ||
return _context3.stop(); | ||
} | ||
} | ||
}, _callee3, this); | ||
})); | ||
function close() { | ||
return _ref3.apply(this, arguments); | ||
} | ||
return close; | ||
}() | ||
}, { | ||
key: 'onmessage', | ||
set: function set(fn) { | ||
var _this2 = this; | ||
var time = new Date().getTime() - 5; | ||
if (this._preparePromise) { | ||
this._preparePromise.then(function () { | ||
_this2.method.onMessage(_this2._state, messageHandler(fn, time), time); | ||
_this3.method.onMessage(_this3._state, messageHandler(fn, time), time); | ||
}); | ||
@@ -179,24 +72,27 @@ } else { | ||
} | ||
} | ||
}, { | ||
key: 'type', | ||
get: function get() { | ||
return this.method.type; | ||
} | ||
}]); | ||
return BroadcastChannel; | ||
}(); | ||
}, | ||
close: function close() { | ||
var _this4 = this; | ||
; | ||
this.closed = true; | ||
var awaitPrepare = this._preparePromise ? this._preparePromise : Promise.resolve(); | ||
return awaitPrepare.then(function () { | ||
return _this4.method.close(_this4._state); | ||
}); | ||
}, | ||
function messageHandler(fn, minTime) { | ||
return function (msgObj) { | ||
if (msgObj.time >= minTime) { | ||
fn(msgObj.data); | ||
get type() { | ||
return this.method.type; | ||
} | ||
}; | ||
} | ||
exports['default'] = BroadcastChannel; | ||
function messageHandler(fn, minTime) { | ||
return function (msgObj) { | ||
if (msgObj.time >= minTime) { | ||
fn(msgObj.data); | ||
} | ||
}; | ||
}; | ||
module.exports = BroadcastChannel; | ||
return BroadcastChannel; | ||
}(); |
@@ -6,29 +6,9 @@ 'use strict'; | ||
}); | ||
var _stringify = require('babel-runtime/core-js/json/stringify'); | ||
var _stringify2 = _interopRequireDefault(_stringify); | ||
exports.chooseMethod = chooseMethod; | ||
var isNode = require('detect-node'); | ||
var _detectNode = require('detect-node'); | ||
var NativeMethod = require('./methods/native.js'); | ||
var IndexeDbMethod = require('./methods/indexed-db.js'); | ||
var LocalstorageMethod = require('./methods/localstorage.js'); | ||
var _detectNode2 = _interopRequireDefault(_detectNode); | ||
var _native = require('./methods/native.js'); | ||
var NativeMethod = _interopRequireWildcard(_native); | ||
var _indexedDb = require('./methods/indexed-db.js'); | ||
var IndexeDbMethod = _interopRequireWildcard(_indexedDb); | ||
var _localstorage = require('./methods/localstorage.js'); | ||
var LocalstorageMethod = _interopRequireWildcard(_localstorage); | ||
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
// order is important | ||
@@ -38,2 +18,4 @@ var METHODS = [NativeMethod, // fastest | ||
var REQUIRE_FUN = require; | ||
/** | ||
@@ -43,4 +25,4 @@ * The NodeMethod is loaded lazy | ||
*/ | ||
if (_detectNode2['default']) { | ||
var NodeMethod = require('./methods/node.js'); | ||
if (isNode) { | ||
var NodeMethod = REQUIRE_FUN('./methods/node.js'); | ||
METHODS.push(NodeMethod); | ||
@@ -59,3 +41,3 @@ } | ||
var chooseMethods = METHODS; | ||
if (!options.webWorkerSupport && !_detectNode2['default']) { | ||
if (!options.webWorkerSupport && !isNode) { | ||
// prefer localstorage over idb when no webworker-support needed | ||
@@ -70,5 +52,5 @@ chooseMethods = METHODS.filter(function (m) { | ||
}); | ||
if (!useMethod) throw new Error('No useable methode found:' + (0, _stringify2['default'])(METHODS.map(function (m) { | ||
if (!useMethod) throw new Error('No useable methode found:' + JSON.stringify(METHODS.map(function (m) { | ||
return m.type; | ||
})));else return useMethod; | ||
} |
@@ -6,72 +6,75 @@ 'use strict'; | ||
}); | ||
exports.postMessage = exports.handleMessagePing = exports.create = exports.cleanOldMessages = exports.getOldMessages = exports.removeMessageById = exports.getMessagesHigherThen = exports.getAllMessages = exports.writeMessage = exports.createDatabase = exports.type = undefined; | ||
exports.type = undefined; | ||
exports.getIdb = getIdb; | ||
exports.createDatabase = createDatabase; | ||
exports.writeMessage = writeMessage; | ||
exports.getAllMessages = getAllMessages; | ||
exports.getMessagesHigherThen = getMessagesHigherThen; | ||
exports.removeMessageById = removeMessageById; | ||
exports.getOldMessages = getOldMessages; | ||
exports.cleanOldMessages = cleanOldMessages; | ||
exports.create = create; | ||
exports.handleMessagePing = handleMessagePing; | ||
exports.close = close; | ||
exports.postMessage = postMessage; | ||
exports.onMessage = onMessage; | ||
exports.canBeUsed = canBeUsed; | ||
var _getIterator2 = require('babel-runtime/core-js/get-iterator'); | ||
var _util = require('../util.js'); | ||
var _getIterator3 = _interopRequireDefault(_getIterator2); | ||
var _options = require('../options'); | ||
var _set = require('babel-runtime/core-js/set'); | ||
/** | ||
* this method uses indexeddb to store the messages | ||
* There is currently no observerAPI for idb | ||
* @link https://github.com/w3c/IndexedDB/issues/51 | ||
* So we use the localstorage 'storage'-event | ||
* to ping other tabs when a message comes in | ||
*/ | ||
var _set2 = _interopRequireDefault(_set); | ||
var isNode = require('detect-node'); | ||
var randomToken = require('random-token'); | ||
var randomInt = require('random-int'); | ||
var IdleQueue = require('custom-idle-queue'); | ||
var _regenerator = require('babel-runtime/regenerator'); | ||
var DB_PREFIX = 'pubkey.broadcast-channel-0-'; | ||
var OBJECT_STORE_ID = 'messages'; | ||
var _regenerator2 = _interopRequireDefault(_regenerator); | ||
var type = exports.type = 'idb'; | ||
var _promise = require('babel-runtime/core-js/promise'); | ||
function getIdb() { | ||
if (typeof indexedDB !== 'undefined') return indexedDB; | ||
if (typeof mozIndexedDB !== 'undefined') return mozIndexedDB; | ||
if (typeof webkitIndexedDB !== 'undefined') return webkitIndexedDB; | ||
if (typeof msIndexedDB !== 'undefined') return msIndexedDB; | ||
var _promise2 = _interopRequireDefault(_promise); | ||
return false; | ||
} | ||
var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator'); | ||
function createDatabase(channelName) { | ||
var IndexedDB = getIdb(); | ||
var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2); | ||
// create table | ||
var dbName = DB_PREFIX + channelName; | ||
var openRequest = IndexedDB.open(dbName, 1); | ||
var createDatabase = exports.createDatabase = function () { | ||
var _ref = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee(channelName) { | ||
var IndexedDB, dbName, openRequest, db; | ||
return _regenerator2['default'].wrap(function _callee$(_context) { | ||
while (1) { | ||
switch (_context.prev = _context.next) { | ||
case 0: | ||
IndexedDB = getIdb(); | ||
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); | ||
}; | ||
}); | ||
// create table | ||
return dbPromise; | ||
} | ||
dbName = DB_PREFIX + channelName; | ||
openRequest = IndexedDB.open(dbName, 1); | ||
openRequest.onupgradeneeded = function (ev) { | ||
var db = ev.target.result; | ||
db.createObjectStore(OBJECT_STORE_ID, { | ||
keyPath: 'id', | ||
autoIncrement: true | ||
}); | ||
}; | ||
_context.next = 6; | ||
return new _promise2['default'](function (res, rej) { | ||
openRequest.onerror = function (ev) { | ||
return rej(ev); | ||
}; | ||
openRequest.onsuccess = function () { | ||
res(openRequest.result); | ||
}; | ||
}); | ||
case 6: | ||
db = _context.sent; | ||
return _context.abrupt('return', db); | ||
case 8: | ||
case 'end': | ||
return _context.stop(); | ||
} | ||
} | ||
}, _callee, this); | ||
})); | ||
return function createDatabase(_x) { | ||
return _ref.apply(this, arguments); | ||
}; | ||
}(); | ||
/** | ||
@@ -81,300 +84,145 @@ * writes the new message to the database | ||
*/ | ||
var writeMessage = exports.writeMessage = function () { | ||
var _ref2 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee2(db, readerUuid, messageJson) { | ||
var time, writeObject, transaction; | ||
return _regenerator2['default'].wrap(function _callee2$(_context2) { | ||
while (1) { | ||
switch (_context2.prev = _context2.next) { | ||
case 0: | ||
time = new Date().getTime(); | ||
writeObject = { | ||
uuid: readerUuid, | ||
time: time, | ||
data: messageJson | ||
}; | ||
transaction = db.transaction([OBJECT_STORE_ID], 'readwrite'); | ||
return _context2.abrupt('return', new _promise2['default'](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); | ||
})); | ||
case 4: | ||
case 'end': | ||
return _context2.stop(); | ||
} | ||
} | ||
}, _callee2, this); | ||
})); | ||
return function writeMessage(_x2, _x3, _x4) { | ||
return _ref2.apply(this, arguments); | ||
function writeMessage(db, readerUuid, messageJson) { | ||
var time = new Date().getTime(); | ||
var writeObject = { | ||
uuid: readerUuid, | ||
time: time, | ||
data: messageJson | ||
}; | ||
}(); | ||
var getAllMessages = exports.getAllMessages = function () { | ||
var _ref3 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee3(db) { | ||
var objectStore, ret; | ||
return _regenerator2['default'].wrap(function _callee3$(_context3) { | ||
while (1) { | ||
switch (_context3.prev = _context3.next) { | ||
case 0: | ||
objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID); | ||
ret = []; | ||
return _context3.abrupt('return', new _promise2['default'](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 transaction = db.transaction([OBJECT_STORE_ID], 'readwrite'); | ||
case 3: | ||
case 'end': | ||
return _context3.stop(); | ||
} | ||
} | ||
}, _callee3, this); | ||
})); | ||
return new Promise(function (res, rej) { | ||
transaction.oncomplete = function () { | ||
return res(); | ||
}; | ||
transaction.onerror = function (ev) { | ||
return rej(ev); | ||
}; | ||
return function getAllMessages(_x5) { | ||
return _ref3.apply(this, arguments); | ||
}; | ||
}(); | ||
var objectStore = transaction.objectStore(OBJECT_STORE_ID); | ||
objectStore.add(writeObject); | ||
}); | ||
} | ||
var getMessagesHigherThen = exports.getMessagesHigherThen = function () { | ||
var _ref4 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee4(db, lastCursorId) { | ||
var objectStore, ret, keyRangeValue; | ||
return _regenerator2['default'].wrap(function _callee4$(_context4) { | ||
while (1) { | ||
switch (_context4.prev = _context4.next) { | ||
case 0: | ||
objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID); | ||
ret = []; | ||
keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity); | ||
return _context4.abrupt('return', new _promise2['default'](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); | ||
} | ||
}; | ||
})); | ||
case 4: | ||
case 'end': | ||
return _context4.stop(); | ||
} | ||
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); | ||
} | ||
}, _callee4, this); | ||
})); | ||
}; | ||
}); | ||
} | ||
return function getMessagesHigherThen(_x6, _x7) { | ||
return _ref4.apply(this, arguments); | ||
}; | ||
}(); | ||
var removeMessageById = exports.removeMessageById = function () { | ||
var _ref5 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee5(db, id) { | ||
var request; | ||
return _regenerator2['default'].wrap(function _callee5$(_context5) { | ||
while (1) { | ||
switch (_context5.prev = _context5.next) { | ||
case 0: | ||
request = db.transaction([OBJECT_STORE_ID], 'readwrite').objectStore(OBJECT_STORE_ID)['delete'](id); | ||
return _context5.abrupt('return', new _promise2['default'](function (res) { | ||
request.onsuccess = function () { | ||
return res(); | ||
}; | ||
})); | ||
case 2: | ||
case 'end': | ||
return _context5.stop(); | ||
} | ||
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); | ||
} | ||
}, _callee5, this); | ||
})); | ||
}; | ||
}); | ||
} | ||
return function removeMessageById(_x8, _x9) { | ||
return _ref5.apply(this, arguments); | ||
}; | ||
}(); | ||
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 getOldMessages = exports.getOldMessages = function () { | ||
var _ref6 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee6(db, ttl) { | ||
var olderThen, objectStore, ret; | ||
return _regenerator2['default'].wrap(function _callee6$(_context6) { | ||
while (1) { | ||
switch (_context6.prev = _context6.next) { | ||
case 0: | ||
olderThen = new Date().getTime() - ttl; | ||
objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID); | ||
ret = []; | ||
return _context6.abrupt('return', new _promise2['default'](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); | ||
} | ||
}; | ||
})); | ||
case 4: | ||
case 'end': | ||
return _context6.stop(); | ||
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); | ||
} | ||
}, _callee6, this); | ||
})); | ||
}; | ||
}); | ||
} | ||
return function getOldMessages(_x10, _x11) { | ||
return _ref6.apply(this, arguments); | ||
}; | ||
}(); | ||
function cleanOldMessages(db, ttl) { | ||
return getOldMessages(db, ttl).then(function (tooOld) { | ||
return Promise.all(tooOld.map(function (msgObj) { | ||
return removeMessageById(db, msgObj.id); | ||
})); | ||
}); | ||
} | ||
var cleanOldMessages = exports.cleanOldMessages = function () { | ||
var _ref7 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee7(db, ttl) { | ||
var tooOld; | ||
return _regenerator2['default'].wrap(function _callee7$(_context7) { | ||
while (1) { | ||
switch (_context7.prev = _context7.next) { | ||
case 0: | ||
_context7.next = 2; | ||
return getOldMessages(db, ttl); | ||
function create(channelName, options) { | ||
options = (0, _options.fillOptionsWithDefaults)(options); | ||
case 2: | ||
tooOld = _context7.sent; | ||
return _context7.abrupt('return', _promise2['default'].all(tooOld.map(function (msgObj) { | ||
return removeMessageById(db, msgObj.id); | ||
}))); | ||
var uuid = randomToken(10); | ||
case 4: | ||
case 'end': | ||
return _context7.stop(); | ||
} | ||
} | ||
}, _callee7, this); | ||
})); | ||
// ensures we do not read messages in parrallel | ||
var readQueue = new IdleQueue(1); | ||
return function cleanOldMessages(_x12, _x13) { | ||
return _ref7.apply(this, arguments); | ||
}; | ||
}(); | ||
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 Set(), | ||
messagesCallback: null, | ||
readQueue: readQueue, | ||
db: db | ||
}; | ||
var create = exports.create = function () { | ||
var _ref8 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee9(channelName) { | ||
var _this = this; | ||
/** | ||
* 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); | ||
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
var uuid, readQueue, db, state; | ||
return _regenerator2['default'].wrap(function _callee9$(_context9) { | ||
while (1) { | ||
switch (_context9.prev = _context9.next) { | ||
case 0: | ||
options = (0, _options.fillOptionsWithDefaults)(options); | ||
return state; | ||
}); | ||
} | ||
uuid = (0, _randomToken2['default'])(10); | ||
function _readLoop(state) { | ||
if (state.closed) return; | ||
// ensures we do not read messages in parrallel | ||
return handleMessagePing(state).then(function () { | ||
return (0, _util.sleep)(state.options.idb.fallbackInterval); | ||
}).then(function () { | ||
return _readLoop(state); | ||
}); | ||
} | ||
readQueue = new _customIdleQueue2['default'](1); | ||
_context9.next = 5; | ||
return createDatabase(channelName); | ||
case 5: | ||
db = _context9.sent; | ||
state = { | ||
closed: false, | ||
lastCursorId: 0, | ||
channelName: channelName, | ||
options: options, | ||
uuid: uuid, | ||
// contains all messages that have been emitted before | ||
emittedMessagesIds: new _set2['default'](), | ||
messagesCallback: null, | ||
readQueue: readQueue, | ||
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 | ||
*/ | ||
(0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee8() { | ||
return _regenerator2['default'].wrap(function _callee8$(_context8) { | ||
while (1) { | ||
switch (_context8.prev = _context8.next) { | ||
case 0: | ||
if (!(state.closed === false)) { | ||
_context8.next = 7; | ||
break; | ||
} | ||
_context8.next = 3; | ||
return handleMessagePing(state); | ||
case 3: | ||
_context8.next = 5; | ||
return new _promise2['default'](function (res) { | ||
return setTimeout(res, state.options.idb.fallbackInterval); | ||
}); | ||
case 5: | ||
_context8.next = 0; | ||
break; | ||
case 7: | ||
case 'end': | ||
return _context8.stop(); | ||
} | ||
} | ||
}, _callee8, _this); | ||
}))(); | ||
return _context9.abrupt('return', state); | ||
case 9: | ||
case 'end': | ||
return _context9.stop(); | ||
} | ||
} | ||
}, _callee9, this); | ||
})); | ||
return function create(_x15) { | ||
return _ref8.apply(this, arguments); | ||
}; | ||
}(); | ||
/** | ||
@@ -384,210 +232,55 @@ * when the storage-event pings, so that we now new messages came, | ||
*/ | ||
function handleMessagePing(state) { | ||
/** | ||
* when there are no listener, we do nothing | ||
*/ | ||
if (!state.messagesCallback) return Promise.resolve(); | ||
/** | ||
* if we have 2 or more read-tasks in the queue, | ||
* we do not have to set more | ||
*/ | ||
if (state.readQueue._idleCalls.size > 1) return Promise.resolve(); | ||
var handleMessagePing = exports.handleMessagePing = function () { | ||
var _ref10 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee11(state) { | ||
var _this2 = this; | ||
return state.readQueue.requestIdlePromise().then(function () { | ||
return state.readQueue.wrapCall(function () { | ||
return _handleMessagePingInner(state); | ||
}); | ||
}); | ||
} | ||
return _regenerator2['default'].wrap(function _callee11$(_context11) { | ||
while (1) { | ||
switch (_context11.prev = _context11.next) { | ||
case 0: | ||
if (state.messagesCallback) { | ||
_context11.next = 2; | ||
break; | ||
} | ||
return _context11.abrupt('return'); | ||
case 2: | ||
if (!(state.readQueue._idleCalls.size > 1)) { | ||
_context11.next = 4; | ||
break; | ||
} | ||
return _context11.abrupt('return'); | ||
case 4: | ||
_context11.next = 6; | ||
return state.readQueue.requestIdlePromise(); | ||
case 6: | ||
_context11.next = 8; | ||
return state.readQueue.wrapCall((0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee10() { | ||
var newerMessages, useMessages, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _loop, _iterator, _step; | ||
return _regenerator2['default'].wrap(function _callee10$(_context10) { | ||
while (1) { | ||
switch (_context10.prev = _context10.next) { | ||
case 0: | ||
_context10.next = 2; | ||
return getMessagesHigherThen(state.db, state.lastCursorId); | ||
case 2: | ||
newerMessages = _context10.sent; | ||
useMessages = newerMessages.map(function (msgObj) { | ||
if (msgObj.id > state.lastCursorId) { | ||
state.lastCursorId = msgObj.id; | ||
} | ||
return msgObj; | ||
}).filter(function (msgObj) { | ||
return msgObj.uuid !== state.uuid; | ||
}) // not send by own | ||
.filter(function (msgObj) { | ||
return !state.emittedMessagesIds.has(msgObj.id); | ||
}) // not already emitted | ||
.filter(function (msgObj) { | ||
return msgObj.time >= state.messagesCallbackTime; | ||
}) // not older then onMessageCallback | ||
.sort(function (msgObjA, msgObjB) { | ||
return msgObjA.time - msgObjB.time; | ||
}); // sort by time | ||
_iteratorNormalCompletion = true; | ||
_didIteratorError = false; | ||
_iteratorError = undefined; | ||
_context10.prev = 7; | ||
_loop = function _loop() { | ||
var msgObj = _step.value; | ||
if (state.messagesCallback) { | ||
state.emittedMessagesIds.add(msgObj.id); | ||
setTimeout(function () { | ||
return state.emittedMessagesIds['delete'](msgObj.id); | ||
}, state.options.idb.ttl * 2); | ||
state.messagesCallback(msgObj.data); | ||
} | ||
}; | ||
for (_iterator = (0, _getIterator3['default'])(useMessages); !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | ||
_loop(); | ||
} | ||
_context10.next = 16; | ||
break; | ||
case 12: | ||
_context10.prev = 12; | ||
_context10.t0 = _context10['catch'](7); | ||
_didIteratorError = true; | ||
_iteratorError = _context10.t0; | ||
case 16: | ||
_context10.prev = 16; | ||
_context10.prev = 17; | ||
if (!_iteratorNormalCompletion && _iterator['return']) { | ||
_iterator['return'](); | ||
} | ||
case 19: | ||
_context10.prev = 19; | ||
if (!_didIteratorError) { | ||
_context10.next = 22; | ||
break; | ||
} | ||
throw _iteratorError; | ||
case 22: | ||
return _context10.finish(19); | ||
case 23: | ||
return _context10.finish(16); | ||
case 24: | ||
case 'end': | ||
return _context10.stop(); | ||
} | ||
} | ||
}, _callee10, _this2, [[7, 12, 16, 24], [17,, 19, 23]]); | ||
}))); | ||
case 8: | ||
case 'end': | ||
return _context11.stop(); | ||
} | ||
function _handleMessagePingInner(state) { | ||
return getMessagesHigherThen(state.db, state.lastCursorId).then(function (newerMessages) { | ||
var useMessages = newerMessages.map(function (msgObj) { | ||
if (msgObj.id > state.lastCursorId) { | ||
state.lastCursorId = msgObj.id; | ||
} | ||
}, _callee11, this); | ||
})); | ||
return msgObj; | ||
}).filter(function (msgObj) { | ||
return msgObj.uuid !== state.uuid; | ||
}) // not send by own | ||
.filter(function (msgObj) { | ||
return !state.emittedMessagesIds.has(msgObj.id); | ||
}) // not already emitted | ||
.filter(function (msgObj) { | ||
return msgObj.time >= state.messagesCallbackTime; | ||
}) // not older then onMessageCallback | ||
.sort(function (msgObjA, msgObjB) { | ||
return msgObjA.time - msgObjB.time; | ||
}); // sort by time | ||
return function handleMessagePing(_x16) { | ||
return _ref10.apply(this, arguments); | ||
}; | ||
}(); | ||
var postMessage = exports.postMessage = function () { | ||
var _ref12 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee12(channelState, messageJson) { | ||
return _regenerator2['default'].wrap(function _callee12$(_context12) { | ||
while (1) { | ||
switch (_context12.prev = _context12.next) { | ||
case 0: | ||
_context12.next = 2; | ||
return writeMessage(channelState.db, channelState.uuid, messageJson); | ||
useMessages.forEach(function (msgObj) { | ||
if (state.messagesCallback) { | ||
state.emittedMessagesIds.add(msgObj.id); | ||
setTimeout(function () { | ||
return state.emittedMessagesIds['delete'](msgObj.id); | ||
}, state.options.idb.ttl * 2); | ||
case 2: | ||
if ((0, _randomInt2['default'])(0, 10) === 0) { | ||
/* await (do not await) */cleanOldMessages(channelState.db, channelState.options.idb.ttl); | ||
} | ||
case 3: | ||
case 'end': | ||
return _context12.stop(); | ||
} | ||
state.messagesCallback(msgObj.data); | ||
} | ||
}, _callee12, this); | ||
})); | ||
}); | ||
return function postMessage(_x17, _x18) { | ||
return _ref12.apply(this, arguments); | ||
}; | ||
}(); | ||
exports.getIdb = getIdb; | ||
exports.close = close; | ||
exports.onMessage = onMessage; | ||
exports.canBeUsed = canBeUsed; | ||
var _detectNode = require('detect-node'); | ||
var _detectNode2 = _interopRequireDefault(_detectNode); | ||
var _randomToken = require('random-token'); | ||
var _randomToken2 = _interopRequireDefault(_randomToken); | ||
var _randomInt = require('random-int'); | ||
var _randomInt2 = _interopRequireDefault(_randomInt); | ||
var _customIdleQueue = require('custom-idle-queue'); | ||
var _customIdleQueue2 = _interopRequireDefault(_customIdleQueue); | ||
var _options = require('../options'); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
var DB_PREFIX = 'pubkey.broadcast-channel-0-'; /** | ||
* this method uses indexeddb to store the messages | ||
* There is currently no observerAPI for idb | ||
* @link https://github.com/w3c/IndexedDB/issues/51 | ||
* So we use the localstorage 'storage'-event | ||
* to ping other tabs when a message comes in | ||
*/ | ||
var OBJECT_STORE_ID = 'messages'; | ||
var type = exports.type = 'idb'; | ||
function getIdb() { | ||
if (typeof indexedDB !== 'undefined') return indexedDB; | ||
if (typeof mozIndexedDB !== 'undefined') return mozIndexedDB; | ||
if (typeof webkitIndexedDB !== 'undefined') return webkitIndexedDB; | ||
if (typeof msIndexedDB !== 'undefined') return msIndexedDB; | ||
return false; | ||
return Promise.resolve(); | ||
}); | ||
} | ||
@@ -601,2 +294,10 @@ | ||
function postMessage(channelState, messageJson) { | ||
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); | ||
} | ||
}); | ||
} | ||
function onMessage(channelState, fn, time) { | ||
@@ -609,3 +310,3 @@ channelState.messagesCallbackTime = time; | ||
function canBeUsed() { | ||
if (_detectNode2['default']) return false; | ||
if (isNode) return false; | ||
var idb = getIdb(); | ||
@@ -612,0 +313,0 @@ |
@@ -6,79 +6,6 @@ 'use strict'; | ||
}); | ||
exports.postMessage = exports.type = undefined; | ||
var _set = require('babel-runtime/core-js/set'); | ||
var _set2 = _interopRequireDefault(_set); | ||
var _regenerator = require('babel-runtime/regenerator'); | ||
var _regenerator2 = _interopRequireDefault(_regenerator); | ||
var _stringify = require('babel-runtime/core-js/json/stringify'); | ||
var _stringify2 = _interopRequireDefault(_stringify); | ||
var _promise = require('babel-runtime/core-js/promise'); | ||
var _promise2 = _interopRequireDefault(_promise); | ||
var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator'); | ||
var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2); | ||
/** | ||
* writes the new message to the storage | ||
* and fires the storage-event so other readers can find it | ||
*/ | ||
var postMessage = exports.postMessage = function () { | ||
var _ref = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee(channelState, messageJson) { | ||
var key, writeObj, value, ev; | ||
return _regenerator2['default'].wrap(function _callee$(_context) { | ||
while (1) { | ||
switch (_context.prev = _context.next) { | ||
case 0: | ||
_context.next = 2; | ||
return new _promise2['default'](function (res) { | ||
return setTimeout(res, 0); | ||
}); | ||
case 2: | ||
key = storageKey(channelState.channelName); | ||
writeObj = { | ||
token: (0, _randomToken2['default'])(10), | ||
time: new Date().getTime(), | ||
data: messageJson, | ||
uuid: channelState.uuid | ||
}; | ||
value = (0, _stringify2['default'])(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 | ||
*/ | ||
ev = document.createEvent('Event'); | ||
ev.initEvent('storage', true, true); | ||
ev.key = key; | ||
ev.newValue = value; | ||
window.dispatchEvent(ev); | ||
case 11: | ||
case 'end': | ||
return _context.stop(); | ||
} | ||
} | ||
}, _callee, this); | ||
})); | ||
return function postMessage(_x, _x2) { | ||
return _ref.apply(this, arguments); | ||
}; | ||
}(); | ||
exports.type = undefined; | ||
exports.getLocalStorage = getLocalStorage; | ||
exports.storageKey = storageKey; | ||
exports.postMessage = postMessage; | ||
exports.addStorageEventListener = addStorageEventListener; | ||
@@ -91,17 +18,5 @@ exports.removeStorageEventListener = removeStorageEventListener; | ||
var _detectNode = require('detect-node'); | ||
var _detectNode2 = _interopRequireDefault(_detectNode); | ||
var _randomToken = require('random-token'); | ||
var _randomToken2 = _interopRequireDefault(_randomToken); | ||
var _customIdleQueue = require('custom-idle-queue'); | ||
var _customIdleQueue2 = _interopRequireDefault(_customIdleQueue); | ||
var _options = require('../options'); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
var _util = require('../util'); | ||
@@ -116,2 +31,5 @@ /** | ||
var isNode = require('detect-node'); | ||
var randomToken = require('random-token'); | ||
var KEY_PREFIX = 'pubkey.broadcastChannel-'; | ||
@@ -140,3 +58,38 @@ var type = exports.type = 'localstorage'; | ||
return KEY_PREFIX + channelName; | ||
}function addStorageEventListener(channelName, fn) { | ||
} | ||
/** | ||
* 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: 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 | ||
*/ | ||
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); | ||
@@ -155,7 +108,3 @@ var listener = function listener(ev) { | ||
function create(channelName) { | ||
var _this = this; | ||
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
function create(channelName, options) { | ||
options = (0, _options.fillOptionsWithDefaults)(options); | ||
@@ -167,9 +116,7 @@ if (!canBeUsed()) { | ||
var startTime = new Date().getTime(); | ||
var uuid = (0, _randomToken2['default'])(10); | ||
var uuid = randomToken(10); | ||
// contains all messages that have been emitted before | ||
var emittedMessagesIds = new _set2['default'](); | ||
var emittedMessagesIds = new Set(); | ||
var writeQueue = new _customIdleQueue2['default'](1); | ||
var state = { | ||
@@ -180,65 +127,18 @@ startTime: startTime, | ||
uuid: uuid, | ||
emittedMessagesIds: emittedMessagesIds, | ||
writeQueue: writeQueue | ||
emittedMessagesIds: emittedMessagesIds | ||
}; | ||
state.listener = addStorageEventListener(channelName, function () { | ||
var _ref2 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee2(msgObj) { | ||
return _regenerator2['default'].wrap(function _callee2$(_context2) { | ||
while (1) { | ||
switch (_context2.prev = _context2.next) { | ||
case 0: | ||
if (state.messagesCallback) { | ||
_context2.next = 2; | ||
break; | ||
} | ||
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.time && msgObj.time < state.messagesCallbackTime) return; // too old | ||
return _context2.abrupt('return'); | ||
emittedMessagesIds.add(msgObj.token); | ||
setTimeout(function () { | ||
return emittedMessagesIds['delete'](msgObj.token); | ||
}, options.localstorage.removeTimeout); | ||
state.messagesCallback(msgObj.data); | ||
}); | ||
case 2: | ||
if (!(msgObj.uuid === uuid)) { | ||
_context2.next = 4; | ||
break; | ||
} | ||
return _context2.abrupt('return'); | ||
case 4: | ||
if (!(!msgObj.token || emittedMessagesIds.has(msgObj.token))) { | ||
_context2.next = 6; | ||
break; | ||
} | ||
return _context2.abrupt('return'); | ||
case 6: | ||
if (!(msgObj.time && msgObj.time < state.messagesCallbackTime)) { | ||
_context2.next = 8; | ||
break; | ||
} | ||
return _context2.abrupt('return'); | ||
case 8: | ||
// too old | ||
emittedMessagesIds.add(msgObj.token); | ||
setTimeout(function () { | ||
return emittedMessagesIds['delete'](msgObj.token); | ||
}, options.localstorage.removeTimeout); | ||
state.messagesCallback(msgObj.data); | ||
case 11: | ||
case 'end': | ||
return _context2.stop(); | ||
} | ||
} | ||
}, _callee2, _this); | ||
})); | ||
return function (_x4) { | ||
return _ref2.apply(this, arguments); | ||
}; | ||
}()); | ||
return state; | ||
@@ -249,3 +149,2 @@ } | ||
removeStorageEventListener(channelState.listener); | ||
channelState.writeQueue.clear(); | ||
} | ||
@@ -259,3 +158,3 @@ | ||
function canBeUsed() { | ||
if (_detectNode2['default']) return false; | ||
if (isNode) return false; | ||
var ls = getLocalStorage(); | ||
@@ -262,0 +161,0 @@ |
@@ -6,3 +6,2 @@ 'use strict'; | ||
}); | ||
exports.type = undefined; | ||
exports.create = create; | ||
@@ -13,14 +12,8 @@ exports.close = close; | ||
exports.canBeUsed = canBeUsed; | ||
var isNode = require('detect-node'); | ||
var _detectNode = require('detect-node'); | ||
var _detectNode2 = _interopRequireDefault(_detectNode); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
var type = exports.type = 'native'; | ||
function create(channelName) { | ||
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
function create(channelName, options) { | ||
if (!options) options = {}; | ||
var state = { | ||
@@ -58,5 +51,5 @@ channelName: channelName, | ||
function canBeUsed() { | ||
if (_detectNode2['default']) return false; | ||
if (isNode) return false; | ||
if (typeof BroadcastChannel === 'function') return true; | ||
}; |
@@ -8,18 +8,2 @@ 'use strict'; | ||
var _values = require('babel-runtime/core-js/object/values'); | ||
var _values2 = _interopRequireDefault(_values); | ||
var _keys = require('babel-runtime/core-js/object/keys'); | ||
var _keys2 = _interopRequireDefault(_keys); | ||
var _getIterator2 = require('babel-runtime/core-js/get-iterator'); | ||
var _getIterator3 = _interopRequireDefault(_getIterator2); | ||
var _set = require('babel-runtime/core-js/set'); | ||
var _set2 = _interopRequireDefault(_set); | ||
var _slicedToArray2 = require('babel-runtime/helpers/slicedToArray'); | ||
@@ -29,6 +13,2 @@ | ||
var _stringify = require('babel-runtime/core-js/json/stringify'); | ||
var _stringify2 = _interopRequireDefault(_stringify); | ||
var _regenerator = require('babel-runtime/regenerator'); | ||
@@ -38,6 +18,2 @@ | ||
var _promise = require('babel-runtime/core-js/promise'); | ||
var _promise2 = _interopRequireDefault(_promise); | ||
var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator'); | ||
@@ -67,3 +43,3 @@ | ||
case 5: | ||
_context.t0 = _promise2['default']; | ||
_context.t0 = Promise; | ||
_context.next = 8; | ||
@@ -118,3 +94,3 @@ return mkdir(paths.readers)['catch'](function () { | ||
_context2.next = 5; | ||
return writeFile(pathToFile, (0, _stringify2['default'])({ | ||
return writeFile(pathToFile, JSON.stringify({ | ||
time: new Date().getTime() | ||
@@ -166,3 +142,3 @@ })); | ||
_context3.next = 5; | ||
return new _promise2['default'](function (res) { | ||
return new Promise(function (res) { | ||
server.listen(pathToSocket, function () { | ||
@@ -207,3 +183,3 @@ res(); | ||
_context4.next = 4; | ||
return new _promise2['default'](function (res) { | ||
return new Promise(function (res) { | ||
client.connect(pathToSocket, res); | ||
@@ -251,3 +227,3 @@ }); | ||
_context5.next = 7; | ||
return writeFile(msgPath, (0, _stringify2['default'])(writeObject)); | ||
return writeFile(msgPath, JSON.stringify(writeObject)); | ||
@@ -414,3 +390,3 @@ case 7: | ||
_context10.next = 3; | ||
return _promise2['default'].all(messageObjects.filter(function (obj) { | ||
return Promise.all(messageObjects.filter(function (obj) { | ||
return obj.time < olderThen; | ||
@@ -456,3 +432,3 @@ }).map(function (obj) { | ||
_context12.next = 6; | ||
return _promise2['default'].all([getReadersUuids(channelName), createSocketEventEmitter(channelName, uuid), createSocketInfoFile(channelName, uuid)]); | ||
return Promise.all([getReadersUuids(channelName), createSocketEventEmitter(channelName, uuid), createSocketInfoFile(channelName, uuid)]); | ||
@@ -467,3 +443,3 @@ case 6: | ||
_context12.next = 14; | ||
return _promise2['default'].all(otherReaderUuids.filter(function (readerUuid) { | ||
return Promise.all(otherReaderUuids.filter(function (readerUuid) { | ||
return readerUuid !== uuid; | ||
@@ -511,3 +487,3 @@ }) // not own | ||
// contains all messages that have been emitted before | ||
emittedMessagesIds: new _set2['default'](), | ||
emittedMessagesIds: new Set(), | ||
messagesCallbackTime: null, | ||
@@ -656,3 +632,3 @@ messagesCallback: null, | ||
}); | ||
_iterator = (0, _getIterator3['default'])(useMessages); | ||
_iterator = useMessages[Symbol.iterator](); | ||
@@ -744,3 +720,3 @@ case 16: | ||
// remove subscriptions to closed readers | ||
(0, _keys2['default'])(channelState.otherReaderClients).filter(function (readerUuid) { | ||
Object.keys(channelState.otherReaderClients).filter(function (readerUuid) { | ||
return !otherReaders.includes(readerUuid); | ||
@@ -753,3 +729,3 @@ }).forEach(function (readerUuid) { | ||
_context17.next = 6; | ||
return _promise2['default'].all(otherReaders.filter(function (readerUuid) { | ||
return Promise.all(otherReaders.filter(function (readerUuid) { | ||
return readerUuid !== channelState.uuid; | ||
@@ -841,4 +817,4 @@ }) // not own | ||
_context18.next = 8; | ||
return _promise2['default'].all((0, _values2['default'])(channelState.otherReaderClients).map(function (client) { | ||
return client.write((0, _stringify2['default'])(pingObj)); | ||
return Promise.all(Object.values(channelState.otherReaderClients).map(function (client) { | ||
return client.write(JSON.stringify(pingObj)); | ||
})); | ||
@@ -902,3 +878,3 @@ | ||
(0, _values2['default'])(channelState.otherReaderClients).forEach(function (client) { | ||
Object.values(channelState.otherReaderClients).forEach(function (client) { | ||
return client.destroy(); | ||
@@ -905,0 +881,0 @@ }); |
@@ -7,11 +7,5 @@ 'use strict'; | ||
exports.fillOptionsWithDefaults = fillOptionsWithDefaults; | ||
var _clone = require('clone'); | ||
var _clone2 = _interopRequireDefault(_clone); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
function fillOptionsWithDefaults(options) { | ||
options = (0, _clone2['default'])(options); | ||
if (!options) options = {}; | ||
options = JSON.parse(JSON.stringify(options)); | ||
@@ -18,0 +12,0 @@ // main |
@@ -8,2 +8,3 @@ 'use strict'; | ||
exports.cleanPipeName = cleanPipeName; | ||
exports.sleep = sleep; | ||
/** | ||
@@ -32,2 +33,9 @@ * returns true if the given object is a promise | ||
} | ||
}; | ||
}; | ||
function sleep(time) { | ||
if (!time) time = 0; | ||
return new Promise(function (res) { | ||
return setTimeout(res, time); | ||
}); | ||
} |
{ | ||
"name": "broadcast-channel", | ||
"version": "0.0.1", | ||
"version": "1.0.0", | ||
"description": "A BroadcastChannel implementation that works with new browsers, older browsers and Node.js", | ||
"homepage": "https://pubkey.github.io/broadcast-channel/", | ||
"homepage": "https://github.com/pubkey/broadcast-channel#readme", | ||
"keywords": [ | ||
@@ -26,3 +26,2 @@ "broadcast-channel", | ||
}, | ||
"homepage": "https://github.com/pubkey/broadcast-channel#readme", | ||
"main": "./dist/lib/index.js", | ||
@@ -38,2 +37,3 @@ "jsnext:main": "./dist/es/index.js", | ||
"test:typings": "npm run build && mocha ./test/typings.test.js -b --timeout 12000 --exit", | ||
"test:size": "npm run build && rimraf test_tmp/browserify.js && browserify --no-builtins dist/lib/browserify.index.js > test_tmp/browserify.js && uglifyjs --compress --mangle --output test_tmp/browserify.min.js -- test_tmp/browserify.js && echo \"Build-Size (minified+gzip):\" && gzip-size --raw test_tmp/browserify.min.js", | ||
"lint": "eslint --ignore-path ./config/.eslintignore src test config scripts", | ||
@@ -48,2 +48,3 @@ "clear": "rimraf -rf ./dist && rimraf -rf ./gen", | ||
"build": "npm run clear && concurrently \"npm run build:es6\" \"npm run build:es5\" \"npm run build:test\" && concurrently \"npm run build:browser\" \"npm run build:worker\" \"npm run build:iframe\"", | ||
"build:min": "uglifyjs --compress --mangle --output dist/lib/browserify.min.js -- dist/lib/browserify.index.js", | ||
"docs:only": "http-server ./docs", | ||
@@ -58,3 +59,2 @@ "docs:serve": "npm run build && npm run docs:only" | ||
"babel-runtime": "6.26.0", | ||
"clone": "2.1.1", | ||
"custom-idle-queue": "2.0.1", | ||
@@ -93,2 +93,3 @@ "detect-node": "2.0.3", | ||
"child-process-promise": "^2.2.1", | ||
"clone": "2.1.1", | ||
"concurrently": "3.5.1", | ||
@@ -99,2 +100,3 @@ "convert-hrtime": "2.0.0", | ||
"eslint": "4.19.1", | ||
"gzip-size-cli": "^2.1.0", | ||
"http-server": "0.11.1", | ||
@@ -101,0 +103,0 @@ "karma": "2.0.2", |
@@ -51,2 +51,9 @@ BEFORE: | ||
=> sending localstorage-pings is slower | ||
=> sending localstorage-pings is slower | ||
====== build-size | ||
BEFORE: 37251 | ||
AFTER: 4077 |
@@ -16,3 +16,3 @@ | ||
<img src="https://travis-ci.org/pubkey/broadcast-channel.svg?branch=master" /></a> | ||
<a href="https://twitter.com/intent/follow?screen_name=pubkeypubkey"> | ||
<a href="https://twitter.com/pubkeypubkey"> | ||
<img src="https://img.shields.io/twitter/follow/pubkeypubkey.svg?style=social&logo=twitter" | ||
@@ -26,4 +26,2 @@ alt="follow on Twitter"></a> | ||
# BroadcastChannel | ||
A BroadcastChannel allows simple communication between browsing contexts with the same origin or different NodeJs processes. | ||
@@ -30,0 +28,0 @@ |
@@ -1,4 +0,3 @@ | ||
require('babel-polyfill'); | ||
const BroadcastChannel = require('./index.js'); | ||
window['BroadcastChannel2'] = BroadcastChannel; |
142
src/index.js
@@ -13,4 +13,7 @@ import { | ||
class BroadcastChannel { | ||
constructor(name, options = {}) { | ||
module.exports = (() => { | ||
const BroadcastChannel = function (name, options = {}) { | ||
this.name = name; | ||
@@ -22,40 +25,52 @@ this.options = fillOptionsWithDefaults(options); | ||
this._prepare(); | ||
} | ||
_prepare() { | ||
const maybePromise = this.method.create(this.name, this.options); | ||
if (isPromise(maybePromise)) { | ||
this._preparePromise = maybePromise; | ||
maybePromise.then(async (s) => { | ||
// used in tests to simulate slow runtime | ||
if (this.options.prepareDelay) { | ||
// await new Promise(res => setTimeout(res, this.options.prepareDelay)); | ||
} | ||
this._state = s; | ||
}; | ||
BroadcastChannel.prototype = { | ||
_prepare() { | ||
const maybePromise = this.method.create(this.name, this.options); | ||
if (isPromise(maybePromise)) { | ||
this._preparePromise = maybePromise; | ||
maybePromise.then(s => { | ||
// used in tests to simulate slow runtime | ||
if (this.options.prepareDelay) { | ||
// await new Promise(res => setTimeout(res, this.options.prepareDelay)); | ||
} | ||
this._state = s; | ||
}); | ||
} else { | ||
this._state = maybePromise; | ||
} | ||
}, | ||
postMessage(msg) { | ||
const msgObj = { | ||
time: new Date().getTime(), | ||
data: msg | ||
}; | ||
if (this.closed) { | ||
throw new Error( | ||
'BroadcastChannel.postMessage(): ' + | ||
'Cannot post message after channel has closed' | ||
); | ||
} | ||
const awaitPrepare = this._preparePromise ? this._preparePromise : Promise.resolve(); | ||
return awaitPrepare.then(() => { | ||
return this.method.postMessage( | ||
this._state, | ||
msgObj | ||
); | ||
}); | ||
} else { | ||
this._state = maybePromise; | ||
} | ||
} | ||
async postMessage(msg) { | ||
const msgObj = { | ||
time: new Date().getTime(), | ||
data: msg | ||
}; | ||
if (this.closed) { | ||
throw new Error( | ||
'BroadcastChannel.postMessage(): ' + | ||
'Cannot post message after channel has closed' | ||
); | ||
} | ||
if (this._preparePromise) await this._preparePromise; | ||
return this.method.postMessage( | ||
this._state, | ||
msgObj | ||
); | ||
} | ||
set onmessage(fn) { | ||
const time = new Date().getTime() - 5; | ||
if (this._preparePromise) { | ||
this._preparePromise.then(() => { | ||
}, | ||
set onmessage(fn) { | ||
const time = new Date().getTime() - 5; | ||
if (this._preparePromise) { | ||
this._preparePromise.then(() => { | ||
this.method.onMessage( | ||
this._state, | ||
messageHandler(fn, time), | ||
time | ||
); | ||
}); | ||
} else { | ||
this.method.onMessage( | ||
@@ -66,32 +81,29 @@ this._state, | ||
); | ||
} | ||
}, | ||
close() { | ||
this.closed = true; | ||
const awaitPrepare = this._preparePromise ? this._preparePromise : Promise.resolve(); | ||
return awaitPrepare.then(() => { | ||
return this.method.close( | ||
this._state | ||
); | ||
}); | ||
} else { | ||
this.method.onMessage( | ||
this._state, | ||
messageHandler(fn, time), | ||
time | ||
); | ||
}, | ||
get type() { | ||
return this.method.type; | ||
} | ||
} | ||
async close() { | ||
this.closed = true; | ||
if (this._preparePromise) await this._preparePromise; | ||
await this.method.close( | ||
this._state | ||
); | ||
} | ||
get type() { | ||
return this.method.type; | ||
} | ||
}; | ||
}; | ||
function messageHandler(fn, minTime) { | ||
return msgObj => { | ||
if (msgObj.time >= minTime) { | ||
fn(msgObj.data); | ||
} | ||
function messageHandler(fn, minTime) { | ||
return msgObj => { | ||
if (msgObj.time >= minTime) { | ||
fn(msgObj.data); | ||
} | ||
}; | ||
}; | ||
} | ||
export default BroadcastChannel; | ||
module.exports = BroadcastChannel; | ||
return BroadcastChannel; | ||
})(); |
@@ -1,6 +0,6 @@ | ||
import isNode from 'detect-node'; | ||
const isNode = require('detect-node'); | ||
import * as NativeMethod from './methods/native.js'; | ||
import * as IndexeDbMethod from './methods/indexed-db.js'; | ||
import * as LocalstorageMethod from './methods/localstorage.js'; | ||
const NativeMethod = require('./methods/native.js'); | ||
const IndexeDbMethod = require('./methods/indexed-db.js'); | ||
const LocalstorageMethod = require('./methods/localstorage.js'); | ||
@@ -14,2 +14,4 @@ // order is important | ||
const REQUIRE_FUN = require; | ||
/** | ||
@@ -20,3 +22,3 @@ * The NodeMethod is loaded lazy | ||
if (isNode) { | ||
const NodeMethod = require('./methods/node.js'); | ||
const NodeMethod = REQUIRE_FUN('./methods/node.js'); | ||
METHODS.push(NodeMethod); | ||
@@ -23,0 +25,0 @@ } |
@@ -9,8 +9,12 @@ /** | ||
import isNode from 'detect-node'; | ||
import randomToken from 'random-token'; | ||
import randomInt from 'random-int'; | ||
import IdleQueue from 'custom-idle-queue'; | ||
const isNode = require('detect-node'); | ||
const randomToken = require('random-token'); | ||
const randomInt = require('random-int'); | ||
const IdleQueue = require('custom-idle-queue'); | ||
import { | ||
sleep | ||
} from '../util.js'; | ||
import { | ||
fillOptionsWithDefaults | ||
@@ -33,3 +37,3 @@ } from '../options'; | ||
export async function createDatabase(channelName) { | ||
export function createDatabase(channelName) { | ||
const IndexedDB = getIdb(); | ||
@@ -48,3 +52,3 @@ | ||
}; | ||
const db = await new Promise((res, rej) => { | ||
const dbPromise = new Promise((res, rej) => { | ||
openRequest.onerror = ev => rej(ev); | ||
@@ -56,4 +60,5 @@ openRequest.onsuccess = () => { | ||
return db; | ||
return dbPromise; | ||
} | ||
/** | ||
@@ -63,3 +68,3 @@ * writes the new message to the database | ||
*/ | ||
export async function writeMessage(db, readerUuid, messageJson) { | ||
export function writeMessage(db, readerUuid, messageJson) { | ||
const time = new Date().getTime(); | ||
@@ -83,3 +88,3 @@ const writeObject = { | ||
export async function getAllMessages(db) { | ||
export function getAllMessages(db) { | ||
const objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID); | ||
@@ -101,3 +106,3 @@ const ret = []; | ||
export async function getMessagesHigherThen(db, lastCursorId) { | ||
export function getMessagesHigherThen(db, lastCursorId) { | ||
const objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID); | ||
@@ -120,3 +125,3 @@ const ret = []; | ||
export async function removeMessageById(db, id) { | ||
export function removeMessageById(db, id) { | ||
const request = db.transaction([OBJECT_STORE_ID], 'readwrite') | ||
@@ -130,3 +135,3 @@ .objectStore(OBJECT_STORE_ID) | ||
export async function getOldMessages(db, ttl) { | ||
export function getOldMessages(db, ttl) { | ||
const olderThen = new Date().getTime() - ttl; | ||
@@ -156,10 +161,12 @@ const objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID); | ||
export async function cleanOldMessages(db, ttl) { | ||
const tooOld = await getOldMessages(db, ttl); | ||
return Promise.all( | ||
tooOld.map(msgObj => removeMessageById(db, msgObj.id)) | ||
); | ||
export function cleanOldMessages(db, ttl) { | ||
return getOldMessages(db, ttl) | ||
.then(tooOld => { | ||
return Promise.all( | ||
tooOld.map(msgObj => removeMessageById(db, msgObj.id)) | ||
); | ||
}); | ||
} | ||
export async function create(channelName, options = {}) { | ||
export function create(channelName, options) { | ||
options = fillOptionsWithDefaults(options); | ||
@@ -172,31 +179,37 @@ | ||
const db = await createDatabase(channelName); | ||
const state = { | ||
closed: false, | ||
lastCursorId: 0, | ||
channelName, | ||
options, | ||
uuid, | ||
// contains all messages that have been emitted before | ||
emittedMessagesIds: new Set(), | ||
messagesCallback: null, | ||
readQueue, | ||
db | ||
}; | ||
/** | ||
* if service-workers are used, | ||
* we have no 'storage'-event if they post a message, | ||
* therefore we also have to set an interval | ||
*/ | ||
(async () => { | ||
while (state.closed === false) { | ||
await handleMessagePing(state); | ||
await new Promise(res => setTimeout(res, state.options.idb.fallbackInterval)); | ||
} | ||
})(); | ||
return createDatabase(channelName).then(db => { | ||
const state = { | ||
closed: false, | ||
lastCursorId: 0, | ||
channelName, | ||
options, | ||
uuid, | ||
// contains all messages that have been emitted before | ||
emittedMessagesIds: new Set(), | ||
messagesCallback: null, | ||
readQueue, | ||
db | ||
}; | ||
return state; | ||
/** | ||
* if service-workers are used, | ||
* we have no 'storage'-event if they post a message, | ||
* therefore we also have to set an interval | ||
*/ | ||
_readLoop(state); | ||
return state; | ||
}); | ||
} | ||
function _readLoop(state) { | ||
if (state.closed) return; | ||
return handleMessagePing(state) | ||
.then(() => sleep(state.options.idb.fallbackInterval)) | ||
.then(() => _readLoop(state)); | ||
} | ||
/** | ||
@@ -206,7 +219,7 @@ * when the storage-event pings, so that we now new messages came, | ||
*/ | ||
export async function handleMessagePing(state) { | ||
export function handleMessagePing(state) { | ||
/** | ||
* when there are no listener, we do nothing | ||
*/ | ||
if (!state.messagesCallback) return; | ||
if (!state.messagesCallback) return Promise.resolve(); | ||
@@ -217,8 +230,13 @@ /** | ||
*/ | ||
if (state.readQueue._idleCalls.size > 1) return; | ||
if (state.readQueue._idleCalls.size > 1) return Promise.resolve(); | ||
await state.readQueue.requestIdlePromise(); | ||
await state.readQueue.wrapCall( | ||
async () => { | ||
const newerMessages = await getMessagesHigherThen(state.db, state.lastCursorId); | ||
return state.readQueue.requestIdlePromise() | ||
.then(() => state.readQueue.wrapCall( | ||
() => _handleMessagePingInner(state) | ||
)); | ||
} | ||
function _handleMessagePingInner(state) { | ||
return getMessagesHigherThen(state.db, state.lastCursorId) | ||
.then(newerMessages => { | ||
const useMessages = newerMessages | ||
@@ -236,3 +254,4 @@ .map(msgObj => { | ||
for (const msgObj of useMessages) { | ||
useMessages.forEach(msgObj => { | ||
if (state.messagesCallback) { | ||
@@ -247,5 +266,6 @@ state.emittedMessagesIds.add(msgObj.id); | ||
} | ||
} | ||
} | ||
); | ||
}); | ||
return Promise.resolve(); | ||
}); | ||
} | ||
@@ -259,15 +279,15 @@ | ||
export async function postMessage(channelState, messageJson) { | ||
await writeMessage( | ||
export function postMessage(channelState, messageJson) { | ||
return writeMessage( | ||
channelState.db, | ||
channelState.uuid, | ||
messageJson | ||
); | ||
if (randomInt(0, 10) === 0) { | ||
/* await (do not await) */ cleanOldMessages( | ||
channelState.db, | ||
channelState.options.idb.ttl | ||
); | ||
} | ||
).then(() => { | ||
if (randomInt(0, 10) === 0) { | ||
/* await (do not await) */ cleanOldMessages( | ||
channelState.db, | ||
channelState.options.idb.ttl | ||
); | ||
} | ||
}); | ||
} | ||
@@ -274,0 +294,0 @@ |
@@ -9,5 +9,4 @@ /** | ||
import isNode from 'detect-node'; | ||
import randomToken from 'random-token'; | ||
import IdleQueue from 'custom-idle-queue'; | ||
const isNode = require('detect-node'); | ||
const randomToken = require('random-token'); | ||
@@ -18,2 +17,6 @@ import { | ||
import { | ||
sleep | ||
} from '../util'; | ||
const KEY_PREFIX = 'pubkey.broadcastChannel-'; | ||
@@ -49,25 +52,29 @@ export const type = 'localstorage'; | ||
*/ | ||
export async function postMessage(channelState, messageJson) { | ||
await new Promise(res => setTimeout(res, 0)); | ||
export function postMessage(channelState, messageJson) { | ||
return new Promise(res => { | ||
sleep().then(() => { | ||
const key = storageKey(channelState.channelName); | ||
const writeObj = { | ||
token: randomToken(10), | ||
time: new Date().getTime(), | ||
data: messageJson, | ||
uuid: channelState.uuid | ||
}; | ||
const value = JSON.stringify(writeObj); | ||
localStorage.setItem(key, value); | ||
const key = storageKey(channelState.channelName); | ||
const writeObj = { | ||
token: randomToken(10), | ||
time: new Date().getTime(), | ||
data: messageJson, | ||
uuid: channelState.uuid | ||
}; | ||
const 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 | ||
*/ | ||
const ev = document.createEvent('Event'); | ||
ev.initEvent('storage', true, true); | ||
ev.key = key; | ||
ev.newValue = value; | ||
window.dispatchEvent(ev); | ||
/** | ||
* StorageEvent does not fire the 'storage' event | ||
* in the window that changes the state of the local storage. | ||
* So we fire it manually | ||
*/ | ||
const ev = document.createEvent('Event'); | ||
ev.initEvent('storage', true, true); | ||
ev.key = key; | ||
ev.newValue = value; | ||
window.dispatchEvent(ev); | ||
res(); | ||
}); | ||
}); | ||
} | ||
@@ -89,5 +96,5 @@ | ||
export function create(channelName, options = {}) { | ||
export function create(channelName, options) { | ||
options = fillOptionsWithDefaults(options); | ||
if(!canBeUsed()){ | ||
if (!canBeUsed()) { | ||
throw new Error('BroadcastChannel: localstorage cannot be used'); | ||
@@ -102,4 +109,2 @@ } | ||
const writeQueue = new IdleQueue(1); | ||
const state = { | ||
@@ -110,4 +115,3 @@ startTime, | ||
uuid, | ||
emittedMessagesIds, | ||
writeQueue | ||
emittedMessagesIds | ||
}; | ||
@@ -118,3 +122,3 @@ | ||
channelName, | ||
async (msgObj) => { | ||
(msgObj) => { | ||
if (!state.messagesCallback) return; // no listener | ||
@@ -140,3 +144,2 @@ if (msgObj.uuid === uuid) return; // own message | ||
removeStorageEventListener(channelState.listener); | ||
channelState.writeQueue.clear(); | ||
} | ||
@@ -143,0 +146,0 @@ |
@@ -1,7 +0,7 @@ | ||
import isNode from 'detect-node'; | ||
const isNode = require('detect-node'); | ||
export const type = 'native'; | ||
export function create(channelName, options = {}) { | ||
export function create(channelName, options) { | ||
if(!options) options = {}; | ||
const state = { | ||
@@ -8,0 +8,0 @@ channelName, |
@@ -1,5 +0,4 @@ | ||
import clone from 'clone'; | ||
export function fillOptionsWithDefaults(options) { | ||
options = clone(options); | ||
if(!options) options = {}; | ||
options = JSON.parse(JSON.stringify(options)); | ||
@@ -6,0 +5,0 @@ // main |
@@ -29,1 +29,6 @@ /** | ||
}; | ||
export function sleep(time) { | ||
if (!time) time = 0; | ||
return new Promise(res => setTimeout(res, time)); | ||
} |
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
8
0
3
168493
52
35
3795
117
6
- Removedclone@2.1.1
- Removedclone@2.1.1(transitive)