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>
98 lines
2.3 KiB
PHP
98 lines
2.3 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Hosting\Terminal;
|
|
|
|
use phpseclib3\Net\SSH2;
|
|
|
|
class RemoteSshShellSession implements ShellSession
|
|
{
|
|
private const STARTUP_TIMEOUT_SECONDS = 10;
|
|
private const READ_TIMEOUT_SECONDS = 0.1;
|
|
|
|
private bool $closed = false;
|
|
|
|
public function __construct(
|
|
private SSH2 $ssh,
|
|
private string $launchCommand,
|
|
private int $cols = 120,
|
|
private int $rows = 30,
|
|
) {}
|
|
|
|
public function boot(): void
|
|
{
|
|
$this->ssh->setWindowSize($this->cols, $this->rows);
|
|
$this->ssh->setTimeout(self::STARTUP_TIMEOUT_SECONDS);
|
|
$this->ssh->enablePTY();
|
|
|
|
if ($this->ssh->exec($this->launchCommand, false) !== true) {
|
|
throw new \RuntimeException('Unable to start remote terminal shell.');
|
|
}
|
|
}
|
|
|
|
public function read(): string
|
|
{
|
|
if (! $this->isAlive()) {
|
|
return '';
|
|
}
|
|
|
|
$output = '';
|
|
$this->ssh->setTimeout(self::READ_TIMEOUT_SECONDS);
|
|
|
|
while (true) {
|
|
$chunk = $this->ssh->read('', SSH2::READ_NEXT);
|
|
|
|
if ($chunk === true) {
|
|
if ($this->ssh->isTimeout()) {
|
|
break;
|
|
}
|
|
|
|
$this->closed = true;
|
|
break;
|
|
}
|
|
|
|
if (! is_string($chunk) || $chunk === '') {
|
|
break;
|
|
}
|
|
|
|
$output .= $chunk;
|
|
}
|
|
|
|
return $output;
|
|
}
|
|
|
|
public function write(string $input): void
|
|
{
|
|
if ($input === '' || ! $this->isAlive()) {
|
|
return;
|
|
}
|
|
|
|
$this->ssh->write($input);
|
|
}
|
|
|
|
public function resize(int $cols, int $rows): void
|
|
{
|
|
// phpseclib applies the PTY size during shell creation; runtime resize is left as a no-op
|
|
// to avoid injecting visible shell commands into the user session.
|
|
}
|
|
|
|
public function isAlive(): bool
|
|
{
|
|
return ! $this->closed && $this->ssh->isConnected();
|
|
}
|
|
|
|
public function close(): void
|
|
{
|
|
if ($this->ssh->isConnected()) {
|
|
try {
|
|
$this->ssh->write("exit\n");
|
|
} catch (\Throwable) {
|
|
// Ignore shutdown write failures.
|
|
}
|
|
|
|
$this->ssh->disconnect();
|
|
}
|
|
|
|
$this->closed = true;
|
|
}
|
|
}
|