mirror of https://github.com/zulip/zulip.git
sending messages: Extract sent_messages.js.
This commit extract send_messages.js to clean up code related to the following things: * sending data to /json/report_send_time * restarting the event loop if events don't arrive on time The code related to /json/report changes the following ways: * We track the state almost completely in the new send_messages.js module, with other modules just making one-line calls. * We no longer send "displayed" times to the servers, since we were kind of lying about them anyway. * We now explicitly track the state of each single sent message in its own object. * We now look up data related to the messages by local_id, instead of message_id. The problem with message_id was that is was mutable. Now we use local_id, and we extend the local_id concept to messages that don't get rendered client side. We no longer need to react to the 'message_id_changed' event to change our hash key. * The code used to live in many places: * various big chunks were scattered among compose.js, and those were all moved or reduced to one-line calls into the new module * echo.js continues to make basically one-line calls, but it no longer calls compose.report_as_received(), nor does it set the "start" time. * message_util.js used to report received events, but only when they finally got drawn in the home view; this code is gone now The code related to restarting the event loop if events don't arrive changes as follows: * The timer now gets set up from within send_messages.message_state.report_server_ack, where we can easily inspect the current state of the possibly-still-in-flight message. * The code to confirm that an event was received happens now in server_events.js, rather than later, so that we don't falsely blame the event loop for a downstream bug. (Plus it's easier to just do it one place.) This change removes a fair amount of code from our node tests. Some of the removal is good stuff related to us completing killing off unnecessary code. Other removals are more expediency-driven, and we should make another sweep at ramping up our coverage on compose.js, with possibly a little more mocking of the new `send_messages` code layer, since it's now abstracted better. There is also some minor cleanup to echo.resend_message() in this commit. See #5968 for a detailed breakdown of the changes.
This commit is contained in:
parent
30361f50f8
commit
3f06f28ad7
|
@ -57,6 +57,7 @@
|
||||||
"typing_events": false,
|
"typing_events": false,
|
||||||
"typing_data": false,
|
"typing_data": false,
|
||||||
"typing_status": false,
|
"typing_status": false,
|
||||||
|
"sent_messages": false,
|
||||||
"compose": false,
|
"compose": false,
|
||||||
"compose_actions": false,
|
"compose_actions": false,
|
||||||
"compose_state": false,
|
"compose_state": false,
|
||||||
|
|
|
@ -34,6 +34,11 @@ set_global('stream_edit', {});
|
||||||
set_global('markdown', {});
|
set_global('markdown', {});
|
||||||
set_global('loading', {});
|
set_global('loading', {});
|
||||||
|
|
||||||
|
set_global('sent_messages', {
|
||||||
|
start_tracking_message: noop,
|
||||||
|
report_server_ack: noop,
|
||||||
|
});
|
||||||
|
|
||||||
// Setting these up so that we can test that links to uploads within messages are
|
// Setting these up so that we can test that links to uploads within messages are
|
||||||
// automatically converted to server relative links.
|
// automatically converted to server relative links.
|
||||||
global.document.location.protocol = 'https:';
|
global.document.location.protocol = 'https:';
|
||||||
|
@ -261,72 +266,23 @@ people.add(bob);
|
||||||
$("#send-status").show();
|
$("#send-status").show();
|
||||||
$("#compose-send-button").attr('disabled', 'disabled');
|
$("#compose-send-button").attr('disabled', 'disabled');
|
||||||
$("#sending-indicator").show();
|
$("#sending-indicator").show();
|
||||||
var set_timeout_called = false;
|
|
||||||
global.patch_builtin('setTimeout', function (func, delay) {
|
|
||||||
assert.equal(delay, 5000);
|
|
||||||
func();
|
|
||||||
set_timeout_called = true;
|
|
||||||
});
|
|
||||||
var server_events_triggered;
|
|
||||||
global.server_events = {
|
|
||||||
restart_get_events: function () {
|
|
||||||
server_events_triggered = true;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
var reify_message_id_checked;
|
var reify_message_id_checked;
|
||||||
echo.reify_message_id = function (local_id, message_id) {
|
echo.reify_message_id = function (local_id, message_id) {
|
||||||
assert.equal(local_id, 1001);
|
assert.equal(local_id, 1001);
|
||||||
assert.equal(message_id, 12);
|
assert.equal(message_id, 12);
|
||||||
reify_message_id_checked = true;
|
reify_message_id_checked = true;
|
||||||
};
|
};
|
||||||
var test_date = 'Wed Jun 28 2017 22:12:48 GMT+0000 (UTC)';
|
|
||||||
compose.send_message_success(1001, 12, new Date(test_date), false);
|
compose.send_message_success(1001, 12, false);
|
||||||
|
|
||||||
assert.equal($("#new_message_content").val(), '');
|
assert.equal($("#new_message_content").val(), '');
|
||||||
assert($("#new_message_content").is_focused());
|
assert($("#new_message_content").is_focused());
|
||||||
assert(!$("#send-status").visible());
|
assert(!$("#send-status").visible());
|
||||||
assert.equal($("#compose-send-button").prop('disabled'), false);
|
assert.equal($("#compose-send-button").prop('disabled'), false);
|
||||||
assert(!$("#sending-indicator").visible());
|
assert(!$("#sending-indicator").visible());
|
||||||
assert.equal(_.keys(compose.send_times_data).length, 1);
|
|
||||||
assert.equal(compose.send_times_data[12].start.getTime(), new Date(test_date).getTime());
|
|
||||||
assert(!compose.send_times_data[12].locally_echoed);
|
|
||||||
assert(reify_message_id_checked);
|
assert(reify_message_id_checked);
|
||||||
assert(server_events_triggered);
|
|
||||||
assert(set_timeout_called);
|
|
||||||
}());
|
|
||||||
|
|
||||||
(function test_mark_rendered_content_disparity() {
|
|
||||||
compose.mark_rendered_content_disparity(13, true);
|
|
||||||
assert.deepEqual(compose.send_times_data[13], { rendered_content_disparity: true });
|
|
||||||
}());
|
|
||||||
|
|
||||||
(function test_report_as_received() {
|
|
||||||
var msg = {
|
|
||||||
id: 12,
|
|
||||||
sent_by_me: true,
|
|
||||||
};
|
|
||||||
var set_timeout_called = false;
|
|
||||||
global.patch_builtin('setTimeout', function (func, delay) {
|
|
||||||
assert.equal(delay, 0);
|
|
||||||
func();
|
|
||||||
set_timeout_called = true;
|
|
||||||
});
|
|
||||||
compose.send_times_data[12].locally_echoed = true;
|
|
||||||
channel.post = function (payload) {
|
|
||||||
assert.equal(payload.url, '/json/report_send_time');
|
|
||||||
assert.equal(typeof(payload.data.time), 'string');
|
|
||||||
assert(payload.data.locally_echoed);
|
|
||||||
assert(!payload.data.rendered_content_disparity);
|
|
||||||
};
|
|
||||||
compose.report_as_received(msg);
|
|
||||||
assert.equal(typeof(compose.send_times_data[12].received), 'object');
|
|
||||||
assert.equal(typeof(compose.send_times_data[12].displayed), 'object');
|
|
||||||
assert(set_timeout_called);
|
|
||||||
|
|
||||||
delete compose.send_times_data[13];
|
|
||||||
msg.id = 13;
|
|
||||||
compose.report_as_received(msg);
|
|
||||||
assert.equal(typeof(compose.send_times_data[13].received), 'object');
|
|
||||||
assert.equal(typeof(compose.send_times_data[13].displayed), 'object');
|
|
||||||
}());
|
}());
|
||||||
|
|
||||||
(function test_send_message() {
|
(function test_send_message() {
|
||||||
|
@ -337,7 +293,6 @@ people.add(bob);
|
||||||
stub_state.local_id_counter = 0;
|
stub_state.local_id_counter = 0;
|
||||||
stub_state.send_msg_ajax_post_called = 0;
|
stub_state.send_msg_ajax_post_called = 0;
|
||||||
stub_state.get_events_running_called = 0;
|
stub_state.get_events_running_called = 0;
|
||||||
stub_state.server_events_triggered = 0;
|
|
||||||
stub_state.reify_message_id_checked = 0;
|
stub_state.reify_message_id_checked = 0;
|
||||||
return stub_state;
|
return stub_state;
|
||||||
}
|
}
|
||||||
|
@ -346,9 +301,6 @@ people.add(bob);
|
||||||
func();
|
func();
|
||||||
});
|
});
|
||||||
global.server_events = {
|
global.server_events = {
|
||||||
restart_get_events: function () {
|
|
||||||
stub_state.server_events_triggered += 1;
|
|
||||||
},
|
|
||||||
assert_get_events_running: function () {
|
assert_get_events_running: function () {
|
||||||
stub_state.get_events_running_called += 1;
|
stub_state.get_events_running_called += 1;
|
||||||
},
|
},
|
||||||
|
@ -392,7 +344,7 @@ people.add(bob);
|
||||||
assert.equal(typeof(message_id), 'number');
|
assert.equal(typeof(message_id), 'number');
|
||||||
stub_state.reify_message_id_checked += 1;
|
stub_state.reify_message_id_checked += 1;
|
||||||
};
|
};
|
||||||
compose.send_times_data = {};
|
|
||||||
// Setting message content with a host server link and we will assert
|
// Setting message content with a host server link and we will assert
|
||||||
// later that this has been converted to a relative link.
|
// later that this has been converted to a relative link.
|
||||||
$("#new_message_content").val('[foobar]' +
|
$("#new_message_content").val('[foobar]' +
|
||||||
|
@ -409,10 +361,8 @@ people.add(bob);
|
||||||
get_events_running_called: 1,
|
get_events_running_called: 1,
|
||||||
reify_message_id_checked: 1,
|
reify_message_id_checked: 1,
|
||||||
send_msg_ajax_post_called: 1,
|
send_msg_ajax_post_called: 1,
|
||||||
server_events_triggered: 1,
|
|
||||||
};
|
};
|
||||||
assert.deepEqual(stub_state, state);
|
assert.deepEqual(stub_state, state);
|
||||||
assert.equal(_.keys(compose.send_times_data).length, 1);
|
|
||||||
assert.equal($("#new_message_content").val(), '');
|
assert.equal($("#new_message_content").val(), '');
|
||||||
assert($("#new_message_content").is_focused());
|
assert($("#new_message_content").is_focused());
|
||||||
assert(!$("#send-status").visible());
|
assert(!$("#send-status").visible());
|
||||||
|
@ -444,10 +394,8 @@ people.add(bob);
|
||||||
get_events_running_called: 1,
|
get_events_running_called: 1,
|
||||||
reify_message_id_checked: 0,
|
reify_message_id_checked: 0,
|
||||||
send_msg_ajax_post_called: 1,
|
send_msg_ajax_post_called: 1,
|
||||||
server_events_triggered: 0,
|
|
||||||
};
|
};
|
||||||
assert.deepEqual(stub_state, state);
|
assert.deepEqual(stub_state, state);
|
||||||
assert.equal(_.keys(compose.send_times_data).length, 1);
|
|
||||||
assert(server_error_triggered);
|
assert(server_error_triggered);
|
||||||
assert(reload_initiate_triggered);
|
assert(reload_initiate_triggered);
|
||||||
}());
|
}());
|
||||||
|
@ -485,10 +433,8 @@ people.add(bob);
|
||||||
get_events_running_called: 1,
|
get_events_running_called: 1,
|
||||||
reify_message_id_checked: 0,
|
reify_message_id_checked: 0,
|
||||||
send_msg_ajax_post_called: 1,
|
send_msg_ajax_post_called: 1,
|
||||||
server_events_triggered: 0,
|
|
||||||
};
|
};
|
||||||
assert.deepEqual(stub_state, state);
|
assert.deepEqual(stub_state, state);
|
||||||
assert.equal(_.keys(compose.send_times_data).length, 1);
|
|
||||||
assert(server_error_triggered);
|
assert(server_error_triggered);
|
||||||
assert(!reload_initiate_triggered);
|
assert(!reload_initiate_triggered);
|
||||||
assert(xhr_error_msg_checked);
|
assert(xhr_error_msg_checked);
|
||||||
|
@ -511,6 +457,10 @@ people.add(bob);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
sent_messages.get_new_local_id = function () {
|
||||||
|
return 'loc-55';
|
||||||
|
};
|
||||||
|
|
||||||
compose.send_message();
|
compose.send_message();
|
||||||
|
|
||||||
var state = {
|
var state = {
|
||||||
|
@ -518,10 +468,8 @@ people.add(bob);
|
||||||
get_events_running_called: 1,
|
get_events_running_called: 1,
|
||||||
reify_message_id_checked: 0,
|
reify_message_id_checked: 0,
|
||||||
send_msg_ajax_post_called: 1,
|
send_msg_ajax_post_called: 1,
|
||||||
server_events_triggered: 0,
|
|
||||||
};
|
};
|
||||||
assert.deepEqual(stub_state, state);
|
assert.deepEqual(stub_state, state);
|
||||||
assert.equal(_.keys(compose.send_times_data).length, 1);
|
|
||||||
assert(server_error_triggered);
|
assert(server_error_triggered);
|
||||||
assert(!reload_initiate_triggered);
|
assert(!reload_initiate_triggered);
|
||||||
assert(xhr_error_msg_checked);
|
assert(xhr_error_msg_checked);
|
||||||
|
@ -792,9 +740,10 @@ function test_with_mock_socket(test_params) {
|
||||||
// socket_user_agent field will be added.
|
// socket_user_agent field will be added.
|
||||||
var request = {foo: 'bar'};
|
var request = {foo: 'bar'};
|
||||||
|
|
||||||
// Our success function gets passed all the way through to
|
var success_func_checked = false;
|
||||||
// socket.send, so we can just use a stub to test that.
|
var success = function () {
|
||||||
var success = 'success-function-stub';
|
success_func_checked = true;
|
||||||
|
};
|
||||||
|
|
||||||
// Our error function gets wrapped, so we set up a real
|
// Our error function gets wrapped, so we set up a real
|
||||||
// function to test the wrapping mechanism.
|
// function to test the wrapping mechanism.
|
||||||
|
@ -818,8 +767,8 @@ function test_with_mock_socket(test_params) {
|
||||||
socket_user_agent: 'unittest_transmit_message',
|
socket_user_agent: 'unittest_transmit_message',
|
||||||
});
|
});
|
||||||
|
|
||||||
// Our success function never gets wrapped.
|
send_args.success({});
|
||||||
assert.equal(send_args.success, success);
|
assert(success_func_checked);
|
||||||
|
|
||||||
// Our error function does get wrapped, so we test by
|
// Our error function does get wrapped, so we test by
|
||||||
// using socket.send's error callback, which should
|
// using socket.send's error callback, which should
|
||||||
|
@ -1258,25 +1207,6 @@ function test_with_mock_socket(test_params) {
|
||||||
assert($("#markdown_preview").visible());
|
assert($("#markdown_preview").visible());
|
||||||
}());
|
}());
|
||||||
|
|
||||||
(function test_message_id_changed_document() {
|
|
||||||
var handler = $(document).get_on_handler('message_id_changed');
|
|
||||||
compose.send_times_data = {
|
|
||||||
1031: {
|
|
||||||
data: 'Test data!',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
event.old_id = 1031;
|
|
||||||
event.new_id = 1045;
|
|
||||||
|
|
||||||
handler(event);
|
|
||||||
|
|
||||||
var send_times_data = {
|
|
||||||
1045: {
|
|
||||||
data: 'Test data!',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
assert.deepEqual(compose.send_times_data, send_times_data);
|
|
||||||
}());
|
|
||||||
}());
|
}());
|
||||||
|
|
||||||
(function test_upload_started() {
|
(function test_upload_started() {
|
||||||
|
|
|
@ -179,20 +179,6 @@ function send_message_ajax(request, success, error) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function report_send_time(send_time, receive_time, display_time, locally_echoed, rendered_changed) {
|
|
||||||
var data = {time: send_time.toString(),
|
|
||||||
received: receive_time.toString(),
|
|
||||||
displayed: display_time.toString(),
|
|
||||||
locally_echoed: locally_echoed};
|
|
||||||
if (locally_echoed) {
|
|
||||||
data.rendered_content_disparity = rendered_changed;
|
|
||||||
}
|
|
||||||
channel.post({
|
|
||||||
url: '/json/report_send_time',
|
|
||||||
data: data,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var socket;
|
var socket;
|
||||||
if (page_params.use_websockets) {
|
if (page_params.use_websockets) {
|
||||||
socket = new Socket("/sockjs");
|
socket = new Socket("/sockjs");
|
||||||
|
@ -211,61 +197,6 @@ function send_message_socket(request, success, error) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.send_times_data = {};
|
|
||||||
function maybe_report_send_times(message_id) {
|
|
||||||
var data = exports.send_times_data[message_id];
|
|
||||||
if (data.send_finished === undefined || data.received === undefined ||
|
|
||||||
data.displayed === undefined) {
|
|
||||||
// We report the data once we have both the send and receive times
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
report_send_time(data.send_finished - data.start,
|
|
||||||
data.received - data.start,
|
|
||||||
data.displayed - data.start,
|
|
||||||
data.locally_echoed,
|
|
||||||
data.rendered_content_disparity || false);
|
|
||||||
}
|
|
||||||
|
|
||||||
function mark_end_to_end_receive_time(message_id) {
|
|
||||||
if (exports.send_times_data[message_id] === undefined) {
|
|
||||||
exports.send_times_data[message_id] = {};
|
|
||||||
}
|
|
||||||
exports.send_times_data[message_id].received = new Date();
|
|
||||||
maybe_report_send_times(message_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
function mark_end_to_end_display_time(message_id) {
|
|
||||||
exports.send_times_data[message_id].displayed = new Date();
|
|
||||||
maybe_report_send_times(message_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.mark_rendered_content_disparity = function (message_id, changed) {
|
|
||||||
if (exports.send_times_data[message_id] === undefined) {
|
|
||||||
exports.send_times_data[message_id] = {};
|
|
||||||
}
|
|
||||||
exports.send_times_data[message_id].rendered_content_disparity = changed;
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.report_as_received = function report_as_received(message) {
|
|
||||||
if (message.sent_by_me) {
|
|
||||||
mark_end_to_end_receive_time(message.id);
|
|
||||||
setTimeout(function () {
|
|
||||||
mark_end_to_end_display_time(message.id);
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function process_send_time(message_id, start_time, locally_echoed) {
|
|
||||||
var send_finished = new Date();
|
|
||||||
if (exports.send_times_data[message_id] === undefined) {
|
|
||||||
exports.send_times_data[message_id] = {};
|
|
||||||
}
|
|
||||||
exports.send_times_data[message_id].start = start_time;
|
|
||||||
exports.send_times_data[message_id].send_finished = send_finished;
|
|
||||||
exports.send_times_data[message_id].locally_echoed = locally_echoed;
|
|
||||||
maybe_report_send_times(message_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
function clear_compose_box() {
|
function clear_compose_box() {
|
||||||
$("#new_message_content").val('').focus();
|
$("#new_message_content").val('').focus();
|
||||||
drafts.delete_draft_after_send();
|
drafts.delete_draft_after_send();
|
||||||
|
@ -276,25 +207,25 @@ function clear_compose_box() {
|
||||||
resize.resize_bottom_whitespace();
|
resize.resize_bottom_whitespace();
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.send_message_success = function (local_id, message_id, start_time, locally_echoed) {
|
exports.send_message_success = function (local_id, message_id, locally_echoed) {
|
||||||
if (!locally_echoed) {
|
if (!locally_echoed) {
|
||||||
clear_compose_box();
|
clear_compose_box();
|
||||||
}
|
}
|
||||||
|
|
||||||
process_send_time(message_id, start_time, locally_echoed);
|
|
||||||
|
|
||||||
echo.reify_message_id(local_id, message_id);
|
echo.reify_message_id(local_id, message_id);
|
||||||
|
|
||||||
setTimeout(function () {
|
|
||||||
if (exports.send_times_data[message_id].received === undefined) {
|
|
||||||
blueslip.log("Restarting get_events due to delayed receipt of sent message " + message_id);
|
|
||||||
server_events.restart_get_events();
|
|
||||||
}
|
|
||||||
}, 5000);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.transmit_message = function (request, success, error) {
|
exports.transmit_message = function (request, on_success, error) {
|
||||||
delete exports.send_times_data[request.id];
|
|
||||||
|
function success(data) {
|
||||||
|
// Call back to our callers to do things like closing the compose
|
||||||
|
// box and turning off spinners and reifying locally echoed messages.
|
||||||
|
on_success(data);
|
||||||
|
|
||||||
|
// Once everything is done, get ready to report times to the server.
|
||||||
|
sent_messages.report_server_ack(request.local_id);
|
||||||
|
}
|
||||||
|
|
||||||
if (page_params.use_websockets) {
|
if (page_params.use_websockets) {
|
||||||
send_message_socket(request, success, error);
|
send_message_socket(request, success, error);
|
||||||
} else {
|
} else {
|
||||||
|
@ -313,27 +244,41 @@ exports.send_message = function send_message(request) {
|
||||||
request.to = JSON.stringify([request.to]);
|
request.to = JSON.stringify([request.to]);
|
||||||
}
|
}
|
||||||
|
|
||||||
var start_time = new Date();
|
|
||||||
var local_id;
|
var local_id;
|
||||||
|
var locally_echoed;
|
||||||
|
|
||||||
local_id = echo.try_deliver_locally(request);
|
local_id = echo.try_deliver_locally(request);
|
||||||
if (local_id !== undefined) {
|
if (local_id) {
|
||||||
// We delivered this message locally
|
// We are rendering this message locally with an id
|
||||||
request.local_id = local_id;
|
// like 92l99.01 that corresponds to a reasonable
|
||||||
|
// approximation of the id we'll get from the server
|
||||||
|
// in terms of sorting messages.
|
||||||
|
locally_echoed = true;
|
||||||
|
} else {
|
||||||
|
// We are not rendering this message locally, but we
|
||||||
|
// track the message's life cycle with an id like
|
||||||
|
// loc-1, loc-2, loc-3,etc.
|
||||||
|
locally_echoed = false;
|
||||||
|
local_id = sent_messages.get_new_local_id();
|
||||||
}
|
}
|
||||||
|
|
||||||
var locally_echoed = local_id !== undefined;
|
request.local_id = local_id;
|
||||||
|
|
||||||
|
sent_messages.start_tracking_message({
|
||||||
|
local_id: local_id,
|
||||||
|
locally_echoed: locally_echoed,
|
||||||
|
});
|
||||||
|
|
||||||
request.locally_echoed = locally_echoed;
|
request.locally_echoed = locally_echoed;
|
||||||
|
|
||||||
function success(data) {
|
function success(data) {
|
||||||
exports.send_message_success(local_id, data.id, start_time, locally_echoed);
|
exports.send_message_success(local_id, data.id, locally_echoed);
|
||||||
}
|
}
|
||||||
|
|
||||||
function error(response) {
|
function error(response) {
|
||||||
// If we're not local echo'ing messages, or if this message was not
|
// If we're not local echo'ing messages, or if this message was not
|
||||||
// locally echoed, show error in compose box
|
// locally echoed, show error in compose box
|
||||||
if (!request.locally_echoed) {
|
if (!locally_echoed) {
|
||||||
compose_error(response, $('#new_message_content'));
|
compose_error(response, $('#new_message_content'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -893,15 +838,6 @@ exports.initialize = function () {
|
||||||
compose_actions.start("stream", {});
|
compose_actions.start("stream", {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).on('message_id_changed', function (event) {
|
|
||||||
if (exports.send_times_data[event.old_id] !== undefined) {
|
|
||||||
var value = exports.send_times_data[event.old_id];
|
|
||||||
delete exports.send_times_data[event.old_id];
|
|
||||||
exports.send_times_data[event.new_id] =
|
|
||||||
_.extend({}, exports.send_times_data[event.old_id], value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return exports;
|
return exports;
|
||||||
|
|
|
@ -9,26 +9,34 @@ function resend_message(message, row) {
|
||||||
message.content = message.raw_content;
|
message.content = message.raw_content;
|
||||||
var retry_spinner = row.find('.refresh-failed-message');
|
var retry_spinner = row.find('.refresh-failed-message');
|
||||||
retry_spinner.toggleClass('rotating', true);
|
retry_spinner.toggleClass('rotating', true);
|
||||||
|
|
||||||
// Always re-set queue_id if we've gotten a new one
|
// Always re-set queue_id if we've gotten a new one
|
||||||
// since the time when the message object was initially created
|
// since the time when the message object was initially created
|
||||||
message.queue_id = page_params.queue_id;
|
message.queue_id = page_params.queue_id;
|
||||||
var start_time = new Date();
|
|
||||||
compose.transmit_message(message, function success(data) {
|
|
||||||
retry_spinner.toggleClass('rotating', false);
|
|
||||||
|
|
||||||
|
var local_id = message.local_id;
|
||||||
|
|
||||||
|
function on_success(data) {
|
||||||
var message_id = data.id;
|
var message_id = data.id;
|
||||||
|
var locally_echoed = true;
|
||||||
|
|
||||||
retry_spinner.toggleClass('rotating', false);
|
retry_spinner.toggleClass('rotating', false);
|
||||||
compose.send_message_success(message.local_id, message_id, start_time, true);
|
|
||||||
|
compose.send_message_success(local_id, message_id, locally_echoed);
|
||||||
|
|
||||||
// Resend succeeded, so mark as no longer failed
|
// Resend succeeded, so mark as no longer failed
|
||||||
message_store.get(message_id).failed_request = false;
|
message_store.get(message_id).failed_request = false;
|
||||||
ui.show_failed_message_success(message_id);
|
ui.show_failed_message_success(message_id);
|
||||||
}, function error(response) {
|
}
|
||||||
exports.message_send_error(message.local_id, response);
|
|
||||||
|
function on_error(response) {
|
||||||
|
exports.message_send_error(local_id, response);
|
||||||
retry_spinner.toggleClass('rotating', false);
|
retry_spinner.toggleClass('rotating', false);
|
||||||
blueslip.log("Manual resend of message failed");
|
blueslip.log("Manual resend of message failed");
|
||||||
});
|
}
|
||||||
|
|
||||||
|
sent_messages.start_resend(local_id);
|
||||||
|
compose.transmit_message(message, on_success, on_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
function truncate_precision(float) {
|
function truncate_precision(float) {
|
||||||
|
@ -205,18 +213,18 @@ exports.process_from_server = function process_from_server(messages) {
|
||||||
var msgs_to_rerender = [];
|
var msgs_to_rerender = [];
|
||||||
messages = _.filter(messages, function (message) {
|
messages = _.filter(messages, function (message) {
|
||||||
// In case we get the sent message before we get the send ACK, reify here
|
// In case we get the sent message before we get the send ACK, reify here
|
||||||
exports.reify_message_id(message.local_id, message.id);
|
|
||||||
|
|
||||||
var client_message = waiting_for_ack[message.local_id];
|
var client_message = waiting_for_ack[message.local_id];
|
||||||
if (client_message !== undefined) {
|
if (client_message !== undefined) {
|
||||||
|
exports.reify_message_id(message.local_id, message.id);
|
||||||
|
|
||||||
if (client_message.content !== message.content) {
|
if (client_message.content !== message.content) {
|
||||||
client_message.content = message.content;
|
client_message.content = message.content;
|
||||||
updated = true;
|
updated = true;
|
||||||
compose.mark_rendered_content_disparity(message.id, true);
|
sent_messages.mark_disparity(message.local_id);
|
||||||
}
|
}
|
||||||
msgs_to_rerender.push(client_message);
|
msgs_to_rerender.push(client_message);
|
||||||
locally_processed_ids.push(client_message.id);
|
locally_processed_ids.push(client_message.id);
|
||||||
compose.report_as_received(client_message);
|
|
||||||
delete waiting_for_ack[client_message.id];
|
delete waiting_for_ack[client_message.id];
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,14 +19,6 @@ exports.add_messages = function add_messages(messages, msg_list, opts) {
|
||||||
$('#first_run_message').remove();
|
$('#first_run_message').remove();
|
||||||
|
|
||||||
msg_list.add_messages(messages, opts);
|
msg_list.add_messages(messages, opts);
|
||||||
|
|
||||||
if (msg_list === home_msg_list && opts.messages_are_new) {
|
|
||||||
_.each(messages, function (message) {
|
|
||||||
if (message.local_id === undefined) {
|
|
||||||
compose.report_as_received(message);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,184 @@
|
||||||
|
var sent_messages = (function () {
|
||||||
|
|
||||||
|
var exports = {};
|
||||||
|
|
||||||
|
exports.messages = {};
|
||||||
|
|
||||||
|
exports.reset_id_state = function () {
|
||||||
|
exports.next_local_id = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.get_new_local_id = function () {
|
||||||
|
exports.next_local_id += 1;
|
||||||
|
var local_id = exports.next_local_id;
|
||||||
|
return 'loc-' + local_id.toString();
|
||||||
|
};
|
||||||
|
|
||||||
|
function report_send_time(send_time, receive_time,
|
||||||
|
locally_echoed, rendered_changed) {
|
||||||
|
var data = {
|
||||||
|
time: send_time.toString(),
|
||||||
|
received: receive_time.toString(),
|
||||||
|
locally_echoed: locally_echoed,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (locally_echoed) {
|
||||||
|
data.rendered_content_disparity = rendered_changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
channel.post({
|
||||||
|
url: '/json/report_send_time',
|
||||||
|
data: data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.start_tracking_message = function (opts) {
|
||||||
|
var local_id = opts.local_id;
|
||||||
|
|
||||||
|
if (!opts.local_id) {
|
||||||
|
blueslip.error('You must supply a local_id');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exports.messages[local_id] !== undefined) {
|
||||||
|
blueslip.error('We are re-using a local_id');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var state = exports.message_state(opts);
|
||||||
|
|
||||||
|
exports.messages[local_id] = state;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.message_state = function (opts) {
|
||||||
|
var self = {};
|
||||||
|
self.data = {};
|
||||||
|
|
||||||
|
self.data.start = new Date();
|
||||||
|
|
||||||
|
self.data.local_id = opts.local_id;
|
||||||
|
self.data.locally_echoed = opts.locally_echoed;
|
||||||
|
|
||||||
|
|
||||||
|
self.data.received = undefined;
|
||||||
|
self.data.send_finished = undefined;
|
||||||
|
self.data.rendered_content_disparity = false;
|
||||||
|
|
||||||
|
self.start_resend = function () {
|
||||||
|
self.data.start = new Date();
|
||||||
|
self.data.received = undefined;
|
||||||
|
self.data.send_finished = undefined;
|
||||||
|
self.data.rendered_content_disparity = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
self.maybe_restart_event_loop = function () {
|
||||||
|
if (self.data.received) {
|
||||||
|
// We got our event, no need to do anything
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
blueslip.log("Restarting get_events due to " +
|
||||||
|
"delayed receipt of sent message " +
|
||||||
|
self.data.local_id);
|
||||||
|
|
||||||
|
server_events.restart_get_events();
|
||||||
|
};
|
||||||
|
|
||||||
|
self.maybe_report_send_times = function () {
|
||||||
|
if (!self.ready()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var data = self.data;
|
||||||
|
report_send_time(data.send_finished - data.start,
|
||||||
|
data.received - data.start,
|
||||||
|
data.locally_echoed,
|
||||||
|
data.rendered_content_disparity);
|
||||||
|
};
|
||||||
|
|
||||||
|
self.report_event_received = function () {
|
||||||
|
self.data.received = new Date();
|
||||||
|
self.maybe_report_send_times();
|
||||||
|
};
|
||||||
|
|
||||||
|
self.mark_disparity = function () {
|
||||||
|
self.data.rendered_content_disparity = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
self.report_server_ack = function () {
|
||||||
|
self.data.send_finished = new Date();
|
||||||
|
self.maybe_report_send_times();
|
||||||
|
|
||||||
|
// We only start our timer for events coming in here,
|
||||||
|
// since it's plausible the server rejected our message,
|
||||||
|
// or took a while to process it, but there is nothing
|
||||||
|
// wrong with our event loop.
|
||||||
|
|
||||||
|
if (!self.data.received) {
|
||||||
|
setTimeout(self.maybe_restart_event_loop, 5000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.ready = function () {
|
||||||
|
return (self.data.send_finished !== undefined) &&
|
||||||
|
(self.data.received !== undefined);
|
||||||
|
};
|
||||||
|
|
||||||
|
return self;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.get_message_state = function (local_id) {
|
||||||
|
var state = exports.messages[local_id];
|
||||||
|
|
||||||
|
if (!state) {
|
||||||
|
blueslip.warn('Unknown local_id: ' + local_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return state;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
exports.mark_disparity = function (local_id) {
|
||||||
|
var state = exports.get_message_state(local_id);
|
||||||
|
if (!state) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state.mark_disparity();
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.report_event_received = function (local_id) {
|
||||||
|
var state = exports.get_message_state(local_id);
|
||||||
|
if (!state) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.report_event_received();
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.start_resend = function (local_id) {
|
||||||
|
var state = exports.get_message_state(local_id);
|
||||||
|
if (!state) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.start_resend();
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.report_server_ack = function (local_id) {
|
||||||
|
var state = exports.get_message_state(local_id);
|
||||||
|
if (!state) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.report_server_ack();
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.initialize = function () {
|
||||||
|
exports.reset_id_state();
|
||||||
|
};
|
||||||
|
|
||||||
|
return exports;
|
||||||
|
|
||||||
|
}());
|
||||||
|
if (typeof module !== 'undefined') {
|
||||||
|
module.exports = sent_messages;
|
||||||
|
}
|
|
@ -68,8 +68,9 @@ function get_events_success(events) {
|
||||||
case 'message':
|
case 'message':
|
||||||
var msg = event.message;
|
var msg = event.message;
|
||||||
msg.flags = event.flags;
|
msg.flags = event.flags;
|
||||||
if (event.local_message_id !== undefined) {
|
if (event.local_message_id) {
|
||||||
msg.local_id = event.local_message_id;
|
msg.local_id = event.local_message_id;
|
||||||
|
sent_messages.report_event_received(event.local_message_id);
|
||||||
}
|
}
|
||||||
messages.push(msg);
|
messages.push(msg);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -267,6 +267,7 @@ $(function () {
|
||||||
pm_list.initialize();
|
pm_list.initialize();
|
||||||
stream_list.initialize();
|
stream_list.initialize();
|
||||||
drafts.initialize();
|
drafts.initialize();
|
||||||
|
sent_messages.initialize();
|
||||||
compose.initialize();
|
compose.initialize();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -873,6 +873,7 @@ JS_SPECS = {
|
||||||
'js/markdown.js',
|
'js/markdown.js',
|
||||||
'js/echo.js',
|
'js/echo.js',
|
||||||
'js/socket.js',
|
'js/socket.js',
|
||||||
|
'js/sent_messages.js',
|
||||||
'js/compose_state.js',
|
'js/compose_state.js',
|
||||||
'js/compose_actions.js',
|
'js/compose_actions.js',
|
||||||
'js/compose.js',
|
'js/compose.js',
|
||||||
|
|
Loading…
Reference in New Issue