/** * Read the stdout pipe from Lazarus process. This function uses * stream_select to be non blocking * * @return void */ public function tick() { $stream = $this->application->process->stdout->stream; $read = [$stream]; $write = []; $except = []; $result = stream_select($read, $write, $except, 0); if ($result === false) { throw new Exception('stream_select failed'); } if ($result === 0) { return; } // This solves a bug on Windows - If you read the exact size (> 1), // PHP will block if (OsDetector::isWindows()) { $status = fstat($stream); if ($status['size'] > 0) { $size = $status['size']; if ($size > 1) { $size -= 1; $data = stream_get_contents($stream, $size); $data .= stream_get_contents($stream, 1); } else { $data = stream_get_contents($stream, 1); } $this->application->process->stdout->emit('data', array($data, $this)); } } else { // On Linux and OSX, we don't need to pass a size limit $data = stream_get_contents($stream); if (!empty($data)) { $this->application->process->stdout->emit('data', array($data, $this)); } } }
/** * Runs the application * * @return void */ public function run() { if (!self::$defaultApplication) { self::$defaultApplication = $this; } $application = $this; if (OsDetector::isMacOS()) { $processName = './phpgui-i386-darwin'; $processPath = __DIR__ . '/../lazarus/phpgui-i386-darwin.app/Contents/MacOS/'; } elseif (OsDetector::isFreeBSD()) { $processName = './phpgui-x86_64-freebsd'; $processPath = __DIR__ . '/../lazarus/'; } elseif (OsDetector::isUnix()) { $processName = './phpgui-x86_64-linux'; $processPath = __DIR__ . '/../lazarus/'; } elseif (OsDetector::isWindows()) { $processName = '.\\phpgui-x86_64-win64'; $processPath = __DIR__ . '\\..\\lazarus\\'; } else { throw new RuntimeException('Operational System not identified by PHP-GUI.'); } $this->process = $process = new Process($processName, $processPath); $this->process->on('exit', function () use($application) { $application->loop->stop(); }); $this->receiver = $receiver = new Receiver($this); $this->sender = $sender = new Sender($this, $receiver); $this->loop->addTimer(0.001, function ($timer) use($process, $application, $receiver) { $process->start($timer->getLoop()); // We need to pause all default streams // The react/loop uses fread to read data from streams // On Windows, fread always is blocking // Stdin is paused, we use our own way to write on it $process->stdin->pause(); // Stdout is paused, we use our own way to read it $process->stdout->pause(); // Stderr is paused for avoiding fread $process->stderr->pause(); $process->stdout->on('data', function ($data) use($receiver) { $receiver->onData($data); }); $process->stderr->on('data', function ($data) { if (!empty($data)) { Output::err($data); } }); $application->running = true; // Bootstrap the application $application->fire('start'); }); $this->loop->addPeriodicTimer(0.001, function () use($application) { $application->sender->tick(); if (@is_resource($application->process->stdout->stream)) { $application->receiver->tick(); } }); $this->loop->run(); }