123 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			123 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| namespace cli;
 | |
| 
 | |
| use nulib\app\app;
 | |
| use nulib\app\cli\Application;
 | |
| use nulib\app\RunFile;
 | |
| use nulib\ExitError;
 | |
| use nulib\ext\yaml;
 | |
| use nulib\os\path;
 | |
| use nulib\os\proc\Cmd;
 | |
| use nulib\os\sh;
 | |
| use nulib\output\msg;
 | |
| 
 | |
| class BgLauncherApp extends Application {
 | |
|   const ACTION_INFOS = 0, ACTION_START = 1, ACTION_STOP = 2;
 | |
|   const ARGS = [
 | |
|     "purpose" => "lancer un script en tâche de fond",
 | |
|     "usage" => "ApplicationClass args...",
 | |
| 
 | |
|     "sections" => [
 | |
|       parent::VERBOSITY_SECTION,
 | |
|     ],
 | |
| 
 | |
|     ["-i", "--infos", "name" => "action", "value" => self::ACTION_INFOS,
 | |
|       "help" => "Afficher des informations sur la tâche",
 | |
|     ],
 | |
|     ["-s", "--start", "name" => "action", "value" => self::ACTION_START,
 | |
|       "help" => "Démarrer la tâche",
 | |
|     ],
 | |
|     ["-k", "--stop", "name" => "action", "value" => self::ACTION_STOP,
 | |
|       "help" => "Arrêter la tâche",
 | |
|     ],
 | |
|   ];
 | |
| 
 | |
|   protected int $action = self::ACTION_START;
 | |
| 
 | |
|   static function show_infos(RunFile $runfile, ?int $level=null): void {
 | |
|     msg::print($runfile->getDesc(), $level);
 | |
|     msg::print(yaml::with(["data" => $runfile->read()]), ($level ?? 0) - 1);
 | |
|   }
 | |
| 
 | |
|   function main() {
 | |
|     $args = $this->args;
 | |
| 
 | |
|     $appClass = $args[0] ?? null;
 | |
|     if ($appClass === null) {
 | |
|       self::die("Vous devez spécifier la classe de l'application");
 | |
|     }
 | |
|     $appClass = $args[0] = str_replace("/", "\\", $appClass);
 | |
|     if (!class_exists($appClass)) {
 | |
|       self::die("$appClass: classe non trouvée");
 | |
|     }
 | |
| 
 | |
|     $useRunfile = constant("$appClass::USE_RUNFILE");
 | |
|     if (!$useRunfile) {
 | |
|       self::die("Cette application ne supporte le lancement en tâche de fond");
 | |
|     }
 | |
| 
 | |
|     $runfile = app::with($appClass)->getRunfile();
 | |
|     switch ($this->action) {
 | |
|     case self::ACTION_START:
 | |
|       $argc = count($args);
 | |
|       $appClass::_manage_runfile($argc, $args, $runfile);
 | |
|       if ($runfile->warnIfLocked()) self::exit(app::EC_LOCKED);
 | |
|       array_splice($args, 0, 0, [
 | |
|         PHP_BINARY,
 | |
|         path::abspath(NULIB_APP_app_launcher),
 | |
|       ]);
 | |
|       app::params_putenv();
 | |
|       self::_start($args, $runfile);
 | |
|       break;
 | |
|     case self::ACTION_STOP:
 | |
|       self::_stop($runfile);
 | |
|       self::show_infos($runfile, -1);
 | |
|       break;
 | |
|     case self::ACTION_INFOS:
 | |
|       self::show_infos($runfile);
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   public static function _start(array $args, Runfile $runfile): void {
 | |
|     $pid = pcntl_fork();
 | |
|     if ($pid == -1) {
 | |
|       # parent, impossible de forker
 | |
|       throw new ExitError(app::EC_FORK_PARENT, "Unable to fork");
 | |
|     } elseif (!$pid) {
 | |
|       # child, fork ok
 | |
|       $runfile->wfPrepare($pid);
 | |
|       $outfile = $runfile->getOutfile() ?? "/tmp/NULIB_APP_app_console.out";
 | |
|       $exitcode = app::EC_FORK_CHILD;
 | |
|       try {
 | |
|         # rediriger STDIN, STDOUT et STDERR
 | |
|         fclose(fopen($outfile, "wb")); // vider le fichier
 | |
|         fclose(STDIN); $in = fopen("/dev/null", "rb");
 | |
|         fclose(STDOUT); $out = fopen($outfile, "ab");
 | |
|         fclose(STDERR); $err = fopen($outfile, "ab");
 | |
|         # puis lancer la commande
 | |
|         $cmd = new Cmd($args);
 | |
|         $cmd->addSource("/g/init.env");
 | |
|         $cmd->addRedir("both", $outfile, true);
 | |
|         $cmd->fork_exec($exitcode, false);
 | |
|         sh::_waitpid(-$pid, $exitcode);
 | |
|       } finally {
 | |
|         $runfile->wfReaped($exitcode);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   public static function _stop(Runfile $runfile): bool {
 | |
|     $data = $runfile->read();
 | |
|     $pid = $runfile->_getCid($data);
 | |
|     msg::action("stop $pid");
 | |
|     if ($runfile->wfKill($reason)) {
 | |
|       msg::asuccess();
 | |
|       return true;
 | |
|     } else {
 | |
|       msg::afailure($reason);
 | |
|       return false;
 | |
|     }
 | |
|   }
 | |
| }
 |