mirror of
				https://github.com/pelican-dev/panel.git
				synced 2025-11-04 04:46:52 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			142 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			142 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
 | 
						|
namespace App\Filament\Server\Widgets;
 | 
						|
 | 
						|
use App\Exceptions\Http\HttpForbiddenException;
 | 
						|
use App\Livewire\AlertBanner;
 | 
						|
use App\Models\Permission;
 | 
						|
use App\Models\Server;
 | 
						|
use App\Models\User;
 | 
						|
use App\Services\Nodes\NodeJWTService;
 | 
						|
use App\Services\Servers\GetUserPermissionsService;
 | 
						|
use Filament\Widgets\Widget;
 | 
						|
use Illuminate\Support\Arr;
 | 
						|
use Livewire\Attributes\Session;
 | 
						|
use Livewire\Attributes\On;
 | 
						|
 | 
						|
class ServerConsole extends Widget
 | 
						|
{
 | 
						|
    protected static string $view = 'filament.components.server-console';
 | 
						|
 | 
						|
    protected int|string|array $columnSpan = 'full';
 | 
						|
 | 
						|
    protected static bool $isLazy = false;
 | 
						|
 | 
						|
    public ?Server $server = null;
 | 
						|
 | 
						|
    public ?User $user = null;
 | 
						|
 | 
						|
    /** @var string[] */
 | 
						|
    #[Session(key: 'server.{server.id}.history')]
 | 
						|
    public array $history = [];
 | 
						|
 | 
						|
    public int $historyIndex = 0;
 | 
						|
 | 
						|
    public string $input = '';
 | 
						|
 | 
						|
    private GetUserPermissionsService $getUserPermissionsService;
 | 
						|
 | 
						|
    private NodeJWTService $nodeJWTService;
 | 
						|
 | 
						|
    public function boot(GetUserPermissionsService $getUserPermissionsService, NodeJWTService $nodeJWTService): void
 | 
						|
    {
 | 
						|
        $this->getUserPermissionsService = $getUserPermissionsService;
 | 
						|
        $this->nodeJWTService = $nodeJWTService;
 | 
						|
    }
 | 
						|
 | 
						|
    protected function getToken(): string
 | 
						|
    {
 | 
						|
        if (!$this->user || !$this->server || $this->user->cannot(Permission::ACTION_WEBSOCKET_CONNECT, $this->server)) {
 | 
						|
            throw new HttpForbiddenException('You do not have permission to connect to this server\'s websocket.');
 | 
						|
        }
 | 
						|
 | 
						|
        $permissions = $this->getUserPermissionsService->handle($this->server, $this->user);
 | 
						|
 | 
						|
        return $this->nodeJWTService
 | 
						|
            ->setExpiresAt(now()->addMinutes(10)->toImmutable())
 | 
						|
            ->setUser($this->user)
 | 
						|
            ->setClaims([
 | 
						|
                'server_uuid' => $this->server->uuid,
 | 
						|
                'permissions' => $permissions,
 | 
						|
            ])
 | 
						|
            ->handle($this->server->node, $this->user->id . $this->server->uuid)->toString();
 | 
						|
    }
 | 
						|
 | 
						|
    protected function getSocket(): string
 | 
						|
    {
 | 
						|
        $socket = str_replace(['https://', 'http://'], ['wss://', 'ws://'], $this->server->node->getConnectionAddress());
 | 
						|
        $socket .= sprintf('/api/servers/%s/ws', $this->server->uuid);
 | 
						|
 | 
						|
        return $socket;
 | 
						|
    }
 | 
						|
 | 
						|
    protected function authorizeSendCommand(): bool
 | 
						|
    {
 | 
						|
        return $this->user->can(Permission::ACTION_CONTROL_CONSOLE, $this->server);
 | 
						|
    }
 | 
						|
 | 
						|
    protected function canSendCommand(): bool
 | 
						|
    {
 | 
						|
        return $this->authorizeSendCommand() && !$this->server->isInConflictState() && $this->server->retrieveStatus()->isStartingOrRunning();
 | 
						|
    }
 | 
						|
 | 
						|
    public function up(): void
 | 
						|
    {
 | 
						|
        $this->historyIndex = min($this->historyIndex + 1, count($this->history) - 1);
 | 
						|
 | 
						|
        $this->input = $this->history[$this->historyIndex] ?? '';
 | 
						|
    }
 | 
						|
 | 
						|
    public function down(): void
 | 
						|
    {
 | 
						|
        $this->historyIndex = max($this->historyIndex - 1, -1);
 | 
						|
 | 
						|
        $this->input = $this->history[$this->historyIndex] ?? '';
 | 
						|
    }
 | 
						|
 | 
						|
    public function enter(): void
 | 
						|
    {
 | 
						|
        if (!empty($this->input) && $this->canSendCommand()) {
 | 
						|
            $this->dispatch('sendServerCommand', command: $this->input);
 | 
						|
 | 
						|
            $this->history = Arr::prepend($this->history, $this->input);
 | 
						|
            $this->historyIndex = -1;
 | 
						|
 | 
						|
            $this->input = '';
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    #[On('token-request')]
 | 
						|
    public function tokenRequest(): void
 | 
						|
    {
 | 
						|
        $this->dispatch('sendAuthRequest', token: $this->getToken());
 | 
						|
    }
 | 
						|
 | 
						|
    #[On('store-stats')]
 | 
						|
    public function storeStats(string $data): void
 | 
						|
    {
 | 
						|
        $data = json_decode($data);
 | 
						|
 | 
						|
        $timestamp = now()->getTimestamp();
 | 
						|
 | 
						|
        foreach ($data as $key => $value) {
 | 
						|
            $cacheKey = "servers.{$this->server->id}.$key";
 | 
						|
            $data = cache()->get($cacheKey, []);
 | 
						|
 | 
						|
            $data[$timestamp] = $value;
 | 
						|
 | 
						|
            cache()->put($cacheKey, $data, now()->addMinute());
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    #[On('websocket-error')]
 | 
						|
    public function websocketError(): void
 | 
						|
    {
 | 
						|
        AlertBanner::make('websocket_error')
 | 
						|
            ->title('Could not connect to websocket!')
 | 
						|
            ->body('Check your browser console for more details.')
 | 
						|
            ->danger()
 | 
						|
            ->send();
 | 
						|
    }
 | 
						|
}
 |