conf = (object)Config::load([__DIR__ . '/../../datas/config.default.json', '?' . __DIR__ . '/../../datas/config.json'])->all(); $this->maxGenPerBatch = $this->conf->maxGenPerBatch; $this->chromePath = $this->conf->chromePath; foreach (array_slice(glob($this->queuePath . "*.json"), 0, $this->maxGenPerBatch) as $filename) { $this->fileList[] = $filename; } foreach ($this->fileList as $demande) { $this->demandes[] = json_decode(file_get_contents($demande)); } $this->db = new DataBase(); } /** * Processes the demands in the queue. * * This method iterates over the list of demands in the `$demandes` property. * For each demand, it sets the parameters for the `DataBase` object, writes the HMAC * to a temporary file, and checks if the demand is already complete. * * If the demand is complete and not a PDF, it resizes the image to the demanded size using the * `ResizeToDemande` class. * * If the demand is not complete, it generates the complete image using the `makeComplete` method. * * In either case, it deletes the demand from the queue using the `deleteQueue` method and * updates the database using the `addUpdate` method. * * Finally, it sets the `$open` property to `true` to indicate that the queue is open. * If the `$open` property is `true`, it generates a complete * image for all demands in the queue using the `makeComplete` method. * * @return void */ public function compute() { foreach ($this->demandes as $demande) { $this->db->setParams($demande); file_put_contents('/tmp/soshot_queue', $demande->hmac); // todo verif permit type if ($this->testComplete($demande->complete) && $demande->type !== 'pdf') { if (ResizeToDemande::makeDemande($demande)) { $this->deleteQueue($demande->hmac); $this->db->addUpdate(1, $demande->type); } } else { $this->makeComplete($demande); if ($demande->type !== 'pdf') { if (!ResizeToDemande::makeDemande($demande)) { // todo log } } $this->deleteQueue($demande->hmac); $this->db->addUpdate(1, $demande->type); $completeDemande = (object)[ 'hmac' => $demande->hmac, 'url' => $demande->url, 'type' => 'complete' ]; $complete = new DataBase($completeDemande); $complete->addUpdate(1, $demande->type); } $this->open = true; if ($this->open === true) { $this->makeComplete(null, true); } } } /** * Deletes a demand from the queue. * * This method takes an HMAC as a parameter and deletes the corresponding JSON file * from the queue directory using the `unlink` function. * * @param string $hmac The HMAC of the demand to delete. * * @return void */ private function deleteQueue(string $hmac) { if (file_exists($this->queuePath . $hmac . '.json')) { unlink($this->queuePath . $hmac . '.json'); } } /** * Checks if a file exists. * * This method takes a file path as a parameter and checks if the file exists using * the `file_exists` function. It returns `true` if the file exists, and `false` * otherwise. * * @param string $complete The file path to check. * * @return bool `true` if the file exists, `false` otherwise. */ private function testComplete(string $complete): bool { if (file_exists($complete)) { return true; } return false; } /** * Generates a complete image or PDF for a demand. * * This method takes a demand object as a parameter and generates a complete image * or PDF for the demand. * * If the `$close` parameter is set to `true`, it closes the browser and deletes the socket file. * The method first checks if a socket file exists and connects to an existing browser if it does. * * If not, it creates a new browser instance using the `BrowserFactory` class. * * It then navigates to the URL specified in the demand and takes a screenshot of the page. * * If the demand type is 'pdf' or the `alwaysMakePdf` configuration option is set to `true`, it also * generates a PDF of the page. * * Finally, it saves the screenshot and PDF to the appropriate file paths and * updates the database using the `addUpdate` method. * * If an `OperationTimedOut` exception is thrown, it logs the error, closes the browser, * deletes the socket file, copies an error image to the file path, and updates the * database with an error status. * * @param object|null $demande The demand object containing the URL, HMAC, file path, and type of the demand. * @param bool $close Whether to close the browser and delete the socket file after * generating the complete image or PDF. Defaults to `false`. * * @return void */ private function makeComplete(object|null $demande, bool $close = false) { if (file_exists($this->fileSocket)) { $socket = \file_get_contents($this->fileSocket); try { $browser = BrowserFactory::connectToBrowser($socket); } catch (BrowserConnectionFailed $e) { $browser = $this->openBrowser(); } } else { $factory = new BrowserFactory($this->chromePath); $browser = $factory->createBrowser([ 'userAgent' => 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)', 'keepAlive' => true, 'headless' => true, 'windowSize' => [1920, 1080], 'userDataDir' => $this->tmpDir, 'customFlags' => [ '--disable-dev-shm-usage', '--disable-gpu' ], 'noSandbox' => true, //'connectionDelay' => 0.8, // add 0.8 second of delay between each instruction sent to chrome, //'debugLogger' => 'php://stdout', ]); \file_put_contents($this->fileSocket, $browser->getSocketUri(), LOCK_EX); } if ($close === true) { $socket = \file_get_contents($this->fileSocket); $browser = BrowserFactory::connectToBrowser($socket); $browser->close(); unlink($this->fileSocket); return true; } $dir = $this->thumbPath . substr($demande->hmac, 0, 4) . '/'; if (!is_dir($dir)) { mkdir($dir); } try { $page = $browser->createPage(); $page->navigate($demande->url)->waitForNavigation(Page::LOAD, 15000); sleep(4); $page->screenshot([ 'captureBeyondViewport' => true, 'clip' => $page->getFullPageClip(), 'format' => $this->conf->fileFormat, ])->saveToFile($demande->complete); if ($demande->type === 'pdf' || $this->conf->alwaysMakePdf === true) { if ($this->conf->alwaysMakePdf === true) { $pdfFile = str_replace($demande->type, 'pdf', $demande->filePath); $pdfFile = str_replace($this->conf->fileFormat, 'pdf', $pdfFile); } else { $pdfFile = $demande->filePath; } $page->pdf([ 'printBackground' => true, 'displayHeaderFooter' => true, 'paperWidth' => 8.268, 'paperHeight' => 11.693, 'scale' => 1 ])->saveToFile($pdfFile); if ($this->conf->alwaysMakePdf === true) { $this->db->addUpdate(1, 'pdf'); } } $this->db->addUpdate(1, 'complete'); } catch (OperationTimedOut $e) { // todo log $socket = \file_get_contents($this->fileSocket); $browser = BrowserFactory::connectToBrowser($socket); $browser->close(); unlink($this->fileSocket); copy(__DIR__ . '/../../src/images/error_thumb.png', $demande->filePath); $this->db->addUpdate(2, $demande->type); } } /** * Creates and opens a new browser instance. * * This method creates a new browser instance using the `BrowserFactory` class with * the specified configuration options. It then saves the socket URI to a file and * returns the browser instance. * * @return Browser The created browser instance. */ private function openBrowser(): Browser { $factory = new BrowserFactory($this->chromePath); // Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html) $browser = $factory->createBrowser([ 'userAgent' => 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)', 'keepAlive' => true, 'headless' => true, 'windowSize' => [1920, 1080], 'userDataDir' => $this->tmpDir, 'customFlags' => [ '--disable-dev-shm-usage', '--disable-gpu' ], 'noSandbox' => true, ]); \file_put_contents($this->fileSocket, $browser->getSocketUri(), LOCK_EX); return $browser; } }