diff --git a/www/common/outer/worker-channel.js b/www/common/outer/worker-channel.js index 06c81d1eb..3649ab0ea 100644 --- a/www/common/outer/worker-channel.js +++ b/www/common/outer/worker-channel.js @@ -8,22 +8,30 @@ define([ return Math.random().toString(16).replace('0.', '') + Math.random().toString(16).replace('0.', ''); }; - var create = function (onMsg, postMsg, cb, isWorker) { + var create = function (onMsg, postMsg, cb) { var chanLoaded; - var waitingData; - if (!isWorker) { - chanLoaded = false; - waitingData = []; - onMsg.reg(function (data) { - if (chanLoaded) { return; } - waitingData.push(data); - }); - } + var waitingData = []; var evReady = Util.mkEvent(true); + onMsg.reg(function (msg) { + if (chanLoaded) { return; } + var data = msg.data; + if (data === '_READY') { + postMsg('_READY'); + chanLoaded = true; + evReady.fire(); + waitingData.forEach(function (d) { + onMsg.fire(d); + }); + return; + } + waitingData.push(data); + }); + var handlers = {}; var queries = {}; + var acks = {}; // list of handlers which are registered from the other side... var insideHandlers = []; @@ -32,16 +40,24 @@ define([ var chan = {}; // Send a query. channel.query('Q_SOMETHING', { args: "whatever" }, function (reply) { ... }); + // We have a timeout for receiving an ACK, but unlimited time for receiving an answer to the query chan.query = function (q, content, cb, opts) { var txid = mkTxid(); opts = opts || {}; var to = opts.timeout || 30000; var timeout = setTimeout(function () { delete queries[txid]; - //console.log("Timeout making query " + q); + cb('TIMEOUT'); }, to); - queries[txid] = function (data, msg) { + acks[txid] = function (err) { clearTimeout(timeout); + delete acks[txid]; + if (err) { + delete queries[txid]; + cb('UNHANDLED'); + } + }; + queries[txid] = function (data, msg) { delete queries[txid]; cb(undefined, data.content, msg); }; @@ -103,10 +119,10 @@ define([ } insideHandlers.push(content); }); - chan.whenReg('EV_REGISTER_HANDLER', evReady.fire); + //chan.whenReg('EV_REGISTER_HANDLER', evReady.fire); // Make sure both iframes are ready - var isReady =false; + var isReady = false; chan.onReady = function (h) { if (isReady) { return void h(); @@ -121,29 +137,43 @@ define([ }; onMsg.reg(function (msg) { + if (!chanLoaded) { return; } + if (!msg.data || msg.data === '_READY') { return; } var data = JSON.parse(msg.data); - if (typeof(data.q) === 'string' && handlers[data.q]) { - handlers[data.q].forEach(function (f) { - f(data || JSON.parse(msg.data), msg); - data = undefined; - }); + if (typeof(data.ack) !== "undefined") { + if (acks[data.txid]) { acks[data.txid](!data.ack); } + } else if (typeof(data.q) === 'string') { + if (handlers[data.q]) { + // If this is a "query", send an ack + if (data.txid) { + postMsg(JSON.stringify({ + txid: data.txid, + ack: true + })); + } + handlers[data.q].forEach(function (f) { + f(data || JSON.parse(msg.data), msg); + data = undefined; + }); + } else { + if (data.txid) { + postMsg(JSON.stringify({ + txid: data.txid, + ack: false + })); + } + } } else if (typeof(data.q) === 'undefined' && queries[data.txid]) { queries[data.txid](data, msg); } else { - console.log("DROP Unhandled message"); - console.log(msg.data, isWorker); - console.log(msg); + /*console.log("DROP Unhandled message"); + console.log(msg.data, window); + console.log(msg);*/ } }); - if (isWorker) { - evReady.fire(); - } else { - chanLoaded = true; - waitingData.forEach(function (d) { - onMsg.fire(d); - }); - waitingData = []; - } + + postMsg('_READY'); + cb(chan); }; diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index 1a0a066c8..4ccd28b65 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -36,7 +36,7 @@ define([ '/common/cryptpad-common.js', '/bower_components/chainpad-crypto/crypto.js', '/common/cryptget.js', - '/common/sframe-channel.js', + '/common/outer/worker-channel.js', '/filepicker/main.js', '/common/common-messaging.js', '/common/common-notifier.js', @@ -89,9 +89,36 @@ define([ } }); - SFrameChannel.create($('#sbox-iframe')[0].contentWindow, waitFor(function (sfc) { - sframeChan = sfc; - }), false, { cache: cache, localStore: localStore, language: Cryptpad.getLanguage() }); + // The inner iframe tries to get some data from us every ms (cache, store...). + // It will send a "READY" message and wait for our answer with the correct txid. + // First, we have to answer to this message, otherwise we're going to block + // sframe-boot.js. Then we can start the channel. + var msgEv = _Util.mkEvent(); + var iframe = $('#sbox-iframe')[0].contentWindow; + var iframeReady = false; + var postMsg = function (data) { + iframe.postMessage(data, '*'); + }; + var whenReady = waitFor(function (msg) { + if (msg.source !== iframe) { return; } + var data = JSON.parse(msg.data); + if (!data.txid) { return; } + // Remove the listener once we've received the READY message + window.removeEventListener('message', whenReady); + // Answer with the requested data + postMsg(JSON.stringify({ txid: data.txid, cache: cache, localStore: localStore, language: Cryptpad.getLanguage() })); + + // Then start the channel + window.addEventListener('message', function (msg) { + if (msg.source !== iframe) { return; } + msgEv.fire(msg); + }); + SFrameChannel.create(msgEv, postMsg, waitFor(function (sfc) { + sframeChan = sfc; + })); + }); + window.addEventListener('message', whenReady); + Cryptpad.loading.onDriveEvent.reg(function (data) { if (sframeChan) { sframeChan.event('EV_LOADING_INFO', data); } }); diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js index 468d724dd..3170d974e 100644 --- a/www/common/sframe-common.js +++ b/www/common/sframe-common.js @@ -3,7 +3,7 @@ define([ '/bower_components/nthen/index.js', '/customize/messages.js', '/common/sframe-chainpad-netflux-inner.js', - '/common/sframe-channel.js', + '/common/outer/worker-channel.js', '/common/sframe-common-title.js', '/common/common-ui-elements.js', '/common/sframe-common-history.js', @@ -481,8 +481,16 @@ define([ window.CryptPad_sframe_common = true; nThen(function (waitFor) { - SFrameChannel.create(window.parent, waitFor(function (sfc) { ctx.sframeChan = sfc; }), true); - // CpNfInner.start() should be here.... + var msgEv = Util.mkEvent(); + var iframe = window.parent; + window.addEventListener('message', function (msg) { + if (msg.source !== iframe) { return; } + msgEv.fire(msg); + }); + var postMsg = function (data) { + iframe.postMessage(data, '*'); + }; + SFrameChannel.create(msgEv, postMsg, waitFor(function (sfc) { ctx.sframeChan = sfc; })); }).nThen(function (waitFor) { localForage.clear(); Language.applyTranslation();