major refactoring under the hood
[pharext/pharext] / src / pharext / Task / StreamFetch.php
diff --git a/src/pharext/Task/StreamFetch.php b/src/pharext/Task/StreamFetch.php
new file mode 100644 (file)
index 0000000..4f090ef
--- /dev/null
@@ -0,0 +1,75 @@
+<?php
+
+namespace pharext\Task;
+
+use pharext\Exception;
+use pharext\Task;
+use pharext\Tempfile;
+
+/**
+ * Fetch a remote archive
+ */
+class StreamFetch implements Task
+{
+       /**
+        * @var string
+        */
+       private $source;
+
+       /**
+        * @var callable
+        */
+       private $progress;
+
+       /**
+        * @param string $source remote file location
+        * @param callable $progress progress callback
+        */
+       public function __construct($source, callable $progress) {
+               $this->source = $source;
+               $this->progress = $progress;
+       }
+
+       private function createStreamContext() {
+               $progress = $this->progress;
+
+               return stream_context_create([],["notification" => function($notification, $severity, $message, $code, $bytes_cur, $bytes_max) use($progress) {
+                       switch ($notification) {
+                               case STREAM_NOTIFY_CONNECT:
+                                       $progress(0);
+                                       break;
+                               case STREAM_NOTIFY_PROGRESS:
+                                       $progress($bytes_max ? $bytes_cur/$bytes_max : .5);
+                                       break;
+                               case STREAM_NOTIFY_COMPLETED:
+                                       /* this is not generated, why? */
+                                       $progress(1);
+                                       break;
+                       }
+               }]);
+       }
+
+       /**
+        * @param bool $verbose
+        * @return \pharext\Task\Tempfile
+        * @throws \pharext\Exception
+        */
+       public function run($verbose = false) {
+               $context = $this->createStreamContext();
+
+               if (!$remote = fopen($this->source, "r", false, $context)) {
+                       throw new Exception;
+               }
+               
+               $local = new Tempfile("remote");
+               if (!stream_copy_to_stream($remote, $local->getStream())) {
+                       throw new Exception;
+               }
+               $local->closeStream();
+
+               /* STREAM_NOTIFY_COMPLETED is not generated, see above */
+               call_user_func($this->progress, 1);
+
+               return $local;
+       }
+}