Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fetch all URLs from a single URL, fix #46 #78

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 19 additions & 6 deletions News.qml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ Item {
bottomMargin: 10
}

function fetchFallbackNews() {
console.log("fetching fallback posts json");
fetchNews(downloader.newsFallbackUrl);
}

function fetchNews(jsonUrl) {
var news = new XMLHttpRequest();

Expand All @@ -55,11 +60,8 @@ Item {
}

if (newsObj === null) {
var fallbackJsonUrl = 'qrc:/resources/disconnected_posts.json';

if (jsonUrl !== fallbackJsonUrl) {
console.log("fetching fallback posts json");
fetchNews(fallbackJsonUrl);
if (jsonUrl !== downloader.newsFallbackUrl) {
fetchFallbackNews();
return;
}
}
Expand Down Expand Up @@ -98,6 +100,14 @@ Item {
news.send();
}

Connections {
target: splashController

onNewsUrlFetched: {
fetchNews(newsUrl);
}
}

SwipeView {
id: swipe

Expand All @@ -111,7 +121,10 @@ Item {
}

Component.onCompleted: {
fetchNews('https://unvanquished.net/api/get_recent_posts/');
var newsUrl = downloader.newsUrl;
if (newsUrl != "") {
fetchNews(newsUrl);
}
}
}

Expand Down
94 changes: 76 additions & 18 deletions currentversionfetcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@
*/

#include "currentversionfetcher.h"
#include "system.h"

#include <QDebug>
#include <QUrl>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>

CurrentVersionFetcher::CurrentVersionFetcher(QObject* parent) : QObject(parent), manager_(new QNetworkAccessManager(this))
{
Expand All @@ -35,35 +37,91 @@ void CurrentVersionFetcher::fetchCurrentVersion(QString url)
manager_->get(request);
}

void ComponentVersionFetcher(QJsonObject jsonObject, QString componentSlug, QString componentSystem, QString *componentVersion, QString *componentUrl)
{
QString componentMirror;
QString componentPath;

QJsonObject componentObject = jsonObject[componentSlug].toObject();
if (componentObject.isEmpty()) {
qDebug() << "ComponentVersionFetcher: undefined “" << componentSlug << "” key";
} else {
QJsonValue version = componentObject.value("version");
if (version == QJsonValue::Undefined) {
qDebug() << "ComponentVersionFetcher: undefined “version” value for" << componentSlug;
} else {
*componentVersion = version.toString();
}

QJsonArray mirrorsArray = componentObject["mirrors"].toArray();
if (!mirrorsArray.count()) {
qDebug() << "ComponentVersionFetcher: undefined “mirrors” key for " << componentSlug;
} else {
componentMirror = mirrorsArray.first().toString();
}

QJsonObject parcelsObject = componentObject["parcels"].toObject();
if (parcelsObject.isEmpty()) {
qDebug() << "ComponentVersionFetcher: undefined “parcels” key for" << componentSlug;
} else {
QJsonObject systemObject = parcelsObject[componentSystem].toObject();
if (systemObject.isEmpty()) {
qDebug() << "ComponentVersionFetcher: undefined “" << componentSystem << "” key for " << componentSlug;
} else {
QJsonValue path = systemObject.value("path");
if (path == QJsonValue::Undefined) {
qDebug() << "ComponentVersionFetcher: undefined “path” value for" << componentSlug;
} else {
componentPath = path.toString();
}
}
}

*componentUrl = componentMirror + "/" + componentPath;
if (*componentUrl == "/") {
*componentUrl = "";
}

qDebug() << "ComponentVersionFetcher: fetched component =" << componentSlug;
qDebug() << "ComponentVersionFetcher: fetched system =" << componentSystem;
qDebug() << "ComponentVersionFetcher: fetched version =" << *componentVersion;
qDebug() << "ComponentVersionFetcher: fetched mirror =" << componentMirror;
qDebug() << "ComponentVersionFetcher: fetched path =" << componentPath;
qDebug() << "ComponentVersionFetcher: fetched url =" << *componentUrl;
}
}

void CurrentVersionFetcher::reply(QNetworkReply* reply)
{
QString game;
QString updater;
QString updaterVersion;
QString updaterUrl;
QString gameVersion;
QString gameUrl;
QString newsVersion;
QString newsUrl;

if (reply->error() != QNetworkReply::NoError) {
qDebug() << "CurrentVersionFetcher: network error";
emit onCurrentVersions(updater, game);
emit onCurrentVersions(updaterVersion, updaterUrl, gameVersion, gameUrl, newsUrl);
return;
}

QJsonParseError error;
QJsonDocument json = QJsonDocument::fromJson(reply->readAll(), &error);
if (error.error != QJsonParseError::NoError) {
qDebug() << "CurrentVersionFetcher: JSON parsing error";
emit onCurrentVersions(updater, game);
emit onCurrentVersions(updaterVersion, updaterUrl, gameVersion, gameUrl, newsUrl);
return;
}
QJsonValue value = json.object().value("updater");
if (value != QJsonValue::Undefined) {
updater = value.toString();
} else {
qDebug() << "CurrentVersionFetcher: undefined “updater” value";
}
value = json.object().value("unvanquished");
if (value != QJsonValue::Undefined) {
game = value.toString();
} else {
qDebug() << "CurrentVersionFetcher: undefined “unvanquished” value";
}
qDebug() << "CurrentVersionFetcher: fetched versions: updater =" << updater << "game =" << game;
emit onCurrentVersions(updater, game);

QJsonObject jsonObject = json.object();

ComponentVersionFetcher(jsonObject, "updater", Sys::updaterSystem(), &updaterVersion, &updaterUrl);

ComponentVersionFetcher(jsonObject, "game", "all-all", &gameVersion, &gameUrl);

ComponentVersionFetcher(jsonObject, "news", "all-all", &newsVersion, &newsUrl);

emit onCurrentVersions(updaterVersion, updaterUrl, gameVersion, gameUrl, newsUrl);
}

2 changes: 1 addition & 1 deletion currentversionfetcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class CurrentVersionFetcher : public QObject
void fetchCurrentVersion(QString url);

signals:
void onCurrentVersions(QString updater, QString game);
void onCurrentVersions(QString updaterVersion, QString updaterUrl, QString gameVersion, QString gameUrl, QString newsUrl);

private slots:
void reply(QNetworkReply* reply);
Expand Down
4 changes: 2 additions & 2 deletions deployment.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## Network resources used by the updater
- News REST endpoint which returns links to Wordpress articles on unvanquished.net. The featured image in each news article must be a type which is supported by the updater (see issue #51). Currently PNG and JPEG are known to work.
- versions.json file on unvanquished.net, used to determine whether update is needed
- current.json file on unvanquished.net, used to determine whether update is needed
- Github releases. These are targeted by download links on unvanquished.net and by the updater's self-update process.
- Torrent URL used to download the latest game version

Expand Down Expand Up @@ -35,4 +35,4 @@
```
2. Upload `UnvUpdaterWin.zip` and `UnvanquishedUpdater.exe` from `build-docker/release-win/`.

4. Bump the updater version on unvanquished.net to the new tag, so that it is reflected in versions.json and the download links.
4. Bump the updater version on unvanquished.net to the new tag, so that it is reflected in current.json and the download links.
2 changes: 1 addition & 1 deletion gamelauncher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ GameLauncher::GameLauncher(const QString& connectUrl, const Settings& settings)
// Does our version of daemon have -connect-trusted?
static bool haveConnectTrusted(const QString& gameVersion)
{
// Updater version up to v0.2.0 may set "unknown" as game version if versions.json request fails
// Updater version up to v0.2.0 may set "unknown" as game version if current.json request fails
if (gameVersion == "unknown")
return false;
// Hacky string comparison, assume we won't go down to 0.9 or up to 0.100 :)
Expand Down
10 changes: 5 additions & 5 deletions linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ QString archiveName()
return "linux-amd64.zip";
}

QString updaterSystem()
{
return "linux-amd64";
}

void migrateHomePath()
{
QString legacyHomePath = QDir::homePath() + "/.unvanquished";
Expand Down Expand Up @@ -247,11 +252,6 @@ bool updateUpdater(const QString& updaterArchive, const QString& connectUrl)
return false;
}

QString updaterArchiveName()
{
return "UnvUpdaterLinux.zip";
}

std::string getCertStore()
{
// From Go: https://golang.org/src/crypto/x509/root_linux.go
Expand Down
17 changes: 12 additions & 5 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ struct CommandLineOptions {
QString ariaLogFilename;
int splashMilliseconds = 3000;
RelaunchCommand relaunchCommand = RelaunchCommand::NONE;
QString updateUpdaterVersion;
QString updateUpdaterUrl;
QString connectUrl;
};

Expand Down Expand Up @@ -121,13 +121,16 @@ CommandLineOptions getCommandLineOptions(const QApplication& app) {
splashMsOption.setValueName("duration in milliseconds");
QCommandLineOption internalCommandOption("internalcommand");
internalCommandOption.setValueName("command");
QCommandLineOption updaterUrl("updaterurl");
updaterUrl.setValueName("url");
QCommandLineParser optionParser;
optionParser.addHelpOption();
optionParser.addVersionOption();
optionParser.addOption(logFileNameOption);
optionParser.addOption(ariaLogFilenameOption);
optionParser.addOption(splashMsOption);
optionParser.addOption(internalCommandOption);
optionParser.addOption(updaterUrl);
optionParser.addPositionalArgument("URL", "address of Unvanquished server to connect to", "[URL]");
optionParser.process(app);
CommandLineOptions options;
Expand All @@ -144,9 +147,13 @@ CommandLineOptions getCommandLineOptions(const QApplication& app) {
options.relaunchCommand = RelaunchCommand::PLAY_NOW;
} else if (command == "updategame") {
options.relaunchCommand = RelaunchCommand::UPDATE_GAME;
} else if (command.startsWith("updateupdater:")) {
} else if (command.startsWith("updateupdater")) {
options.relaunchCommand = RelaunchCommand::UPDATE_UPDATER;
options.updateUpdaterVersion = command.section(':', 1);
if (optionParser.isSet(updaterUrl)) {
options.updateUpdaterUrl = optionParser.value(updaterUrl);
} else {
options.updateUpdaterUrl = "";
}
} else {
argParseError("Invalid --internalcommand option: " + command);
}
Expand Down Expand Up @@ -208,9 +215,9 @@ int main(int argc, char *argv[])
}

SplashController splashController(
options.relaunchCommand, options.updateUpdaterVersion, options.connectUrl, settings);
options.relaunchCommand, options.updateUpdaterUrl, options.connectUrl, settings);
splashController.checkForUpdate();
QmlDownloader downloader(options.ariaLogFilename, options.connectUrl, settings);
QmlDownloader downloader(options.ariaLogFilename, options.connectUrl, splashController, settings);
QQmlApplicationEngine engine;
engine.addImportPath(QLatin1String("qrc:/"));
engine.addImageProvider(QLatin1String("fluidicons"), new IconsImageProvider());
Expand Down
10 changes: 5 additions & 5 deletions osx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ QString archiveName()
return "macos-amd64.zip";
}

QString updaterSystem()
{
return "macos-amd64";
}

QString defaultInstallPath()
{
return QDir::homePath() + "/Games/Unvanquished";
Expand Down Expand Up @@ -163,11 +168,6 @@ bool updateUpdater(const QString& updaterArchive, const QString&)
return true;
}

QString updaterArchiveName()
{
return "UnvUpdaterOSX.zip";
}

std::string getCertStore()
{
return ""; // Not used on OSX.
Expand Down
22 changes: 16 additions & 6 deletions qmldownloader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@
#include "qmldownloader.h"
#include "system.h"

static const QString UPDATER_BASE_URL("https://github.com/Unvanquished/updater/releases/download");

QmlDownloader::QmlDownloader(QString ariaLogFilename, QString connectUrl, Settings& settings) :
QmlDownloader::QmlDownloader(QString ariaLogFilename, QString connectUrl, SplashController& splashController, Settings& settings) :
ariaLogFilename_(ariaLogFilename),
connectUrl_(connectUrl),
splashController_(splashController),
settings_(settings),
downloadSpeed_(0),
uploadSpeed_(0),
Expand All @@ -42,6 +42,14 @@ QmlDownloader::~QmlDownloader()
stopAria();
}

QString QmlDownloader::newsFallbackUrl() const {
return "qrc:/resources/disconnected_posts.json";
}

QString QmlDownloader::newsUrl() const {
return splashController_.newsUrl();
}

int QmlDownloader::downloadSpeed() const {
return downloadSpeed_;
}
Expand Down Expand Up @@ -155,6 +163,9 @@ void QmlDownloader::startUpdate(const QString& selectedInstallPath)
emit fatalMessage("Install dir not writable. Please select another");
return;
}

QString gameUrl = splashController_.gameUrl();
qDebug() << "Using torrent file:" << gameUrl;
// Persist the install path only now that download has been initiated and we know the path is good
emit statusMessage("Installing to " + dir.canonicalPath());
if (settings_.installPath() != selectedInstallPath) {
Expand All @@ -166,7 +177,7 @@ void QmlDownloader::startUpdate(const QString& selectedInstallPath)
setState(DOWNLOADING);
worker_ = new DownloadWorker(ariaLogFilename_);
worker_->setDownloadDirectory(dir.canonicalPath().toStdString());
worker_->addTorrent("https://cdn.unvanquished.net/current.torrent");
worker_->addTorrent(gameUrl.toStdString());
worker_->moveToThread(&thread_);
connect(&thread_, SIGNAL(finished()), worker_, SLOT(deleteLater()));
connect(worker_, SIGNAL(onDownloadEvent(int)), this, SLOT(onDownloadEvent(int)));
Expand Down Expand Up @@ -201,14 +212,13 @@ void QmlDownloader::stopAria()
}
}

void QmlDownloader::startUpdaterUpdate(QString version)
void QmlDownloader::startUpdaterUpdate(QString updaterUrl)
{
QString url = UPDATER_BASE_URL + "/" + version + "/" + Sys::updaterArchiveName();
temp_dir_.reset(new QTemporaryDir());
worker_ = new DownloadWorker(ariaLogFilename_);
worker_->setDownloadDirectory(QDir(temp_dir_->path()).canonicalPath().toStdString());
worker_->setConnectUrl(connectUrl_);
worker_->addUpdaterUri(url.toStdString());
worker_->addUpdaterUri(updaterUrl.toStdString());
worker_->moveToThread(&thread_);
connect(&thread_, SIGNAL(finished()), worker_, SLOT(deleteLater()));
connect(worker_, SIGNAL(onDownloadEvent(int)), this, SLOT(onDownloadEvent(int)));
Expand Down
Loading