Changeset View
Changeset View
Standalone View
Standalone View
src/console/PhutilConsoleServer.php
- This file was added.
| <?php | |||||
| final class PhutilConsoleServer extends Phobject { | |||||
| private $clients = array(); | |||||
| private $handler; | |||||
| private $enableLog; | |||||
| public function handleMessage(PhutilConsoleMessage $message) { | |||||
| $data = $message->getData(); | |||||
| $type = $message->getType(); | |||||
| switch ($type) { | |||||
| case PhutilConsoleMessage::TYPE_CONFIRM: | |||||
| $ok = phutil_console_confirm($data['prompt'], !$data['default']); | |||||
| return $this->buildMessage( | |||||
| PhutilConsoleMessage::TYPE_INPUT, | |||||
| $ok); | |||||
| case PhutilConsoleMessage::TYPE_PROMPT: | |||||
| $response = phutil_console_prompt( | |||||
| $data['prompt'], | |||||
| idx($data, 'history')); | |||||
| return $this->buildMessage( | |||||
| PhutilConsoleMessage::TYPE_INPUT, | |||||
| $response); | |||||
| case PhutilConsoleMessage::TYPE_OUT: | |||||
| $this->writeText(STDOUT, $data); | |||||
| return null; | |||||
| case PhutilConsoleMessage::TYPE_ERR: | |||||
| $this->writeText(STDERR, $data); | |||||
| return null; | |||||
| case PhutilConsoleMessage::TYPE_LOG: | |||||
| if ($this->enableLog) { | |||||
| $this->writeText(STDERR, $data); | |||||
| } | |||||
| return null; | |||||
| case PhutilConsoleMessage::TYPE_ENABLED: | |||||
| switch ($data['which']) { | |||||
| case PhutilConsoleMessage::TYPE_LOG: | |||||
| $enabled = $this->enableLog; | |||||
| break; | |||||
| default: | |||||
| $enabled = true; | |||||
| break; | |||||
| } | |||||
| return $this->buildMessage( | |||||
| PhutilConsoleMessage::TYPE_IS_ENABLED, | |||||
| $enabled); | |||||
| case PhutilConsoleMessage::TYPE_TTY: | |||||
| case PhutilConsoleMessage::TYPE_COLS: | |||||
| switch ($data['which']) { | |||||
| case PhutilConsoleMessage::TYPE_OUT: | |||||
| $which = STDOUT; | |||||
| break; | |||||
| case PhutilConsoleMessage::TYPE_ERR: | |||||
| $which = STDERR; | |||||
| break; | |||||
| } | |||||
| switch ($type) { | |||||
| case PhutilConsoleMessage::TYPE_TTY: | |||||
| if (function_exists('posix_isatty')) { | |||||
| $is_a_tty = posix_isatty($which); | |||||
| } else { | |||||
| $is_a_tty = null; | |||||
| } | |||||
| return $this->buildMessage( | |||||
| PhutilConsoleMessage::TYPE_IS_TTY, | |||||
| $is_a_tty); | |||||
| case PhutilConsoleMessage::TYPE_COLS: | |||||
| // TODO: This is an approximation which might not be perfectly | |||||
| // accurate. | |||||
| $width = phutil_console_get_terminal_width(); | |||||
| return $this->buildMessage( | |||||
| PhutilConsoleMessage::TYPE_COL_WIDTH, | |||||
| $width); | |||||
| } | |||||
| break; | |||||
| default: | |||||
| if ($this->handler) { | |||||
| return call_user_func($this->handler, $message); | |||||
| } else { | |||||
| throw new Exception( | |||||
| pht( | |||||
| "Received unknown console message of type '%s'.", | |||||
| $type)); | |||||
| } | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Set handler called for unknown messages. | |||||
| * | |||||
| * @param callable Signature: (PhutilConsoleMessage $message). | |||||
| */ | |||||
| public function setHandler($callback) { | |||||
| $this->handler = $callback; | |||||
| return $this; | |||||
| } | |||||
| private function buildMessage($type, $data) { | |||||
| $response = new PhutilConsoleMessage(); | |||||
| $response->setType($type); | |||||
| $response->setData($data); | |||||
| return $response; | |||||
| } | |||||
| public function addExecFutureClient(ExecFuture $future) { | |||||
| $io_channel = new PhutilExecChannel($future); | |||||
| $protocol_channel = new PhutilPHPObjectProtocolChannel($io_channel); | |||||
| $server_channel = new PhutilConsoleServerChannel($protocol_channel); | |||||
| $io_channel->setStderrHandler(array($server_channel, 'didReceiveStderr')); | |||||
| return $this->addClient($server_channel); | |||||
| } | |||||
| public function addClient(PhutilConsoleServerChannel $channel) { | |||||
| $this->clients[] = $channel; | |||||
| return $this; | |||||
| } | |||||
| public function setEnableLog($enable) { | |||||
| $this->enableLog = $enable; | |||||
| return $this; | |||||
| } | |||||
| public function run() { | |||||
| while ($this->clients) { | |||||
| PhutilChannel::waitForAny($this->clients); | |||||
| foreach ($this->clients as $key => $client) { | |||||
| if (!$client->update()) { | |||||
| // If the client has exited, remove it from the list of clients. | |||||
| // We still need to process any remaining buffered I/O. | |||||
| unset($this->clients[$key]); | |||||
| } | |||||
| while ($message = $client->read()) { | |||||
| $response = $this->handleMessage($message); | |||||
| if ($response) { | |||||
| $client->write($response); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| private function writeText($where, array $argv) { | |||||
| $text = call_user_func_array('phutil_console_format', $argv); | |||||
| fprintf($where, '%s', $text); | |||||
| } | |||||
| } | |||||