Better handling of network disconnection/reconnection (#1546)
* Ensure that our preload.js setImmediate call finds right function FREEBIE * Our own socket close event, better logging, unregistration FREEBIE * Return CLOSED for NetworkStatusView if we've fully disconnected * background.js: Remove messageReceiver = null, log in connect() A null messageReciever makes the NetworkStatusView think we're online. FREEBIE
This commit is contained in:
parent
52cc8355a6
commit
b64f2969fd
6 changed files with 363 additions and 228 deletions
|
@ -54,12 +54,12 @@ module.exports = function(grunt) {
|
||||||
'libtextsecure/storage/groups.js',
|
'libtextsecure/storage/groups.js',
|
||||||
'libtextsecure/storage/unprocessed.js',
|
'libtextsecure/storage/unprocessed.js',
|
||||||
'libtextsecure/protobufs.js',
|
'libtextsecure/protobufs.js',
|
||||||
'libtextsecure/websocket-resources.js',
|
|
||||||
'libtextsecure/helpers.js',
|
'libtextsecure/helpers.js',
|
||||||
'libtextsecure/stringview.js',
|
'libtextsecure/stringview.js',
|
||||||
'libtextsecure/event_target.js',
|
'libtextsecure/event_target.js',
|
||||||
'libtextsecure/api.js',
|
'libtextsecure/api.js',
|
||||||
'libtextsecure/account_manager.js',
|
'libtextsecure/account_manager.js',
|
||||||
|
'libtextsecure/websocket-resources.js',
|
||||||
'libtextsecure/message_receiver.js',
|
'libtextsecure/message_receiver.js',
|
||||||
'libtextsecure/outgoing_message.js',
|
'libtextsecure/outgoing_message.js',
|
||||||
'libtextsecure/sendmessage.js',
|
'libtextsecure/sendmessage.js',
|
||||||
|
|
|
@ -69,7 +69,6 @@
|
||||||
Whisper.events.on('shutdown', function() {
|
Whisper.events.on('shutdown', function() {
|
||||||
if (messageReceiver) {
|
if (messageReceiver) {
|
||||||
messageReceiver.close().then(function() {
|
messageReceiver.close().then(function() {
|
||||||
messageReceiver = null;
|
|
||||||
Whisper.events.trigger('shutdown-complete');
|
Whisper.events.trigger('shutdown-complete');
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -147,7 +146,6 @@
|
||||||
messageReceiver.close().then(function() {
|
messageReceiver.close().then(function() {
|
||||||
Whisper.events.trigger('shutdown-complete');
|
Whisper.events.trigger('shutdown-complete');
|
||||||
});
|
});
|
||||||
messageReceiver = null;
|
|
||||||
} else {
|
} else {
|
||||||
Whisper.events.trigger('shutdown-complete');
|
Whisper.events.trigger('shutdown-complete');
|
||||||
}
|
}
|
||||||
|
@ -155,6 +153,7 @@
|
||||||
|
|
||||||
var connectCount = 0;
|
var connectCount = 0;
|
||||||
function connect(firstRun) {
|
function connect(firstRun) {
|
||||||
|
console.log('connect');
|
||||||
window.removeEventListener('online', connect);
|
window.removeEventListener('online', connect);
|
||||||
window.addEventListener('offline', disconnect);
|
window.addEventListener('offline', disconnect);
|
||||||
|
|
||||||
|
@ -163,7 +162,6 @@
|
||||||
|
|
||||||
if (messageReceiver) {
|
if (messageReceiver) {
|
||||||
messageReceiver.close();
|
messageReceiver.close();
|
||||||
messageReceiver = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var USERNAME = storage.get('number_id');
|
var USERNAME = storage.get('number_id');
|
||||||
|
@ -485,7 +483,6 @@
|
||||||
console.log('offline');
|
console.log('offline');
|
||||||
if (messageReceiver) {
|
if (messageReceiver) {
|
||||||
messageReceiver.close();
|
messageReceiver.close();
|
||||||
messageReceiver = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37186,211 +37186,6 @@ Internal.SessionLock.queueJobForNumber = function queueJobForNumber(number, runJ
|
||||||
loadProtoBufs('DeviceMessages.proto');
|
loadProtoBufs('DeviceMessages.proto');
|
||||||
})();
|
})();
|
||||||
|
|
||||||
/*
|
|
||||||
* vim: ts=4:sw=4:expandtab
|
|
||||||
*/
|
|
||||||
;(function(){
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/*
|
|
||||||
* WebSocket-Resources
|
|
||||||
*
|
|
||||||
* Create a request-response interface over websockets using the
|
|
||||||
* WebSocket-Resources sub-protocol[1].
|
|
||||||
*
|
|
||||||
* var client = new WebSocketResource(socket, function(request) {
|
|
||||||
* request.respond(200, 'OK');
|
|
||||||
* });
|
|
||||||
*
|
|
||||||
* client.sendRequest({
|
|
||||||
* verb: 'PUT',
|
|
||||||
* path: '/v1/messages',
|
|
||||||
* body: '{ some: "json" }',
|
|
||||||
* success: function(message, status, request) {...},
|
|
||||||
* error: function(message, status, request) {...}
|
|
||||||
* });
|
|
||||||
*
|
|
||||||
* 1. https://github.com/WhisperSystems/WebSocket-Resources
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
var Request = function(options) {
|
|
||||||
this.verb = options.verb || options.type;
|
|
||||||
this.path = options.path || options.url;
|
|
||||||
this.body = options.body || options.data;
|
|
||||||
this.success = options.success;
|
|
||||||
this.error = options.error;
|
|
||||||
this.id = options.id;
|
|
||||||
|
|
||||||
if (this.id === undefined) {
|
|
||||||
var bits = new Uint32Array(2);
|
|
||||||
window.crypto.getRandomValues(bits);
|
|
||||||
this.id = dcodeIO.Long.fromBits(bits[0], bits[1], true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.body === undefined) {
|
|
||||||
this.body = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var IncomingWebSocketRequest = function(options) {
|
|
||||||
var request = new Request(options);
|
|
||||||
var socket = options.socket;
|
|
||||||
|
|
||||||
this.verb = request.verb;
|
|
||||||
this.path = request.path;
|
|
||||||
this.body = request.body;
|
|
||||||
|
|
||||||
this.respond = function(status, message) {
|
|
||||||
socket.send(
|
|
||||||
new textsecure.protobuf.WebSocketMessage({
|
|
||||||
type: textsecure.protobuf.WebSocketMessage.Type.RESPONSE,
|
|
||||||
response: { id: request.id, message: message, status: status }
|
|
||||||
}).encode().toArrayBuffer()
|
|
||||||
);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
var outgoing = {};
|
|
||||||
var OutgoingWebSocketRequest = function(options, socket) {
|
|
||||||
var request = new Request(options);
|
|
||||||
outgoing[request.id] = request;
|
|
||||||
socket.send(
|
|
||||||
new textsecure.protobuf.WebSocketMessage({
|
|
||||||
type: textsecure.protobuf.WebSocketMessage.Type.REQUEST,
|
|
||||||
request: {
|
|
||||||
verb : request.verb,
|
|
||||||
path : request.path,
|
|
||||||
body : request.body,
|
|
||||||
id : request.id
|
|
||||||
}
|
|
||||||
}).encode().toArrayBuffer()
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
window.WebSocketResource = function(socket, opts) {
|
|
||||||
opts = opts || {};
|
|
||||||
var handleRequest = opts.handleRequest;
|
|
||||||
if (typeof handleRequest !== 'function') {
|
|
||||||
handleRequest = function(request) {
|
|
||||||
request.respond(404, 'Not found');
|
|
||||||
};
|
|
||||||
}
|
|
||||||
this.sendRequest = function(options) {
|
|
||||||
return new OutgoingWebSocketRequest(options, socket);
|
|
||||||
};
|
|
||||||
|
|
||||||
socket.onmessage = function(socketMessage) {
|
|
||||||
var blob = socketMessage.data;
|
|
||||||
var handleArrayBuffer = function(buffer) {
|
|
||||||
var message = textsecure.protobuf.WebSocketMessage.decode(buffer);
|
|
||||||
if (message.type === textsecure.protobuf.WebSocketMessage.Type.REQUEST ) {
|
|
||||||
handleRequest(
|
|
||||||
new IncomingWebSocketRequest({
|
|
||||||
verb : message.request.verb,
|
|
||||||
path : message.request.path,
|
|
||||||
body : message.request.body,
|
|
||||||
id : message.request.id,
|
|
||||||
socket : socket
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else if (message.type === textsecure.protobuf.WebSocketMessage.Type.RESPONSE ) {
|
|
||||||
var response = message.response;
|
|
||||||
var request = outgoing[response.id];
|
|
||||||
if (request) {
|
|
||||||
request.response = response;
|
|
||||||
var callback = request.error;
|
|
||||||
if (response.status >= 200 && response.status < 300) {
|
|
||||||
callback = request.success;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof callback === 'function') {
|
|
||||||
callback(response.message, response.status, request);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw 'Received response for unknown request ' + message.response.id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (blob instanceof ArrayBuffer) {
|
|
||||||
handleArrayBuffer(blob);
|
|
||||||
} else {
|
|
||||||
var reader = new FileReader();
|
|
||||||
reader.onload = function() {
|
|
||||||
handleArrayBuffer(reader.result);
|
|
||||||
};
|
|
||||||
reader.readAsArrayBuffer(blob);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (opts.keepalive) {
|
|
||||||
var keepalive = new KeepAlive(this, {
|
|
||||||
path : opts.keepalive.path,
|
|
||||||
disconnect : opts.keepalive.disconnect
|
|
||||||
});
|
|
||||||
var resetKeepAliveTimer = keepalive.reset.bind(keepalive);
|
|
||||||
socket.addEventListener('open', resetKeepAliveTimer);
|
|
||||||
socket.addEventListener('message', resetKeepAliveTimer);
|
|
||||||
socket.addEventListener('close', keepalive.stop.bind(keepalive));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.close = function(code, reason) {
|
|
||||||
if (!code) { code = 3000; }
|
|
||||||
socket.close(code, reason);
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
function KeepAlive(websocketResource, opts) {
|
|
||||||
if (websocketResource instanceof WebSocketResource) {
|
|
||||||
opts = opts || {};
|
|
||||||
this.path = opts.path;
|
|
||||||
if (this.path === undefined) {
|
|
||||||
this.path = '/';
|
|
||||||
}
|
|
||||||
this.disconnect = opts.disconnect;
|
|
||||||
if (this.disconnect === undefined) {
|
|
||||||
this.disconnect = true;
|
|
||||||
}
|
|
||||||
this.wsr = websocketResource;
|
|
||||||
} else {
|
|
||||||
throw new TypeError('KeepAlive expected a WebSocketResource');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
KeepAlive.prototype = {
|
|
||||||
constructor: KeepAlive,
|
|
||||||
stop: function() {
|
|
||||||
clearTimeout(this.keepAliveTimer);
|
|
||||||
clearTimeout(this.disconnectTimer);
|
|
||||||
},
|
|
||||||
reset: function() {
|
|
||||||
clearTimeout(this.keepAliveTimer);
|
|
||||||
clearTimeout(this.disconnectTimer);
|
|
||||||
this.keepAliveTimer = setTimeout(function() {
|
|
||||||
console.log('Sending a keepalive message');
|
|
||||||
this.wsr.sendRequest({
|
|
||||||
verb: 'GET',
|
|
||||||
path: this.path,
|
|
||||||
success: this.reset.bind(this)
|
|
||||||
});
|
|
||||||
if (this.disconnect) {
|
|
||||||
// automatically disconnect if server doesn't ack
|
|
||||||
this.disconnectTimer = setTimeout(function() {
|
|
||||||
clearTimeout(this.keepAliveTimer);
|
|
||||||
this.wsr.close(3001, 'No response to keepalive request');
|
|
||||||
}.bind(this), 1000);
|
|
||||||
} else {
|
|
||||||
this.reset();
|
|
||||||
}
|
|
||||||
}.bind(this), 55000);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
}());
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* vim: ts=4:sw=4:expandtab
|
* vim: ts=4:sw=4:expandtab
|
||||||
*/
|
*/
|
||||||
|
@ -38365,6 +38160,244 @@ var TextSecureServer = (function() {
|
||||||
|
|
||||||
}());
|
}());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* vim: ts=4:sw=4:expandtab
|
||||||
|
*/
|
||||||
|
;(function(){
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* WebSocket-Resources
|
||||||
|
*
|
||||||
|
* Create a request-response interface over websockets using the
|
||||||
|
* WebSocket-Resources sub-protocol[1].
|
||||||
|
*
|
||||||
|
* var client = new WebSocketResource(socket, function(request) {
|
||||||
|
* request.respond(200, 'OK');
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* client.sendRequest({
|
||||||
|
* verb: 'PUT',
|
||||||
|
* path: '/v1/messages',
|
||||||
|
* body: '{ some: "json" }',
|
||||||
|
* success: function(message, status, request) {...},
|
||||||
|
* error: function(message, status, request) {...}
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* 1. https://github.com/WhisperSystems/WebSocket-Resources
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Request = function(options) {
|
||||||
|
this.verb = options.verb || options.type;
|
||||||
|
this.path = options.path || options.url;
|
||||||
|
this.body = options.body || options.data;
|
||||||
|
this.success = options.success;
|
||||||
|
this.error = options.error;
|
||||||
|
this.id = options.id;
|
||||||
|
|
||||||
|
if (this.id === undefined) {
|
||||||
|
var bits = new Uint32Array(2);
|
||||||
|
window.crypto.getRandomValues(bits);
|
||||||
|
this.id = dcodeIO.Long.fromBits(bits[0], bits[1], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.body === undefined) {
|
||||||
|
this.body = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var IncomingWebSocketRequest = function(options) {
|
||||||
|
var request = new Request(options);
|
||||||
|
var socket = options.socket;
|
||||||
|
|
||||||
|
this.verb = request.verb;
|
||||||
|
this.path = request.path;
|
||||||
|
this.body = request.body;
|
||||||
|
|
||||||
|
this.respond = function(status, message) {
|
||||||
|
socket.send(
|
||||||
|
new textsecure.protobuf.WebSocketMessage({
|
||||||
|
type: textsecure.protobuf.WebSocketMessage.Type.RESPONSE,
|
||||||
|
response: { id: request.id, message: message, status: status }
|
||||||
|
}).encode().toArrayBuffer()
|
||||||
|
);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
var outgoing = {};
|
||||||
|
var OutgoingWebSocketRequest = function(options, socket) {
|
||||||
|
var request = new Request(options);
|
||||||
|
outgoing[request.id] = request;
|
||||||
|
socket.send(
|
||||||
|
new textsecure.protobuf.WebSocketMessage({
|
||||||
|
type: textsecure.protobuf.WebSocketMessage.Type.REQUEST,
|
||||||
|
request: {
|
||||||
|
verb : request.verb,
|
||||||
|
path : request.path,
|
||||||
|
body : request.body,
|
||||||
|
id : request.id
|
||||||
|
}
|
||||||
|
}).encode().toArrayBuffer()
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
window.WebSocketResource = function(socket, opts) {
|
||||||
|
opts = opts || {};
|
||||||
|
var handleRequest = opts.handleRequest;
|
||||||
|
if (typeof handleRequest !== 'function') {
|
||||||
|
handleRequest = function(request) {
|
||||||
|
request.respond(404, 'Not found');
|
||||||
|
};
|
||||||
|
}
|
||||||
|
this.sendRequest = function(options) {
|
||||||
|
return new OutgoingWebSocketRequest(options, socket);
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.onmessage = function(socketMessage) {
|
||||||
|
var blob = socketMessage.data;
|
||||||
|
var handleArrayBuffer = function(buffer) {
|
||||||
|
var message = textsecure.protobuf.WebSocketMessage.decode(buffer);
|
||||||
|
if (message.type === textsecure.protobuf.WebSocketMessage.Type.REQUEST ) {
|
||||||
|
handleRequest(
|
||||||
|
new IncomingWebSocketRequest({
|
||||||
|
verb : message.request.verb,
|
||||||
|
path : message.request.path,
|
||||||
|
body : message.request.body,
|
||||||
|
id : message.request.id,
|
||||||
|
socket : socket
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (message.type === textsecure.protobuf.WebSocketMessage.Type.RESPONSE ) {
|
||||||
|
var response = message.response;
|
||||||
|
var request = outgoing[response.id];
|
||||||
|
if (request) {
|
||||||
|
request.response = response;
|
||||||
|
var callback = request.error;
|
||||||
|
if (response.status >= 200 && response.status < 300) {
|
||||||
|
callback = request.success;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof callback === 'function') {
|
||||||
|
callback(response.message, response.status, request);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw 'Received response for unknown request ' + message.response.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (blob instanceof ArrayBuffer) {
|
||||||
|
handleArrayBuffer(blob);
|
||||||
|
} else {
|
||||||
|
var reader = new FileReader();
|
||||||
|
reader.onload = function() {
|
||||||
|
handleArrayBuffer(reader.result);
|
||||||
|
};
|
||||||
|
reader.readAsArrayBuffer(blob);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (opts.keepalive) {
|
||||||
|
this.keepalive = new KeepAlive(this, {
|
||||||
|
path : opts.keepalive.path,
|
||||||
|
disconnect : opts.keepalive.disconnect
|
||||||
|
});
|
||||||
|
var resetKeepAliveTimer = this.keepalive.reset.bind(this.keepalive);
|
||||||
|
socket.addEventListener('open', resetKeepAliveTimer);
|
||||||
|
socket.addEventListener('message', resetKeepAliveTimer);
|
||||||
|
socket.addEventListener('close', this.keepalive.stop.bind(this.keepalive));
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.addEventListener('close', function() {
|
||||||
|
this.closed = true;
|
||||||
|
}.bind(this))
|
||||||
|
|
||||||
|
this.close = function(code, reason) {
|
||||||
|
if (this.closed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('WebSocketResource.close()');
|
||||||
|
if (!code) {
|
||||||
|
code = 3000;
|
||||||
|
}
|
||||||
|
if (this.keepalive) {
|
||||||
|
this.keepalive.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.close(code, reason);
|
||||||
|
socket.onmessage = null;
|
||||||
|
|
||||||
|
// On linux the socket can wait a long time to emit its close event if we've
|
||||||
|
// lost the internet connection. On the order of minutes. This speeds that
|
||||||
|
// process up.
|
||||||
|
setTimeout(function() {
|
||||||
|
if (this.closed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.closed = true;
|
||||||
|
|
||||||
|
console.log('Dispatching our own socket close event');
|
||||||
|
var ev = new Event('close');
|
||||||
|
ev.code = code;
|
||||||
|
ev.reason = reason;
|
||||||
|
this.dispatchEvent(ev);
|
||||||
|
}.bind(this), 10000);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
window.WebSocketResource.prototype = new textsecure.EventTarget();
|
||||||
|
|
||||||
|
|
||||||
|
function KeepAlive(websocketResource, opts) {
|
||||||
|
if (websocketResource instanceof WebSocketResource) {
|
||||||
|
opts = opts || {};
|
||||||
|
this.path = opts.path;
|
||||||
|
if (this.path === undefined) {
|
||||||
|
this.path = '/';
|
||||||
|
}
|
||||||
|
this.disconnect = opts.disconnect;
|
||||||
|
if (this.disconnect === undefined) {
|
||||||
|
this.disconnect = true;
|
||||||
|
}
|
||||||
|
this.wsr = websocketResource;
|
||||||
|
} else {
|
||||||
|
throw new TypeError('KeepAlive expected a WebSocketResource');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KeepAlive.prototype = {
|
||||||
|
constructor: KeepAlive,
|
||||||
|
stop: function() {
|
||||||
|
clearTimeout(this.keepAliveTimer);
|
||||||
|
clearTimeout(this.disconnectTimer);
|
||||||
|
},
|
||||||
|
reset: function() {
|
||||||
|
clearTimeout(this.keepAliveTimer);
|
||||||
|
clearTimeout(this.disconnectTimer);
|
||||||
|
this.keepAliveTimer = setTimeout(function() {
|
||||||
|
if (this.disconnect) {
|
||||||
|
// automatically disconnect if server doesn't ack
|
||||||
|
this.disconnectTimer = setTimeout(function() {
|
||||||
|
clearTimeout(this.keepAliveTimer);
|
||||||
|
this.wsr.close(3001, 'No response to keepalive request');
|
||||||
|
}.bind(this), 1000);
|
||||||
|
} else {
|
||||||
|
this.reset();
|
||||||
|
}
|
||||||
|
console.log('Sending a keepalive message');
|
||||||
|
this.wsr.sendRequest({
|
||||||
|
verb: 'GET',
|
||||||
|
path: this.path,
|
||||||
|
success: this.reset.bind(this)
|
||||||
|
});
|
||||||
|
}.bind(this), 55000);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
}());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* vim: ts=4:sw=4:expandtab
|
* vim: ts=4:sw=4:expandtab
|
||||||
*/
|
*/
|
||||||
|
@ -38395,8 +38428,11 @@ MessageReceiver.prototype = new textsecure.EventTarget();
|
||||||
MessageReceiver.prototype.extend({
|
MessageReceiver.prototype.extend({
|
||||||
constructor: MessageReceiver,
|
constructor: MessageReceiver,
|
||||||
connect: function() {
|
connect: function() {
|
||||||
|
this.hasConnected = true;
|
||||||
|
|
||||||
if (this.socket && this.socket.readyState !== WebSocket.CLOSED) {
|
if (this.socket && this.socket.readyState !== WebSocket.CLOSED) {
|
||||||
this.socket.close();
|
this.socket.close();
|
||||||
|
this.wsr.close();
|
||||||
}
|
}
|
||||||
// initialize the socket and start listening for messages
|
// initialize the socket and start listening for messages
|
||||||
this.socket = this.server.getMessageSocket();
|
this.socket = this.server.getMessageSocket();
|
||||||
|
@ -38405,16 +38441,45 @@ MessageReceiver.prototype.extend({
|
||||||
this.socket.onopen = this.onopen.bind(this);
|
this.socket.onopen = this.onopen.bind(this);
|
||||||
this.wsr = new WebSocketResource(this.socket, {
|
this.wsr = new WebSocketResource(this.socket, {
|
||||||
handleRequest: this.handleRequest.bind(this),
|
handleRequest: this.handleRequest.bind(this),
|
||||||
keepalive: { path: '/v1/keepalive', disconnect: true }
|
keepalive: {
|
||||||
|
path: '/v1/keepalive',
|
||||||
|
disconnect: true
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Because sometimes the socket doesn't properly emit its close event
|
||||||
|
this._onClose = this.onclose.bind(this)
|
||||||
|
this.wsr.addEventListener('close', this._onClose);
|
||||||
|
|
||||||
// Ensures that an immediate 'empty' event from the websocket will fire only after
|
// Ensures that an immediate 'empty' event from the websocket will fire only after
|
||||||
// all cached envelopes are processed.
|
// all cached envelopes are processed.
|
||||||
this.incoming = [this.pending];
|
this.incoming = [this.pending];
|
||||||
},
|
},
|
||||||
|
shutdown: function() {
|
||||||
|
if (this.socket) {
|
||||||
|
this.socket.onclose = null;
|
||||||
|
this.socket.onerror = null;
|
||||||
|
this.socket.onopen = null;
|
||||||
|
this.socket = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.wsr) {
|
||||||
|
this.wsr.removeEventListener('close', this._onClose);
|
||||||
|
this.wsr = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
close: function() {
|
close: function() {
|
||||||
|
console.log('MessageReceiver.close()');
|
||||||
this.calledClose = true;
|
this.calledClose = true;
|
||||||
this.socket.close(3000, 'called close');
|
|
||||||
|
// Our WebSocketResource instance will close the socket and emit a 'close' event
|
||||||
|
// if the socket doesn't emit one quickly enough.
|
||||||
|
if (this.wsr) {
|
||||||
|
this.wsr.close(3000, 'called close');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.shutdown();
|
||||||
|
|
||||||
return this.drain();
|
return this.drain();
|
||||||
},
|
},
|
||||||
onopen: function() {
|
onopen: function() {
|
||||||
|
@ -38435,6 +38500,8 @@ MessageReceiver.prototype.extend({
|
||||||
this.calledClose
|
this.calledClose
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.shutdown();
|
||||||
|
|
||||||
if (this.calledClose) {
|
if (this.calledClose) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -38699,6 +38766,8 @@ MessageReceiver.prototype.extend({
|
||||||
getStatus: function() {
|
getStatus: function() {
|
||||||
if (this.socket) {
|
if (this.socket) {
|
||||||
return this.socket.readyState;
|
return this.socket.readyState;
|
||||||
|
} else if (this.hasConnected) {
|
||||||
|
return WebSocket.CLOSED;
|
||||||
} else {
|
} else {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,8 +28,11 @@ MessageReceiver.prototype = new textsecure.EventTarget();
|
||||||
MessageReceiver.prototype.extend({
|
MessageReceiver.prototype.extend({
|
||||||
constructor: MessageReceiver,
|
constructor: MessageReceiver,
|
||||||
connect: function() {
|
connect: function() {
|
||||||
|
this.hasConnected = true;
|
||||||
|
|
||||||
if (this.socket && this.socket.readyState !== WebSocket.CLOSED) {
|
if (this.socket && this.socket.readyState !== WebSocket.CLOSED) {
|
||||||
this.socket.close();
|
this.socket.close();
|
||||||
|
this.wsr.close();
|
||||||
}
|
}
|
||||||
// initialize the socket and start listening for messages
|
// initialize the socket and start listening for messages
|
||||||
this.socket = this.server.getMessageSocket();
|
this.socket = this.server.getMessageSocket();
|
||||||
|
@ -38,16 +41,45 @@ MessageReceiver.prototype.extend({
|
||||||
this.socket.onopen = this.onopen.bind(this);
|
this.socket.onopen = this.onopen.bind(this);
|
||||||
this.wsr = new WebSocketResource(this.socket, {
|
this.wsr = new WebSocketResource(this.socket, {
|
||||||
handleRequest: this.handleRequest.bind(this),
|
handleRequest: this.handleRequest.bind(this),
|
||||||
keepalive: { path: '/v1/keepalive', disconnect: true }
|
keepalive: {
|
||||||
|
path: '/v1/keepalive',
|
||||||
|
disconnect: true
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Because sometimes the socket doesn't properly emit its close event
|
||||||
|
this._onClose = this.onclose.bind(this)
|
||||||
|
this.wsr.addEventListener('close', this._onClose);
|
||||||
|
|
||||||
// Ensures that an immediate 'empty' event from the websocket will fire only after
|
// Ensures that an immediate 'empty' event from the websocket will fire only after
|
||||||
// all cached envelopes are processed.
|
// all cached envelopes are processed.
|
||||||
this.incoming = [this.pending];
|
this.incoming = [this.pending];
|
||||||
},
|
},
|
||||||
|
shutdown: function() {
|
||||||
|
if (this.socket) {
|
||||||
|
this.socket.onclose = null;
|
||||||
|
this.socket.onerror = null;
|
||||||
|
this.socket.onopen = null;
|
||||||
|
this.socket = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.wsr) {
|
||||||
|
this.wsr.removeEventListener('close', this._onClose);
|
||||||
|
this.wsr = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
close: function() {
|
close: function() {
|
||||||
|
console.log('MessageReceiver.close()');
|
||||||
this.calledClose = true;
|
this.calledClose = true;
|
||||||
this.socket.close(3000, 'called close');
|
|
||||||
|
// Our WebSocketResource instance will close the socket and emit a 'close' event
|
||||||
|
// if the socket doesn't emit one quickly enough.
|
||||||
|
if (this.wsr) {
|
||||||
|
this.wsr.close(3000, 'called close');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.shutdown();
|
||||||
|
|
||||||
return this.drain();
|
return this.drain();
|
||||||
},
|
},
|
||||||
onopen: function() {
|
onopen: function() {
|
||||||
|
@ -68,6 +100,8 @@ MessageReceiver.prototype.extend({
|
||||||
this.calledClose
|
this.calledClose
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.shutdown();
|
||||||
|
|
||||||
if (this.calledClose) {
|
if (this.calledClose) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -332,6 +366,8 @@ MessageReceiver.prototype.extend({
|
||||||
getStatus: function() {
|
getStatus: function() {
|
||||||
if (this.socket) {
|
if (this.socket) {
|
||||||
return this.socket.readyState;
|
return this.socket.readyState;
|
||||||
|
} else if (this.hasConnected) {
|
||||||
|
return WebSocket.CLOSED;
|
||||||
} else {
|
} else {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,22 +138,55 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
if (opts.keepalive) {
|
if (opts.keepalive) {
|
||||||
var keepalive = new KeepAlive(this, {
|
this.keepalive = new KeepAlive(this, {
|
||||||
path : opts.keepalive.path,
|
path : opts.keepalive.path,
|
||||||
disconnect : opts.keepalive.disconnect
|
disconnect : opts.keepalive.disconnect
|
||||||
});
|
});
|
||||||
var resetKeepAliveTimer = keepalive.reset.bind(keepalive);
|
var resetKeepAliveTimer = this.keepalive.reset.bind(this.keepalive);
|
||||||
socket.addEventListener('open', resetKeepAliveTimer);
|
socket.addEventListener('open', resetKeepAliveTimer);
|
||||||
socket.addEventListener('message', resetKeepAliveTimer);
|
socket.addEventListener('message', resetKeepAliveTimer);
|
||||||
socket.addEventListener('close', keepalive.stop.bind(keepalive));
|
socket.addEventListener('close', this.keepalive.stop.bind(this.keepalive));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.close = function(code, reason) {
|
socket.addEventListener('close', function() {
|
||||||
if (!code) { code = 3000; }
|
this.closed = true;
|
||||||
socket.close(code, reason);
|
}.bind(this))
|
||||||
};
|
|
||||||
|
|
||||||
|
this.close = function(code, reason) {
|
||||||
|
if (this.closed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('WebSocketResource.close()');
|
||||||
|
if (!code) {
|
||||||
|
code = 3000;
|
||||||
|
}
|
||||||
|
if (this.keepalive) {
|
||||||
|
this.keepalive.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.close(code, reason);
|
||||||
|
socket.onmessage = null;
|
||||||
|
|
||||||
|
// On linux the socket can wait a long time to emit its close event if we've
|
||||||
|
// lost the internet connection. On the order of minutes. This speeds that
|
||||||
|
// process up.
|
||||||
|
setTimeout(function() {
|
||||||
|
if (this.closed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.closed = true;
|
||||||
|
|
||||||
|
console.log('Dispatching our own socket close event');
|
||||||
|
var ev = new Event('close');
|
||||||
|
ev.code = code;
|
||||||
|
ev.reason = reason;
|
||||||
|
this.dispatchEvent(ev);
|
||||||
|
}.bind(this), 10000);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
window.WebSocketResource.prototype = new textsecure.EventTarget();
|
||||||
|
|
||||||
|
|
||||||
function KeepAlive(websocketResource, opts) {
|
function KeepAlive(websocketResource, opts) {
|
||||||
if (websocketResource instanceof WebSocketResource) {
|
if (websocketResource instanceof WebSocketResource) {
|
||||||
|
@ -182,12 +215,6 @@
|
||||||
clearTimeout(this.keepAliveTimer);
|
clearTimeout(this.keepAliveTimer);
|
||||||
clearTimeout(this.disconnectTimer);
|
clearTimeout(this.disconnectTimer);
|
||||||
this.keepAliveTimer = setTimeout(function() {
|
this.keepAliveTimer = setTimeout(function() {
|
||||||
console.log('Sending a keepalive message');
|
|
||||||
this.wsr.sendRequest({
|
|
||||||
verb: 'GET',
|
|
||||||
path: this.path,
|
|
||||||
success: this.reset.bind(this)
|
|
||||||
});
|
|
||||||
if (this.disconnect) {
|
if (this.disconnect) {
|
||||||
// automatically disconnect if server doesn't ack
|
// automatically disconnect if server doesn't ack
|
||||||
this.disconnectTimer = setTimeout(function() {
|
this.disconnectTimer = setTimeout(function() {
|
||||||
|
@ -197,6 +224,12 @@
|
||||||
} else {
|
} else {
|
||||||
this.reset();
|
this.reset();
|
||||||
}
|
}
|
||||||
|
console.log('Sending a keepalive message');
|
||||||
|
this.wsr.sendRequest({
|
||||||
|
verb: 'GET',
|
||||||
|
path: this.path,
|
||||||
|
success: this.reset.bind(this)
|
||||||
|
});
|
||||||
}.bind(this), 55000);
|
}.bind(this), 55000);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
|
|
||||||
// Linux seems to periodically let the event loop stop, so this is a global workaround
|
// Linux seems to periodically let the event loop stop, so this is a global workaround
|
||||||
setInterval(function() {
|
setInterval(function() {
|
||||||
setImmediate(function() {});
|
window.nodeSetImmediate(function() {});
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
window.EmojiConvertor = require('emoji-js');
|
window.EmojiConvertor = require('emoji-js');
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue