Differential D11288 Diff 27128 src/applications/aphlict/management/PhabricatorAphlictManagementWorkflow.php
Changeset View
Changeset View
Standalone View
Standalone View
src/applications/aphlict/management/PhabricatorAphlictManagementWorkflow.php
| <?php | <?php | ||||
| abstract class PhabricatorAphlictManagementWorkflow | abstract class PhabricatorAphlictManagementWorkflow | ||||
| extends PhabricatorManagementWorkflow { | extends PhabricatorManagementWorkflow { | ||||
| private $debug = false; | |||||
| private $clientHost; | |||||
| public function didConstruct() { | |||||
| $this | |||||
| ->setArguments( | |||||
| array( | |||||
| array( | |||||
| 'name' => 'client-host', | |||||
| 'param' => 'hostname', | |||||
| 'help' => pht('Hostname to bind to for the client server.'), | |||||
| ), | |||||
| )); | |||||
| } | |||||
| public function execute(PhutilArgumentParser $args) { | |||||
| $this->clientHost = $args->getArg('client-host'); | |||||
| return 0; | |||||
| } | |||||
| final public function getPIDPath() { | final public function getPIDPath() { | ||||
| return PhabricatorEnv::getEnvConfig('notification.pidfile'); | return PhabricatorEnv::getEnvConfig('notification.pidfile'); | ||||
| } | } | ||||
| final public function getPID() { | final public function getPID() { | ||||
| $pid = null; | $pid = null; | ||||
| if (Filesystem::pathExists($this->getPIDPath())) { | if (Filesystem::pathExists($this->getPIDPath())) { | ||||
| $pid = (int)Filesystem::readFile($this->getPIDPath()); | $pid = (int)Filesystem::readFile($this->getPIDPath()); | ||||
| } | } | ||||
| return $pid; | return $pid; | ||||
| } | } | ||||
| final public function cleanup($signo = '?') { | final public function cleanup($signo = '?') { | ||||
| global $g_future; | global $g_future; | ||||
| if ($g_future) { | if ($g_future) { | ||||
| $g_future->resolveKill(); | $g_future->resolveKill(); | ||||
| $g_future = null; | $g_future = null; | ||||
| } | } | ||||
| Filesystem::remove($this->getPIDPath()); | Filesystem::remove($this->getPIDPath()); | ||||
| exit(1); | exit(1); | ||||
| } | } | ||||
| protected final function setDebug($debug) { | |||||
| $this->debug = $debug; | |||||
| } | |||||
| public static function requireExtensions() { | public static function requireExtensions() { | ||||
| self::mustHaveExtension('pcntl'); | self::mustHaveExtension('pcntl'); | ||||
| self::mustHaveExtension('posix'); | self::mustHaveExtension('posix'); | ||||
| } | } | ||||
| private static function mustHaveExtension($ext) { | private static function mustHaveExtension($ext) { | ||||
| if (!extension_loaded($ext)) { | if (!extension_loaded($ext)) { | ||||
| echo "ERROR: The PHP extension '{$ext}' is not installed. You must ". | echo "ERROR: The PHP extension '{$ext}' is not installed. You must ". | ||||
| "install it to run aphlict on this machine.\n"; | "install it to run aphlict on this machine.\n"; | ||||
| exit(1); | exit(1); | ||||
| } | } | ||||
| $extension = new ReflectionExtension($ext); | $extension = new ReflectionExtension($ext); | ||||
| foreach ($extension->getFunctions() as $function) { | foreach ($extension->getFunctions() as $function) { | ||||
| $function = $function->name; | $function = $function->name; | ||||
| if (!function_exists($function)) { | if (!function_exists($function)) { | ||||
| echo "ERROR: The PHP function {$function}() is disabled. You must ". | echo "ERROR: The PHP function {$function}() is disabled. You must ". | ||||
| "enable it to run aphlict on this machine.\n"; | "enable it to run aphlict on this machine.\n"; | ||||
| exit(1); | exit(1); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| final protected function willLaunch($debug = false) { | final protected function willLaunch() { | ||||
| $console = PhutilConsole::getConsole(); | $console = PhutilConsole::getConsole(); | ||||
| $pid = $this->getPID(); | $pid = $this->getPID(); | ||||
| if ($pid) { | if ($pid) { | ||||
| throw new PhutilArgumentUsageException( | throw new PhutilArgumentUsageException( | ||||
| pht( | pht( | ||||
| 'Unable to start notifications server because it is already '. | 'Unable to start notifications server because it is already '. | ||||
| 'running. Use `aphlict restart` to restart it.')); | 'running. Use `aphlict restart` to restart it.')); | ||||
| } | } | ||||
| if (posix_getuid() == 0) { | if (posix_getuid() == 0) { | ||||
| throw new PhutilArgumentUsageException( | throw new PhutilArgumentUsageException( | ||||
| pht( | pht( | ||||
| // TODO: Update this message after a while. | // TODO: Update this message after a while. | ||||
| 'The notification server should not be run as root. It no '. | 'The notification server should not be run as root. It no '. | ||||
| 'longer requires access to privileged ports.')); | 'longer requires access to privileged ports.')); | ||||
| } | } | ||||
| // Make sure we can write to the PID file. | // Make sure we can write to the PID file. | ||||
| if (!$debug) { | if (!$this->debug) { | ||||
| Filesystem::writeFile($this->getPIDPath(), ''); | Filesystem::writeFile($this->getPIDPath(), ''); | ||||
| } | } | ||||
| // First, start the server in configuration test mode with --test. This | // First, start the server in configuration test mode with --test. This | ||||
| // will let us error explicitly if there are missing modules, before we | // will let us error explicitly if there are missing modules, before we | ||||
| // fork and lose access to the console. | // fork and lose access to the console. | ||||
| $test_argv = $this->getServerArgv($debug); | $test_argv = $this->getServerArgv(); | ||||
| $test_argv[] = '--test=true'; | $test_argv[] = '--test=true'; | ||||
| execx( | execx( | ||||
| '%s %s %Ls', | '%s %s %Ls', | ||||
| $this->getNodeBinary(), | $this->getNodeBinary(), | ||||
| $this->getAphlictScriptPath(), | $this->getAphlictScriptPath(), | ||||
| $test_argv); | $test_argv); | ||||
| } | } | ||||
| private function getServerArgv($debug) { | private function getServerArgv() { | ||||
| $ssl_key = PhabricatorEnv::getEnvConfig('notification.ssl-key'); | $ssl_key = PhabricatorEnv::getEnvConfig('notification.ssl-key'); | ||||
| $ssl_cert = PhabricatorEnv::getEnvConfig('notification.ssl-cert'); | $ssl_cert = PhabricatorEnv::getEnvConfig('notification.ssl-cert'); | ||||
| $server_uri = PhabricatorEnv::getEnvConfig('notification.server-uri'); | $server_uri = PhabricatorEnv::getEnvConfig('notification.server-uri'); | ||||
| $server_uri = new PhutilURI($server_uri); | $server_uri = new PhutilURI($server_uri); | ||||
| $client_uri = PhabricatorEnv::getEnvConfig('notification.client-uri'); | $client_uri = PhabricatorEnv::getEnvConfig('notification.client-uri'); | ||||
| $client_uri = new PhutilURI($client_uri); | $client_uri = new PhutilURI($client_uri); | ||||
| $log = PhabricatorEnv::getEnvConfig('notification.log'); | $log = PhabricatorEnv::getEnvConfig('notification.log'); | ||||
| $server_argv = array(); | $server_argv = array(); | ||||
| $server_argv[] = '--port='.$client_uri->getPort(); | $server_argv[] = '--client-port='.$client_uri->getPort(); | ||||
| $server_argv[] = '--admin='.$server_uri->getPort(); | $server_argv[] = '--admin-port='.$server_uri->getPort(); | ||||
| $server_argv[] = '--host='.$server_uri->getDomain(); | $server_argv[] = '--admin-host='.$server_uri->getDomain(); | ||||
| if ($ssl_key) { | if ($ssl_key) { | ||||
| $server_argv[] = '--ssl-key='.$ssl_key; | $server_argv[] = '--ssl-key='.$ssl_key; | ||||
| } | } | ||||
| if ($ssl_cert) { | if ($ssl_cert) { | ||||
| $server_argv[] = '--ssl-cert='.$ssl_cert; | $server_argv[] = '--ssl-cert='.$ssl_cert; | ||||
| } | } | ||||
| if (!$debug) { | if (!$this->debug) { | ||||
| $server_argv[] = '--log='.$log; | $server_argv[] = '--log='.$log; | ||||
| } | } | ||||
| if ($this->clientHost) { | |||||
| $server_argv[] = '--client-host='.$this->clientHost; | |||||
| } | |||||
| return $server_argv; | return $server_argv; | ||||
| } | } | ||||
| private function getAphlictScriptPath() { | private function getAphlictScriptPath() { | ||||
| $root = dirname(phutil_get_library_root('phabricator')); | $root = dirname(phutil_get_library_root('phabricator')); | ||||
| return $root.'/support/aphlict/server/aphlict_server.js'; | return $root.'/support/aphlict/server/aphlict_server.js'; | ||||
| } | } | ||||
| final protected function launch($debug = false) { | final protected function launch() { | ||||
| $console = PhutilConsole::getConsole(); | $console = PhutilConsole::getConsole(); | ||||
| if ($debug) { | if ($this->debug) { | ||||
| $console->writeOut(pht("Starting Aphlict server in foreground...\n")); | $console->writeOut(pht("Starting Aphlict server in foreground...\n")); | ||||
| } else { | } else { | ||||
| Filesystem::writeFile($this->getPIDPath(), getmypid()); | Filesystem::writeFile($this->getPIDPath(), getmypid()); | ||||
| } | } | ||||
| $command = csprintf( | $command = csprintf( | ||||
| '%s %s %Ls', | '%s %s %Ls', | ||||
| $this->getNodeBinary(), | $this->getNodeBinary(), | ||||
| $this->getAphlictScriptPath(), | $this->getAphlictScriptPath(), | ||||
| $this->getServerArgv($debug)); | $this->getServerArgv()); | ||||
| if (!$debug) { | if (!$this->debug) { | ||||
| declare(ticks = 1); | declare(ticks = 1); | ||||
| pcntl_signal(SIGINT, array($this, 'cleanup')); | pcntl_signal(SIGINT, array($this, 'cleanup')); | ||||
| pcntl_signal(SIGTERM, array($this, 'cleanup')); | pcntl_signal(SIGTERM, array($this, 'cleanup')); | ||||
| } | } | ||||
| register_shutdown_function(array($this, 'cleanup')); | register_shutdown_function(array($this, 'cleanup')); | ||||
| if ($debug) { | if ($this->debug) { | ||||
| $console->writeOut("Launching server:\n\n $ ".$command."\n\n"); | $console->writeOut("Launching server:\n\n $ ".$command."\n\n"); | ||||
| $err = phutil_passthru('%C', $command); | $err = phutil_passthru('%C', $command); | ||||
| $console->writeOut(">>> Server exited!\n"); | $console->writeOut(">>> Server exited!\n"); | ||||
| exit($err); | exit($err); | ||||
| } else { | } else { | ||||
| while (true) { | while (true) { | ||||
| global $g_future; | global $g_future; | ||||
| ▲ Show 20 Lines • Show All 90 Lines • Show Last 20 Lines | |||||