blob: e56d40dcd6ac30e4d8bda403af136365b59dd517 [file] [log] [blame]
/*
* Copyright (c) 2013 DataTorrent, Inc. ALL Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*global settings, angular, google, jQuery, _, URI*/
(function () {
'use strict';
var chartOptions = {
legend: 'none',
vAxis: { format: settings.machine.metricformat },
chartArea: { top: 20, height: 240 }
};
function getEmptyChartOptionsFn(scope) {
return function () {
var now = Date.now();
var max = new Date(now);
var min = new Date(now - scope.lookback * 60 * 1000);
var options = jQuery.extend({}, chartOptions, {
vAxis: { minValue: 0, maxValue: 100 },
hAxis: { viewWindow: { min: min, max: max }}
});
return options;
};
}
function chartData(data, property) {
return _.map(data, function (obj) {
return {
timestamp: obj.timestamp,
value: obj[property]
};
});
}
function getRequestParams($scope) {
return {
customer: $scope.customer.value,
product: $scope.product.value,
os: $scope.os.value,
software1: $scope.software1.value,
software2: $scope.software2.value,
deviceId: $scope.deviceId.value,
lookback: $scope.lookback
};
}
function PollRequest (rest, scope, callback) {
this.rest = rest;
this.scope = scope;
this.max = scope.lookback;
this.dataCache = null;
this.callback = callback;
this.cancelled = false;
this.interval = null;
this.timeout = null;
this.params = getRequestParams(this.scope);
}
PollRequest.prototype = {
cancel: function () {
this.cancelled = true;
this.scope.requestProgress = 0;
clearInterval(this.interval);
clearTimeout(this.timeout);
},
responseStatus: function () {
this.scope.requestProgress = Math.round((Date.now() - this.requestStartTime) / 1000);
this.scope.$apply();
},
fetchMachineData: function () {
if (this.dataCache && this.dataCache.length) {
this.params.lastTimestamp = _.last(this.dataCache).timestamp;
}
var max = this.max;
this.requestStartTime = Date.now();
this.interval = setInterval(this.responseStatus.bind(this), 250);
var that = this;
this.rest.getMachineData(this.params).then(function (response) {
if (that.cancelled) {
return;
}
that.scope.response = response;
var minutes = response.minutes;
that.scope.requestProgress = 0;
clearInterval(that.interval);
var now = Date.now();
that.scope.lastResponse = new Date(now);
that.scope.responseTime = now - that.requestStartTime;
if (!that.dataCache) {
that.dataCache = minutes;
that.scope.minutesCached = 0;
that.scope.minutesReceived = minutes.length;
} else if (minutes.length > 0) {
that.scope.minutesCached = that.dataCache.length;
that.scope.minutesReceived = minutes.length;
that.dataCache.pop(); // remove last element since response should have new values for the last minute
var newlength = that.dataCache.length + minutes.length;
if (newlength > max) {
that.dataCache.splice(0, newlength - max);
}
that.dataCache.push.apply(that.dataCache, minutes); // add all elements
}
that.callback(that.dataCache);
var nextTimeout = settings.machine.pollInterval - (Date.now() - that.requestStartTime);
nextTimeout = Math.max(0, nextTimeout);
that.timeout = setTimeout(that.fetchMachineData.bind(that), nextTimeout);
},
function (errorResponse) {
that.cancel();
});
}
};
angular.module('machine')
.controller('MachineController', ['$scope', '$timeout', '$location', '$routeParams', 'rest', function ($scope, $timeout, $location, $routeParams, rest) {
var queryParams = new URI(window.location.href).query(true);
var emptyChartOptionsFn = getEmptyChartOptionsFn($scope);
rest.getApp(settings.machine.appName).then(function (app) {
$scope.app = app;
$scope.appURL = settings.appsURL + app.id;
});
$scope.cpu = 0;
$scope.ram = 0;
$scope.hdd = 0;
$scope.range = function (name) {
var r = settings.machine.range[name];
return _.range(r.start, r.stop + 1);
};
function setupSelect(name, label) {
var rangeValues = $scope.range(name);
var list = _.map(rangeValues, function (value) {
return {
value: String(value),
label: label + ' ' + value
};
});
list.splice(0, 0, { value: "", label: 'ALL '});
$scope.select[name] = list;
var selected = null;
if (queryParams[name]) {
selected = _.findWhere(list, { value: queryParams[name] });
}
if (selected) {
$scope[name] = selected;
} else {
$scope[name] = list[0];
}
}
$scope.select = {};
setupSelect('customer', 'Customer');
setupSelect('product', 'Product');
setupSelect('os', 'OS');
setupSelect('software1', 'Software1 Version');
setupSelect('software2', 'Software2 Version');
setupSelect('deviceId', 'Device ID');
$scope.lookback = queryParams.lookback ? parseInt(queryParams.lookback, 10) : settings.machine.lookback;
$scope.reload = function () {
//TODO have Angular route instead of reloading the page
window.location.href = window.location.pathname + '?' + jQuery.param(getRequestParams($scope));
};
function updateCharts(data) {
if (data && (data.length > 0)) {
var current = _.last(data);
$scope.cpu = parseFloat(current.cpu);
$scope.ram = parseFloat(current.ram);
$scope.hdd = parseFloat(current.hdd);
}
$scope.cpuChart = {
data: chartData(data, 'cpu'),
options: chartOptions,
emptyChartOptions: emptyChartOptionsFn
};
$scope.ramChart = {
data: chartData(data, 'ram'),
options: chartOptions,
emptyChartOptions: emptyChartOptionsFn
};
$scope.hddChart = {
data: chartData(data, 'hdd'),
options: chartOptions,
emptyChartOptions: emptyChartOptionsFn
};
}
$scope.cpuChart = {
emptyChartOptions: emptyChartOptionsFn
};
$scope.ramChart = {
emptyChartOptions: emptyChartOptionsFn
};
$scope.hddChart = {
emptyChartOptions: emptyChartOptionsFn
};
var request = null;
function reloadCharts() {
//TODO check if lookback is valid
if (request) {
request.cancel();
}
request = new PollRequest(rest, $scope, updateCharts);
request.fetchMachineData();
}
$scope.$watch('[customer, product, os, software1, software1, deviceId]', function () {
reloadCharts();
}, true);
var lookbackTimeout;
var firstUpdate = true;
$scope.$watch('lookback', function () {
if (!firstUpdate) { // skip first change since there is a watch for select fields
clearTimeout(lookbackTimeout);
lookbackTimeout = setTimeout(reloadCharts, 500);
} else {
firstUpdate = false;
}
});
// stop server polling on destroy (e.g. when navigating to another view)
$scope.$on('$destroy', function () {
if (request) {
request.cancel();
}
}.bind(this));
}]);
})();