php-spark/src/Pipe/Filters/ProgressFilter.php

98 lines
2.5 KiB
PHP

<?php
namespace Spark\Pipe\Filters;
class ProgressFilter implements FilterInterface
{
private array $args = [];
private static $defaultArgs = [
'max' => null,
];
private ?int $max = null;
private int $current = 0;
private int $lastCurrent = 0;
private ?int $nextRefresh = null;
private array $deltas = [];
private array $times = [];
public function setArguments(array $args)
{
$this->args = array_merge(self::$defaultArgs, $args);
$max = $this->args['max'];
if (str_starts_with($max, '@')) {
$this->max = filesize(substr($max,1));
} else {
$this->max = $max;
}
}
public function pipe(?string $chunk)
{
if ($chunk === null) {
$this->nextRefresh = 0;
$this->refresh();
fwrite(STDERR, "\n");
return;
}
$this->current += strlen($chunk);
$this->refresh();
return $chunk;
}
private function refresh()
{
if (microtime(true) < $this->nextRefresh) {
return;
}
$now = microtime(true);
$delta = $this->current - $this->lastCurrent;
array_push($this->deltas, $delta);
array_push($this->times, $now);
while (count($this->deltas) > 10) {
array_shift($this->deltas);
array_shift($this->times);
}
$deltaTime = end($this->times) - reset($this->times);
if ($deltaTime > 0) {
$rate = array_sum($this->deltas) / $deltaTime;
$rateu = "b/s";
if ($rate > 1024) {
$rate /= 1024;
$rateu = "KiB/s";
if ($rate > 1024) {
$rate /= 1024;
$rateu = "MiB/s";
if ($rate > 1024) {
$rate /= 1024;
$rateu = "GiB/s";
}
}
}
} else {
$rate = null;
}
if ($this->max) {
fprintf(STDERR, "\r%.1fMiB/%.1fMiB (%.1f%%) ", $this->current/1024/1024, $this->max/1024/1024, 100/$this->max*$this->current);
} else {
fprintf(STDERR, "\r%.1fMiB ", $this->current/1024/1024);
}
if ($rate) {
fprintf(STDERR, "(%.1f%s)", $rate, $rateu);
}
fprintf(STDERR, "\e[K");
$this->lastCurrent = $this->current;
$this->nextRefresh = $now + .1;
}
}