/** * Service which pings an endpoint URL and estimates the latency to it. */ angular.module('quay').factory('PingService', [function() { var pingService = {}; var pingCache = {}; var invokeCallback = function($scope, pings, callback) { if (pings[0] == -1) { setTimeout(function() { $scope.$apply(function() { callback(-1, false, -1); }); }, 0); return; } var sum = 0; for (var i = 0; i < pings.length; ++i) { sum += pings[i]; } // Report the average ping. setTimeout(function() { $scope.$apply(function() { callback(Math.floor(sum / pings.length), true, pings.length); }); }, 0); }; var reportPingResult = function($scope, url, ping, callback) { // Lookup the cached ping data, if any. var cached = pingCache[url]; if (!cached) { cached = pingCache[url] = { 'pings': [] }; } // If an error occurred, report it and done. if (ping < 0) { cached['pings'] = [-1]; invokeCallback($scope, [-1], callback); return; } // Otherwise, add the current ping and determine the average. cached['pings'].push(ping); // Invoke the callback. invokeCallback($scope, cached['pings'], callback); // Schedule another check if we've done less than three. if (cached['pings'].length < 3) { setTimeout(function() { pingUrlInternal($scope, url, callback); }, 1000); } }; var pingUrlInternal = function($scope, url, callback) { var path = url + '?cb=' + (Math.random() * 100); var start = new Date(); var xhr = new XMLHttpRequest(); xhr.onerror = function() { reportPingResult($scope, url, -1, callback); }; xhr.onreadystatechange = function () { if (xhr.readyState === xhr.HEADERS_RECEIVED) { if (xhr.status != 200) { reportPingResult($scope, url, -1, callback); return; } var ping = (new Date() - start); reportPingResult($scope, url, ping, callback); } }; xhr.open("GET", path); xhr.send(null); }; pingService.pingUrl = function($scope, url, callback) { if (pingCache[url]) { invokeCallback($scope, pingCache[url]['pings'], callback); return; } // Note: We do each in a callback after 1s to prevent it running when other code // runs (which can skew the results). setTimeout(function() { pingUrlInternal($scope, url, callback); }, 1000); }; return pingService; }]);