More work on replayable errors

Expose a button that does that retries outgoing messages if possible.

// FREEBIE
This commit is contained in:
lilia 2015-10-02 18:31:07 -07:00
parent bc0c9bd133
commit a32f3ff1f6
8 changed files with 131 additions and 55 deletions

View File

@ -248,6 +248,10 @@
{{ #conflict }} {{ #conflict }}
<button class='conflict'><span>Verify</span></button> <button class='conflict'><span>Verify</span></button>
{{ /conflict }} {{ /conflict }}
{{ #retry }}
<button class='retry'><span>Retry</span></button>
<span class='error-message'>{{message}}</span>
{{ /retry }}
{{ #errors }} {{ #errors }}
<div> <div>
<span class='error-message'>{{message}}</span> <span class='error-message'>{{message}}</span>

View File

@ -7,9 +7,9 @@
var registeredFunctions = {}; var registeredFunctions = {};
var Type = { var Type = {
SEND_MESSAGE: 1, ENCRYPT_MESSAGE: 1,
INIT_SESSION: 2, INIT_SESSION: 2,
NETWORK_REQUEST: 3, TRANSMIT_MESSAGE: 3,
}; };
window.textsecure = window.textsecure || {}; window.textsecure = window.textsecure || {};
window.textsecure.replay = { window.textsecure.replay = {
@ -48,7 +48,7 @@
function OutgoingIdentityKeyError(number, message, timestamp, identityKey) { function OutgoingIdentityKeyError(number, message, timestamp, identityKey) {
ReplayableError.call(this, { ReplayableError.call(this, {
functionCode : Type.SEND_MESSAGE, functionCode : Type.ENCRYPT_MESSAGE,
args : [number, message, timestamp] args : [number, message, timestamp]
}); });
this.name = 'OutgoingIdentityKeyError'; this.name = 'OutgoingIdentityKeyError';
@ -59,23 +59,40 @@
OutgoingIdentityKeyError.prototype = new ReplayableError(); OutgoingIdentityKeyError.prototype = new ReplayableError();
OutgoingIdentityKeyError.prototype.constructor = OutgoingIdentityKeyError; OutgoingIdentityKeyError.prototype.constructor = OutgoingIdentityKeyError;
function NetworkError(number, jsonData, legacy, code) { function OutgoingMessageError(number, message, timestamp, httpError) {
ReplayableError.call(this, { ReplayableError.call(this, {
functionCode : Type.NETWORK_REQUEST, functionCode : Type.ENCRYPT_MESSAGE,
args : [number, message, timestamp]
});
this.name = 'OutgoingMessageError';
if (httpError) {
this.code = httpError.code;
this.message = httpError.message;
this.stack = httpError.stack;
}
}
OutgoingMessageError.prototype = new ReplayableError();
OutgoingMessageError.prototype.constructor = OutgoingMessageError;
function SendMessageNetworkError(number, jsonData, legacy, httpError) {
ReplayableError.call(this, {
functionCode : Type.TRANSMIT_MESSAGE,
args : [number, jsonData, legacy] args : [number, jsonData, legacy]
}); });
this.name = 'NetworkError'; this.name = 'SendMessageNetworkError';
this.message = 'Network request failed'
this.code = code;
this.number = number; this.number = number;
this.code = httpError.code;
this.message = httpError.message;
this.stack = httpError.stack;
} }
NetworkError.prototype = new ReplayableError(); SendMessageNetworkError.prototype = new ReplayableError();
NetworkError.prototype.constructor = NetworkError; SendMessageNetworkError.prototype.constructor = SendMessageNetworkError;
window.textsecure.NetworkError = NetworkError; window.textsecure.SendMessageNetworkError = SendMessageNetworkError;
window.textsecure.IncomingIdentityKeyError = IncomingIdentityKeyError; window.textsecure.IncomingIdentityKeyError = IncomingIdentityKeyError;
window.textsecure.OutgoingIdentityKeyError = OutgoingIdentityKeyError; window.textsecure.OutgoingIdentityKeyError = OutgoingIdentityKeyError;
window.textsecure.ReplayableError = ReplayableError; window.textsecure.ReplayableError = ReplayableError;
window.textsecure.OutgoingMessageError = OutgoingMessageError;
})(); })();
@ -39637,14 +39654,14 @@ MessageSender.prototype = {
}); });
})).then(function(jsonData) { })).then(function(jsonData) {
var legacy = (message instanceof textsecure.protobuf.DataMessage); var legacy = (message instanceof textsecure.protobuf.DataMessage);
return this.sendRequest(number, jsonData, legacy); return this.sendMessageRequest(number, jsonData, legacy);
}.bind(this)); }.bind(this));
}, },
sendRequest: function(number, jsonData, legacy) { sendMessageRequest: function(number, jsonData, legacy) {
return this.server.sendMessages(number, jsonData, legacy).catch(function(e) { return this.server.sendMessages(number, jsonData, legacy).catch(function(e) {
if (e.name === 'HTTPError' && e.code === -1) { if (e.name === 'HTTPError' && (e.code !== 409 && e.code !== 410)) {
throw new NetworkError(number, jsonData, legacy); throw new textsecure.SendMessageNetworkError(number, jsonData, legacy, e);
} }
throw e; throw e;
}); });
@ -39684,9 +39701,10 @@ MessageSender.prototype = {
}; };
var registerError = function(number, reason, error) { var registerError = function(number, reason, error) {
if (!error) { if (!error || error.name === 'HTTPError') {
error = new Error(reason); error = new textsecure.OutgoingMessageError(number, message.toArrayBuffer(), timestamp, error);
} }
error.number = number; error.number = number;
error.reason = reason; error.reason = reason;
errors[errors.length] = error; errors[errors.length] = error;
@ -40025,8 +40043,8 @@ window.textsecure = window.textsecure || {};
textsecure.MessageSender = function(url, username, password) { textsecure.MessageSender = function(url, username, password) {
var sender = new MessageSender(url, username, password); var sender = new MessageSender(url, username, password);
textsecure.replay.registerFunction(sender.tryMessageAgain.bind(sender), textsecure.replay.Type.SEND_MESSAGE); textsecure.replay.registerFunction(sender.tryMessageAgain.bind(sender), textsecure.replay.Type.ENCRYPT_MESSAGE);
textsecure.replay.registerFunction(sender.sendRequest.bind(sender), textsecure.replay.Type.NETWORK_REQUEST); textsecure.replay.registerFunction(sender.sendMessageRequest.bind(sender), textsecure.replay.Type.TRANSMIT_MESSAGE);
this.sendRequestGroupSyncMessage = sender.sendRequestGroupSyncMessage .bind(sender); this.sendRequestGroupSyncMessage = sender.sendRequestGroupSyncMessage .bind(sender);
this.sendRequestContactSyncMessage = sender.sendRequestContactSyncMessage.bind(sender); this.sendRequestContactSyncMessage = sender.sendRequestContactSyncMessage.bind(sender);

View File

@ -175,8 +175,18 @@
this.set({errors: errors}); this.set({errors: errors});
}, },
removeOutgoingErrors: function(number) {
var errors = _.partition(this.get('errors'), function(e) {
return e.number === number &&
(e.name === 'OutgoingMessageError' ||
e.name === 'SendMessageNetworkError');
});
this.set({errors: errors[1]});
return errors[0][0];
},
resend: function(number) { resend: function(number) {
var error = this.getSendError(number); var error = this.removeOutgoingErrors(number);
if (error) { if (error) {
var promise = new textsecure.ReplayableError(error).replay(); var promise = new textsecure.ReplayableError(error).replay();
this.send(promise); this.send(promise);

View File

@ -10,22 +10,33 @@
templateName: 'contact-detail', templateName: 'contact-detail',
initialize: function(options) { initialize: function(options) {
this.conflict = options.conflict; this.conflict = options.conflict;
this.retry = _.find(options.errors, function(e) {
return (e.name === 'OutgoingMessageError' ||
e.name === 'SendMessageNetworkError');
});
this.errors = _.reject(options.errors, function(e) { this.errors = _.reject(options.errors, function(e) {
return (e.name === 'IncomingIdentityKeyError' || return (e.name === 'IncomingIdentityKeyError' ||
e.name === 'OutgoingIdentityKeyError'); e.name === 'OutgoingIdentityKeyError' ||
e.name === 'OutgoingMessageError' ||
e.name === 'SendMessageNetworkError');
}); });
}, },
events: { events: {
'click .conflict': 'triggerConflict' 'click .conflict': 'triggerConflict',
'click .retry': 'triggerRetry'
}, },
triggerConflict: function() { triggerConflict: function() {
this.$el.trigger('conflict', {conflict: this.conflict}); this.$el.trigger('conflict', {conflict: this.conflict});
}, },
triggerRetry: function() {
this.$el.trigger('retry', {error: this.retry});
},
render_attributes: function() { render_attributes: function() {
return { return {
name : this.model.getTitle(), name : this.model.getTitle(),
avatar : this.model.getAvatar(), avatar : this.model.getAvatar(),
conflict : this.conflict, conflict : this.conflict,
retry : this.retry,
errors : this.errors errors : this.errors
}; };
} }
@ -43,7 +54,8 @@
}, },
events: { events: {
'click .back': 'goBack', 'click .back': 'goBack',
'conflict': 'conflictDialogue' 'conflict': 'conflictDialogue',
'retry': 'retryMessage',
}, },
goBack: function() { goBack: function() {
this.trigger('back'); this.trigger('back');
@ -82,6 +94,9 @@
this.render(); this.render();
}); });
}, },
retryMessage: function(e, data) {
this.model.resend(data.error.number);
},
renderContact: function(contact) { renderContact: function(contact) {
var v = new ContactView({ var v = new ContactView({
model: contact, model: contact,

View File

@ -6,9 +6,9 @@
var registeredFunctions = {}; var registeredFunctions = {};
var Type = { var Type = {
SEND_MESSAGE: 1, ENCRYPT_MESSAGE: 1,
INIT_SESSION: 2, INIT_SESSION: 2,
NETWORK_REQUEST: 3, TRANSMIT_MESSAGE: 3,
}; };
window.textsecure = window.textsecure || {}; window.textsecure = window.textsecure || {};
window.textsecure.replay = { window.textsecure.replay = {
@ -47,7 +47,7 @@
function OutgoingIdentityKeyError(number, message, timestamp, identityKey) { function OutgoingIdentityKeyError(number, message, timestamp, identityKey) {
ReplayableError.call(this, { ReplayableError.call(this, {
functionCode : Type.SEND_MESSAGE, functionCode : Type.ENCRYPT_MESSAGE,
args : [number, message, timestamp] args : [number, message, timestamp]
}); });
this.name = 'OutgoingIdentityKeyError'; this.name = 'OutgoingIdentityKeyError';
@ -58,22 +58,39 @@
OutgoingIdentityKeyError.prototype = new ReplayableError(); OutgoingIdentityKeyError.prototype = new ReplayableError();
OutgoingIdentityKeyError.prototype.constructor = OutgoingIdentityKeyError; OutgoingIdentityKeyError.prototype.constructor = OutgoingIdentityKeyError;
function NetworkError(number, jsonData, legacy, code) { function OutgoingMessageError(number, message, timestamp, httpError) {
ReplayableError.call(this, { ReplayableError.call(this, {
functionCode : Type.NETWORK_REQUEST, functionCode : Type.ENCRYPT_MESSAGE,
args : [number, message, timestamp]
});
this.name = 'OutgoingMessageError';
if (httpError) {
this.code = httpError.code;
this.message = httpError.message;
this.stack = httpError.stack;
}
}
OutgoingMessageError.prototype = new ReplayableError();
OutgoingMessageError.prototype.constructor = OutgoingMessageError;
function SendMessageNetworkError(number, jsonData, legacy, httpError) {
ReplayableError.call(this, {
functionCode : Type.TRANSMIT_MESSAGE,
args : [number, jsonData, legacy] args : [number, jsonData, legacy]
}); });
this.name = 'NetworkError'; this.name = 'SendMessageNetworkError';
this.message = 'Network request failed'
this.code = code;
this.number = number; this.number = number;
this.code = httpError.code;
this.message = httpError.message;
this.stack = httpError.stack;
} }
NetworkError.prototype = new ReplayableError(); SendMessageNetworkError.prototype = new ReplayableError();
NetworkError.prototype.constructor = NetworkError; SendMessageNetworkError.prototype.constructor = SendMessageNetworkError;
window.textsecure.NetworkError = NetworkError; window.textsecure.SendMessageNetworkError = SendMessageNetworkError;
window.textsecure.IncomingIdentityKeyError = IncomingIdentityKeyError; window.textsecure.IncomingIdentityKeyError = IncomingIdentityKeyError;
window.textsecure.OutgoingIdentityKeyError = OutgoingIdentityKeyError; window.textsecure.OutgoingIdentityKeyError = OutgoingIdentityKeyError;
window.textsecure.ReplayableError = ReplayableError; window.textsecure.ReplayableError = ReplayableError;
window.textsecure.OutgoingMessageError = OutgoingMessageError;
})(); })();

View File

@ -37,14 +37,14 @@ MessageSender.prototype = {
}); });
})).then(function(jsonData) { })).then(function(jsonData) {
var legacy = (message instanceof textsecure.protobuf.DataMessage); var legacy = (message instanceof textsecure.protobuf.DataMessage);
return this.sendRequest(number, jsonData, legacy); return this.sendMessageRequest(number, jsonData, legacy);
}.bind(this)); }.bind(this));
}, },
sendRequest: function(number, jsonData, legacy) { sendMessageRequest: function(number, jsonData, legacy) {
return this.server.sendMessages(number, jsonData, legacy).catch(function(e) { return this.server.sendMessages(number, jsonData, legacy).catch(function(e) {
if (e.name === 'HTTPError' && e.code === -1) { if (e.name === 'HTTPError' && (e.code !== 409 && e.code !== 410)) {
throw new NetworkError(number, jsonData, legacy); throw new textsecure.SendMessageNetworkError(number, jsonData, legacy, e);
} }
throw e; throw e;
}); });
@ -84,9 +84,10 @@ MessageSender.prototype = {
}; };
var registerError = function(number, reason, error) { var registerError = function(number, reason, error) {
if (!error) { if (!error || error.name === 'HTTPError') {
error = new Error(reason); error = new textsecure.OutgoingMessageError(number, message.toArrayBuffer(), timestamp, error);
} }
error.number = number; error.number = number;
error.reason = reason; error.reason = reason;
errors[errors.length] = error; errors[errors.length] = error;
@ -425,8 +426,8 @@ window.textsecure = window.textsecure || {};
textsecure.MessageSender = function(url, username, password) { textsecure.MessageSender = function(url, username, password) {
var sender = new MessageSender(url, username, password); var sender = new MessageSender(url, username, password);
textsecure.replay.registerFunction(sender.tryMessageAgain.bind(sender), textsecure.replay.Type.SEND_MESSAGE); textsecure.replay.registerFunction(sender.tryMessageAgain.bind(sender), textsecure.replay.Type.ENCRYPT_MESSAGE);
textsecure.replay.registerFunction(sender.sendRequest.bind(sender), textsecure.replay.Type.NETWORK_REQUEST); textsecure.replay.registerFunction(sender.sendMessageRequest.bind(sender), textsecure.replay.Type.TRANSMIT_MESSAGE);
this.sendRequestGroupSyncMessage = sender.sendRequestGroupSyncMessage .bind(sender); this.sendRequestGroupSyncMessage = sender.sendRequestGroupSyncMessage .bind(sender);
this.sendRequestContactSyncMessage = sender.sendRequestContactSyncMessage.bind(sender); this.sendRequestContactSyncMessage = sender.sendRequestContactSyncMessage.bind(sender);

View File

@ -61,13 +61,18 @@
} }
} }
.conflict { .contact-detail button {
border: none; border: none;
border-radius: 5px; border-radius: 5px;
color: white; color: white;
padding: 0.5em; padding: 0.5em;
font-weight: bold; font-weight: bold;
background: #d00; background: $blue;
span {
vertical-align: middle;
padding-left: 5px;
}
&:before { &:before {
content: ''; content: '';
@ -75,13 +80,15 @@
vertical-align: middle; vertical-align: middle;
width: 18px; width: 18px;
height: 18px; height: 18px;
background: url('/images/error.png') no-repeat center center; background: url('/images/refresh.png') no-repeat center center;
background-size: 100%; background-size: 100%;
} }
}
.conflict {
background: #d00;
span { &:before {
vertical-align: middle; background: url('/images/error.png') no-repeat center center;
padding-left: 5px;
} }
} }
} }

View File

@ -550,24 +550,28 @@ input.search {
font-weight: bold; font-weight: bold;
padding-right: 1em; padding-right: 1em;
vertical-align: top; } vertical-align: top; }
.message-detail .conflict { .message-detail .contact-detail button {
border: none; border: none;
border-radius: 5px; border-radius: 5px;
color: white; color: white;
padding: 0.5em; padding: 0.5em;
font-weight: bold; font-weight: bold;
background: #d00; } background: #2090ea; }
.message-detail .conflict:before { .message-detail .contact-detail button span {
vertical-align: middle;
padding-left: 5px; }
.message-detail .contact-detail button:before {
content: ''; content: '';
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
width: 18px; width: 18px;
height: 18px; height: 18px;
background: url("/images/error.png") no-repeat center center; background: url("/images/refresh.png") no-repeat center center;
background-size: 100%; } background-size: 100%; }
.message-detail .conflict span { .message-detail .conflict {
vertical-align: middle; background: #d00; }
padding-left: 5px; } .message-detail .conflict:before {
background: url("/images/error.png") no-repeat center center; }
.group-update { .group-update {
font-size: smaller; } font-size: smaller; }