| /* |
| * 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)); |
| }]); |
| |
| })(); |