diff --git a/CMakeLists.txt b/CMakeLists.txt index ebb0eef..b71b105 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,7 @@ include(ECMPoQmTools) include(KDEGitCommitHooks) include(KDEClangFormat) include(ECMAddTests) +include(ECMQtDeclareLoggingCategory) ecm_setup_version(${PROJECT_VERSION} VARIABLE_PREFIX ASTRA diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 2b88110..8b34ca4 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -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 diff --git a/launcher/include/logger.h b/launcher/include/logger.h new file mode 100644 index 0000000..d27b078 --- /dev/null +++ b/launcher/include/logger.h @@ -0,0 +1,6 @@ +// SPDX-FileCopyrightText: 2023 Joshua Goins +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +void initializeLogging(); \ No newline at end of file diff --git a/launcher/include/processlogger.h b/launcher/include/processlogger.h new file mode 100644 index 0000000..113a4ba --- /dev/null +++ b/launcher/include/processlogger.h @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: 2023 Joshua Goins +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include +#include +#include + +class ProcessLogger : public QObject +{ +public: + explicit ProcessLogger(QProcess *process); + +private: + QFile file; +}; \ No newline at end of file diff --git a/launcher/include/profile.h b/launcher/include/profile.h index 51667f4..8c9d767 100644 --- a/launcher/include/profile.h +++ b/launcher/include/profile.h @@ -122,6 +122,7 @@ public: void readGameData(); Q_INVOKABLE void readGameVersion(); void readWineInfo(); + void readDalamudInfo(); [[nodiscard]] QString expansionVersionText() const; [[nodiscard]] QString dalamudVersionText() const; diff --git a/launcher/include/utility.h b/launcher/include/utility.h index 511a160..dcc86b7 100644 --- a/launcher/include/utility.h +++ b/launcher/include/utility.h @@ -4,9 +4,11 @@ #pragma once #include +#include namespace Utility { QDir stateDirectory(); QString toWindowsPath(const QDir &dir); +void printRequest(const QString &type, const QNetworkRequest &request); } \ No newline at end of file diff --git a/launcher/src/account.cpp b/launcher/src/account.cpp index 2320e9f..c622ecf 100644 --- a/launcher/src/account.cpp +++ b/launcher/src/account.cpp @@ -11,6 +11,7 @@ #include #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); diff --git a/launcher/src/accountmanager.cpp b/launcher/src/accountmanager.cpp index 37f28ef..fa7d160 100644 --- a/launcher/src/accountmanager.cpp +++ b/launcher/src/accountmanager.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "accountmanager.h" +#include "astra_log.h" #include @@ -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); } } diff --git a/launcher/src/assetupdater.cpp b/launcher/src/assetupdater.cpp index 8a9d9df..89fd756 100644 --- a/launcher/src/assetupdater.cpp +++ b/launcher/src/assetupdater.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "assetupdater.h" +#include "utility.h" #include #include @@ -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; diff --git a/launcher/src/gameinstaller.cpp b/launcher/src/gameinstaller.cpp index 21d64aa..ef8b723 100644 --- a/launcher/src/gameinstaller.cpp +++ b/launcher/src/gameinstaller.cpp @@ -9,8 +9,10 @@ #include #include +#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; }); } diff --git a/launcher/src/launchercore.cpp b/launcher/src/launchercore.cpp index 889346f..31b50c6 100755 --- a/launcher/src/launchercore.cpp +++ b/launcher/src/launchercore.cpp @@ -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(); } diff --git a/launcher/src/logger.cpp b/launcher/src/logger.cpp new file mode 100644 index 0000000..2f60179 --- /dev/null +++ b/launcher/src/logger.cpp @@ -0,0 +1,114 @@ +// SPDX-FileCopyrightText: 2023 Joshua Goins +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "logger.h" +#include "utility.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +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); +} \ No newline at end of file diff --git a/launcher/src/main.cpp b/launcher/src/main.cpp index bb861e1..f873831 100755 --- a/launcher/src/main.cpp +++ b/launcher/src/main.cpp @@ -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()); diff --git a/launcher/src/patcher.cpp b/launcher/src/patcher.cpp index 9f30a02..aa587f6 100644 --- a/launcher/src/patcher.cpp +++ b/launcher/src/patcher.cpp @@ -13,8 +13,10 @@ #include #include +#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 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 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()) { diff --git a/launcher/src/patchlist.cpp b/launcher/src/patchlist.cpp index 0be7b45..7947a7f 100644 --- a/launcher/src/patchlist.cpp +++ b/launcher/src/patchlist.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "patchlist.h" +#include "astra_patcher_log.h" #include @@ -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 PatchList::patches() const diff --git a/launcher/src/processlogger.cpp b/launcher/src/processlogger.cpp new file mode 100644 index 0000000..5a29bf9 --- /dev/null +++ b/launcher/src/processlogger.cpp @@ -0,0 +1,30 @@ +// SPDX-FileCopyrightText: 2023 Joshua Goins +// 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(); +} diff --git a/launcher/src/profile.cpp b/launcher/src/profile.cpp index 06400e5..1f841bd 100644 --- a/launcher/src/profile.cpp +++ b/launcher/src/profile.cpp @@ -9,6 +9,7 @@ #include #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; } } } diff --git a/launcher/src/profilemanager.cpp b/launcher/src/profilemanager.cpp index b6be493..ea43bc4 100644 --- a/launcher/src/profilemanager.cpp +++ b/launcher/src/profilemanager.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "profilemanager.h" +#include "astra_log.h" #include #include @@ -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); } } diff --git a/launcher/src/sapphirelauncher.cpp b/launcher/src/sapphirelauncher.cpp index 8592f74..c02efc7 100644 --- a/launcher/src/sapphirelauncher.cpp +++ b/launcher/src/sapphirelauncher.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "sapphirelauncher.h" +#include "utility.h" #include #include @@ -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()); diff --git a/launcher/src/squareboot.cpp b/launcher/src/squareboot.cpp index 28d2f39..7dd0420 100644 --- a/launcher/src/squareboot.cpp +++ b/launcher/src/squareboot.cpp @@ -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; diff --git a/launcher/src/squarelauncher.cpp b/launcher/src/squarelauncher.cpp index 7a669fa..a4d4b78 100644 --- a/launcher/src/squarelauncher.cpp +++ b/launcher/src/squarelauncher.cpp @@ -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> 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; diff --git a/launcher/src/utility.cpp b/launcher/src/utility.cpp index 7cd0598..138441d 100644 --- a/launcher/src/utility.cpp +++ b/launcher/src/utility.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "utility.h" +#include "astra_http_log.h" #include @@ -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(); +}