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.then(() => { 40 this.promisesFulfilled += 1; 41 }).catch(() => { 42 this.promisesRejected += 1; 43 }).finally(() => { 44 this.promiseInfo.delete(promise); 45 }); 46 } 47 48 hasPendingTasks(): boolean { 49 return this.promisesSeen > (this.promisesFulfilled + this.promisesRejected); 50 } 51 52 progressMessage(): string|undefined { 53 const {value} = this.promiseInfo.values().next(); 54 if (value === undefined) { 55 return value; 56 } else { 57 const nowMs = (new Date()).getMilliseconds(); 58 const runtimeSeconds = Math.round((nowMs - value.startTimeMs) / 1000); 59 return `${value.message} (${runtimeSeconds}s)`; 60 } 61 } 62} 63 64export const taskTracker = new TaskTracker(); 65