58    public const TOKEN_DELIMITER = 
":";
 
   59    public const TOKEN_HASH_ALGO = 
"xxh3";
 
   61    private \PrefixedLogger $logger;
 
   66    private int $commandTokenSeed;
 
   68    public function __construct(
 
   71        $this->logger = new \PrefixedLogger($logger, 
"Console Reader Daemon");
 
   72        $this->commandTokenSeed = mt_rand();
 
   73        $this->prepareSubprocess();
 
   76    private function prepareSubprocess() : 
void{
 
   79        $sub = Utils::assumeNotFalse(proc_open(
 
   82                '-dopcache.enable_cli=0',
 
   84                sprintf(
'require base64_decode("%s", true);', base64_encode(Path::join(__DIR__, 
'ConsoleReaderChildProcess.php'))),
 
   85                (
string) $this->commandTokenSeed
 
   89                2 => Utils::assumeNotFalse(fopen(
"php://stderr", 
"w")),
 
   92        ), 
"Something has gone horribly wrong");
 
   94        $this->subprocess = $sub;
 
   95        $this->socket = $pipes[1];
 
   98    private function shutdownSubprocess() : 
void{
 
  102        proc_terminate($this->subprocess);
 
  103        proc_close($this->subprocess);
 
  106    public function readLine() : ?
string{
 
  107        $r = [$this->socket];
 
  110        if(stream_select($r, $w, $e, 0, 0) === 1){
 
  111            $line = fgets($this->socket);
 
  113                $this->logger->debug(
"Lost connection to subprocess, restarting (maybe the child process was killed from outside?)");
 
  114                $this->shutdownSubprocess();
 
  115                $this->prepareSubprocess();
 
  118            $line = rtrim($line, 
"\n");
 
  126            if($command === 
null){
 
  129                $this->logger->warning(
"Unexpected output from child process: $line");
 
  133            $command = preg_replace(
"#\\x1b\\x5b([^\\x1b]*\\x7e|[\\x40-\\x50])#", 
"", trim($command)) ?? 
throw new AssumptionFailedError(
"This regex is assumed to be valid");
 
  134            $command = preg_replace(
'/[[:cntrl:]]/', 
'', $command) ?? 
throw new AssumptionFailedError(
"This regex is assumed to be valid");
 
  136            return $command !== 
"" ? $command : 
null;
 
  142    public function quit() : 
void{
 
  143        $this->shutdownSubprocess();