Mailbox and notifications prototype

pull/1/head
yflory 6 years ago
parent 3feb310fc4
commit ce2d0d5b83

@ -625,6 +625,13 @@ define([
// Set the display name (username) in the proxy // Set the display name (username) in the proxy
Store.setDisplayName = function (clientId, value, cb) { Store.setDisplayName = function (clientId, value, cb) {
if (store.mailbox) {
// XXX test mailbox, should be removed in prod
store.mailbox.post('notifications', 'NAME_CHANGED', {
old: store.proxy[Constants.displayNameKey],
new: value
});
}
store.proxy[Constants.displayNameKey] = value; store.proxy[Constants.displayNameKey] = value;
broadcast([clientId], "UPDATE_METADATA"); broadcast([clientId], "UPDATE_METADATA");
if (store.messenger) { store.messenger.updateMyData(); } if (store.messenger) { store.messenger.updateMyData(); }
@ -950,6 +957,7 @@ define([
// Mailbox // Mailbox
Store.mailbox = { Store.mailbox = {
execCommand: function (clientId, data, cb) { execCommand: function (clientId, data, cb) {
if (!store.loggedIn) { return void cb(); }
if (!store.mailbox) { return void cb ({error: 'Mailbox is disabled'}); } if (!store.mailbox) { return void cb ({error: 'Mailbox is disabled'}); }
store.mailbox.execCommand(clientId, data, cb); store.mailbox.execCommand(clientId, data, cb);
} }
@ -1092,6 +1100,7 @@ define([
channel.queue.forEach(function (data) { channel.queue.forEach(function (data) {
channel.sendMessage(data.message, clientId); channel.sendMessage(data.message, clientId);
}); });
channel.queue = [];
channel.bcast("PAD_CONNECT", { channel.bcast("PAD_CONNECT", {
myID: wc.myID, myID: wc.myID,
id: wc.id, id: wc.id,
@ -1310,13 +1319,15 @@ define([
if (messengerIdx !== -1) { if (messengerIdx !== -1) {
messengerEventClients.splice(messengerIdx, 1); messengerEventClients.splice(messengerIdx, 1);
} }
// TODO mailbox events
try { try {
store.cursor.removeClient(clientId); store.cursor.removeClient(clientId);
} catch (e) { console.error(e); } } catch (e) { console.error(e); }
try { try {
store.onlyoffice.removeClient(clientId); store.onlyoffice.removeClient(clientId);
} catch (e) { console.error(e); } } catch (e) { console.error(e); }
try {
store.mailbox.removeClient(clientId);
} catch (e) { console.error(e); }
Object.keys(Store.channels).forEach(function (chanId) { Object.keys(Store.channels).forEach(function (chanId) {
var chanIdx = Store.channels[chanId].clients.indexOf(clientId); var chanIdx = Store.channels[chanId].clients.indexOf(clientId);
@ -1413,6 +1424,9 @@ define([
}; };
var loadMailbox = function (waitFor) { var loadMailbox = function (waitFor) {
if (!store.loggedIn || !store.proxy.edPublic) {
return;
}
store.mailbox = Mailbox.init(store, waitFor, function (ev, data, clients) { store.mailbox = Mailbox.init(store, waitFor, function (ev, data, clients) {
clients.forEach(function (cId) { clients.forEach(function (cId) {
postMessage(cId, 'MAILBOX_EVENT', { postMessage(cId, 'MAILBOX_EVENT', {

@ -1,30 +1,242 @@
define([ define([
'/common/common-util.js', '/common/common-util.js',
'/common/common-constants.js', '/common/common-constants.js',
'/common/common-realtime.js',
'/customize/messages.js', '/customize/messages.js',
'/bower_components/chainpad-netflux/chainpad-netflux.js', '/bower_components/chainpad-netflux/chainpad-netflux.js',
'/bower_components/chainpad-crypto/crypto.js', '/bower_components/chainpad-crypto/crypto.js',
], function (Util, Constants, Messages, CpNetflux, Crypto) { ], function (Util, Constants, Realtime, Messages, CpNetflux, Crypto) {
var Mailbox = {}; var Mailbox = {};
var TYPES = [
'notifications'
];
var BLOCKING_TYPES = [
];
/*
proxy.mailboxes = {
friends: {
keys: '',
channel: '',
hash: '',
lastKnownHash: '',
viewed: []
}
};
*/
var isMessageNew = function (hash, m) {
return (m.viewed || []).indexOf(hash) === -1 && hash !== m.lastKnownHash;
};
var showMessage = function (ctx, type, msg, cId) {
ctx.emit('MESSAGE', {
type: type,
content: msg
}, cId ? [cId] : ctx.clients);
};
var openChannel = function (ctx, type, m, onReady) {
var box = ctx.boxes[type] = {
queue: [],
history: [],
sendMessage: function (msg) { // To send a message to our box
try {
msg = JSON.stringify(msg);
} catch (e) {
console.error(e);
}
box.queue.push(msg);
}
};
/*
// XXX
if (!Crypto.Mailbox) {
return void console.error("chainpad-crypto is outdated and doesn't support mailboxes.");
}
var crypto = Crypto.Mailbox.createEncryptor();
*/
var crypto = {
encrypt: function (x) { return x; },
decrypt: function (x) { return x; }
};
var cfg = {
network: ctx.store.network,
channel: m.channel, // TODO
noChainPad: true,
crypto: crypto,
owners: [ctx.store.proxy.edPublic],
lastKnownHash: m.lastKnownHash
};
cfg.onConnect = function (wc, sendMessage) {
// Send a message to our box?
box.sendMessage = function (msg) {
try {
msg = JSON.stringify(msg);
} catch (e) {
console.error(e);
}
sendMessage(msg, function (err, hash) {
if (m.viewed.indexOf(hash) === -1) {
m.viewed.push(hash);
}
});
};
box.queue.forEach(function (msg) {
box.sendMessage(msg);
});
box.queue = [];
};
cfg.onMessage = function (msg, user, vKey, isCpi, hash) {
// TODO
try {
msg = JSON.parse(msg);
} catch (e) {
console.error(e);
}
if (isMessageNew(hash, m)) {
// Message should be displayed
var message = {
msg: msg,
hash: hash
};
box.history.push(message);
showMessage(ctx, type, message);
} else {
// Message has already been viewer by the user
if (history.length === 0) {
m.lastKnownHash = hash;
}
console.log(hash + ' is not new');
}
};
cfg.onReady = function () {
onReady();
};
CpNetflux.start(cfg);
};
// Send a message to someone else
var sendTo = function () {
};
// Mark a message as read
var dismiss = function (ctx, data, cId, cb) {
var type = data.type;
var hash = data.hash;
var m = Util.find(ctx, ['store', 'proxy', 'mailboxes', type]);
if (!m) { return void cb({error: 'NOT_FOUND'}); }
var box = ctx.boxes[type];
if (!box) { return void cb({error: 'NOT_LOADED'}); }
// If the hash in in our history, get the index from the history:
// - if the index is 0, we can change our lastKnownHash
// - otherwise, just push to view
var idx;
if (box.history.some(function (el, i) {
if (hash === el.hash) {
idx = i;
return true;
}
})) {
if (idx === 0) {
m.lastKnownHash = hash;
} else if (m.viewed.indexOf(hash) === -1) {
m.viewed.push(hash);
}
}
// Check the "viewed" array to see if we're able to bump lastKnownhash more
var sliceIdx;
box.history.some(function (el, i) {
var isViewed = m.viewed.indexOf(el.hash);
if (isViewed !== -1) {
sliceIdx = i + 1;
m.viewed.splice(isViewed, 1);
return false;
}
return true;
});
if (sliceIdx) {
box.history = box.history.slice(sliceIdx);
}
Realtime.whenRealtimeSyncs(ctx.store.realtime, function () {
cb();
});
};
var subscribe = function (ctx, data, cId, cb) {
// Get existing notifications
Object.keys(ctx.boxes).forEach(function (type) {
ctx.boxes[type].history.forEach(function (obj) {
showMessage(ctx, type, obj, cId);
});
});
// Subscribe to new notifications
var idx = ctx.clients.indexOf(cId);
if (idx === -1) {
ctx.clients.push(cId);
}
cb();
};
var removeClient = function (ctx, cId) {
var idx = ctx.clients.indexOf(cId);
ctx.clients.splice(idx, 1);
};
Mailbox.init = function (store, waitFor, emit) { Mailbox.init = function (store, waitFor, emit) {
var mailbox = {}; var mailbox = {};
var ctx = { var ctx = {
store: store, store: store,
emit: emit, emit: emit,
clients: [],
boxes: {}
}; };
mailbox.removeClient = function (clientId) { var mailboxes = store.proxy.mailboxes || {};
// TODO Object.keys(mailboxes).forEach(function (key) {
//removeClient(ctx, clientId); if (TYPES.indexOf(key) === -1) { return; }
var m = mailboxes[key];
if (BLOCKING_TYPES.indexOf(key) === -1) {
openChannel(ctx, key, m, function () {
console.log(key + ' mailbox is ready');
});
} else {
openChannel(ctx, key, m, waitFor(function () {
console.log(key + ' mailbox is ready');
}));
}
});
// XXX test function used to populate a mailbox, should be removed in prod
mailbox.post = function (box, type, content) {
var b = ctx.boxes[box];
if (!b) { return; }
b.sendMessage({
type: type,
content: content,
sender: store.proxy.curvePublic
});
}; };
mailbox.leavePad = function (padChan) {
// TODO mailbox.removeClient = function (clientId) {
//leaveChannel(ctx, padChan); removeClient(ctx, clientId);
}; };
mailbox.execCommand = function (clientId, obj, cb) { mailbox.execCommand = function (clientId, obj, cb) {
var cmd = obj.cmd; var cmd = obj.cmd;
var data = obj.data; var data = obj.data;
if (cmd === 'SUBSCRIBE') {
return void subscribe(ctx, data, clientId, cb);
}
if (cmd === 'DISMISS') {
return void dismiss(ctx, data, clientId, cb);
}
}; };
return mailbox; return mailbox;

@ -0,0 +1,127 @@
define([
'jquery',
'/common/common-util.js',
'/common/common-interface.js',
'/common/common-ui-elements.js',
'/customize/messages.js'
], function ($, Util, UI, UIElements, Messages) {
var Mailbox = {};
Mailbox.create = function (Common) {
var mailbox = {};
var metadataMgr = Common.getMetadataMgr();
var sframeChan = Common.getSframeChannel();
var execCommand = function (cmd, data, cb) {
sframeChan.query('Q_MAILBOX_COMMAND', {
cmd: cmd,
data: data
}, function (err, obj) {
if (err) { return void cb({error: err}); }
cb(obj);
});
};
var history = {};
var removeFromHistory = function (type, hash) {
history[type] = history[type].filter(function (obj) {
return obj.hash !== hash;
});
};
mailbox.dismiss = function (type, hash, cb) {
execCommand('DISMISS', {
hash: hash,
type: type
}, function (obj) {
if (obj && obj.error) { return void cb(obj.error); }
removeFromHistory(type, hash);
cb();
});
};
mailbox.sendTo = function (user, type, content) {
};
// UI
var onViewedHandlers = [];
var onMessageHandlers = [];
// Call the onMessage handlers
var pushMessage = function (data) {
onMessageHandlers.forEach(function (f) {
try {
f(data);
} catch (e) {
console.error(e);
}
});
};
// Get all existing notifications + the new ones when they come
mailbox.subscribe = function (cfg) {
if (typeof(cfg.onViewed) === "function") {
onViewedHandlers.push(cfg.onViewed);
}
if (typeof(cfg.onMessage) === "function") {
onMessageHandlers.push(cfg.onMessage);
}
Object.keys(history).forEach(function (type) {
history[type].forEach(function (data) {
pushMessage({
type: type,
content: data
});
});
});
};
var onViewed = function (data) {
// data = { type: 'type', hash: 'hash' }
onViewedHandlers.forEach(function (f) {
try {
f(data);
} catch (e) {
console.error(e);
}
});
removeFromHistory(data.type, data.hash);
};
var onMessage = function (data) {
// data = { type: 'type', content: {msg: 'msg', hash: 'hash'} }
console.log(data.content);
pushMessage(data);
if (!history[data.type]) { history[data.type] = []; }
history[data.type].push(data.content);
};
// CHANNEL WITH WORKER
sframeChan.on('EV_MAILBOX_EVENT', function (obj) {
// obj = { ev: 'type', data: obj }
var ev = obj.ev;
var data = obj.data;
if (ev === 'MESSAGE') {
return void onMessage(data);
}
if (ev === 'VIEWED') {
return void onViewed(data);
}
});
execCommand('SUBSCRIBE', null, function () {
console.log('subscribed');
});
return mailbox;
};
return Mailbox;
});

@ -877,6 +877,13 @@ define([
Cryptpad.cursor.execCommand(data, cb); Cryptpad.cursor.execCommand(data, cb);
}); });
Cryptpad.mailbox.onEvent.reg(function (data) {
sframeChan.event('EV_MAILBOX_EVENT', data);
});
sframeChan.on('Q_MAILBOX_COMMAND', function (data, cb) {
Cryptpad.mailbox.execCommand(data, cb);
});
Cryptpad.onTimeoutEvent.reg(function () { Cryptpad.onTimeoutEvent.reg(function () {
sframeChan.event('EV_WORKER_TIMEOUT'); sframeChan.event('EV_WORKER_TIMEOUT');
}); });

@ -10,6 +10,7 @@ define([
'/common/sframe-common-file.js', '/common/sframe-common-file.js',
'/common/sframe-common-codemirror.js', '/common/sframe-common-codemirror.js',
'/common/sframe-common-cursor.js', '/common/sframe-common-cursor.js',
'/common/sframe-common-mailbox.js',
'/common/metadata-manager.js', '/common/metadata-manager.js',
'/customize/application_config.js', '/customize/application_config.js',
@ -33,6 +34,7 @@ define([
File, File,
CodeMirror, CodeMirror,
Cursor, Cursor,
Mailbox,
MetadataMgr, MetadataMgr,
AppConfig, AppConfig,
CommonRealtime, CommonRealtime,
@ -630,6 +632,8 @@ define([
ctx.sframeChan.ready(); ctx.sframeChan.ready();
cb(funcs); cb(funcs);
Mailbox.create(funcs);
}); });
} }; } };
}); });

Loading…
Cancel
Save