documentation rewrite

Signed-off-by: galeon <dertiellis@gmail.com>
This commit is contained in:
galeon committed 2026-10-11 22:32:13 +03:00
1 parent 1943996608
commit f10b654953
34 files changed
+2099 -4576

No files matched your search

+45 -133
View File
@@ -1,155 +1,67 @@
# JavaRuntimeService
## Обзор класса
`javaruntimeservice.h`, `javaruntimeservice.cpp`
`JavaRuntimeService` — каталог сборок Java, которые лаунчер умеет скачать: качает, кэширует в
папке лаунчера и отдаёт из кэша, пока тот не устарел. Устроен так же, как
[VersionManifestService](VersionManifestService.md).
Каталог сборок Java, которые лаунчер может скачать. Устроен как
[VersionManifestService](VersionManifestService.md), но кэш хранится сутки и лежит в
`<root>/cache/java_runtimes.json`.
Источников два, и они дополняют друг друга. **Mojang** (категория «Java») — ровно тот рантайм,
которым запускает игру официальный лаунчер: версий немного, зато они заведомо совместимы.
**Eclipse Temurin** (категории JDK и JRE) — свежие сборки всех мажорных версий, включая те, до
которых Mojang ещё не дошёл.
Источников два:
Отдаются только сборки под текущие операционную систему и архитектуру: выбрать заведомо
неработающую нечем. Исключение — macOS на Apple Silicon, где под Java 8 и 16 сборок `aarch64` нет
вовсе и приходится брать `x64`, который работает через Rosetta.
- **Mojang** (в интерфейсе категория «Java») — те же рантаймы, с которыми игру запускает
официальный лаунчер. Их немного, зато с игрой они точно совместимы.
- **Eclipse Temurin** (JDK и JRE) — свежие сборки всех мажорных версий, в том числе тех, которых у
Mojang ещё нет.
## Место в проекте и зависимости
В каталог попадают только сборки под текущую ОС и архитектуру.
Подключает [javaruntime.h](javaruntime.md): перечисление `JavaRuntimeKind` и структура
`JavaRuntimeEntry` приходят оттуда.
Экземпляр держит [LauncherBackend](LauncherBackend.md), ставит сборки
[JavaInstaller](JavaInstaller.md).
Экземпляр создаётся и принадлежит [LauncherBackend](LauncherBackend.md). Записями каталога
пользуется [JavaInstaller](JavaInstaller.md).
## Как обновляется каталог
Путь к файлу кэша даёт `LauncherPaths::javaCatalogFile()` из [launcherpaths.h](launcherpaths.md).
Запросы идут параллельно. Каталог заменяется целиком, когда ответят все.
Требования сборки: `Qt6::Core` (`QDateTime`, `QHash`, `QSet`) и `Qt6::Network`
(`QNetworkAccessManager`).
1. `api.adoptium.net/v3/info/available_releases` — какие мажорные версии есть и какие из них LTS.
2. Для каждой мажорной версии `assets/feature_releases/<major>/ga` с фильтрами: ОС, архитектура,
HotSpot, обычная куча, vendor `eclipse`, три последних релиза. Из каждого берутся бинарники с
`image_type` = `jdk` или `jre` в виде `.zip` или `.tar.gz` по `https`.
3. `piston-meta.mojang.com/.../java-runtime/.../all.json` — раздел под текущую платформу
(`windows-x64`, `mac-os-arm64`, `linux` и т. п.), по одному варианту на компонент. Компонент
`minecraft-java-exe` пропускается: это не Java.
## Иерархия и роль
**Нет сборки под aarch64.** У Temurin под ARM нет Java 8 и 16. Если для aarch64 ничего не нашлось,
запрос повторяется для `x64`. На Mac с Apple Silicon такая сборка работает через Rosetta. Сейчас
повтор делается на любой ОС с aarch64, хотя комментарий в заголовке говорит только про macOS.
Наследует `QObject`: мета-объектная система, два сигнала и владение по родителю. Виртуальных
методов базового класса не переопределяет.
Id строк: `temurin-<jdk|jre>-<версия>-<арх>` и `mojang-<компонент>`, пропущенные через
`JavaRuntimeStore::sanitizeId()`.
## Псевдонимы типов
Версия Temurin 8 показывается как `8u<security>`, остальные — как `openjdk_version` без `-LTS`.
Мажорная версия у Mojang берётся из имени (`8u…` → 8, иначе первое число).
`JavaRuntimeService::Callback` — `std::function<void(bool ok, const QString &warning)>`. Как и в
остальных каталогах лаунчера, `ok == true` с непустым `warning` означает данные из устаревшего
кэша.
У сборок Mojang `size` равен 0: в каталоге указан только размер манифеста, а не рантайма.
## Публичные методы
Если какие-то запросы упали, а другие ответили, каталог всё равно обновляется, а предупреждения
склеиваются через `; `. Если не пришло ничего, но старые данные есть, колбэк получает `ok = true` и
предупреждение.
#### explicit JavaRuntimeService(QObject \*parent = nullptr)
Кэш помечается платформой (`mojangPlatform()`). Кэш с другой платформы не читается. Это возможно,
например, если папку лаунчера перенесли с другой машины.
Создаёт сервис и его `QNetworkAccessManager`. Кэш читается лениво. Конструктор помечен `explicit`.
## Методы
#### void ensureLoaded(Callback callback, bool forceRefresh = false)
- `ensureLoaded(callback, forceRefresh)` — как у манифеста версий.
- `entries(kind)` — строки одного вида, отсортированы по мажорной версии, потом по дате выхода,
новые сверху.
- `find(id)`.
- `bestFor(major)` — что скачать, если игре нужна Java `major`, а подходящей нет. Выбирается
наименьшая мажорная версия не ниже `major`. При равенстве порядок такой: Temurin JDK, потом
Mojang, потом Temurin JRE. JDK идёт первым, потому что установщикам Forge и NeoForge иногда нужны
инструменты из полного комплекта. Если и здесь равенство, берётся более свежая.
- `isRefreshing()`, `hasData()`.
Единственная точка входа. Свежий кэш означает отложенный вызов колбэка без сети; иначе запускается
обновление. Параметр `forceRefresh` обходит проверку свежести — так работает кнопка обновления
каталога.
Одно обновление складывается из нескольких запросов сразу к обоим источникам. Ответы приходят
вразнобой, поэтому они накапливаются, и каталог подменяется целиком только когда пришли все.
#### QList&lt;JavaRuntimeEntry&gt; entries(JavaRuntimeKind kind) const
Сборки одной категории: `Mojang`, `Jdk` или `Jre`. Новые версии идут первыми.
#### std::optional&lt;JavaRuntimeEntry&gt; find(const QString &id) const
Запись по идентификатору сборки; `std::nullopt`, если такой нет. Поиск идёт по внутреннему
указателю.
#### std::optional&lt;JavaRuntimeEntry&gt; bestFor(int major) const
Что скачать, если для версии игры нужна Java указанной мажорной версии, а подходящей в системе
нет.
Правила выбора: точное совпадение мажорной версии предпочтительнее более новой, а JDK
предпочтительнее JRE — установщики Forge и NeoForge иногда требуют инструментов из полного
комплекта. `std::nullopt` означает, что предложить нечего.
#### bool isRefreshing() const
Идут ли сейчас запросы. Признак остаётся истинным, пока не завершится последний из них.
#### bool hasData() const
Есть ли в каталоге хоть что-то — из сети или из кэша.
## Сигналы
#### catalogChanged()
Каталог заменён новыми данными. Испускается один раз за обновление, когда пришли ответы от всех
источников, а не по каждому из них.
Обработчик перечитывает `entries()` для нужных категорий и обновляет интерфейс.
#### refreshingChanged()
Изменился признак обновления. Обработчик показывает или убирает индикатор загрузки.
## Владение и время жизни
Класс наследует `QObject` и принимает `parent` — родитель его и удалит.
`QNetworkAccessManager` создаётся в конструкторе с сервисом в роли родителя.
Отложенные колбэки хранятся до завершения текущего обновления. Уничтожение сервиса с
незавершёнными запросами обрывает их вместе с менеджером сети, и колбэки не вызываются.
## Потокобезопасность
Только поток GUI. Чтение и запись кэша выполняются синхронно в вызывающем потоке.
## Взаимодействие с другими классами
`LauncherBackend` вызывает `ensureLoaded()` при открытии окна выбора Java и по кнопке обновления,
а сигналы переправляет в свойства, которые читает QML. Перед отдачей в интерфейс он сводит записи
каталога с уже установленными сборками из `JavaRuntimeStore` — окно выбора показывает статус, не
считая ничего само.
[JavaInstaller](JavaInstaller.md) получает запись каталога и по ней скачивает и распаковывает
сборку. `bestFor()` используется, когда для запуска не хватает Java и лаунчер должен сам
предложить, что поставить.
Требования версий игры к Java берутся из пространства имён `JavaRequirement` в
[javaruntime.h](javaruntime.md).
## Внешнее взаимодействие
**Сеть, исходящие запросы.** Класс обращается к двум внешним каталогам: API Adoptium (сборки
Temurin) и списку рантаймов Mojang. Формат обоих — JSON поверх HTTPS, разбор разделён на две
функции.
Запросов на одно обновление несколько: список сборок Temurin запрашивается по мажорным версиям,
и на macOS с Apple Silicon неудачный запрос сборки `aarch64` может быть переспрошен для `x64` —
это и есть тот самый случай Java 8 и 16.
Общий счётчик незавершённых запросов сводит их воедино: пока он не обнулился, каталог не
подменяется, а предупреждения от отдельных источников накапливаются.
Все сигналы и колбэки приходят в поток GUI.
## Пример использования
```cpp
auto *javaCatalog = new JavaRuntimeService(this);
connect(javaCatalog, &JavaRuntimeService::catalogChanged, this, &Backend::rebuildJavaCatalog);
javaCatalog->ensureLoaded([this, javaCatalog](bool ok, const QString &warning) {
if (!ok) {
emit javaCatalogError(warning);
return;
}
const auto best = javaCatalog->bestFor(version.javaMajor);
if (best)
emit suggestJavaInstall(best->id, best->version);
});
```
Сигналы: `catalogChanged()`, `refreshingChanged()`.
---