Changeset View
Changeset View
Standalone View
Standalone View
src/hgdaemon/ArcanistHgProxyServer.php
| Show First 20 Lines • Show All 162 Lines • ▼ Show 20 Lines | public function start() { | ||||
| if (!$this->doNotDaemonize) { | if (!$this->doNotDaemonize) { | ||||
| $this->daemonize(); | $this->daemonize(); | ||||
| } | } | ||||
| // Start the Mercurial process which we'll forward client requests to. | // Start the Mercurial process which we'll forward client requests to. | ||||
| $hg = $this->startMercurialProcess(); | $hg = $this->startMercurialProcess(); | ||||
| $clients = array(); | $clients = array(); | ||||
| $this->log(null, 'Listening'); | $this->log(null, pht('Listening')); | ||||
| $this->idleSince = time(); | $this->idleSince = time(); | ||||
| while (true) { | while (true) { | ||||
| // Wait for activity on any active clients, the Mercurial process, or | // Wait for activity on any active clients, the Mercurial process, or | ||||
| // the listening socket where new clients connect. | // the listening socket where new clients connect. | ||||
| PhutilChannel::waitForAny( | PhutilChannel::waitForAny( | ||||
| array_merge($clients, array($hg)), | array_merge($clients, array($hg)), | ||||
| array( | array( | ||||
| 'read' => $socket ? array($socket) : array(), | 'read' => $socket ? array($socket) : array(), | ||||
| 'except' => $socket ? array($socket) : array(), | 'except' => $socket ? array($socket) : array(), | ||||
| )); | )); | ||||
| if (!$hg->update()) { | if (!$hg->update()) { | ||||
| throw new Exception('Server exited unexpectedly!'); | throw new Exception(pht('Server exited unexpectedly!')); | ||||
| } | } | ||||
| // Accept any new clients. | // Accept any new clients. | ||||
| while ($socket && ($client = $this->acceptNewClient($socket))) { | while ($socket && ($client = $this->acceptNewClient($socket))) { | ||||
| $clients[] = $client; | $clients[] = $client; | ||||
| $key = last_key($clients); | $key = last_key($clients); | ||||
| $client->setName($key); | $client->setName($key); | ||||
| $this->log($client, 'Connected'); | $this->log($client, pht('Connected')); | ||||
| $this->idleSince = time(); | $this->idleSince = time(); | ||||
| // Check if we've hit the client limit. If there's a configured | // Check if we've hit the client limit. If there's a configured | ||||
| // client limit and we've hit it, stop accepting new connections | // client limit and we've hit it, stop accepting new connections | ||||
| // and close the socket. | // and close the socket. | ||||
| $this->lifetimeClientCount++; | $this->lifetimeClientCount++; | ||||
| Show All 9 Lines | while (true) { | ||||
| foreach ($clients as $key => $client) { | foreach ($clients as $key => $client) { | ||||
| if ($this->updateClient($client, $hg)) { | if ($this->updateClient($client, $hg)) { | ||||
| // In this case, the client is still connected so just move on to | // In this case, the client is still connected so just move on to | ||||
| // the next one. Otherwise we continue below and handle the | // the next one. Otherwise we continue below and handle the | ||||
| // disconnect. | // disconnect. | ||||
| continue; | continue; | ||||
| } | } | ||||
| $this->log($client, 'Disconnected'); | $this->log($client, pht('Disconnected')); | ||||
| unset($clients[$key]); | unset($clients[$key]); | ||||
| // If we have a client limit and we've served that many clients, exit. | // If we have a client limit and we've served that many clients, exit. | ||||
| if ($this->clientLimit) { | if ($this->clientLimit) { | ||||
| if ($this->lifetimeClientCount >= $this->clientLimit) { | if ($this->lifetimeClientCount >= $this->clientLimit) { | ||||
| if (!$clients) { | if (!$clients) { | ||||
| $this->log(null, 'Exiting (Client Limit)'); | $this->log(null, pht('Exiting (Client Limit)')); | ||||
| return; | return; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| // If we have an idle limit and haven't had any activity in at least | // If we have an idle limit and haven't had any activity in at least | ||||
| // that long, exit. | // that long, exit. | ||||
| if ($this->idleLimit) { | if ($this->idleLimit) { | ||||
| $remaining = $this->idleLimit - (time() - $this->idleSince); | $remaining = $this->idleLimit - (time() - $this->idleSince); | ||||
| if ($remaining <= 0) { | if ($remaining <= 0) { | ||||
| $this->log(null, 'Exiting (Idle Limit)'); | $this->log(null, pht('Exiting (Idle Limit)')); | ||||
| return; | return; | ||||
| } | } | ||||
| if ($remaining <= 5) { | if ($remaining <= 5) { | ||||
| $this->log(null, 'Exiting in '.$remaining.' seconds'); | $this->log(null, pht('Exiting in %d seconds', $remaining)); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * Update one client, processing any commands it has sent us. We fully | * Update one client, processing any commands it has sent us. We fully | ||||
| ▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | while (true) { | ||||
| $client->update(); | $client->update(); | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| // Log the elapsed time. | // Log the elapsed time. | ||||
| $t_end = microtime(true); | $t_end = microtime(true); | ||||
| $t = 1000000 * ($t_end - $t_start); | $t = 1000000 * ($t_end - $t_start); | ||||
| $this->log($client, '< '.number_format($t, 0).'us'); | $this->log($client, pht('< %sus', number_format($t, 0))); | ||||
| $this->idleSince = time(); | $this->idleSince = time(); | ||||
| return true; | return true; | ||||
| } | } | ||||
| /* -( Managing Clients )--------------------------------------------------- */ | /* -( Managing Clients )--------------------------------------------------- */ | ||||
| Show All 20 Lines | private function startWorkingCopySocket() { | ||||
| $socket = @stream_socket_server($socket_uri, $errno, $errstr); | $socket = @stream_socket_server($socket_uri, $errno, $errstr); | ||||
| if ($errno || !$socket) { | if ($errno || !$socket) { | ||||
| Filesystem::remove($socket_path); | Filesystem::remove($socket_path); | ||||
| $socket = @stream_socket_server($socket_uri, $errno, $errstr); | $socket = @stream_socket_server($socket_uri, $errno, $errstr); | ||||
| } | } | ||||
| if ($errno || !$socket) { | if ($errno || !$socket) { | ||||
| throw new Exception( | throw new Exception( | ||||
| "Unable to start socket! Error #{$errno}: {$errstr}"); | pht( | ||||
| 'Unable to start socket! Error #%d: %s', | |||||
| $errno, | |||||
| $errstr)); | |||||
| } | } | ||||
| $ok = stream_set_blocking($socket, 0); | $ok = stream_set_blocking($socket, 0); | ||||
| if ($ok === false) { | if ($ok === false) { | ||||
| throw new Exception('Unable to set socket nonblocking!'); | throw new Exception(pht('Unable to set socket nonblocking!')); | ||||
| } | } | ||||
| return $socket; | return $socket; | ||||
| } | } | ||||
| /** | /** | ||||
| * @task client | * @task client | ||||
| ▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | /* -( Internals )---------------------------------------------------------- */ | ||||
| } | } | ||||
| private function log($client, $message) { | private function log($client, $message) { | ||||
| if ($this->quiet) { | if ($this->quiet) { | ||||
| return; | return; | ||||
| } | } | ||||
| if ($client) { | if ($client) { | ||||
| $message = '[Client '.$client->getName().'] '.$message; | $message = sprintf( | ||||
| '[%s] %s', | |||||
| pht('Client %s', $client->getName()), | |||||
| $message); | |||||
| } else { | } else { | ||||
| $message = '[Server] '.$message; | $message = sprintf( | ||||
| '[%s] %s', | |||||
| pht('Server'), | |||||
| $message); | |||||
| } | } | ||||
| echo $message."\n"; | echo $message."\n"; | ||||
| } | } | ||||
| private function daemonize() { | private function daemonize() { | ||||
| // Keep stdout if it's been redirected somewhere, otherwise shut it down. | // Keep stdout if it's been redirected somewhere, otherwise shut it down. | ||||
| $keep_stdout = false; | $keep_stdout = false; | ||||
| $keep_stderr = false; | $keep_stderr = false; | ||||
| if (function_exists('posix_isatty')) { | if (function_exists('posix_isatty')) { | ||||
| if (!posix_isatty(STDOUT)) { | if (!posix_isatty(STDOUT)) { | ||||
| $keep_stdout = true; | $keep_stdout = true; | ||||
| } | } | ||||
| if (!posix_isatty(STDERR)) { | if (!posix_isatty(STDERR)) { | ||||
| $keep_stderr = true; | $keep_stderr = true; | ||||
| } | } | ||||
| } | } | ||||
| $pid = pcntl_fork(); | $pid = pcntl_fork(); | ||||
| if ($pid === -1) { | if ($pid === -1) { | ||||
| throw new Exception('Unable to fork!'); | throw new Exception(pht('Unable to fork!')); | ||||
| } else if ($pid) { | } else if ($pid) { | ||||
| // We're the parent; exit. First, drop our reference to the socket so | // We're the parent; exit. First, drop our reference to the socket so | ||||
| // our __destruct() doesn't tear it down; the child will tear it down | // our __destruct() doesn't tear it down; the child will tear it down | ||||
| // later. | // later. | ||||
| $this->socket = null; | $this->socket = null; | ||||
| exit(0); | exit(0); | ||||
| } | } | ||||
| Show All 15 Lines | |||||