Merge branch 'serviceworker' into staging

pull/1/head
yflory 7 years ago
commit 4896fe81fe

@ -89,7 +89,7 @@ define([
};
/* Used to accept friend requests within apps other than /contacts/ */
Msg.addDirectMessageHandler = function (cfg) {
Msg.addDirectMessageHandler = function (cfg, href) {
var network = cfg.network;
var proxy = cfg.proxy;
if (!network) { return void console.error('Network not ready'); }
@ -97,13 +97,12 @@ define([
var msg;
if (sender === network.historyKeeper) { return; }
try {
var parsed = Hash.parsePadUrl(window.location.href);
var parsed = Hash.parsePadUrl(href);
var secret = Hash.getSecrets(parsed.type, parsed.hash);
if (!parsed.hashData) { return; }
var chan = Hash.hrefToHexChannelId(window.location.href);
var chan = secret.channel;
// Decrypt
var keyStr = parsed.hashData.key;
var cryptor = Crypto.createEditCryptor(keyStr);
var key = cryptor.cryptKey;
var key = secret.keys ? secret.keys.cryptKey : Hash.decodeBase64(secret.key);
var decryptMsg;
try {
decryptMsg = Crypto.decrypt(message, key);
@ -197,15 +196,14 @@ define([
var network = cfg.network;
var netfluxId = data.netfluxId;
var parsed = Hash.parsePadUrl(data.href);
var secret = Hash.getSecrets(parsed.type, parsed.hash);
if (!parsed.hashData) { return; }
// Message
var chan = Hash.hrefToHexChannelId(data.href);
var chan = secret.channel;
var myData = createData(cfg.proxy);
var msg = ["FRIEND_REQ", chan, myData];
// Encryption
var keyStr = parsed.hashData.key;
var cryptor = Crypto.createEditCryptor(keyStr);
var key = cryptor.cryptKey;
var key = secret.keys ? secret.keys.cryptKey : Hash.decodeBase64(secret.key);
var msgStr = Crypto.encrypt(JSON.stringify(msg), key);
// Send encrypted message
if (pendingRequests.indexOf(netfluxId) === -1) {

@ -7,25 +7,27 @@ define([
'/common/common-constants.js',
'/common/common-feedback.js',
'/common/outer/local-store.js',
'/common/outer/store-rpc.js',
'/common/outer/worker-channel.js',
'/customize/application_config.js',
'/bower_components/nthen/index.js',
], function (Config, Messages, Util, Hash,
Messaging, Constants, Feedback, LocalStore, AStore,
Messaging, Constants, Feedback, LocalStore, Channel,
AppConfig, Nthen) {
/* This file exposes functionality which is specific to Cryptpad, but not to
any particular pad type. This includes functions for committing metadata
about pads to your local storage for future use and improved usability.
Additionally, there is some basic functionality for import/export.
*/
var postMessage = function (cmd, data, cb) {
setTimeout(function () {
var urlArgs = Util.find(Config, ['requireConf', 'urlArgs']) || '';
var postMessage = function (/*cmd, data, cb*/) {
/*setTimeout(function () {
AStore.query(cmd, data, cb);
});
});*/
console.error('NOT_READY');
};
var tryParsing = function (x) {
try { return JSON.parse(x); }
@ -531,6 +533,11 @@ define([
var messaging = common.messaging = {};
messaging.onFriendRequest = Util.mkEvent();
messaging.onFriendComplete = Util.mkEvent();
messaging.addHandlers = function (href) {
postMessage("ADD_DIRECT_MESSAGE_HANDLERS", {
href: href
});
};
// Messenger
var messenger = common.messenger = {};
@ -570,8 +577,8 @@ define([
// Pad RPC
var pad = common.padRpc = {};
pad.joinPad = function (data, cb) {
postMessage("JOIN_PAD", data, cb);
pad.joinPad = function (data) {
postMessage("JOIN_PAD", data);
};
pad.sendPadMsg = function (data, cb) {
postMessage("SEND_PAD_MSG", data, cb);
@ -581,6 +588,7 @@ define([
pad.onJoinEvent = Util.mkEvent();
pad.onLeaveEvent = Util.mkEvent();
pad.onDisconnectEvent = Util.mkEvent();
pad.onConnectEvent = Util.mkEvent();
pad.onErrorEvent = Util.mkEvent();
// Loading events
@ -669,41 +677,25 @@ define([
window.location.href = '/login/';
};
common.startAccountDeletion = function (cb) {
common.startAccountDeletion = function (data, cb) {
// Logout other tabs
LocalStore.logout(null, true);
cb();
};
var onMessage = function (cmd, data, cb) {
cb = cb || function () {};
switch (cmd) {
case 'REQUEST_LOGIN': {
requestLogin();
break;
}
case 'UPDATE_METADATA': {
common.changeMetadata();
break;
}
case 'UPDATE_TOKEN': {
var queries = {
REQUEST_LOGIN: requestLogin,
UPDATE_METADATA: common.changeMetadata,
UPDATE_TOKEN: function (data) {
var localToken = tryParsing(localStorage.getItem(Constants.tokenKey));
if (localToken !== data.token) { requestLogin(); }
break;
}
case 'Q_FRIEND_REQUEST': {
common.messaging.onFriendRequest.fire(data, cb);
break;
}
case 'EV_FRIEND_COMPLETE': {
common.messaging.onFriendComplete.fire(data);
break;
}
},
// Messaging
Q_FRIEND_REQUEST: common.messaging.onFriendRequest.fire,
EV_FIREND_COMPLETE: common.messaging.onFriendComplete.fire,
// Network
case 'NETWORK_DISCONNECT': {
common.onNetworkDisconnect.fire(); break;
}
case 'NETWORK_RECONNECT': {
NETWORK_DISCONNECT: common.onNetworkDisconnect.fire,
NETWORK_RECONNECT: function (data) {
require(['/api/config?' + (+new Date())], function (NewConfig) {
var update = updateLocalVersion(NewConfig.requireConf && NewConfig.requireConf.urlArgs);
if (update) {
@ -712,65 +704,30 @@ define([
}
common.onNetworkReconnect.fire(data);
});
break;
}
},
// Messenger
case 'CONTACTS_MESSAGE': {
common.messenger.onMessageEvent.fire(data); break;
}
case 'CONTACTS_JOIN': {
common.messenger.onJoinEvent.fire(data); break;
}
case 'CONTACTS_LEAVE': {
common.messenger.onLeaveEvent.fire(data); break;
}
case 'CONTACTS_UPDATE': {
common.messenger.onUpdateEvent.fire(data); break;
}
case 'CONTACTS_FRIEND': {
common.messenger.onFriendEvent.fire(data); break;
}
case 'CONTACTS_UNFRIEND': {
common.messenger.onUnfriendEvent.fire(data); break;
}
CONTACTS_MESSAGE: common.messenger.onMessageEvent.fire,
CONTACTS_JOIN: common.messenger.onJoinEvent.fire,
CONTACTS_LEAVE: common.messenger.onLeaveEvent.fire,
CONTACTS_UPDATE: common.messenger.onUpdateEvent.fire,
CONTACTS_FRIEND: common.messenger.onFriendEvent.fire,
CONTACTS_UNFRIEND: common.messenger.onUnfriendEvent.fire,
// Pad
case 'PAD_READY': {
common.padRpc.onReadyEvent.fire(); break;
}
case 'PAD_MESSAGE': {
common.padRpc.onMessageEvent.fire(data); break;
}
case 'PAD_JOIN': {
common.padRpc.onJoinEvent.fire(data); break;
}
case 'PAD_LEAVE': {
common.padRpc.onLeaveEvent.fire(data); break;
}
case 'PAD_DISCONNECT': {
common.padRpc.onDisconnectEvent.fire(data); break;
}
case 'PAD_ERROR': {
common.padRpc.onErrorEvent.fire(data); break;
}
PAD_READY: common.padRpc.onReadyEvent.fire,
PAD_MESSAGE: common.padRpc.onMessageEvent.fire,
PAD_JOIN: common.padRpc.onJoinEvent.fire,
PAD_LEAVE: common.padRpc.onLeaveEvent.fire,
PAD_DISCONNECT: common.padRpc.onDisconnectEvent.fire,
PAD_CONNECT: common.padRpc.onConnectEvent.fire,
PAD_ERROR: common.padRpc.onErrorEvent.fire,
// Drive
case 'DRIVE_LOG': {
common.drive.onLog.fire(data); break;
}
case 'DRIVE_CHANGE': {
common.drive.onChange.fire(data); break;
}
case 'DRIVE_REMOVE': {
common.drive.onRemove.fire(data); break;
}
DRIVE_LOG: common.drive.onLog.fire,
DRIVE_CHANGE: common.drive.onChange.fire,
DRIVE_REMOVE: common.drive.onRemove.fire,
// Account deletion
case 'DELETE_ACCOUNT': {
common.startAccountDeletion(cb); break;
}
DELETE_ACCOUNT: common.startAccountDeletion,
// Loading
case 'LOADING_DRIVE': {
common.loading.onDriveEvent.fire(data); break;
}
}
LOADING_DRIVE: common.loading.onDriveEvent.fire
};
common.ready = (function () {
@ -828,19 +785,137 @@ define([
}
}).nThen(function (waitFor) {
var cfg = {
query: onMessage, // TODO temporary, will be replaced by a webworker channel
init: true,
//query: onMessage, // TODO temporary, will be replaced by a webworker channel
userHash: LocalStore.getUserHash(),
anonHash: LocalStore.getFSHash(),
localToken: tryParsing(localStorage.getItem(Constants.tokenKey)),
language: common.getLanguage(),
messenger: rdyCfg.messenger,
driveEvents: rdyCfg.driveEvents
messenger: rdyCfg.messenger, // Boolean
driveEvents: rdyCfg.driveEvents // Boolean
};
if (sessionStorage[Constants.newPadPathKey]) {
cfg.initialPath = sessionStorage[Constants.newPadPathKey];
delete sessionStorage[Constants.newPadPathKey];
}
AStore.query("CONNECT", cfg, waitFor(function (data) {
var channelIsReady = waitFor();
var msgEv = Util.mkEvent();
var postMsg, worker;
Nthen(function (waitFor2) {
if (typeof(SharedWorker) !== "undefined") {
worker = new SharedWorker('/common/outer/sharedworker.js?' + urlArgs);
worker.onerror = function (e) {
console.error(e);
};
worker.port.onmessage = function (ev) {
if (ev.data === "SW_READY") {
return;
}
msgEv.fire(ev);
};
postMsg = function (data) {
worker.port.postMessage(data);
};
postMsg('INIT');
window.addEventListener('beforeunload', function () {
postMsg('CLOSE');
});
} else if (false && 'serviceWorker' in navigator) {
var initializing = true;
var stopWaiting = waitFor2(); // Call this function when we're ready
postMsg = function (data) {
if (worker) { return void worker.postMessage(data); }
};
navigator.serviceWorker.register('/common/outer/serviceworker.js?' + urlArgs, {scope: '/'})
.then(function(reg) {
// Add handler for receiving messages from the service worker
navigator.serviceWorker.addEventListener('message', function (ev) {
if (initializing && ev.data === "SW_READY") {
initializing = false;
} else {
msgEv.fire(ev);
}
});
// Initialize the worker
// If it is active (probably running in another tab), just post INIT
if (reg.active) {
worker = reg.active;
postMsg("INIT");
}
// If it was not active, wait for the "activated" state and post INIT
reg.onupdatefound = function () {
if (initializing) {
var w = reg.installing;
var onStateChange = function () {
if (w.state === "activated") {
worker = w;
postMsg("INIT");
w.removeEventListener("statechange", onStateChange);
}
};
w.addEventListener('statechange', onStateChange);
return;
}
// XXX
// New version detected (from another tab): kill?
console.error('New version detected: ABORT?');
};
return void stopWaiting();
}).catch(function(error) {
/**/console.log('Registration failed with ' + error);
});
window.addEventListener('beforeunload', function () {
postMsg('CLOSE');
});
} else if (Worker) {
worker = new Worker('/common/outer/webworker.js?' + urlArgs);
worker.onmessage = function (ev) {
msgEv.fire(ev);
};
postMsg = function (data) {
worker.postMessage(data);
};
} else {
require(['/common/outer/noworker.js'], waitFor2(function (NoWorker) {
NoWorker.onMessage(function (data) {
msgEv.fire({data: data});
});
postMsg = function (d) { setTimeout(function () { NoWorker.query(d); }); };
NoWorker.create();
}));
}
}).nThen(function () {
Channel.create(msgEv, postMsg, function (chan) {
console.log('Outer ready');
Object.keys(queries).forEach(function (q) {
chan.on(q, function (data, cb) {
try {
queries[q](data, cb);
} catch (e) {
console.error("Error in outer when executing query " + q);
console.error(e);
console.log(data);
}
});
});
postMessage = function (cmd, data, cb) {
cb = cb || function () {};
chan.query(cmd, data, function (err, data) {
if (err) { return void cb ({error: err}); }
cb(data);
});
};
console.log('Posting CONNECT');
postMessage('CONNECT', cfg, function (data) {
if (data.error) { throw new Error(data.error); }
if (data.state === 'ALREADY_INIT') {
data = data.returned;
@ -864,7 +939,12 @@ define([
initFeedback(data.feedback);
initialized = true;
}));
channelIsReady();
});
}, false);
});
}).nThen(function (waitFor) {
// Load the new pad when the hash has changed
var oldHref = document.location.href;
@ -893,9 +973,12 @@ define([
document.location.reload();
} else if (o && !n) {
LocalStore.logout();
postMessage("DISCONNECT");
}
});
LocalStore.onLogout(function () {
console.log('onLogout: disconnect');
postMessage("DISCONNECT");
});
if (PINNING_ENABLED && LocalStore.isLoggedIn()) {
console.log("logged in. pads will be pinned");

@ -23,7 +23,10 @@ define([
Crypto, ChainPad, Listmap, nThen, Saferphore) {
var Store = {};
var create = function () {
var postMessage = function () {};
var broadcast = function () {};
var sendDriveEvent = function () {};
var storeHash;
@ -35,10 +38,10 @@ define([
};
Store.get = function (key, cb) {
Store.get = function (clientId, key, cb) {
cb(Util.find(store.proxy, key));
};
Store.set = function (data, cb) {
Store.set = function (clientId, data, cb) {
var path = data.key.slice();
var key = path.pop();
var obj = Util.find(store.proxy, path);
@ -48,6 +51,7 @@ define([
} else {
obj[key] = data.value;
}
broadcast([clientId], "UPDATE_METADATA");
onSync(cb);
};
@ -131,7 +135,7 @@ define([
/////////////////////// RPC //////////////////////////////////////
//////////////////////////////////////////////////////////////////
Store.pinPads = function (data, cb) {
Store.pinPads = function (clientId, data, cb) {
if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
if (typeof(cb) !== 'function') {
console.error('expected a callback');
@ -143,7 +147,7 @@ define([
});
};
Store.unpinPads = function (data, cb) {
Store.unpinPads = function (clientId, data, cb) {
if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
store.rpc.unpin(data, function (e, hash) {
@ -154,7 +158,7 @@ define([
var account = {};
Store.getPinnedUsage = function (data, cb) {
Store.getPinnedUsage = function (clientId, data, cb) {
if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
store.rpc.getFileListSize(function (err, bytes) {
@ -166,7 +170,7 @@ define([
};
// Update for all users from accounts and return current user limits
Store.updatePinLimit = function (data, cb) {
Store.updatePinLimit = function (clientId, data, cb) {
if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
store.rpc.updatePinLimits(function (e, limit, plan, note) {
if (e) { return void cb({error: e}); }
@ -177,7 +181,7 @@ define([
});
};
// Get current user limits
Store.getPinLimit = function (data, cb) {
Store.getPinLimit = function (clientId, data, cb) {
if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
var ALWAYS_REVALIDATE = true;
@ -195,14 +199,14 @@ define([
cb(account);
};
Store.clearOwnedChannel = function (data, cb) {
Store.clearOwnedChannel = function (clientId, data, cb) {
if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
store.rpc.clearOwnedChannel(data, function (err) {
cb({error:err});
});
};
Store.removeOwnedChannel = function (data, cb) {
Store.removeOwnedChannel = function (clientId, data, cb) {
if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
store.rpc.removeOwnedChannel(data, function (err) {
cb({error:err});
@ -230,7 +234,7 @@ define([
});
};
Store.uploadComplete = function (data, cb) {
Store.uploadComplete = function (clientId, data, cb) {
if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
if (data.owned) {
// Owned file
@ -247,7 +251,7 @@ define([
});
};
Store.uploadStatus = function (data, cb) {
Store.uploadStatus = function (clientId, data, cb) {
if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
store.rpc.uploadStatus(data.size, function (err, res) {
if (err) { return void cb({error:err}); }
@ -255,7 +259,7 @@ define([
});
};
Store.uploadCancel = function (data, cb) {
Store.uploadCancel = function (clientId, data, cb) {
if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
store.rpc.uploadCancel(data.size, function (err, res) {
if (err) { return void cb({error:err}); }
@ -263,7 +267,7 @@ define([
});
};
Store.uploadChunk = function (data, cb) {
Store.uploadChunk = function (clientId, data, cb) {
store.rpc.send.unauthenticated('UPLOAD', data.chunk, function (e, msg) {
cb({
error: e,
@ -272,14 +276,15 @@ define([
});
};
Store.initRpc = function (data, cb) {
Store.initRpc = function (clientId, data, cb) {
if (store.rpc) { return void cb(account); }
require(['/common/pinpad.js'], function (Pinpad) {
Pinpad.create(store.network, store.proxy, function (e, call) {
if (e) { return void cb({error: e}); }
store.rpc = call;
Store.getPinLimit(null, function (obj) {
Store.getPinLimit(null, null, function (obj) {
if (obj.error) { console.error(obj.error); }
account.limit = obj.limit;
account.plan = obj.plan;
@ -302,7 +307,7 @@ define([
//////////////////////////////////////////////////////////////////
////////////////// ANON RPC //////////////////////////////////////
//////////////////////////////////////////////////////////////////
Store.anonRpcMsg = function (data, cb) {
Store.anonRpcMsg = function (clientId, data, cb) {
if (!store.anon_rpc) { return void cb({error: 'ANON_RPC_NOT_READY'}); }
store.anon_rpc.send(data.msg, data.data, function (err, res) {
if (err) { return void cb({error: err}); }
@ -310,7 +315,7 @@ define([
});
};
Store.getFileSize = function (data, cb) {
Store.getFileSize = function (clientId, data, cb) {
if (!store.anon_rpc) { return void cb({error: 'ANON_RPC_NOT_READY'}); }
var channelId = Hash.hrefToHexChannelId(data.href, data.password);
@ -324,7 +329,7 @@ define([
});
};
Store.isNewChannel = function (data, cb) {
Store.isNewChannel = function (clientId, data, cb) {
if (!store.anon_rpc) { return void cb({error: 'ANON_RPC_NOT_READY'}); }
var channelId = Hash.hrefToHexChannelId(data.href, data.password);
store.anon_rpc.send("IS_NEW_CHANNEL", channelId, function (e, response) {
@ -339,7 +344,7 @@ define([
});
};
Store.getMultipleFileSize = function (data, cb) {
Store.getMultipleFileSize = function (clientId, data, cb) {
if (!store.anon_rpc) { return void cb({error: 'ANON_RPC_NOT_READY'}); }
if (!Array.isArray(data.files)) {
return void cb({error: 'INVALID_FILE_LIST'});
@ -355,7 +360,7 @@ define([
});
};
Store.getDeletedPads = function (data, cb) {
Store.getDeletedPads = function (clientId, data, cb) {
if (!store.anon_rpc) { return void cb({error: 'ANON_RPC_NOT_READY'}); }
var list = getCanonicalChannelList(true);
if (!Array.isArray(list)) {
@ -372,7 +377,8 @@ define([
});
};
Store.initAnonRpc = function (data, cb) {
Store.initAnonRpc = function (clientId, data, cb) {
if (store.anon_rpc) { return void cb(); }
require([
'/common/rpc.js',
], function (Rpc) {
@ -389,7 +395,7 @@ define([
//////////////////////////////////////////////////////////////////
// Get the metadata for sframe-common-outer
Store.getMetadata = function (data, cb) {
Store.getMetadata = function (clientId, data, cb) {
var disableThumbnails = Util.find(store.proxy, ['settings', 'general', 'disableThumbnails']);
var metadata = {
// "user" is shared with everybody via the userlist
@ -421,7 +427,7 @@ define([
};
};
Store.addPad = function (data, cb) {
Store.addPad = function (clientId, data, cb) {
if (!data.href) { return void cb({error:'NO_HREF'}); }
var pad = makePad(data.href, data.title);
if (data.owners) { pad.owners = data.owners; }
@ -432,6 +438,9 @@ define([
if (e) { return void cb({error: "Error while adding a template:"+ e}); }
var path = data.path || ['root'];
store.userObject.add(id, path);
sendDriveEvent('DRIVE_CHANGE', {
path: ['drive', UserObject.FILES_DATA]
}, clientId);
onSync(cb);
});
};
@ -465,7 +474,7 @@ define([
ownedPads.forEach(function (c) {
var w = waitFor();
sem.take(function (give) {
Store.removeOwnedChannel(c, give(function (obj) {
Store.removeOwnedChannel(null, c, give(function (obj) {
if (obj && obj.error) { console.error(obj.error); }
w();
}));
@ -473,11 +482,11 @@ define([
});
};
Store.deleteAccount = function (data, cb) {
Store.deleteAccount = function (clientId, data, cb) {
var edPublic = store.proxy.edPublic;
// No password for drive
var secret = Hash.getSecrets('drive', storeHash);
Store.anonRpcMsg({
Store.anonRpcMsg(clientId, {
msg: 'GET_METADATA',
data: secret.channel
}, function (data) {
@ -488,7 +497,7 @@ define([
nThen(function (waitFor) {
var token = Math.floor(Math.random()*Number.MAX_SAFE_INTEGER);
store.proxy[Constants.tokenKey] = token;
postMessage("DELETE_ACCOUNT", token, waitFor());
postMessage(clientId, "DELETE_ACCOUNT", token, waitFor());
}).nThen(function (waitFor) {
removeOwnedPads(waitFor);
}).nThen(function (waitFor) {
@ -498,7 +507,7 @@ define([
}));
}).nThen(function (waitFor) {
// Delete Drive
Store.removeOwnedChannel(secret.channel, waitFor());
Store.removeOwnedChannel(clientId, secret.channel, waitFor());
}).nThen(function () {
store.network.disconnect();
cb({
@ -537,7 +546,7 @@ define([
* - driveReadme
* - driveReadmeTitle
*/
Store.createReadme = function (data, cb) {
Store.createReadme = function (clientId, data, cb) {
require(['/common/cryptget.js'], function (Crypt) {
var hash = Hash.createRandomHash('pad');
Crypt.put(hash, data.driveReadme, function (e) {
@ -551,7 +560,7 @@ define([
channel: channel,
title: data.driveReadmeTitle,
};
Store.addPad(fileData, cb);
Store.addPad(clientId, fileData, cb);
});
});
};
@ -562,7 +571,7 @@ define([
* data
* - anonHash
*/
Store.migrateAnonDrive = function (data, cb) {
Store.migrateAnonDrive = function (clientId, data, cb) {
require(['/common/mergeDrive.js'], function (Merge) {
var hash = data.anonHash;
Merge.anonDriveIntoUser(store, hash, cb);
@ -573,6 +582,7 @@ define([
if (typeof attr === "string") {
console.error('DEPRECATED: use setAttribute with an array, not a string');
return {
path: ['settings'],
obj: store.proxy.settings,
key: attr
};
@ -589,23 +599,28 @@ define([
obj = obj[el];
});
return {
path: ['settings'].concat(attr),
obj: obj,
key: attr[attr.length-1]
};
};
// Set the display name (username) in the proxy
Store.setDisplayName = function (value, cb) {
Store.setDisplayName = function (clientId, value, cb) {
store.proxy[Constants.displayNameKey] = value;
broadcast([clientId], "UPDATE_METADATA");
onSync(cb);
};
// Reset the drive part of the userObject (from settings)
Store.resetDrive = function (data, cb) {
Store.resetDrive = function (clientId, data, cb) {
nThen(function (waitFor) {
removeOwnedPads(waitFor);
}).nThen(function () {
store.proxy.drive = store.fo.getStructure();
sendDriveEvent('DRIVE_CHANGE', {
path: ['drive', 'filesData']
}, clientId);
onSync(cb);
});
};
@ -617,25 +632,28 @@ define([
* - attr (Array)
* - value (String)
*/
Store.setPadAttribute = function (data, cb) {
Store.setPadAttribute = function (clientId, data, cb) {
store.userObject.setPadAttribute(data.href, data.attr, data.value, function () {
sendDriveEvent('DRIVE_CHANGE', {
path: ['drive', UserObject.FILES_DATA]
}, clientId);
onSync(cb);
});
};
Store.getPadAttribute = function (data, cb) {
Store.getPadAttribute = function (clientId, data, cb) {
store.userObject.getPadAttribute(data.href, data.attr, function (err, val) {
if (err) { return void cb({error: err}); }
cb(val);
});
};
Store.setAttribute = function (data, cb) {
Store.setAttribute = function (clientId, data, cb) {
try {
var object = getAttributeObject(data.attr);
object.obj[object.key] = data.value;
} catch (e) { return void cb({error: e}); }
onSync(cb);
};
Store.getAttribute = function (data, cb) {
Store.getAttribute = function (clientId, data, cb) {
var object;
try {
object = getAttributeObject(data.attr);
@ -644,12 +662,12 @@ define([
};
// Tags
Store.listAllTags = function (data, cb) {
Store.listAllTags = function (clientId, data, cb) {
cb(store.userObject.getTagsList());
};
// Templates
Store.getTemplates = function (data, cb) {
Store.getTemplates = function (clientId, data, cb) {
var templateFiles = store.userObject.getFiles(['template']);
var res = [];
templateFiles.forEach(function (f) {
@ -658,7 +676,7 @@ define([
});
cb(res);
};
Store.incrementTemplateUse = function (href) {
Store.incrementTemplateUse = function (clientId, href) {
store.userObject.getPadAttribute(href, 'used', function (err, data) {
// This is a not critical function, abort in case of error to make sure we won't
// create any issue with the user object or the async store
@ -669,12 +687,15 @@ define([
};
// Pads
Store.moveToTrash = function (data, cb) {
Store.moveToTrash = function (clientId, data, cb) {
var href = Hash.getRelativeHref(data.href);
store.userObject.forget(href);
sendDriveEvent('DRIVE_CHANGE', {
path: ['drive', UserObject.FILES_DATA]
}, clientId);
onSync(cb);
};
Store.setPadTitle = function (data, cb) {
Store.setPadTitle = function (clientId, data, cb) {
var title = data.title;
var href = data.href;
var channel = data.channel;
@ -683,14 +704,16 @@ define([
if (AppConfig.disableAnonymousStore && !store.loggedIn) { return void cb(); }
var channelData = Store.channels && Store.channels[channel];
var owners;
if (Store.channel && Store.channel.wc && channel === Store.channel.wc.id) {
owners = Store.channel.data.owners || undefined;
if (channelData && channelData.wc && channel === channelData.wc.id) {
owners = channelData.data.owners || undefined;
}
var expire;
if (Store.channel && Store.channel.wc && channel === Store.channel.wc.id) {
expire = +Store.channel.data.expire || undefined;
if (channelData && channelData.wc && channel === channelData.wc.id) {
expire = +channelData.data.expire || undefined;
}
var allPads = Util.find(store.proxy, ['drive', 'filesData']) || {};
@ -757,7 +780,7 @@ define([
// Add the pad if it does not exist in our drive
if (!contains) {
Store.addPad({
Store.addPad(clientId, {
href: href,
channel: channel,
title: title,
@ -767,12 +790,16 @@ define([
path: data.path
}, cb);
return;
} else {
sendDriveEvent('DRIVE_CHANGE', {
path: ['drive', UserObject.FILES_DATA]
}, clientId);
}
onSync(cb);
};
// Filepicker app
Store.getSecureFilesList = function (query, cb) {
Store.getSecureFilesList = function (clientId, query, cb) {
var list = {};
var hashes = [];
var types = query.types;
@ -801,38 +828,42 @@ define([
});
cb(list);
};
Store.getPadData = function (id, cb) {
Store.getPadData = function (clientId, id, cb) {
cb(store.userObject.getFileData(id));
};
// Messaging (manage friends from the userlist)
var getMessagingCfg = function () {
var getMessagingCfg = function (clientId) {
return {
proxy: store.proxy,
realtime: store.realtime,
network: store.network,
updateMetadata: function () {
postMessage("UPDATE_METADATA");
postMessage(clientId, "UPDATE_METADATA");
},
pinPads: Store.pinPads,
pinPads: function (data, cb) { Store.pinPads(null, data, cb); },
friendComplete: function (data) {
postMessage("EV_FRIEND_COMPLETE", data);
postMessage(clientId, "EV_FRIEND_COMPLETE", data);
},
friendRequest: function (data, cb) {
postMessage("Q_FRIEND_REQUEST", data, cb);
postMessage(clientId, "Q_FRIEND_REQUEST", data, cb);
},
};
};
Store.inviteFromUserlist = function (data, cb) {
var messagingCfg = getMessagingCfg();
Store.inviteFromUserlist = function (clientId, data, cb) {
var messagingCfg = getMessagingCfg(clientId);
Messaging.inviteFromUserlist(messagingCfg, data, cb);
};
Store.addDirectMessageHandlers = function (clientId, data) {
var messagingCfg = getMessagingCfg(clientId);
Messaging.addDirectMessageHandler(messagingCfg, data.href);
};
// Messenger
// Get hashes for the share button
Store.getStrongerHash = function (data, cb) {
Store.getStrongerHash = function (clientId, data, cb) {
var allPads = Util.find(store.proxy, ['drive', 'filesData']) || {};
// If we have a stronger version in drive, add it and add a redirect button
@ -918,51 +949,108 @@ define([
/////////////////////// PAD //////////////////////////////////////
//////////////////////////////////////////////////////////////////
// TODO with sharedworker
// channel will be an object storing the webchannel associated to each browser tab
var channel = Store.channel = {
var channels = Store.channels = {};
Store.joinPad = function (clientId, data) {
var isNew = typeof channels[data.channel] === "undefined";
var channel = channels[data.channel] = channels[data.channel] || {
queue: [],
data: {}
data: {},
clients: [],
bcast: function (cmd, data, notMe) {
channel.clients.forEach(function (cId) {
if (cId === notMe) { return; }
postMessage(cId, cmd, data);
});
},
history: [],
pushHistory: function (msg, isCp) {
if (isCp) {
channel.history.push('cp|' + msg);
var i;
for (i = channel.history.length - 2; i > 0; i--) {
if (/^cp\|/.test(channel.history[i])) { break; }
}
channel.history = channel.history.slice(i);
return;
}
channel.history.push(msg);
}
};
Store.joinPad = function (data, cb) {
if (channel.clients.indexOf(clientId) === -1) {
channel.clients.push(clientId);
}
if (!isNew && channel.wc) {
postMessage(clientId, "PAD_CONNECT", {
myID: channel.wc.myID,
id: channel.wc.id,
members: channel.wc.members
});
channel.wc.members.forEach(function (m) {
postMessage(clientId, "PAD_JOIN", m);
});
channel.history.forEach(function (msg) {
postMessage(clientId, "PAD_MESSAGE", {
msg: CpNfWorker.removeCp(msg),
user: channel.wc.myID,
validateKey: channel.data.validateKey
});
});
postMessage(clientId, "PAD_READY");
return;
}
var conf = {
onReady: function (padData) {
channel.data = padData || {};
postMessage("PAD_READY");
}, // post EV_PAD_READY
onMessage: function (user, m, validateKey) {
postMessage("PAD_MESSAGE", {
postMessage(clientId, "PAD_READY");
},
onMessage: function (user, m, validateKey, isCp) {
channel.pushHistory(m, isCp);
channel.bcast("PAD_MESSAGE", {
user: user,
msg: m,
validateKey: validateKey
});
}, // post EV_PAD_MESSAGE
},
onJoin: function (m) {
postMessage("PAD_JOIN", m);
}, // post EV_PAD_JOIN
channel.bcast("PAD_JOIN", m);
},
onLeave: function (m) {
postMessage("PAD_LEAVE", m);
}, // post EV_PAD_LEAVE
channel.bcast("PAD_LEAVE", m);
},
onDisconnect: function () {
postMessage("PAD_DISCONNECT");
}, // post EV_PAD_DISCONNECT
channel.bcast("PAD_DISCONNECT");
},
onError: function (err) {
postMessage("PAD_ERROR", err);
}, // post EV_PAD_ERROR
channel.bcast("PAD_ERROR", err);
delete channels[data.channel]; // TODO test?
},
channel: data.channel,
validateKey: data.validateKey,
owners: data.owners,
password: data.password,
expire: data.expire,
network: store.network,
readOnly: data.readOnly,
//readOnly: data.readOnly,
onConnect: function (wc, sendMessage) {
channel.sendMessage = sendMessage;
channel.sendMessage = function (msg, cId, cb) {
// Send to server
sendMessage(msg, cb);
// Broadcast to other tabs
channel.pushHistory(CpNfWorker.removeCp(msg), /^cp\|/.test(msg));
channel.bcast("PAD_MESSAGE", {
user: wc.myID,
msg: CpNfWorker.removeCp(msg),
validateKey: channel.data.validateKey
}, cId);
};
channel.wc = wc;
channel.queue.forEach(function (data) {
sendMessage(data.message);
channel.sendMessage(data.message, clientId);
});
cb({
channel.bcast("PAD_CONNECT", {
myID: wc.myID,
id: wc.id,
members: wc.members
@ -971,14 +1059,20 @@ define([
};
CpNfWorker.start(conf);
};
Store.sendPadMsg = function (data, cb) {
if (!channel.wc) { channel.queue.push(data); }
channel.sendMessage(data, cb);
Store.sendPadMsg = function (clientId, data, cb) {
var msg = data.msg;
var channel = channels[data.channel];
if (!channel) {
return; }
if (!channel.wc) {
channel.queue.push(msg);
return void cb();
}
channel.sendMessage(msg, clientId, cb);
};
// TODO
// GET_FULL_HISTORY from sframe-common-outer
Store.getFullHistory = function (data, cb) {
Store.getFullHistory = function (clientId, data, cb) {
var network = store.network;
var hkn = network.historyKeeper;
//var crypto = Crypto.createEncryptor(data.keys);
@ -1013,67 +1107,187 @@ define([
network.sendto(hkn, JSON.stringify(['GET_FULL_HISTORY', data.channel, data.validateKey]));
};
// TODO with sharedworker
// when the tab is closed, leave the pad
// Drive
Store.userObjectCommand = function (cmdData, cb) {
Store.userObjectCommand = function (clientId, cmdData, cb) {
if (!cmdData || !cmdData.cmd) { return; }
var data = cmdData.data;
var cb2 = function (data2) {
var paths = data.paths || [data.path] || [];
paths = paths.concat(data.newPath || []);
paths.forEach(function (p) {
sendDriveEvent('DRIVE_CHANGE', {
//path: ['drive', UserObject.FILES_DATA]
path: ['drive'].concat(p)
}, clientId);
});
cb(data2);
};
switch (cmdData.cmd) {
case 'move':
store.userObject.move(data.paths, data.newPath, cb); break;
store.userObject.move(data.paths, data.newPath, cb2); break;
case 'restore':
store.userObject.restore(data.path, cb); break;
store.userObject.restore(data.path, cb2); break;
case 'addFolder':
store.userObject.addFolder(data.path, data.name, cb); break;
store.userObject.addFolder(data.path, data.name, cb2); break;
case 'delete':
store.userObject.delete(data.paths, cb, data.nocheck, data.isOwnPadRemoved); break;
store.userObject.delete(data.paths, cb2, data.nocheck, data.isOwnPadRemoved); break;
case 'emptyTrash':
store.userObject.emptyTrash(cb); break;
store.userObject.emptyTrash(cb2); break;
case 'rename':
store.userObject.rename(data.path, data.newName, cb); break;
store.userObject.rename(data.path, data.newName, cb2); break;
default:
cb();
}
};
// Clients management
var driveEventClients = [];
var messengerEventClients = [];
var dropChannel = function (chanId) {
if (!Store.channels[chanId]) { return; }
if (Store.channels[chanId].wc) {
Store.channels[chanId].wc.leave('');
}
delete Store.channels[chanId];
};
Store._removeClient = function (clientId) {
var driveIdx = driveEventClients.indexOf(clientId);
if (driveIdx !== -1) {
driveEventClients.splice(driveIdx, 1);
}
var messengerIdx = messengerEventClients.indexOf(clientId);
if (messengerIdx !== -1) {
messengerEventClients.splice(messengerIdx, 1);
}
Object.keys(Store.channels).forEach(function (chanId) {
var chanIdx = Store.channels[chanId].clients.indexOf(clientId);
if (chanIdx !== -1) {
Store.channels[chanId].clients.splice(chanIdx, 1);
}
if (Store.channels[chanId].clients.length === 0) {
dropChannel(chanId);
}
});
};
// Special events
var driveEventInit = false;
sendDriveEvent = function (q, data, sender) {
driveEventClients.forEach(function (cId) {
if (cId === sender) { return; }
postMessage(cId, q, data);
});
};
Store._subscribeToDrive = function (clientId) {
if (driveEventClients.indexOf(clientId) === -1) {
driveEventClients.push(clientId);
}
if (!driveEventInit) {
store.proxy.on('change', [], function (o, n, p) {
sendDriveEvent('DRIVE_CHANGE', {
old: o,
new: n,
path: p
});
});
store.proxy.on('remove', [], function (o, p) {
sendDriveEvent(clientId, 'DRIVE_REMOVE', {
old: o,
path: p
});
});
driveEventInit = true;
}
};
var messengerEventInit = false;
var sendMessengerEvent = function (q, data) {
messengerEventClients.forEach(function (cId) {
postMessage(cId, q, data);
});
};
Store._subscribeToMessenger = function (clientId) {
if (messengerEventClients.indexOf(clientId) === -1) {
messengerEventClients.push(clientId);
}
if (!messengerEventInit) {
var messenger = store.messenger = Messenger.messenger(store);
messenger.on('message', function (message) {
sendMessengerEvent('CONTACTS_MESSAGE', message);
});
messenger.on('join', function (curvePublic, channel) {
sendMessengerEvent('CONTACTS_JOIN', {
curvePublic: curvePublic,
channel: channel,
});
});
messenger.on('leave', function (curvePublic, channel) {
sendMessengerEvent('CONTACTS_LEAVE', {
curvePublic: curvePublic,
channel: channel,
});
});
messenger.on('update', function (info, curvePublic) {
sendMessengerEvent('CONTACTS_UPDATE', {
curvePublic: curvePublic,
info: info,
});
});
messenger.on('friend', function (curvePublic) {
sendMessengerEvent('CONTACTS_FRIEND', {
curvePublic: curvePublic,
});
});
messenger.on('unfriend', function (curvePublic) {
sendMessengerEvent('CONTACTS_UNFRIEND', {
curvePublic: curvePublic,
});
});
messengerEventInit = true;
}
};
//////////////////////////////////////////////////////////////////
/////////////////////// Init /////////////////////////////////////
//////////////////////////////////////////////////////////////////
var onReady = function (returned, cb) {
var onReady = function (clientId, returned, cb) {
var proxy = store.proxy;
var userObject = store.userObject = UserObject.init(proxy.drive, {
pinPads: Store.pinPads,
unpinPads: Store.unpinPads,
removeOwnedChannel: Store.removeOwnedChannel,
pinPads: function (data, cb) { Store.pinPads(null, data, cb); },
unpinPads: function (data, cb) { Store.unpinPads(null, data, cb); },
removeOwnedChannel: function (data, cb) { Store.removeOwnedChannel(null, data, cb); },
edPublic: store.proxy.edPublic,
loggedIn: store.loggedIn,
log: function (msg) {
postMessage("DRIVE_LOG", msg);
// broadcast to all drive apps
sendDriveEvent("DRIVE_LOG", msg);
}
});
nThen(function (waitFor) {
postMessage('LOADING_DRIVE', {
postMessage(clientId, 'LOADING_DRIVE', {
state: 2
});
userObject.migrate(waitFor());
}).nThen(function (waitFor) {
Migrate(proxy, waitFor(), function (version, progress) {
postMessage('LOADING_DRIVE', {
postMessage(clientId, 'LOADING_DRIVE', {
state: 2,
progress: progress
});
});
}).nThen(function () {
postMessage('LOADING_DRIVE', {
postMessage(clientId, 'LOADING_DRIVE', {
state: 3
});
userObject.fixFiles();
var requestLogin = function () {
postMessage("REQUEST_LOGIN");
broadcast([], "REQUEST_LOGIN");
};
if (store.loggedIn) {
@ -1118,26 +1332,26 @@ define([
proxy.on('change', [Constants.displayNameKey], function (o, n) {
if (typeof(n) !== "string") { return; }
postMessage("UPDATE_METADATA");
broadcast([], "UPDATE_METADATA");
});
proxy.on('change', ['profile'], function () {
// Trigger userlist update when the avatar has changed
postMessage("UPDATE_METADATA");
broadcast([], "UPDATE_METADATA");
});
proxy.on('change', ['friends'], function () {
// Trigger userlist update when the friendlist has changed
postMessage("UPDATE_METADATA");
broadcast([], "UPDATE_METADATA");
});
proxy.on('change', ['settings'], function () {
postMessage("UPDATE_METADATA");
broadcast([], "UPDATE_METADATA");
});
proxy.on('change', [Constants.tokenKey], function () {
postMessage("UPDATE_TOKEN", { token: proxy[Constants.tokenKey] });
broadcast([], "UPDATE_TOKEN", { token: proxy[Constants.tokenKey] });
});
});
};
var connect = function (data, cb) {
var connect = function (clientId, data, cb) {
var hash = data.userHash || data.anonHash || Hash.createRandomHash('drive');
storeHash = hash;
if (!hash) {
@ -1177,9 +1391,9 @@ define([
&& !drive['filesData']) {
drive[Constants.oldStorageKey] = [];
}
postMessage('LOADING_DRIVE', { state: 1 });
postMessage(clientId, 'LOADING_DRIVE', { state: 1 });
// Drive already exist: return the existing drive, don't load data from legacy store
onReady(returned, cb);
onReady(clientId, returned, cb);
})
.on('change', ['drive', 'migrate'], function () {
var path = arguments[2];
@ -1187,15 +1401,15 @@ define([
if (path[0] === 'drive' && path[1] === "migrate" && value === 1) {
rt.network.disconnect();
rt.realtime.abort();
postMessage('NETWORK_DISCONNECT');
broadcast([], 'NETWORK_DISCONNECT');
}
});
rt.proxy.on('disconnect', function () {
postMessage('NETWORK_DISCONNECT');
broadcast([], 'NETWORK_DISCONNECT');
});
rt.proxy.on('reconnect', function (info) {
postMessage('NETWORK_RECONNECT', {myId: info.myId});
broadcast([], 'NETWORK_RECONNECT', {myId: info.myId});
});
};
@ -1210,7 +1424,7 @@ define([
* - requestLogin
*/
var initialized = false;
Store.init = function (data, callback) {
Store.init = function (clientId, data, callback) {
if (initialized) {
return void callback({
state: 'ALREADY_INIT',
@ -1218,75 +1432,21 @@ define([
});
}
initialized = true;
postMessage = function (cmd, d, cb) {
setTimeout(function () {
data.query(cmd, d, cb); // TODO temporary, will be replaced by webworker channel
});
postMessage = function (clientId, cmd, d, cb) {
data.query(clientId, cmd, d, cb);
};
broadcast = function (excludes, cmd, d, cb) {
data.broadcast(excludes, cmd, d, cb);
};
store.data = data;
connect(data, function (ret) {
connect(clientId, data, function (ret) {
if (Object.keys(store.proxy).length === 1) {
Feedback.send("FIRST_APP_USE", true);
}
store.returned = ret;
callback(ret);
var messagingCfg = getMessagingCfg();
Messaging.addDirectMessageHandler(messagingCfg);
// Send events whenever there is a change or a removal in the drive
if (data.driveEvents) {
store.proxy.on('change', [], function (o, n, p) {
postMessage('DRIVE_CHANGE', {
old: o,
new: n,
path: p
});
});
store.proxy.on('remove', [], function (o, p) {
postMessage('DRIVE_REMOVE', {
old: o,
path: p
});
});
}
if (data.messenger) {
var messenger = store.messenger = Messenger.messenger(store);
messenger.on('message', function (message) {
postMessage('CONTACTS_MESSAGE', message);
});
messenger.on('join', function (curvePublic, channel) {
postMessage('CONTACTS_JOIN', {
curvePublic: curvePublic,
channel: channel,
});
});
messenger.on('leave', function (curvePublic, channel) {
postMessage('CONTACTS_LEAVE', {
curvePublic: curvePublic,
channel: channel,
});
});
messenger.on('update', function (info, curvePublic) {
postMessage('CONTACTS_UPDATE', {
curvePublic: curvePublic,
info: info,
});
});
messenger.on('friend', function (curvePublic) {
postMessage('CONTACTS_FRIEND', {
curvePublic: curvePublic,
});
});
messenger.on('unfriend', function (curvePublic) {
postMessage('CONTACTS_UNFRIEND', {
curvePublic: curvePublic,
});
});
}
});
};
@ -1295,4 +1455,9 @@ define([
store.network.disconnect();
};
return Store;
};
return {
create: create
};
});

@ -22,6 +22,10 @@ define([], function () {
var unBencode = function (str) { return str.replace(/^\d+:/, ''); };
var removeCp = function (str) {
return str.replace(/^cp\|([A-Za-z0-9+\/=]{0,20}\|)?/, '');
};
var start = function (conf) {
var channel = conf.channel;
var validateKey = conf.validateKey;
@ -72,7 +76,7 @@ define([], function () {
// at the beginning of each message on the server.
// We have to make sure our regex ignores this nonce using {0,20} (our IDs
// should only be 8 characters long)
return msg.replace(/^cp\|([A-Za-z0-9+\/=]{0,20}\|)?/, '');
return removeCp(msg);
};
var msgOut = function (msg) {
@ -124,6 +128,8 @@ define([], function () {
lastKnownHash = msg.slice(0,64);
var isCp = /^cp\|/.test(msg);
var message = msgIn(peer, msg);
verbose(message);
@ -134,7 +140,7 @@ define([], function () {
message = unBencode(message);//.slice(message.indexOf(':[') + 1);
// pass the message into Chainpad
onMessage(peer, message, validateKey);
onMessage(peer, message, validateKey, isCp);
//sframeChan.query('Q_RT_MESSAGE', message, function () { });
};
@ -259,7 +265,8 @@ define([], function () {
};
return {
start: start
start: start,
removeCp: removeCp
/*function (config) {
config.sframeChan.whenReg('EV_RT_READY', function () {
start(config);

@ -0,0 +1,103 @@
define([
'/common/common-util.js',
'/common/outer/worker-channel.js',
'/common/outer/store-rpc.js',
], function (Util, Channel, SRpc) {
var msgEv = Util.mkEvent();
var sendMsg = Util.mkEvent();
var create = function () {
var Rpc = SRpc();
var postMessage = function (data) {
sendMsg.fire(data);
};
Channel.create(msgEv, postMessage, function (chan) {
var clientId = '1';
Object.keys(Rpc.queries).forEach(function (q) {
if (q === 'CONNECT') { return; }
if (q === 'JOIN_PAD') { return; }
if (q === 'SEND_PAD_MSG') { return; }
chan.on(q, function (data, cb) {
try {
Rpc.queries[q](clientId, data, cb);
} catch (e) {
console.error('Error in webworker when executing query ' + q);
console.error(e);
console.log(data);
}
});
});
chan.on('CONNECT', function (cfg, cb) {
// load Store here, with cfg, and pass a "query" (chan.query)
// cId is a clientId used in ServiceWorker or SharedWorker
cfg.query = function (cId, cmd, data, cb) {
cb = cb || function () {};
chan.query(cmd, data, function (err, data2) {
if (err) { return void cb({error: err}); }
cb(data2);
});
};
cfg.broadcast = function (excludes, cmd, data, cb) {
cb = cb || function () {};
if (excludes.indexOf(clientId) !== -1) { return; }
chan.query(cmd, data, function (err, data2) {
if (err) { return void cb({error: err}); }
cb(data2);
});
};
Rpc.queries['CONNECT'](clientId, cfg, function (data) {
if (data && data.state === "ALREADY_INIT") {
return void cb(data);
}
if (cfg.driveEvents) {
Rpc._subscribeToDrive(clientId);
}
if (cfg.messenger) {
Rpc._subscribeToMessenger(clientId);
}
cb(data);
});
});
var chanId;
chan.on('JOIN_PAD', function (data, cb) {
chanId = data.channel;
try {
Rpc.queries['JOIN_PAD'](clientId, data, cb);
} catch (e) {
console.error('Error in webworker when executing query JOIN_PAD');
console.error(e);
console.log(data);
}
});
chan.on('SEND_PAD_MSG', function (msg, cb) {
var data = {
msg: msg,
channel: chanId
};
try {
Rpc.queries['SEND_PAD_MSG'](clientId, data, cb);
} catch (e) {
console.error('Error in webworker when executing query SEND_PAD_MSG');
console.error(e);
console.log(data);
}
});
}, true);
};
return {
query: function (data) {
msgEv.fire({data: data});
},
onMessage: function (cb) {
sendMsg.reg(function (data) {
setTimeout(function () {
cb(data);
});
});
},
create: create
};
});

@ -0,0 +1,175 @@
/* jshint ignore:start */
importScripts('/bower_components/requirejs/require.js');
window = self;
localStorage = {
setItem: function (k, v) { localStorage[k] = v; },
getItem: function (k) { return localStorage[k]; }
};
self.tabs = {};
var postMsg = function (client, data) {
client.postMessage(data);
};
var debug = function (msg) { console.log(msg); };
// debug = function () {};
var init = function (client, cb) {
debug('SW INIT');
require([
'/common/requireconfig.js'
], function (RequireConfig) {
require.config(RequireConfig());
require([
'/common/common-util.js',
'/common/outer/worker-channel.js',
'/common/outer/store-rpc.js'
], function (Util, Channel, SRpc) {
debug('SW Required ressources loaded');
var msgEv = Util.mkEvent();
if (!self.Rpc) {
self.Rpc = SRpc();
}
var Rpc = self.Rpc;
var postToClient = function (data) {
postMsg(client, data);
};
Channel.create(msgEv, postToClient, function (chan) {
debug('SW Channel created');
var clientId = client.id;
self.tabs[clientId].chan = chan;
Object.keys(Rpc.queries).forEach(function (q) {
if (q === 'CONNECT') { return; }
if (q === 'JOIN_PAD') { return; }
if (q === 'SEND_PAD_MSG') { return; }
chan.on(q, function (data, cb) {
try {
Rpc.queries[q](clientId, data, cb);
} catch (e) {
console.error('Error in webworker when executing query ' + q);
console.error(e);
console.log(data);
}
if (q === "DISCONNECT") {
console.log('Deleting existing store!');
delete self.Rpc;
delete self.store;
}
});
});
chan.on('CONNECT', function (cfg, cb) {
debug('SW Connect callback');
if (self.store) {
debug('Store already exists!');
if (cfg.driveEvents) {
Rpc._subscribeToDrive(clientId);
}
if (cfg.messenger) {
Rpc._subscribeToMessenger(clientId);
}
return void cb(self.store);
}
debug('Loading new async store');
// One-time initialization (init async-store)
cfg.query = function (cId, cmd, data, cb) {
cb = cb || function () {};
self.tabs[cId].chan.query(cmd, data, function (err, data2) {
if (err) { return void cb({error: err}); }
cb(data2);
});
};
cfg.broadcast = function (excludes, cmd, data, cb) {
cb = cb || function () {};
Object.keys(self.tabs).forEach(function (cId) {
if (excludes.indexOf(cId) !== -1) { return; }
self.tabs[cId].chan.query(cmd, data, function (err, data2) {
if (err) { return void cb({error: err}); }
cb(data2);
});
});
};
Rpc.queries['CONNECT'](clientId, cfg, function (data) {
if (cfg.driveEvents) {
Rpc._subscribeToDrive(clientId);
}
if (cfg.messenger) {
Rpc._subscribeToMessenger(clientId);
}
if (data && data.state === "ALREADY_INIT") {
return void cb(data.returned);
}
self.store = data;
cb(data);
});
});
chan.on('JOIN_PAD', function (data, cb) {
self.tabs[clientId].channelId = data.channel;
try {
Rpc.queries['JOIN_PAD'](clientId, data, cb);
} catch (e) {
console.error('Error in webworker when executing query JOIN_PAD');
console.error(e);
console.log(data);
}
});
chan.on('SEND_PAD_MSG', function (msg, cb) {
var data = {
msg: msg,
channel: self.tabs[clientId].channelId
};
try {
Rpc.queries['SEND_PAD_MSG'](clientId, data, cb);
} catch (e) {
console.error('Error in webworker when executing query SEND_PAD_MSG');
console.error(e);
console.log(data);
}
});
cb();
}, true);
self.tabs[client.id].msgEv = msgEv;
self.tabs[client.id].close = function () {
Rpc._removeClient(client.id);
};
});
});
};
self.addEventListener('message', function (e) {
var cId = e.source.id;
if (e.data === "INIT") {
if (tabs[cId]) { return; }
tabs[cId] = {
client: e.source
};
init(e.source, function () {
postMsg(e.source, 'SW_READY');
});
} else if (e.data === "CLOSE") {
if (tabs[cId] && tabs[cId].close) {
console.log('leave');
tabs[cId].close();
}
} else if (self.tabs[cId] && self.tabs[cId].msgEv) {
self.tabs[cId].msgEv.fire(e);
}
});
self.addEventListener('install', function (e) {
debug('V1 installing…');
self.skipWaiting();
});
self.addEventListener('activate', function (e) {
debug('V1 now ready to handle fetches!');
});

@ -0,0 +1,174 @@
/* jshint ignore:start */
importScripts('/bower_components/requirejs/require.js');
window = self;
localStorage = {
setItem: function (k, v) { localStorage[k] = v; },
getItem: function (k) { return localStorage[k]; }
};
self.tabs = {};
var postMsg = function (client, data) {
client.port.postMessage(data);
};
var debug = function (msg) { console.log(msg); };
// debug = function () {};
var init = function (client, cb) {
debug('SharedW INIT');
require([
'/common/requireconfig.js'
], function (RequireConfig) {
require.config(RequireConfig());
require([
'/common/common-util.js',
'/common/outer/worker-channel.js',
'/common/outer/store-rpc.js'
], function (Util, Channel, SRpc) {
debug('SharedW Required ressources loaded');
var msgEv = Util.mkEvent();
if (!self.Rpc) {
self.Rpc = SRpc();
}
var Rpc = self.Rpc;
var postToClient = function (data) {
postMsg(client, data);
};
Channel.create(msgEv, postToClient, function (chan) {
debug('SharedW Channel created');
var clientId = client.id;
client.chan = chan;
Object.keys(Rpc.queries).forEach(function (q) {
if (q === 'CONNECT') { return; }
if (q === 'JOIN_PAD') { return; }
if (q === 'SEND_PAD_MSG') { return; }
chan.on(q, function (data, cb) {
try {
Rpc.queries[q](clientId, data, cb);
} catch (e) {
console.error('Error in webworker when executing query ' + q);
console.error(e);
console.log(data);
}
if (q === "DISCONNECT") {
console.log('Deleting existing store!');
delete self.Rpc;
delete self.store;
}
});
});
chan.on('CONNECT', function (cfg, cb) {
debug('SharedW connecting to store...');
if (self.store) {
debug('Store already exists!');
if (cfg.driveEvents) {
Rpc._subscribeToDrive(clientId);
}
if (cfg.messenger) {
Rpc._subscribeToMessenger(clientId);
}
return void cb(self.store);
}
debug('Loading new async store');
// One-time initialization (init async-store)
cfg.query = function (cId, cmd, data, cb) {
cb = cb || function () {};
self.tabs[cId].chan.query(cmd, data, function (err, data2) {
if (err) { return void cb({error: err}); }
cb(data2);
});
};
cfg.broadcast = function (excludes, cmd, data, cb) {
cb = cb || function () {};
Object.keys(self.tabs).forEach(function (cId) {
if (excludes.indexOf(cId) !== -1) { return; }
self.tabs[cId].chan.query(cmd, data, function (err, data2) {
if (err) { return void cb({error: err}); }
cb(data2);
});
});
};
Rpc.queries['CONNECT'](clientId, cfg, function (data) {
if (cfg.driveEvents) {
Rpc._subscribeToDrive(clientId);
}
if (cfg.messenger) {
Rpc._subscribeToMessenger(clientId);
}
if (data && data.state === "ALREADY_INIT") {
self.store = data.returned;
return void cb(data.returned);
}
self.store = data;
cb(data);
});
});
chan.on('JOIN_PAD', function (data, cb) {
client.channelId = data.channel;
try {
Rpc.queries['JOIN_PAD'](clientId, data, cb);
} catch (e) {
console.error('Error in webworker when executing query JOIN_PAD');
console.error(e);
console.log(data);
}
});
chan.on('SEND_PAD_MSG', function (msg, cb) {
var data = {
msg: msg,
channel: client.channelId
};
try {
Rpc.queries['SEND_PAD_MSG'](clientId, data, cb);
} catch (e) {
console.error('Error in webworker when executing query SEND_PAD_MSG');
console.error(e);
console.log(data);
}
});
cb();
}, true);
client.msgEv = msgEv;
client.close = function () {
Rpc._removeClient(client.id);
};
});
});
};
onconnect = function(e) {
debug('New SharedWorker client');
var port = e.ports[0];
var cId = Number(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER))
var client = self.tabs[cId] = {
id: cId,
port: port
};
port.onmessage = function (e) {
if (e.data === "INIT") {
if (client.init) { return; }
client.init = true;
init(client, function () {
postMsg(client, 'SW_READY');
});
} else if (e.data === "CLOSE") {
if (client && client.close) {
console.log('leave');
client.close();
}
} else if (client && client.msgEv) {
client.msgEv.fire(e);
}
};
};

@ -1,193 +1,96 @@
define([
'/common/outer/async-store.js'
], function (Store) {
], function (AStore) {
var create = function () {
var Store = AStore.create();
var Rpc = {};
Rpc.query = function (cmd, data, cb) {
switch (cmd) {
// READY
case 'CONNECT': {
Store.init(data, cb); break;
}
case 'DISCONNECT': {
Store.disconnect(data, cb); break;
}
case 'CREATE_README': {
Store.createReadme(data, cb); break;
}
case 'MIGRATE_ANON_DRIVE': {
Store.migrateAnonDrive(data, cb); break;
}
var queries = Rpc.queries = {
// Ready
CONNECT: Store.init,
DISCONNECT: Store.disconnect,
CREATE_README: Store.createReadme,
MIGRATE_ANON_DRIVE: Store.migrateAnonDrive,
// RPC
case 'INIT_RPC': {
Store.initRpc(data, cb); break;
}
case 'UPDATE_PIN_LIMIT': {
Store.updatePinLimit(data, cb); break;
}
case 'GET_PIN_LIMIT': {
Store.getPinLimit(data, cb); break;
}
case 'CLEAR_OWNED_CHANNEL': {
Store.clearOwnedChannel(data, cb); break;
}
case 'REMOVE_OWNED_CHANNEL': {
Store.removeOwnedChannel(data, cb); break;
}
case 'UPLOAD_CHUNK': {
Store.uploadChunk(data, cb); break;
}
case 'UPLOAD_COMPLETE': {
Store.uploadComplete(data, cb); break;
}
case 'UPLOAD_STATUS': {
Store.uploadStatus(data, cb); break;
}
case 'UPLOAD_CANCEL': {
Store.uploadCancel(data, cb); break;
}
case 'PIN_PADS': {
Store.pinPads(data, cb); break;
}
case 'UNPIN_PADS': {
Store.unpinPads(data, cb); break;
}
case 'GET_DELETED_PADS': {
Store.getDeletedPads(data, cb); break;
}
case 'GET_PINNED_USAGE': {
Store.getPinnedUsage(data, cb); break;
}
INIT_RPC: Store.initRpc,
UPDATE_PIN_LIMIT: Store.updatePinLimit,
GET_PIN_LIMIT: Store.getPinLimit,
CLEAR_OWNED_CHANNEL: Store.clearOwnedChannel,
REMOVE_OWNED_CHANNEL: Store.removeOwnedChannel,
UPLOAD_CHUNK: Store.uploadChunk,
UPLOAD_COMPLETE: Store.uploadComplete,
UPLOAD_STATUS: Store.uploadStatus,
UPLOAD_CANCEL: Store.uploadCancel,
PIN_PADS: Store.pinPads,
UNPIN_PADS: Store.unpinPads,
GET_DELETED_PADS: Store.getDeletedPads,
GET_PINNED_USAGE: Store.getPinnedUsage,
// ANON RPC
case 'INIT_ANON_RPC': {
Store.initAnonRpc(data, cb); break;
}
case 'ANON_RPC_MESSAGE': {
Store.anonRpcMsg(data, cb); break;
}
case 'GET_FILE_SIZE': {
Store.getFileSize(data, cb); break;
}
case 'GET_MULTIPLE_FILE_SIZE': {
Store.getMultipleFileSize(data, cb); break;
}
INIT_ANON_RPC: Store.initAnonRpc,
ANON_RPC_MESSAGE: Store.anonRpcMsg,
GET_FILE_SIZE: Store.getFileSize,
GET_MULTIPLE_FILE_SIZE: Store.getMultipleFileSize,
// Store
case 'GET': {
Store.get(data, cb); break;
}
case 'SET': {
Store.set(data, cb); break;
}
case 'ADD_PAD': {
Store.addPad(data, cb); break;
}
case 'SET_PAD_TITLE': {
Store.setPadTitle(data, cb); break;
}
case 'MOVE_TO_TRASH': {
Store.moveToTrash(data, cb); break;
}
case 'RESET_DRIVE': {
Store.resetDrive(data, cb); break;
}
case 'GET_METADATA': {
Store.getMetadata(data, cb); break;
}
case 'SET_DISPLAY_NAME': {
Store.setDisplayName(data, cb); break;
}
case 'SET_PAD_ATTRIBUTE': {
Store.setPadAttribute(data, cb); break;
}
case 'GET_PAD_ATTRIBUTE': {
Store.getPadAttribute(data, cb); break;
}
case 'SET_ATTRIBUTE': {
Store.setAttribute(data, cb); break;
}
case 'GET_ATTRIBUTE': {
Store.getAttribute(data, cb); break;
}
case 'LIST_ALL_TAGS': {
Store.listAllTags(data, cb); break;
}
case 'GET_TEMPLATES': {
Store.getTemplates(data, cb); break;
}
case 'GET_SECURE_FILES_LIST': {
Store.getSecureFilesList(data, cb); break;
}
case 'GET_PAD_DATA': {
Store.getPadData(data, cb); break;
}
case 'GET_STRONGER_HASH': {
Store.getStrongerHash(data, cb); break;
}
case 'INCREMENT_TEMPLATE_USE': {
Store.incrementTemplateUse(data); break;
}
GET: Store.get,
SET: Store.set,
ADD_PAD: Store.addPad,
SET_PAD_TITLE: Store.setPadTitle,
MOVE_TO_TRASH: Store.moveToTrash,
RESET_DRIVE: Store.resetDrive,
GET_METADATA: Store.getMetadata,
SET_DISPLAY_NAME: Store.setDisplayName,
SET_PAD_ATTRIBUTE: Store.setPadAttribute,
GET_PAD_ATTRIBUTE: Store.getPadAttribute,
SET_ATTRIBUTE: Store.setAttribute,
GET_ATTRIBUTE: Store.getAttribute,
LIST_ALL_TAGS: Store.listAllTags,
GET_TEMPLATES: Store.getTemplates,
GET_SECURE_FILES_LIST: Store.getSecureFilesList,
GET_PAD_DATA: Store.getPadData,
GET_STRONGER_HASH: Store.getStrongerHash,
INCREMENT_TEMPLATE_USE: Store.incrementTemplateUse,
// Messaging
case 'INVITE_FROM_USERLIST': {
Store.inviteFromUserlist(data, cb); break;
}
INVITE_FROM_USERLIST: Store.inviteFromUserlist,
ADD_DIRECT_MESSAGE_HANDLERS: Store.addDirectMessageHandlers,
// Messenger
case 'CONTACTS_GET_FRIEND_LIST': {
Store.messenger.getFriendList(data, cb); break;
}
case 'CONTACTS_GET_MY_INFO': {
Store.messenger.getMyInfo(data, cb); break;
}
case 'CONTACTS_GET_FRIEND_INFO': {
Store.messenger.getFriendInfo(data, cb); break;
}
case 'CONTACTS_REMOVE_FRIEND': {
Store.messenger.removeFriend(data, cb); break;
}
case 'CONTACTS_OPEN_FRIEND_CHANNEL': {
Store.messenger.openFriendChannel(data, cb); break;
}
case 'CONTACTS_GET_FRIEND_STATUS': {
Store.messenger.getFriendStatus(data, cb); break;
}
case 'CONTACTS_GET_MORE_HISTORY': {
Store.messenger.getMoreHistory(data, cb); break;
}
case 'CONTACTS_SEND_MESSAGE': {
Store.messenger.sendMessage(data, cb); break;
}
case 'CONTACTS_SET_CHANNEL_HEAD': {
Store.messenger.setChannelHead(data, cb); break;
}
CONTACTS_GET_FRIEND_LIST: Store.messenger.getFriendList,
CONTACTS_GET_MY_INFO: Store.messenger.getMyInfo,
CONTACTS_GET_FRIEND_INFO: Store.messenger.getFriendInfo,
CONTACTS_REMOVE_FRIEND: Store.messenger.removeFriend,
CONTACTS_OPEN_FRIEND_CHANNEL: Store.messenger.openFriendChannel,
CONTACTS_GET_FRIEND_STATUS: Store.messenger.getFriendStatus,
CONTACTS_GET_MORE_HISTORY: Store.messenger.getMoreHistory,
CONTACTS_SEND_MESSAGE: Store.messenger.sendMessage,
CONTACTS_SET_CHANNEL_HEAD: Store.messenger.setChannelHead,
// Pad
case 'SEND_PAD_MSG': {
Store.sendPadMsg(data, cb); break;
}
case 'JOIN_PAD': {
Store.joinPad(data, cb); break;
}
case 'GET_FULL_HISTORY': {
Store.getFullHistory(data, cb); break;
}
SEND_PAD_MSG: Store.sendPadMsg,
JOIN_PAD: Store.joinPad,
GET_FULL_HISTORY: Store.getFullHistory,
IS_NEW_CHANNEL: Store.isNewChannel,
// Drive
case 'DRIVE_USEROBJECT': {
Store.userObjectCommand(data, cb); break;
}
// Settings
case 'DELETE_ACCOUNT': {
Store.deleteAccount(data, cb); break;
}
case 'IS_NEW_CHANNEL': {
Store.isNewChannel(data, cb); break;
}
default: {
console.error("UNHANDLED_STORE_RPC");
DRIVE_USEROBJECT: Store.userObjectCommand,
// Settings,
DELETE_ACCOUNT: Store.deleteAccount,
};
break;
}
Rpc.query = function (cmd, data, cb) {
if (queries[cmd]) {
queries[cmd]('0', data, cb);
} else {
console.error('UNHANDLED_STORE_RPC');
}
};
// Internal calls
Rpc._removeClient = Store._removeClient;
Rpc._subscribeToDrive = Store._subscribeToDrive;
Rpc._subscribeToMessenger = Store._subscribeToMessenger;
return Rpc;
};
return create;
});

@ -0,0 +1,100 @@
/* jshint ignore:start */
importScripts('/bower_components/requirejs/require.js');
window = self;
localStorage = {
setItem: function (k, v) { localStorage[k] = v; },
getItem: function (k) { return localStorage[k]; }
};
require([
'/common/requireconfig.js'
], function (RequireConfig) {
require.config(RequireConfig());
require([
'/common/common-util.js',
'/common/outer/worker-channel.js',
'/common/outer/store-rpc.js'
], function (Util, Channel, SRpc) {
var msgEv = Util.mkEvent();
var Rpc = SRpc();
Channel.create(msgEv, postMessage, function (chan) {
var clientId = '1';
Object.keys(Rpc.queries).forEach(function (q) {
if (q === 'CONNECT') { return; }
if (q === 'JOIN_PAD') { return; }
if (q === 'SEND_PAD_MSG') { return; }
chan.on(q, function (data, cb) {
try {
Rpc.queries[q](clientId, data, cb);
} catch (e) {
console.error('Error in webworker when executing query ' + q);
console.error(e);
console.log(data);
}
});
});
chan.on('CONNECT', function (cfg, cb) {
// load Store here, with cfg, and pass a "query" (chan.query)
// cId is a clientId used in ServiceWorker or SharedWorker
cfg.query = function (cId, cmd, data, cb) {
cb = cb || function () {};
chan.query(cmd, data, function (err, data2) {
if (err) { return void cb({error: err}); }
cb(data2);
});
};
cfg.broadcast = function (excludes, cmd, data, cb) {
cb = cb || function () {};
if (excludes.indexOf(clientId) !== -1) { return; }
chan.query(cmd, data, function (err, data2) {
if (err) { return void cb({error: err}); }
cb(data2);
});
};
Rpc.queries['CONNECT'](clientId, cfg, function (data) {
if (data && data.state === "ALREADY_INIT") {
return void cb(data);
}
if (cfg.driveEvents) {
Rpc._subscribeToDrive(clientId);
}
if (cfg.messenger) {
Rpc._subscribeToMessenger(clientId);
}
cb(data);
});
});
var chanId;
chan.on('JOIN_PAD', function (data, cb) {
chanId = data.channel;
try {
Rpc.queries['JOIN_PAD'](clientId, data, cb);
} catch (e) {
console.error('Error in webworker when executing query JOIN_PAD');
console.error(e);
console.log(data);
}
});
chan.on('SEND_PAD_MSG', function (msg, cb) {
var data = {
msg: msg,
channel: chanId
};
try {
Rpc.queries['SEND_PAD_MSG'](clientId, data, cb);
} catch (e) {
console.error('Error in webworker when executing query SEND_PAD_MSG');
console.error(e);
console.log(data);
}
});
}, true);
onmessage = function (e) {
msgEv.fire(e);
};
});
});

@ -0,0 +1,147 @@
// This file provides the API for the channel for talking to and from the sandbox iframe.
define([
//'/common/sframe-protocol.js',
'/common/common-util.js'
], function (/*SFrameProtocol,*/ Util) {
var mkTxid = function () {
return Math.random().toString(16).replace('0.', '') + Math.random().toString(16).replace('0.', '');
};
var create = function (onMsg, postMsg, cb, isWorker) {
if (!isWorker) {
var chanLoaded = false;
var waitingData = [];
onMsg.reg(function (data) {
if (chanLoaded) { return; }
waitingData.push(data);
});
}
var evReady = Util.mkEvent(true);
var handlers = {};
var queries = {};
// list of handlers which are registered from the other side...
var insideHandlers = [];
var callWhenRegistered = {};
var chan = {};
// Send a query. channel.query('Q_SOMETHING', { args: "whatever" }, function (reply) { ... });
chan.query = function (q, content, cb) {
var txid = mkTxid();
var timeout = setTimeout(function () {
delete queries[txid];
//console.log("Timeout making query " + q);
}, 30000);
queries[txid] = function (data, msg) {
clearTimeout(timeout);
delete queries[txid];
cb(undefined, data.content, msg);
};
evReady.reg(function () {
postMsg(JSON.stringify({
txid: txid,
content: content,
q: q
}));
});
};
// Fire an event. channel.event('EV_SOMETHING', { args: "whatever" });
var event = chan.event = function (e, content) {
evReady.reg(function () {
postMsg(JSON.stringify({ content: content, q: e }));
});
};
// Be notified on query or event. channel.on('EV_SOMETHING', function (args, reply) { ... });
// If the type is a query, your handler will be invoked with a reply function that takes
// one argument (the content to reply with).
chan.on = function (queryType, handler, quiet) {
(handlers[queryType] = handlers[queryType] || []).push(function (data, msg) {
handler(data.content, function (replyContent) {
postMsg(JSON.stringify({
txid: data.txid,
content: replyContent
}));
}, msg);
});
if (!quiet) {
event('EV_REGISTER_HANDLER', queryType);
}
};
// If a particular handler is registered, call the callback immediately, otherwise it will be called
// when that handler is first registered.
// channel.whenReg('Q_SOMETHING', function () { ...query Q_SOMETHING?... });
chan.whenReg = function (queryType, cb, always) {
var reg = always;
if (insideHandlers.indexOf(queryType) > -1) {
cb();
} else {
reg = true;
}
if (reg) {
(callWhenRegistered[queryType] = callWhenRegistered[queryType] || []).push(cb);
}
};
// Same as whenReg except it will invoke every time there is another registration, not just once.
chan.onReg = function (queryType, cb) { chan.whenReg(queryType, cb, true); };
chan.on('EV_REGISTER_HANDLER', function (content) {
if (callWhenRegistered[content]) {
callWhenRegistered[content].forEach(function (f) { f(); });
delete callWhenRegistered[content];
}
insideHandlers.push(content);
});
chan.whenReg('EV_REGISTER_HANDLER', evReady.fire);
// Make sure both iframes are ready
var isReady =false;
chan.onReady = function (h) {
if (isReady) {
return void h();
}
if (typeof(h) !== "function") { return; }
chan.on('EV_RPC_READY', function () { isReady = true; h(); });
};
chan.ready = function () {
chan.whenReg('EV_RPC_READY', function () {
chan.event('EV_RPC_READY');
});
};
onMsg.reg(function (msg) {
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;
});
} 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);
}
});
if (isWorker) {
evReady.fire();
} else {
chanLoaded = true;
waitingData.forEach(function (d) {
onMsg.fire(d);
});
waitingData = [];
}
cb(chan);
};
return { create: create };
});

@ -116,6 +116,10 @@ define([], function () {
sframeChan.event('EV_RT_DISCONNECT');
});
padRpc.onConnectEvent.reg(function (data) {
onOpen(data);
});
padRpc.onErrorEvent.reg(function (err) {
sframeChan.event('EV_RT_ERROR', err);
});
@ -128,8 +132,6 @@ define([], function () {
owners: owners,
password: password,
expire: expire
}, function(data) {
onOpen(data);
});
};

@ -704,6 +704,9 @@ define([
readOnly: readOnly,
crypto: Crypto.createEncryptor(secret.keys),
onConnect: function () {
var href = parsed.getUrl();
// Add friends requests handlers when we have the final href
Cryptpad.messaging.addHandlers(href);
if (window.location.hash && window.location.hash !== '#') {
window.location = parsed.getUrl({
present: parsed.hashData.present,

@ -51,6 +51,8 @@ define([
if (!window.Worker) {
return void $container.text("WebWorkers not supported by your browser");
}
/*
// Shared worker
console.log('ready');
var myWorker = new SharedWorker('/worker/worker.js');
console.log(myWorker);
@ -65,7 +67,73 @@ define([
}
$container.append('<br>');
$container.append(e.data);
};*/
// Service worker
if ('serviceWorker' in navigator) {
console.log('here');
var initializing = true;
var worker;
var postMessage = function (data) {
console.log(data, navigator.serviceWorker);
if (worker) {
return void worker.postMessage(data);
}
console.log('NOT READY');
/*if (navigator.serviceWorker && navigator.serviceWorker.controller) {
navigator.serviceWorker.controller.postMessage(data);
}*/
};
navigator.serviceWorker.register('/worker/sw.js', {scope: '/'})
.then(function(reg) {
console.log(reg);
console.log('Registration succeeded. Scope is ' + reg.scope);
$container.append('<br>');
$container.append('Registered! (scope: ' + reg.scope +')');
reg.onupdatefound = function () {
if (initializing) {
var w = reg.installing;
var onStateChange = function () {
if (w.state === "activated") {
console.log(w);
worker = w;
postMessage("INIT");
w.removeEventListener("statechange", onStateChange);
}
};
w.addEventListener('statechange', onStateChange);
return;
}
console.log('new SW version found!');
// KILL EVERYTHING
UI.confirm("New version detected, you have to reload", function (yes) {
if (yes) { common.gotoURL(); }
});
};
// Here we add the event listener for receiving messages
navigator.serviceWorker.addEventListener('message', function (e) {
var data = e.data;
if (data && data.state === "READY") {
initializing = false;
$container.append('<hr>sw.js ready');
postMessage(["Hello worker"]);
return;
}
$container.append('<br>');
$container.append(e.data);
});
if (reg.active) {
worker = reg.active;
postMessage("INIT");
}
}).catch(function(error) {
console.log('Registration failed with ' + error);
$container.append('Registration error: ' + error);
});
} else {
console.log('NO SERVICE WORKER');
}
$container.append('<hr>inner.js ready');
});
});

@ -0,0 +1,69 @@
/* jshint ignore:start */
var id;
//= Math.floor(Math.random()*100000);
var postMsg = function (client, data) {
client.postMessage(data);
};
var broadcast = function (data, excludes) {
// Loop over all available clients
clients.matchAll().then(function (clients) {
clients.forEach(function (client) {
if (excludes.indexOf(client.id) === -1) {
postMsg(client, data);
}
})
})
};
var sendTo = function (data, clientId){
clients.matchAll().then(function (clients) {
clients.some(function (client) {
if (client.id === clientId) {
postMsg(client, data)
}
})
})
};
var getClients = function () {
clients.matchAll().then(function (clients) {
var cl = clients.map(function (c) {
console.log(JSON.stringify(c));
return c.id;
});
console.log(cl);
});
};
self.addEventListener('message', function (e) {
console.log(clients);
console.log('worker received');
console.log(e.data);
console.log(e.source);
var cId = e.source.id;
if (e.data === "INIT") {
if (!id) {
id = Math.floor(Math.random()*100000);
}
broadcast(cId + ' has joined!', [cId]);
postMsg(e.source, {state: 'READY'});
postMsg(e.source, "Welcome to SW " + id + "!");
postMsg(e.source, "You are identified as " + cId);
} else {
console.log(e.data);
postMsg(e.source, 'Yo (Re: '+e.data+')');
}
});
self.addEventListener('install', function (e) {
console.log(e);
console.log('V1 installing…');
self.skipWaiting();
});
self.addEventListener('activate', function (e) {
console.log(e);
console.log('V1 now ready to handle fetches!');
});
Loading…
Cancel
Save