private function connect() { // If we're in the process of connecting already return that same promise if ($this->connectPromisor) { return $this->connectPromisor->promise(); } // If a read watcher exists we know we're already connected if ($this->readWatcher) { return new Success($this); } $this->connectPromisor = new Deferred(); $socketPromise = connect($this->uri, ["timeout" => $this->timeout]); $onWrite = function ($watcherId) { if ($this->outputBufferLength === 0) { disable($watcherId); return; } $bytes = @fwrite($this->socket, $this->outputBuffer); if ($bytes === 0) { $this->onError(new ConnectException("Connection went away (write)", $code = 1)); } else { $this->outputBuffer = (string) substr($this->outputBuffer, $bytes); $this->outputBufferLength -= $bytes; } }; $socketPromise->when(function ($error, $socket) use($onWrite) { $connectPromisor = $this->connectPromisor; $this->connectPromisor = null; if ($error) { $connectPromisor->fail(new ConnectException("Connection attempt failed", $code = 0, $error)); return; } $this->socket = $socket; foreach ($this->handlers["connect"] as $handler) { $pipelinedCommand = $handler(); if (!empty($pipelinedCommand)) { $this->outputBuffer = $pipelinedCommand . $this->outputBuffer; $this->outputBufferLength += strlen($pipelinedCommand); } } $this->readWatcher = onReadable($this->socket, function () { $read = fread($this->socket, 8192); if ($read != "") { $this->parser->append($read); } elseif (!is_resource($this->socket) || @feof($this->socket)) { $this->onError(new ConnectException("Connection went away (read)", $code = 2)); } }); $this->writeWatcher = onWritable($this->socket, $onWrite, ["enable" => !empty($this->outputBuffer)]); $connectPromisor->succeed(); }); return $this->connectPromisor->promise(); }
/** * Receive notifications from the server when it starts/stops * * @param Server $server * @return \Amp\Promise */ public function update(Server $server) : amp\Promise { switch ($server->state()) { case Server::STARTING: $this->loadMimeFileTypes(__DIR__ . "/../etc/mime"); break; case Server::STARTED: $this->debug = $server->getOption("debug"); amp\enable($this->cacheWatcher); break; case Server::STOPPED: amp\disable($this->cacheWatcher); $this->cache = []; $this->cacheTimeouts = []; $this->cacheEntryCount = 0; $this->bufferedFileCount = 0; break; } return new amp\Success(); }
/** * Receive notifications from the server when it starts/stops * * @param \SplSubject $subject * @return \Amp\Promise */ public function update(\SplSubject $subject) : amp\Promise { switch ($subject->state()) { case Server::STARTED: $this->debug = $subject->getOption("debug"); amp\enable($this->cacheWatcher); break; case Server::STOPPED: amp\disable($this->cacheWatcher); $this->cache = []; $this->cacheTimeouts = []; $this->cacheEntryCount = 0; $this->bufferedFileCount = 0; break; } return new amp\Success(); }
private static function onWrite($state, $op, $bytes) { $op->bytesWritten += $bytes; if ($op->bytesWritten < $op->size) { return; } \array_shift($state->writeOperations); $options = ["cb_data" => [$state, $op, $op->bytesWritten]]; amp\immediately(self::$succeeder, $options); if (empty($state->writeOperations)) { $state->isWriteEnabled = false; amp\disable($state->writeWatcherId); } }