Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import {HttpClient} from './httpclient';
- export enum ExitCode {
- Finished = 'finished',
- Cancelled = 'cancelled',
- Errored = 'errored',
- }
- export interface Handle<T> {
- dataReceived(data: T): void;
- finished(status: ExitCode, error?: any): void;
- statusChanged(status: RobotStatus): void;
- }
- export enum RobotStatus {
- Initial = 'initial',
- Starting = 'starting',
- Running = 'running',
- Cancelling = 'cancelling',
- Cancelled = 'cancelled',
- Finished = 'finished',
- }
- class OperationCancelled extends Error {
- }
- export interface Scope<T> {
- name: string;
- data: T;
- runScope<D>(
- params: ScopeParams<D>,
- func: (scope: Scope<D>, ...args: any[]) => Promise<any>,
- ...args: any[]
- ): Promise<any>;
- }
- export interface ScopeParams<T> {
- name: string;
- data: T;
- }
- export abstract class Robot<T> {
- private _handle: Handle<T>;
- private _status: RobotStatus = RobotStatus.Initial;
- private _client: HttpClient;
- private _tasks: Promise<any>[] = [];
- get status() {
- return this._status;
- }
- protected get client() {
- return this._client;
- }
- protected constructor(handle: Handle<T>, client: HttpClient) {
- this._handle = handle;
- this._client = client;
- }
- public async start() {
- if (
- ![
- RobotStatus.Initial,
- RobotStatus.Cancelled,
- RobotStatus.Finished,
- ].includes(this._status)
- ) {
- throw new Error('Robot is already running');
- }
- this._tasks = [];
- this.setStatus(RobotStatus.Starting);
- this.setStatus(RobotStatus.Running);
- try {
- let scope: Scope<{}> = {
- name: 'main',
- data: {},
- runScope: <D>(
- params: ScopeParams<D>,
- func: (scope: Scope<D>, ...args: any[]) => Promise<any>,
- ...args: any[]
- ) => {
- return this.runScope(scope, params, func, args);
- },
- };
- await this.onStart(scope);
- await Promise.all(this._tasks);
- this.setStatus(RobotStatus.Finished);
- this._handle.finished(ExitCode.Finished);
- } catch (e) {
- if (e instanceof OperationCancelled) {
- this.setStatus(RobotStatus.Cancelled);
- this._handle.finished(ExitCode.Cancelled);
- } else {
- this.setStatus(RobotStatus.Cancelled);
- this._handle.finished(ExitCode.Errored, e);
- }
- }
- }
- public async cancel() {
- this.setStatus(RobotStatus.Cancelling);
- await this.onCancel();
- this.setStatus(RobotStatus.Cancelled);
- }
- protected abstract onStart(scope: Scope<{}>): Promise<any>;
- protected abstract onCancel(): Promise<any>;
- protected abstract onFinished(): Promise<any>;
- private setStatus(value: RobotStatus) {
- this._status = value;
- this._handle.statusChanged(value);
- }
- protected onDataReceived(data: T) {
- if (
- [RobotStatus.Cancelling, RobotStatus.Cancelled].includes(this._status)
- ) {
- return;
- }
- if ([RobotStatus.Initial, RobotStatus.Finished].includes(this._status)) {
- console.log(
- `Received data in ${this._status} status. This means that the robot didn't finish properly.`
- );
- }
- this._handle.dataReceived(data);
- }
- protected runScope<T, D>(
- scope: Scope<T>,
- params: ScopeParams<D>,
- func: (scope: Scope<D>, ...args: any[]) => Promise<any>,
- ...args: any[]
- ) {
- let newScope: Scope<D> = {
- name: `${scope.name}.${params.name}`,
- data: params.data,
- runScope: <E>(
- params: ScopeParams<E>,
- func: (scope: Scope<E>, ...args: any[]) => Promise<any>,
- ...args: any[]
- ) => {
- return this.runScope(newScope, params, func, args);
- },
- };
- let promise = func
- .bind(this)(newScope, ...args)
- .then(value => {
- this._tasks.splice(this._tasks.indexOf(promise), 1);
- return value;
- })
- .catch(e => {
- if (e instanceof OperationCancelled) {
- throw e;
- } else {
- console.log(`An error occurred in ${newScope.name} scope`);
- console.log(e);
- }
- });
- this._tasks.push(promise);
- console.log(`Running scope ${newScope.name}`);
- return promise;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement