Advertisement
szymski

Untitled

Nov 24th, 2019
239
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import {HttpClient} from './httpclient';
  2.  
  3. export enum ExitCode {
  4.   Finished = 'finished',
  5.   Cancelled = 'cancelled',
  6.   Errored = 'errored',
  7. }
  8.  
  9. export interface Handle<T> {
  10.   dataReceived(data: T): void;
  11.  
  12.   finished(status: ExitCode, error?: any): void;
  13.  
  14.   statusChanged(status: RobotStatus): void;
  15. }
  16.  
  17. export enum RobotStatus {
  18.   Initial = 'initial',
  19.   Starting = 'starting',
  20.   Running = 'running',
  21.   Cancelling = 'cancelling',
  22.   Cancelled = 'cancelled',
  23.   Finished = 'finished',
  24. }
  25.  
  26. class OperationCancelled extends Error {
  27. }
  28.  
  29. export interface Scope<T> {
  30.   name: string;
  31.   data: T;
  32.  
  33.   runScope<D>(
  34.     params: ScopeParams<D>,
  35.     func: (scope: Scope<D>, ...args: any[]) => Promise<any>,
  36.     ...args: any[]
  37.   ): Promise<any>;
  38. }
  39.  
  40. export interface ScopeParams<T> {
  41.   name: string;
  42.   data: T;
  43. }
  44.  
  45. export abstract class Robot<T> {
  46.   private _handle: Handle<T>;
  47.   private _status: RobotStatus = RobotStatus.Initial;
  48.   private _client: HttpClient;
  49.   private _tasks: Promise<any>[] = [];
  50.  
  51.   get status() {
  52.     return this._status;
  53.   }
  54.  
  55.   protected get client() {
  56.     return this._client;
  57.   }
  58.  
  59.   protected constructor(handle: Handle<T>, client: HttpClient) {
  60.     this._handle = handle;
  61.     this._client = client;
  62.   }
  63.  
  64.   public async start() {
  65.     if (
  66.       ![
  67.         RobotStatus.Initial,
  68.         RobotStatus.Cancelled,
  69.         RobotStatus.Finished,
  70.       ].includes(this._status)
  71.     ) {
  72.       throw new Error('Robot is already running');
  73.     }
  74.  
  75.     this._tasks = [];
  76.  
  77.     this.setStatus(RobotStatus.Starting);
  78.     this.setStatus(RobotStatus.Running);
  79.  
  80.     try {
  81.       let scope: Scope<{}> = {
  82.         name: 'main',
  83.         data: {},
  84.  
  85.         runScope: <D>(
  86.           params: ScopeParams<D>,
  87.           func: (scope: Scope<D>, ...args: any[]) => Promise<any>,
  88.           ...args: any[]
  89.         ) => {
  90.           return this.runScope(scope, params, func, args);
  91.         },
  92.       };
  93.       await this.onStart(scope);
  94.       await Promise.all(this._tasks);
  95.  
  96.       this.setStatus(RobotStatus.Finished);
  97.       this._handle.finished(ExitCode.Finished);
  98.     } catch (e) {
  99.       if (e instanceof OperationCancelled) {
  100.         this.setStatus(RobotStatus.Cancelled);
  101.         this._handle.finished(ExitCode.Cancelled);
  102.       } else {
  103.         this.setStatus(RobotStatus.Cancelled);
  104.         this._handle.finished(ExitCode.Errored, e);
  105.       }
  106.     }
  107.   }
  108.  
  109.   public async cancel() {
  110.     this.setStatus(RobotStatus.Cancelling);
  111.     await this.onCancel();
  112.     this.setStatus(RobotStatus.Cancelled);
  113.   }
  114.  
  115.   protected abstract onStart(scope: Scope<{}>): Promise<any>;
  116.  
  117.   protected abstract onCancel(): Promise<any>;
  118.  
  119.   protected abstract onFinished(): Promise<any>;
  120.  
  121.   private setStatus(value: RobotStatus) {
  122.     this._status = value;
  123.     this._handle.statusChanged(value);
  124.   }
  125.  
  126.   protected onDataReceived(data: T) {
  127.     if (
  128.       [RobotStatus.Cancelling, RobotStatus.Cancelled].includes(this._status)
  129.     ) {
  130.       return;
  131.     }
  132.  
  133.     if ([RobotStatus.Initial, RobotStatus.Finished].includes(this._status)) {
  134.       console.log(
  135.         `Received data in ${this._status} status. This means that the robot didn't finish properly.`
  136.      );
  137.    }
  138.  
  139.    this._handle.dataReceived(data);
  140.  }
  141.  
  142.  protected runScope<T, D>(
  143.    scope: Scope<T>,
  144.    params: ScopeParams<D>,
  145.    func: (scope: Scope<D>, ...args: any[]) => Promise<any>,
  146.    ...args: any[]
  147.  ) {
  148.    let newScope: Scope<D> = {
  149.      name: `${scope.name}.${params.name}`,
  150.      data: params.data,
  151.  
  152.      runScope: <E>(
  153.        params: ScopeParams<E>,
  154.        func: (scope: Scope<E>, ...args: any[]) => Promise<any>,
  155.        ...args: any[]
  156.      ) => {
  157.        return this.runScope(newScope, params, func, args);
  158.      },
  159.    };
  160.  
  161.    let promise = func
  162.      .bind(this)(newScope, ...args)
  163.      .then(value => {
  164.        this._tasks.splice(this._tasks.indexOf(promise), 1);
  165.        return value;
  166.      })
  167.      .catch(e => {
  168.        if (e instanceof OperationCancelled) {
  169.          throw e;
  170.        } else {
  171.          console.log(`An error occurred in ${newScope.name} scope`);
  172.          console.log(e);
  173.        }
  174.      });
  175.  
  176.    this._tasks.push(promise);
  177.  
  178.    console.log(`Running scope ${newScope.name}`);
  179.  
  180.    return promise;
  181.  }
  182. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement