mirror of
https://github.com/nasa/openmct.git
synced 2024-12-19 05:07:52 +00:00
Merge pull request #1362 from nasa/open1348
[Telemetry] Added legacy provider to expose old style telemetry providers to users of the new telemetry API
This commit is contained in:
commit
6f417fc4c7
@ -14,7 +14,8 @@
|
||||
"nonew": true,
|
||||
"predef": [
|
||||
"define",
|
||||
"Promise"
|
||||
"Promise",
|
||||
"WeakMap"
|
||||
],
|
||||
"shadow": "outer",
|
||||
"strict": "implied",
|
||||
|
@ -192,7 +192,7 @@ define([
|
||||
* @memberof module:openmct.MCT#
|
||||
* @name telemetry
|
||||
*/
|
||||
this.telemetry = new api.TelemetryAPI();
|
||||
this.telemetry = new api.TelemetryAPI(this);
|
||||
|
||||
this.TimeConductor = this.conductor; // compatibility for prototype
|
||||
this.on('navigation', this.selection.clear.bind(this.selection));
|
||||
|
148
src/api/telemetry/LegacyTelemetryProvider.js
Normal file
148
src/api/telemetry/LegacyTelemetryProvider.js
Normal file
@ -0,0 +1,148 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2016, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is 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.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define([
|
||||
'../objects/object-utils'
|
||||
], function (
|
||||
utils
|
||||
) {
|
||||
/**
|
||||
* @implements module:openmct.TelemetryAPI~TelemetryProvider
|
||||
* @constructor
|
||||
*/
|
||||
function LegacyTelemetryProvider(instantiate) {
|
||||
this.instantiate = instantiate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can provide telemetry for all objects that have the "telemetry"
|
||||
* capability
|
||||
*
|
||||
* @see module:openmct.TelemetryAPI~TelemetryProvider#canProvideTelemetry
|
||||
*/
|
||||
LegacyTelemetryProvider.prototype.canProvideTelemetry = function (domainObject) {
|
||||
return this.instantiate(utils.toOldFormat(domainObject),
|
||||
utils.makeKeyString(domainObject.identifier)).hasCapability("telemetry");
|
||||
};
|
||||
|
||||
function createDatum(domainObject, metadata, legacySeries, i) {
|
||||
var datum = {};
|
||||
|
||||
metadata.domains.reduce(function (d, domain) {
|
||||
d[domain.key] = legacySeries.getDomainValue(i, domain.key);
|
||||
return d;
|
||||
}, datum);
|
||||
|
||||
metadata.ranges.reduce(function (d, range) {
|
||||
d[range.key] = legacySeries.getRangeValue(i, range.key);
|
||||
return d;
|
||||
}, datum);
|
||||
|
||||
datum.name = domainObject.name;
|
||||
|
||||
return datum;
|
||||
}
|
||||
|
||||
function adaptSeries(domainObject, metadata, legacySeries) {
|
||||
var series = [];
|
||||
|
||||
for (var i = 0; i < legacySeries.getPointCount(); i++) {
|
||||
series.push(createDatum(domainObject, metadata, legacySeries, i));
|
||||
}
|
||||
|
||||
return series;
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {object} ConvertedTelemetryObject
|
||||
* Telemetry data objects are converted from TelemetrySeries. Metadata is used
|
||||
* to populate the returned object with attributes corresponding to the keys
|
||||
* of domains and ranges. The attribute values are those returned by calls to
|
||||
* [TelemetrySeries.getDomainValue()]{@link TelemetrySeries#getDomainValue}
|
||||
* and [TelemetrySeries.getRangeValue()]{@link TelemetrySeries#getRangeValue}.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @see module:openmct.TelemetryAPI~TelemetryProvider#request
|
||||
* @param {module:openmct.DomainObject}
|
||||
* @param {module:openmct.TelemetryAPI~TelemetryRequest} options
|
||||
* options for this request. Passed straight through to legacy provider
|
||||
* @returns {Promise.<ConvertedTelemetryObject[]>} a promise for an array of
|
||||
* telemetry data.
|
||||
*/
|
||||
LegacyTelemetryProvider.prototype.request = function (domainObject, request) {
|
||||
var oldObject = this.instantiate(utils.toOldFormat(domainObject), utils.makeKeyString(domainObject.identifier));
|
||||
var capability = oldObject.getCapability("telemetry");
|
||||
|
||||
return capability.requestData(request).then(function (telemetrySeries) {
|
||||
return Promise.resolve(adaptSeries(domainObject, capability.getMetadata(), telemetrySeries));
|
||||
}).catch(function (error) {
|
||||
return Promise.reject(error);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @callback LegacyTelemetryProvider~SubscribeCallback
|
||||
* @param {ConvertedTelemetryObject}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @see module:openmct.TelemetryAPI~TelemetryProvider#request
|
||||
* @param {module:openmct.DomainObject}
|
||||
* @param {LegacyTelemetryProvider~SubscribeCallback} callback will be called with a single datum when
|
||||
* new data is available.
|
||||
* @param {module:openmct.TelemetryAPI~TelemetryRequest} options
|
||||
* options for this request. Passed straight through to legacy provider
|
||||
* @returns {platform|telemetry.TelemetrySubscription|*}
|
||||
*/
|
||||
LegacyTelemetryProvider.prototype.subscribe = function (domainObject, callback, request) {
|
||||
var oldObject = this.instantiate(utils.toOldFormat(domainObject), utils.makeKeyString(domainObject.identifier));
|
||||
var capability = oldObject.getCapability("telemetry");
|
||||
|
||||
function callbackWrapper(series) {
|
||||
callback(createDatum(domainObject, capability.getMetadata(), series, series.getPointCount() - 1));
|
||||
}
|
||||
|
||||
return capability.subscribe(callbackWrapper, request);
|
||||
};
|
||||
|
||||
LegacyTelemetryProvider.prototype.limitEvaluator = function (domainObject) {
|
||||
var oldObject = this.instantiate(
|
||||
utils.toOldFormat(domainObject),
|
||||
utils.makeKeyString(domainObject.identifier));
|
||||
var limitEvaluator = oldObject.getCapability("limit");
|
||||
|
||||
return {
|
||||
evaluate: function (datum, property) {
|
||||
return limitEvaluator.evaluate(datum, property.key);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
return function (openmct, instantiate) {
|
||||
// Push onto the start of the default providers array so that it's
|
||||
// always the last resort
|
||||
openmct.telemetry.defaultProviders.unshift(
|
||||
new LegacyTelemetryProvider(instantiate));
|
||||
};
|
||||
|
||||
});
|
@ -21,9 +21,13 @@
|
||||
*****************************************************************************/
|
||||
|
||||
define([
|
||||
'./TelemetryMetadataManager',
|
||||
'./TelemetryValueFormatter',
|
||||
'lodash',
|
||||
'EventEmitter'
|
||||
], function (
|
||||
TelemetryMetadataManager,
|
||||
TelemetryValueFormatter,
|
||||
_,
|
||||
EventEmitter
|
||||
) {
|
||||
@ -155,9 +159,13 @@ define([
|
||||
* @augments module:openmct.TelemetryAPI~TelemetryProvider
|
||||
* @memberof module:openmct
|
||||
*/
|
||||
function TelemetryAPI() {
|
||||
function TelemetryAPI(MCT) {
|
||||
this.MCT = MCT;
|
||||
this.providersByStrategy = {};
|
||||
this.defaultProviders = [];
|
||||
this.metadataCache = new WeakMap();
|
||||
this.formatMapCache = new WeakMap();
|
||||
this.valueFormatterCache = new WeakMap();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -240,6 +248,85 @@ define([
|
||||
Promise.reject([]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get telemetry metadata for a given domain object. Returns a telemetry
|
||||
* metadata manager which provides methods for interrogating telemetry
|
||||
* metadata.
|
||||
*
|
||||
* @returns {TelemetryMetadataManager}
|
||||
*/
|
||||
TelemetryAPI.prototype.getMetadata = function (domainObject) {
|
||||
if (!this.metadataCache.has(domainObject)) {
|
||||
if (!this.typeService) {
|
||||
this.typeService = this.MCT.$injector.get('typeService');
|
||||
}
|
||||
this.metadataCache.set(
|
||||
domainObject,
|
||||
new TelemetryMetadataManager(domainObject, this.typeService)
|
||||
);
|
||||
}
|
||||
return this.metadataCache.get(domainObject);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return an array of valueMetadatas that are common to all supplied
|
||||
* telemetry objects and match the requested hints.
|
||||
*
|
||||
*/
|
||||
TelemetryAPI.prototype.commonValuesForHints = function (metadatas, hints) {
|
||||
var options = metadatas.map(function (metadata) {
|
||||
var values = metadata.valuesForHints(hints);
|
||||
return _.indexBy(values, 'key');
|
||||
}).reduce(function (a, b) {
|
||||
var results = {};
|
||||
Object.keys(a).forEach(function (key) {
|
||||
if (b.hasOwnProperty(key)) {
|
||||
results[key] = a[key];
|
||||
}
|
||||
});
|
||||
return results;
|
||||
});
|
||||
var sortKeys = hints.map(function (h) {
|
||||
return 'hints.' + h;
|
||||
});
|
||||
return _.sortByAll(options, sortKeys);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a value formatter for a given valueMetadata.
|
||||
*
|
||||
* @returns {TelemetryValueFormatter}
|
||||
*/
|
||||
TelemetryAPI.prototype.getValueFormatter = function (valueMetadata) {
|
||||
if (!this.valueFormatterCache.has(valueMetadata)) {
|
||||
if (!this.formatService) {
|
||||
this.formatService = this.MCT.$injector.get('formatService');
|
||||
}
|
||||
this.valueFormatterCache.set(
|
||||
valueMetadata,
|
||||
new TelemetryValueFormatter(valueMetadata, this.formatService)
|
||||
);
|
||||
}
|
||||
return this.valueFormatterCache.get(valueMetadata);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a format map of all value formatters for a given piece of telemetry
|
||||
* metadata.
|
||||
*
|
||||
* @returns {Object<String, {TelemetryValueFormatter}>}
|
||||
*/
|
||||
TelemetryAPI.prototype.getFormatMap = function (metadata) {
|
||||
if (!this.formatMapCache.has(metadata)) {
|
||||
var formatMap = metadata.values().reduce(function (map, valueMetadata) {
|
||||
map[valueMetadata.key] = this.getValueFormatter(valueMetadata);
|
||||
return map;
|
||||
}.bind(this), {});
|
||||
this.formatMapCache.set(metadata, formatMap);
|
||||
}
|
||||
return this.formatMapCache.get(metadata);
|
||||
};
|
||||
|
||||
/**
|
||||
* Subscribe to realtime telemetry for a specific domain object.
|
||||
* The callback will be called whenever data is received from a
|
||||
|
152
src/api/telemetry/TelemetryMetadataManager.js
Normal file
152
src/api/telemetry/TelemetryMetadataManager.js
Normal file
@ -0,0 +1,152 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2016, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is 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.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
define([
|
||||
'lodash'
|
||||
], function (
|
||||
_
|
||||
) {
|
||||
|
||||
function valueMetadatasFromOldFormat(metadata) {
|
||||
var valueMetadatas = [];
|
||||
|
||||
valueMetadatas.push({
|
||||
key: 'name',
|
||||
name: 'Name'
|
||||
});
|
||||
|
||||
metadata.domains.forEach(function (domain, index) {
|
||||
var valueMetadata = _.clone(domain);
|
||||
valueMetadata.hints = {
|
||||
x: index + 1,
|
||||
domain: index + 1
|
||||
};
|
||||
valueMetadatas.push(valueMetadata);
|
||||
});
|
||||
|
||||
metadata.ranges.forEach(function (range, index) {
|
||||
var valueMetadata = _.clone(range);
|
||||
valueMetadata.hints = {
|
||||
y: index,
|
||||
range: index,
|
||||
priority: index + metadata.domains.length + 1
|
||||
};
|
||||
|
||||
if (valueMetadata.type === 'enum') {
|
||||
valueMetadata.key = 'enum';
|
||||
valueMetadata.hints.y -= 10;
|
||||
valueMetadata.hints.range -= 10;
|
||||
valueMetadata.enumerations =
|
||||
_.sortBy(valueMetadata.enumerations.map(function (e) {
|
||||
return {
|
||||
string: e.string,
|
||||
value: +e.value
|
||||
};
|
||||
}), 'e.value');
|
||||
valueMetadata.values = _.pluck(valueMetadata.enumerations, 'value');
|
||||
valueMetadata.max = _.max(valueMetadata.values);
|
||||
valueMetadata.min = _.min(valueMetadata.values);
|
||||
}
|
||||
|
||||
valueMetadatas.push(valueMetadata);
|
||||
});
|
||||
|
||||
return valueMetadatas;
|
||||
}
|
||||
|
||||
function applyReasonableDefaults(valueMetadata, index) {
|
||||
valueMetadata.source = valueMetadata.source || valueMetadata.key;
|
||||
valueMetadata.hints = valueMetadata.hints || {};
|
||||
|
||||
if (!valueMetadata.hints.hasOwnProperty('priority')) {
|
||||
valueMetadata.hints.priority = index;
|
||||
}
|
||||
return valueMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility class for handling telemetry metadata for a domain object.
|
||||
* Wraps old format metadata to new format metadata.
|
||||
* Provides methods for interrogating telemetry metadata.
|
||||
*/
|
||||
function TelemetryMetadataManager(domainObject, typeService) {
|
||||
this.metadata = domainObject.telemetry || {};
|
||||
|
||||
if (this.metadata.values) {
|
||||
this.valueMetadatas = this.metadata.values;
|
||||
} else {
|
||||
var typeMetadata = typeService
|
||||
.getType(domainObject.type).typeDef.telemetry;
|
||||
|
||||
_.extend(this.metadata, typeMetadata);
|
||||
this.valueMetadatas = valueMetadatasFromOldFormat(this.metadata);
|
||||
}
|
||||
|
||||
this.valueMetadatas = this.valueMetadatas.map(applyReasonableDefaults);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get value metadata for a single key.
|
||||
*/
|
||||
TelemetryMetadataManager.prototype.value = function (key) {
|
||||
return this.valueMetadatas.filter(function (metadata) {
|
||||
return metadata.key === key;
|
||||
})[0];
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns all value metadatas, sorted by priority.
|
||||
*/
|
||||
TelemetryMetadataManager.prototype.values = function () {
|
||||
return this.valuesForHints(['priority']);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an array of valueMetadatas that posess all hints requested.
|
||||
* Array is sorted based on hint priority.
|
||||
*
|
||||
*/
|
||||
TelemetryMetadataManager.prototype.valuesForHints = function (
|
||||
hints
|
||||
) {
|
||||
function hasHint(hint) {
|
||||
/*jshint validthis: true */
|
||||
return this.hints.hasOwnProperty(hint);
|
||||
}
|
||||
function hasHints(metadata) {
|
||||
return hints.every(hasHint, metadata);
|
||||
}
|
||||
var matchingMetadata = this.valueMetadatas.filter(hasHints);
|
||||
var sortedMetadata = _.sortBy(matchingMetadata, function (metadata) {
|
||||
return hints.map(function (hint) {
|
||||
return metadata.hints[hint];
|
||||
});
|
||||
});
|
||||
return sortedMetadata;
|
||||
};
|
||||
|
||||
|
||||
return TelemetryMetadataManager;
|
||||
|
||||
});
|
98
src/api/telemetry/TelemetryValueFormatter.js
Normal file
98
src/api/telemetry/TelemetryValueFormatter.js
Normal file
@ -0,0 +1,98 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2016, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is 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.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define([
|
||||
'lodash'
|
||||
], function (
|
||||
_
|
||||
) {
|
||||
|
||||
// TODO: needs reference to formatService;
|
||||
function TelemetryValueFormatter(valueMetadata, formatService) {
|
||||
this.valueMetadata = valueMetadata;
|
||||
this.parseCache = new WeakMap();
|
||||
this.formatCache = new WeakMap();
|
||||
try {
|
||||
this.formatter = formatService
|
||||
.getFormat(valueMetadata.format, valueMetadata);
|
||||
} catch (e) {
|
||||
// TODO: Better formatting
|
||||
this.formatter = {
|
||||
parse: function (x) {
|
||||
return Number(x);
|
||||
},
|
||||
format: function (x) {
|
||||
return x;
|
||||
},
|
||||
validate: function (x) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (valueMetadata.type === 'enum') {
|
||||
this.formatter = {};
|
||||
this.enumerations = valueMetadata.enumerations.reduce(function (vm, e) {
|
||||
vm.byValue[e.value] = e.string;
|
||||
vm.byString[e.string] = e.value;
|
||||
return vm;
|
||||
}, {byValue: {}, byString: {}});
|
||||
this.formatter.format = function (value) {
|
||||
return this.enumerations.byValue[value];
|
||||
}.bind(this);
|
||||
this.formatter.parse = function (string) {
|
||||
if (typeof string === "string" && this.enumerations.hasOwnProperty(string)) {
|
||||
return this.enumerations.byString[string];
|
||||
}
|
||||
return Number(string);
|
||||
}.bind(this);
|
||||
}
|
||||
}
|
||||
|
||||
TelemetryValueFormatter.prototype.parse = function (datum) {
|
||||
if (_.isObject(datum)) {
|
||||
if (!this.parseCache.has(datum)) {
|
||||
this.parseCache.set(
|
||||
datum,
|
||||
this.formatter.parse(datum[this.valueMetadata.source])
|
||||
);
|
||||
}
|
||||
return this.parseCache.get(datum);
|
||||
}
|
||||
return this.formatter.parse(datum);
|
||||
};
|
||||
|
||||
TelemetryValueFormatter.prototype.format = function (datum) {
|
||||
if (_.isObject(datum)) {
|
||||
if (!this.formatCache.has(datum)) {
|
||||
this.formatCache.set(
|
||||
datum,
|
||||
this.formatter.format(datum[this.valueMetadata.source])
|
||||
);
|
||||
}
|
||||
return this.formatCache.get(datum);
|
||||
}
|
||||
return this.formatter.format(datum);
|
||||
};
|
||||
|
||||
return TelemetryValueFormatter;
|
||||
});
|
@ -22,12 +22,14 @@
|
||||
|
||||
define([
|
||||
'./TelemetryAPI',
|
||||
'./LegacyTelemetryProvider',
|
||||
'legacyRegistry'
|
||||
], function (
|
||||
TelemetryAPI,
|
||||
LegacyTelemetryProvider,
|
||||
legacyRegistry
|
||||
) {
|
||||
legacyRegistry.register('api/telemetry-api', {
|
||||
legacyRegistry.register('src/api/telemetry', {
|
||||
name: 'Telemetry API',
|
||||
description: 'The public Telemetry API',
|
||||
extensions: {
|
||||
@ -38,6 +40,14 @@ define([
|
||||
depends: [
|
||||
'formatService'
|
||||
]
|
||||
},
|
||||
{
|
||||
key: "LegacyTelemetryAdapter",
|
||||
implementation: LegacyTelemetryProvider,
|
||||
depends: [
|
||||
"openmct",
|
||||
"instantiate"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ define([
|
||||
|
||||
'../src/adapter/bundle',
|
||||
'../src/api/objects/bundle',
|
||||
'../src/api/telemetry/bundle',
|
||||
|
||||
'../example/builtins/bundle',
|
||||
'../example/composite/bundle',
|
||||
@ -96,6 +97,7 @@ define([
|
||||
var DEFAULTS = [
|
||||
'src/adapter',
|
||||
'src/api/objects',
|
||||
'src/api/telemetry',
|
||||
'platform/framework',
|
||||
'platform/core',
|
||||
'platform/representation',
|
||||
|
Loading…
Reference in New Issue
Block a user