seasonal builds
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
#pragma once
|
||||
|
||||
#include <QDate>
|
||||
#include <QDateTime>
|
||||
#include <QHash>
|
||||
#include <QList>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
|
||||
class QNetworkAccessManager;
|
||||
class QJsonObject;
|
||||
|
||||
// Одна готовая сборка с сервера сезонных сборок.
|
||||
struct SeasonalBuildEntry
|
||||
{
|
||||
QString id; // season-5 — он же ключ, по которому сборка
|
||||
// узнаётся среди локальных записей
|
||||
QString name; // «Сезон 5: Пустоши»
|
||||
int revision = 0; // растёт при каждой публикации
|
||||
QString minecraftVersion; // 1.20.1
|
||||
QString loader; // "" | forge | fabric | neoforge | quilt
|
||||
QString loaderVersion; // 47.4.0
|
||||
int modCount = 0;
|
||||
QDate seasonStart;
|
||||
QDate seasonEnd; // невалидная — сезон ещё не закончен
|
||||
QString serverUrl; // адрес игрового сервера, не файлового
|
||||
int javaMajor = 0; // 0 — определять по версии игры
|
||||
QString description;
|
||||
|
||||
QUrl archiveUrl;
|
||||
qint64 archiveSize = 0;
|
||||
QString archiveSha256;
|
||||
|
||||
bool isValid() const { return !id.isEmpty() && revision > 0 && archiveUrl.isValid(); }
|
||||
};
|
||||
|
||||
// Каталог сезонных сборок: скачивает index.json с файлового сервера, кэширует
|
||||
// его в папке лаунчера и отдаёт из кэша, пока тот не устарел. Устройство
|
||||
// повторяет VersionManifestService — включая то, что пустой разбор считается
|
||||
// испорченным ответом и хороший кэш им не затирается.
|
||||
class SeasonalBuildService : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
// ok = true и непустой warning — данные отдали из устаревшего кэша.
|
||||
using Callback = std::function<void(bool ok, const QString &warning)>;
|
||||
|
||||
explicit SeasonalBuildService(QObject *parent = nullptr);
|
||||
|
||||
QList<SeasonalBuildEntry> builds() const { return m_builds; }
|
||||
bool hasData() const { return !m_builds.isEmpty(); }
|
||||
bool isRefreshing() const { return m_refreshing; }
|
||||
// Последняя ошибка обращения к серверу; пусто — всё в порядке.
|
||||
QString lastError() const { return m_lastError; }
|
||||
|
||||
std::optional<SeasonalBuildEntry> find(const QString &id) const;
|
||||
|
||||
// Адрес сервера сборок. Меняется из настроек, поэтому при смене хоста
|
||||
// накопленные данные и кэш сбрасываются: ссылки в них указывают на старый.
|
||||
void setBaseUrl(const QUrl &baseUrl);
|
||||
QUrl baseUrl() const { return m_baseUrl; }
|
||||
|
||||
void ensureLoaded(Callback callback, bool forceRefresh = false);
|
||||
|
||||
signals:
|
||||
void buildsChanged();
|
||||
void refreshingChanged();
|
||||
|
||||
private:
|
||||
bool readCache();
|
||||
void writeCache();
|
||||
void startRefresh();
|
||||
void finishRefresh(bool ok, const QString &warning);
|
||||
void applyBuilds(QList<SeasonalBuildEntry> list);
|
||||
QList<SeasonalBuildEntry> parseCatalog(const QJsonObject &root, QString *error) const;
|
||||
|
||||
QNetworkAccessManager *m_network;
|
||||
QUrl m_baseUrl;
|
||||
QList<SeasonalBuildEntry> m_builds;
|
||||
QHash<QString, int> m_indexById;
|
||||
QDateTime m_fetchedAt;
|
||||
QString m_lastError;
|
||||
bool m_refreshing = false;
|
||||
bool m_cacheRead = false;
|
||||
QList<Callback> m_pending;
|
||||
};
|
||||
Reference in New Issue
Block a user