From 2ccca016a5cb5e0c65d2168c01123f454537807d Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Fri, 14 Aug 2015 16:47:20 -0700 Subject: [PATCH] [Code Style] Use prototypes in telemetry bundle WTD-1482 --- platform/telemetry/src/TelemetryCapability.js | 263 ++++++++-------- platform/telemetry/src/TelemetryController.js | 1 + platform/telemetry/src/TelemetryDelegator.js | 61 ++-- platform/telemetry/src/TelemetryFormatter.js | 60 ++-- platform/telemetry/src/TelemetryHandler.js | 34 ++- platform/telemetry/src/TelemetryQueue.js | 86 +++--- platform/telemetry/src/TelemetrySubscriber.js | 59 ++-- .../telemetry/src/TelemetrySubscription.js | 289 +++++++++--------- platform/telemetry/src/TelemetryTable.js | 51 +--- 9 files changed, 443 insertions(+), 461 deletions(-) diff --git a/platform/telemetry/src/TelemetryCapability.js b/platform/telemetry/src/TelemetryCapability.js index 041379e497..1fbd12a691 100644 --- a/platform/telemetry/src/TelemetryCapability.js +++ b/platform/telemetry/src/TelemetryCapability.js @@ -42,154 +42,147 @@ define( * at the specific data which is appropriate to the domain object.) * * @memberof platform/telemetry + * @implements {Capability} * @constructor */ function TelemetryCapability($injector, $q, $log, domainObject) { - var telemetryService, - subscriptions = [], - unsubscribeFunction; - // We could depend on telemetryService directly, but - // there isn't a platform implementation of this; - function getTelemetryService() { - if (telemetryService === undefined) { - try { - telemetryService = - $injector.get("telemetryService"); - } catch (e) { - // $injector should throw if telemetryService - // is unavailable or unsatisfiable. - $log.warn("Telemetry service unavailable"); - telemetryService = null; - } + // there isn't a platform implementation of this. + this.initializeTelemetryService = function () { + try { + return (this.telemetryService = + $injector.get("telemetryService")); + } catch (e) { + // $injector should throw if telemetryService + // is unavailable or unsatisfiable. + $log.warn("Telemetry service unavailable"); + return (this.telemetryService = null); } - return telemetryService; - } - - // Build a request object. This takes the request that was - // passed to the capability, and adds source, id, and key - // fields associated with the object (from its type definition - // and/or its model) - function buildRequest(request) { - // Start with any "telemetry" field in type; use that as a - // basis for the request. - var type = domainObject.getCapability("type"), - typeRequest = (type && type.getDefinition().telemetry) || {}, - modelTelemetry = domainObject.getModel().telemetry, - fullRequest = Object.create(typeRequest); - - // Add properties from the telemetry field of this - // specific domain object. - Object.keys(modelTelemetry).forEach(function (k) { - fullRequest[k] = modelTelemetry[k]; - }); - - // Add properties from this specific requestData call. - Object.keys(request).forEach(function (k) { - fullRequest[k] = request[k]; - }); - - // Ensure an ID and key are present - if (!fullRequest.id) { - fullRequest.id = domainObject.getId(); - } - if (!fullRequest.key) { - fullRequest.key = domainObject.getId(); - } - - return fullRequest; - } - - // Issue a request for telemetry data - function requestTelemetry(request) { - // Bring in any defaults from the object model - var fullRequest = buildRequest(request || {}), - source = fullRequest.source, - key = fullRequest.key; - - // Pull out the relevant field from the larger, - // structured response. - function getRelevantResponse(response) { - return ((response || {})[source] || {})[key] || - EMPTY_SERIES; - } - - // Issue a request to the service - function requestTelemetryFromService() { - return telemetryService.requestTelemetry([fullRequest]); - } - - // If a telemetryService is not available, - // getTelemetryService() should reject, and this should - // bubble through subsequent then calls. - return getTelemetryService() && - requestTelemetryFromService() - .then(getRelevantResponse); - } - - // Listen for real-time and/or streaming updates - function subscribe(callback, request) { - var fullRequest = buildRequest(request || {}); - - // Unpack the relevant telemetry series - function update(telemetries) { - var source = fullRequest.source, - key = fullRequest.key, - result = ((telemetries || {})[source] || {})[key]; - if (result) { - callback(result); - } - } - - return getTelemetryService() && - telemetryService.subscribe(update, [fullRequest]); - } - - return { - /** - * Request telemetry data for this specific domain object. - * @param {TelemetryRequest} [request] parameters for this - * specific request - * @returns {Promise} a promise for the resulting telemetry - * object - * @memberof platform/telemetry.TelemetryCapability# - */ - requestData: requestTelemetry, - - /** - * Get metadata about this domain object's associated - * telemetry. - * @memberof platform/telemetry.TelemetryCapability# - */ - getMetadata: function () { - // metadata just looks like a request, - // so use buildRequest to bring in both - // type-level and object-level telemetry - // properties - return buildRequest({}); - }, - - /** - * Subscribe to updates to telemetry data for this domain - * object. - * @param {Function} callback a function to call when new - * data becomes available; the telemetry series - * containing the data will be given as an argument. - * @param {TelemetryRequest} [request] parameters for the - * subscription request - * @memberof platform/telemetry.TelemetryCapability# - */ - subscribe: subscribe }; + + + this.$q = $q; + this.$log = $log; + this.domainObject = domainObject; } + // Build a request object. This takes the request that was + // passed to the capability, and adds source, id, and key + // fields associated with the object (from its type definition + // and/or its model) + TelemetryCapability.prototype.buildRequest = function (request) { + // Start with any "telemetry" field in type; use that as a + // basis for the request. + var domainObject = this.domainObject, + type = domainObject.getCapability("type"), + typeRequest = (type && type.getDefinition().telemetry) || {}, + modelTelemetry = domainObject.getModel().telemetry, + fullRequest = Object.create(typeRequest); + + // Add properties from the telemetry field of this + // specific domain object. + Object.keys(modelTelemetry).forEach(function (k) { + fullRequest[k] = modelTelemetry[k]; + }); + + // Add properties from this specific requestData call. + Object.keys(request).forEach(function (k) { + fullRequest[k] = request[k]; + }); + + // Ensure an ID and key are present + if (!fullRequest.id) { + fullRequest.id = domainObject.getId(); + } + if (!fullRequest.key) { + fullRequest.key = domainObject.getId(); + } + + return fullRequest; + }; + + + /** + * Request telemetry data for this specific domain object. + * @param {TelemetryRequest} [request] parameters for this + * specific request + * @returns {Promise} a promise for the resulting telemetry + * object + */ + TelemetryCapability.prototype.requestData = function requestTelemetry(request) { + // Bring in any defaults from the object model + var fullRequest = this.buildRequest(request || {}), + source = fullRequest.source, + key = fullRequest.key, + telemetryService = this.telemetryService || + this.initializeTelemetryService(); // Lazy initialization + + // Pull out the relevant field from the larger, + // structured response. + function getRelevantResponse(response) { + return ((response || {})[source] || {})[key] || + EMPTY_SERIES; + } + + // Issue a request to the service + function requestTelemetryFromService() { + return telemetryService.requestTelemetry([fullRequest]); + } + + // If a telemetryService is not available, + // getTelemetryService() should reject, and this should + // bubble through subsequent then calls. + return telemetryService && + requestTelemetryFromService().then(getRelevantResponse); + }; + + /** + * Get metadata about this domain object's associated + * telemetry. + * @returns {TelemetryMetadata} metadata about this object's telemetry + */ + TelemetryCapability.prototype.getMetadata = function () { + // metadata just looks like a request, + // so use buildRequest to bring in both + // type-level and object-level telemetry + // properties + return (this.metadata = this.metadata || this.buildRequest({})); + }; + + /** + * Subscribe to updates to telemetry data for this domain + * object. + * @param {Function} callback a function to call when new + * data becomes available; the telemetry series + * containing the data will be given as an argument. + * @param {TelemetryRequest} [request] parameters for the + * subscription request + */ + TelemetryCapability.prototype.subscribe = function subscribe(callback, request) { + var fullRequest = this.buildRequest(request || {}), + telemetryService = this.telemetryService || + this.initializeTelemetryService(); // Lazy initialization + + // Unpack the relevant telemetry series + function update(telemetries) { + var source = fullRequest.source, + key = fullRequest.key, + result = ((telemetries || {})[source] || {})[key]; + if (result) { + callback(result); + } + } + + return telemetryService && + telemetryService.subscribe(update, [fullRequest]); + }; + /** * The telemetry capability is applicable when a * domain object model has a "telemetry" field. */ TelemetryCapability.appliesTo = function (model) { - return (model && - model.telemetry) ? true : false; + return (model && model.telemetry) ? true : false; }; return TelemetryCapability; diff --git a/platform/telemetry/src/TelemetryController.js b/platform/telemetry/src/TelemetryController.js index 3334baf48d..83279252d5 100644 --- a/platform/telemetry/src/TelemetryController.js +++ b/platform/telemetry/src/TelemetryController.js @@ -36,6 +36,7 @@ define( * * @memberof platform/telemetry * @constructor + * @deprecated use platform/telemetry.TelemetryHandler instead */ function TelemetryController($scope, $q, $timeout, $log) { diff --git a/platform/telemetry/src/TelemetryDelegator.js b/platform/telemetry/src/TelemetryDelegator.js index 865503154d..37fd1bedbf 100644 --- a/platform/telemetry/src/TelemetryDelegator.js +++ b/platform/telemetry/src/TelemetryDelegator.js @@ -33,37 +33,40 @@ define( * @memberof platform/telemetry */ function TelemetryDelegator($q) { - return { - /** - * Promise telemetry-providing objects associated with - * this domain object (either the domain object itself, - * or the objects it delegates) - * @returns {Promise.} domain objects with - * a telemetry capability - * @memberof platform/telemetry.TelemetryDelegator# - */ - promiseTelemetryObjects: function (domainObject) { - // If object has been cleared, there are no relevant - // telemetry-providing domain objects. - if (!domainObject) { - return $q.when([]); - } - - // Otherwise, try delegation first, and attach the - // object itself if it has a telemetry capability. - return $q.when(domainObject.useCapability( - "delegation", - "telemetry" - )).then(function (result) { - var head = domainObject.hasCapability("telemetry") ? - [ domainObject ] : [], - tail = result || []; - return head.concat(tail); - }); - } - }; + this.$q = $q; } + /** + * Promise telemetry-providing objects associated with + * this domain object (either the domain object itself, + * or the objects it delegates) + * @param {DomainObject} the domain object which may have + * or delegate telemetry + * @returns {Promise.} domain objects with + * a telemetry capability + */ + TelemetryDelegator.prototype.promiseTelemetryObjects = function (domainObject) { + var $q = this.$q; + + // If object has been cleared, there are no relevant + // telemetry-providing domain objects. + if (!domainObject) { + return $q.when([]); + } + + // Otherwise, try delegation first, and attach the + // object itself if it has a telemetry capability. + return $q.when(domainObject.useCapability( + "delegation", + "telemetry" + )).then(function (result) { + var head = domainObject.hasCapability("telemetry") ? + [ domainObject ] : [], + tail = result || []; + return head.concat(tail); + }); + }; + return TelemetryDelegator; } ); diff --git a/platform/telemetry/src/TelemetryFormatter.js b/platform/telemetry/src/TelemetryFormatter.js index 277ad0ca24..bbd4cf100c 100644 --- a/platform/telemetry/src/TelemetryFormatter.js +++ b/platform/telemetry/src/TelemetryFormatter.js @@ -39,41 +39,35 @@ define( * @constructor */ function TelemetryFormatter() { - function formatDomainValue(v, key) { - return isNaN(v) ? "" : moment.utc(v).format(DATE_FORMAT); - } - - function formatRangeValue(v, key) { - return isNaN(v) ? v : v.toFixed(3); - } - - return { - /** - * Format a domain value. - * @param {number} v the domain value; a timestamp - * in milliseconds since start of 1970 - * @param {string} [key] the key which identifies the - * domain; if unspecified or unknown, this will - * be treated as a standard timestamp. - * @returns {string} a textual representation of the - * data and time, suitable for display. - * @memberof platform/telemetry.TelemetryFormatter# - */ - formatDomainValue: formatDomainValue, - /** - * Format a range value. - * @param {number} v the range value; a numeric value - * @param {string} [key] the key which identifies the - * range; if unspecified or unknown, this will - * be treated as a numeric value. - * @returns {string} a textual representation of the - * value, suitable for display. - * @memberof platform/telemetry.TelemetryFormatter# - */ - formatRangeValue: formatRangeValue - }; } + /** + * Format a domain value. + * @param {number} v the domain value; a timestamp + * in milliseconds since start of 1970 + * @param {string} [key] the key which identifies the + * domain; if unspecified or unknown, this will + * be treated as a standard timestamp. + * @returns {string} a textual representation of the + * data and time, suitable for display. + */ + TelemetryFormatter.prototype.formatDomainValue = function (v, key) { + return isNaN(v) ? "" : moment.utc(v).format(DATE_FORMAT); + }; + + /** + * Format a range value. + * @param {number} v the range value; a numeric value + * @param {string} [key] the key which identifies the + * range; if unspecified or unknown, this will + * be treated as a numeric value. + * @returns {string} a textual representation of the + * value, suitable for display. + */ + TelemetryFormatter.prototype.formatRangeValue = function (v, key) { + return isNaN(v) ? String(v) : v.toFixed(VALUE_FORMAT_DIGITS); + }; + return TelemetryFormatter; } ); diff --git a/platform/telemetry/src/TelemetryHandler.js b/platform/telemetry/src/TelemetryHandler.js index f600f52cb7..cd0df98724 100644 --- a/platform/telemetry/src/TelemetryHandler.js +++ b/platform/telemetry/src/TelemetryHandler.js @@ -36,19 +36,31 @@ define( * @param $q Angular's $q */ function TelemetryHandler($q, telemetrySubscriber) { - return { - handle: function (domainObject, callback, lossless) { - var subscription = telemetrySubscriber.subscribe( - domainObject, - callback, - lossless - ); - - return new TelemetryHandle($q, subscription); - } - }; + this.$q = $q; + this.telemetrySubscriber = telemetrySubscriber; } + /** + * Start receiving telemetry associated with this domain object + * (either directly, or via delegation.) + * @param {DomainObject} domainObject the domain object + * @param {Function} callback callback to invoke when new data is + * available + * @param {boolean} lossless true if the callback should be invoked + * one separate time for each new latest value + * @returns {TelemetryHandle} a handle to telemetry data + * associated with this object + */ + TelemetryHandler.prototype.handle = function (domainObject, callback, lossless) { + var subscription = this.telemetrySubscriber.subscribe( + domainObject, + callback, + lossless + ); + + return new TelemetryHandle(this.$q, subscription); + }; + return TelemetryHandler; } diff --git a/platform/telemetry/src/TelemetryQueue.js b/platform/telemetry/src/TelemetryQueue.js index b5da77d717..d51c42a98f 100644 --- a/platform/telemetry/src/TelemetryQueue.js +++ b/platform/telemetry/src/TelemetryQueue.js @@ -34,6 +34,7 @@ define( * objects.) * @memberof platform/telemetry * @constructor + * @implements {platform/telemetry.TelemetryPool} */ function TelemetryQueue() { // General approach here: @@ -60,9 +61,37 @@ define( // 0 1 2 3 4 // a * * * * * // b * * * - // c * * * - var queue = [], - counts = {}; + // c * * * + + this.queue = []; + this.counts = {}; + } + + + TelemetryQueue.prototype.isEmpty = function () { + return this.queue.length < 1; + }; + + TelemetryQueue.prototype.poll = function () { + var counts = this.counts; + + // Decrement counts for a specific key + function decrementCount(key) { + if (counts[key] < 2) { + delete counts[key]; + } else { + counts[key] -= 1; + } + } + + // Decrement counts for the object that will be popped + Object.keys(counts).forEach(decrementCount); + return this.queue.shift(); + }; + + TelemetryQueue.prototype.put = function (key, value) { + var queue = this.queue, + counts = this.counts; // Look up an object in the queue that does not have a value // assigned to this key (or, add a new one) @@ -71,7 +100,7 @@ define( // Track the largest free position for this key counts[key] = index + 1; - + // If it's before the end of the queue, add it there if (index < queue.length) { return queue[index]; @@ -84,54 +113,9 @@ define( queue.push(object); return object; } - - // Decrement counts for a specific key - function decrementCount(key) { - if (counts[key] < 2) { - delete counts[key]; - } else { - counts[key] -= 1; - } - } - - // Decrement all counts - function decrementCounts() { - Object.keys(counts).forEach(decrementCount); - } - return { - /** - * Check if any value groups remain in this pool. - * @return {boolean} true if value groups remain - * @memberof platform/telemetry.TelemetryQueue# - */ - isEmpty: function () { - return queue.length < 1; - }, - /** - * Retrieve the next value group from this pool. - * This gives an object containing key-value pairs, - * where keys and values correspond to the arguments - * given to previous put functions. - * @return {object} key-value pairs - * @memberof platform/telemetry.TelemetryQueue# - */ - poll: function () { - // Decrement counts for the object that will be popped - decrementCounts(); - return queue.shift(); - }, - /** - * Put a key-value pair into the pool. - * @param {string} key the key to store the value under - * @param {*} value the value to store - * @memberof platform/telemetry.TelemetryQueue# - */ - put: function (key, value) { - getFreeObject(key)[key] = value; - } - }; - } + getFreeObject(key)[key] = value; + }; return TelemetryQueue; } diff --git a/platform/telemetry/src/TelemetrySubscriber.js b/platform/telemetry/src/TelemetrySubscriber.js index 7f8a6fd58e..c6e7ec0bf1 100644 --- a/platform/telemetry/src/TelemetrySubscriber.js +++ b/platform/telemetry/src/TelemetrySubscriber.js @@ -44,39 +44,36 @@ define( * @param $timeout Angular's $timeout */ function TelemetrySubscriber($q, $timeout) { - return { - /** - * Subscribe to streaming telemetry updates - * associated with this domain object (either - * directly or via capability delegation.) - * - * @param {DomainObject} domainObject the object whose - * associated telemetry data is of interest - * @param {Function} callback a function to invoke - * when new data has become available. - * @param {boolean} lossless flag to indicate whether the - * callback should be notified for all values - * (otherwise, multiple values in quick succession - * will call back with only the latest value.) - * @returns {TelemetrySubscription} the subscription, - * which will provide access to latest values. - * - * @method - * @memberof TelemetrySubscriber - * @memberof platform/telemetry.TelemetrySubscriber# - */ - subscribe: function (domainObject, callback, lossless) { - return new TelemetrySubscription( - $q, - $timeout, - domainObject, - callback, - lossless - ); - } - }; + this.$q = $q; + this.$timeout = $timeout; } + /** + * Subscribe to streaming telemetry updates + * associated with this domain object (either + * directly or via capability delegation.) + * + * @param {DomainObject} domainObject the object whose + * associated telemetry data is of interest + * @param {Function} callback a function to invoke + * when new data has become available. + * @param {boolean} lossless flag to indicate whether the + * callback should be notified for all values + * (otherwise, multiple values in quick succession + * will call back with only the latest value.) + * @returns {platform/telemetry.TelemetrySubscription} the + * subscription, which will provide access to latest values. + */ + TelemetrySubscriber.prototype.subscribe = function (domainObject, callback, lossless) { + return new TelemetrySubscription( + this.$q, + this.$timeout, + domainObject, + callback, + lossless + ); + }; + return TelemetrySubscriber; } ); diff --git a/platform/telemetry/src/TelemetrySubscription.js b/platform/telemetry/src/TelemetrySubscription.js index b4ecdd4770..8b4d7d7a9c 100644 --- a/platform/telemetry/src/TelemetrySubscription.js +++ b/platform/telemetry/src/TelemetrySubscription.js @@ -26,6 +26,32 @@ define( function (TelemetryQueue, TelemetryTable, TelemetryDelegator) { "use strict"; + /** + * A pool of telemetry values. + * @interface platform/telemetry.TelemetryPool + * @private + */ + /** + * Check if any value groups remain in this pool. + * @return {boolean} true if value groups remain + * @method platform/telemetry.TelemetryPool#isEmpty + */ + /** + * Retrieve the next value group from this pool. + * This gives an object containing key-value pairs, + * where keys and values correspond to the arguments + * given to previous put functions. + * @return {object} key-value pairs + * @method platform/telemetry.TelemetryPool#poll + */ + /** + * Put a key-value pair into the pool. + * @param {string} key the key to store the value under + * @param {*} value the value to store + * @method platform/telemetry.TelemetryPool#put + */ + + /** * A TelemetrySubscription tracks latest values for streaming * telemetry data and handles notifying interested observers. @@ -52,14 +78,9 @@ define( * the callback once, with access to the latest data */ function TelemetrySubscription($q, $timeout, domainObject, callback, lossless) { - var delegator = new TelemetryDelegator($q), - unsubscribePromise, - telemetryObjectPromise, - latestValues = {}, - telemetryObjects = [], + var self = this, + delegator = new TelemetryDelegator($q), pool = lossless ? new TelemetryQueue() : new TelemetryTable(), - metadatas, - unlistenToMutation, updatePending; // Look up domain objects which have telemetry capabilities. @@ -72,7 +93,7 @@ define( function updateValuesFromPool() { var values = pool.poll(); Object.keys(values).forEach(function (k) { - latestValues[k] = values[k]; + self.latestValues[k] = values[k]; }); } @@ -165,8 +186,8 @@ define( // initial subscription chain; this allows `getTelemetryObjects()` // to return a non-Promise to simplify usage elsewhere. function cacheObjectReferences(objects) { - telemetryObjects = objects; - metadatas = objects.map(lookupMetadata); + self.telemetryObjects = objects; + self.metadatas = objects.map(lookupMetadata); // Fire callback, as this will be the first time that // telemetry objects are available, or these objects // will have changed. @@ -176,14 +197,6 @@ define( return objects; } - function unsubscribeAll() { - return unsubscribePromise.then(function (unsubscribes) { - return $q.all(unsubscribes.map(function (unsubscribe) { - return unsubscribe(); - })); - }); - } - function initialize() { // Get a reference to relevant objects (those with telemetry // capabilities) and subscribe to their telemetry updates. @@ -191,23 +204,23 @@ define( // will be unsubscribe functions. (This must be a promise // because delegation is supported, and retrieving delegate // telemetry-capable objects may be an asynchronous operation.) - telemetryObjectPromise = promiseRelevantObjects(domainObject); - unsubscribePromise = telemetryObjectPromise + self.telemetryObjectPromise = promiseRelevantObjects(domainObject); + self.unsubscribePromise = self.telemetryObjectPromise .then(cacheObjectReferences) .then(subscribeAll); } function idsMatch(ids) { - return ids.length === telemetryObjects.length && + return ids.length === self.telemetryObjects.length && ids.every(function (id, index) { - return telemetryObjects[index].getId() === id; + return self.telemetryObjects[index].getId() === id; }); } function modelChange(model) { if (!idsMatch((model || {}).composition || [])) { // Reinitialize if composition has changed - unsubscribeAll().then(initialize); + self.unsubscribeAll().then(initialize); } } @@ -219,122 +232,126 @@ define( } } - initialize(); - unlistenToMutation = addMutationListener(); + this.$q = $q; + this.latestValues = {}; + this.telemetryObjects = []; + this.metadatas = []; - return { - /** - * Terminate all underlying subscriptions associated - * with this object. - * @method - * @memberof TelemetrySubscription - * @memberof platform/telemetry.TelemetrySubscription# - */ - unsubscribe: function () { - if (unlistenToMutation) { - unlistenToMutation(); - } - return unsubscribeAll(); - }, - /** - * Get the most recent domain value that has been observed - * for the specified domain object. This will typically be - * a timestamp. - * - * The domain object passed here should be one that is - * subscribed-to here; that is, it should be one of the - * domain objects returned by `getTelemetryObjects()`. - * - * @param {DomainObject} domainObject the object of interest - * @returns the most recent domain value observed - * @method - * @memberof TelemetrySubscription - * @memberof platform/telemetry.TelemetrySubscription# - */ - getDomainValue: function (domainObject) { - var id = domainObject.getId(); - return (latestValues[id] || {}).domain; - }, - /** - * Get the most recent range value that has been observed - * for the specified domain object. This will typically - * be a numeric measurement. - * - * The domain object passed here should be one that is - * subscribed-to here; that is, it should be one of the - * domain objects returned by `getTelemetryObjects()`. - * - * @param {DomainObject} domainObject the object of interest - * @returns the most recent range value observed - * @method - * @memberof TelemetrySubscription - * @memberof platform/telemetry.TelemetrySubscription# - */ - getRangeValue: function (domainObject) { - var id = domainObject.getId(); - return (latestValues[id] || {}).range; - }, - /** - * Get the latest telemetry datum for this domain object. - * - * @param {DomainObject} domainObject the object of interest - * @returns {TelemetryDatum} the most recent datum - * @memberof platform/telemetry.TelemetrySubscription# - */ - getDatum: function (domainObject) { - var id = domainObject.getId(); - return (latestValues[id] || {}).datum; - }, - /** - * Get all telemetry-providing domain objects which are - * being observed as part of this subscription. - * - * Capability delegation will be taken into account (so, if - * a Telemetry Panel was passed in the constructor, this will - * return its contents.) Capability delegation is resolved - * asynchronously so the return value here may change over - * time; while this resolution is pending, this method will - * return an empty array. - * - * @returns {DomainObject[]} all subscribed-to domain objects - * @method - * @memberof TelemetrySubscription - * @memberof platform/telemetry.TelemetrySubscription# - */ - getTelemetryObjects: function () { - return telemetryObjects; - }, - /** - * Get all telemetry metadata associated with - * telemetry-providing domain objects managed by - * this controller. - * - * This will ordered in the - * same manner as `getTelemetryObjects()` or - * `getResponse()`; that is, the metadata at a - * given index will correspond to the telemetry-providing - * domain object at the same index. - * @returns {Array} an array of metadata objects - * @memberof platform/telemetry.TelemetrySubscription# - */ - getMetadata: function () { - return metadatas; - }, - /** - * Get a promise for all telemetry-providing objects - * associated with this subscription. - * @returns {Promise.} a promise for - * telemetry-providing objects - * @memberof platform/telemetry.TelemetrySubscription# - */ - promiseTelemetryObjects: function () { - // Unsubscribe promise is available after objects - // are loaded. - return telemetryObjectPromise; - } - }; + initialize(); + this.unlistenToMutation = addMutationListener(); } + TelemetrySubscription.prototype.unsubscribeAll = function () { + var $q = this.$q; + return this.unsubscribePromise.then(function (unsubscribes) { + return $q.all(unsubscribes.map(function (unsubscribe) { + return unsubscribe(); + })); + }); + }; + + /** + * Terminate all underlying subscriptions associated + * with this object. + */ + TelemetrySubscription.prototype.unsubscribe = function () { + if (this.unlistenToMutation) { + this.unlistenToMutation(); + } + return this.unsubscribeAll(); + }; + + /** + * Get the most recent domain value that has been observed + * for the specified domain object. This will typically be + * a timestamp. + * + * The domain object passed here should be one that is + * subscribed-to here; that is, it should be one of the + * domain objects returned by `getTelemetryObjects()`. + * + * @param {DomainObject} domainObject the object of interest + * @returns the most recent domain value observed + */ + TelemetrySubscription.prototype.getDomainValue = function (domainObject) { + var id = domainObject.getId(); + return (this.latestValues[id] || {}).domain; + }; + + /** + * Get the most recent range value that has been observed + * for the specified domain object. This will typically + * be a numeric measurement. + * + * The domain object passed here should be one that is + * subscribed-to here; that is, it should be one of the + * domain objects returned by `getTelemetryObjects()`. + * + * @param {DomainObject} domainObject the object of interest + * @returns the most recent range value observed + */ + TelemetrySubscription.prototype.getRangeValue = function (domainObject) { + var id = domainObject.getId(); + return (this.latestValues[id] || {}).range; + }; + + /** + * Get the latest telemetry datum for this domain object. + * + * @param {DomainObject} domainObject the object of interest + * @returns {TelemetryDatum} the most recent datum + */ + TelemetrySubscription.prototype.getDatum = function (domainObject) { + var id = domainObject.getId(); + return (this.latestValues[id] || {}).datum; + }; + + /** + * Get all telemetry-providing domain objects which are + * being observed as part of this subscription. + * + * Capability delegation will be taken into account (so, if + * a Telemetry Panel was passed in the constructor, this will + * return its contents.) Capability delegation is resolved + * asynchronously so the return value here may change over + * time; while this resolution is pending, this method will + * return an empty array. + * + * @returns {DomainObject[]} all subscribed-to domain objects + */ + TelemetrySubscription.prototype.getTelemetryObjects = function () { + return this.telemetryObjects; + }; + + /** + * Get all telemetry metadata associated with + * telemetry-providing domain objects managed by + * this controller. + * + * This will ordered in the + * same manner as `getTelemetryObjects()` or + * `getResponse()`; that is, the metadata at a + * given index will correspond to the telemetry-providing + * domain object at the same index. + * @returns {TelemetryMetadata[]} an array of metadata objects + */ + TelemetrySubscription.prototype.getMetadata = function () { + return this.metadatas; + }; + + /** + * Get a promise for all telemetry-providing objects + * associated with this subscription. + * @returns {Promise.} a promise for + * telemetry-providing objects + * @memberof platform/telemetry.TelemetrySubscription# + */ + TelemetrySubscription.prototype.promiseTelemetryObjects = function () { + // Unsubscribe promise is available after objects + // are loaded. + return this.telemetryObjectPromise; + }; + return TelemetrySubscription; } diff --git a/platform/telemetry/src/TelemetryTable.js b/platform/telemetry/src/TelemetryTable.js index c992a3ec18..2cfcf8823d 100644 --- a/platform/telemetry/src/TelemetryTable.js +++ b/platform/telemetry/src/TelemetryTable.js @@ -34,45 +34,26 @@ define( * values. * @memberof platform/telemetry * @constructor + * @implements {platform/telemetry.TelemetryPool} */ function TelemetryTable() { - var table; - - return { - /** - * Check if any value groups remain in this pool. - * @return {boolean} true if value groups remain - * @memberof platform/telemetry.TelemetryTable# - */ - isEmpty: function () { - return !table; - }, - /** - * Retrieve the next value group from this pool. - * This gives an object containing key-value pairs, - * where keys and values correspond to the arguments - * given to previous put functions. - * @return {object} key-value pairs - * @memberof platform/telemetry.TelemetryTable# - */ - poll: function () { - var t = table; - table = undefined; - return t; - }, - /** - * Put a key-value pair into the pool. - * @param {string} key the key to store the value under - * @param {*} value the value to store - * @memberof platform/telemetry.TelemetryTable# - */ - put: function (key, value) { - table = table || {}; - table[key] = value; - } - }; } + TelemetryTable.prototype.isEmpty = function () { + return !this.table; + }; + + TelemetryTable.prototype.poll = function () { + var t = this.table; + this.table = undefined; + return t; + }; + + TelemetryTable.prototype.put = function (key, value) { + this.table = this.table || {}; + this.table[key] = value; + }; + return TelemetryTable; } );