Page MenuHomePhabricator

D20746.id49466.diff
No OneTemporary

D20746.id49466.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -189,6 +189,7 @@
'PhutilConsoleMetrics' => 'console/PhutilConsoleMetrics.php',
'PhutilConsoleMetricsSignalHandler' => 'future/exec/PhutilConsoleMetricsSignalHandler.php',
'PhutilConsoleProgressBar' => 'console/PhutilConsoleProgressBar.php',
+ 'PhutilConsoleProgressSink' => 'progress/PhutilConsoleProgressSink.php',
'PhutilConsoleServer' => 'console/PhutilConsoleServer.php',
'PhutilConsoleServerChannel' => 'console/PhutilConsoleServerChannel.php',
'PhutilConsoleSkip' => 'console/view/PhutilConsoleSkip.php',
@@ -366,6 +367,7 @@
'PhutilProcessQuery' => 'filesystem/PhutilProcessQuery.php',
'PhutilProcessRef' => 'filesystem/PhutilProcessRef.php',
'PhutilProcessRefTestCase' => 'filesystem/__tests__/PhutilProcessRefTestCase.php',
+ 'PhutilProgressSink' => 'progress/PhutilProgressSink.php',
'PhutilProseDiff' => 'utils/PhutilProseDiff.php',
'PhutilProseDiffTestCase' => 'utils/__tests__/PhutilProseDiffTestCase.php',
'PhutilProseDifferenceEngine' => 'utils/PhutilProseDifferenceEngine.php',
@@ -851,6 +853,7 @@
'PhutilConsoleMetrics' => 'Phobject',
'PhutilConsoleMetricsSignalHandler' => 'PhutilSignalHandler',
'PhutilConsoleProgressBar' => 'Phobject',
+ 'PhutilConsoleProgressSink' => 'PhutilProgressSink',
'PhutilConsoleServer' => 'Phobject',
'PhutilConsoleServerChannel' => 'PhutilChannelChannel',
'PhutilConsoleSkip' => 'PhutilConsoleLogLine',
@@ -1033,6 +1036,7 @@
'PhutilProcessQuery' => 'Phobject',
'PhutilProcessRef' => 'Phobject',
'PhutilProcessRefTestCase' => 'PhutilTestCase',
+ 'PhutilProgressSink' => 'Phobject',
'PhutilProseDiff' => 'Phobject',
'PhutilProseDiffTestCase' => 'PhutilTestCase',
'PhutilProseDifferenceEngine' => 'Phobject',
diff --git a/src/future/http/HTTPSFuture.php b/src/future/http/HTTPSFuture.php
--- a/src/future/http/HTTPSFuture.php
+++ b/src/future/http/HTTPSFuture.php
@@ -25,6 +25,7 @@
private $downloadPath;
private $downloadHandle;
private $parser;
+ private $progressSink;
/**
* Create a temp file containing an SSL cert, and use it for this session.
@@ -154,6 +155,15 @@
return $this;
}
+ public function setProgressSink(PhutilProgressSink $progress_sink) {
+ $this->progressSink = $progress_sink;
+ return $this;
+ }
+
+ public function getProgressSink() {
+ return $this->progressSink;
+ }
+
/**
* Attach a file to the request.
*
@@ -406,6 +416,11 @@
$streaming_parser->setWriteHandle($this->downloadHandle);
}
+ $progress_sink = $this->getProgressSink();
+ if ($progress_sink) {
+ $streaming_parser->setProgressSink($progress_sink);
+ }
+
$this->parser = $streaming_parser;
}
} else {
@@ -499,6 +514,16 @@
}
}
+ $sink = $this->getProgressSink();
+ if ($sink) {
+ $status = head($this->result);
+ if ($status->isError()) {
+ $sink->didFailWork();
+ } else {
+ $sink->didCompleteWork();
+ }
+ }
+
$profiler = PhutilServiceProfiler::getInstance();
$profiler->endServiceCall($this->profilerCallID, array());
diff --git a/src/parser/http/PhutilHTTPResponseParser.php b/src/parser/http/PhutilHTTPResponseParser.php
--- a/src/parser/http/PhutilHTTPResponseParser.php
+++ b/src/parser/http/PhutilHTTPResponseParser.php
@@ -8,6 +8,7 @@
private $buffer;
private $state = 'headers';
private $writeHandle;
+ private $progressSink;
public function setFollowLocationHeaders($follow_location_headers) {
$this->followLocationHeaders = $follow_location_headers;
@@ -27,6 +28,15 @@
return $this->writeHandle;
}
+ public function setProgressSink(PhutilProgressSink $progress_sink) {
+ $this->progressSink = $progress_sink;
+ return $this;
+ }
+
+ public function getProgressSink() {
+ return $this->progressSink;
+ }
+
public function readBytes($bytes) {
if ($this->state == 'discard') {
return $this;
@@ -154,8 +164,15 @@
if ($this->state == 'body') {
if (strlen($this->buffer)) {
- $this->response->appendBody($this->buffer);
+ $bytes = $this->buffer;
$this->buffer = '';
+
+ $this->response->appendBody($bytes);
+
+ $sink = $this->getProgressSink();
+ if ($sink) {
+ $sink->didMakeProgress(strlen($bytes));
+ }
}
break;
}
diff --git a/src/progress/PhutilConsoleProgressSink.php b/src/progress/PhutilConsoleProgressSink.php
new file mode 100644
--- /dev/null
+++ b/src/progress/PhutilConsoleProgressSink.php
@@ -0,0 +1,115 @@
+<?php
+
+final class PhutilConsoleProgressSink
+ extends PhutilProgressSink {
+
+ private $lastUpdate;
+ private $isTTY;
+ private $width;
+ private $lineWidth;
+
+ protected function publishProgress() {
+ if (!$this->shouldPublishToConsole()) {
+ return;
+ }
+
+ $completed = $this->getCompletedWork();
+ $total = $this->getTotalWork();
+
+ if ($total !== null) {
+ $percent = ($completed / $total);
+ $percent = min(1, $percent);
+ $percent = max(0, $percent);
+ } else {
+ $percent = null;
+ }
+
+ // TODO: In TTY mode, draw a nice ASCII progress bar.
+
+ if ($percent !== null) {
+ $marker = sprintf('% 3.1f%%', 100 * $percent);
+ } else {
+ $marker = sprintf('% 16d', $completed);
+ }
+
+ $message = pht('[%s] Working...', $marker);
+
+ if ($this->isTTY()) {
+ $this->overwriteLine($message);
+ } else {
+ $this->printLine($message."\n");
+ }
+
+ $this->didPublishToConsole();
+ }
+
+ protected function publishCompletion() {
+ $this->printLine("\n");
+ }
+
+ protected function publishFailure() {
+ $this->printLine("\n");
+ }
+
+ private function shouldPublishToConsole() {
+ if (!$this->lastUpdate) {
+ return true;
+ }
+
+ // Limit the number of times per second we actually write to the console.
+ if ($this->isTTY()) {
+ $writes_per_second = 5;
+ } else {
+ $writes_per_second = 0.5;
+ }
+
+ $now = microtime(true);
+ if (($now - $this->lastUpdate) < (1.0 / $writes_per_second)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ private function didPublishToConsole() {
+ $this->lastUpdate = microtime(true);
+ }
+
+ private function isTTY() {
+ if ($this->isTTY === null) {
+ $this->isTTY = (function_exists('posix_isatty') && posix_isatty(STDERR));
+ }
+ return $this->isTTY;
+ }
+
+ private function getWidth() {
+ if ($this->width === null) {
+ $width = phutil_console_get_terminal_width();
+ $width = min(nonempty($width, 78), 78);
+ $this->width = $width;
+ }
+
+ return $this->width;
+ }
+
+ private function overwriteLine($line) {
+ $head = "\r";
+ $tail = '';
+
+ if ($this->lineWidth) {
+ $line_len = strlen($line);
+
+ if ($line_len < $this->lineWidth) {
+ $tail = str_repeat(' ', $this->lineWidth - $line_len);
+ }
+
+ $this->lineWidth = strlen($line);
+ }
+
+ $this->printLine($head.$line.$tail);
+ }
+
+ private function printLine($line) {
+ fprintf(STDERR, '%s', $line);
+ }
+}
diff --git a/src/progress/PhutilProgressSink.php b/src/progress/PhutilProgressSink.php
new file mode 100644
--- /dev/null
+++ b/src/progress/PhutilProgressSink.php
@@ -0,0 +1,54 @@
+<?php
+
+abstract class PhutilProgressSink
+ extends Phobject {
+
+ private $isRunning;
+ private $totalWork;
+ private $completedWork;
+
+ public function __construct() {
+ $this->isRunning = true;
+ }
+
+ public function __destruct() {
+ if ($this->isRunning) {
+ $this->didFailWork();
+ }
+ }
+
+ final public function setTotalWork($total_work) {
+ $this->totalWork = $total_work;
+ return $this;
+ }
+
+ final public function getTotalWork() {
+ return $this->totalWork;
+ }
+
+ final public function getCompletedWork() {
+ return $this->completedWork;
+ }
+
+ final public function didMakeProgress($amount = 1) {
+ if ($this->isRunning) {
+ $this->completedWork += $amount;
+ $this->publishProgress();
+ }
+ }
+
+ final public function didCompleteWork() {
+ $this->isRunning = false;
+ $this->publishCompletion();
+ }
+
+ final public function didFailWork() {
+ $this->isRunning = false;
+ $this->publishFailure();
+ }
+
+ abstract protected function publishProgress();
+ abstract protected function publishCompletion();
+ abstract protected function publishFailure();
+
+}

File Metadata

Mime Type
text/plain
Expires
Tue, Mar 18, 2:27 PM (5 d, 23 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7709984
Default Alt Text
D20746.id49466.diff (8 KB)

Event Timeline