Deploy Ladill Hosting / deploy (push) Failing after 17s
Shared web hosting extracted from the platform monolith, with CI deploy to /var/www/ladill-hosting matching Bird/Domains/Email. Co-authored-by: Cursor <cursoragent@cursor.com>
138 lines
3.0 KiB
PHP
138 lines
3.0 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Hosting\Terminal;
|
|
|
|
class LocalPtyShellSession implements ShellSession
|
|
{
|
|
/** @var resource|null */
|
|
private $process = null;
|
|
|
|
/** @var array<int, resource> */
|
|
private array $pipes = [];
|
|
|
|
public function __construct(
|
|
private string $command,
|
|
) {}
|
|
|
|
public function boot(): void
|
|
{
|
|
$spec = [
|
|
0 => ['pipe', 'r'],
|
|
1 => ['pty'],
|
|
2 => ['pty'],
|
|
];
|
|
|
|
$process = proc_open($this->command, $spec, $pipes, base_path());
|
|
|
|
if (! is_resource($process)) {
|
|
throw new \RuntimeException('Unable to start local PTY shell.');
|
|
}
|
|
|
|
$this->process = $process;
|
|
$this->pipes = $pipes;
|
|
|
|
foreach ($this->pipes as $pipe) {
|
|
stream_set_blocking($pipe, false);
|
|
}
|
|
}
|
|
|
|
public function read(): string
|
|
{
|
|
if (! $this->isAlive()) {
|
|
return '';
|
|
}
|
|
|
|
$output = '';
|
|
$stream = $this->outputStream();
|
|
|
|
if (! $stream) {
|
|
return '';
|
|
}
|
|
|
|
$read = [$stream];
|
|
|
|
$write = null;
|
|
$except = null;
|
|
$available = @stream_select($read, $write, $except, 0, 200000);
|
|
|
|
if ($available === false || $available === 0) {
|
|
return '';
|
|
}
|
|
|
|
$chunk = @stream_get_contents($stream);
|
|
|
|
if ($chunk !== false && $chunk !== '') {
|
|
$output .= $chunk;
|
|
}
|
|
|
|
return $output;
|
|
}
|
|
|
|
public function write(string $input): void
|
|
{
|
|
$stream = $this->inputStream();
|
|
|
|
if ($input === '' || ! $stream) {
|
|
return;
|
|
}
|
|
|
|
@fwrite($stream, $input);
|
|
@fflush($stream);
|
|
}
|
|
|
|
public function resize(int $cols, int $rows): void
|
|
{
|
|
// proc_open PTYs do not expose a portable runtime resize API.
|
|
}
|
|
|
|
public function isAlive(): bool
|
|
{
|
|
return is_resource($this->process) && (proc_get_status($this->process)['running'] ?? false);
|
|
}
|
|
|
|
public function close(): void
|
|
{
|
|
$input = $this->inputStream();
|
|
|
|
if ($input) {
|
|
@fwrite($input, "exit\n");
|
|
@fflush($input);
|
|
}
|
|
|
|
foreach ($this->pipes as $pipe) {
|
|
if (is_resource($pipe)) {
|
|
@fclose($pipe);
|
|
}
|
|
}
|
|
|
|
$this->pipes = [];
|
|
|
|
if (is_resource($this->process)) {
|
|
@proc_terminate($this->process);
|
|
@proc_close($this->process);
|
|
}
|
|
|
|
$this->process = null;
|
|
}
|
|
|
|
/** @return resource|null */
|
|
private function inputStream()
|
|
{
|
|
return isset($this->pipes[0]) && is_resource($this->pipes[0]) ? $this->pipes[0] : null;
|
|
}
|
|
|
|
/** @return resource|null */
|
|
private function outputStream()
|
|
{
|
|
if (isset($this->pipes[1]) && is_resource($this->pipes[1])) {
|
|
return $this->pipes[1];
|
|
}
|
|
|
|
if (isset($this->pipes[2]) && is_resource($this->pipes[2])) {
|
|
return $this->pipes[2];
|
|
}
|
|
|
|
return isset($this->pipes[0]) && is_resource($this->pipes[0]) ? $this->pipes[0] : null;
|
|
}
|
|
}
|