Merge branch 'mailbox' into staging
This commit is contained in:
@@ -123,6 +123,13 @@ define([
|
||||
list = list.concat(fList);
|
||||
}
|
||||
|
||||
if (store.proxy.mailboxes) {
|
||||
var mList = Object.keys(store.proxy.mailboxes).map(function (m) {
|
||||
return store.proxy.mailboxes[m].channel;
|
||||
});
|
||||
list = list.concat(mList);
|
||||
}
|
||||
|
||||
list.push(userChannel);
|
||||
list.sort();
|
||||
|
||||
@@ -451,6 +458,7 @@ define([
|
||||
avatar: Util.find(store.proxy, ['profile', 'avatar']),
|
||||
profile: Util.find(store.proxy, ['profile', 'view']),
|
||||
color: getUserColor(),
|
||||
notifications: Util.find(store.proxy, ['mailboxes', 'notifications', 'channel']),
|
||||
curvePublic: store.proxy.curvePublic,
|
||||
},
|
||||
// "priv" is not shared with other users but is needed by the apps
|
||||
@@ -460,7 +468,8 @@ define([
|
||||
friends: store.proxy.friends || {},
|
||||
settings: store.proxy.settings,
|
||||
thumbnails: disableThumbnails === false,
|
||||
isDriveOwned: Boolean(Util.find(store, ['driveMetadata', 'owners']))
|
||||
isDriveOwned: Boolean(Util.find(store, ['driveMetadata', 'owners'])),
|
||||
pendingFriends: store.proxy.friends_pending || {}
|
||||
}
|
||||
};
|
||||
cb(JSON.parse(JSON.stringify(metadata)));
|
||||
@@ -626,6 +635,27 @@ define([
|
||||
|
||||
// Set the display name (username) in the proxy
|
||||
Store.setDisplayName = function (clientId, value, cb) {
|
||||
if (store.mailbox && store.proxy.friends) {
|
||||
// XXX test mailbox, should be removed in prod
|
||||
/*store.mailbox.post('notifications', 'NAME_CHANGED', {
|
||||
old: store.proxy[Constants.displayNameKey],
|
||||
new: value
|
||||
});
|
||||
Object.keys(store.proxy.friends).forEach(function (curve) {
|
||||
var f = store.proxy.friends[curve];
|
||||
if (!f.notifications) { return; }
|
||||
store.mailbox.sendTo('NAME_CHANGED', {
|
||||
old: store.proxy[Constants.displayNameKey],
|
||||
new: value
|
||||
}, {
|
||||
channel: f.notifications,
|
||||
curvePublic: curve
|
||||
}, function (obj) {
|
||||
if (obj && obj.error) { return void console.error(obj.error); }
|
||||
console.log('notif sent to '+f);
|
||||
});
|
||||
});*/
|
||||
}
|
||||
store.proxy[Constants.displayNameKey] = value;
|
||||
broadcast([clientId], "UPDATE_METADATA");
|
||||
if (store.messenger) { store.messenger.updateMyData(); }
|
||||
@@ -881,36 +911,73 @@ define([
|
||||
|
||||
|
||||
// Messaging (manage friends from the userlist)
|
||||
var getMessagingCfg = function (clientId) {
|
||||
return {
|
||||
proxy: store.proxy,
|
||||
realtime: store.realtime,
|
||||
network: store.network,
|
||||
updateMetadata: function () {
|
||||
postMessage(clientId, "UPDATE_METADATA");
|
||||
},
|
||||
pinPads: function (data, cb) { Store.pinPads(null, data, cb); },
|
||||
friendComplete: function (data) {
|
||||
if (data.friend && store.messenger && store.messenger.onFriendAdded) {
|
||||
store.messenger.onFriendAdded(data.friend);
|
||||
}
|
||||
postMessage(clientId, "EV_FRIEND_COMPLETE", data);
|
||||
},
|
||||
friendRequest: function (data, cb) {
|
||||
postMessage(clientId, "Q_FRIEND_REQUEST", data, cb);
|
||||
},
|
||||
};
|
||||
};
|
||||
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);
|
||||
};
|
||||
Store.answerFriendRequest = function (clientId, obj, cb) {
|
||||
var value = obj.value;
|
||||
var data = obj.data;
|
||||
if (data.type !== 'notifications') { return void cb ({error: 'EINVAL'}); }
|
||||
var hash = data.content.hash;
|
||||
var msg = data.content.msg;
|
||||
|
||||
// Messenger
|
||||
var dismiss = function (cb) {
|
||||
cb = cb || function () {};
|
||||
store.mailbox.dismiss({
|
||||
hash: hash,
|
||||
type: 'notifications'
|
||||
}, cb);
|
||||
};
|
||||
|
||||
// If we accept the request, add the friend to the list
|
||||
if (value) {
|
||||
Messaging.acceptFriendRequest(store, msg.content, function (obj) {
|
||||
if (obj && obj.error) { return void cb(obj); }
|
||||
Messaging.addToFriendList({
|
||||
proxy: store.proxy,
|
||||
realtime: store.realtime,
|
||||
pinPads: function (data, cb) { Store.pinPads(null, data, cb); },
|
||||
}, msg.content, function (err) {
|
||||
if (store.messenger) {
|
||||
store.messenger.onFriendAdded(msg.content);
|
||||
}
|
||||
broadcast([], "UPDATE_METADATA");
|
||||
if (err) { return void cb({error: err}); }
|
||||
dismiss(cb);
|
||||
});
|
||||
});
|
||||
return;
|
||||
}
|
||||
// Otherwise, just remove the notification
|
||||
store.mailbox.sendTo('DECLINE_FRIEND_REQUEST', {}, {
|
||||
channel: msg.content.notifications,
|
||||
curvePublic: msg.content.curvePublic
|
||||
}, function (obj) {
|
||||
cb(obj);
|
||||
});
|
||||
dismiss();
|
||||
};
|
||||
Store.sendFriendRequest = function (clientId, data, cb) {
|
||||
var friend = Messaging.getFriend(store.proxy, data.curvePublic);
|
||||
if (friend) { return void cb({error: 'ALREADY_FRIEND'}); }
|
||||
if (!data.notifications || !data.curvePublic) { return void cb({error: 'INVALID_USER'}); }
|
||||
|
||||
store.proxy.friends_pending = store.proxy.friends_pending || {};
|
||||
|
||||
var twoDaysAgo = +new Date() - (2 * 24 * 3600 * 1000);
|
||||
if (store.proxy.friends_pending[data.curvePublic] &&
|
||||
store.proxy.friends_pending[data.curvePublic] > twoDaysAgo) {
|
||||
return void cb({error: 'TIMEOUT'});
|
||||
}
|
||||
|
||||
store.proxy.friends_pending[data.curvePublic] = +new Date();
|
||||
broadcast([], "UPDATE_METADATA");
|
||||
|
||||
var myData = Messaging.createData(store.proxy);
|
||||
store.mailbox.sendTo('FRIEND_REQUEST', myData, {
|
||||
channel: data.notifications,
|
||||
curvePublic: data.curvePublic
|
||||
}, function (obj) {
|
||||
cb(obj);
|
||||
});
|
||||
};
|
||||
|
||||
// Get hashes for the share button
|
||||
Store.getStrongerHash = function (clientId, data, cb) {
|
||||
@@ -925,6 +992,7 @@ define([
|
||||
cb();
|
||||
};
|
||||
|
||||
// Messenger
|
||||
Store.messenger = {
|
||||
execCommand: function (clientId, data, cb) {
|
||||
if (!store.messenger) { return void cb({error: 'Messenger is disabled'}); }
|
||||
@@ -951,6 +1019,7 @@ define([
|
||||
// Mailbox
|
||||
Store.mailbox = {
|
||||
execCommand: function (clientId, data, cb) {
|
||||
if (!store.loggedIn) { return void cb(); }
|
||||
if (!store.mailbox) { return void cb ({error: 'Mailbox is disabled'}); }
|
||||
store.mailbox.execCommand(clientId, data, cb);
|
||||
}
|
||||
@@ -1314,13 +1383,15 @@ define([
|
||||
if (messengerIdx !== -1) {
|
||||
messengerEventClients.splice(messengerIdx, 1);
|
||||
}
|
||||
// TODO mailbox events
|
||||
try {
|
||||
store.cursor.removeClient(clientId);
|
||||
} catch (e) { console.error(e); }
|
||||
try {
|
||||
store.onlyoffice.removeClient(clientId);
|
||||
} catch (e) { console.error(e); }
|
||||
try {
|
||||
store.mailbox.removeClient(clientId);
|
||||
} catch (e) { console.error(e); }
|
||||
|
||||
Object.keys(Store.channels).forEach(function (chanId) {
|
||||
var chanIdx = Store.channels[chanId].clients.indexOf(clientId);
|
||||
@@ -1385,7 +1456,9 @@ define([
|
||||
};
|
||||
var loadMessenger = function () {
|
||||
if (AppConfig.availablePadTypes.indexOf('contacts') === -1) { return; }
|
||||
var messenger = store.messenger = Messenger.messenger(store);
|
||||
var messenger = store.messenger = Messenger.messenger(store, function () {
|
||||
broadcast([], "UPDATE_METADATA");
|
||||
});
|
||||
messenger.on('event', function (ev, data) {
|
||||
sendMessengerEvent('CHAT_EVENT', {
|
||||
ev: ev,
|
||||
@@ -1417,7 +1490,16 @@ define([
|
||||
};
|
||||
|
||||
var loadMailbox = function (waitFor) {
|
||||
store.mailbox = Mailbox.init(store, waitFor, function (ev, data, clients) {
|
||||
if (!store.loggedIn || !store.proxy.edPublic) {
|
||||
return;
|
||||
}
|
||||
store.mailbox = Mailbox.init({
|
||||
store: store,
|
||||
updateMetadata: function () {
|
||||
broadcast([], "UPDATE_METADATA");
|
||||
},
|
||||
pinPads: function (data, cb) { Store.pinPads(null, data, cb); },
|
||||
}, waitFor, function (ev, data, clients) {
|
||||
clients.forEach(function (cId) {
|
||||
postMessage(cId, 'MAILBOX_EVENT', {
|
||||
ev: ev,
|
||||
@@ -1427,6 +1509,18 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
var cleanFriendRequests = function () {
|
||||
try {
|
||||
if (!store.proxy.friends_pending) { return; }
|
||||
var twoDaysAgo = +new Date() - (2 * 24 * 3600 * 1000);
|
||||
Object.keys(store.proxy.friends_pending).forEach(function (curve) {
|
||||
if (store.proxy.friends_pending[curve] < twoDaysAgo) {
|
||||
delete store.proxy.friends_pending[curve];
|
||||
}
|
||||
});
|
||||
} catch (e) {}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
/////////////////////// Init /////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////
|
||||
@@ -1522,6 +1616,7 @@ define([
|
||||
loadCursor();
|
||||
loadOnlyOffice();
|
||||
loadMailbox(waitFor);
|
||||
cleanFriendRequests();
|
||||
}).nThen(function () {
|
||||
var requestLogin = function () {
|
||||
broadcast([], "REQUEST_LOGIN");
|
||||
@@ -1575,9 +1670,31 @@ define([
|
||||
// Trigger userlist update when the avatar has changed
|
||||
broadcast([], "UPDATE_METADATA");
|
||||
});
|
||||
proxy.on('change', ['friends'], function () {
|
||||
proxy.on('change', ['friends'], function (o, n, p) {
|
||||
// Trigger userlist update when the friendlist has changed
|
||||
broadcast([], "UPDATE_METADATA");
|
||||
|
||||
if (!store.messenger) { return; }
|
||||
if (o !== undefined) { return; }
|
||||
var curvePublic = p.slice(-1)[0];
|
||||
var friend = proxy.friends && proxy.friends[curvePublic];
|
||||
store.messenger.onFriendAdded(friend);
|
||||
});
|
||||
proxy.on('remove', ['friends'], function (o, p) {
|
||||
broadcast([], "UPDATE_METADATA");
|
||||
|
||||
if (!store.messenger) { return; }
|
||||
var curvePublic = p[1];
|
||||
if (!curvePublic) { return; }
|
||||
if (p[2] !== 'channel') { return; }
|
||||
store.messenger.onFriendRemoved(curvePublic, o);
|
||||
});
|
||||
proxy.on('change', ['friends_pending'], function () {
|
||||
// Trigger userlist update when the friendlist has changed
|
||||
broadcast([], "UPDATE_METADATA");
|
||||
});
|
||||
proxy.on('remove', ['friends_pending'], function () {
|
||||
broadcast([], "UPDATE_METADATA");
|
||||
});
|
||||
proxy.on('change', ['settings'], function () {
|
||||
broadcast([], "UPDATE_METADATA");
|
||||
|
||||
59
www/common/outer/mailbox-handlers.js
Normal file
59
www/common/outer/mailbox-handlers.js
Normal file
@@ -0,0 +1,59 @@
|
||||
define([
|
||||
'/common/common-messaging.js',
|
||||
], function (Messaging) {
|
||||
|
||||
var handlers = {};
|
||||
|
||||
handlers['FRIEND_REQUEST'] = function (ctx, data, cb) {
|
||||
if (data.msg.author === data.msg.content.curvePublic &&
|
||||
Messaging.getFriend(ctx.store.proxy, data.msg.author)) {
|
||||
Messaging.acceptFriendRequest(ctx.store, data.msg.content, function (obj) {
|
||||
if (obj && obj.error) { return void cb(); }
|
||||
cb(true);
|
||||
});
|
||||
return;
|
||||
}
|
||||
cb();
|
||||
};
|
||||
handlers['DECLINE_FRIEND_REQUEST'] = function (ctx, box, data, cb) {
|
||||
// Our friend request was declined.
|
||||
if (!ctx.store.proxy.friends_pending[data.msg.author]) { return void cb(true); }
|
||||
delete ctx.store.proxy.friends_pending[data.msg.author];
|
||||
ctx.updateMetadata();
|
||||
cb();
|
||||
};
|
||||
handlers['ACCEPT_FRIEND_REQUEST'] = function (ctx, box, data, cb) {
|
||||
// Our friend request was accepted.
|
||||
// Make sure we really sent it
|
||||
if (!ctx.store.proxy.friends_pending[data.msg.author]) { return void cb(); }
|
||||
// And add the friend
|
||||
Messaging.addToFriendList({
|
||||
proxy: ctx.store.proxy,
|
||||
realtime: ctx.store.realtime,
|
||||
pinPads: ctx.pinPads
|
||||
}, data.msg.content, function (err) {
|
||||
if (err) { console.error(err); }
|
||||
delete ctx.store.proxy.friends_pending[data.msg.author];
|
||||
if (ctx.store.messenger) {
|
||||
ctx.store.messenger.onFriendAdded(data.msg.content);
|
||||
}
|
||||
ctx.updateMetadata();
|
||||
});
|
||||
cb();
|
||||
};
|
||||
|
||||
return function (ctx, box, data, cb) {
|
||||
var type = data.msg.type;
|
||||
|
||||
if (handlers[type]) {
|
||||
try {
|
||||
handlers[type](ctx, box, data, cb);
|
||||
} catch (e) {
|
||||
cb();
|
||||
}
|
||||
} else {
|
||||
cb();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1,31 +1,395 @@
|
||||
// jshint ignore: start
|
||||
define([
|
||||
'/common/common-util.js',
|
||||
'/common/common-constants.js',
|
||||
'/customize/messages.js',
|
||||
'/common/common-hash.js',
|
||||
'/common/common-realtime.js',
|
||||
'/common/outer/mailbox-handlers.js',
|
||||
'/bower_components/chainpad-netflux/chainpad-netflux.js',
|
||||
'/bower_components/chainpad-crypto/crypto.js',
|
||||
], function (Util, Constants, Messages, CpNetflux, Crypto) {
|
||||
], function (Util, Hash, Realtime, Handlers, CpNetflux, Crypto) {
|
||||
var Mailbox = {};
|
||||
|
||||
Mailbox.init = function (store, waitFor, emit) {
|
||||
var TYPES = [
|
||||
'notifications',
|
||||
'test'
|
||||
];
|
||||
var BLOCKING_TYPES = [
|
||||
];
|
||||
|
||||
var initializeMailboxes = function (ctx, mailboxes) {
|
||||
if (!mailboxes['notifications']) {
|
||||
mailboxes.notifications = {
|
||||
channel: Hash.createChannelId(),
|
||||
lastKnownHash: '',
|
||||
viewed: []
|
||||
};
|
||||
ctx.pinPads([mailboxes.notifications.channel], function (res) {
|
||||
if (res.error) { console.error(res); }
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
proxy.mailboxes = {
|
||||
friends: {
|
||||
channel: '',
|
||||
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 getMyKeys = function (ctx) {
|
||||
var proxy = ctx.store && ctx.store.proxy;
|
||||
if (!proxy.curvePrivate || !proxy.curvePublic) { return; }
|
||||
return {
|
||||
curvePrivate: proxy.curvePrivate,
|
||||
curvePublic: proxy.curvePublic
|
||||
};
|
||||
};
|
||||
|
||||
// Send a message to someone else
|
||||
var sendTo = function (ctx, type, msg, user, cb) {
|
||||
if (!Crypto.Mailbox) {
|
||||
return void cb({error: "chainpad-crypto is outdated and doesn't support mailboxes."});
|
||||
}
|
||||
var keys = getMyKeys(ctx);
|
||||
if (!keys) { return void cb({error: "missing asymmetric encryption keys"}); }
|
||||
if (!user || !user.channel || !user.curvePublic) { return void cb({error: "no notification channel"}); }
|
||||
|
||||
var crypto = Crypto.Mailbox.createEncryptor(keys);
|
||||
var network = ctx.store.network;
|
||||
|
||||
var ciphertext = crypto.encrypt(JSON.stringify({
|
||||
type: type,
|
||||
content: msg
|
||||
}), user.curvePublic);
|
||||
|
||||
network.join(user.channel).then(function (wc) {
|
||||
wc.bcast(ciphertext).then(function () {
|
||||
cb();
|
||||
wc.leave();
|
||||
});
|
||||
}, function (err) {
|
||||
cb({error: err});
|
||||
});
|
||||
};
|
||||
|
||||
var updateLastKnownHash = function (ctx, type) {
|
||||
var m = Util.find(ctx, ['store', 'proxy', 'mailboxes', type]);
|
||||
if (!m) { return; }
|
||||
var box = ctx.boxes[type];
|
||||
if (!box) { return; }
|
||||
|
||||
};
|
||||
|
||||
// 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) {
|
||||
idx = i;
|
||||
return true;
|
||||
}
|
||||
})) {
|
||||
if (idx === 0) {
|
||||
m.lastKnownHash = hash;
|
||||
box.history.shift();
|
||||
delete box.content[hash];
|
||||
} else if (m.viewed.indexOf(hash) === -1) {
|
||||
m.viewed.push(hash);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear data in memory if needed
|
||||
// Check the "viewed" array to see if we're able to bump lastKnownhash more
|
||||
var sliceIdx;
|
||||
var lastKnownHash;
|
||||
box.history.some(function (hash, i) {
|
||||
var isViewed = m.viewed.indexOf(hash);
|
||||
if (isViewed !== -1) {
|
||||
sliceIdx = i + 1;
|
||||
m.viewed.splice(isViewed, 1);
|
||||
lastKnownHash = hash;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (sliceIdx) {
|
||||
box.history = box.history.slice(sliceIdx);
|
||||
m.lastKnownHash = lastKnownHash;
|
||||
}
|
||||
|
||||
// Make sure we remove data about dismissed messages
|
||||
Object.keys(box.content).forEach(function (h) {
|
||||
if (box.history.indexOf(h) === -1 || m.viewed.indexOf(h) !== -1) {
|
||||
delete box.content[h];
|
||||
}
|
||||
});
|
||||
|
||||
Realtime.whenRealtimeSyncs(ctx.store.realtime, function () {
|
||||
cb();
|
||||
ctx.emit('VIEWED', {
|
||||
type: type,
|
||||
hash: hash
|
||||
}, ctx.clients.filter(function (clientId) {
|
||||
return clientId !== cId;
|
||||
}));
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
var openChannel = function (ctx, type, m, onReady) {
|
||||
var box = ctx.boxes[type] = {
|
||||
queue: [], // Store the messages to send when the channel is ready
|
||||
history: [], // All the hashes loaded from the server in corretc order
|
||||
content: {}, // Content of the messages that should be displayed
|
||||
sendMessage: function (msg) { // To send a message to our box
|
||||
try {
|
||||
msg = JSON.stringify(msg);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
box.queue.push(msg);
|
||||
}
|
||||
};
|
||||
Crypto = Crypto;
|
||||
if (!Crypto.Mailbox) {
|
||||
return void console.error("chainpad-crypto is outdated and doesn't support mailboxes.");
|
||||
}
|
||||
var keys = getMyKeys(ctx);
|
||||
if (!keys) { return void console.error("missing asymmetric encryption keys"); }
|
||||
var crypto = Crypto.Mailbox.createEncryptor(keys);
|
||||
// XXX remove 'test'
|
||||
if (type === 'test') {
|
||||
crypto = {
|
||||
encrypt: function (x) { return x; },
|
||||
decrypt: function (x) { return x; }
|
||||
};
|
||||
}
|
||||
var cfg = {
|
||||
network: ctx.store.network,
|
||||
channel: m.channel,
|
||||
noChainPad: true,
|
||||
crypto: crypto,
|
||||
owners: [ctx.store.proxy.edPublic],
|
||||
lastKnownHash: m.lastKnownHash
|
||||
};
|
||||
cfg.onConnect = function (wc, sendMessage) {
|
||||
// Send a message to our box?
|
||||
// NOTE: we use our own curvePublic so that we can decrypt our own message :)
|
||||
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);
|
||||
}
|
||||
}, keys.curvePublic);
|
||||
};
|
||||
box.queue.forEach(function (msg) {
|
||||
box.sendMessage(msg);
|
||||
});
|
||||
box.queue = [];
|
||||
};
|
||||
cfg.onMessage = function (msg, user, vKey, isCp, hash, author) {
|
||||
if (hash === m.lastKnownHash) { return; }
|
||||
try {
|
||||
msg = JSON.parse(msg);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
if (author) { msg.author = author; }
|
||||
box.history.push(hash);
|
||||
if (isMessageNew(hash, m)) {
|
||||
// Message should be displayed
|
||||
var message = {
|
||||
msg: msg,
|
||||
hash: hash
|
||||
};
|
||||
Handlers(ctx, box, message, function (toDismiss) {
|
||||
if (toDismiss) {
|
||||
dismiss(ctx, {
|
||||
type: type,
|
||||
hash: hash
|
||||
}, '', function () {
|
||||
console.log('Notification handled automatically');
|
||||
});
|
||||
return;
|
||||
}
|
||||
box.content[hash] = msg;
|
||||
showMessage(ctx, type, message);
|
||||
});
|
||||
} else {
|
||||
// Message has already been viewed by the user
|
||||
if (Object.keys(box.content).length === 0) {
|
||||
// If nothing is displayed yet, we can bump our lastKnownHash and remove this hash
|
||||
// from our "viewed" array
|
||||
m.lastKnownHash = hash;
|
||||
box.history = [];
|
||||
var idxViewed = m.viewed.indexOf(hash);
|
||||
if (idxViewed !== -1) { m.viewed.splice(idxViewed, 1); }
|
||||
}
|
||||
}
|
||||
};
|
||||
cfg.onReady = function () {
|
||||
// Clean the "viewed" array: make sure all the "viewed" hashes are
|
||||
// in history
|
||||
var toClean = [];
|
||||
m.viewed.forEach(function (h, i) {
|
||||
if (box.history.indexOf(h) === -1) {
|
||||
toClean.push(i);
|
||||
}
|
||||
});
|
||||
for (var i = toClean.length-1; i>=0; i--) {
|
||||
m.viewed.splice(toClean[i], 1);
|
||||
}
|
||||
// Listen for changes in the "viewed" and lastKnownHash values
|
||||
var view = function (h) {
|
||||
delete box.content[h];
|
||||
ctx.emit('VIEWED', {
|
||||
type: type,
|
||||
hash: h
|
||||
}, ctx.clients);
|
||||
};
|
||||
ctx.store.proxy.on('change', ['mailboxes', type], function (o, n, p) {
|
||||
if (p[2] === 'lastKnownHash') {
|
||||
// Hide everything up to this hash
|
||||
var sliceIdx;
|
||||
box.history.some(function (h, i) {
|
||||
sliceIdx = i + 1;
|
||||
view(h);
|
||||
if (h === n) { return true; }
|
||||
});
|
||||
box.history = box.history.slice(sliceIdx);
|
||||
}
|
||||
if (p[2] === 'viewed') {
|
||||
// Hide this message
|
||||
view(n);
|
||||
}
|
||||
});
|
||||
// Continue
|
||||
onReady();
|
||||
};
|
||||
CpNetflux.start(cfg);
|
||||
};
|
||||
|
||||
|
||||
var subscribe = function (ctx, data, cId, cb) {
|
||||
// Get existing notifications
|
||||
Object.keys(ctx.boxes).forEach(function (type) {
|
||||
Object.keys(ctx.boxes[type].content).forEach(function (h) {
|
||||
var message = {
|
||||
msg: ctx.boxes[type].content[h],
|
||||
hash: h
|
||||
};
|
||||
showMessage(ctx, type, message, 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 (cfg, waitFor, emit) {
|
||||
var mailbox = {};
|
||||
var store = cfg.store;
|
||||
var ctx = {
|
||||
store: store,
|
||||
pinPads: cfg.pinPads,
|
||||
updateMetadata: cfg.updateMetadata,
|
||||
emit: emit,
|
||||
clients: [],
|
||||
boxes: {}
|
||||
};
|
||||
|
||||
var mailboxes = store.proxy.mailboxes = store.proxy.mailboxes || {};
|
||||
|
||||
initializeMailboxes(ctx, mailboxes);
|
||||
|
||||
Object.keys(mailboxes).forEach(function (key) {
|
||||
if (TYPES.indexOf(key) === -1) { return; }
|
||||
var m = mailboxes[key];
|
||||
|
||||
if (BLOCKING_TYPES.indexOf(key) === -1) {
|
||||
openChannel(ctx, key, m, function () {
|
||||
updateLastKnownHash(ctx, key);
|
||||
//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.dismiss = function (data, cb) {
|
||||
dismiss(ctx, data, '', cb);
|
||||
};
|
||||
|
||||
mailbox.sendTo = function (type, msg, user, cb) {
|
||||
sendTo(ctx, type, msg, user, cb);
|
||||
};
|
||||
|
||||
mailbox.removeClient = function (clientId) {
|
||||
// TODO
|
||||
//removeClient(ctx, clientId);
|
||||
};
|
||||
mailbox.leavePad = function (padChan) {
|
||||
// TODO
|
||||
//leaveChannel(ctx, padChan);
|
||||
removeClient(ctx, clientId);
|
||||
};
|
||||
mailbox.execCommand = function (clientId, obj, cb) {
|
||||
var cmd = obj.cmd;
|
||||
var data = obj.data;
|
||||
if (cmd === 'SUBSCRIBE') {
|
||||
return void subscribe(ctx, data, clientId, cb);
|
||||
}
|
||||
if (cmd === 'DISMISS') {
|
||||
return void dismiss(ctx, data, clientId, cb);
|
||||
}
|
||||
if (cmd === 'SENDTO') {
|
||||
return void sendTo(ctx, data.type, data.msg, data.user, cb);
|
||||
}
|
||||
};
|
||||
|
||||
return mailbox;
|
||||
|
||||
@@ -58,8 +58,8 @@ define([
|
||||
ADD_SHARED_FOLDER: Store.addSharedFolder,
|
||||
LOAD_SHARED_FOLDER: Store.loadSharedFolderAnon,
|
||||
// Messaging
|
||||
INVITE_FROM_USERLIST: Store.inviteFromUserlist,
|
||||
ADD_DIRECT_MESSAGE_HANDLERS: Store.addDirectMessageHandlers,
|
||||
ANSWER_FRIEND_REQUEST: Store.answerFriendRequest,
|
||||
SEND_FRIEND_REQUEST: Store.sendFriendRequest,
|
||||
// Chat
|
||||
CHAT_COMMAND: Store.messenger.execCommand,
|
||||
// OnlyOffice
|
||||
|
||||
Reference in New Issue
Block a user