[ Index ]

PHP Cross Reference of Phabricator

title

Body

[close]

/src/applications/aphlict/management/ -> PhabricatorAphlictManagementWorkflow.php (source)

   1  <?php
   2  
   3  abstract class PhabricatorAphlictManagementWorkflow
   4    extends PhabricatorManagementWorkflow {
   5  
   6    final public function getPIDPath() {
   7      return PhabricatorEnv::getEnvConfig('notification.pidfile');
   8    }
   9  
  10    final public function getPID() {
  11      $pid = null;
  12      if (Filesystem::pathExists($this->getPIDPath())) {
  13        $pid = (int)Filesystem::readFile($this->getPIDPath());
  14      }
  15      return $pid;
  16    }
  17  
  18    final public function cleanup($signo = '?') {
  19      global $g_future;
  20      if ($g_future) {
  21        $g_future->resolveKill();
  22        $g_future = null;
  23      }
  24  
  25      Filesystem::remove($this->getPIDPath());
  26  
  27      exit(1);
  28    }
  29  
  30    public static function requireExtensions() {
  31      self::mustHaveExtension('pcntl');
  32      self::mustHaveExtension('posix');
  33    }
  34  
  35    private static function mustHaveExtension($ext) {
  36      if (!extension_loaded($ext)) {
  37        echo "ERROR: The PHP extension '{$ext}' is not installed. You must ".
  38             "install it to run aphlict on this machine.\n";
  39        exit(1);
  40      }
  41  
  42      $extension = new ReflectionExtension($ext);
  43      foreach ($extension->getFunctions() as $function) {
  44        $function = $function->name;
  45        if (!function_exists($function)) {
  46          echo "ERROR: The PHP function {$function}() is disabled. You must ".
  47               "enable it to run aphlict on this machine.\n";
  48          exit(1);
  49        }
  50      }
  51    }
  52  
  53    final protected function willLaunch() {
  54      $console = PhutilConsole::getConsole();
  55  
  56      $pid = $this->getPID();
  57      if ($pid) {
  58        throw new PhutilArgumentUsageException(
  59          pht(
  60            'Unable to start notifications server because it is already '.
  61            'running. Use `aphlict restart` to restart it.'));
  62      }
  63  
  64      if (posix_getuid() != 0) {
  65        throw new PhutilArgumentUsageException(
  66          pht(
  67            'You must run this script as root; the Aphlict server needs to bind '.
  68            'to privileged ports.'));
  69      }
  70  
  71      // This will throw if we can't find an appropriate `node`.
  72      $this->getNodeBinary();
  73    }
  74  
  75    final protected function launch($debug = false) {
  76      $console = PhutilConsole::getConsole();
  77  
  78      if ($debug) {
  79        $console->writeOut(pht("Starting Aphlict server in foreground...\n"));
  80      } else {
  81        Filesystem::writeFile($this->getPIDPath(), getmypid());
  82      }
  83  
  84      $server_uri = PhabricatorEnv::getEnvConfig('notification.server-uri');
  85      $server_uri = new PhutilURI($server_uri);
  86  
  87      $client_uri = PhabricatorEnv::getEnvConfig('notification.client-uri');
  88      $client_uri = new PhutilURI($client_uri);
  89  
  90      $user = PhabricatorEnv::getEnvConfig('notification.user');
  91      $log  = PhabricatorEnv::getEnvConfig('notification.log');
  92  
  93      $server_argv = array();
  94      $server_argv[] = csprintf('--port=%s', $client_uri->getPort());
  95      $server_argv[] = csprintf('--admin=%s', $server_uri->getPort());
  96      $server_argv[] = csprintf('--host=%s', $server_uri->getDomain());
  97  
  98      if ($user) {
  99        $server_argv[] = csprintf('--user=%s', $user);
 100      }
 101  
 102      if (!$debug) {
 103        $server_argv[] = csprintf('--log=%s', $log);
 104      }
 105  
 106      $command = csprintf(
 107        '%s %s %C',
 108        $this->getNodeBinary(),
 109        dirname(__FILE__).'/../../../../support/aphlict/server/aphlict_server.js',
 110        implode(' ', $server_argv));
 111  
 112      if (!$debug) {
 113        declare(ticks = 1);
 114        pcntl_signal(SIGINT, array($this, 'cleanup'));
 115        pcntl_signal(SIGTERM, array($this, 'cleanup'));
 116      }
 117      register_shutdown_function(array($this, 'cleanup'));
 118  
 119      if ($debug) {
 120        $console->writeOut("Launching server:\n\n    $ ".$command."\n\n");
 121  
 122        $err = phutil_passthru('%C', $command);
 123        $console->writeOut(">>> Server exited!\n");
 124        exit($err);
 125      } else {
 126        while (true) {
 127          global $g_future;
 128          $g_future = new ExecFuture('exec %C', $command);
 129          $g_future->resolve();
 130  
 131          // If the server exited, wait a couple of seconds and restart it.
 132          unset($g_future);
 133          sleep(2);
 134        }
 135      }
 136    }
 137  
 138  
 139  /* -(  Commands  )----------------------------------------------------------- */
 140  
 141  
 142    final protected function executeStartCommand() {
 143      $console = PhutilConsole::getConsole();
 144      $this->willLaunch();
 145  
 146      $pid = pcntl_fork();
 147      if ($pid < 0) {
 148        throw new Exception('Failed to fork()!');
 149      } else if ($pid) {
 150        $console->writeErr(pht("Aphlict Server started.\n"));
 151        exit(0);
 152      }
 153  
 154      // When we fork, the child process will inherit its parent's set of open
 155      // file descriptors. If the parent process of bin/aphlict is waiting for
 156      // bin/aphlict's file descriptors to close, it will be stuck waiting on
 157      // the daemonized process. (This happens if e.g. bin/aphlict is started
 158      // in another script using passthru().)
 159      fclose(STDOUT);
 160      fclose(STDERR);
 161  
 162      $this->launch();
 163      return 0;
 164    }
 165  
 166  
 167    final protected function executeStopCommand() {
 168      $console = PhutilConsole::getConsole();
 169  
 170      $pid = $this->getPID();
 171      if (!$pid) {
 172        $console->writeErr(pht("Aphlict is not running.\n"));
 173        return 0;
 174      }
 175  
 176      $console->writeErr(pht("Stopping Aphlict Server (%s)...\n", $pid));
 177      posix_kill($pid, SIGINT);
 178  
 179      $start = time();
 180      do {
 181        if (!PhabricatorDaemonReference::isProcessRunning($pid)) {
 182          $console->writeOut(
 183            "%s\n",
 184            pht('Aphlict Server (%s) exited normally.', $pid));
 185          $pid = null;
 186          break;
 187        }
 188        usleep(100000);
 189      } while (time() < $start + 5);
 190  
 191      if ($pid) {
 192        $console->writeErr(pht('Sending %s a SIGKILL.', $pid)."\n");
 193        posix_kill($pid, SIGKILL);
 194        unset($pid);
 195      }
 196  
 197      Filesystem::remove($this->getPIDPath());
 198      return 0;
 199    }
 200  
 201    private function getNodeBinary() {
 202      if (Filesystem::binaryExists('nodejs')) {
 203        return 'nodejs';
 204      }
 205  
 206      if (Filesystem::binaryExists('node')) {
 207        return 'node';
 208      }
 209  
 210      throw new PhutilArgumentUsageException(
 211        pht(
 212          'No `nodejs` or `node` binary was found in $PATH. You must install '.
 213          'Node.js to start the Aphlict server.'));
 214    }
 215  
 216  }


Generated: Sun Nov 30 09:20:46 2014 Cross-referenced by PHPXref 0.7.1