File indexing completed on 2024-11-17 04:55:45

0001 /*
0002  *   SPDX-FileCopyrightText: 2013 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
0003  *
0004  *   SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005  */
0006 
0007 #include "SnapTransaction.h"
0008 #include "SnapBackend.h"
0009 #include "SnapResource.h"
0010 #include "libsnapclient/config-paths.h"
0011 #include "utils.h"
0012 #include <KLocalizedString>
0013 #include <QJsonArray>
0014 #include <QJsonDocument>
0015 #include <QProcess>
0016 #include <QTimer>
0017 #include <Snapd/Request>
0018 
0019 SnapTransaction::SnapTransaction(QSnapdClient *client, SnapResource *app, Role role, AbstractResource::State newState)
0020     : Transaction(app, app, role)
0021     , m_client(client)
0022     , m_app(app)
0023     , m_newState(newState)
0024 {
0025     if (role == RemoveRole)
0026         setRequest(m_client->remove(app->packageName()));
0027     else
0028         setRequest(m_client->install(app->packageName()));
0029 }
0030 
0031 void SnapTransaction::cancel()
0032 {
0033     m_request->cancel();
0034 }
0035 
0036 void SnapTransaction::finishTransaction()
0037 {
0038     switch (m_request->error()) {
0039     case QSnapdRequest::NoError:
0040         static_cast<SnapBackend *>(m_app->backend())->refreshStates();
0041         setStatus(DoneStatus);
0042         m_app->setState(m_newState);
0043         break;
0044     case QSnapdRequest::Cancelled:
0045         setStatus(CancelledStatus);
0046         break;
0047     case QSnapdRequest::NeedsClassic:
0048         setStatus(SetupStatus);
0049         if (role() == Transaction::InstallRole) {
0050             Q_EMIT proceedRequest(m_app->name(),
0051                                   i18n("This Snap application is not compatible with security sandboxing "
0052                                        "and will have full access to this computer. Install it anyway?"));
0053             return;
0054         }
0055         break;
0056     case QSnapdRequest::AuthDataRequired: {
0057         setStatus(SetupStatus);
0058         QProcess *p = new QProcess;
0059         p->setProgram(QStringLiteral(CMAKE_INSTALL_FULL_LIBEXECDIR "/discover/SnapMacaroonDialog"));
0060         p->start();
0061 
0062         connect(p, &QProcess::finished, this, [this, p](int code, QProcess::ExitStatus status) {
0063             p->deleteLater();
0064             if (code != 0) {
0065                 qWarning() << "login failed... code:" << code << status << p->readAll();
0066                 Q_EMIT passiveMessage(m_request->errorString());
0067                 setStatus(DoneWithErrorStatus);
0068                 return;
0069             }
0070             const auto doc = QJsonDocument::fromJson(p->readAllStandardOutput());
0071             const auto result = doc.object();
0072 
0073             const auto macaroon = result[QStringLiteral("macaroon")].toString();
0074             const auto discharges = kTransform<QStringList>(result[QStringLiteral("discharges")].toArray(), [](const QJsonValue &val) {
0075                 return val.toString();
0076             });
0077             static_cast<SnapBackend *>(m_app->backend())->client()->setAuthData(new QSnapdAuthData(macaroon, discharges));
0078             m_request->runAsync();
0079         });
0080     }
0081         return;
0082     default:
0083         qDebug() << "snap error" << m_request.get() << m_request->error() << m_request->errorString();
0084         Q_EMIT passiveMessage(m_request->errorString());
0085         setStatus(DoneWithErrorStatus);
0086         break;
0087     }
0088 }
0089 
0090 void SnapTransaction::proceed()
0091 {
0092     setRequest(m_client->install(QSnapdClient::Classic, m_app->packageName()));
0093 }
0094 
0095 void SnapTransaction::setRequest(QSnapdRequest *req)
0096 {
0097     m_request.reset(req);
0098 
0099     setCancellable(true);
0100     connect(m_request.data(), &QSnapdRequest::progress, this, &SnapTransaction::progressed);
0101     connect(m_request.data(), &QSnapdRequest::complete, this, &SnapTransaction::finishTransaction);
0102 
0103     setStatus(CommittingStatus);
0104     m_request->runAsync();
0105 }
0106 
0107 void SnapTransaction::progressed()
0108 {
0109     const auto change = m_request->change();
0110     int percentage = 0, count = 0;
0111 
0112     auto status = SetupStatus;
0113     for (int i = 0, c = change->taskCount(); i < c; ++i) {
0114         ++count;
0115         auto task = change->task(i);
0116         if (task->kind() == QLatin1String("download-snap")) {
0117             status = task->status() == QLatin1String("doing") || task->status() == QLatin1String("do") ? DownloadingStatus : CommittingStatus;
0118         } else if (task->kind() == QLatin1String("clear-snap")) {
0119             status = CommittingStatus;
0120         }
0121         percentage += (100 * task->progressDone()) / task->progressTotal();
0122     }
0123     setProgress(percentage / qMax(count, 1));
0124     setStatus(status);
0125 }