138 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			138 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
namespace nur\sery\wip\app;
 | 
						|
 | 
						|
use nur\sery\app\Runfile;
 | 
						|
use nur\sery\cl;
 | 
						|
use nur\sery\file\TmpfileWriter;
 | 
						|
use nur\sery\os\path;
 | 
						|
use nur\sery\os\proc\Cmd;
 | 
						|
use nur\sery\output\msg;
 | 
						|
use nur\sery\StateException;
 | 
						|
use nur\sery\str;
 | 
						|
use nur\sery\wip\app\app2;
 | 
						|
 | 
						|
class launcher {
 | 
						|
  /**
 | 
						|
   * transformer une liste d'argument de la forme
 | 
						|
   * - ["myArg" => $value]  devient  ["--my-arg", "$value"]
 | 
						|
   * - ["myOpt" => true]    devient  ["--my-opt"]
 | 
						|
   * - ["myOpt" => false]   est momis
 | 
						|
   * - les valeurs séquentielles sont prises telles quelles
 | 
						|
   */
 | 
						|
  static function verifix_args(array $args): array {
 | 
						|
    if (!cl::is_list($args)) {
 | 
						|
      $fixedArgs = [];
 | 
						|
      $index = 0;
 | 
						|
      foreach ($args as $arg => $value) {
 | 
						|
        if ($arg === $index) {
 | 
						|
          $index++;
 | 
						|
          $fixedArgs[] = $value;
 | 
						|
          continue;
 | 
						|
        } elseif ($value === false) {
 | 
						|
          continue;
 | 
						|
        }
 | 
						|
        $arg = str::us2camel($arg);
 | 
						|
        $arg = str::camel2us($arg, false, "-");
 | 
						|
        $arg = str_replace("_", "-", $arg);
 | 
						|
        $fixedArgs[] = "--$arg";
 | 
						|
        if ($value !== true) $fixedArgs[] = "$value";
 | 
						|
      }
 | 
						|
      $args = $fixedArgs;
 | 
						|
    }
 | 
						|
    # corriger le chemin de l'application pour qu'il soit absolu et normalisé
 | 
						|
    $args[0] = path::abspath($args[0]);
 | 
						|
    return $args;
 | 
						|
  }
 | 
						|
 | 
						|
  static function launch(string $appClass, array $args): int {
 | 
						|
    $app = app2::get();
 | 
						|
    $vendorBindir = $app->getVendorbindir();
 | 
						|
    $launch_php = "$vendorBindir/_launch.php";
 | 
						|
    if (!file_exists($launch_php)) {
 | 
						|
      $launch_php = __DIR__."/../../lib/_launch.php";
 | 
						|
    }
 | 
						|
    $tmpfile = new TmpfileWriter();
 | 
						|
    $tmpfile->keep()->serialize($app->getParams());
 | 
						|
 | 
						|
    $args = self::verifix_args($args);
 | 
						|
    $cmd = new Cmd([
 | 
						|
      $launch_php,
 | 
						|
      "--internal-use", $tmpfile->getFile(),
 | 
						|
      $appClass, "--", ...$args,
 | 
						|
    ]);
 | 
						|
    $cmd->addRedir("both", "/tmp/nulib_app_launcher-launch.log");
 | 
						|
    $cmd->passthru($exitcode);
 | 
						|
 | 
						|
    # attendre un peu que la commande aie le temps de s'initialiser
 | 
						|
    sleep(1);
 | 
						|
 | 
						|
    $tmpfile->close();
 | 
						|
    return $exitcode;
 | 
						|
  }
 | 
						|
 | 
						|
  static function _start(array $args, Runfile $runfile): bool {
 | 
						|
    if ($runfile->warnIfLocked()) return false;
 | 
						|
    $pid = pcntl_fork();
 | 
						|
    if ($pid == -1) {
 | 
						|
      # parent, impossible de forker
 | 
						|
      throw new StateException("unable to fork");
 | 
						|
    } elseif ($pid) {
 | 
						|
      # parent, fork ok
 | 
						|
      return true;
 | 
						|
    } else {
 | 
						|
      ## child, fork ok
 | 
						|
      # Créer un groupe de process, pour pouvoir tuer tous les enfants en même temps
 | 
						|
      $runfile->tm_startPg();
 | 
						|
      $logfile = $runfile->getLogfile() ?? "/tmp/nulib_app_launcher-_start.log";
 | 
						|
      $pid = posix_getpid();
 | 
						|
      $exitcode = -776;
 | 
						|
      try {
 | 
						|
        # puis lancer la commande
 | 
						|
        $cmd = new Cmd($args);
 | 
						|
        $cmd->addSource("/g/init.env");
 | 
						|
        $cmd->addRedir("both", $logfile, true);
 | 
						|
        msg::debug("$pid: launching\n".$cmd->getCmd());
 | 
						|
        $cmd->fork_exec($exitcode);
 | 
						|
        msg::debug("$pid: exitcode=$exitcode");
 | 
						|
        return true;
 | 
						|
      } finally {
 | 
						|
        $runfile->wfStopped($exitcode);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  static function _stop(Runfile $runfile): void {
 | 
						|
    $data = $runfile->read();
 | 
						|
    $pid = $data["pg_pid"];
 | 
						|
    if ($pid === null) {
 | 
						|
      msg::warning("$data[name]: groupe de process inconnu");
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    msg::action("kill $pid");
 | 
						|
    if (!posix_kill(-$pid, SIGKILL)) {
 | 
						|
      switch (posix_get_last_error()) {
 | 
						|
      case PCNTL_ESRCH:
 | 
						|
        msg::afailure("process inexistant");
 | 
						|
        break;
 | 
						|
      case PCNTL_EPERM:
 | 
						|
        msg::afailure("process non accessible");
 | 
						|
        break;
 | 
						|
      case PCNTL_EINVAL:
 | 
						|
        msg::afailure("signal invalide");
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    $timeout = 10;
 | 
						|
    while ($runfile->tm_isUndead($pid)) {
 | 
						|
      sleep(1);
 | 
						|
      if (--$timeout == 0) {
 | 
						|
        msg::afailure("impossible d'arrêter la tâche");
 | 
						|
        return;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    $runfile->wfStopped(-778);
 | 
						|
    msg::asuccess();
 | 
						|
  }
 | 
						|
}
 |