diff --git a/lib/historyKeeper.js b/lib/historyKeeper.js index b874aa074..93ab16e1a 100644 --- a/lib/historyKeeper.js +++ b/lib/historyKeeper.js @@ -64,6 +64,11 @@ module.exports.create = function (Env, cb) { }); } + if (metadata && metadata.selfdestruct && metadata.selfdestruct !== Env.id) { + HK.expireChannel(Env, channelName); + return void cb('ESELFDESTRUCT'); + } + if (Env.selfDestructTo && Env.selfDestructTo[channelName]) { clearTimeout(Env.selfDestructTo[channelName]); } diff --git a/lib/hk-util.js b/lib/hk-util.js index 342bd4e70..9d0f65433 100644 --- a/lib/hk-util.js +++ b/lib/hk-util.js @@ -120,7 +120,7 @@ var CHECKPOINT_PATTERN = /^cp\|(([A-Za-z0-9+\/=]+)\|)?/; /* expireChannel is here to clean up channels that should have been removed but for some reason are still present */ -const expireChannel = function (Env, channel) { +const expireChannel = HK.expireChannel = function (Env, channel) { return void Env.store.archiveChannel(channel, function (err) { Env.Log.info("ARCHIVAL_CHANNEL_BY_HISTORY_KEEPER_EXPIRATION", { channelId: channel, @@ -571,6 +571,10 @@ const handleRPC = function (Env, Server, seq, userId, parsed) { if the provided metadata has an expire time then we also create a task to expire it. */ const handleFirstMessage = function (Env, channelName, metadata) { + if (metadata.selfdestruct) { + // Set the selfdestruct flag to history keeper ID to handle server crash. + metadata.selfdestruct = Env.id; + } Env.store.writeMetadata(channelName, JSON.stringify(metadata), function (err) { if (err) { // FIXME tell the user that there was a channel error? diff --git a/www/common/sframe-app-framework.js b/www/common/sframe-app-framework.js index 98f66463d..f8e3dd0d9 100644 --- a/www/common/sframe-app-framework.js +++ b/www/common/sframe-app-framework.js @@ -459,7 +459,8 @@ define([ } } - common.getSframeChannel().on('EV_VERSION_TIME', function (time) { + var sframeChan = common.getSframeChannel(); + sframeChan.on('EV_VERSION_TIME', function (time) { if (!versionHashEl) { return; } var vTime = time; var vTimeStr = vTime ? new Date(vTime).toLocaleString() @@ -468,6 +469,11 @@ define([ versionHashEl.innerText = vTxt; versionHashEl = undefined; }); + sframeChan.on('EV_INTEGRATION_NEEDSAVE', function (format) { + // XXX + // check priv.initialState.name (Blob) to get the format + sframeChan.event('Q_INTEGRATION_SAVE', {}); + }); }; var noCache = false; // Prevent reload loops diff --git a/www/common/sframe-app-outer.js b/www/common/sframe-app-outer.js index c04a99237..7d74fb836 100644 --- a/www/common/sframe-app-outer.js +++ b/www/common/sframe-app-outer.js @@ -29,6 +29,7 @@ define([ useCreationScreen: !isIntegration, messaging: true, integration: isIntegration, + integrationUtils: integration.utils, initialState: integration.initialState || undefined }); }); diff --git a/www/common/sframe-chainpad-netflux-outer.js b/www/common/sframe-chainpad-netflux-outer.js index f47dc812a..e74392678 100644 --- a/www/common/sframe-chainpad-netflux-outer.js +++ b/www/common/sframe-chainpad-netflux-outer.js @@ -31,6 +31,7 @@ define([], function () { var versionHash = conf.versionHash; var validateKey = metadata.validateKey; var onConnect = conf.onConnect || function () { }; + var onError = conf.onError || function () { }; var lastTime; // Time of last patch (if versioned link); conf = undefined; @@ -143,6 +144,7 @@ define([], function () { }); padRpc.onErrorEvent.reg(function (err) { + onError(err); sframeChan.event('EV_RT_ERROR', err); }); diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index 75b02ad65..9fa8fd9ac 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -1926,6 +1926,19 @@ define([ } }); + var integrationSave = function () {}; + if (cfg.integration) { + // TODO + sframeChan.on('Q_INTEGRATION_SAVE', function (obj, cb) { + if (cfg.integrationUtils && cfg.integrationUtils.save) { + cfg.integrationUtils.save(obj, cb); + } + }); + integrationSave = function () { + sframeChan.event('EV_INTEGRATION_NEEDSAVE'); + }; + } + if (cfg.messaging) { sframeChan.on('Q_CHAT_OPENPADCHAT', function (data, cb) { Cryptpad.universal.execCommand({ @@ -2016,6 +2029,11 @@ define([ validateKey: secret.keys.validateKey }; } + if (cfg.integration) { + rtConfig.metadata = rtConfig.metadata || {}; + rtConfig.metadata.selfdestruct = true; + } + var cpNfCfg = { sframeChan: sframeChan, @@ -2036,6 +2054,13 @@ define([ } if (readOnly || cfg.noHash) { return; } replaceHash(Utils.Hash.getEditHashFromKeys(secret)); + }, + onError: function (err) { + if (!cfg.integration) { return; } + console.error(err); + if (cfg.integrationUtils && cfg.integrationUtils.reload) { + cfg.integrationUtils.reload(); + } } }; @@ -2089,9 +2114,7 @@ define([ metadata: {} }; - if (cfg.integration) { - rtConfig.metadata.selfdestruct = true; - } + if (cfg.integration) { rtConfig.metadata.selfdestruct = true; } if (data.team) { Cryptpad.initialTeam = data.team.id; diff --git a/www/cryptpad-api.js b/www/cryptpad-api.js index 7e70a4c0f..09d2bdaed 100644 --- a/www/cryptpad-api.js +++ b/www/cryptpad-api.js @@ -69,14 +69,13 @@ }; }; + var makeIframe = function () {} // placeholder + var start = function (config, chan) { return new Promise(function (resolve, reject) { setTimeout(function () { var key = config.document.key; - - chan.on('SAVE', function (data) { - config.events.onSave(data); - }); + var blob; var getBlob = function (cb) { var xhr = new XMLHttpRequest(); @@ -97,7 +96,7 @@ xhr.send(); }; - var start = function (blob) { + var start = function () { chan.send('START', { key: key, application: config.documentType, @@ -106,26 +105,45 @@ if (obj && obj.error) { reject(obj.error); return console.error(obj.error); } console.log('OUTER START SUCCESS'); resolve({}); + resolve = function () {}; + reject = function () {}; }); }; var onKeyValidated = function () { - getBlob(function (err, blob) { + if (config.document.blob) { // This is a reload + blob = config.document.blob; + return start(); + } + getBlob(function (err, _blob) { if (err) { reject(err); return console.error(err); } - blob.name = `document.${config.document.fileType}`; - start(blob); + _blob.name = `document.${config.document.fileType}`; + blob = _blob; + start(); }); }; - chan.send('GET_SESSION', { - key: key - }, function (obj) { - if (obj && obj.error) { reject(obj.error); return console.error(obj.error); } - if (obj.key !== key) { - key = obj.key; - config.events.onNewKey(key); - } - onKeyValidated(); + var getSession = function (cb) { + chan.send('GET_SESSION', { + key: key + }, function (obj) { + if (obj && obj.error) { reject(obj.error); return console.error(obj.error); } + if (obj.key !== key) { + key = obj.key; + config.events.onNewKey(key); + } + cb(); + }); + }; + getSession(onKeyValidated); + + chan.on('SAVE', function (data) { + config.events.onSave(data); + }); + chan.on('RELOAD', function (data) { + config.document.blob = blob; + document.getElementById('cryptpad-editor').remove(); + makeIframe(config); }); }); @@ -188,20 +206,22 @@ return reject('Invalid arg: cryptpadURL'); } - var iframe = document.createElement('iframe'); - iframe.setAttribute('id', 'cryptpad-editor'); - iframe.setAttribute("src", url); - container.appendChild(iframe); + makeIframe = function (config) { + var iframe = document.createElement('iframe'); + iframe.setAttribute('id', 'cryptpad-editor'); + iframe.setAttribute("src", url); + container.appendChild(iframe); - var onMsg = function (msg) { - var data = typeof(msg.data) === "string" ? JSON.parse(msg.data) : msg.data; - if (!data || data.q !== 'INTEGRATION_READY') { return; } - window.removeEventListener('message', onMsg); - var chan = makeChan(iframe, parsed.origin); - start(config, chan).then(resolve).catch(reject); + var onMsg = function (msg) { + var data = typeof(msg.data) === "string" ? JSON.parse(msg.data) : msg.data; + if (!data || data.q !== 'INTEGRATION_READY') { return; } + window.removeEventListener('message', onMsg); + var chan = makeChan(iframe, parsed.origin); + start(config, chan).then(resolve).catch(reject); + }; + window.addEventListener('message', onMsg); }; - window.addEventListener('message', onMsg); - + makeIframe(config); }); }); }; diff --git a/www/integration/main.js b/www/integration/main.js index ce7aceb1f..48daa1b3d 100644 --- a/www/integration/main.js +++ b/www/integration/main.js @@ -110,6 +110,14 @@ define([ }); }); + var save = function (data, cb) { + + }; + var reload = function (data, cb) { + chan.send('RELOAD', data); + console.error(data); + }; + chan.on('START', function (data) { console.warn('INNER START', data); var href = Hash.hashToHref(data.key, data.application); @@ -118,7 +126,11 @@ define([ pathname: `/${data.application}/`, hash: data.key, href: href, - initialState: isNew ? data.document : undefined + initialState: data.document, + utils: { + save: save, + reload: reload + } }; require(['/common/sframe-app-outer.js'], function () { console.warn('SAO REQUIRED');