mirror of
https://github.com/redstrate/Astra.git
synced 2025-04-20 03:37:47 +00:00
Add better logging
Astra's own logs are now stored in a rotating log, the default message format is improved. The client and DXVK now dump their logs in the same place instead of in the game directory.
This commit is contained in:
parent
2662b0e0bb
commit
c05311fccc
22 changed files with 299 additions and 25 deletions
|
@ -34,6 +34,7 @@ include(ECMPoQmTools)
|
|||
include(KDEGitCommitHooks)
|
||||
include(KDEClangFormat)
|
||||
include(ECMAddTests)
|
||||
include(ECMQtDeclareLoggingCategory)
|
||||
|
||||
ecm_setup_version(${PROJECT_VERSION}
|
||||
VARIABLE_PREFIX ASTRA
|
||||
|
|
|
@ -3,6 +3,30 @@
|
|||
|
||||
add_library(astra_static STATIC)
|
||||
|
||||
ecm_qt_declare_logging_category(astra_static
|
||||
HEADER astra_log.h
|
||||
IDENTIFIER ASTRA_LOG
|
||||
CATEGORY_NAME zone.xiv.astra
|
||||
DESCRIPTION "Astra logs"
|
||||
EXPORT ASTRA
|
||||
)
|
||||
|
||||
ecm_qt_declare_logging_category(astra_static
|
||||
HEADER astra_http_log.h
|
||||
IDENTIFIER ASTRA_HTTP
|
||||
CATEGORY_NAME zone.xiv.astra.http
|
||||
DESCRIPTION "Astra HTTP requests"
|
||||
EXPORT ASTRA
|
||||
)
|
||||
|
||||
ecm_qt_declare_logging_category(astra_static
|
||||
HEADER astra_patcher_log.h
|
||||
IDENTIFIER ASTRA_PATCHER
|
||||
CATEGORY_NAME zone.xiv.astra.patcher
|
||||
DESCRIPTION "Astra patcher"
|
||||
EXPORT ASTRA
|
||||
)
|
||||
|
||||
target_sources(astra_static PRIVATE
|
||||
include/patchlist.h
|
||||
src/patchlist.cpp)
|
||||
|
@ -25,7 +49,9 @@ target_sources(astra PRIVATE
|
|||
include/gameinstaller.h
|
||||
include/headline.h
|
||||
include/launchercore.h
|
||||
include/logger.h
|
||||
include/patcher.h
|
||||
include/processlogger.h
|
||||
include/profile.h
|
||||
include/profilemanager.h
|
||||
include/sapphirelauncher.h
|
||||
|
@ -41,8 +67,10 @@ target_sources(astra PRIVATE
|
|||
src/encryptedarg.cpp
|
||||
src/gameinstaller.cpp
|
||||
src/launchercore.cpp
|
||||
src/logger.cpp
|
||||
src/main.cpp
|
||||
src/patcher.cpp
|
||||
src/processlogger.cpp
|
||||
src/profile.cpp
|
||||
src/profilemanager.cpp
|
||||
src/sapphirelauncher.cpp
|
||||
|
|
6
launcher/include/logger.h
Normal file
6
launcher/include/logger.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
// SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
void initializeLogging();
|
17
launcher/include/processlogger.h
Normal file
17
launcher/include/processlogger.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
// SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QFile>
|
||||
#include <QObject>
|
||||
#include <QProcess>
|
||||
|
||||
class ProcessLogger : public QObject
|
||||
{
|
||||
public:
|
||||
explicit ProcessLogger(QProcess *process);
|
||||
|
||||
private:
|
||||
QFile file;
|
||||
};
|
|
@ -122,6 +122,7 @@ public:
|
|||
void readGameData();
|
||||
Q_INVOKABLE void readGameVersion();
|
||||
void readWineInfo();
|
||||
void readDalamudInfo();
|
||||
|
||||
[[nodiscard]] QString expansionVersionText() const;
|
||||
[[nodiscard]] QString dalamudVersionText() const;
|
||||
|
|
|
@ -4,9 +4,11 @@
|
|||
#pragma once
|
||||
|
||||
#include <QDir>
|
||||
#include <QNetworkRequest>
|
||||
|
||||
namespace Utility
|
||||
{
|
||||
QDir stateDirectory();
|
||||
QString toWindowsPath(const QDir &dir);
|
||||
void printRequest(const QString &type, const QNetworkRequest &request);
|
||||
}
|
|
@ -11,6 +11,7 @@
|
|||
#include <qt6keychain/keychain.h>
|
||||
|
||||
#include "launchercore.h"
|
||||
#include "utility.h"
|
||||
|
||||
Account::Account(LauncherCore &launcher, const QString &key, QObject *parent)
|
||||
: QObject(parent)
|
||||
|
@ -234,11 +235,15 @@ void Account::fetchAvatar()
|
|||
url.setPath(QStringLiteral("/character/%1").arg(lodestoneId()));
|
||||
|
||||
QNetworkRequest request(url);
|
||||
Utility::printRequest(QStringLiteral("GET"), request);
|
||||
|
||||
const auto reply = m_launcher.mgr->get(request);
|
||||
connect(reply, &QNetworkReply::finished, [this, filename, reply] {
|
||||
auto document = QJsonDocument::fromJson(reply->readAll());
|
||||
if (document.isObject()) {
|
||||
const QNetworkRequest avatarRequest(document.object()[QLatin1String("Character")].toObject()[QLatin1String("Avatar")].toString());
|
||||
Utility::printRequest(QStringLiteral("GET"), avatarRequest);
|
||||
|
||||
auto avatarReply = m_launcher.mgr->get(avatarRequest);
|
||||
QObject::connect(avatarReply, &QNetworkReply::finished, [this, filename, avatarReply] {
|
||||
QFile file(filename);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "accountmanager.h"
|
||||
#include "astra_log.h"
|
||||
|
||||
#include <KSharedConfig>
|
||||
|
||||
|
@ -16,7 +17,10 @@ void AccountManager::load()
|
|||
auto config = KSharedConfig::openStateConfig();
|
||||
for (const auto &id : config->groupList()) {
|
||||
if (id.contains(QLatin1String("account-"))) {
|
||||
auto account = new Account(m_launcher, QString(id).remove(QLatin1String("account-")), this);
|
||||
const QString uuid = QString(id).remove(QLatin1String("account-"));
|
||||
qInfo(ASTRA_LOG) << "Loading account" << uuid;
|
||||
|
||||
auto account = new Account(m_launcher, uuid, this);
|
||||
m_accounts.append(account);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "assetupdater.h"
|
||||
#include "utility.h"
|
||||
|
||||
#include <KLocalizedString>
|
||||
#include <QFile>
|
||||
|
@ -56,6 +57,7 @@ QCoro::Task<> AssetUpdater::checkRemoteDalamudAssetVersion()
|
|||
{
|
||||
// first we want to fetch the list of assets required
|
||||
const QNetworkRequest request(dalamudAssetManifestUrl());
|
||||
Utility::printRequest(QStringLiteral("GET"), request);
|
||||
|
||||
const auto reply = launcher.mgr->get(request);
|
||||
co_await reply;
|
||||
|
@ -80,6 +82,7 @@ QCoro::Task<> AssetUpdater::checkRemoteDalamudAssetVersion()
|
|||
QCoro::Task<> AssetUpdater::checkRemoteDalamudVersion()
|
||||
{
|
||||
const QNetworkRequest request(dalamudVersionManifestUrl(m_profile.dalamudChannel()));
|
||||
Utility::printRequest(QStringLiteral("GET"), request);
|
||||
|
||||
remoteDalamudVersion.clear();
|
||||
remoteRuntimeVersion.clear();
|
||||
|
@ -132,6 +135,8 @@ QCoro::Task<> AssetUpdater::installDalamudAssets()
|
|||
|
||||
for (const auto &assetObject : remoteDalamudAssetArray) {
|
||||
const QNetworkRequest assetRequest(assetObject.toObject()[QLatin1String("Url")].toString());
|
||||
Utility::printRequest(QStringLiteral("GET"), assetRequest);
|
||||
|
||||
const auto assetReply = launcher.mgr->get(assetRequest);
|
||||
|
||||
const auto future = QtFuture::connect(assetReply, &QNetworkReply::finished).then([this, assetReply, assetObject] {
|
||||
|
@ -171,6 +176,7 @@ QCoro::Task<> AssetUpdater::installDalamud()
|
|||
Q_EMIT launcher.stageChanged(i18n("Updating Dalamud..."));
|
||||
|
||||
const QNetworkRequest request(dalamudLatestPackageUrl(chosenChannel));
|
||||
Utility::printRequest(QStringLiteral("GET"), request);
|
||||
|
||||
const auto reply = launcher.mgr->get(request);
|
||||
co_await reply;
|
||||
|
@ -200,6 +206,7 @@ QCoro::Task<> AssetUpdater::installRuntime()
|
|||
// core
|
||||
{
|
||||
const QNetworkRequest request(dotnetRuntimePackageURL.arg(remoteRuntimeVersion));
|
||||
Utility::printRequest(QStringLiteral("GET"), request);
|
||||
|
||||
const auto reply = launcher.mgr->get(request);
|
||||
co_await reply;
|
||||
|
@ -215,6 +222,7 @@ QCoro::Task<> AssetUpdater::installRuntime()
|
|||
// desktop
|
||||
{
|
||||
const QNetworkRequest request(dotnetDesktopPackageURL.arg(remoteRuntimeVersion));
|
||||
Utility::printRequest(QStringLiteral("GET"), request);
|
||||
|
||||
const auto reply = launcher.mgr->get(request);
|
||||
co_await reply;
|
||||
|
|
|
@ -9,8 +9,10 @@
|
|||
#include <QStandardPaths>
|
||||
#include <physis.hpp>
|
||||
|
||||
#include "astra_log.h"
|
||||
#include "launchercore.h"
|
||||
#include "profile.h"
|
||||
#include "utility.h"
|
||||
|
||||
const QString installerUrl = QStringLiteral("https://download.finalfantasyxiv.com/inst/ffxivsetup.exe");
|
||||
const QByteArray installerSha256 = QByteArray::fromHex("cf70bfaaf4f429794358ef84acbcbdc4193bee109fa1b6aea81bd4de038e500e");
|
||||
|
@ -29,6 +31,8 @@ void GameInstaller::installGame()
|
|||
QNetworkRequest request((QUrl(installerUrl)));
|
||||
|
||||
auto reply = m_launcher.mgr->get(request);
|
||||
Utility::printRequest(QStringLiteral("GET"), request);
|
||||
|
||||
QObject::connect(reply, &QNetworkReply::finished, [this, reply, installDirectory] {
|
||||
if (reply->error() != QNetworkReply::NetworkError::NoError) {
|
||||
Q_EMIT error(i18n("An error has occurred when downloading the installer.\n\n%1", reply->errorString()));
|
||||
|
@ -55,5 +59,6 @@ void GameInstaller::installGame()
|
|||
physis_install_game(fileNameStd.c_str(), installDirectoryStd.c_str());
|
||||
|
||||
Q_EMIT installFinished();
|
||||
qInfo(ASTRA_LOG) << "Installed game in" << installDirectory;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -18,10 +18,12 @@
|
|||
|
||||
#include "account.h"
|
||||
#include "assetupdater.h"
|
||||
#include "astra_log.h"
|
||||
#include "compatibilitytoolinstaller.h"
|
||||
#include "config.h"
|
||||
#include "encryptedarg.h"
|
||||
#include "launchercore.h"
|
||||
#include "processlogger.h"
|
||||
#include "sapphirelauncher.h"
|
||||
#include "squarelauncher.h"
|
||||
#include "utility.h"
|
||||
|
@ -74,8 +76,6 @@ void LauncherCore::launchGame(Profile &profile, const LoginAuth &auth)
|
|||
|
||||
QCoro::Task<> LauncherCore::beginLogin(LoginInformation &info)
|
||||
{
|
||||
qDebug() << "Logging in, performing asset update check.";
|
||||
|
||||
auto assetUpdater = new AssetUpdater(*info.profile, *this, this);
|
||||
co_await assetUpdater->update();
|
||||
|
||||
|
@ -122,6 +122,8 @@ void LauncherCore::beginVanillaGame(const QString &gameExecutablePath, Profile &
|
|||
|
||||
auto args = getGameArgs(profile, auth);
|
||||
|
||||
new ProcessLogger(gameProcess);
|
||||
|
||||
launchExecutable(profile, gameProcess, {gameExecutablePath, args}, true, true);
|
||||
}
|
||||
|
||||
|
@ -144,7 +146,7 @@ void LauncherCore::beginDalamudGame(const QString &gameExecutablePath, Profile &
|
|||
// so we need to match typical XIVQuickLauncher behavior here. Why? I have no clue.
|
||||
const QDir dalamudPluginDir = dalamudUserPluginDir.absoluteFilePath(QStringLiteral("installedPlugins"));
|
||||
|
||||
const QString logDir = stateDir.absoluteFilePath(QStringLiteral("logs"));
|
||||
const QString logDir = stateDir.absoluteFilePath(QStringLiteral("log"));
|
||||
|
||||
if (!QDir().exists(logDir))
|
||||
QDir().mkpath(logDir);
|
||||
|
@ -171,6 +173,8 @@ void LauncherCore::beginDalamudGame(const QString &gameExecutablePath, Profile &
|
|||
#endif
|
||||
dalamudProcess->setProcessEnvironment(env);
|
||||
|
||||
new ProcessLogger(dalamudProcess);
|
||||
|
||||
const auto args = getGameArgs(profile, auth);
|
||||
|
||||
launchExecutable(profile,
|
||||
|
@ -286,6 +290,10 @@ void LauncherCore::launchExecutable(const Profile &profile, QProcess *process, c
|
|||
env.insert(QStringLiteral("WINEFSYNC"), QString::number(1));
|
||||
env.insert(QStringLiteral("WINEFSYNC_FUTEX2"), QString::number(1));
|
||||
}
|
||||
|
||||
const QString logDir = Utility::stateDirectory().absoluteFilePath(QStringLiteral("log"));
|
||||
|
||||
env.insert(QStringLiteral("DXVK_LOG_PATH"), logDir);
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_MAC) || defined(Q_OS_LINUX)
|
||||
|
@ -371,7 +379,6 @@ void LauncherCore::launchExecutable(const Profile &profile, QProcess *process, c
|
|||
process->setWorkingDirectory(profile.gamePath() + QStringLiteral("/game/"));
|
||||
|
||||
process->setProcessEnvironment(env);
|
||||
process->setProcessChannelMode(QProcess::ProcessChannelMode::ForwardedChannels);
|
||||
|
||||
process->start(executable, arguments);
|
||||
}
|
||||
|
@ -457,13 +464,13 @@ bool LauncherCore::autoLogin(Profile *profile)
|
|||
QString otp;
|
||||
if (profile->account()->useOTP()) {
|
||||
if (!profile->account()->rememberOTP()) {
|
||||
Q_EMIT loginError("This account does not have an OTP secret set, but requires it for login.");
|
||||
Q_EMIT loginError(i18n("This account does not have an OTP secret set, but requires it for login."));
|
||||
return false;
|
||||
}
|
||||
|
||||
otp = profile->account()->getOTP();
|
||||
if (otp.isEmpty()) {
|
||||
Q_EMIT loginError("Failed to generate OTP, review the stored secret.");
|
||||
Q_EMIT loginError(i18n("Failed to generate OTP, review the stored secret."));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -681,6 +688,8 @@ void LauncherCore::refreshNews()
|
|||
|
||||
QCoro::Task<> LauncherCore::fetchNews()
|
||||
{
|
||||
qInfo(ASTRA_LOG) << "Fetching news...";
|
||||
|
||||
QUrlQuery query;
|
||||
query.addQueryItem(QStringLiteral("lang"), QStringLiteral("en-us"));
|
||||
query.addQueryItem(QStringLiteral("media"), QStringLiteral("pcapp"));
|
||||
|
@ -698,6 +707,7 @@ QCoro::Task<> LauncherCore::fetchNews()
|
|||
QStringLiteral("https://launcher.finalfantasyxiv.com/v600/index.html?rc_lang=%1&time=%2")
|
||||
.arg("en-us", QDateTime::currentDateTimeUtc().toString("yyyy-MM-dd-HH"))
|
||||
.toUtf8());
|
||||
Utility::printRequest(QStringLiteral("GET"), request);
|
||||
|
||||
auto reply = mgr->get(request);
|
||||
co_await reply;
|
||||
|
@ -790,7 +800,6 @@ void LauncherCore::setCurrentProfile(Profile *profile)
|
|||
void LauncherCore::clearAvatarCache()
|
||||
{
|
||||
const auto cacheLocation = QStandardPaths::standardLocations(QStandardPaths::CacheLocation)[0] + QStringLiteral("/avatars");
|
||||
qInfo() << cacheLocation;
|
||||
if (QDir(cacheLocation).exists()) {
|
||||
QDir(cacheLocation).removeRecursively();
|
||||
}
|
||||
|
|
114
launcher/src/logger.cpp
Normal file
114
launcher/src/logger.cpp
Normal file
|
@ -0,0 +1,114 @@
|
|||
// SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "logger.h"
|
||||
#include "utility.h"
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QMutexLocker>
|
||||
#include <QStandardPaths>
|
||||
#include <QtLogging>
|
||||
#include <iostream>
|
||||
|
||||
class Logger
|
||||
{
|
||||
public:
|
||||
void log(const QtMsgType type, const QMessageLogContext &context, const QString &message)
|
||||
{
|
||||
const QString formattedMsg = qFormatLogMessage(type, context, message);
|
||||
|
||||
if (file.isOpen()) {
|
||||
QMutexLocker locker(&mutex);
|
||||
QByteArray buf;
|
||||
QTextStream str(&buf);
|
||||
|
||||
str << formattedMsg << QStringLiteral("\n");
|
||||
str.flush();
|
||||
file.write(buf.constData(), buf.size());
|
||||
file.flush();
|
||||
}
|
||||
|
||||
std::cout << formattedMsg.toStdString() << std::endl;
|
||||
}
|
||||
|
||||
void initialize()
|
||||
{
|
||||
const QString filename{QStringLiteral("astra.log")};
|
||||
|
||||
const QDir logDirectory = Utility::stateDirectory().absoluteFilePath("log");
|
||||
|
||||
if (!logDirectory.exists()) {
|
||||
QDir().mkpath(logDirectory.absolutePath());
|
||||
}
|
||||
|
||||
// Sort them from highest to lowest (4, 3, 2, 1, 0)
|
||||
auto existingLogEntries = logDirectory.entryList({filename + QStringLiteral(".*")});
|
||||
std::sort(existingLogEntries.begin(), existingLogEntries.end(), [](const auto &left, const auto &right) {
|
||||
auto leftIndex = left.split(QStringLiteral(".")).last().toInt();
|
||||
auto rightIndex = right.split(QStringLiteral(".")).last().toInt();
|
||||
return leftIndex > rightIndex;
|
||||
});
|
||||
|
||||
// Iterate through the existing logs, prune them and move the oldest up
|
||||
for (const auto &entry : existingLogEntries) {
|
||||
bool valid = false;
|
||||
const auto index = entry.split(QStringLiteral(".")).last().toInt(&valid);
|
||||
if (!valid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const QString entryFullPath = logDirectory.absoluteFilePath(entry);
|
||||
const QFileInfo info(entryFullPath);
|
||||
if (info.exists()) {
|
||||
QFile existingFile(entryFullPath);
|
||||
if (index > 3) {
|
||||
existingFile.remove();
|
||||
continue;
|
||||
}
|
||||
const auto &newName = logDirectory.absoluteFilePath(QStringLiteral("%1.%2").arg(filename, QString::number(index + 1)));
|
||||
const auto success = existingFile.copy(newName);
|
||||
if (success) {
|
||||
existingFile.remove();
|
||||
} else {
|
||||
qFatal("Cannot move log file '%s' to '%s': %s",
|
||||
qUtf8Printable(existingFile.fileName()),
|
||||
qUtf8Printable(newName),
|
||||
qUtf8Printable(existingFile.errorString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
file.setFileName(logDirectory.absoluteFilePath(filename + QStringLiteral(".0")));
|
||||
file.open(QIODevice::WriteOnly | QIODevice::Unbuffered);
|
||||
}
|
||||
|
||||
private:
|
||||
QMutex mutex;
|
||||
QFile file;
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(Logger, logger)
|
||||
|
||||
void handler(QtMsgType type, const QMessageLogContext &context, const QString &message)
|
||||
{
|
||||
switch (type) {
|
||||
case QtDebugMsg:
|
||||
case QtInfoMsg:
|
||||
case QtWarningMsg:
|
||||
case QtCriticalMsg:
|
||||
logger()->log(type, context, message);
|
||||
break;
|
||||
case QtFatalMsg:
|
||||
logger()->log(QtCriticalMsg, context, message);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void initializeLogging()
|
||||
{
|
||||
logger()->initialize();
|
||||
qInstallMessageHandler(handler);
|
||||
}
|
|
@ -15,10 +15,13 @@
|
|||
#include "compatibilitytoolinstaller.h"
|
||||
#include "gameinstaller.h"
|
||||
#include "launchercore.h"
|
||||
#include "logger.h"
|
||||
#include "sapphirelauncher.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
initializeLogging();
|
||||
|
||||
QtWebView::initialize();
|
||||
|
||||
QApplication app(argc, argv);
|
||||
|
@ -28,6 +31,11 @@ int main(int argc, char *argv[])
|
|||
QQuickStyle::setStyle(QStringLiteral("org.kde.desktop"));
|
||||
}
|
||||
|
||||
// Default to a sensible message pattern
|
||||
if (qEnvironmentVariableIsEmpty("QT_MESSAGE_PATTERN")) {
|
||||
qputenv("QT_MESSAGE_PATTERN", "[%{time yyyy-MM-dd h:mm:ss.zzz}] %{if-category}[%{category}] %{endif}[%{type}] %{message}");
|
||||
}
|
||||
|
||||
KLocalizedString::setApplicationDomain("astra");
|
||||
|
||||
KAboutData about(QStringLiteral("astra"),
|
||||
|
@ -47,7 +55,11 @@ int main(int argc, char *argv[])
|
|||
physis_get_physis_version(),
|
||||
QStringLiteral("https://xiv.zone/physis"),
|
||||
KAboutLicense::GPL_V3);
|
||||
about.addComponent(QStringLiteral("libphysis"), QStringLiteral("C bindings for physis"), physis_get_libphysis_version(), {}, KAboutLicense::GPL_V3);
|
||||
about.addComponent(QStringLiteral("libphysis"),
|
||||
QStringLiteral("C bindings for physis"),
|
||||
physis_get_libphysis_version(),
|
||||
QStringLiteral("https://git.sr.ht/~redstrate/libphysis"),
|
||||
KAboutLicense::GPL_V3);
|
||||
about.setDesktopFileName(QStringLiteral("zone.xiv.astra"));
|
||||
about.setBugAddress(QByteArrayLiteral("https://lists.sr.ht/~redstrate/public-inbox"));
|
||||
about.setComponentName(QStringLiteral("astra"));
|
||||
|
@ -58,11 +70,9 @@ int main(int argc, char *argv[])
|
|||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription(i18n("Linux FFXIV Launcher"));
|
||||
|
||||
#ifdef ENABLE_STEAM
|
||||
QCommandLineOption steamOption(QStringLiteral("steam"), QStringLiteral("Used for booting the launcher from Steam."), QStringLiteral("verb"));
|
||||
steamOption.setFlags(QCommandLineOption::HiddenFromHelp);
|
||||
parser.addOption(steamOption);
|
||||
#endif
|
||||
|
||||
about.setupCommandLine(&parser);
|
||||
parser.parse(QCoreApplication::arguments());
|
||||
|
|
|
@ -13,8 +13,10 @@
|
|||
#include <physis.hpp>
|
||||
#include <qcorofuture.h>
|
||||
|
||||
#include "astra_patcher_log.h"
|
||||
#include "launchercore.h"
|
||||
#include "patchlist.h"
|
||||
#include "utility.h"
|
||||
|
||||
Patcher::Patcher(LauncherCore &launcher, const QString &baseDirectory, BootData &bootData, QObject *parent)
|
||||
: QObject(parent)
|
||||
|
@ -67,19 +69,22 @@ QCoro::Task<bool> Patcher::patch(const PatchList &patchList)
|
|||
|
||||
const QueuedPatch queuedPatch{patch.name, patch.repository, patch.version, patchPath, patch.hashes, patch.hashBlockSize, patch.length, isBoot()};
|
||||
|
||||
qDebug() << "Adding a queued patch:";
|
||||
qDebug() << "- Name:" << patch.name;
|
||||
qDebug() << "- Repository or is boot:" << (isBoot() ? QStringLiteral("boot") : patch.repository);
|
||||
qDebug() << "- Version:" << patch.version;
|
||||
qDebug() << "- Downloaded Path:" << patchPath;
|
||||
qDebug() << "- Hashes:" << patch.hashes;
|
||||
qDebug() << "- Hash Block Size:" << patch.hashBlockSize;
|
||||
qDebug() << "- Length:" << patch.length;
|
||||
qDebug(ASTRA_PATCHER) << "Adding a queued patch:";
|
||||
qDebug(ASTRA_PATCHER) << "- Name:" << patch.name;
|
||||
qDebug(ASTRA_PATCHER) << "- Repository or is boot:" << (isBoot() ? QStringLiteral("boot") : patch.repository);
|
||||
qDebug(ASTRA_PATCHER) << "- Version:" << patch.version;
|
||||
qDebug(ASTRA_PATCHER) << "- Downloaded Path:" << patchPath;
|
||||
qDebug(ASTRA_PATCHER) << "- Hashes:" << patch.hashes;
|
||||
qDebug(ASTRA_PATCHER) << "- Hash Block Size:" << patch.hashBlockSize;
|
||||
qDebug(ASTRA_PATCHER) << "- Length:" << patch.length;
|
||||
|
||||
m_patchQueue[ourIndex] = queuedPatch;
|
||||
|
||||
if (!QFile::exists(patchPath)) {
|
||||
auto patchReply = m_launcher.mgr->get(QNetworkRequest(patch.url));
|
||||
const auto patchRequest = QNetworkRequest(patch.url);
|
||||
Utility::printRequest(QStringLiteral("GET"), patchRequest);
|
||||
|
||||
auto patchReply = m_launcher.mgr->get(patchRequest);
|
||||
|
||||
connect(patchReply, &QNetworkReply::downloadProgress, this, [this, queuedPatch](int received, int total) {
|
||||
Q_EMIT m_launcher.stageChanged(i18n("Updating %1.\nDownloading %2", getBaseString(), queuedPatch.getVersion()));
|
||||
|
@ -93,7 +98,7 @@ QCoro::Task<bool> Patcher::patch(const PatchList &patchList)
|
|||
file.close();
|
||||
}));
|
||||
} else {
|
||||
qDebug() << "Found existing patch: " << patch.name;
|
||||
qDebug(ASTRA_PATCHER) << "Found existing patch: " << patch.name;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -147,7 +152,7 @@ void Patcher::processPatch(const QueuedPatch &patch)
|
|||
physis_gamedata_apply_patch(m_gameData, patch.path.toStdString().c_str());
|
||||
}
|
||||
|
||||
qDebug() << "Installed" << patch.path << "to" << (isBoot() ? QStringLiteral("boot") : patch.repository);
|
||||
qDebug(ASTRA_PATCHER) << "Installed" << patch.path << "to" << (isBoot() ? QStringLiteral("boot") : patch.repository);
|
||||
|
||||
QString verFilePath;
|
||||
if (isBoot()) {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "patchlist.h"
|
||||
#include "astra_patcher_log.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
|
@ -32,7 +33,7 @@ PatchList::PatchList(const QString &patchList)
|
|||
"PatchList",
|
||||
"Patch parsing failed, we were given an non-empty patchlist body but nothing were parsed.");
|
||||
|
||||
qDebug() << "Finished parsing patch list. Num patches:" << m_patches.size();
|
||||
qDebug(ASTRA_PATCHER) << "Finished parsing patch list. # of patches:" << m_patches.size();
|
||||
}
|
||||
|
||||
QVector<Patch> PatchList::patches() const
|
||||
|
|
30
launcher/src/processlogger.cpp
Normal file
30
launcher/src/processlogger.cpp
Normal file
|
@ -0,0 +1,30 @@
|
|||
// SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "processlogger.h"
|
||||
#include "astra_log.h"
|
||||
#include "utility.h"
|
||||
|
||||
ProcessLogger::ProcessLogger(QProcess *process)
|
||||
{
|
||||
const QDir logDirectory = Utility::stateDirectory().absoluteFilePath("log");
|
||||
|
||||
file.setFileName(logDirectory.absoluteFilePath(QStringLiteral("ffxiv.log")));
|
||||
file.open(QIODevice::WriteOnly | QIODevice::Unbuffered);
|
||||
|
||||
connect(process, &QProcess::readyReadStandardOutput, this, [this, process] {
|
||||
file.write(process->readAllStandardOutput());
|
||||
file.flush();
|
||||
});
|
||||
|
||||
connect(process, &QProcess::readyReadStandardError, this, [this, process] {
|
||||
file.write(process->readAllStandardError());
|
||||
file.flush();
|
||||
});
|
||||
|
||||
connect(process, &QProcess::finished, this, [this] {
|
||||
deleteLater();
|
||||
});
|
||||
|
||||
qInfo(ASTRA_LOG) << "Client logs are being written to" << file.fileName().toUtf8().constData();
|
||||
}
|
|
@ -9,6 +9,7 @@
|
|||
#include <QProcess>
|
||||
|
||||
#include "account.h"
|
||||
#include "astra_log.h"
|
||||
#include "launchercore.h"
|
||||
#include "profileconfig.h"
|
||||
|
||||
|
@ -44,6 +45,7 @@ Profile::Profile(LauncherCore &launcher, const QString &key, QObject *parent)
|
|||
}
|
||||
|
||||
m_dalamudVersion = versionString.remove(QLatin1String("Dalamud/"));
|
||||
qInfo(ASTRA_LOG) << "Dalamud version:" << m_dalamudVersion;
|
||||
}
|
||||
|
||||
const QString dalamudAssetsVer = dalamudAssetsDir.absoluteFilePath(QStringLiteral("asset.ver"));
|
||||
|
@ -52,6 +54,7 @@ Profile::Profile(LauncherCore &launcher, const QString &key, QObject *parent)
|
|||
assetJson.open(QFile::ReadOnly | QFile::Text);
|
||||
|
||||
m_dalamudAssetVersion = QString(assetJson.readAll()).toInt();
|
||||
qInfo(ASTRA_LOG) << "Dalamud asset version:" << m_dalamudVersion;
|
||||
}
|
||||
|
||||
const QString dalamudRuntimeVer = dalamudRuntimeDir.absoluteFilePath(QStringLiteral("runtime.ver"));
|
||||
|
@ -60,6 +63,7 @@ Profile::Profile(LauncherCore &launcher, const QString &key, QObject *parent)
|
|||
runtimeVer.open(QFile::ReadOnly | QFile::Text);
|
||||
|
||||
m_runtimeVersion = QString(runtimeVer.readAll());
|
||||
qInfo(ASTRA_LOG) << "Dalamud runtime version:" << m_dalamudVersion;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "profilemanager.h"
|
||||
#include "astra_log.h"
|
||||
|
||||
#include <KSharedConfig>
|
||||
#include <QDir>
|
||||
|
@ -101,8 +102,9 @@ void ProfileManager::load()
|
|||
auto config = KSharedConfig::openStateConfig();
|
||||
for (const auto &id : config->groupList()) {
|
||||
if (id.contains(QLatin1String("profile-"))) {
|
||||
qInfo() << "Adding profile" << id;
|
||||
auto profile = new Profile(m_launcher, QString(id).remove(QLatin1String("profile-")), this);
|
||||
const QString uuid = QString(id).remove(QLatin1String("profile-"));
|
||||
qInfo(ASTRA_LOG) << "Loading profile" << uuid;
|
||||
auto profile = new Profile(m_launcher, uuid, this);
|
||||
insertProfile(profile);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "sapphirelauncher.h"
|
||||
#include "utility.h"
|
||||
|
||||
#include <KLocalizedString>
|
||||
#include <QJsonDocument>
|
||||
|
@ -22,8 +23,10 @@ void SapphireLauncher::login(const QString &lobbyUrl, const LoginInformation &in
|
|||
|
||||
QNetworkRequest request(url);
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, QByteArrayLiteral("application/x-www-form-urlencoded"));
|
||||
Utility::printRequest(QStringLiteral("POST"), request);
|
||||
|
||||
const auto reply = window.mgr->post(request, QJsonDocument(data).toJson(QJsonDocument::JsonFormat::Compact));
|
||||
|
||||
connect(reply, &QNetworkReply::finished, [this, reply, &info] {
|
||||
if (reply->error() != QNetworkReply::NetworkError::NoError) {
|
||||
Q_EMIT window.loginError(i18n("Could not contact lobby server.\n\n%1", reply->errorString()));
|
||||
|
@ -53,6 +56,8 @@ void SapphireLauncher::registerAccount(const QString &lobbyUrl, const LoginInfor
|
|||
QNetworkRequest request(url);
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, QByteArrayLiteral("application/x-www-form-urlencoded"));
|
||||
|
||||
Utility::printRequest(QStringLiteral("POST"), request);
|
||||
|
||||
const auto reply = window.mgr->post(request, QJsonDocument(data).toJson(QJsonDocument::JsonFormat::Compact));
|
||||
connect(reply, &QNetworkReply::finished, [&] {
|
||||
const QJsonDocument document = QJsonDocument::fromJson(reply->readAll());
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "account.h"
|
||||
#include "squarelauncher.h"
|
||||
#include "utility.h"
|
||||
|
||||
SquareBoot::SquareBoot(LauncherCore &window, SquareLauncher &launcher, QObject *parent)
|
||||
: QObject(parent)
|
||||
|
@ -43,6 +44,7 @@ QCoro::Task<> SquareBoot::bootCheck(const LoginInformation &info)
|
|||
}
|
||||
|
||||
request.setRawHeader(QByteArrayLiteral("Host"), QStringLiteral("patch-bootver.%1").arg(window.squareEnixServer()).toUtf8());
|
||||
Utility::printRequest(QStringLiteral("GET"), request);
|
||||
|
||||
const auto reply = window.mgr->get(request);
|
||||
co_await reply;
|
||||
|
@ -77,6 +79,8 @@ QCoro::Task<> SquareBoot::checkGateStatus(const LoginInformation &info)
|
|||
// TODO: really?
|
||||
window.buildRequest(*info.profile, request);
|
||||
|
||||
Utility::printRequest(QStringLiteral("GET"), request);
|
||||
|
||||
const auto reply = window.mgr->get(request);
|
||||
window.setupIgnoreSSL(reply);
|
||||
co_await reply;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include "account.h"
|
||||
#include "launchercore.h"
|
||||
#include "utility.h"
|
||||
|
||||
SquareLauncher::SquareLauncher(LauncherCore &window, QObject *parent)
|
||||
: QObject(parent)
|
||||
|
@ -65,6 +66,8 @@ QCoro::Task<std::optional<SquareLauncher::StoredInfo>> SquareLauncher::getStored
|
|||
auto request = QNetworkRequest(url);
|
||||
window.buildRequest(*info.profile, request);
|
||||
|
||||
Utility::printRequest(QStringLiteral("GET"), request);
|
||||
|
||||
const auto reply = window.mgr->get(request);
|
||||
co_await reply;
|
||||
|
||||
|
@ -123,6 +126,8 @@ QCoro::Task<> SquareLauncher::login(const LoginInformation &info)
|
|||
request.setRawHeader(QByteArrayLiteral("Referer"), referer.toEncoded());
|
||||
request.setRawHeader(QByteArrayLiteral("Cache-Control"), QByteArrayLiteral("no-cache"));
|
||||
|
||||
Utility::printRequest(QStringLiteral("POST"), request);
|
||||
|
||||
const auto reply = window.mgr->post(request, postData.toString(QUrl::FullyEncoded).toUtf8());
|
||||
window.setupIgnoreSSL(reply);
|
||||
co_await reply;
|
||||
|
@ -183,6 +188,8 @@ QCoro::Task<> SquareLauncher::registerSession(const LoginInformation &info)
|
|||
}
|
||||
}
|
||||
|
||||
Utility::printRequest(QStringLiteral("POST"), request);
|
||||
|
||||
const auto reply = window.mgr->post(request, report.toUtf8());
|
||||
co_await reply;
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "utility.h"
|
||||
#include "astra_http_log.h"
|
||||
|
||||
#include <QStandardPaths>
|
||||
|
||||
|
@ -21,3 +22,8 @@ QString Utility::toWindowsPath(const QDir &dir)
|
|||
{
|
||||
return QStringLiteral("Z:") + dir.absolutePath().replace(QLatin1Char('/'), QLatin1Char('\\'));
|
||||
}
|
||||
|
||||
void Utility::printRequest(const QString &type, const QNetworkRequest &request)
|
||||
{
|
||||
qDebug(ASTRA_HTTP) << type.toUtf8().constData() << request.url().toDisplayString();
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue