| // Copyright 2013 The Flutter Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| import 'dart:async'; | |
| import 'dart:collection'; | |
| import 'environment.dart'; | |
| /// A WorkerTask. | |
| abstract class WorkerTask { | |
| /// WorkerTask with a name. | |
| WorkerTask(this.name); | |
| /// Name of worker task. | |
| final String name; | |
| /// Run the task which is complete when the returned future completes. | |
| /// Returns true if successful. | |
| Future<bool> run(); | |
| /// Returns the run time of this task. | |
| Duration get runTime { | |
| if (_startTime == null || _finishTime == null) { | |
| return Duration.zero; | |
| } | |
| return _finishTime!.difference(_startTime!); | |
| } | |
| // When did this task start running? | |
| DateTime? _startTime; | |
| // When did this task finish running? | |
| DateTime? _finishTime; | |
| } | |
| /// A pool of worker tasks that will run numWorkers tasks at a time | |
| /// until all of the tasks are finished. | |
| class WorkerPool { | |
| /// Construct a worker pool with a specific reporter and max concurrency | |
| /// limit. | |
| WorkerPool(this._environment, this._reporter, [this._maxConcurrency = 4]); | |
| final Environment _environment; | |
| final WorkerPoolProgressReporter _reporter; | |
| final int _maxConcurrency; | |
| late Completer<bool> _runCompleter; | |
| bool _anyFailed = false; | |
| final Set<WorkerTask> _running = <WorkerTask>{}; | |
| final Set<WorkerTask> _pending = <WorkerTask>{}; | |
| final Set<WorkerTask> _finished = <WorkerTask>{}; | |
| /// Run all tasks in the pool. Report progress via reporter. | |
| /// Returns 0 on success and non-zero on failure. | |
| Future<bool> run(Set<WorkerTask> tasks) async { | |
| _environment.logger.info('Running ${tasks.length}'); | |
| _runCompleter = Completer<bool>(); | |
| _reporter.onRun(tasks); | |
| _pending.addAll(tasks); | |
| _runQueue(); | |
| return _runCompleter.future; | |
| } | |
| /// Returns the current set of pending tasks. | |
| UnmodifiableSetView<WorkerTask> get pending { | |
| return UnmodifiableSetView<WorkerTask>(_pending); | |
| } | |
| /// Returns the current set of running tasks. | |
| UnmodifiableSetView<WorkerTask> get running { | |
| return UnmodifiableSetView<WorkerTask>(_running); | |
| } | |
| /// Returns the current set of finished tasks. | |
| UnmodifiableSetView<WorkerTask> get finished { | |
| return UnmodifiableSetView<WorkerTask>(_finished); | |
| } | |
| void _runQueue() { | |
| if (_pending.isEmpty && _running.isEmpty) { | |
| _reporter.onFinish(); | |
| // Nothing left to do or running. | |
| _runCompleter.complete(!_anyFailed); | |
| return; | |
| } | |
| while (_running.length < _maxConcurrency && _pending.isNotEmpty) { | |
| final WorkerTask task = _pending.elementAt(0); | |
| _pending.remove(task); | |
| _runTask(task); | |
| } | |
| } | |
| Future<void> _runTask(WorkerTask task) async { | |
| task._startTime = DateTime.now(); | |
| final Future<bool> result = task.run(); | |
| _running.add(task); | |
| _reporter.onTaskStart(this, task); | |
| Object? err; | |
| late final bool r; | |
| try { | |
| r = await result; | |
| } catch (e) { | |
| err = e; | |
| r = false; | |
| } | |
| _anyFailed = _anyFailed || !r; | |
| task._finishTime = DateTime.now(); | |
| _running.remove(task); | |
| _finished.add(task); | |
| _reporter.onTaskDone(this, task, err); | |
| // Kick the queue again. | |
| _runQueue(); | |
| } | |
| } | |
| /// WorkerPoolProgressReporter can be used to monitor worker pool progress. | |
| abstract class WorkerPoolProgressReporter { | |
| /// Invoked when [WorkerPool.run] is invoked. | |
| void onRun(Set<WorkerTask> tasks); | |
| /// Invoked right before [WorkerPool.run] is returned from. | |
| void onFinish(); | |
| /// Invoked right after a task has been started. | |
| void onTaskStart(WorkerPool pool, WorkerTask task); | |
| /// Invoked right after a task has finished. | |
| void onTaskDone(WorkerPool pool, WorkerTask task, [Object? err]); | |
| } | |
| /// Useful for tests. | |
| class NoopWorkerPoolProgressReporter implements WorkerPoolProgressReporter { | |
| @override | |
| void onRun(Set<WorkerTask> tasks) {} | |
| @override | |
| void onFinish() {} | |
| @override | |
| void onTaskStart(WorkerPool pool, WorkerTask task) {} | |
| @override | |
| void onTaskDone(WorkerPool pool, WorkerTask task, [Object? err]) {} | |
| } |