[ 'timeout' => 3, 'follow_location' => 0, ]])); } try { if (! is_file($settingsFile) || ! is_file($router)) { throw new RuntimeException('A configuração da avaliação existente não está disponível. Nenhuma base foi criada ou alterada.'); } $settings = json_decode(file_get_contents($settingsFile), true, 32, JSON_THROW_ON_ERROR); if (($settings['APP_ENV'] ?? '') !== 'payable-testing' || ($settings['DB_HOST'] ?? '') !== '127.0.0.1' || ! preg_match('/^compras_receipts_test_[a-f0-9]{12}$/D', $settings['DB_DATABASE'] ?? '') || realpath($settings['HOST_ROOT'] ?? '') !== realpath($root)) { throw new RuntimeException('A configuração não corresponde à avaliação isolada de Compras. Arranque cancelado.'); } $response = evaluationResponse($entry); if ($response === false || ! str_contains($response, 'Explorar Compras')) { $port = @stream_socket_client('tcp://127.0.0.1:8005', $code, $message, 1); if (is_resource($port)) { fclose($port); throw new RuntimeException('A porta 8005 está ocupada, mas não responde como avaliação de Compras. Nenhum processo foi terminado.'); } if (in_array('--check', $argv, true)) { throw new RuntimeException('A avaliação não está em execução. Use composer run dev para a retomar.'); } $children['avaliação'] = new Process([PHP_BINARY, '-S', '127.0.0.1:8005', '-t', 'public', $router], $root, ['PAYABLE_SETTINGS_FILE' => $settingsFile], timeout: null); $children['avaliação']->start(); for ($attempt = 0; $attempt < 50; $attempt++) { usleep(100000); $response = evaluationResponse($entry); if ($response !== false && str_contains($response, 'Explorar Compras')) { break; } if (! $children['avaliação']->isRunning()) { break; } } if ($response === false || ! str_contains($response, 'Explorar Compras')) { throw new RuntimeException('Não foi possível retomar a avaliação existente. Consulte o arranque local; os dados foram preservados.'); } } fwrite(STDOUT, "Compras — ambiente de desenvolvimento e avaliação\n$entry\nEscolha «Entrar como proprietário» ou um perfil de avaliação.\nMesma base persistente; sem migrações, seeds ou redefinição de contas.\n"); if (! in_array('--check', $argv, true)) { $children['reposição'] = new Process([PHP_BINARY, 'scripts/replenishment-evaluation.php', '--daemon'], $root, timeout: null); $children['reposição']->start(); $hot = is_file($root.'/public/hot') ? trim(file_get_contents($root.'/public/hot')) : ''; $host = parse_url($hot, PHP_URL_HOST); $viteReady = in_array($host, ['127.0.0.1', 'localhost', '[::1]'], true) && ($module = evaluationResponse($hot.'/resources/js/app.tsx')) !== false && str_contains($module, 'SgcShell'); if (! $viteReady) { $children['vite'] = Process::fromShellCommandline('npm.cmd run dev -- --host 127.0.0.1', $root, ['APP_URL' => 'http://127.0.0.1:8005'], timeout: null); $children['vite']->start(); } else { fwrite(STDOUT, "Vite de Compras já disponível; reutilizado.\n"); } if (function_exists('sapi_windows_set_ctrl_handler')) { sapi_windows_set_ctrl_handler(function () use (&$stop): bool { $stop = true; return true; }); } while ($children && ! $stop) { foreach ($children as $name => $process) { fwrite(STDOUT, $process->getIncrementalOutput()); fwrite(STDERR, $process->getIncrementalErrorOutput()); if (! $process->isRunning()) { $status = $process->getExitCode() ?? 1; $stop = true; } } usleep(100000); } } } catch (Throwable $error) { fwrite(STDERR, $error->getMessage()."\n"); $status = 1; } finally { foreach ($children as $process) { if ($process->isRunning()) { $process->stop(2); } } } exit($status);