mirror of https://github.com/zulip/zulip.git
Add client-side SockJS wrapper
The wrapper handles our RPC protocol, authentication scheme, and reconnections. (imported from commit 1fed2d160582c235a32de80a80b3e451c13a7b1c)
This commit is contained in:
parent
7da51fd6a8
commit
ca16644152
|
@ -0,0 +1,126 @@
|
|||
function Socket(url) {
|
||||
this.url = url;
|
||||
this._is_open = false;
|
||||
this._is_authenticated = false;
|
||||
this._send_queue = [];
|
||||
this._next_req_id = 0;
|
||||
this._requests = {};
|
||||
this._connection_failures = 0;
|
||||
|
||||
this._is_unloading = false;
|
||||
$(window).on("unload", function () {
|
||||
this._is_unloading = true;
|
||||
});
|
||||
|
||||
this._sockjs = new SockJS(url);
|
||||
this._setup_sockjs_callbacks(this._sockjs);
|
||||
}
|
||||
|
||||
Socket.prototype = {
|
||||
send: function Socket_send(msg, success, error) {
|
||||
if (! this._can_send()) {
|
||||
this._send_queue.push({msg: msg, success: success, error: error});
|
||||
return;
|
||||
}
|
||||
|
||||
this._do_send('request', msg, success, error);
|
||||
},
|
||||
|
||||
_do_send: function Socket__do_send(type, msg, success, error) {
|
||||
var req_id = this._next_req_id;
|
||||
this._next_req_id++;
|
||||
this._requests[req_id] = {success: success, error: error};
|
||||
// TODO: I think we might need to catch exceptions here for certain transports
|
||||
this._sockjs.send(JSON.stringify({client_meta: {req_id: req_id},
|
||||
type: type, request: msg}));
|
||||
},
|
||||
|
||||
_can_send: function Socket__can_send() {
|
||||
return this._is_open && this._is_authenticated;
|
||||
},
|
||||
|
||||
_drain_queue_send: function Socket__drain_queue_send() {
|
||||
var that = this;
|
||||
var queue = this._send_queue;
|
||||
this._send_queue = [];
|
||||
_.each(queue, function (elem) {
|
||||
that.send(elem.msg, elem.success, elem.error);
|
||||
});
|
||||
},
|
||||
|
||||
_drain_queue_error: function Socket__drain_queue_error() {
|
||||
var that = this;
|
||||
var queue = this._send_queue;
|
||||
this._send_queue = [];
|
||||
_.each(queue, function (elem) {
|
||||
elem.error('connection');
|
||||
});
|
||||
},
|
||||
|
||||
_setup_sockjs_callbacks: function Socket__setup_sockjs_callbacks(sockjs) {
|
||||
var that = this;
|
||||
sockjs.onopen = function Socket__sockjs_onopen() {
|
||||
that._is_open = true;
|
||||
|
||||
// We can only authenticate after the DOM has loaded because we need
|
||||
// the CSRF token
|
||||
$(function () {
|
||||
that._do_send('auth', {csrf_token: csrf_token},
|
||||
function () {
|
||||
that._is_authenticated = true;
|
||||
that._connection_failures = 0;
|
||||
that._drain_queue_send();
|
||||
},
|
||||
function (type, resp) {
|
||||
blueslip.info("Could not authenticate with server: " + resp.msg);
|
||||
that._try_to_reconnect();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
sockjs.onmessage = function Socket__sockjs_onmessage(event) {
|
||||
var req_info = that._requests[event.data.client_meta.req_id];
|
||||
if (req_info === undefined) {
|
||||
blueslip.error("Got a response for an unknown request");
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.response.result === 'success') {
|
||||
req_info.success(event.data.response);
|
||||
} else {
|
||||
req_info.error('response', event.data.response);
|
||||
}
|
||||
};
|
||||
|
||||
sockjs.onclose = function Socket__sockjs_onclose() {
|
||||
if (that._is_unloading) {
|
||||
return;
|
||||
}
|
||||
blueslip.info("SockJS connection lost. Attempting to reconnect soon.");
|
||||
that._try_to_reconnect();
|
||||
};
|
||||
},
|
||||
|
||||
_try_to_reconnect: function Socket__try_to_reconnect() {
|
||||
var that = this;
|
||||
this._is_open = false;
|
||||
this._is_authenticated = false;
|
||||
this._connection_failures++;
|
||||
this._drain_queue_error();
|
||||
|
||||
var wait_time;
|
||||
if (this._connection_failures === 1) {
|
||||
// We specify a non-zero timeout here so that we don't try to
|
||||
// immediately reconnect when the page is refreshing
|
||||
wait_time = 30;
|
||||
} else {
|
||||
wait_time = Math.min(90, Math.exp(this._connection_failures/2)) * 1000;
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
blueslip.info("Attempting reconnect.");
|
||||
that._sockjs = new SockJS(that.url);
|
||||
that._setup_sockjs_callbacks(that._sockjs);
|
||||
}, wait_time);
|
||||
}
|
||||
};
|
|
@ -4,7 +4,7 @@
|
|||
var globals =
|
||||
// Third-party libraries
|
||||
' $ _ jQuery Spinner Handlebars XDate zxcvbn Intl mixpanel Notification'
|
||||
+ ' LazyLoad Dropbox'
|
||||
+ ' LazyLoad Dropbox SockJS'
|
||||
|
||||
// Node-based unit tests
|
||||
+ ' module'
|
||||
|
@ -27,7 +27,7 @@ var globals =
|
|||
+ ' invite ui util activity timerender MessageList MessageListView blueslip unread stream_list'
|
||||
+ ' onboarding message_edit tab_bar emoji popovers navigate message_tour'
|
||||
+ ' avatar feature_flags search_suggestion referral stream_color Dict'
|
||||
+ ' Filter summary admin stream_data muting WinChan muting_ui'
|
||||
+ ' Filter summary admin stream_data muting WinChan muting_ui Socket'
|
||||
|
||||
// colorspace.js
|
||||
+ ' colorspace'
|
||||
|
|
|
@ -367,6 +367,7 @@ JS_SPECS = {
|
|||
'js/reload.js',
|
||||
'js/notifications_bar.js',
|
||||
'js/compose_fade.js',
|
||||
'js/socket.js',
|
||||
'js/compose.js',
|
||||
'js/stream_color.js',
|
||||
'js/admin.js',
|
||||
|
|
Loading…
Reference in New Issue