Files
ladill-servers/app/Http/Controllers/Hosting/HostingTerminalSessionController.php
T
isaaccladandCursor b6c8ac343f Extract Ladill Servers as standalone app at servers.ladill.com.
VPS and dedicated server ordering, managed panels, SSO, billing, and launcher integration — forked from hosting infrastructure with server-focused routes and dashboard.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-06 19:18:30 +00:00

160 lines
4.5 KiB
PHP

<?php
namespace App\Http\Controllers\Hosting;
use App\Http\Controllers\Controller;
use App\Models\HostingAccount;
use App\Services\Hosting\BrowserTerminalSessionManager;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class HostingTerminalSessionController extends Controller
{
public function __construct(
private BrowserTerminalSessionManager $sessionManager,
) {}
public function start(Request $request, HostingAccount $account): JsonResponse
{
$this->authorize('useTerminal', $account);
$account->loadMissing('node');
$validated = $request->validate([
'path' => 'nullable|string|max:255',
'cols' => 'nullable|integer|min:40|max:240',
'rows' => 'nullable|integer|min:10|max:80',
]);
$session = $this->sessionManager->createSession(
$account,
(int) $request->user()->id,
(string) ($validated['path'] ?? '/public_html'),
(int) ($validated['cols'] ?? 120),
(int) ($validated['rows'] ?? 30),
);
return response()->json([
'session_id' => $session['session_id'],
'status' => $session['status'],
]);
}
public function read(Request $request, HostingAccount $account, string $session): JsonResponse
{
$this->authorize('useTerminal', $account);
try {
$payload = $this->sessionManager->readOutput(
$account,
(int) $request->user()->id,
$session,
(int) $request->integer('offset', 0),
);
} catch (\RuntimeException $e) {
return response()->json(['message' => $e->getMessage()], 404);
}
return response()->json($payload);
}
public function input(Request $request, HostingAccount $account, string $session): JsonResponse
{
$this->authorize('useTerminal', $account);
$input = $this->extractTerminalInput($request);
if ($input === null) {
return response()->json(['message' => 'Invalid terminal input payload.'], 422);
}
if (strlen($input) > 8192) {
return response()->json(['message' => 'Terminal input payload is too large.'], 422);
}
if ($input === '') {
return response()->json(['ok' => true]);
}
try {
$this->sessionManager->appendInput(
$account,
(int) $request->user()->id,
$session,
$input,
);
} catch (\RuntimeException $e) {
return response()->json(['message' => $e->getMessage()], 404);
}
return response()->json(['ok' => true]);
}
public function resize(Request $request, HostingAccount $account, string $session): JsonResponse
{
$this->authorize('useTerminal', $account);
$validated = $request->validate([
'cols' => 'required|integer|min:40|max:240',
'rows' => 'required|integer|min:10|max:80',
]);
try {
$this->sessionManager->resizeSession(
$account,
(int) $request->user()->id,
$session,
(int) $validated['cols'],
(int) $validated['rows'],
);
} catch (\RuntimeException $e) {
return response()->json(['message' => $e->getMessage()], 404);
}
return response()->json(['ok' => true]);
}
public function close(Request $request, HostingAccount $account, string $session): JsonResponse
{
$this->authorize('useTerminal', $account);
try {
$this->sessionManager->closeSession(
$account,
(int) $request->user()->id,
$session,
);
} catch (\RuntimeException $e) {
return response()->json(['message' => $e->getMessage()], 404);
}
return response()->json(['ok' => true]);
}
private function extractTerminalInput(Request $request): ?string
{
$input = $request->input('input');
if (is_string($input)) {
return $input;
}
$raw = $request->getContent();
if (! is_string($raw)) {
return null;
}
if ($raw === '') {
return '';
}
$decoded = json_decode($raw, true);
if (is_array($decoded) && array_key_exists('input', $decoded) && is_string($decoded['input'])) {
return $decoded['input'];
}
return $raw;
}
}