Merge pull request #477 from glowing-bear/reconnect
[WIP] Start implementing auto-reconnect
This commit is contained in:
commit
afdcaadb72
6 changed files with 148 additions and 17 deletions
|
@ -263,6 +263,19 @@ td.time {
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#reconnect {
|
||||||
|
top: 35px;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 9999;
|
||||||
|
width: 80%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 5px;
|
||||||
|
left: 10%;
|
||||||
|
}
|
||||||
|
#reconnect a {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
|
|
@ -295,6 +295,11 @@ $ openssl req -nodes -newkey rsa:4096 -keyout relay.pem -x509 -days 365 -out rel
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="soundNotification"></div>
|
<div id="soundNotification"></div>
|
||||||
|
<div id="reconnect" class="alert alert-danger" ng-click="reconnect()" ng-show="reconnecting">
|
||||||
|
<p><strong>Connection to WeeChat lost</strong></p>
|
||||||
|
<i class="glyphicon glyphicon-refresh"></i>
|
||||||
|
Reconnecting... <a class="btn btn-tiny" ng-click="reconnect()">Click to try to reconnect now</a>
|
||||||
|
</div>
|
||||||
<div id="settingsModal" class="gb-modal" data-state="hidden">
|
<div id="settingsModal" class="gb-modal" data-state="hidden">
|
||||||
<div class="backdrop" ng-click="closeModal($event)"></div>
|
<div class="backdrop" ng-click="closeModal($event)"></div>
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
|
|
|
@ -12,9 +12,12 @@ weechat.factory('connection',
|
||||||
|
|
||||||
var protocol = new weeChat.Protocol();
|
var protocol = new weeChat.Protocol();
|
||||||
|
|
||||||
// Takes care of the connection and websocket hooks
|
var connectionData = [];
|
||||||
|
var reconnectTimer;
|
||||||
|
|
||||||
var connect = function (host, port, passwd, ssl, noCompression) {
|
// Takes care of the connection and websocket hooks
|
||||||
|
var connect = function (host, port, passwd, ssl, noCompression, successCallback, failCallback) {
|
||||||
|
connectionData = [host, port, passwd, ssl, noCompression];
|
||||||
var proto = ssl ? 'wss' : 'ws';
|
var proto = ssl ? 'wss' : 'ws';
|
||||||
// If host is an IPv6 literal wrap it in brackets
|
// If host is an IPv6 literal wrap it in brackets
|
||||||
if (host.indexOf(":") !== -1) {
|
if (host.indexOf(":") !== -1) {
|
||||||
|
@ -79,21 +82,15 @@ weechat.factory('connection',
|
||||||
// Connection is successful
|
// Connection is successful
|
||||||
// Send all the other commands required for initialization
|
// Send all the other commands required for initialization
|
||||||
_requestBufferInfos().then(function(bufinfo) {
|
_requestBufferInfos().then(function(bufinfo) {
|
||||||
//XXX move to handlers?
|
handlers.handleBufferInfo(bufinfo);
|
||||||
var bufferInfos = bufinfo.objects[0].content;
|
|
||||||
// buffers objects
|
|
||||||
for (var i = 0; i < bufferInfos.length ; i++) {
|
|
||||||
var buffer = new models.Buffer(bufferInfos[i]);
|
|
||||||
models.addBuffer(buffer);
|
|
||||||
// Switch to first buffer on startup
|
|
||||||
if (i === 0) {
|
|
||||||
models.setActiveBuffer(buffer.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
_requestHotlist().then(function(hotlist) {
|
_requestHotlist().then(function(hotlist) {
|
||||||
handlers.handleHotlistInfo(hotlist);
|
handlers.handleHotlistInfo(hotlist);
|
||||||
|
|
||||||
|
if (successCallback) {
|
||||||
|
successCallback();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
_requestSync();
|
_requestSync();
|
||||||
|
@ -123,10 +120,19 @@ weechat.factory('connection',
|
||||||
* Handles websocket disconnection
|
* Handles websocket disconnection
|
||||||
*/
|
*/
|
||||||
$log.info("Disconnected from relay");
|
$log.info("Disconnected from relay");
|
||||||
|
if ($rootScope.userdisconnect || !$rootScope.waseverconnected) {
|
||||||
|
handleClose(evt);
|
||||||
|
$rootScope.userdisconnect = false;
|
||||||
|
} else {
|
||||||
|
reconnect(evt);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var handleClose = function (evt) {
|
||||||
ngWebsockets.failCallbacks('disconnection');
|
ngWebsockets.failCallbacks('disconnection');
|
||||||
$rootScope.connected = false;
|
$rootScope.connected = false;
|
||||||
$rootScope.$emit('relayDisconnect');
|
$rootScope.$emit('relayDisconnect');
|
||||||
if (ssl && evt.code === 1006) {
|
if (ssl && evt && evt.code === 1006) {
|
||||||
// A password error doesn't trigger onerror, but certificate issues do. Check time of last error.
|
// A password error doesn't trigger onerror, but certificate issues do. Check time of last error.
|
||||||
if (typeof $rootScope.lastError !== "undefined" && (Date.now() - $rootScope.lastError) < 1000) {
|
if (typeof $rootScope.lastError !== "undefined" && (Date.now() - $rootScope.lastError) < 1000) {
|
||||||
// abnormal disconnect by client, most likely ssl error
|
// abnormal disconnect by client, most likely ssl error
|
||||||
|
@ -166,11 +172,64 @@ weechat.factory('connection',
|
||||||
$rootScope.errorMessage = true;
|
$rootScope.errorMessage = true;
|
||||||
$rootScope.securityError = true;
|
$rootScope.securityError = true;
|
||||||
$rootScope.$emit('relayDisconnect');
|
$rootScope.$emit('relayDisconnect');
|
||||||
|
|
||||||
|
if (failCallback) {
|
||||||
|
failCallback();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var attemptReconnect = function (bufferId, timeout) {
|
||||||
|
$log.info('Attempting to reconnect...');
|
||||||
|
var d = connectionData;
|
||||||
|
connect(d[0], d[1], d[2], d[3], d[4], function() {
|
||||||
|
$rootScope.reconnecting = false;
|
||||||
|
// on success, update active buffer
|
||||||
|
models.setActiveBuffer(bufferId);
|
||||||
|
$log.info('Sucessfully reconnected to relay');
|
||||||
|
}, function() {
|
||||||
|
// on failure, schedule another attempt
|
||||||
|
if (timeout >= 600000) {
|
||||||
|
// If timeout is ten minutes or more, give up
|
||||||
|
$log.info('Failed to reconnect, giving up');
|
||||||
|
handleClose();
|
||||||
|
} else {
|
||||||
|
$log.info('Failed to reconnect, scheduling next attempt in', timeout/1000, 'seconds');
|
||||||
|
// Clear previous timer, if exists
|
||||||
|
if (reconnectTimer !== undefined) {
|
||||||
|
clearTimeout(reconnectTimer);
|
||||||
|
}
|
||||||
|
reconnectTimer = setTimeout(function() {
|
||||||
|
// exponential timeout increase
|
||||||
|
attemptReconnect(bufferId, timeout * 1.5);
|
||||||
|
}, timeout);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var reconnect = function (evt) {
|
||||||
|
if (connectionData.length < 5) {
|
||||||
|
// something is wrong
|
||||||
|
$log.error('Cannot reconnect, connection information is missing');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$rootScope.reconnecting = true;
|
||||||
|
// Have to do this to get the reconnect banner to show
|
||||||
|
$rootScope.$apply();
|
||||||
|
|
||||||
|
var bufferId = models.getActiveBuffer().id,
|
||||||
|
timeout = 3000; // start with a three-second timeout
|
||||||
|
|
||||||
|
reconnectTimer = setTimeout(function() {
|
||||||
|
attemptReconnect(bufferId, timeout);
|
||||||
|
}, timeout);
|
||||||
|
};
|
||||||
|
|
||||||
var disconnect = function() {
|
var disconnect = function() {
|
||||||
|
$rootScope.userdisconnect = true;
|
||||||
ngWebsockets.send(weeChat.Protocol.formatQuit());
|
ngWebsockets.send(weeChat.Protocol.formatQuit());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -270,7 +329,8 @@ weechat.factory('connection',
|
||||||
sendMessage: sendMessage,
|
sendMessage: sendMessage,
|
||||||
sendCoreCommand: sendCoreCommand,
|
sendCoreCommand: sendCoreCommand,
|
||||||
fetchMoreLines: fetchMoreLines,
|
fetchMoreLines: fetchMoreLines,
|
||||||
requestNicklist: requestNicklist
|
requestNicklist: requestNicklist,
|
||||||
|
attemptReconnect: attemptReconnect
|
||||||
};
|
};
|
||||||
}]);
|
}]);
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -264,6 +264,8 @@ weechat.controller('WeechatCtrl', ['$rootScope', '$scope', '$store', '$timeout',
|
||||||
|
|
||||||
$rootScope.connected = false;
|
$rootScope.connected = false;
|
||||||
$rootScope.waseverconnected = false;
|
$rootScope.waseverconnected = false;
|
||||||
|
$rootScope.userdisconnect = false;
|
||||||
|
$rootScope.reconnecting = false;
|
||||||
|
|
||||||
$rootScope.models = models;
|
$rootScope.models = models;
|
||||||
|
|
||||||
|
@ -513,6 +515,10 @@ weechat.controller('WeechatCtrl', ['$rootScope', '$scope', '$store', '$timeout',
|
||||||
$scope.connectbutton = 'Connect';
|
$scope.connectbutton = 'Connect';
|
||||||
connection.disconnect();
|
connection.disconnect();
|
||||||
};
|
};
|
||||||
|
$scope.reconnect = function() {
|
||||||
|
var bufferId = models.getActiveBuffer().id;
|
||||||
|
connection.attemptReconnect(bufferId, 3000);
|
||||||
|
};
|
||||||
|
|
||||||
//XXX this is a bit out of place here, either move up to the rest of the firefox install code or remove
|
//XXX this is a bit out of place here, either move up to the rest of the firefox install code or remove
|
||||||
$scope.install = function() {
|
$scope.install = function() {
|
||||||
|
|
|
@ -43,6 +43,53 @@ weechat.factory('handlers', ['$rootScope', '$log', 'models', 'plugins', 'notific
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var handleBufferInfo = function(message) {
|
||||||
|
var bufferInfos = message.objects[0].content;
|
||||||
|
// buffers objects
|
||||||
|
for (var i = 0; i < bufferInfos.length ; i++) {
|
||||||
|
var bufferId = bufferInfos[i].pointers[0];
|
||||||
|
var buffer = models.getBuffer(bufferId);
|
||||||
|
if (buffer !== undefined) {
|
||||||
|
// We already know this buffer
|
||||||
|
handleBufferUpdate(buffer, bufferInfos[i]);
|
||||||
|
} else {
|
||||||
|
buffer = new models.Buffer(bufferInfos[i]);
|
||||||
|
models.addBuffer(buffer);
|
||||||
|
// Switch to first buffer on startup
|
||||||
|
if (i === 0) {
|
||||||
|
models.setActiveBuffer(buffer.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var handleBufferUpdate = function(buffer, message) {
|
||||||
|
if (message.pointers[0] !== buffer.id) {
|
||||||
|
// this is information about some other buffer!
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// weechat properties -- short name can be changed
|
||||||
|
buffer.shortName = message.short_name;
|
||||||
|
buffer.trimmedName = buffer.shortName.replace(/^[#&+]/, '');
|
||||||
|
buffer.title = message.title;
|
||||||
|
buffer.number = message.number;
|
||||||
|
|
||||||
|
// reset these, hotlist info will arrive shortly
|
||||||
|
buffer.notification = 0;
|
||||||
|
buffer.unread = 0;
|
||||||
|
buffer.lastSeen = -1;
|
||||||
|
|
||||||
|
if (message.local_variables.type !== undefined) {
|
||||||
|
buffer.type = message.local_variables.type;
|
||||||
|
buffer.indent = (['channel', 'private'].indexOf(buffer.type) >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.notify !== undefined) {
|
||||||
|
buffer.notify = message.notify;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
var handleBufferLineAdded = function(message) {
|
var handleBufferLineAdded = function(message) {
|
||||||
message.objects[0].content.forEach(function(l) {
|
message.objects[0].content.forEach(function(l) {
|
||||||
handleLine(l, false);
|
handleLine(l, false);
|
||||||
|
@ -216,7 +263,8 @@ weechat.factory('handlers', ['$rootScope', '$log', 'models', 'plugins', 'notific
|
||||||
handleEvent: handleEvent,
|
handleEvent: handleEvent,
|
||||||
handleLineInfo: handleLineInfo,
|
handleLineInfo: handleLineInfo,
|
||||||
handleHotlistInfo: handleHotlistInfo,
|
handleHotlistInfo: handleHotlistInfo,
|
||||||
handleNicklist: handleNicklist
|
handleNicklist: handleNicklist,
|
||||||
|
handleBufferInfo: handleBufferInfo
|
||||||
};
|
};
|
||||||
|
|
||||||
}]);
|
}]);
|
||||||
|
|
|
@ -110,7 +110,6 @@ function($rootScope, $q) {
|
||||||
$rootScope.$emit('onMessage', message);
|
$rootScope.$emit('onMessage', message);
|
||||||
}
|
}
|
||||||
|
|
||||||
$rootScope.$apply();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var connect = function(url,
|
var connect = function(url,
|
||||||
|
|
Loading…
Reference in a new issue