task.ts 3.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. /**
  2. * Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. */
  6. import { RuntimeContext } from './execution/runtime-context'
  7. import { Progress } from './execution/progress'
  8. import { ExecuteObservable, ExecuteObservableChild, ExecuteInContext } from './execution/observable';
  9. import { SyncRuntimeContext } from './execution/synchronous';
  10. import { idFactory } from '../mol-util/id-factory';
  11. /** A "named function wrapper" with built in "computation tree progress tracking". */
  12. interface Task<T> {
  13. /** run the task without observation */
  14. run(): Promise<T>,
  15. /** run the task with the specified observer, default updateRate is 250ms */
  16. run(observer: Progress.Observer, updateRateMs?: number): Promise<T>,
  17. /**
  18. * Run a child task that adds a new node to the progress tree. Allows to passing the progress so
  19. * that the progress tree can be kept in a "good state" without having to separately call update.
  20. */
  21. runAsChild(ctx: RuntimeContext, progress?: string | Partial<RuntimeContext.ProgressUpdate>): Promise<T>
  22. /** Run the task on the specified context. */
  23. runInContext(ctx: RuntimeContext): Promise<T>
  24. readonly id: number,
  25. readonly name: string
  26. }
  27. namespace Task {
  28. class Impl<T> implements Task<T> {
  29. readonly id: number;
  30. run(observer?: Progress.Observer, updateRateMs = 250): Promise<T> {
  31. if (observer) return ExecuteObservable(this, observer, updateRateMs);
  32. return this.f(SyncRuntimeContext);
  33. }
  34. runAsChild(ctx: RuntimeContext, progress?: string | Partial<RuntimeContext.ProgressUpdate>): Promise<T> {
  35. if (ctx.isSynchronous) return this.f(SyncRuntimeContext);
  36. return ExecuteObservableChild(ctx, this, progress as string | Partial<RuntimeContext.ProgressUpdate>);
  37. }
  38. runInContext(ctx: RuntimeContext): Promise<T> {
  39. if (ctx.isSynchronous) return this.f(SyncRuntimeContext);
  40. return ExecuteInContext(ctx, this);
  41. }
  42. constructor(public name: string, public f: (ctx: RuntimeContext) => Promise<T>, public onAbort?: () => void) {
  43. this.id = getNextId();
  44. }
  45. }
  46. export function is<T = any>(t: any): t is Task<T> {
  47. const _t = t as Task<any>;
  48. return !!t && typeof _t.id === 'number' && typeof _t.name === 'string' && !!_t.run;
  49. }
  50. export interface Aborted { isAborted: true, reason: string, toString(): string }
  51. export function isAbort(e: any): e is Aborted { return !!e && !!e.isAborted; }
  52. export function Aborted(reason: string): Aborted { return { isAborted: true, reason, toString() { return `Aborted${reason ? ': ' + reason : ''}`; } }; }
  53. export function create<T>(name: string, f: (ctx: RuntimeContext) => Promise<T>, onAbort?: () => void): Task<T> {
  54. return new Impl(name, f, onAbort);
  55. }
  56. export function constant<T>(name: string, value: T): Task<T> { return create(name, async ctx => value); }
  57. export function empty(): Task<void> { return create('', async ctx => {}); }
  58. export function fail(name: string, reason: string): Task<any> { return create(name, async ctx => { throw new Error(reason); }); }
  59. export interface Progress {
  60. taskId: number,
  61. taskName: string,
  62. startedTime: number,
  63. message: string,
  64. canAbort: boolean,
  65. isIndeterminate: boolean,
  66. current: number,
  67. max: number
  68. }
  69. const getNextId = idFactory(0, 0x3fffffff)
  70. }
  71. export { Task }