#pragma once #include #include #include #include #include class QNetworkAccessManager; class QNetworkReply; class QSaveFile; class QTimer; // Загрузка одного архива сезонной сборки в файл. Пишем потоком и сверяем // sha256: пак — это сотни мегабайт, держать их в памяти незачем, а // распаковывать битую загрузку поверх рабочей .minecraft нельзя. // // Распаковкой занимается BuildSwitcher: она идёт в отдельном потоке вместе с // остальными операциями над содержимым .minecraft. // // Набор геттеров повторяет VersionInstaller и JavaInstaller: панель загрузки в // интерфейсе читает их одинаково, независимо от того, кто сейчас работает. class SeasonalPackDownloader : public QObject { Q_OBJECT public: explicit SeasonalPackDownloader(QObject *parent = nullptr); ~SeasonalPackDownloader() override; bool isRunning() const { return m_running; } QString label() const { return m_label; } QString stage() const { return m_stage; } QString currentFile() const { return m_currentFile; } qint64 bytesDone() const { return m_bytesDone; } qint64 bytesTotal() const { return m_bytesTotal; } double fraction() const; // 0..1, либо -1 пока итог неизвестен // targetPath перезаписывается: недокачанный пак с прошлой попытки не // должен пережить новую. void download(const QUrl &url, const QString &targetPath, const QString &sha256, qint64 expectedSize, const QString &label); void cancel(); signals: void started(const QString &label); void progressChanged(); void finished(const QString &path); void failed(const QString &label, const QString &message); void canceled(const QString &label); private: void fail(const QString &message); void reset(); void scheduleProgress(); void flushProgress(); QNetworkAccessManager *m_network; QNetworkReply *m_reply = nullptr; std::unique_ptr m_file; QCryptographicHash m_hash{QCryptographicHash::Sha256}; QString m_targetPath; QString m_sha256; QString m_label; QString m_stage; QString m_currentFile; qint64 m_bytesDone = 0; qint64 m_bytesTotal = 0; QTimer *m_progressTimer; bool m_progressDirty = false; bool m_running = false; bool m_canceling = false; };