2018-02-20 13:08:50 +01:00
|
|
|
function send_message_ajax(request, success, error) {
|
|
|
|
channel.post({
|
|
|
|
url: '/json/messages',
|
|
|
|
data: request,
|
|
|
|
success: success,
|
|
|
|
error: function (xhr, error_type) {
|
2018-08-04 15:40:25 +02:00
|
|
|
if (error_type !== 'timeout' && reload_state.is_pending()) {
|
2018-02-20 13:08:50 +01:00
|
|
|
// The error might be due to the server changing
|
|
|
|
reload.initiate({immediate: true,
|
|
|
|
save_pointer: true,
|
|
|
|
save_narrow: true,
|
|
|
|
save_compose: true,
|
|
|
|
send_after_reload: true});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const response = channel.xhr_error_message("Error sending message", xhr);
|
2018-02-20 13:08:50 +01:00
|
|
|
error(response);
|
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
exports.send_message = function (request, on_success, error) {
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
dependencies: Remove WebSockets system for sending messages.
Zulip has had a small use of WebSockets (specifically, for the code
path of sending messages, via the webapp only) since ~2013. We
originally added this use of WebSockets in the hope that the latency
benefits of doing so would allow us to avoid implementing a markdown
local echo; they were not. Further, HTTP/2 may have eliminated the
latency difference we hoped to exploit by using WebSockets in any
case.
While we’d originally imagined using WebSockets for other endpoints,
there was never a good justification for moving more components to the
WebSockets system.
This WebSockets code path had a lot of downsides/complexity,
including:
* The messy hack involving constructing an emulated request object to
hook into doing Django requests.
* The `message_senders` queue processor system, which increases RAM
needs and must be provisioned independently from the rest of the
server).
* A duplicate check_send_receive_time Nagios test specific to
WebSockets.
* The requirement for users to have their firewalls/NATs allow
WebSocket connections, and a setting to disable them for networks
where WebSockets don’t work.
* Dependencies on the SockJS family of libraries, which has at times
been poorly maintained, and periodically throws random JavaScript
exceptions in our production environments without a deep enough
traceback to effectively investigate.
* A total of about 1600 lines of our code related to the feature.
* Increased load on the Tornado system, especially around a Zulip
server restart, and especially for large installations like
zulipchat.com, resulting in extra delay before messages can be sent
again.
As detailed in
https://github.com/zulip/zulip/pull/12862#issuecomment-536152397, it
appears that removing WebSockets moderately increases the time it
takes for the `send_message` API query to return from the server, but
does not significantly change the time between when a message is sent
and when it is received by clients. We don’t understand the reason
for that change (suggesting the possibility of a measurement error),
and even if it is a real change, we consider that potential small
latency regression to be acceptable.
If we later want WebSockets, we’ll likely want to just use Django
Channels.
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2019-07-23 01:43:40 +02:00
|
|
|
send_message_ajax(request, success, error);
|
2018-02-20 13:08:50 +01:00
|
|
|
};
|
|
|
|
|
2018-02-23 16:18:27 +01:00
|
|
|
exports.reply_message = function (opts) {
|
|
|
|
// This code does an application-triggered reply to a message (as
|
|
|
|
// opposed to the user themselves doing it). Its only use case
|
|
|
|
// for now is experimental widget-aware bots, so treat this as
|
|
|
|
// somewhat beta code. To understand the use case, think of a
|
|
|
|
// bot that wants to give users 3 or 4 canned replies to some
|
|
|
|
// choice, but it wants to front-end each of these options
|
|
|
|
// with a one-click button. This function is part of that architecture.
|
2019-11-02 00:06:25 +01:00
|
|
|
const message = opts.message;
|
|
|
|
let content = opts.content;
|
2018-02-23 16:18:27 +01:00
|
|
|
|
|
|
|
function success() {
|
|
|
|
// TODO: If server response comes back before the message event,
|
|
|
|
// we could show it earlier, although that creates some
|
|
|
|
// complexity. For now do nothing. (Note that send_message
|
|
|
|
// already handles things like reporting times to the server.)
|
|
|
|
}
|
|
|
|
|
|
|
|
function error() {
|
|
|
|
// TODO: In our current use case, which is widgets, to meaningfully
|
|
|
|
// handle errors, we would want the widget to provide some
|
|
|
|
// kind of callback to us so it can do some appropriate UI.
|
|
|
|
// For now do nothing.
|
|
|
|
}
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const locally_echoed = false;
|
|
|
|
const local_id = sent_messages.get_new_local_id();
|
2018-02-23 16:18:27 +01:00
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const reply = {
|
2018-02-23 16:18:27 +01:00
|
|
|
sender_id: page_params.user_id,
|
|
|
|
queue_id: page_params.queue_id,
|
|
|
|
local_id: local_id,
|
|
|
|
};
|
|
|
|
|
|
|
|
sent_messages.start_tracking_message({
|
|
|
|
local_id: local_id,
|
|
|
|
locally_echoed: locally_echoed,
|
|
|
|
});
|
|
|
|
|
|
|
|
if (message.type === 'stream') {
|
2019-11-02 00:06:25 +01:00
|
|
|
const stream = message.stream;
|
2018-02-23 16:18:27 +01:00
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const mention = people.get_mention_syntax(message.sender_full_name, message.sender_id);
|
2018-02-23 16:18:27 +01:00
|
|
|
|
|
|
|
content = mention + ' ' + content;
|
|
|
|
|
|
|
|
reply.type = 'stream';
|
|
|
|
reply.to = stream;
|
|
|
|
reply.content = content;
|
2020-02-19 02:44:17 +01:00
|
|
|
reply.topic = message.topic;
|
2018-02-23 16:18:27 +01:00
|
|
|
|
2019-10-25 09:45:13 +02:00
|
|
|
exports.send_message(reply, success, error);
|
2018-02-23 16:18:27 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (message.type === 'private') {
|
2019-11-02 00:06:25 +01:00
|
|
|
const pm_recipient = people.pm_reply_to(message);
|
2018-02-23 16:18:27 +01:00
|
|
|
|
|
|
|
reply.type = 'private';
|
|
|
|
reply.to = JSON.stringify(pm_recipient.split(','));
|
|
|
|
reply.content = content;
|
|
|
|
|
2019-10-25 09:45:13 +02:00
|
|
|
exports.send_message(reply, success, error);
|
2018-02-23 16:18:27 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
blueslip.error('unknown message type: ' + message.type);
|
|
|
|
};
|
|
|
|
|
2019-10-25 09:45:13 +02:00
|
|
|
window.transmit = exports;
|