diff options
| author | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 18:51:45 +0300 |
|---|---|---|
| committer | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 18:51:45 +0300 |
| commit | d3261e64152397db2dca4d691a990c6bc2a6f4dd (patch) | |
| tree | fac2f7be638651181a72453d714f0f96675c2b8b /archived/projt-launcher/launcher/java/services/RuntimeProbeTask.cpp | |
| parent | 31b9a8949ed0a288143e23bf739f2eb64fdc63be (diff) | |
| download | Project-Tick-d3261e64152397db2dca4d691a990c6bc2a6f4dd.tar.gz Project-Tick-d3261e64152397db2dca4d691a990c6bc2a6f4dd.zip | |
NOISSUE add archived projects
Signed-off-by: Mehmet Samet Duman <yongdohyun@projecttick.org>
Diffstat (limited to 'archived/projt-launcher/launcher/java/services/RuntimeProbeTask.cpp')
| -rw-r--r-- | archived/projt-launcher/launcher/java/services/RuntimeProbeTask.cpp | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/archived/projt-launcher/launcher/java/services/RuntimeProbeTask.cpp b/archived/projt-launcher/launcher/java/services/RuntimeProbeTask.cpp new file mode 100644 index 0000000000..b13b8d7ece --- /dev/null +++ b/archived/projt-launcher/launcher/java/services/RuntimeProbeTask.cpp @@ -0,0 +1,297 @@ +// SPDX-License-Identifier: GPL-3.0-only +// SPDX-FileCopyrightText: 2026 Project Tick +// SPDX-FileContributor: Project Tick Team +/* + * ProjT Launcher - Minecraft Launcher + * Copyright (C) 2026 Project Tick + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "java/services/RuntimeProbeTask.hpp" + +#include <QDebug> +#include <QFile> +#include <QFileInfo> +#include <QMap> +#include <utility> + +#include "Application.h" +#include "Commandline.h" +#include "FileSystem.h" +#include "java/services/RuntimeEnvironment.hpp" + +namespace projt::java +{ + RuntimeProbeTask::RuntimeProbeTask(ProbeSettings settings) : Task(), m_settings(std::move(settings)) + {} + + QString RuntimeProbeTask::probeJarPath() + { + return APPLICATION->getJarPath("JavaCheck.jar"); + } + + void RuntimeProbeTask::executeTask() + { + QString checkerJar = probeJarPath(); + + if (checkerJar.isEmpty()) + { + qDebug() << "Java checker library could not be found. Please check your installation."; + ProbeReport report; + report.path = m_settings.binaryPath; + report.token = m_settings.token; + report.status = ProbeReport::Status::Errored; + emit probeFinished(report); + emitSucceeded(); + return; + } +#ifdef Q_OS_WIN + checkerJar = FS::getPathNameInLocal8bit(checkerJar); +#endif + + QStringList args; + process.reset(new QProcess()); + if (!m_settings.extraArgs.isEmpty()) + { + args.append(Commandline::splitArgs(m_settings.extraArgs)); + } + if (m_settings.minMem != 0) + { + args << QString("-Xms%1m").arg(m_settings.minMem); + } + if (m_settings.maxMem != 0) + { + args << QString("-Xmx%1m").arg(m_settings.maxMem); + } + if (m_settings.permGen != 64 && m_settings.permGen != 0) + { + args << QString("-XX:PermSize=%1m").arg(m_settings.permGen); + } + + args.append({ "-jar", checkerJar, "--list", "os.arch", "java.version", "java.vendor" }); + process->setArguments(args); + process->setProgram(m_settings.binaryPath); + process->setProcessChannelMode(QProcess::SeparateChannels); + process->setProcessEnvironment(buildCleanEnvironment()); + qDebug() << "Running runtime probe:" << m_settings.binaryPath << args.join(" "); + + connect(process.get(), &QProcess::finished, this, &RuntimeProbeTask::finished); + connect(process.get(), &QProcess::errorOccurred, this, &RuntimeProbeTask::error); + connect(process.get(), &QProcess::readyReadStandardOutput, this, &RuntimeProbeTask::stdoutReady); + connect(process.get(), &QProcess::readyReadStandardError, this, &RuntimeProbeTask::stderrReady); + connect(&killTimer, &QTimer::timeout, this, &RuntimeProbeTask::timeout); + killTimer.setSingleShot(true); + killTimer.start(15000); + process->start(); + } + + void RuntimeProbeTask::stdoutReady() + { + QByteArray data = process->readAllStandardOutput(); + QString added = QString::fromLocal8Bit(data); + added.remove('\r'); + m_stdout += added; + } + + void RuntimeProbeTask::stderrReady() + { + QByteArray data = process->readAllStandardError(); + QString added = QString::fromLocal8Bit(data); + added.remove('\r'); + m_stderr += added; + } + + void RuntimeProbeTask::finished(int exitcode, QProcess::ExitStatus status) + { + killTimer.stop(); + QProcessPtr activeProcess = process; + process.reset(); + + ProbeReport report; + report.path = m_settings.binaryPath; + report.token = m_settings.token; + report.stderrLog = m_stderr; + report.stdoutLog = m_stdout; + qDebug() << "STDOUT" << m_stdout; + if (!m_stderr.isEmpty()) + { + qWarning() << "STDERR" << m_stderr; + } + qDebug() << "Runtime probe finished with status" << status << "exit code" << exitcode; + + if (status == QProcess::CrashExit) + { + report.status = ProbeReport::Status::Errored; + emit probeFinished(report); + emitSucceeded(); + return; + } + + auto parseBlocks = [](const QString& stdoutText) + { + QList<QMap<QString, QString>> blocks; + QMap<QString, QString> current; + const auto lines = stdoutText.split('\n'); + for (QString line : lines) + { + line = line.trimmed(); + if (line.isEmpty()) + { + if (!current.isEmpty()) + { + blocks.append(current); + current.clear(); + } + continue; + } + if (line.contains("/bedrock/strata")) + { + continue; + } + const auto eq = line.indexOf('='); + if (eq <= 0) + { + continue; + } + const auto key = line.left(eq).trimmed(); + const auto value = line.mid(eq + 1).trimmed(); + if (!key.isEmpty() && !value.isEmpty()) + { + current.insert(key, value); + } + } + if (!current.isEmpty()) + { + blocks.append(current); + } + return blocks; + }; + + auto resolvePath = [](const QString& path) + { + if (path.isEmpty()) + { + return QString(); + } + auto resolved = FS::ResolveExecutable(path); + QString chosen = resolved.isEmpty() ? path : resolved; + QFileInfo info(chosen); + if (info.exists()) + { + return info.canonicalFilePath(); + } + return chosen; + }; + + auto matchesProbeTarget = [](const QString& targetPath, const QString& candidatePath) + { + if (targetPath.isEmpty() || candidatePath.isEmpty()) + { + return false; + } + if (candidatePath == targetPath) + { + return true; + } +#ifdef Q_OS_WIN + const QFileInfo targetInfo(targetPath); + const QFileInfo candidateInfo(candidatePath); + auto normalizeJavaName = [](QString fileName) + { + fileName = fileName.toLower(); + if (fileName == "javaw.exe") + { + return QStringLiteral("java.exe"); + } + return fileName; + }; + + return targetInfo.absolutePath().compare(candidateInfo.absolutePath(), Qt::CaseInsensitive) == 0 + && normalizeJavaName(targetInfo.fileName()) == normalizeJavaName(candidateInfo.fileName()); +#else + return false; +#endif + }; + + const auto targetPath = resolvePath(m_settings.binaryPath); + QMap<QString, QString> results; + auto blocks = parseBlocks(m_stdout); + for (const auto& block : blocks) + { + const auto candidatePath = resolvePath(block.value("java.path")); + if (matchesProbeTarget(targetPath, candidatePath)) + { + results = block; + break; + } + } + if (results.isEmpty() && !blocks.isEmpty() && targetPath.isEmpty()) + { + results = blocks.first(); + } + + if (results.isEmpty() || !results.contains("os.arch") || !results.contains("java.version") + || !results.contains("java.vendor")) + { + report.status = ProbeReport::Status::InvalidData; + emit probeFinished(report); + emitSucceeded(); + return; + } + + auto osArch = results["os.arch"]; + auto javaVersion = results["java.version"]; + auto javaVendor = results["java.vendor"]; + bool is64 = osArch == "x86_64" || osArch == "amd64" || osArch == "aarch64" || osArch == "arm64" + || osArch == "riscv64" || osArch == "ppc64le" || osArch == "ppc64"; + + report.status = ProbeReport::Status::Valid; + report.is_64bit = is64; + report.platformTag = is64 ? "64" : "32"; + report.platformArch = osArch; + report.version = javaVersion; + report.vendor = javaVendor; + qDebug() << "Runtime probe succeeded."; + emit probeFinished(report); + emitSucceeded(); + } + + void RuntimeProbeTask::error(QProcess::ProcessError err) + { + if (err == QProcess::FailedToStart) + { + qDebug() << "Runtime probe failed to start."; + qDebug() << "Process environment:"; + qDebug() << process->environment(); + qDebug() << "Native environment:"; + qDebug() << QProcessEnvironment::systemEnvironment().toStringList(); + killTimer.stop(); + ProbeReport report; + report.path = m_settings.binaryPath; + report.token = m_settings.token; + emit probeFinished(report); + } + emitSucceeded(); + } + + void RuntimeProbeTask::timeout() + { + if (process) + { + qDebug() << "Runtime probe has been killed by timeout."; + process->kill(); + } + } +} // namespace projt::java |
