mirror of https://github.com/zulip/zulip.git
150 lines
5.4 KiB
JavaScript
150 lines
5.4 KiB
JavaScript
import * as Sentry from "@sentry/browser";
|
|
|
|
import * as blueslip from "./blueslip";
|
|
import * as channel from "./channel";
|
|
import {page_params} from "./page_params";
|
|
import * as people from "./people";
|
|
import * as reload from "./reload";
|
|
import * as reload_state from "./reload_state";
|
|
import * as sent_messages from "./sent_messages";
|
|
import * as server_events from "./server_events";
|
|
import * as stream_data from "./stream_data";
|
|
|
|
export function send_message(request, on_success, error) {
|
|
if (!request.resend) {
|
|
sent_messages.start_tracking_message({
|
|
local_id: request.local_id,
|
|
locally_echoed: request.locally_echoed,
|
|
});
|
|
}
|
|
const txn = sent_messages.start_send(request.local_id);
|
|
try {
|
|
const scope = Sentry.getCurrentHub().pushScope();
|
|
scope.setSpan(txn);
|
|
channel.post({
|
|
url: "/json/messages",
|
|
data: request,
|
|
success: function success(data) {
|
|
// Call back to our callers to do things like closing the compose
|
|
// box, turning off spinners, reifying locally echoed messages and
|
|
// displaying visibility policy related compose banners.
|
|
on_success(data);
|
|
// Once everything is done, get ready to report times to the server.
|
|
const state = sent_messages.get_message_state(request.local_id);
|
|
/* istanbul ignore if */
|
|
if (!state) {
|
|
return;
|
|
}
|
|
state.report_server_ack();
|
|
|
|
// 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.
|
|
/* istanbul ignore if */
|
|
if (!state.saw_event) {
|
|
setTimeout(() => {
|
|
if (state.saw_event) {
|
|
// We got our event, no need to do anything
|
|
return;
|
|
}
|
|
|
|
blueslip.log(
|
|
`Restarting get_events due to delayed receipt of sent message ${request.local_id}`,
|
|
);
|
|
|
|
server_events.restart_get_events();
|
|
}, 5000);
|
|
}
|
|
},
|
|
error(xhr, error_type) {
|
|
if (error_type !== "timeout" && reload_state.is_pending()) {
|
|
// 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;
|
|
}
|
|
|
|
const response = channel.xhr_error_message("Error sending message", xhr);
|
|
error(response, xhr.responseJSON?.code);
|
|
},
|
|
});
|
|
} finally {
|
|
Sentry.getCurrentHub().popScope();
|
|
}
|
|
}
|
|
|
|
export function reply_message(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.
|
|
const message = opts.message;
|
|
let content = opts.content;
|
|
|
|
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(_response, _server_error_code) {
|
|
// 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.
|
|
}
|
|
|
|
const locally_echoed = false;
|
|
const local_id = sent_messages.get_new_local_id();
|
|
|
|
const reply = {
|
|
sender_id: page_params.user_id,
|
|
queue_id: page_params.queue_id,
|
|
local_id,
|
|
};
|
|
|
|
sent_messages.start_tracking_message({
|
|
local_id,
|
|
locally_echoed,
|
|
});
|
|
|
|
if (message.type === "stream") {
|
|
const stream_name = stream_data.get_stream_name_from_id(message.stream_id);
|
|
|
|
const mention = people.get_mention_syntax(message.sender_full_name, message.sender_id);
|
|
|
|
content = mention + " " + content;
|
|
|
|
reply.type = "stream";
|
|
reply.to = stream_name;
|
|
reply.content = content;
|
|
reply.topic = message.topic;
|
|
|
|
send_message(reply, success, error);
|
|
return;
|
|
}
|
|
|
|
if (message.type === "private") {
|
|
const pm_recipient = people.pm_reply_to(message);
|
|
|
|
reply.type = "private";
|
|
reply.to = JSON.stringify(pm_recipient.split(","));
|
|
reply.content = content;
|
|
|
|
send_message(reply, success, error);
|
|
return;
|
|
}
|
|
|
|
blueslip.error("unknown message type", {message, content});
|
|
}
|