mirror of
https://github.com/nasa/openmct.git
synced 2025-01-19 11:17:04 +00:00
[Telemetry] Add JSDoc
Add JSDoc and in-line comments to scripts in the platform/telemetry bundle, for WTD-575.
This commit is contained in:
parent
f8a0544435
commit
55c2d15cdc
@ -9,17 +9,20 @@ define(
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* A telemetry aggregator makes many telemetry providers
|
||||
* appear as one.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function TelemetryAggregator($q, telemetryProviders) {
|
||||
|
||||
// Merge the results from many providers into one
|
||||
// result object.
|
||||
function mergeResults(results) {
|
||||
var merged = {};
|
||||
|
||||
results.forEach(function (result) {
|
||||
Object.keys(result).forEach(function (k) {
|
||||
// Otherwise, just take the result
|
||||
merged[k] = result[k];
|
||||
});
|
||||
});
|
||||
@ -27,6 +30,8 @@ define(
|
||||
return merged;
|
||||
}
|
||||
|
||||
// Request telemetry from all providers; once they've
|
||||
// responded, merge the results into one result object.
|
||||
function requestTelemetry(requests) {
|
||||
return $q.all(telemetryProviders.map(function (provider) {
|
||||
return provider.requestTelemetry(requests);
|
||||
@ -34,6 +39,14 @@ define(
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* Request telemetry data.
|
||||
* @param {TelemetryRequest[]} requests and array of
|
||||
* requests to be handled
|
||||
* @returns {Promise} a promise for telemetry data
|
||||
* which may (or may not, depending on
|
||||
* availability) satisfy the requests
|
||||
*/
|
||||
requestTelemetry: requestTelemetry
|
||||
};
|
||||
}
|
||||
|
@ -9,6 +9,9 @@ define(
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* A telemetry capability provides a means of requesting telemetry
|
||||
* for a specific object, and for unwrapping the response (to get
|
||||
* at the specific data which is appropriate to the domain object.)
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
@ -23,6 +26,8 @@ define(
|
||||
telemetryService =
|
||||
$q.when($injector.get("telemetryService"));
|
||||
} catch (e) {
|
||||
// $injector should throw is telemetryService
|
||||
// is unavailable or unsatisfiable.
|
||||
$log.warn("Telemetry service unavailable");
|
||||
telemetryService = $q.reject(e);
|
||||
}
|
||||
@ -30,21 +35,30 @@ define(
|
||||
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];
|
||||
});
|
||||
|
||||
// Include domain object ID, at minimum
|
||||
// Ensure an ID and key are present
|
||||
if (!fullRequest.id) {
|
||||
fullRequest.id = domainObject.getId();
|
||||
}
|
||||
@ -55,37 +69,63 @@ define(
|
||||
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] || {};
|
||||
}
|
||||
|
||||
// Issue a request to the service
|
||||
function requestTelemetryFromService(telemetryService) {
|
||||
return telemetryService.requestTelemetry([fullRequest]);
|
||||
}
|
||||
|
||||
// If a telemetryService is not available,
|
||||
// getTelemetryService() should reject, and this should
|
||||
// bubble through subsequent then calls.
|
||||
return getTelemetryService()
|
||||
.then(requestTelemetryFromService)
|
||||
.then(getRelevantResponse);
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
requestData: requestTelemetry,
|
||||
|
||||
/**
|
||||
* Get metadata about this domain object's associated
|
||||
* telemetry.
|
||||
*/
|
||||
getMetadata: function () {
|
||||
// metadata just looks like a request,
|
||||
// so use buildRequest to bring in both
|
||||
// type-level and object-level telemetry
|
||||
// properties
|
||||
return buildRequest({});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* The telemetry capability is applicable when a
|
||||
* domain object model has a "telemetry" field.
|
||||
*/
|
||||
TelemetryCapability.appliesTo = function (model) {
|
||||
return (model &&
|
||||
model.telemetry &&
|
||||
model.telemetry.source) ? true : false;
|
||||
model.telemetry) ? true : false;
|
||||
};
|
||||
|
||||
return TelemetryCapability;
|
||||
|
@ -17,19 +17,44 @@ define(
|
||||
*/
|
||||
function TelemetryController($scope, $q, $timeout, $log) {
|
||||
|
||||
// Private to maintain in this scope
|
||||
var self = {
|
||||
// IDs of domain objects with telemetry
|
||||
ids: [],
|
||||
|
||||
// Containers for latest responses (id->response)
|
||||
// Used internally; see buildResponseContainer
|
||||
// for format
|
||||
response: {},
|
||||
|
||||
// Request fields (id->requests)
|
||||
request: {},
|
||||
|
||||
// Number of outstanding requests
|
||||
pending: 0,
|
||||
|
||||
// Array of object metadatas, for easy retrieval
|
||||
metadatas: [],
|
||||
|
||||
// Interval at which to poll for new data
|
||||
interval: 1000,
|
||||
|
||||
// Flag tracking whether or not a request
|
||||
// is in progress
|
||||
refreshing: false,
|
||||
|
||||
// Used to track whether a new telemetryUpdate
|
||||
// is being issued.
|
||||
broadcasting: false
|
||||
};
|
||||
|
||||
|
||||
// Broadcast that a telemetryUpdate has occurred.
|
||||
function doBroadcast() {
|
||||
// This may get called multiple times from
|
||||
// multiple objects, so set a flag to suppress
|
||||
// multiple simultaneous events from being
|
||||
// broadcast, then issue the actual broadcast
|
||||
// later (via $timeout)
|
||||
if (!self.broadcasting) {
|
||||
self.broadcasting = true;
|
||||
$timeout(function () {
|
||||
@ -39,11 +64,14 @@ define(
|
||||
}
|
||||
}
|
||||
|
||||
// Issue a request for new telemetry for one of the
|
||||
// objects being tracked by this controller
|
||||
function requestTelemetryForId(id, trackPending) {
|
||||
var responseObject = self.response[id],
|
||||
domainObject = responseObject.domainObject,
|
||||
telemetry = domainObject.getCapability('telemetry');
|
||||
|
||||
// Callback for when data comes back
|
||||
function storeData(data) {
|
||||
self.pending -= trackPending ? 1 : 0;
|
||||
responseObject.data = data;
|
||||
@ -52,30 +80,50 @@ define(
|
||||
|
||||
self.pending += trackPending ? 1 : 0;
|
||||
|
||||
// Shouldn't happen, but isn't fatal,
|
||||
// so warn.
|
||||
if (!telemetry) {
|
||||
$log.warn([
|
||||
"Expected telemetry capability for ",
|
||||
id,
|
||||
" but found none. Cannot request data."
|
||||
].join(""));
|
||||
|
||||
// Request won't happen, so don't
|
||||
// mark it as pending.
|
||||
self.pending -= trackPending ? 1 : 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Issue the request using the object's telemetry capability
|
||||
return $q.when(telemetry.requestData(self.request))
|
||||
.then(storeData);
|
||||
}
|
||||
|
||||
// Request telemetry for all objects tracked by this
|
||||
// controller. A flag is passed to indicate whether the
|
||||
// pending counter should be incremented (this will
|
||||
// cause isRequestPending() to change, which we only
|
||||
// want to happen for requests which have originated
|
||||
// outside of this controller's polling action.)
|
||||
function requestTelemetry(trackPending) {
|
||||
return $q.all(self.ids.map(function (id) {
|
||||
return requestTelemetryForId(id, trackPending);
|
||||
}));
|
||||
}
|
||||
|
||||
// Look up domain objects which have telemetry capabilities.
|
||||
// This will either be the object in view, or object that
|
||||
// this object delegates its telemetry capability to.
|
||||
function promiseRelevantDomainObjects(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"
|
||||
@ -87,6 +135,9 @@ define(
|
||||
});
|
||||
}
|
||||
|
||||
// Build the response containers that are used internally
|
||||
// by this controller to track latest responses, etc, for
|
||||
// a given domain object.
|
||||
function buildResponseContainer(domainObject) {
|
||||
var telemetry = domainObject &&
|
||||
domainObject.getCapability("telemetry"),
|
||||
@ -103,12 +154,17 @@ define(
|
||||
data: {}
|
||||
};
|
||||
} else {
|
||||
// Shouldn't happen, as we've checked for
|
||||
// telemetry capabilities previously, but
|
||||
// be defensive.
|
||||
$log.warn([
|
||||
"Expected telemetry capability for ",
|
||||
domainObject.getId(),
|
||||
" but none was found."
|
||||
].join(""));
|
||||
|
||||
// Create an empty container so subsequent
|
||||
// behavior won't hit an exception.
|
||||
self.response[domainObject.getId()] = {
|
||||
name: domainObject.getModel().name,
|
||||
domainObject: domainObject,
|
||||
@ -119,11 +175,21 @@ define(
|
||||
}
|
||||
}
|
||||
|
||||
// Build response containers (as above) for all
|
||||
// domain objects, and update some controller-internal
|
||||
// state to support subsequent calls.
|
||||
function buildResponseContainers(domainObjects) {
|
||||
// Build the containers
|
||||
domainObjects.forEach(buildResponseContainer);
|
||||
|
||||
// Maintain a list of relevant ids, to convert
|
||||
// back from dictionary-like container objects to arrays.
|
||||
self.ids = domainObjects.map(function (obj) {
|
||||
return obj.getId();
|
||||
});
|
||||
|
||||
// Keep a reference to all applicable metadata
|
||||
// to return from getMetadata
|
||||
self.metadatas = self.ids.map(function (id) {
|
||||
return self.response[id].metadata;
|
||||
});
|
||||
@ -135,11 +201,16 @@ define(
|
||||
}
|
||||
}
|
||||
|
||||
// Get relevant telemetry-providing domain objects
|
||||
// for the domain object which is represented in this
|
||||
// scope. This will be the domain object itself, or
|
||||
// its telemetry delegates, or both.
|
||||
function getTelemetryObjects(domainObject) {
|
||||
promiseRelevantDomainObjects(domainObject)
|
||||
.then(buildResponseContainers);
|
||||
}
|
||||
|
||||
// Handle a polling refresh interval
|
||||
function startTimeout() {
|
||||
if (!self.refreshing && self.interval !== undefined) {
|
||||
self.refreshing = true;
|
||||
@ -154,19 +225,58 @@ define(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Watch for a represented domain object
|
||||
$scope.$watch("domainObject", getTelemetryObjects);
|
||||
startTimeout(); // Begin refreshing
|
||||
|
||||
// Begin polling for data changes
|
||||
startTimeout();
|
||||
|
||||
return {
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
getMetadata: function () {
|
||||
return self.metadatas;
|
||||
},
|
||||
/**
|
||||
* Get all telemetry-providing domain objects managed by
|
||||
* this controller.
|
||||
*
|
||||
* This will ordered in the
|
||||
* same manner as `getMetadata()` or
|
||||
* `getResponse()`; that is, the metadata at a
|
||||
* given index will correspond to the telemetry-providing
|
||||
* domain object at the same index.
|
||||
* @returns {DomainObject[]} an array of metadata objects
|
||||
*/
|
||||
getTelemetryObjects: function () {
|
||||
return self.ids.map(function (id) {
|
||||
return self.response[id].domainObject;
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Get the latest telemetry response for a specific
|
||||
* domain object (if an argument is given) or for all
|
||||
* objects managed by this controller (if no argument
|
||||
* is supplied.)
|
||||
*
|
||||
* In the first form, this returns a single object; in
|
||||
* the second form, it returns an array ordered in
|
||||
* same manner as `getMetadata()` or
|
||||
* `getTelemetryObjects()`; that is, the telemetry
|
||||
* response at agiven index will correspond to the
|
||||
* telemetry-providing domain object at the same index.
|
||||
* @returns {Array} an array of responses
|
||||
*/
|
||||
getResponse: function getResponse(arg) {
|
||||
var id = arg && (typeof arg === 'string' ?
|
||||
arg : arg.getId());
|
||||
@ -177,13 +287,33 @@ define(
|
||||
|
||||
return (self.ids || []).map(getResponse);
|
||||
},
|
||||
/**
|
||||
* Check if the latest request (not counting
|
||||
* requests from TelemtryController's own polling)
|
||||
* is still outstanding. Users of the TelemetryController
|
||||
* may use this method as a condition upon which to
|
||||
* show user feedback, such as a wait spinner.
|
||||
*
|
||||
* @returns {boolean} true if the request is still outstanding
|
||||
*/
|
||||
isRequestPending: function () {
|
||||
return self.pending > 0;
|
||||
},
|
||||
/**
|
||||
* Issue a new data request. This will change the
|
||||
* request parameters that are passed along to all
|
||||
* telemetry capabilities managed by this controller.
|
||||
*/
|
||||
requestData: function (request) {
|
||||
self.request = request || {};
|
||||
return requestTelemetry(true);
|
||||
},
|
||||
/**
|
||||
* Change the interval at which this controller will
|
||||
* perform its polling activity.
|
||||
* @param {number} durationMillis the interval at
|
||||
* which to poll, in milliseconds
|
||||
*/
|
||||
setRefreshInterval: function (durationMillis) {
|
||||
self.interval = durationMillis;
|
||||
startTimeout();
|
||||
|
@ -65,9 +65,6 @@ define(
|
||||
expect(TelemetryCapability.appliesTo({
|
||||
telemetry: { source: "testSource" }
|
||||
})).toBeTruthy();
|
||||
expect(TelemetryCapability.appliesTo({
|
||||
telemetry: { xsource: "testSource" }
|
||||
})).toBeFalsy();
|
||||
expect(TelemetryCapability.appliesTo({
|
||||
xtelemetry: { source: "testSource" }
|
||||
})).toBeFalsy();
|
||||
|
Loading…
Reference in New Issue
Block a user