Beispiel #1
0
 private function collectProcessGarbage()
 {
     foreach ($this->processes as $key => $procHandle) {
         $info = proc_get_status($procHandle);
         if ($info["running"]) {
             continue;
         }
         $this->defunctProcessCount--;
         proc_close($procHandle);
         unset($this->processes[$key]);
         if ($this->expectedFailures > 0) {
             $this->expectedFailures--;
             continue;
         }
         if (!$this->stopPromisor) {
             $this->spawn();
         }
     }
     // If we've reaped all known dead processes we can stop checking
     if (empty($this->defunctProcessCount)) {
         \Amp\disable($this->procGarbageWatcher);
     }
     if ($this->stopPromisor && empty($this->processes)) {
         \Amp\cancel($this->procGarbageWatcher);
         if ($this->stopPromisor !== true) {
             \Amp\immediately([$this->stopPromisor, "succeed"]);
         }
         $this->stopPromisor = true;
     }
 }
Beispiel #2
0
 /**
  * Write specified $dataToWrite to the $socket destination stream
  *
  * @param resource $socket
  * @param string $dataToWrite
  * @return \Amp\Promise
  */
 public function write($socket, $dataToWrite)
 {
     $this->promisor = new Deferred();
     $this->socket = $socket;
     $this->buffer = $dataToWrite;
     \Amp\immediately(function () {
         $this->doWrite();
     });
     return $this->promisor->promise();
 }
Beispiel #3
0
 public function addConnection()
 {
     \Amp\immediately(function () {
         if (count($this->connections) >= $this->limit) {
             return;
         }
         $this->connections[] = $conn = new Connection($this->config);
         end($this->connections);
         $this->connectionMap[spl_object_hash($conn)] = key($this->connections);
         $this->connectionPromise = $conn->connect();
         $this->connectionPromise->when(function ($error) use($conn) {
             if ($error) {
                 $this->unmapConnection($conn);
                 if (empty($this->connections)) {
                     $this->virtualConnection->fail($error);
                 }
                 return;
             }
             if ($this->config->charset != "utf8mb4" || $this->config->collate != "" && $this->config->collate != "utf8mb4_general_ci") {
                 $conn->setCharset($this->config->charset, $this->config->collate);
             }
         });
     });
 }
Beispiel #4
0
 /**
  * @param int $buffer one of the self::BUFFER_* constants. Determines whether it will buffer the stdout and/or stderr data internally
  * @return Promise is updated with ["out", $data] or ["err", $data] for data received on stdout or stderr
  * That Promise will be resolved to a stdClass object with stdout, stderr (when $buffer is true), exit (holding exit code) and signal (only present when terminated via signal) properties
  */
 public function exec($buffer = self::BUFFER_NONE)
 {
     if ($this->proc) {
         throw new \RuntimeException("Process was already launched");
     }
     $cwd = isset($this->options["cwd"]) ? $this->options["cwd"] : NULL;
     $env = isset($this->options["env"]) ? $this->options["env"] : NULL;
     if (stripos(PHP_OS, "WIN") !== 0) {
         $fds = [["pipe", "r"], ["pipe", "w"], ["pipe", "w"], ["pipe", "w"]];
         $this->proc = @proc_open("{$this->cmd}; echo \$? >&3", $fds, $pipes, $cwd, $env, $this->options);
     } else {
         $options = $this->options;
         $options["bypass_shell"] = true;
         $fds = [["pipe", "r"], ["pipe", "w"], ["pipe", "w"]];
         $this->proc = @proc_open($this->cmd, $fds, $pipes, $cwd, $env, $options);
     }
     if (!$this->proc) {
         return new Failure(new \RuntimeException("Failed executing command: {$this->cmd}"));
     }
     $this->writeBuf = "";
     $this->writeTotal = 0;
     $this->writeCur = 0;
     stream_set_blocking($pipes[0], false);
     stream_set_blocking($pipes[1], false);
     stream_set_blocking($pipes[2], false);
     if (isset($pipes[3])) {
         stream_set_blocking($pipes[3], false);
         $this->openPipes = 3;
     } else {
         $this->openPipes = 2;
     }
     $this->deferred = new Deferred();
     $result = new \stdClass();
     if ($buffer & self::BUFFER_STDOUT) {
         $result->stdout = "";
     }
     if ($buffer & self::BUFFER_STDERR) {
         $result->stderr = "";
     }
     $cleanup = function () use($result) {
         \Amp\cancel($this->stdin);
         $deferreds = $this->writeDeferreds;
         $this->writeDeferreds = [];
         $status = \proc_get_status($this->proc);
         if ($status["running"] === false && $status["signaled"]) {
             $result->signal = $status["termsig"];
             $result->exit = $status["exitcode"];
         }
         if (!isset($this->exit)) {
             $result->exit = proc_close($this->proc);
         }
         unset($this->proc);
         $this->deferred->succeed($result);
         foreach ($deferreds as $deferred) {
             $deferred->fail(new \Exception("Write could not be completed, process finished"));
         }
     };
     $this->stdout = \Amp\onReadable($pipes[1], function ($watcher, $sock) use($result, $cleanup) {
         if ("" == ($data = @\fread($sock, 8192))) {
             \Amp\cancel($watcher);
             if (--$this->openPipes == 0) {
                 \Amp\immediately($cleanup);
             }
         } else {
             if (isset($result->stdout)) {
                 $result->stdout .= $data;
             }
             $this->deferred->update(["out", $data]);
         }
     });
     $this->stderr = \Amp\onReadable($pipes[2], function ($watcher, $sock) use($result, $cleanup) {
         if ("" == ($data = @\fread($sock, 8192))) {
             \Amp\cancel($watcher);
             if (--$this->openPipes == 0) {
                 \Amp\immediately($cleanup);
             }
         } else {
             if (isset($result->stderr)) {
                 $result->stderr .= $data;
             }
             $this->deferred->update(["err", $data]);
         }
     });
     $this->stdin = \Amp\onWritable($pipes[0], function ($watcher, $sock) {
         $this->writeCur += @\fwrite($sock, $this->writeBuf);
         if ($this->writeCur == $this->writeTotal) {
             \Amp\disable($watcher);
         }
         while (($next = key($this->writeDeferreds)) !== null && $next <= $this->writeCur) {
             $this->writeDeferreds[$next]->succeed($this->writeCur);
             unset($this->writeDeferreds[$next]);
         }
     }, ["enable" => false]);
     if (isset($pipes[3])) {
         $this->exit = \Amp\onReadable($pipes[3], function ($watcher, $sock) use($result, $cleanup) {
             stream_set_blocking($sock, true);
             // it should never matter, but just to be really 100% sure.
             $result->exit = (int) stream_get_contents($sock);
             \Amp\cancel($watcher);
             if (--$this->openPipes == 0) {
                 \Amp\immediately($cleanup);
             }
         });
     }
     return $this->deferred->promise();
 }
