Skip to content

Instantly share code, notes, and snippets.

@RomkeVdMeulen
Last active April 10, 2017 11:24
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save RomkeVdMeulen/92d2127827098499762eceaed63eeb3a to your computer and use it in GitHub Desktop.
Save RomkeVdMeulen/92d2127827098499762eceaed63eeb3a to your computer and use it in GitHub Desktop.
Simple poller library built in TypeScipt
import {BackendService} from "./backend";
export class PollerService {
constructor(private backendService: BackendService) {
}
static readonly INTERVAL = {
SHORT: 1000,
STANDARD: 2000,
LONG: 5000,
};
makeBasicPoller(resourceUrl: string, interval = PollerService.INTERVAL.STANDARD) {
return new BasicPoller(this.backendService, resourceUrl, interval);
}
makeListPoller(resourceUrl: string, resourceIds: any[], interval = PollerService.INTERVAL.STANDARD) {
return new ListPoller(this.backendService, resourceUrl, resourceIds, interval);
}
}
export interface Poller {
interval: number;
readonly started: boolean;
start(callback: Function): void;
stop(): void;
}
abstract class PollerBase implements Poller {
protected timeoutId: number | undefined;
constructor(protected backendService: BackendService, protected resourceUrl: string, public interval: number) {
}
abstract start(callback: Function): void;
stop() {
if (this.timeoutId) {
clearTimeout(this.timeoutId);
this.timeoutId = undefined;
}
}
get started() {
return this.timeoutId !== undefined;
}
}
/**
* Basic Poller: calls the callback with every response. If the callback returns
* (a promise that resolves to) false the poller is stopped. In all other cases
* the poller continues.
*/
export class BasicPoller extends PollerBase {
private callback: (resource: any) => any;
constructor(backendService: BackendService, resourceUrl: string, interval: number) {
super(backendService, resourceUrl, interval);
}
start(callback: (resource: any) => any) {
this.callback = callback;
this.schedulePoll();
}
private schedulePoll() {
this.timeoutId = window.setTimeout(
async () => {
if (await this.poll() !== false) {
this.schedulePoll();
}
},
this.interval,
);
}
private async poll() {
const response = await this.backendService.get(this.resourceUrl);
return this.callback(response);
}
}
/**
* Poller for a list of resources. Keeps a list of IDs of resources to be
* retrieved. Builds query string automatically, updated every time resources
* are returned. Automatically stops polling once all resource have been
* received.
*/
export class ListPoller extends PollerBase {
private identifier = "id";
private callback: (resource: any) => void;
constructor(backendService: BackendService, resourceUrl: string, private resourceIds: any[], interval: number) {
super(backendService, resourceUrl, interval);
}
start(callback: (resource: any) => void) {
this.callback = callback;
if (this.resourceIds.length > 0) {
this.schedulePoll();
}
}
setIdentifier(identifier: string) {
this.identifier = identifier;
}
private schedulePoll() {
this.timeoutId = window.setTimeout(
async () => {
await this.poll();
if (this.resourceIds.length > 0) {
this.schedulePoll();
}
},
this.interval,
);
}
private async poll() {
const baseUrl = this.resourceUrl + (!this.resourceUrl.includes("?") ? "?" : "&");
const response = await this.backendService.get(baseUrl + this.buildQuery(this.resourceIds));
if (response instanceof Array) {
(<any[]> response).forEach(this.callback);
const responseIds = this.extractIds(response);
this.resourceIds = this.resourceIds.filter(id => !responseIds.includes(id));
}
}
private buildQuery(resourceIDs: any[]) {
const ident = encodeURIComponent(this.identifier);
return resourceIDs
.map(id => ident + "=" + encodeURIComponent(id))
.join("&");
}
private extractIds(result: any[]) {
return result.map(resource => resource[this.identifier]);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment