/** * @param WorkerBootstrapProfile $bootstrapProfile * @param string $implementationExpression */ protected function __construct(WorkerBootstrapProfile $bootstrapProfile, $implementationExpression) { $bootstrapProfile->getOrFindPhpExecutablePathAndArguments($php, $phpArgs); $bootstrapProfile->compileScriptWithExpression($implementationExpression, null, $scriptPath, $deleteScript); try { $line = array_merge([$php], $phpArgs, [$scriptPath]); $outPath = $bootstrapProfile->getOutputPath(); $this->process = proc_open(implode(' ', array_map('escapeshellarg', $line)), [0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => $outPath !== null ? ['file', $outPath, 'a'] : STDERR], $pipes); $inputSink = Sink::fromStream($pipes[0], true); $outputSource = Source::fromStream($pipes[1], true); $this->channel = $bootstrapProfile->getChannelFactory()->createChannel($outputSource, $inputSink); } catch (\Exception $e) { if (isset($pipes[1])) { fclose($pipes[1]); } if (isset($pipes[0])) { fclose($pipes[0]); } if (isset($this->process)) { proc_terminate($this->process); proc_close($this->process); } if ($deleteScript) { unlink($scriptPath); } throw $e; } }
/** * @param string $socketAddress * @param WorkerBootstrapProfile $bootstrapProfile * @param int|null $timeout * * @throws Exception\ConnectException * * @return ChannelInterface */ private static function connect($socketAddress, WorkerBootstrapProfile $bootstrapProfile, $timeout = null) { $socket = SocketFactory::createClientSocket($socketAddress, $timeout); $connection = Source::fromStream($socket, true, null, false); return $bootstrapProfile->getChannelFactory()->createChannel(new BufferedSource($connection), $connection); }
/** * @param SharedWorkerImplementationInterface $workerImpl * @param string $socketAddress * * @throws Exception\BindOrListenException * @throws Exception\RuntimeException */ public static function runSharedWorker(SharedWorkerImplementationInterface $workerImpl, $socketAddress) { $server = self::startListening($socketAddress); try { $loop = self::getLoop(); $loop->addReadStream($server, function () use($loop, $server, $workerImpl) { $socket = stream_socket_accept($server); $peerName = stream_socket_get_name($socket, true); $connection = Source::fromStream($socket, true, null, false); $channel = self::getChannelFactory()->createChannel(new BufferedSource($connection), $connection); Selectable::registerRead($loop, $channel, function () use($loop, $channel, $peerName, $workerImpl) { try { $message = $channel->receiveMessage(); } catch (IOException\UnderflowException $e) { Selectable::unregisterRead($loop, $channel); $workerImpl->onDisconnect($channel); return; } if (AdminEncoding::isStopMessage($message, self::$adminCookie, $privileged)) { if ($privileged) { $lock = Lock::acquire(); self::stopListening(); $workerImpl->onStop(); $lock->release(); } } elseif (AdminEncoding::isQueryMessage($message, self::$adminCookie, $privileged)) { $result = $workerImpl->onQuery($privileged); if (!$result instanceof WorkerStatus) { $result = new WorkerStatus($result); } AdminEncoding::sendStatusMessage($channel, $result); } else { $workerImpl->onMessage($message, $channel, $peerName); } }); $workerImpl->onConnect($channel, $peerName); }); $workerImpl->setLoop($loop); $workerImpl->initialize(); $loop->run(); $workerImpl->terminate(); } finally { self::stopListening(); } }