mirror of
https://github.com/nasa/openmct.git
synced 2026-05-31 06:26:06 -05:00
* add clearStaleness method since === SKIP_CHECK flag
* fix logic for updating staleness
* should be inclusive to start and end bounds
* should respect prior to start bounds if stale
* should not show staleness for after end bounds
* add `ExampleStalenessProvider`
update telemetry api jsdocs for staless provider
* move sine wave staleness tests into appropriate folder location
* convert `StateGenerator` into class
* clean up coding style
* use timesystem key and now() from openmct time api
* fix `ExampleStalenessProvider` initial conditions
install `ExampleStalenessProvider` by default in index.html
* Revert "fix logic for updating staleness"
To allow contribution from marcelo-earth
This reverts commit 3baef169f7.
* Refactor shouldUpdateStaleness to accept updates based on timestamp
* clarify comment
remove unused code
* fix import paths
* clean up staleness provider
write e2e test for staleness
* fix 404s to example imagery breaking e2e tests
---------
Co-authored-by: Marcelo Arias <hello@marceloarias.com>
137 lines
5.0 KiB
JavaScript
137 lines
5.0 KiB
JavaScript
/*****************************************************************************
|
|
* Open MCT, Copyright (c) 2014-2025, 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.
|
|
*****************************************************************************/
|
|
|
|
/**
|
|
* @implements {import('src/api/telemetry/TelemetryAPI').StalenessProvider}
|
|
*/
|
|
export default class ExampleStalenessProvider {
|
|
#intervalId;
|
|
constructor(openmct, config = { stalenessInterval: 3000, reportStalenessInterval: 300 }) {
|
|
this.openmct = openmct;
|
|
this.stalenessInterval = config.stalenessInterval;
|
|
this.reportStalenessInterval = config.reportStalenessInterval;
|
|
this.observingStaleness = {};
|
|
this.latestReceivedTelemetry = {};
|
|
|
|
this.#observeTimeSystem();
|
|
this.#observeStaleness();
|
|
}
|
|
|
|
#observeTimeSystem() {
|
|
this.openmct.time.on('timeSystemChanged', () => {
|
|
this.timeSystem = this.openmct.time.getTimeSystem();
|
|
});
|
|
}
|
|
|
|
supportsStaleness(domainObject) {
|
|
return this.openmct.telemetry.isTelemetryObject(domainObject);
|
|
}
|
|
|
|
subscribeToStaleness(domainObject, callback) {
|
|
const keyString = this.openmct.objects.makeKeyString(domainObject.identifier);
|
|
|
|
this.observingStaleness[keyString] = { callback };
|
|
const unsubscribe = this.openmct.telemetry.subscribe(domainObject, (datum) => {
|
|
this.#updateLatestReceivedTelemetry(domainObject, datum);
|
|
});
|
|
|
|
return () => {
|
|
delete this.observingStaleness[keyString];
|
|
unsubscribe?.();
|
|
if (Object.keys(this.observingStaleness).length === 0) {
|
|
clearInterval(this.#intervalId);
|
|
}
|
|
};
|
|
}
|
|
|
|
#observeStaleness() {
|
|
this.#intervalId = setInterval(() => {
|
|
if (!this.timeSystem) {
|
|
return;
|
|
}
|
|
|
|
Object.entries(this.observingStaleness).forEach(([keyString, observer]) => {
|
|
if (!this.latestReceivedTelemetry[keyString]) {
|
|
return;
|
|
}
|
|
|
|
const now = this.openmct.time.now();
|
|
const isStale = now - this.latestReceivedTelemetry[keyString] >= this.stalenessInterval;
|
|
|
|
// Overly reports when not stale because of generated telemetry flake
|
|
if (!isStale || !observer.response || isStale !== observer.response.isStale) {
|
|
const stalenessResponseObject = {
|
|
isStale,
|
|
[this.timeSystem.key]: now
|
|
};
|
|
|
|
observer.response = stalenessResponseObject;
|
|
observer.callback(stalenessResponseObject);
|
|
}
|
|
});
|
|
}, this.reportStalenessInterval);
|
|
}
|
|
|
|
/**
|
|
* @param {*} domainObject
|
|
* @returns {import('src/api/telemetry/TelemetryAPI').StalenessResponseObject}
|
|
*/
|
|
async isStale(domainObject) {
|
|
if (!this.timeSystem) {
|
|
this.timeSystem = this.openmct.time.getTimeSystem();
|
|
}
|
|
|
|
const keyString = this.openmct.objects.makeKeyString(domainObject.identifier);
|
|
|
|
if (!this.latestReceivedTelemetry[keyString]) {
|
|
// Naively assumes sorted request response so uses last datum in array
|
|
const response = await this.openmct.telemetry.request(domainObject, { strategy: 'latest' });
|
|
const lastDatum = response?.length ? response[response.length - 1] : undefined;
|
|
this.#updateLatestReceivedTelemetry(domainObject, lastDatum);
|
|
}
|
|
|
|
const timestamp = this.latestReceivedTelemetry[keyString];
|
|
if (timestamp) {
|
|
const isStale = this.openmct.time.now() - timestamp >= this.stalenessInterval;
|
|
|
|
const stalenessResponseObject = { isStale };
|
|
stalenessResponseObject[this.timeSystem.key] = timestamp;
|
|
|
|
return stalenessResponseObject;
|
|
}
|
|
}
|
|
|
|
#updateLatestReceivedTelemetry(domainObject, datum) {
|
|
const keyString = this.openmct.objects.makeKeyString(domainObject.identifier);
|
|
const metadata = this.openmct.telemetry.getMetadata(domainObject);
|
|
const metadataValue = metadata.value(this.timeSystem.key) || { format: this.timeSystem.key };
|
|
const valueFormatter = this.openmct.telemetry.getValueFormatter(metadataValue);
|
|
const timestamp = valueFormatter.parse(datum);
|
|
|
|
if (timestamp) {
|
|
this.latestReceivedTelemetry[keyString] = timestamp;
|
|
} else {
|
|
console.warn('Could not parse timestamp for staleness check');
|
|
}
|
|
}
|
|
}
|