diff --git a/src/util/externalcommand.h b/src/util/externalcommand.h --- a/src/util/externalcommand.h +++ b/src/util/externalcommand.h @@ -122,10 +122,16 @@ Q_SIGNALS: void progress(int); void reportSignal(const QVariantMap&); - + + // remove above signals + void newData(); + public Q_SLOTS: void emitProgress(KJob*, unsigned long percent) { emit progress(percent); } void emitReport(const QVariantMap& report) { emit reportSignal(report); } + + void emitNewData(int percent); + void emitNewData(QString& message); private: void setExitCode(int i); diff --git a/src/util/externalcommand.cpp b/src/util/externalcommand.cpp --- a/src/util/externalcommand.cpp +++ b/src/util/externalcommand.cpp @@ -183,10 +183,6 @@ } auto interface = new org::kde::kpmcore::externalcommand(QStringLiteral("org.kde.kpmcore.externalcommand"), - - - - QStringLiteral("/Helper"), QDBusConnection::systemBus(), this); interface->setTimeout(10 * 24 * 3600 * 1000); // 10 days @@ -373,13 +369,16 @@ auto authResult = m_authJob->actionStatus(QStringLiteral("org.kde.kpmcore.externalcommand.init"), m_authJob->callerID()); - - // Wait until ExternalCommand Helper is ready and sends signal + // Wait until ExternalCommand Helper is ready and sends signal(Connect to newData signal) QEventLoop loop; auto exitLoop = [&] () { loop.exit(); }; - + ExternalCommand cmd; + auto conn = QObject::connect(&cmd, &ExternalCommand::newData, exitLoop); + loop.exec(); + + QObject::disconnect(conn); if (!isActionAuthorized || authResult == PolkitQt1::Authority::No || authResult == PolkitQt1::Authority::Unknown) { qDebug() << "Unable to obtain Administrative privileges, the action can not be executed!!"; @@ -397,6 +396,18 @@ } +void ExternalCommand::emitNewData(int percent) +{ + Q_UNUSED(percent) + emit newData(); +} + +void ExternalCommand::emitNewData(QString& message) +{ + Q_UNUSED(message) + emit newData(); +} + void DBusThread::run() { if (!QDBusConnection::systemBus().registerService(QStringLiteral("org.kde.kpmcore.applicationinterface")) || diff --git a/src/util/externalcommandhelper.h b/src/util/externalcommandhelper.h --- a/src/util/externalcommandhelper.h +++ b/src/util/externalcommandhelper.h @@ -35,10 +35,13 @@ Q_SIGNALS: void progress(int percent); void reportProgress(const QVariantMap& progress); + // remove above signals later on public: bool readData(const QString& sourceDevice, QByteArray& buffer, const qint64 offset, const qint64 size); bool writeData(const QString& targetDevice, const QByteArray& buffer, const qint64 offset); + void sendProgress(int percent); + void sendProgress(QString message); public Q_SLOTS: Q_SCRIPTABLE int helperMain(int argc, char **argv); diff --git a/src/util/externalcommandhelper.cpp b/src/util/externalcommandhelper.cpp --- a/src/util/externalcommandhelper.cpp +++ b/src/util/externalcommandhelper.cpp @@ -58,21 +58,23 @@ if (!QDBusConnection::systemBus().isConnected() || !QDBusConnection::systemBus().registerService(QStringLiteral("org.kde.kpmcore.helperinterface")) || - !QDBusConnection::systemBus().registerObject(QStringLiteral("/Helper"), this, QDBusConnection::ExportAllSlots)) { + !QDBusConnection::systemBus().registerService(QStringLiteral("org.kde.kpmcore.applicationinterface")) || + !QDBusConnection::systemBus().registerObject(QStringLiteral("/Helper"), this, QDBusConnection::ExportAllSlots) || + !QDBusConnection::systemBus().registerObject(QStringLiteral("/Application"), this, QDBusConnection::ExportAllSlots)) { + qDebug() << "Failed to initialize the Helper"; qWarning() << QDBusConnection::systemBus().lastError().message(); - // We have no reason to live when Main GUI app has expired - - qApp->quit(); return app.exec(); } m_loop = std::make_unique(); - emit reportProgress(QVariantMap()); + + // We send zero percent new data on initial start-up + sendProgress(0); // QDBus Service watcher which keeps an eye on the client (Main GUI app) // End the loop and return only once the client has unregistered over the QDBus. @@ -93,7 +95,6 @@ return app.exec(); } - /** Reads the given number of bytes from the sourceDevice into the given buffer. @param sourceDevice device or file to read from @param buffer buffer to store the bytes read in @@ -153,6 +154,64 @@ return true; } +/** Makes asynchronous call to the main application. + @param percent Percent of job completed. +*/ +void ExternalCommandHelper::sendProgress(int percent) +{ + QDBusInterface *iface = new QDBusInterface(QStringLiteral("org.kde.kpmcore.applicationinterface"), QStringLiteral("/Application"), QStringLiteral("org.kde.kpmcore.externalcommand"), QDBusConnection::systemBus()); + + if (!iface->isValid()) { + return; + } + + iface->setTimeout(10 * 24 * 3600 * 1000); + + QDBusPendingCall pcall = iface->asyncCall(QLatin1String("emitNewData"), percent); + + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this); + QEventLoop loop; + + auto exitLoop = [&] (QDBusPendingCallWatcher *watcher) { + loop.exit(); + + if (watcher->isError()) + qWarning() << watcher->error(); + }; + + connect(watcher, &QDBusPendingCallWatcher::finished, exitLoop); + loop.exec(); +} + +/** Makes asynchronous call to the main application. + @param message Message to send to the main application. +*/ +void ExternalCommandHelper::sendProgress(QString message) +{ + QDBusInterface *iface = new QDBusInterface(QStringLiteral("org.kde.kpmcore.applicationinterface"), QStringLiteral("/Application"), QStringLiteral("org.kde.kpmcore.externalcommand"), QDBusConnection::systemBus()); + + if (!iface->isValid()) { + return; + } + + iface->setTimeout(10 * 24 * 3600 * 1000); + + QDBusPendingCall pcall = iface->asyncCall(QLatin1String("emitNewData"), message); + + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this); + QEventLoop loop; + + auto exitLoop = [&] (QDBusPendingCallWatcher *watcher) { + loop.exit(); + + if (watcher->isError()) + qWarning() << watcher->error(); + }; + + connect(watcher, &QDBusPendingCallWatcher::finished, exitLoop); + loop.exec(); +} + // If targetDevice is empty then return QByteArray with data that was read from disk. QVariantMap ExternalCommandHelper::copyblocks(const QString& sourceDevice, const qint64 sourceFirstByte, const qint64 sourceLength, const QString& targetDevice, const qint64 targetFirstByte, const qint64 blockSize) { @@ -177,18 +236,14 @@ QByteArray buffer; int percent = 0; + QTime t; - t.start(); - QVariantMap report; - - report[QStringLiteral("report")] = xi18nc("@info:progress", "Copying %1 blocks (%2 bytes) from %3 to %4, direction: %5.", blocksToCopy, - sourceLength, readOffset, writeOffset, copyDirection == 1 ? i18nc("direction: left", "left") - : i18nc("direction: right", "right")); - - emit reportProgress(report); - + sendProgress(xi18nc("@info:progress", "Copying %1 blocks (%2 bytes) from %3 to %4, direction: %5.", blocksToCopy, + sourceLength, readOffset, writeOffset, copyDirection == 1 ? i18nc("direction: left", "left") + : i18nc("direction: right", "right"))); + bool rval = true; while (blocksCopied < blocksToCopy && !targetDevice.isEmpty()) { @@ -206,10 +261,11 @@ if (percent % 5 == 0 && t.elapsed() > 1000) { const qint64 mibsPerSec = (blocksCopied * blockSize / 1024 / 1024) / (t.elapsed() / 1000); const qint64 estSecsLeft = (100 - percent) * t.elapsed() / percent / 1000; - report[QStringLiteral("report")]= xi18nc("@info:progress", "Copying %1 MiB/second, estimated time left: %2", mibsPerSec, QTime(0, 0).addSecs(estSecsLeft).toString()); - emit reportProgress(report); + + sendProgress(xi18nc("@info:progress", "Copying %1 MiB/second, estimated time left: %2", mibsPerSec, QTime(0, 0).addSecs(estSecsLeft).toString())); + } - emit progress(percent); + sendProgress(percent); } } @@ -219,11 +275,9 @@ const qint64 lastBlockReadOffset = copyDirection > 0 ? readOffset + blockSize * blocksCopied : sourceFirstByte; const qint64 lastBlockWriteOffset = copyDirection > 0 ? writeOffset + blockSize * blocksCopied : targetFirstByte; - - report[QStringLiteral("report")]= xi18nc("@info:progress", "Copying remainder of block size %1 from %2 to %3.", lastBlock, lastBlockReadOffset, lastBlockWriteOffset); - - emit reportProgress(report); - + + sendProgress(xi18nc("@info:progress", "Copying remainder of block size %1 from %2 to %3.", lastBlock, lastBlockReadOffset, lastBlockWriteOffset)); + rval = readData(sourceDevice, buffer, lastBlockReadOffset, lastBlock); if (rval) { @@ -234,15 +288,13 @@ } if (rval) { - emit progress(100); + sendProgress(100); bytesWritten += buffer.size(); } } - - report[QStringLiteral("report")] = xi18ncp("@info:progress argument 2 is a string such as 7 bytes (localized accordingly)", "Copying 1 block (%2) finished.", "Copying %1 blocks (%2) finished.", blocksCopied, i18np("1 byte", "%1 bytes", bytesWritten)); - emit reportProgress(report); - + sendProgress(xi18ncp("@info:progress argument 2 is a string such as 7 bytes (localized accordingly)", "Copying 1 block (%2) finished.", "Copying %1 blocks (%2) finished.", blocksCopied, i18np("1 byte", "%1 bytes", bytesWritten))); + reply[QStringLiteral("success")] = rval; return reply; }