debian-mirror-gitlab/app/assets/javascripts/lib/utils/poll.js

116 lines
3 KiB
JavaScript
Raw Normal View History

2017-08-17 22:00:37 +05:30
import httpStatusCodes from './http_status';
2018-03-17 18:26:18 +05:30
import { normalizeHeaders } from './common_utils';
2017-08-17 22:00:37 +05:30
/**
* Polling utility for handling realtime updates.
2018-03-17 18:26:18 +05:30
* Requirements: Promise based HTTP client
*
* Service for promise based http client and method need to be provided as props
2017-08-17 22:00:37 +05:30
*
* @example
* new Poll({
* resource: resource,
* method: 'name',
* data: {page: 1, scope: 'all'}, // optional
* successCallback: () => {},
* errorCallback: () => {},
* notificationCallback: () => {}, // optional
* }).makeRequest();
*
* Usage in pipelines table with visibility lib:
*
* const poll = new Poll({
* resource: this.service,
* method: 'getPipelines',
* data: { page: pageNumber, scope },
* successCallback: this.successCallback,
* errorCallback: this.errorCallback,
* notificationCallback: this.updateLoading,
* });
*
* if (!Visibility.hidden()) {
* poll.makeRequest();
* }
*
* Visibility.change(() => {
* if (!Visibility.hidden()) {
* poll.restart();
* } else {
* poll.stop();
* }
* });
*
* 1. Checks for response and headers before start polling
* 2. Interval is provided by `Poll-Interval` header.
* 3. If `Poll-Interval` is -1, we stop polling
* 4. If HTTP response is 200, we poll.
* 5. If HTTP response is different from 200, we stop polling.
*
*/
export default class Poll {
constructor(options = {}) {
this.options = options;
this.options.data = options.data || {};
this.options.notificationCallback = options.notificationCallback ||
function notificationCallback() {};
this.intervalHeader = 'POLL-INTERVAL';
this.timeoutID = null;
this.canPoll = true;
}
checkConditions(response) {
2018-03-17 18:26:18 +05:30
const headers = normalizeHeaders(response.headers);
2017-08-17 22:00:37 +05:30
const pollInterval = parseInt(headers[this.intervalHeader], 10);
if (pollInterval > 0 && response.status === httpStatusCodes.OK && this.canPoll) {
this.timeoutID = setTimeout(() => {
this.makeRequest();
}, pollInterval);
}
this.options.successCallback(response);
}
makeRequest() {
const { resource, method, data, errorCallback, notificationCallback } = this.options;
// It's called everytime a new request is made. Useful to update the status.
notificationCallback(true);
return resource[method](data)
.then((response) => {
this.checkConditions(response);
notificationCallback(false);
})
.catch((error) => {
notificationCallback(false);
2017-09-10 17:25:29 +05:30
if (error.status === httpStatusCodes.ABORTED) {
return;
}
2017-08-17 22:00:37 +05:30
errorCallback(error);
});
}
/**
* Stops the polling recursive chain
* and guarantees if the timeout is already running it won't make another request by
* cancelling the previously established timeout.
*/
stop() {
this.canPoll = false;
clearTimeout(this.timeoutID);
}
/**
* Restarts polling after it has been stoped
*/
2018-03-17 18:26:18 +05:30
restart(options) {
// update data
if (options && options.data) {
this.options.data = options.data;
}
2017-08-17 22:00:37 +05:30
this.canPoll = true;
this.makeRequest();
}
}