2018-11-02 05:12:57 +00:00
|
|
|
import Ember from 'ember';
|
2018-08-30 00:15:55 +00:00
|
|
|
import Mixin from '@ember/object/mixin';
|
|
|
|
import { assert } from '@ember/debug';
|
2018-09-17 22:58:28 +00:00
|
|
|
import { task, timeout } from 'ember-concurrency';
|
2018-11-02 05:08:57 +00:00
|
|
|
import jsonWithDefault from 'nomad-ui/utils/json-with-default';
|
2018-08-30 00:15:55 +00:00
|
|
|
|
|
|
|
export default Mixin.create({
|
|
|
|
url: '',
|
|
|
|
|
2018-11-02 05:08:57 +00:00
|
|
|
// The max number of data points tracked. Once the max is reached,
|
|
|
|
// data points at the head of the list are removed in favor of new
|
|
|
|
// data appended at the tail
|
2018-09-14 15:57:26 +00:00
|
|
|
bufferSize: 500,
|
|
|
|
|
2018-11-02 05:08:57 +00:00
|
|
|
// The number of consecutive request failures that can occur before an
|
|
|
|
// empty frame is appended
|
|
|
|
maxFrameMisses: 5,
|
|
|
|
|
2018-08-30 00:15:55 +00:00
|
|
|
fetch() {
|
2018-08-31 02:57:28 +00:00
|
|
|
assert('StatsTrackers need a fetch method, which should have an interface like window.fetch');
|
2018-08-30 00:15:55 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
append(/* frame */) {
|
|
|
|
assert(
|
2018-08-31 02:57:28 +00:00
|
|
|
'StatsTrackers need an append method, which takes the JSON response from a request to url as an argument'
|
2018-08-30 00:15:55 +00:00
|
|
|
);
|
|
|
|
},
|
|
|
|
|
2018-09-17 23:59:09 +00:00
|
|
|
pause() {
|
|
|
|
assert(
|
|
|
|
'StatsTrackers need a pause method, which takes no arguments but adds a frame of data at the current timestamp with null as the value'
|
|
|
|
);
|
|
|
|
},
|
|
|
|
|
2018-11-02 05:08:57 +00:00
|
|
|
frameMisses: 0,
|
|
|
|
|
|
|
|
handleResponse(frame) {
|
|
|
|
if (frame.error) {
|
|
|
|
this.incrementProperty('frameMisses');
|
2019-03-26 07:46:44 +00:00
|
|
|
if (this.frameMisses >= this.maxFrameMisses) {
|
2018-11-02 05:08:57 +00:00
|
|
|
// Missing enough data consecutively is effectively a pause
|
|
|
|
this.pause();
|
|
|
|
this.set('frameMisses', 0);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
this.set('frameMisses', 0);
|
|
|
|
|
|
|
|
// Only append non-error frames
|
|
|
|
this.append(frame);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2018-09-17 22:58:28 +00:00
|
|
|
// Uses EC as a form of debounce to prevent multiple
|
|
|
|
// references to the same tracker from flooding the tracker,
|
|
|
|
// but also avoiding the issue where different places where the
|
|
|
|
// same tracker is used needs to coordinate.
|
|
|
|
poll: task(function*() {
|
2018-09-17 23:59:09 +00:00
|
|
|
// Interrupt any pause attempt
|
2019-03-26 07:46:44 +00:00
|
|
|
this.signalPause.cancelAll();
|
2018-09-17 23:59:09 +00:00
|
|
|
|
2018-09-20 02:30:18 +00:00
|
|
|
try {
|
2019-03-26 07:46:44 +00:00
|
|
|
const url = this.url;
|
2018-09-20 02:30:18 +00:00
|
|
|
assert('Url must be defined', url);
|
|
|
|
|
2019-03-26 07:46:44 +00:00
|
|
|
yield this.fetch(url)
|
2018-11-02 05:08:57 +00:00
|
|
|
.then(jsonWithDefault({ error: true }))
|
|
|
|
.then(frame => this.handleResponse(frame));
|
2018-09-20 02:30:18 +00:00
|
|
|
} catch (error) {
|
|
|
|
throw new Error(error);
|
|
|
|
}
|
2018-09-17 22:58:28 +00:00
|
|
|
|
2018-11-02 05:12:57 +00:00
|
|
|
yield timeout(Ember.testing ? 0 : 2000);
|
2018-09-17 22:58:28 +00:00
|
|
|
}).drop(),
|
2018-09-17 23:59:09 +00:00
|
|
|
|
|
|
|
signalPause: task(function*() {
|
|
|
|
// wait 2 seconds
|
2018-11-02 05:12:57 +00:00
|
|
|
yield timeout(Ember.testing ? 0 : 2000);
|
2018-09-17 23:59:09 +00:00
|
|
|
// if no poll called in 2 seconds, pause
|
|
|
|
this.pause();
|
|
|
|
}).drop(),
|
2018-08-30 00:15:55 +00:00
|
|
|
});
|