Move handlePushMessageContent to message model
And retool message handling flow to helps us avoid instantiating duplicate message and conversation models.
This commit is contained in:
parent
897d391817
commit
9930937707
5 changed files with 98 additions and 112 deletions
105
js/background.js
105
js/background.js
|
@ -17,8 +17,6 @@
|
||||||
;(function() {
|
;(function() {
|
||||||
'use strict';
|
'use strict';
|
||||||
var socket;
|
var socket;
|
||||||
var conversations = new Whisper.ConversationCollection();
|
|
||||||
var messages = new Whisper.MessageCollection();
|
|
||||||
|
|
||||||
if (!localStorage.getItem('first_install_ran')) {
|
if (!localStorage.getItem('first_install_ran')) {
|
||||||
localStorage.setItem('first_install_ran', 1);
|
localStorage.setItem('first_install_ran', 1);
|
||||||
|
@ -80,13 +78,13 @@
|
||||||
var now = new Date().getTime();
|
var now = new Date().getTime();
|
||||||
var timestamp = pushMessage.timestamp.toNumber();
|
var timestamp = pushMessage.timestamp.toNumber();
|
||||||
|
|
||||||
var conversation = conversations.add({
|
var conversation = getConversation({
|
||||||
id : pushMessage.source,
|
id : pushMessage.source,
|
||||||
type : 'private'
|
type : 'private'
|
||||||
}, { merge : true } );
|
});
|
||||||
|
|
||||||
conversation.fetch().always(function() {
|
conversation.fetch().always(function() {
|
||||||
var message = messages.add({
|
var message = conversation.messageCollection.add({
|
||||||
source : pushMessage.source,
|
source : pushMessage.source,
|
||||||
sourceDevice : pushMessage.sourceDevice,
|
sourceDevice : pushMessage.sourceDevice,
|
||||||
relay : pushMessage.relay,
|
relay : pushMessage.relay,
|
||||||
|
@ -105,7 +103,7 @@
|
||||||
return new Promise(function(resolve) {
|
return new Promise(function(resolve) {
|
||||||
resolve(textsecure.protocol_wrapper.handleIncomingPushMessageProto(pushMessage).then(
|
resolve(textsecure.protocol_wrapper.handleIncomingPushMessageProto(pushMessage).then(
|
||||||
function(pushMessageContent) {
|
function(pushMessageContent) {
|
||||||
handlePushMessageContent(pushMessageContent, message);
|
message.handlePushMessageContent(pushMessageContent);
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
}).catch(function(e) {
|
}).catch(function(e) {
|
||||||
|
@ -129,101 +127,6 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
extension.on('message:decrypted', function(options) {
|
|
||||||
var message = messages.add({id: options.message_id});
|
|
||||||
message.fetch().then(function() {
|
|
||||||
var pushMessageContent = handlePushMessageContent(
|
|
||||||
new textsecure.protobuf.PushMessageContent(options.data),
|
|
||||||
message
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function getConversationId(pushMessageContent) {
|
|
||||||
if (pushMessageContent.sync) {
|
|
||||||
return pushMessageContent.sync.destination;
|
|
||||||
} else if (pushMessageContent.group) {
|
|
||||||
return pushMessageContent.group.id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handlePushMessageContent(pushMessageContent, message) {
|
|
||||||
// This function can be called from the background script on an
|
|
||||||
// incoming message or from the frontend after the user accepts an
|
|
||||||
// identity key change.
|
|
||||||
var source = message.get('source');
|
|
||||||
var timestamp = message.get('sent_at');
|
|
||||||
return textsecure.processDecrypted(pushMessageContent, source).then(function(pushMessageContent) {
|
|
||||||
var type = 'incoming';
|
|
||||||
if (pushMessageContent.sync) {
|
|
||||||
type = 'outgoing';
|
|
||||||
timestamp = pushMessageContent.sync.timestamp;
|
|
||||||
}
|
|
||||||
var now = new Date().getTime();
|
|
||||||
|
|
||||||
var conversationId = getConversationId(pushMessageContent) || source;
|
|
||||||
var conversation = new Whisper.Conversation({id: conversationId});
|
|
||||||
var attributes = {};
|
|
||||||
conversation.fetch().always(function() {
|
|
||||||
if (pushMessageContent.group) {
|
|
||||||
var group_update = {};
|
|
||||||
if (pushMessageContent.group.type === textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE) {
|
|
||||||
attributes = {
|
|
||||||
type : 'group',
|
|
||||||
groupId : pushMessageContent.group.id,
|
|
||||||
name : pushMessageContent.group.name,
|
|
||||||
avatar : pushMessageContent.group.avatar,
|
|
||||||
members : pushMessageContent.group.members,
|
|
||||||
};
|
|
||||||
group_update = conversation.changedAttributes(_.pick(pushMessageContent.group, 'name', 'avatar'));
|
|
||||||
var difference = _.difference(pushMessageContent.group.members, conversation.get('members'));
|
|
||||||
if (difference.length > 0) {
|
|
||||||
group_update.joined = difference;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (pushMessageContent.group.type === textsecure.protobuf.PushMessageContent.GroupContext.Type.QUIT) {
|
|
||||||
group_update = { left: source };
|
|
||||||
attributes = { members: _.without(conversation.get('members'), source) };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_.keys(group_update).length > 0) {
|
|
||||||
message.set({group_update: group_update});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
attributes.active_at = now;
|
|
||||||
if (type === 'incoming') {
|
|
||||||
attributes.unreadCount = conversation.get('unreadCount') + 1;
|
|
||||||
}
|
|
||||||
conversation.set(attributes);
|
|
||||||
|
|
||||||
message.set({
|
|
||||||
body : pushMessageContent.body,
|
|
||||||
conversationId : conversation.id,
|
|
||||||
attachments : pushMessageContent.attachments,
|
|
||||||
decrypted_at : now,
|
|
||||||
type : type,
|
|
||||||
sent_at : timestamp,
|
|
||||||
flags : pushMessageContent.flags,
|
|
||||||
errors : []
|
|
||||||
});
|
|
||||||
|
|
||||||
if (message.get('sent_at') > conversation.get('timestamp')) {
|
|
||||||
conversation.set({
|
|
||||||
timestamp: message.get('sent_at'),
|
|
||||||
lastMessage: message.get('body')
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
conversation.save().then(function() {
|
|
||||||
message.save().then(function() {
|
|
||||||
extension.trigger('message', message); // notify frontend listeners
|
|
||||||
notifyConversation(message);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function onDeliveryReceipt(pushMessage) {
|
function onDeliveryReceipt(pushMessage) {
|
||||||
var timestamp = pushMessage.timestamp.toNumber();
|
var timestamp = pushMessage.timestamp.toNumber();
|
||||||
var messages = new Whisper.MessageCollection();
|
var messages = new Whisper.MessageCollection();
|
||||||
|
|
|
@ -77,10 +77,7 @@
|
||||||
var promise = new textsecure.ReplayableError(error).replay();
|
var promise = new textsecure.ReplayableError(error).replay();
|
||||||
if (this.isIncoming()) {
|
if (this.isIncoming()) {
|
||||||
promise.then(function(pushMessageContent) {
|
promise.then(function(pushMessageContent) {
|
||||||
extension.trigger('message:decrypted', {
|
this.handlePushMessageContent(pushMessageContent);
|
||||||
message_id: this.id,
|
|
||||||
data: pushMessageContent
|
|
||||||
});
|
|
||||||
this.save('errors', []);
|
this.save('errors', []);
|
||||||
}.bind(this)).catch(function(e) {
|
}.bind(this)).catch(function(e) {
|
||||||
//this.save('errors', [_.pick(e, ['name', 'message'])]);
|
//this.save('errors', [_.pick(e, ['name', 'message'])]);
|
||||||
|
@ -98,7 +95,90 @@
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
handlePushMessageContent: function(pushMessageContent) {
|
||||||
|
// This function can be called from the background script on an
|
||||||
|
// incoming message or from the frontend after the user accepts an
|
||||||
|
// identity key change.
|
||||||
|
var message = this;
|
||||||
|
var source = message.get('source');
|
||||||
|
var timestamp = message.get('sent_at');
|
||||||
|
return textsecure.processDecrypted(pushMessageContent, source).then(function(pushMessageContent) {
|
||||||
|
var type = 'incoming';
|
||||||
|
if (pushMessageContent.sync) {
|
||||||
|
type = 'outgoing';
|
||||||
|
timestamp = pushMessageContent.sync.timestamp;
|
||||||
|
}
|
||||||
|
var now = new Date().getTime();
|
||||||
|
|
||||||
|
var conversationId = source;
|
||||||
|
if (pushMessageContent.sync) {
|
||||||
|
conversationId = pushMessageContent.sync.destination;
|
||||||
|
} else if (pushMessageContent.group) {
|
||||||
|
conversationId = pushMessageContent.group.id;
|
||||||
|
}
|
||||||
|
var conversation = new Whisper.Conversation({id: conversationId});
|
||||||
|
var attributes = {};
|
||||||
|
conversation.fetch().always(function() {
|
||||||
|
if (pushMessageContent.group) {
|
||||||
|
var group_update = {};
|
||||||
|
if (pushMessageContent.group.type === textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE) {
|
||||||
|
attributes = {
|
||||||
|
type : 'group',
|
||||||
|
groupId : pushMessageContent.group.id,
|
||||||
|
name : pushMessageContent.group.name,
|
||||||
|
avatar : pushMessageContent.group.avatar,
|
||||||
|
members : pushMessageContent.group.members,
|
||||||
|
};
|
||||||
|
group_update = conversation.changedAttributes(_.pick(pushMessageContent.group, 'name', 'avatar'));
|
||||||
|
var difference = _.difference(pushMessageContent.group.members, conversation.get('members'));
|
||||||
|
if (difference.length > 0) {
|
||||||
|
group_update.joined = difference;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (pushMessageContent.group.type === textsecure.protobuf.PushMessageContent.GroupContext.Type.QUIT) {
|
||||||
|
group_update = { left: source };
|
||||||
|
attributes = { members: _.without(conversation.get('members'), source) };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_.keys(group_update).length > 0) {
|
||||||
|
message.set({group_update: group_update});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
attributes.active_at = now;
|
||||||
|
if (type === 'incoming') {
|
||||||
|
attributes.unreadCount = conversation.get('unreadCount') + 1;
|
||||||
|
}
|
||||||
|
conversation.set(attributes);
|
||||||
|
|
||||||
|
message.set({
|
||||||
|
body : pushMessageContent.body,
|
||||||
|
conversationId : conversation.id,
|
||||||
|
attachments : pushMessageContent.attachments,
|
||||||
|
decrypted_at : now,
|
||||||
|
type : type,
|
||||||
|
sent_at : timestamp,
|
||||||
|
flags : pushMessageContent.flags,
|
||||||
|
errors : []
|
||||||
|
});
|
||||||
|
|
||||||
|
if (message.get('sent_at') > conversation.get('timestamp')) {
|
||||||
|
conversation.set({
|
||||||
|
timestamp: message.get('sent_at'),
|
||||||
|
lastMessage: message.get('body')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
conversation.save().then(function() {
|
||||||
|
message.save().then(function() {
|
||||||
|
extension.trigger('message', message); // notify frontend listeners
|
||||||
|
notifyConversation(message);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Whisper.MessageCollection = Backbone.Collection.extend({
|
Whisper.MessageCollection = Backbone.Collection.extend({
|
||||||
|
|
|
@ -41,15 +41,15 @@
|
||||||
windowMap.remove('windowId', windowId);
|
windowMap.remove('windowId', windowId);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getConversation(modelId) {
|
window.getConversation = function(attrs) {
|
||||||
var conversation = window.inbox.get(modelId) || {id: modelId};
|
var conversation = window.inbox.get(attrs.id) || attrs;
|
||||||
conversation = conversations.add(conversation);
|
conversation = conversations.add(attrs);
|
||||||
return conversation;
|
return conversation;
|
||||||
}
|
};
|
||||||
|
|
||||||
window.notifyConversation = function(message) {
|
window.notifyConversation = function(message) {
|
||||||
if (Whisper.Notifications.isEnabled()) {
|
if (Whisper.Notifications.isEnabled()) {
|
||||||
var conversation = getConversation(message.get('conversationId'));
|
var conversation = getConversation({id: message.get('conversationId')});
|
||||||
conversation.fetch().then(function() {
|
conversation.fetch().then(function() {
|
||||||
var notification = new Notification(conversation.getTitle(), {
|
var notification = new Notification(conversation.getTitle(), {
|
||||||
body: message.get('body'),
|
body: message.get('body'),
|
||||||
|
@ -60,13 +60,14 @@
|
||||||
openConversation(conversation.id);
|
openConversation(conversation.id);
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
conversation.fetchMessages();
|
||||||
} else {
|
} else {
|
||||||
openConversation(message.get('conversationId'));
|
openConversation(message.get('conversationId'));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
window.openConversation = function openConversation (modelId) {
|
window.openConversation = function openConversation (modelId) {
|
||||||
var conversation = getConversation(modelId);
|
var conversation = getConversation({id: modelId});
|
||||||
conversation.fetch().then(function() {
|
conversation.fetch().then(function() {
|
||||||
conversation.fetchContacts();
|
conversation.fetchContacts();
|
||||||
});
|
});
|
||||||
|
|
|
@ -46,6 +46,8 @@
|
||||||
initialize: function(options) {
|
initialize: function(options) {
|
||||||
this.view = new Whisper.MessageView({model: this.model});
|
this.view = new Whisper.MessageView({model: this.model});
|
||||||
this.conversation = options.conversation;
|
this.conversation = options.conversation;
|
||||||
|
|
||||||
|
this.listenTo(this.model, 'change', this.render);
|
||||||
},
|
},
|
||||||
events: {
|
events: {
|
||||||
'click .back': 'goBack',
|
'click .back': 'goBack',
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
tagName: 'div',
|
tagName: 'div',
|
||||||
template: $('#message').html(),
|
template: $('#message').html(),
|
||||||
initialize: function() {
|
initialize: function() {
|
||||||
this.listenTo(this.model, 'change:body', this.render);
|
this.listenTo(this.model, 'change:body change:errors', this.render);
|
||||||
this.listenTo(this.model, 'change:delivered', this.renderDelivered);
|
this.listenTo(this.model, 'change:delivered', this.renderDelivered);
|
||||||
},
|
},
|
||||||
className: function() {
|
className: function() {
|
||||||
|
|
Loading…
Reference in a new issue