Скачивание образов по ссылке и из каталога готовых систем было добавлено

- web/features/downloads.py: фоновая операция типа «download» — urllib по 1 МиБ,
  таймаут 30 с, User-Agent Virtuality/<версия>, запись в .<имя>.part и переименование
  в конце; в сообщении скорость и остаток («245 МБ из 3,1 ГБ · 12 МБ/с · осталось 4 мин»);
  отмена между кусками (POST /api/operations/{id}/cancel и /downloads/{id}/cancel);
  проверка схемы, имени файла, занятости имени и свободного места (Content-Length + 512 МиБ);
  для каталога — проверка контрольной суммы (SHA256SUMS/SHA512SUMS/одиночный хеш),
  при несовпадении файл удаляется; после ISO — virsh pool-refresh virtuality-iso,
  после .img.xz — распаковка и запуск конвертации в qcow2 как при загрузке с компьютера.
- /iso и /disk-images: карточка «Скачать по ссылке», на /disk-images — «Каталог готовых
  систем» для процессора сервера с пометками «Рекомендуем», «Загружен», «Скачивается»;
  идущие скачивания вверху страниц с живым прогрессом (опрос раз в 2 с) и «Отменить».
- Тесты: парсер контрольных сумм, проверка ссылок и имён, загрузка с локального
  http-сервера, редирект, отмена, несовпадение суммы, нехватка места, .img.xz, маршруты.
- В ветку скопированы web/core.py, web/catalog.py, presenters.format_bytes и tests/fixtures
  из общей рабочей копии (без изменений), conftest подменяет run_cmd и каталоги и в core.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019LEUXMcdZo7b87mjkUsPgg
Этот коммит содержится в:
Claude
2026-09-25 14:49:43 +00:00
родитель 873b32c517
Коммит 4fd04be588
27 изменённых файлов: 1662 добавлений и 7 удалений
+8 -1
Просмотреть файл
@@ -3,9 +3,14 @@
{% set page_title = 'Готовые системы' %}
{% block page_header %}{% include "_images_header.html" %}{% endblock %}
{% block alerts %}{{ super() }}{% include "_downloads_flash.html" %}{% endblock %}
{% block content %}
{% set kind = 'disk' %}
{% include "_downloads_active.html" %}
<section class="grid grid-main">
<div class="stack">
{% include "_downloads_catalog.html" %}
<article class="card">
<div class="card-header"><div><h2>Готовые системы</h2><p>Образы уже установленных систем — машина запускается сразу, без установки</p></div></div>
{% if images %}
@@ -22,9 +27,10 @@
{% endfor %}
</div>
{% else %}
{{ empty('hard-drive', 'Готовых образов пока нет', 'Подойдут облачные образы Ubuntu и Debian, образы для Raspberry Pi, диски других систем виртуализации.') }}
{{ empty('hard-drive', 'Готовых образов пока нет', 'Выберите систему в каталоге выше — или загрузите свой образ: облачные Ubuntu и Debian, образы для Raspberry Pi, диски других систем виртуализации.') }}
{% endif %}
</article>
</div>
<aside class="stack">
<article class="card">
@@ -33,6 +39,7 @@
{{ uploader('/disk-images/upload', 'image_file', '.qcow2,.img,.raw,.img.xz,.zip,.tar.gz,.tgz', 'Перетащите файл образа сюда', '.qcow2, .img, .raw, а также архивы .img.xz, .zip, .tar.gz', '/disk-images', 'Загрузить') }}
</div>
</article>
{% include "_downloads_url.html" %}
<article class="card">
<div class="card-body stack-sm">
<div class="row">{{ icon('sparkles') }}<h3>Всё делается автоматически</h3></div>