Summary: Sandy plugins can now set up an `onExport` handler to enable customizing the export format of a plugin: `client.onExport(callback: (idler, onStatusMessage) => Promise<state>)` Import will be done in next diff Reviewed By: nikoant Differential Revision: D26124440 fbshipit-source-id: c787c79d929aa8fb484f15a9340d7c87545793cb
125 lines
2.5 KiB
TypeScript
125 lines
2.5 KiB
TypeScript
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* @format
|
|
*/
|
|
|
|
import {CancelledPromiseError} from './errors';
|
|
import {sleep} from './promiseTimeout';
|
|
import {Idler} from 'flipper-plugin';
|
|
|
|
export class IdlerImpl implements Idler {
|
|
private lastIdle = performance.now();
|
|
private kill = false;
|
|
|
|
constructor(private interval = 16) {}
|
|
|
|
shouldIdle(): boolean {
|
|
return this.kill || performance.now() - this.lastIdle > this.interval;
|
|
}
|
|
|
|
async idle(): Promise<void> {
|
|
if (this.kill) {
|
|
throw new CancelledPromiseError('Idler got killed');
|
|
}
|
|
const now = performance.now();
|
|
if (now - this.lastIdle > this.interval) {
|
|
this.lastIdle = now;
|
|
return new Promise((resolve) => {
|
|
if (typeof requestIdleCallback !== 'undefined') {
|
|
requestIdleCallback(() => {
|
|
resolve();
|
|
});
|
|
} else {
|
|
setTimeout(resolve, 0);
|
|
}
|
|
});
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
cancel() {
|
|
this.kill = true;
|
|
}
|
|
|
|
isCancelled() {
|
|
return this.kill;
|
|
}
|
|
}
|
|
|
|
// This smills like we should be using generators :)
|
|
export class TestIdler implements Idler {
|
|
private resolver?: () => void;
|
|
private kill = false;
|
|
private autoRun = false;
|
|
private hasProgressed = false;
|
|
|
|
constructor(autorun = false) {
|
|
this.autoRun = autorun;
|
|
}
|
|
|
|
shouldIdle() {
|
|
if (this.kill) {
|
|
return true;
|
|
}
|
|
if (this.autoRun) {
|
|
return false;
|
|
}
|
|
// In turns we signal that idling is needed and that it isn't
|
|
if (!this.hasProgressed) {
|
|
this.hasProgressed = true;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
async idle() {
|
|
if (this.kill) {
|
|
throw new CancelledPromiseError('Idler got killed');
|
|
}
|
|
if (this.autoRun) {
|
|
return undefined;
|
|
}
|
|
if (this.resolver) {
|
|
throw new Error('Already idling');
|
|
}
|
|
return new Promise<void>((resolve) => {
|
|
this.resolver = () => {
|
|
this.resolver = undefined;
|
|
this.hasProgressed = false;
|
|
resolve();
|
|
};
|
|
});
|
|
}
|
|
|
|
cancel() {
|
|
this.kill = true;
|
|
this.run();
|
|
}
|
|
|
|
async next() {
|
|
if (!this.resolver) {
|
|
throw new Error('Not yet idled');
|
|
}
|
|
|
|
this.resolver();
|
|
// make sure waiting promise runs first
|
|
await sleep(10);
|
|
}
|
|
|
|
/**
|
|
* Automatically progresses through all idle calls
|
|
*/
|
|
run() {
|
|
this.resolver?.();
|
|
this.autoRun = true;
|
|
}
|
|
|
|
isCancelled() {
|
|
return this.kill;
|
|
}
|
|
}
|