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; } }