Beispiel #5
0
 public function do(InternalRequest $ireq)
 {
     $headers = yield;
     if ($headers[":status"] == 101) {
         $yield = (yield $headers);
     } else {
         return $headers;
         // detach if we don't want to establish websocket connection
     }
     while ($yield !== null) {
         $yield = (yield $yield);
     }
     \Amp\immediately([$this, "reapClient"], ["cb_data" => $ireq]);
 }
Beispiel #6
0
 public function do(InternalRequest $ireq)
 {
     $headers = yield;
     if ($headers[":status"] == 101) {
         $yield = (yield $headers);
     } else {
         return $headers;
         // detach if we don't want to establish websocket connection
     }
     while ($yield !== null) {
         $yield = (yield $yield);
     }
     \Amp\immediately(function () use($ireq) {
         $client = new Rfc6455Client();
         $client->connectedAt = $this->now;
         $socket = $ireq->client->socket;
         $client->id = (int) $socket;
         $client->socket = $socket;
         $client->writeBuffer = $ireq->client->writeBuffer;
         $client->serverRefClearer = ($ireq->client->exporter)($ireq->client);
         $client->parser = $this->parser([$this, "onParse"], $options = ["cb_data" => $client]);
         $client->readWatcher = \Amp\onReadable($socket, [$this, "onReadable"], $options = ["enable" => true, "cb_data" => $client]);
         $client->writeWatcher = \Amp\onWritable($socket, [$this, "onWritable"], $options = ["enable" => $client->writeBuffer != "", "cb_data" => $client]);
         $this->clients[$client->id] = $client;
         $this->heartbeatTimeouts[$client->id] = $this->now + $this->heartbeatPeriod;
         resolve($this->tryAppOnOpen($client->id, $ireq->locals["aerys.websocket"]));
     });
 }
Beispiel #7
0
 private function parseSocketData(RequestCycle $cycle)
 {
     try {
         while ($parsedResponseArr = $cycle->parser->parse()) {
             if ($parsedResponseArr['headersOnly']) {
                 $data = [Notify::RESPONSE_HEADERS, $parsedResponseArr];
                 $cycle->futureResponse->update($data);
                 continue;
             } elseif (isset($cycle->continueWatcher) && $parsedResponseArr['status'] == 100) {
                 $this->proceedFrom100ContinueState($cycle);
             } else {
                 $this->assignParsedResponse($cycle, $parsedResponseArr);
             }
             if ($cycle->parser->getBuffer()) {
                 \Amp\immediately(function () use($cycle) {
                     $this->parseSocketData($cycle);
                 });
             }
             break;
         }
     } catch (ParseException $e) {
         $this->fail($cycle, $e);
     }
 }
