1// Copyright (C) 2020 The Android Open Source Project 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15interface PromiseInfo { 16 startTimeMs: number; 17 message: string; 18} 19 20export class TaskTracker { 21 private promisesSeen: number; 22 private promisesRejected: number; 23 private promisesFulfilled: number; 24 private promiseInfo: Map<Promise<unknown>, PromiseInfo>; 25 26 constructor() { 27 this.promisesSeen = 0; 28 this.promisesRejected = 0; 29 this.promisesFulfilled = 0; 30 this.promiseInfo = new Map(); 31 } 32 33 trackPromise(promise: Promise<unknown>, message: string): void { 34 this.promiseInfo.set(promise, { 35 startTimeMs: new Date().getMilliseconds(), 36 message, 37 }); 38 this.promisesSeen += 1; 39 promise 40 .then(() => { 41 this.promisesFulfilled += 1; 42 }) 43 .catch(() => { 44 this.promisesRejected += 1; 45 }) 46 .finally(() => { 47 this.promiseInfo.delete(promise); 48 }); 49 } 50 51 hasPendingTasks(): boolean { 52 return this.promisesSeen > this.promisesFulfilled + this.promisesRejected; 53 } 54 55 progressMessage(): string | undefined { 56 const {value} = this.promiseInfo.values().next(); 57 if (value === undefined) { 58 return value; 59 } else { 60 const nowMs = new Date().getMilliseconds(); 61 const runtimeSeconds = Math.round((nowMs - value.startTimeMs) / 1000); 62 return `${value.message} (${runtimeSeconds}s)`; 63 } 64 } 65} 66 67export const taskTracker = new TaskTracker(); 68