diff options
| author | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 18:45:07 +0300 |
|---|---|---|
| committer | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 18:45:07 +0300 |
| commit | 31b9a8949ed0a288143e23bf739f2eb64fdc63be (patch) | |
| tree | 8a984fa143c38fccad461a77792d6864f3e82cd3 /meshmc/launcher/net/NetJob.cpp | |
| parent | 934382c8a1ce738589dee9ee0f14e1cec812770e (diff) | |
| parent | fad6a1066616b69d7f5fef01178efdf014c59537 (diff) | |
| download | Project-Tick-31b9a8949ed0a288143e23bf739f2eb64fdc63be.tar.gz Project-Tick-31b9a8949ed0a288143e23bf739f2eb64fdc63be.zip | |
Add 'meshmc/' from commit 'fad6a1066616b69d7f5fef01178efdf014c59537'
git-subtree-dir: meshmc
git-subtree-mainline: 934382c8a1ce738589dee9ee0f14e1cec812770e
git-subtree-split: fad6a1066616b69d7f5fef01178efdf014c59537
Diffstat (limited to 'meshmc/launcher/net/NetJob.cpp')
| -rw-r--r-- | meshmc/launcher/net/NetJob.cpp | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/meshmc/launcher/net/NetJob.cpp b/meshmc/launcher/net/NetJob.cpp new file mode 100644 index 0000000000..7b3eff6620 --- /dev/null +++ b/meshmc/launcher/net/NetJob.cpp @@ -0,0 +1,225 @@ +/* SPDX-FileCopyrightText: 2026 Project Tick + * SPDX-FileContributor: Project Tick + * SPDX-License-Identifier: GPL-3.0-or-later + * + * MeshMC - A Custom Launcher for Minecraft + * 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, either version 3 of the License, or + * (at your option) any later version. + * + * 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, see <https://www.gnu.org/licenses/>. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "NetJob.h" +#include "Download.h" + +#include <QDebug> + +void NetJob::partSucceeded(int index) +{ + // do progress. all slots are 1 in size at least + auto& slot = parts_progress[index]; + partProgress(index, slot.total_progress, slot.total_progress); + + m_doing.remove(index); + m_done.insert(index); + downloads[index].get()->disconnect(this); + startMoreParts(); +} + +void NetJob::partFailed(int index) +{ + m_doing.remove(index); + auto& slot = parts_progress[index]; + if (slot.failures == 3) { + m_failed.insert(index); + } else { + slot.failures++; + m_todo.enqueue(index); + } + downloads[index].get()->disconnect(this); + startMoreParts(); +} + +void NetJob::partAborted(int index) +{ + m_aborted = true; + m_doing.remove(index); + m_failed.insert(index); + downloads[index].get()->disconnect(this); + startMoreParts(); +} + +void NetJob::partProgress(int index, qint64 bytesReceived, qint64 bytesTotal) +{ + auto& slot = parts_progress[index]; + slot.current_progress = bytesReceived; + slot.total_progress = bytesTotal; + + int done = m_done.size(); + int doing = m_doing.size(); + int all = parts_progress.size(); + + qint64 bytesAll = 0; + qint64 bytesTotalAll = 0; + for (auto& partIdx : m_doing) { + auto part = parts_progress[partIdx]; + // do not count parts with unknown/nonsensical total size + if (part.total_progress <= 0) { + continue; + } + bytesAll += part.current_progress; + bytesTotalAll += part.total_progress; + } + + qint64 inprogress = + (bytesTotalAll == 0) ? 0 : (bytesAll * 1000) / bytesTotalAll; + auto current = done * 1000 + doing * inprogress; + auto current_total = all * 1000; + // HACK: make sure it never jumps backwards. + // FAIL: This breaks if the size is not known (or is it something else?) and + // jumps to 1000, so if it is 1000 reset it to inprogress + if (m_current_progress == 1000) { + m_current_progress = inprogress; + } + if (m_current_progress > current) { + current = m_current_progress; + } + m_current_progress = current; + setProgress(current, current_total); +} + +void NetJob::executeTask() +{ + // hack that delays early failures so they can be caught easier + QMetaObject::invokeMethod(this, "startMoreParts", Qt::QueuedConnection); +} + +void NetJob::startMoreParts() +{ + if (!isRunning()) { + // this actually makes sense. You can put running downloads into a + // NetJob and then not start it until much later. + return; + } + // OK. We are actively processing tasks, proceed. + // Check for final conditions if there's nothing in the queue. + if (!m_todo.size()) { + if (!m_doing.size()) { + if (!m_failed.size()) { + emitSucceeded(); + } else if (m_aborted) { + emitAborted(); + } else { + emitFailed(tr("Job '%1' failed to process:\n%2") + .arg(objectName()) + .arg(getFailedFiles().join("\n"))); + } + } + return; + } + // There's work to do, try to start more parts. + while (m_doing.size() < 6) { + if (!m_todo.size()) + return; + int doThis = m_todo.dequeue(); + m_doing.insert(doThis); + auto part = downloads[doThis]; + // connect signals :D + connect(part.get(), SIGNAL(succeeded(int)), SLOT(partSucceeded(int))); + connect(part.get(), SIGNAL(failed(int)), SLOT(partFailed(int))); + connect(part.get(), SIGNAL(aborted(int)), SLOT(partAborted(int))); + connect(part.get(), SIGNAL(netActionProgress(int, qint64, qint64)), + SLOT(partProgress(int, qint64, qint64))); + part->start(m_network); + } +} + +QStringList NetJob::getFailedFiles() +{ + QStringList failed; + for (auto index : m_failed) { + failed.push_back(downloads[index]->url().toString()); + } + failed.sort(); + return failed; +} + +bool NetJob::canAbort() const +{ + bool canFullyAbort = true; + // can abort the waiting? + for (auto index : m_todo) { + auto part = downloads[index]; + canFullyAbort &= part->canAbort(); + } + // can abort the active? + for (auto index : m_doing) { + auto part = downloads[index]; + canFullyAbort &= part->canAbort(); + } + return canFullyAbort; +} + +bool NetJob::abort() +{ + bool fullyAborted = true; + // fail all waiting + m_failed.unite(QSet<int>(m_todo.begin(), m_todo.end())); + m_todo.clear(); + // abort active + auto toKill = m_doing.values(); + for (auto index : toKill) { + auto part = downloads[index]; + fullyAborted &= part->abort(); + } + return fullyAborted; +} + +bool NetJob::addNetAction(NetAction::Ptr action) +{ + action->m_index_within_job = downloads.size(); + downloads.append(action); + part_info pi; + parts_progress.append(pi); + partProgress(parts_progress.count() - 1, action->currentProgress(), + action->totalProgress()); + + if (action->isRunning()) { + connect(action.get(), SIGNAL(succeeded(int)), SLOT(partSucceeded(int))); + connect(action.get(), SIGNAL(failed(int)), SLOT(partFailed(int))); + connect(action.get(), SIGNAL(netActionProgress(int, qint64, qint64)), + SLOT(partProgress(int, qint64, qint64))); + } else { + m_todo.append(parts_progress.size() - 1); + } + return true; +} + +NetJob::~NetJob() = default; |