Beispiel #8
0
 /**
  * @param int $buffer one of the self::BUFFER_* constants. Determines whether it will buffer the stdout and/or stderr data internally
  * @return Promise is updated with ["out", $data] or ["err", $data] for data received on stdout or stderr
  * That Promise will be resolved to a stdClass object with stdout, stderr (when $buffer is true), exit (holding exit code) and signal (only present when terminated via signal) properties
  */
 public function exec($buffer = self::BUFFER_NONE)
 {
     if ($this->proc) {
         throw new \RuntimeException("Process was already launched");
     }
     $fds = [["pipe", "r"], ["pipe", "w"], ["pipe", "w"]];
     $cwd = isset($this->options["cwd"]) ? $this->options["cwd"] : NULL;
     $env = isset($this->options["env"]) ? $this->options["env"] : NULL;
     if (!($this->proc = @proc_open($this->cmd, $fds, $pipes, $cwd, $env, $this->options))) {
         return new Failure(new \RuntimeException("Failed executing command: {$this->cmd}"));
     }
     $this->writeBuf = "";
     $this->writeTotal = 0;
     $this->writeCur = 0;
     stream_set_blocking($pipes[0], false);
     stream_set_blocking($pipes[1], false);
     stream_set_blocking($pipes[2], false);
     $this->deferred = new Deferred();
     $result = new \stdClass();
     if ($buffer & self::BUFFER_STDOUT) {
         $result->stdout = "";
     }
     if ($buffer & self::BUFFER_STDERR) {
         $result->stderr = "";
     }
     $this->stdout = \Amp\onReadable($pipes[1], function ($watcher, $sock) use($result) {
         if ("" == ($data = @fread($sock, 8192))) {
             \Amp\cancel($watcher);
             \Amp\cancel($this->stdin);
             \Amp\immediately(function () use($result) {
                 $status = proc_get_status($this->proc);
                 assert($status["running"] === false);
                 if ($status["signaled"]) {
                     $result->signal = $status["termsig"];
                 }
                 $result->exit = $status["exitcode"];
                 $this->proc = NULL;
                 $this->deferred->succeed($result);
                 foreach ($this->writeDeferreds as $deferred) {
                     $deferred->fail(new \Exception("Write could not be completed, process finished"));
                 }
                 $this->writeDeferreds = [];
             });
         } else {
             isset($result->stdout) && ($result->stdout .= $data);
             $this->deferred->update(["out", $data]);
         }
     });
     $this->stderr = \Amp\onReadable($pipes[2], function ($watcher, $sock) use($result) {
         if ("" == ($data = @fread($sock, 8192))) {
             \Amp\cancel($watcher);
         } else {
             isset($result->stderr) && ($result->stderr .= $data);
             $this->deferred->update(["err", $data]);
         }
     });
     $this->stdin = \Amp\onWritable($pipes[0], function ($watcher, $sock) {
         $this->writeCur += @fwrite($sock, $this->writeBuf);
         if ($this->writeCur == $this->writeTotal) {
             \Amp\disable($watcher);
         }
         while (($next = key($this->writeDeferreds)) !== null && $next <= $this->writeCur) {
             $this->writeDeferreds[$next]->succeed($this->writeCur);
             unset($this->writeDeferreds[$next]);
         }
     }, ["enable" => false]);
     return $this->deferred->promise();
 }
Beispiel #9
0
 /**
  * @param string $name field name
  * @param int $size <= 0: use last size, if none present, count toward total size, else separate size just respecting value size
  * @return FieldBody
  */
 public function stream(string $name, int $size = 0) : FieldBody
 {
     if ($this->req) {
         if ($size > 0) {
             if (!empty($this->curSizes)) {
                 foreach ($this->curSizes[$name] as $partialSize) {
                     $size -= $partialSize;
                     if (!isset($this->sizes[$name])) {
                         $this->usedSize -= $partialSize - \strlen($name);
                     }
                 }
             }
             $this->sizes[$name] = $size;
             $this->body = $this->req->getBody($this->totalSize += $size);
         }
         if (!$this->parsing) {
             $this->parsing = true;
             \Amp\immediately(function () {
                 return $this->initIncremental();
             });
         }
         if (empty($this->bodies[$name])) {
             $this->bodyPromisors[$name][] = [$body = new Deferred(), $metadata = new Deferred()];
             return new FieldBody($body->promise(), $metadata->promise());
         }
     } elseif (empty($this->bodies[$name])) {
         return new FieldBody(new Success(), new Success([]));
     }
     $key = key($this->bodies[$name]);
     $ret = $this->bodies[$name][$key];
     unset($this->bodies[$name][$key], $this->curSizes[$name][$key]);
     return $ret;
 }
Beispiel #10
0
 public function do(InternalRequest $ireq)
 {
     $headers = yield;
     if ($headers[":status"] == 101) {
         $yield = (yield $headers);
     } else {
         return $headers;
         // detach Middleware otherwise
     }
     while ($yield !== null) {
         $yield = (yield $yield);
     }
     \Amp\immediately([$this, "reapClient"], ["cb_data" => $ireq]);
 }