TR
games/xencenter-xenadmin-xcp-jumphp / src / Form / ImportForm.php · commit fb1b7c9
<?phpnamespace App\Form;use App\Gui\Units;use App\Model\Connection;use App\Model\Session;use App\Xapi\Xva;use JumPHP\Gui\Button;use JumPHP\Gui\ComboBox;use JumPHP\Gui\Form;use JumPHP\Gui\Label;use JumPHP\Gui\TextBox;use JumPHP\Kernel\Platform;use JumPHP\Native\FilePicker;use JumPHP\Native\Native;/** * File > Import…: an XVA file (typed, or chosen with the system's Open dialog: a desktop app, or the browser's, which hands the file * to the page), the server it will belong to and the storage of its disks. What the file holds (its ova.xml: the VM's name, its * disks) shows before it is sent. Closes with ['xva' => ['op' => 'import', ...]], src/Feature/Xva/XvaTransfers streams it. * * @property Label $where * @property TextBox $path * @property Button $browse * @property Label $info * @property ComboBox $home * @property ComboBox $sr * @property Label $error * @property Button $import * @property Button $cancel */final class ImportForm extends Form{    private array $params = [];    /** @var array<string, mixed>|null what ova.xml says of the file chosen */    private ?array $vm = null;    public function __construct(private Session $session)    {        parent::__construct();    }    /** XAPI's answers, events and the console go on while this dialog is open. */    protected function tick(float $dt): void    {        $this->session->tick($dt);    }    /** @return array<string, mixed> */    public static function paramsFor(Connection $c, ?string $host = null): array    {        $cache = $c->cache;        $hosts = [['ref' => '', 'name' => "Don't assign a home server"]];        foreach ($cache->hosts() as $ref => $h) {            $hosts[] = ['ref' => (string)$ref, 'name' => (string)$h['name_label']];        }        $default = (string)$cache->field((string)$cache->poolRef(), 'default_SR', '');        $srs = [];        foreach ($cache->srs() as $ref => $sr) {            if (($sr['content_type'] ?? '') !== 'iso') {                $srs[] = ['ref' => (string)$ref, 'name' => $cache->name((string)$ref) . ' (' . Units::bytes((float)$sr['physical_size'] - (float)$sr['physical_utilisation']) . ' free)'];            }        }        usort($srs, fn ($a, $b) => ($b['ref'] === $default) <=> ($a['ref'] === $default));        return ['server' => $c->name(), 'pool' => (string)($cache->poolRef() ?? ''), 'hosts' => $hosts, 'srs' => $srs, 'host' => $host];    }    protected function loaded(array $params = []): void    {        $this->params = $params;        $this->vm = null;        $this->where->text = "Into '" . ($params['server'] ?? '') . "'";        $this->path->text = (string)($params['file'] ?? '');        $this->home->items = array_column($params['hosts'] ?? [], 'name');        $at = array_search($params['host'] ?? null, array_column($params['hosts'] ?? [], 'ref'), true);        $this->home->selected = $at === false ? 0 : (int)$at;        $this->sr->items = array_column($params['srs'] ?? [], 'name');        $this->sr->selected = 0;        $this->browse->enabled = Native::supports('open');        $this->error->text = '';        $this->info->text = Native::supports('open') ? '' : 'Type the path of the file' . (Platform::isWasm() ? '.' : ' (no file chooser in this window).');        $this->onFileChange($this->path, $this->path->text);        $this->setFocus($this->path);    }    public function onBrowseClick(Button $sender): void    {        if (!Native::supports('open')) {            return;        }        FilePicker::open(['title' => 'Import an XVA file', 'filters' => ['XVA files' => ['xva'], 'All files' => ['*']]])->then(function (mixed $file): void {            if (is_string($file)) {                $this->path->text = $file;                $this->onFileChange($this->path, $file);            }        }, fn (\Throwable $e) => $this->error->text = $e->getMessage());    }    public function onFileChange(TextBox $sender, string $text): void    {        $this->vm = null;        $file = trim($text);        if ($file === '' || !is_file($file)) {            if ($file !== '') {                $this->info->text = 'No such file.';            }            return;        }        $this->vm = Xva::readHeader(Xva::headOf($file));        $size = (float)@filesize($file);        if ($this->vm === null) {            $this->info->text = Units::bytes($size) . ' — this is not an XVA file (no ova.xml at its start).';            return;        }        $disks = array_map(fn (array $d) => $d[0] . ' (' . Units::bytes($d[1]) . ')', $this->vm['disks']);        $this->info->text = "VM '" . $this->vm['name_label'] . "': " . (int)$this->vm['VCPUs_max'] . ' vCPUs, ' . Units::bytes((float)$this->vm['memory_static_max'])            . ' of memory' . ($disks !== [] ? ', disks ' . implode(', ', $disks) : '') . ' · file ' . Units::bytes($size);    }    public function onImportClick(mixed $sender = null): void    {        $file = trim($this->path->text);        $this->onFileChange($this->path, $file);        if ($file === '' || !is_file($file)) {            $this->error->text = 'Choose the XVA file to import.';            return;        }        if ($this->vm === null) {            $this->error->text = 'This file is not an XVA export.';            return;        }        $sr = $this->params['srs'][(int)$this->sr->selected]['ref'] ?? null;        if ($sr === null) {            $this->error->text = 'There is no storage repository to put the disks on.';            return;        }        $host = $this->params['hosts'][(int)$this->home->selected]['ref'] ?? '';        $this->close(['xva' => ['op' => 'import', 'file' => $file, 'sr' => $sr, 'host' => $host, 'label' => (string)$this->vm['name_label']]]);    }    public function onCancelClick(Button $sender): void    {        $this->close();    }}