mirror of
https://github.com/nasa/openmct.git
synced 2025-01-31 16:36:13 +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";
|
"use strict";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* A telemetry aggregator makes many telemetry providers
|
||||||
|
* appear as one.
|
||||||
*
|
*
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function TelemetryAggregator($q, telemetryProviders) {
|
function TelemetryAggregator($q, telemetryProviders) {
|
||||||
|
|
||||||
|
// Merge the results from many providers into one
|
||||||
|
// result object.
|
||||||
function mergeResults(results) {
|
function mergeResults(results) {
|
||||||
var merged = {};
|
var merged = {};
|
||||||
|
|
||||||
results.forEach(function (result) {
|
results.forEach(function (result) {
|
||||||
Object.keys(result).forEach(function (k) {
|
Object.keys(result).forEach(function (k) {
|
||||||
// Otherwise, just take the result
|
|
||||||
merged[k] = result[k];
|
merged[k] = result[k];
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -27,6 +30,8 @@ define(
|
|||||||
return merged;
|
return merged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Request telemetry from all providers; once they've
|
||||||
|
// responded, merge the results into one result object.
|
||||||
function requestTelemetry(requests) {
|
function requestTelemetry(requests) {
|
||||||
return $q.all(telemetryProviders.map(function (provider) {
|
return $q.all(telemetryProviders.map(function (provider) {
|
||||||
return provider.requestTelemetry(requests);
|
return provider.requestTelemetry(requests);
|
||||||
@ -34,6 +39,14 @@ define(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
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
|
requestTelemetry: requestTelemetry
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,9 @@ define(
|
|||||||
"use strict";
|
"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
|
* @constructor
|
||||||
*/
|
*/
|
||||||
@ -23,6 +26,8 @@ define(
|
|||||||
telemetryService =
|
telemetryService =
|
||||||
$q.when($injector.get("telemetryService"));
|
$q.when($injector.get("telemetryService"));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
// $injector should throw is telemetryService
|
||||||
|
// is unavailable or unsatisfiable.
|
||||||
$log.warn("Telemetry service unavailable");
|
$log.warn("Telemetry service unavailable");
|
||||||
telemetryService = $q.reject(e);
|
telemetryService = $q.reject(e);
|
||||||
}
|
}
|
||||||
@ -30,21 +35,30 @@ define(
|
|||||||
return telemetryService;
|
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) {
|
function buildRequest(request) {
|
||||||
|
// Start with any "telemetry" field in type; use that as a
|
||||||
|
// basis for the request.
|
||||||
var type = domainObject.getCapability("type"),
|
var type = domainObject.getCapability("type"),
|
||||||
typeRequest = (type && type.getDefinition().telemetry) || {},
|
typeRequest = (type && type.getDefinition().telemetry) || {},
|
||||||
modelTelemetry = domainObject.getModel().telemetry,
|
modelTelemetry = domainObject.getModel().telemetry,
|
||||||
fullRequest = Object.create(typeRequest);
|
fullRequest = Object.create(typeRequest);
|
||||||
|
|
||||||
|
// Add properties from the telemetry field of this
|
||||||
|
// specific domain object.
|
||||||
Object.keys(modelTelemetry).forEach(function (k) {
|
Object.keys(modelTelemetry).forEach(function (k) {
|
||||||
fullRequest[k] = modelTelemetry[k];
|
fullRequest[k] = modelTelemetry[k];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Add properties from this specific requestData call.
|
||||||
Object.keys(request).forEach(function (k) {
|
Object.keys(request).forEach(function (k) {
|
||||||
fullRequest[k] = request[k];
|
fullRequest[k] = request[k];
|
||||||
});
|
});
|
||||||
|
|
||||||
// Include domain object ID, at minimum
|
// Ensure an ID and key are present
|
||||||
if (!fullRequest.id) {
|
if (!fullRequest.id) {
|
||||||
fullRequest.id = domainObject.getId();
|
fullRequest.id = domainObject.getId();
|
||||||
}
|
}
|
||||||
@ -55,37 +69,63 @@ define(
|
|||||||
return fullRequest;
|
return fullRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Issue a request for telemetry data
|
||||||
function requestTelemetry(request) {
|
function requestTelemetry(request) {
|
||||||
// Bring in any defaults from the object model
|
// Bring in any defaults from the object model
|
||||||
var fullRequest = buildRequest(request || {}),
|
var fullRequest = buildRequest(request || {}),
|
||||||
source = fullRequest.source,
|
source = fullRequest.source,
|
||||||
key = fullRequest.key;
|
key = fullRequest.key;
|
||||||
|
|
||||||
|
// Pull out the relevant field from the larger,
|
||||||
|
// structured response.
|
||||||
function getRelevantResponse(response) {
|
function getRelevantResponse(response) {
|
||||||
return ((response || {})[source] || {})[key] || {};
|
return ((response || {})[source] || {})[key] || {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Issue a request to the service
|
||||||
function requestTelemetryFromService(telemetryService) {
|
function requestTelemetryFromService(telemetryService) {
|
||||||
return telemetryService.requestTelemetry([fullRequest]);
|
return telemetryService.requestTelemetry([fullRequest]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If a telemetryService is not available,
|
||||||
|
// getTelemetryService() should reject, and this should
|
||||||
|
// bubble through subsequent then calls.
|
||||||
return getTelemetryService()
|
return getTelemetryService()
|
||||||
.then(requestTelemetryFromService)
|
.then(requestTelemetryFromService)
|
||||||
.then(getRelevantResponse);
|
.then(getRelevantResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
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,
|
requestData: requestTelemetry,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get metadata about this domain object's associated
|
||||||
|
* telemetry.
|
||||||
|
*/
|
||||||
getMetadata: function () {
|
getMetadata: function () {
|
||||||
|
// metadata just looks like a request,
|
||||||
|
// so use buildRequest to bring in both
|
||||||
|
// type-level and object-level telemetry
|
||||||
|
// properties
|
||||||
return buildRequest({});
|
return buildRequest({});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The telemetry capability is applicable when a
|
||||||
|
* domain object model has a "telemetry" field.
|
||||||
|
*/
|
||||||
TelemetryCapability.appliesTo = function (model) {
|
TelemetryCapability.appliesTo = function (model) {
|
||||||
return (model &&
|
return (model &&
|
||||||
model.telemetry &&
|
model.telemetry) ? true : false;
|
||||||
model.telemetry.source) ? true : false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return TelemetryCapability;
|
return TelemetryCapability;
|
||||||
|
@ -17,19 +17,44 @@ define(
|
|||||||
*/
|
*/
|
||||||
function TelemetryController($scope, $q, $timeout, $log) {
|
function TelemetryController($scope, $q, $timeout, $log) {
|
||||||
|
|
||||||
|
// Private to maintain in this scope
|
||||||
var self = {
|
var self = {
|
||||||
|
// IDs of domain objects with telemetry
|
||||||
ids: [],
|
ids: [],
|
||||||
|
|
||||||
|
// Containers for latest responses (id->response)
|
||||||
|
// Used internally; see buildResponseContainer
|
||||||
|
// for format
|
||||||
response: {},
|
response: {},
|
||||||
|
|
||||||
|
// Request fields (id->requests)
|
||||||
request: {},
|
request: {},
|
||||||
|
|
||||||
|
// Number of outstanding requests
|
||||||
pending: 0,
|
pending: 0,
|
||||||
|
|
||||||
|
// Array of object metadatas, for easy retrieval
|
||||||
metadatas: [],
|
metadatas: [],
|
||||||
|
|
||||||
|
// Interval at which to poll for new data
|
||||||
interval: 1000,
|
interval: 1000,
|
||||||
|
|
||||||
|
// Flag tracking whether or not a request
|
||||||
|
// is in progress
|
||||||
refreshing: false,
|
refreshing: false,
|
||||||
|
|
||||||
|
// Used to track whether a new telemetryUpdate
|
||||||
|
// is being issued.
|
||||||
broadcasting: false
|
broadcasting: false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Broadcast that a telemetryUpdate has occurred.
|
||||||
function doBroadcast() {
|
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) {
|
if (!self.broadcasting) {
|
||||||
self.broadcasting = true;
|
self.broadcasting = true;
|
||||||
$timeout(function () {
|
$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) {
|
function requestTelemetryForId(id, trackPending) {
|
||||||
var responseObject = self.response[id],
|
var responseObject = self.response[id],
|
||||||
domainObject = responseObject.domainObject,
|
domainObject = responseObject.domainObject,
|
||||||
telemetry = domainObject.getCapability('telemetry');
|
telemetry = domainObject.getCapability('telemetry');
|
||||||
|
|
||||||
|
// Callback for when data comes back
|
||||||
function storeData(data) {
|
function storeData(data) {
|
||||||
self.pending -= trackPending ? 1 : 0;
|
self.pending -= trackPending ? 1 : 0;
|
||||||
responseObject.data = data;
|
responseObject.data = data;
|
||||||
@ -52,30 +80,50 @@ define(
|
|||||||
|
|
||||||
self.pending += trackPending ? 1 : 0;
|
self.pending += trackPending ? 1 : 0;
|
||||||
|
|
||||||
|
// Shouldn't happen, but isn't fatal,
|
||||||
|
// so warn.
|
||||||
if (!telemetry) {
|
if (!telemetry) {
|
||||||
$log.warn([
|
$log.warn([
|
||||||
"Expected telemetry capability for ",
|
"Expected telemetry capability for ",
|
||||||
id,
|
id,
|
||||||
" but found none. Cannot request data."
|
" but found none. Cannot request data."
|
||||||
].join(""));
|
].join(""));
|
||||||
|
|
||||||
|
// Request won't happen, so don't
|
||||||
|
// mark it as pending.
|
||||||
|
self.pending -= trackPending ? 1 : 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Issue the request using the object's telemetry capability
|
||||||
return $q.when(telemetry.requestData(self.request))
|
return $q.when(telemetry.requestData(self.request))
|
||||||
.then(storeData);
|
.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) {
|
function requestTelemetry(trackPending) {
|
||||||
return $q.all(self.ids.map(function (id) {
|
return $q.all(self.ids.map(function (id) {
|
||||||
return requestTelemetryForId(id, trackPending);
|
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) {
|
function promiseRelevantDomainObjects(domainObject) {
|
||||||
|
// If object has been cleared, there are no relevant
|
||||||
|
// telemetry-providing domain objects.
|
||||||
if (!domainObject) {
|
if (!domainObject) {
|
||||||
return $q.when([]);
|
return $q.when([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Otherwise, try delegation first, and attach the
|
||||||
|
// object itself if it has a telemetry capability.
|
||||||
return $q.when(domainObject.useCapability(
|
return $q.when(domainObject.useCapability(
|
||||||
"delegation",
|
"delegation",
|
||||||
"telemetry"
|
"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) {
|
function buildResponseContainer(domainObject) {
|
||||||
var telemetry = domainObject &&
|
var telemetry = domainObject &&
|
||||||
domainObject.getCapability("telemetry"),
|
domainObject.getCapability("telemetry"),
|
||||||
@ -103,12 +154,17 @@ define(
|
|||||||
data: {}
|
data: {}
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
// Shouldn't happen, as we've checked for
|
||||||
|
// telemetry capabilities previously, but
|
||||||
|
// be defensive.
|
||||||
$log.warn([
|
$log.warn([
|
||||||
"Expected telemetry capability for ",
|
"Expected telemetry capability for ",
|
||||||
domainObject.getId(),
|
domainObject.getId(),
|
||||||
" but none was found."
|
" but none was found."
|
||||||
].join(""));
|
].join(""));
|
||||||
|
|
||||||
|
// Create an empty container so subsequent
|
||||||
|
// behavior won't hit an exception.
|
||||||
self.response[domainObject.getId()] = {
|
self.response[domainObject.getId()] = {
|
||||||
name: domainObject.getModel().name,
|
name: domainObject.getModel().name,
|
||||||
domainObject: domainObject,
|
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) {
|
function buildResponseContainers(domainObjects) {
|
||||||
|
// Build the containers
|
||||||
domainObjects.forEach(buildResponseContainer);
|
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) {
|
self.ids = domainObjects.map(function (obj) {
|
||||||
return obj.getId();
|
return obj.getId();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Keep a reference to all applicable metadata
|
||||||
|
// to return from getMetadata
|
||||||
self.metadatas = self.ids.map(function (id) {
|
self.metadatas = self.ids.map(function (id) {
|
||||||
return self.response[id].metadata;
|
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) {
|
function getTelemetryObjects(domainObject) {
|
||||||
promiseRelevantDomainObjects(domainObject)
|
promiseRelevantDomainObjects(domainObject)
|
||||||
.then(buildResponseContainers);
|
.then(buildResponseContainers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle a polling refresh interval
|
||||||
function startTimeout() {
|
function startTimeout() {
|
||||||
if (!self.refreshing && self.interval !== undefined) {
|
if (!self.refreshing && self.interval !== undefined) {
|
||||||
self.refreshing = true;
|
self.refreshing = true;
|
||||||
@ -154,19 +225,58 @@ define(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Watch for a represented domain object
|
||||||
$scope.$watch("domainObject", getTelemetryObjects);
|
$scope.$watch("domainObject", getTelemetryObjects);
|
||||||
startTimeout(); // Begin refreshing
|
|
||||||
|
// Begin polling for data changes
|
||||||
|
startTimeout();
|
||||||
|
|
||||||
return {
|
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 () {
|
getMetadata: function () {
|
||||||
return self.metadatas;
|
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 () {
|
getTelemetryObjects: function () {
|
||||||
return self.ids.map(function (id) {
|
return self.ids.map(function (id) {
|
||||||
return self.response[id].domainObject;
|
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) {
|
getResponse: function getResponse(arg) {
|
||||||
var id = arg && (typeof arg === 'string' ?
|
var id = arg && (typeof arg === 'string' ?
|
||||||
arg : arg.getId());
|
arg : arg.getId());
|
||||||
@ -177,13 +287,33 @@ define(
|
|||||||
|
|
||||||
return (self.ids || []).map(getResponse);
|
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 () {
|
isRequestPending: function () {
|
||||||
return self.pending > 0;
|
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) {
|
requestData: function (request) {
|
||||||
self.request = request || {};
|
self.request = request || {};
|
||||||
return requestTelemetry(true);
|
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) {
|
setRefreshInterval: function (durationMillis) {
|
||||||
self.interval = durationMillis;
|
self.interval = durationMillis;
|
||||||
startTimeout();
|
startTimeout();
|
||||||
|
@ -65,9 +65,6 @@ define(
|
|||||||
expect(TelemetryCapability.appliesTo({
|
expect(TelemetryCapability.appliesTo({
|
||||||
telemetry: { source: "testSource" }
|
telemetry: { source: "testSource" }
|
||||||
})).toBeTruthy();
|
})).toBeTruthy();
|
||||||
expect(TelemetryCapability.appliesTo({
|
|
||||||
telemetry: { xsource: "testSource" }
|
|
||||||
})).toBeFalsy();
|
|
||||||
expect(TelemetryCapability.appliesTo({
|
expect(TelemetryCapability.appliesTo({
|
||||||
xtelemetry: { source: "testSource" }
|
xtelemetry: { source: "testSource" }
|
||||||
})).toBeFalsy();
|
})).toBeFalsy();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user