123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- import {Client, Request} from 'sentry/api';
- import parseLinkHeader from 'sentry/utils/parseLinkHeader';
- type Options = {
- linkPreviousHref: string;
- success: (data: any, link?: string | null) => void;
- };
- const BASE_DELAY = 3000;
- const MAX_DELAY = 60000;
- class CursorPoller {
- constructor(options: Options) {
- this.options = options;
- this.setEndpoint(options.linkPreviousHref);
- }
- api = new Client();
- options: Options;
- pollingEndpoint: string = '';
- timeoutId: number | null = null;
- lastRequest: Request | null = null;
- active: boolean = true;
- reqsWithoutData = 0;
- getDelay() {
- const delay = BASE_DELAY * (this.reqsWithoutData + 1);
- return Math.min(delay, MAX_DELAY);
- }
- setEndpoint(linkPreviousHref: string) {
- if (!linkPreviousHref) {
- this.pollingEndpoint = '';
- return;
- }
- const issueEndpoint = new URL(linkPreviousHref, window.location.origin);
- // Remove collapse stats
- issueEndpoint.searchParams.delete('collapse');
- this.pollingEndpoint = decodeURIComponent(
- issueEndpoint.pathname + issueEndpoint.search
- );
- }
- enable() {
- this.active = true;
- // Proactively clear timeout and last request
- if (this.timeoutId) {
- window.clearTimeout(this.timeoutId);
- }
- if (this.lastRequest) {
- this.lastRequest.cancel();
- }
- this.timeoutId = window.setTimeout(this.poll.bind(this), this.getDelay());
- }
- disable() {
- this.active = false;
- if (this.timeoutId) {
- window.clearTimeout(this.timeoutId);
- this.timeoutId = null;
- }
- if (this.lastRequest) {
- this.lastRequest.cancel();
- }
- }
- poll() {
- this.lastRequest = this.api.request(this.pollingEndpoint, {
- success: (data, _, resp) => {
- // cancel in progress operation if disabled
- if (!this.active) {
- return;
- }
- // if theres no data, nothing changes
- if (!data || !data.length) {
- this.reqsWithoutData += 1;
- return;
- }
- if (this.reqsWithoutData > 0) {
- this.reqsWithoutData -= 1;
- }
- const linksHeader = resp?.getResponseHeader('Link') ?? null;
- const links = parseLinkHeader(linksHeader);
- this.setEndpoint(links.previous.href);
- this.options.success(data, linksHeader);
- },
- error: resp => {
- if (!resp) {
- return;
- }
- // If user does not have access to the endpoint, we should halt polling
- // These errors could mean:
- // * the user lost access to a project
- // * project was renamed
- // * user needs to reauth
- if (resp.status === 404 || resp.status === 403 || resp.status === 401) {
- this.disable();
- }
- },
- complete: () => {
- this.lastRequest = null;
- if (this.active) {
- this.timeoutId = window.setTimeout(this.poll.bind(this), this.getDelay());
- }
- },
- });
- }
- }
- export default CursorPoller;
|