java implementation and downloading
This commit is contained in:
+148
@@ -0,0 +1,148 @@
|
||||
#pragma once
|
||||
|
||||
#include "javaruntime.h"
|
||||
|
||||
#include <QCryptographicHash>
|
||||
#include <QList>
|
||||
#include <QObject>
|
||||
#include <QPair>
|
||||
#include <QQueue>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
#include <memory>
|
||||
|
||||
class QJsonObject;
|
||||
class QNetworkAccessManager;
|
||||
class QNetworkReply;
|
||||
class QProcess;
|
||||
class QSaveFile;
|
||||
class QTimer;
|
||||
|
||||
// Состояние распаковки zip. Спрятано в .cpp, чтобы приватный заголовок
|
||||
// QZipReader не расходился по проекту вместе с этим.
|
||||
struct ZipExtraction;
|
||||
|
||||
// Один файл рантайма Mojang.
|
||||
struct JavaFileTask
|
||||
{
|
||||
QUrl url;
|
||||
QString path; // абсолютный путь назначения
|
||||
QString sha1;
|
||||
qint64 size = 0;
|
||||
bool executable = false;
|
||||
int attempts = 0;
|
||||
};
|
||||
|
||||
// Файл в процессе скачивания. Пишем потоком: рантайм — это две сотни мегабайт.
|
||||
struct JavaActiveDownload
|
||||
{
|
||||
JavaFileTask task;
|
||||
QNetworkReply *reply = nullptr;
|
||||
std::unique_ptr<QSaveFile> file;
|
||||
QCryptographicHash hash{QCryptographicHash::Sha1};
|
||||
qint64 received = 0;
|
||||
};
|
||||
|
||||
// Установка сборки Java в <root>/java/<id>. Два разных пути под одним фасадом:
|
||||
//
|
||||
// * Temurin отдаёт один архив — качаем, сверяем sha256 и распаковываем;
|
||||
//
|
||||
// * Mojang отдаёт манифест с деревом файлов — качаем файлы по отдельности,
|
||||
// как это делает официальный лаунчер.
|
||||
//
|
||||
// Набор геттеров повторяет VersionInstaller: панель загрузки в интерфейсе
|
||||
// читает их одинаково, независимо от того, кто сейчас работает.
|
||||
class JavaInstaller : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit JavaInstaller(QObject *parent = nullptr);
|
||||
~JavaInstaller() override;
|
||||
|
||||
bool isRunning() const { return m_running; }
|
||||
QString runtimeId() const { return m_entry.id; }
|
||||
QString label() const { return m_label; }
|
||||
QString stage() const { return m_stage; }
|
||||
QString currentFile() const { return m_currentFile; }
|
||||
|
||||
// Байты считаются только на загрузке: на распаковке считать нечего, и панель
|
||||
// по нулевому итогу сама прячет мегабайты.
|
||||
qint64 bytesDone() const;
|
||||
qint64 bytesTotal() const { return m_bytesTotal; }
|
||||
double fraction() const; // 0..1, либо -1 пока итог неизвестен
|
||||
|
||||
void install(const JavaRuntimeEntry &entry);
|
||||
void cancel();
|
||||
|
||||
signals:
|
||||
void started(const QString &label);
|
||||
void progressChanged();
|
||||
void finished(const QString &runtimeId, const QString &javaPath);
|
||||
void failed(const QString &label, const QString &message);
|
||||
void canceled(const QString &label);
|
||||
|
||||
private:
|
||||
// ── Общее ───────────────────────────────────────────────────────────
|
||||
void beginArchive();
|
||||
void beginMojang();
|
||||
void complete();
|
||||
void fail(const QString &message);
|
||||
void reset();
|
||||
void setStage(const QString &stage);
|
||||
void scheduleProgress();
|
||||
void flushProgress();
|
||||
|
||||
// ── Temurin ─────────────────────────────────────────────────────────
|
||||
void downloadArchive();
|
||||
void handleArchiveFinished(QNetworkReply *reply);
|
||||
void startExtraction();
|
||||
void extractZipChunk();
|
||||
void startTarExtraction();
|
||||
|
||||
// ── Mojang ──────────────────────────────────────────────────────────
|
||||
void handleManifest(const QByteArray &payload);
|
||||
bool prepareTree(const QJsonObject &files);
|
||||
void pump();
|
||||
void startTask(JavaFileTask task);
|
||||
void handleFileFinished(const std::shared_ptr<JavaActiveDownload> &context);
|
||||
bool retryOrFail(JavaFileTask task, const QString &reason);
|
||||
bool applyLinks();
|
||||
|
||||
QNetworkAccessManager *m_network;
|
||||
|
||||
JavaRuntimeEntry m_entry;
|
||||
QString m_label;
|
||||
QString m_targetDir;
|
||||
QString m_archivePath;
|
||||
|
||||
QString m_stage;
|
||||
QString m_currentFile;
|
||||
qint64 m_bytesSettled = 0;
|
||||
qint64 m_bytesTotal = 0;
|
||||
|
||||
// Шаги распаковки: у архива — записи внутри него, у Mojang — файлы дерева.
|
||||
int m_stepsDone = 0;
|
||||
int m_stepsTotal = 0;
|
||||
|
||||
QNetworkReply *m_reply = nullptr; // архив или манифест
|
||||
std::unique_ptr<QSaveFile> m_archiveFile;
|
||||
QCryptographicHash m_archiveHash{QCryptographicHash::Sha256};
|
||||
|
||||
QProcess *m_tar = nullptr;
|
||||
QTimer *m_extractTimer;
|
||||
QTimer *m_progressTimer;
|
||||
bool m_progressDirty = false;
|
||||
|
||||
// Распаковка zip по кускам: держать GUI-поток занятым на всю сотню
|
||||
// мегабайт нельзя, а поток ради одной операции заводить незачем.
|
||||
std::unique_ptr<ZipExtraction> m_zip;
|
||||
|
||||
QQueue<JavaFileTask> m_queue;
|
||||
QList<std::shared_ptr<JavaActiveDownload>> m_active;
|
||||
QList<QPair<QString, QString>> m_links; // {абсолютный путь ссылки, цель}
|
||||
|
||||
bool m_running = false;
|
||||
bool m_canceling = false;
|
||||
};
|
||||
Reference in New Issue
Block a user