diff --git a/CMakeLists.txt b/CMakeLists.txt index dbaa03953..05b00e4fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ find_package(ECM 0.0.9 REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR} ${CMAKE_SOURCE_DIR}/cmake) find_package(Qt5 5.2 REQUIRED COMPONENTS Quick Test) -find_package(KF5 REQUIRED COMPONENTS I18n KIO ConfigWidgets DBusAddons KCMUtils IconThemes) +find_package(KF5 REQUIRED COMPONENTS I18n ConfigWidgets DBusAddons IconThemes) find_package(Qca-qt5 2.1.0 REQUIRED) include_directories(${CMAKE_SOURCE_DIR}) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index f4659592e..4d752512e 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -33,7 +33,7 @@ add_library(kdeconnectcore ${kdeconnectcore_SRCS}) target_link_libraries(kdeconnectcore PUBLIC Qt5::Network - KF5::KIOCore + KF5::CoreAddons qca-qt5 PRIVATE Qt5::DBus diff --git a/core/daemon.cpp b/core/daemon.cpp index a06358981..683427f85 100644 --- a/core/daemon.cpp +++ b/core/daemon.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include "core_debug.h" #include "kdeconnectconfig.h" @@ -185,6 +186,15 @@ QString Daemon::announcedName() return KdeConnectConfig::instance()->name(); } +QNetworkAccessManager* Daemon::networkAccessManager() +{ + static QPointer manager; + if (!manager) { + manager = new QNetworkAccessManager(this); + } + return manager; +} + Daemon::~Daemon() { diff --git a/core/daemon.h b/core/daemon.h index a2e2cfc22..c073384a0 100644 --- a/core/daemon.h +++ b/core/daemon.h @@ -30,6 +30,7 @@ class NetworkPackage; class DeviceLink; class Device; +class QNetworkAccessManager; class KDECONNECTCORE_EXPORT Daemon : public QObject @@ -62,6 +63,7 @@ public Q_SLOTS: virtual void requestPairing(Device *d) = 0; virtual void reportError(const QString &title, const QString &description) = 0; + virtual QNetworkAccessManager* networkAccessManager(); Q_SIGNALS: Q_SCRIPTABLE void deviceAdded(const QString& id); diff --git a/core/filetransferjob.cpp b/core/filetransferjob.cpp index 27ed8e82b..f503f6a30 100644 --- a/core/filetransferjob.cpp +++ b/core/filetransferjob.cpp @@ -1,5 +1,6 @@ /* * Copyright 2013 Albert Vaca + * Copyright 2015 Aleix Pol i Gonzalez * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -19,6 +20,7 @@ */ #include "filetransferjob.h" +#include "daemon.h" #include #include @@ -30,28 +32,25 @@ FileTransferJob::FileTransferJob(const QSharedPointer& origin, qint64 size, const QUrl& destination) : KJob() , mOrigin(origin) - , mDestinationJob(0) - , mDeviceName("KDE Connect") + , mReply(Q_NULLPTR) + , mDeviceName("KDE Connect") //TODO: Actually fetch the device name , mDestination(destination) , mSpeedBytes(0) - , mSize(size) , mWritten(0) { + Q_ASSERT(mOrigin); if (mDestination.scheme().isEmpty()) { qWarning() << "Destination QUrl" << mDestination << "lacks a scheme. Setting its scheme to 'file'."; mDestination.setScheme("file"); } - Q_ASSERT(destination.isLocalFile()); + if (size >= 0) { + setTotalAmount(Bytes, size); + } setCapabilities(Killable); qCDebug(KDECONNECT_CORE) << "FileTransferJob Downloading payload to" << destination; } -void FileTransferJob::openFinished(KJob* job) -{ - qCDebug(KDECONNECT_CORE) << job->errorString(); -} - void FileTransferJob::start() { QMetaObject::invokeMethod(this, "doStart", Qt::QueuedConnection); @@ -62,10 +61,10 @@ void FileTransferJob::doStart() { description(this, i18n("Receiving file over KDE-Connect"), QPair(i18nc("File transfer origin", "From"), - QString(mDeviceName)) + mDeviceName) ); - QUrl destCheck = mDestination; - if (destCheck.isLocalFile() && QFile::exists(destCheck.toLocalFile())) { + + if (mDestination.isLocalFile() && QFile::exists(mDestination.toLocalFile())) { setError(2); setErrorText(i18n("Filename already present")); emitResult(); @@ -76,7 +75,6 @@ void FileTransferJob::doStart() void FileTransferJob::startTransfer() { - setTotalAmount(Bytes, mSize); setProcessedAmount(Bytes, 0); mTime = QTime::currentTime(); description(this, i18n("Receiving file over KDE-Connect"), @@ -84,90 +82,32 @@ void FileTransferJob::startTransfer() QString(mDeviceName)), QPair(i18nc("File transfer destination", "To"), mDestination.toLocalFile())); - mDestinationJob = KIO::open(mDestination, QIODevice::WriteOnly); - QFile(mDestination.toLocalFile()).open(QIODevice::WriteOnly | QIODevice::Truncate); //KIO won't create the file if it doesn't exist - connect(mDestinationJob, SIGNAL(open(KIO::Job*)), this, SLOT(open(KIO::Job*))); - connect(mDestinationJob, SIGNAL(result(KJob*)), this, SLOT(openFinished(KJob*))); - - //Open destination file - mDestinationJob->start(); + mReply = Daemon::instance()->networkAccessManager()->put(QNetworkRequest(mDestination), mOrigin.data()); + connect(mReply, &QNetworkReply::uploadProgress, this, [this](qint64 bytesSent, qint64 /*bytesTotal*/) { + setProcessedAmount(Bytes, bytesSent); + emitSpeed(bytesSent/mTime.elapsed()); + }); + connect(mReply, &QNetworkReply::finished, this, &FileTransferJob::transferFinished); } -void FileTransferJob::open(KIO::Job* job) +void FileTransferJob::transferFinished() { - Q_UNUSED(job); - - //qCDebug(KDECONNECT_CORE) << "FileTransferJob open"; - - if (!mOrigin) { - qCDebug(KDECONNECT_CORE) << "FileTransferJob: Origin is null"; - return; - } - - //Open source file - mOrigin->open(QIODevice::ReadOnly); - Q_ASSERT(mOrigin->isOpen()); - - connect(mOrigin.data(), SIGNAL(readyRead()),this, SLOT(readyRead())); - connect(mOrigin.data(), SIGNAL(aboutToClose()),this, SLOT(sourceFinished())); - if (mOrigin->bytesAvailable() > 0) readyRead(); - -} - -void FileTransferJob::readyRead() -{ - int bytes = qMin(qint64(4096), mOrigin->bytesAvailable()); - QByteArray data = mOrigin->read(bytes); - mDestinationJob->write(data); - mWritten += data.size(); - setProcessedAmount(Bytes, mWritten); - - //qCDebug(KDECONNECT_CORE) << "readyRead" << mSize << mWritten << bytes; - - if (mSize > -1) { - //If a least 1 second has passed since last update - int secondsSinceLastTime = mTime.secsTo(QTime::currentTime()); - if (secondsSinceLastTime > 0 && mSpeedBytes > 0) { - float speed = (mWritten - mSpeedBytes) / float(secondsSinceLastTime); - emitSpeed(speed); - - mTime = QTime::currentTime(); - mSpeedBytes = mWritten; - } else if(mSpeedBytes == 0) { - mSpeedBytes = mWritten; - } - } - - if (mSize > -1 && mWritten >= mSize) { //At the end or expected size reached - mOrigin->close(); - //sourceFinished(); - } else if (mOrigin->bytesAvailable() > 0) { - QMetaObject::invokeMethod(this, "readyRead", Qt::QueuedConnection); - } -} - -void FileTransferJob::sourceFinished() -{ - //Make sure we do not enter this function again - disconnect(mOrigin.data(), SIGNAL(aboutToClose()),this, SLOT(sourceFinished())); - //TODO: MD5-check the file - if (mSize > -1 && mWritten != mSize) { - qCDebug(KDECONNECT_CORE) << "Received incomplete file (" << mWritten << " of " << mSize << " bytes)"; - setError(1); - setErrorText(i18n("Received incomplete file")); + if (mReply->error()) { + qCDebug(KDECONNECT_CORE) << "Couldn't transfer the file successfully" << mReply->errorString(); + setError(mReply->error()); + setErrorText(i18n("Received incomplete file: %1", mReply->errorString())); } else { - qCDebug(KDECONNECT_CORE) << "Finished transfer" << mDestinationJob->url(); + qCDebug(KDECONNECT_CORE) << "Finished transfer" << mDestination; } - mDestinationJob->close(); - mDestinationJob->deleteLater(); + emitResult(); } bool FileTransferJob::doKill() { - if (mDestinationJob) { - mDestinationJob->close(); + if (mReply) { + mReply->close(); } if (mOrigin) { mOrigin->close(); diff --git a/core/filetransferjob.h b/core/filetransferjob.h index 973bd3a87..859a30321 100644 --- a/core/filetransferjob.h +++ b/core/filetransferjob.h @@ -1,5 +1,6 @@ /* * Copyright 2013 Albert Vaca + * Copyright 2015 Aleix Pol i Gonzalez * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -28,39 +29,48 @@ #include #include -#include -#include +#include +#include +#include +/** + * @short It will stream a device into a url destination + * + * Given a QIODevice, the file transfer job will use the system's QNetworkAccessManager + * for putting the stream into the requested location. + */ class FileTransferJob : public KJob { Q_OBJECT public: + /** + * @p origin specifies the data to read from. + * @p size specifies the expected size of the stream we're reading. + * @p destination specifies where these contents should be stored + */ FileTransferJob(const QSharedPointer& origin, qint64 size, const QUrl &destination); - virtual void start(); + virtual void start() Q_DECL_OVERRIDE; QUrl destination() const { return mDestination; } void setDeviceName(const QString &deviceName) { mDeviceName = deviceName; } -public Q_SLOTS: +private Q_SLOTS: void doStart(); - void readyRead(); - void open(KIO::Job*); - void sourceFinished(); - void openFinished(KJob*); protected: - virtual bool doKill(); + bool doKill() Q_DECL_OVERRIDE; private: void startTransfer(); + void transferFinished(); + QSharedPointer mOrigin; - KIO::FileJob* mDestinationJob; + QNetworkReply* mReply; QString mDeviceName; QUrl mDestination; QTime mTime; qulonglong mSpeedBytes; - qint64 mSize; qint64 mWritten; }; diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index 852e7794b..0aec94248 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -1,11 +1,11 @@ project(kdeconnectd) -find_package(KF5 REQUIRED COMPONENTS Notifications) +find_package(KF5 REQUIRED COMPONENTS Notifications KIO) add_definitions(-DTRANSLATION_DOMAIN="kdeconnect-kded") add_executable(kdeconnectd kdeconnectd.cpp) -target_link_libraries(kdeconnectd kdeconnectcore KF5::DBusAddons KF5::Notifications KF5::I18n Qt5::Widgets) +target_link_libraries(kdeconnectd kdeconnectcore KF5::KIOWidgets KF5::DBusAddons KF5::Notifications KF5::I18n Qt5::Widgets) configure_file(kdeconnectd.desktop.cmake ${CMAKE_CURRENT_BINARY_DIR}/kdeconnectd.desktop) configure_file(org.kde.kdeconnect.service.in ${CMAKE_CURRENT_BINARY_DIR}/org.kde.kdeconnect.service) diff --git a/daemon/kdeconnectd.cpp b/daemon/kdeconnectd.cpp index c43bc9be1..522cf719a 100644 --- a/daemon/kdeconnectd.cpp +++ b/daemon/kdeconnectd.cpp @@ -25,10 +25,12 @@ #include #include +#include #include #include #include +#include #include "core/daemon.h" #include "core/device.h" @@ -68,6 +70,7 @@ class DesktopDaemon : public Daemon public: DesktopDaemon(QObject* parent = Q_NULLPTR) : Daemon(parent) + , m_nam(Q_NULLPTR) {} void requestPairing(Device* d) Q_DECL_OVERRIDE @@ -87,6 +90,17 @@ public: { KNotification::event(KNotification::Error, title, description); } + + QNetworkAccessManager* networkAccessManager() Q_DECL_OVERRIDE + { + if (!m_nam) { + m_nam = new KIO::AccessManager(this); + } + return m_nam; + } + +private: + QNetworkAccessManager* m_nam; }; int main(int argc, char* argv[])