UK
games/xencenter-xenadmin-xcp-jumphp / src / Form / ExportForm.php · commit fb1b7c9
<?phpnamespace App\Form;use App\Gui\Units;use App\Model\Connection;use App\Model\Session;use JumPHP\Gui\Button;use JumPHP\Gui\CheckBox;use JumPHP\Gui\Form;use JumPHP\Gui\Label;use JumPHP\Gui\TextBox;use JumPHP\Kernel\Platform;use JumPHP\Native\FilePicker;use JumPHP\Native\Native;/** * VM > Export…: where to save the XVA file (typed, or the system's Save dialog when this target has one: a desktop app), compressed * or not. A browser cannot write a file of that size anywhere: the dialog says so. Closes with ['xva' => ['op' => 'export', ...]], * src/Feature/Xva/XvaTransfers streams it. * * @property Label $heading * @property Label $where * @property TextBox $path * @property Button $browse * @property CheckBox $compress * @property Label $size * @property Label $error * @property Button $export * @property Button $cancel */final class ExportForm extends Form{    private array $params = [];    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 $vm): array    {        $size = 0.0;        foreach ($c->cache->disksOf($vm) as $d) {            if ($d['vdi'] !== null && ($d['vbd']['type'] ?? '') !== 'CD') {                $size += (float)($d['vdi']['physical_utilisation'] ?? 0);            }        }        $name = $c->cache->name($vm);        $dir = rtrim((string)(getenv('HOME') ?: sys_get_temp_dir()), '/');        return ['target' => $vm, 'name' => $name, 'server' => $c->name(), 'size' => $size,            'file' => $dir . '/' . (trim((string)preg_replace('/[^A-Za-z0-9._-]+/', '-', $name), '-') ?: 'vm') . '.xva',            'halted' => in_array($c->cache->field($vm, 'power_state', ''), ['Halted'], true) || !empty($c->cache->field($vm, 'is_a_snapshot'))];    }    protected function loaded(array $params = []): void    {        $this->params = $params;        $this->heading->text = "Export VM '" . ($params['name'] ?? '') . "'";        $this->where->text = "In '" . ($params['server'] ?? '') . "'";        $this->path->text = (string)($params['file'] ?? '');        $this->browse->enabled = Native::supports('save');        $this->size->text = 'Its disks hold ' . Units::bytes((float)($params['size'] ?? 0)) . ': the file is about that size (less when compressed).';        $this->error->text = '';        $this->export->enabled = true;        if (Platform::isWasm()) {            // a web page can only hand a file to the browser's downloads, all in memory: not for a VM's disks            $this->error->text = 'Exporting to a file is not possible in a browser (a VM does not fit in the page\'s memory): use XenCenter on the desktop, or xe vm-export on the server.';            $this->export->enabled = false;        } elseif (empty($params['halted'])) {            $this->error->text = 'Shut the VM down first: XAPI exports halted VMs (or snapshots) only.';            $this->export->enabled = false;        }        $this->setFocus($this->path);    }    public function onBrowseClick(Button $sender): void    {        if (!Native::supports('save')) {            return;        }        FilePicker::save(['title' => 'Export VM', 'file_name' => basename($this->path->text), 'directory' => dirname($this->path->text),            'filters' => ['XVA files' => ['xva']]])->then(function (?string $file): void {                if ($file !== null) {                    $this->path->text = str_ends_with(strtolower($file), '.xva') ? $file : $file . '.xva';                }            }, fn (\Throwable $e) => $this->error->text = $e->getMessage());    }    public function onExportClick(mixed $sender = null): void    {        if (!$this->export->enabled) {            return;        }        $file = trim($this->path->text);        if ($file === '' || str_ends_with($file, '/')) {            $this->error->text = 'Enter the file to write.';            return;        }        if (!is_dir(dirname($file)) || !is_writable(dirname($file))) {            $this->error->text = 'The folder ' . dirname($file) . ' does not exist or cannot be written.';            return;        }        $this->close(['xva' => ['op' => 'export', 'target' => $this->params['target'] ?? '', 'file' => $file, 'compress' => $this->compress->checked]]);    }    public function onCancelClick(Button $sender): void    {        $this->close();    }}