Files
awx/awx/ui/client/features/output/slide.service.js

189 lines
4.6 KiB
JavaScript

/* eslint camelcase: 0 */
import {
OUTPUT_EVENT_LIMIT,
OUTPUT_PAGE_SIZE,
} from './constants';
function getContinuous (events, reverse = false) {
const counters = events.map(({ counter }) => counter);
const min = Math.min(...counters);
const max = Math.max(...counters);
const missing = [];
for (let i = min; i <= max; i++) {
if (counters.indexOf(i) < 0) {
missing.push(i);
}
}
if (missing.length === 0) {
return events;
}
if (reverse) {
const threshold = Math.max(...missing);
return events.filter(({ counter }) => counter > threshold);
}
const threshold = Math.min(...missing);
return events.filter(({ counter }) => counter < threshold);
}
function SlidingWindowService ($q) {
this.init = ({ getRange, getFirst, getLast, getMaxCounter }, storage) => {
const { getHeadCounter, getTailCounter } = storage;
this.api = {
getRange,
getFirst,
getLast,
getMaxCounter,
};
this.storage = {
getHeadCounter,
getTailCounter,
};
this.buffer = {
events: [],
min: 0,
max: 0,
count: 0,
};
this.cache = {
first: null
};
};
this.getBoundedRange = range => {
const bounds = [1, this.getMaxCounter()];
return [Math.max(range[0], bounds[0]), Math.min(range[1], bounds[1])];
};
this.getNextRange = displacement => {
const tail = this.getTailCounter();
return this.getBoundedRange([tail + 1, tail + 1 + displacement]);
};
this.getPreviousRange = displacement => {
const head = this.getHeadCounter();
return this.getBoundedRange([head - 1 - displacement, head - 1]);
};
this.getNext = (displacement = OUTPUT_PAGE_SIZE) => {
const next = this.getNextRange(displacement);
return this.api.getRange(next)
.then(results => getContinuous(results));
};
this.getPrevious = (displacement = OUTPUT_PAGE_SIZE) => {
const previous = this.getPreviousRange(displacement);
return this.api.getRange(previous)
.then(results => getContinuous(results, true));
};
this.getFirst = () => {
if (this.cache.first) {
return $q.resolve(this.cache.first);
}
return this.api.getFirst()
.then(events => {
if (events.length === OUTPUT_PAGE_SIZE) {
this.cache.first = events;
}
return $q.resolve(events);
});
};
this.getLast = () => this.getFrames()
.then(frames => {
if (frames.length > 0) {
return $q.resolve(frames);
}
return this.api.getLast();
});
this.pushFrames = events => {
const head = this.getHeadCounter();
const tail = this.getTailCounter();
const frames = this.buffer.events.concat(events);
let min;
let max;
let count = 0;
for (let i = frames.length - 1; i >= 0; i--) {
count++;
if (count > OUTPUT_EVENT_LIMIT) {
frames.splice(i, 1);
count--;
continue;
}
if (!min || frames[i].counter < min) {
min = frames[i].counter;
}
if (!max || frames[i].counter > max) {
max = frames[i].counter;
}
}
this.buffer.events = frames;
this.buffer.min = min;
this.buffer.max = max;
this.buffer.count = count;
if (tail - head === 0) {
return frames;
}
if (min >= head && min <= tail + 1) {
return frames.filter(({ counter }) => counter > tail);
}
return [];
};
this.getFrames = () => $q.resolve(this.buffer.events);
this.getMaxCounter = () => {
if (this.buffer.min && this.buffer.min > 1) {
return this.buffer.min - 1;
}
return this.api.getMaxCounter();
};
this.isOnLastPage = () => {
if (this.getTailCounter() === 0) {
return true;
}
return this.getTailCounter() >= (this.getMaxCounter() - OUTPUT_PAGE_SIZE);
};
this.isOnFirstPage = () => this.getHeadCounter() === 1;
this.getTailCounter = () => this.storage.getTailCounter();
this.getHeadCounter = () => this.storage.getHeadCounter();
}
SlidingWindowService.$inject = ['$q'];
export default SlidingWindowService;