Add support of multiple update urls

This commit is contained in:
Gres 2020-04-07 20:54:42 +03:00
parent d931015d6b
commit 576d9d5662
3 changed files with 62 additions and 14 deletions

View File

@ -28,10 +28,11 @@ const auto updatesUrl =
#endif #endif
const auto resultHideWaitUs = 300'000; const auto resultHideWaitUs = 300'000;
} // namespace } // namespace
using Loader = update::Loader;
Manager::Manager() Manager::Manager()
: settings_(std::make_unique<Settings>()) : settings_(std::make_unique<Settings>())
, updater_(std::make_unique<update::Loader>(QUrl(updatesUrl))) , updater_(std::make_unique<Loader>(Loader::Urls{{updatesUrl}}))
, updateAutoChecker_(std::make_unique<update::AutoChecker>(*updater_)) , updateAutoChecker_(std::make_unique<update::AutoChecker>(*updater_))
, models_(std::make_unique<CommonModels>()) , models_(std::make_unique<CommonModels>())
{ {

View File

@ -92,22 +92,26 @@ QStringList toList(const QJsonValue &value)
} // namespace } // namespace
Loader::Loader(const QUrl &updateUrl, QObject *parent) Loader::Loader(const update::Loader::Urls &updateUrls, QObject *parent)
: QObject(parent) : QObject(parent)
, network_(new QNetworkAccessManager(this)) , network_(new QNetworkAccessManager(this))
, model_(new Model(this)) , model_(new Model(this))
, updateUrl_(updateUrl) , updateUrls_(updateUrls)
, downloadPath_( , downloadPath_(
QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) +
"/updates") "/updates")
{ {
std::random_device device;
std::mt19937 generator(device());
std::shuffle(updateUrls_.begin(), updateUrls_.end(), generator);
connect(network_, &QNetworkAccessManager::finished, // connect(network_, &QNetworkAccessManager::finished, //
this, &Loader::handleReply); this, &Loader::handleReply);
} }
void Loader::handleReply(QNetworkReply *reply) void Loader::handleReply(QNetworkReply *reply)
{ {
if (reply->url() == updateUrl_) { if (updateUrls_.contains(reply->url())) {
handleUpdateReply(reply); handleUpdateReply(reply);
} else { } else {
handleComponentReply(reply); handleComponentReply(reply);
@ -116,7 +120,28 @@ void Loader::handleReply(QNetworkReply *reply)
void Loader::checkForUpdates() void Loader::checkForUpdates()
{ {
auto reply = network_->get(QNetworkRequest(updateUrl_)); startDownloadUpdates({});
}
void Loader::startDownloadUpdates(const QUrl &previous)
{
SOFT_ASSERT(!updateUrls_.isEmpty(), return );
QUrl url;
if (previous.isEmpty())
url = updateUrls_.first();
else {
const auto index = updateUrls_.indexOf(previous);
SOFT_ASSERT(index != -1, return );
if (index == updateUrls_.size() - 1)
return;
url = updateUrls_[index + 1];
}
if (url.isEmpty())
return;
auto reply = network_->get(QNetworkRequest(url));
if (reply->error() != QNetworkReply::NoError) if (reply->error() != QNetworkReply::NoError)
handleUpdateReply(reply); handleUpdateReply(reply);
} }
@ -127,13 +152,28 @@ void Loader::handleUpdateReply(QNetworkReply *reply)
if (reply->error() != QNetworkReply::NoError) { if (reply->error() != QNetworkReply::NoError) {
emit error(toError(*reply)); emit error(toError(*reply));
startDownloadUpdates(reply->url());
return; return;
} }
const auto replyData = reply->readAll(); const auto replyData = reply->readAll();
if (replyData.isEmpty()) {
emit error(
tr("Received empty updates info from %1").arg(reply->url().toString()));
startDownloadUpdates(reply->url());
return;
}
SOFT_ASSERT(model_, return ); SOFT_ASSERT(model_, return );
model_->parse(replyData); const auto parseError = model_->parse(replyData);
if (!parseError.isEmpty()) {
emit error(tr("Failed to parse updates from %1 (%2)")
.arg(reply->url().toString(), parseError));
startDownloadUpdates(reply->url());
return;
}
if (model_->hasUpdates()) if (model_->hasUpdates())
emit updatesAvailable(); emit updatesAvailable();
} }
@ -324,20 +364,20 @@ void Model::initView(QTreeView *view)
}); });
} }
void Model::parse(const QByteArray &data) QString Model::parse(const QByteArray &data)
{ {
QJsonParseError error; QJsonParseError error;
const auto doc = QJsonDocument::fromJson(data, &error); const auto doc = QJsonDocument::fromJson(data, &error);
if (doc.isNull()) { if (doc.isNull()) {
LERROR() << error.errorString(); return tr("Failed to parse: %1 at %2")
return; .arg(error.errorString())
.arg(error.offset);
} }
const auto json = doc.object(); const auto json = doc.object();
const auto version = json[versionKey].toInt(); const auto version = json[versionKey].toInt();
if (version != 1) { if (version != 1) {
LERROR() << "Wrong updates.json version" << version; return tr("Wrong updates version %1").arg(version);
return;
} }
beginResetModel(); beginResetModel();
@ -347,6 +387,11 @@ void Model::parse(const QByteArray &data)
updateState(*root_); updateState(*root_);
endResetModel(); endResetModel();
if (!root_) {
return tr("No data parsed");
}
return {};
} }
std::unique_ptr<Model::Component> Model::parse(const QJsonObject &json) const std::unique_ptr<Model::Component> Model::parse(const QJsonObject &json) const

View File

@ -58,7 +58,7 @@ public:
void initView(QTreeView* view); void initView(QTreeView* view);
void parse(const QByteArray& data); QString parse(const QByteArray& data);
void setExpansions(const std::map<QString, QString>& expansions); void setExpansions(const std::map<QString, QString>& expansions);
UserActions userActions() const; UserActions userActions() const;
void updateStates(); void updateStates();
@ -130,7 +130,8 @@ class Loader : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit Loader(const QUrl& updateUrl, QObject* parent = nullptr); using Urls = QVector<QUrl>;
explicit Loader(const Urls& updateUrls, QObject* parent = nullptr);
void checkForUpdates(); void checkForUpdates();
void applyUserActions(); void applyUserActions();
@ -150,10 +151,11 @@ private:
void commitUpdate(); void commitUpdate();
void updateProgress(qint64 bytesSent, qint64 bytesTotal); void updateProgress(qint64 bytesSent, qint64 bytesTotal);
bool startDownload(File& file); bool startDownload(File& file);
void startDownloadUpdates(const QUrl& previous);
QNetworkAccessManager* network_; QNetworkAccessManager* network_;
Model* model_; Model* model_;
QUrl updateUrl_; Urls updateUrls_;
QString downloadPath_; QString downloadPath_;
std::map<QNetworkReply*, File*> downloads_; std::map<QNetworkReply*, File*> downloads_;
UserActions currentActions_; UserActions currentActions_;