clusev/app/Services/CommandRunner.php

47 lines
1.5 KiB
PHP

<?php
namespace App\Services;
use App\Models\Server;
use Illuminate\Support\Collection;
use Throwable;
/**
* Runs one (arbitrary, user-supplied) command across a set of servers and collects a per-server
* result. The command is INTENTIONALLY arbitrary — it runs via FleetService::runPlain (the
* credential's login user, base64 transport, no extra sudo) exactly as the web terminal would.
* One server failing (connect/exec) never aborts the batch. Remote output is byte-capped +
* mb_scrub'd so it can safely land in a Livewire property.
*/
class CommandRunner
{
private const MAX_BYTES = 262144; // 256 KiB per server
public function __construct(private FleetService $fleet) {}
/**
* @param Collection<int, Server> $servers
* @return array<int, array{server:string, ok:bool, output:string}>
*/
public function run(string $command, Collection $servers, int $timeout = 60): array
{
$results = [];
foreach ($servers as $server) {
try {
$res = $this->fleet->runPlain($server, $command, $timeout);
$results[] = ['server' => $server->name, 'ok' => (bool) $res['ok'], 'output' => $this->clean($res['output'])];
} catch (Throwable $e) {
$results[] = ['server' => $server->name, 'ok' => false, 'output' => $this->clean($e->getMessage())];
}
}
return $results;
}
private function clean(string $output): string
{
return mb_scrub(mb_strcut($output, 0, self::MAX_BYTES), 'UTF-8');
}
}