Drop dependency of KIO from kdeconnectcore

Use QNetworkAccessManager for storing the files we receive instead of
directly KIO, then provide the KIO-based QNetworkAccessManager from the
daemon. This way we'll still get the KIO network-transparency, but the
library only depenends on QtNetwork, which will be easier to get in some
platforms.

After this change, we only depend on KConfig, KI18n and KCoreAddons, which
are tier1 and really easy to work with on any platform.

REVIEW: 123325
This commit is contained in:
Aleix Pol 2015-05-05 00:41:39 +02:00
parent ba4c87abc1
commit 11996f56ca
8 changed files with 77 additions and 101 deletions

View file

@ -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) 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(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) find_package(Qca-qt5 2.1.0 REQUIRED)
include_directories(${CMAKE_SOURCE_DIR}) include_directories(${CMAKE_SOURCE_DIR})

View file

@ -33,7 +33,7 @@ add_library(kdeconnectcore ${kdeconnectcore_SRCS})
target_link_libraries(kdeconnectcore target_link_libraries(kdeconnectcore
PUBLIC PUBLIC
Qt5::Network Qt5::Network
KF5::KIOCore KF5::CoreAddons
qca-qt5 qca-qt5
PRIVATE PRIVATE
Qt5::DBus Qt5::DBus

View file

@ -25,6 +25,7 @@
#include <QNetworkConfigurationManager> #include <QNetworkConfigurationManager>
#include <QNetworkAccessManager> #include <QNetworkAccessManager>
#include <QDebug> #include <QDebug>
#include <QPointer>
#include "core_debug.h" #include "core_debug.h"
#include "kdeconnectconfig.h" #include "kdeconnectconfig.h"
@ -185,6 +186,15 @@ QString Daemon::announcedName()
return KdeConnectConfig::instance()->name(); return KdeConnectConfig::instance()->name();
} }
QNetworkAccessManager* Daemon::networkAccessManager()
{
static QPointer<QNetworkAccessManager> manager;
if (!manager) {
manager = new QNetworkAccessManager(this);
}
return manager;
}
Daemon::~Daemon() Daemon::~Daemon()
{ {

View file

@ -30,6 +30,7 @@
class NetworkPackage; class NetworkPackage;
class DeviceLink; class DeviceLink;
class Device; class Device;
class QNetworkAccessManager;
class KDECONNECTCORE_EXPORT Daemon class KDECONNECTCORE_EXPORT Daemon
: public QObject : public QObject
@ -62,6 +63,7 @@ public Q_SLOTS:
virtual void requestPairing(Device *d) = 0; virtual void requestPairing(Device *d) = 0;
virtual void reportError(const QString &title, const QString &description) = 0; virtual void reportError(const QString &title, const QString &description) = 0;
virtual QNetworkAccessManager* networkAccessManager();
Q_SIGNALS: Q_SIGNALS:
Q_SCRIPTABLE void deviceAdded(const QString& id); Q_SCRIPTABLE void deviceAdded(const QString& id);

View file

@ -1,5 +1,6 @@
/* /*
* Copyright 2013 Albert Vaca <albertvaka@gmail.com> * Copyright 2013 Albert Vaca <albertvaka@gmail.com>
* Copyright 2015 Aleix Pol i Gonzalez <aleixpol@kde.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
@ -19,6 +20,7 @@
*/ */
#include "filetransferjob.h" #include "filetransferjob.h"
#include "daemon.h"
#include <core_debug.h> #include <core_debug.h>
#include <qalgorithms.h> #include <qalgorithms.h>
@ -30,28 +32,25 @@
FileTransferJob::FileTransferJob(const QSharedPointer<QIODevice>& origin, qint64 size, const QUrl& destination) FileTransferJob::FileTransferJob(const QSharedPointer<QIODevice>& origin, qint64 size, const QUrl& destination)
: KJob() : KJob()
, mOrigin(origin) , mOrigin(origin)
, mDestinationJob(0) , mReply(Q_NULLPTR)
, mDeviceName("KDE Connect") , mDeviceName("KDE Connect") //TODO: Actually fetch the device name
, mDestination(destination) , mDestination(destination)
, mSpeedBytes(0) , mSpeedBytes(0)
, mSize(size)
, mWritten(0) , mWritten(0)
{ {
Q_ASSERT(mOrigin);
if (mDestination.scheme().isEmpty()) { if (mDestination.scheme().isEmpty()) {
qWarning() << "Destination QUrl" << mDestination << "lacks a scheme. Setting its scheme to 'file'."; qWarning() << "Destination QUrl" << mDestination << "lacks a scheme. Setting its scheme to 'file'.";
mDestination.setScheme("file"); mDestination.setScheme("file");
} }
Q_ASSERT(destination.isLocalFile()); if (size >= 0) {
setTotalAmount(Bytes, size);
}
setCapabilities(Killable); setCapabilities(Killable);
qCDebug(KDECONNECT_CORE) << "FileTransferJob Downloading payload to" << destination; qCDebug(KDECONNECT_CORE) << "FileTransferJob Downloading payload to" << destination;
} }
void FileTransferJob::openFinished(KJob* job)
{
qCDebug(KDECONNECT_CORE) << job->errorString();
}
void FileTransferJob::start() void FileTransferJob::start()
{ {
QMetaObject::invokeMethod(this, "doStart", Qt::QueuedConnection); QMetaObject::invokeMethod(this, "doStart", Qt::QueuedConnection);
@ -62,10 +61,10 @@ void FileTransferJob::doStart()
{ {
description(this, i18n("Receiving file over KDE-Connect"), description(this, i18n("Receiving file over KDE-Connect"),
QPair<QString, QString>(i18nc("File transfer origin", "From"), QPair<QString, QString>(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); setError(2);
setErrorText(i18n("Filename already present")); setErrorText(i18n("Filename already present"));
emitResult(); emitResult();
@ -76,7 +75,6 @@ void FileTransferJob::doStart()
void FileTransferJob::startTransfer() void FileTransferJob::startTransfer()
{ {
setTotalAmount(Bytes, mSize);
setProcessedAmount(Bytes, 0); setProcessedAmount(Bytes, 0);
mTime = QTime::currentTime(); mTime = QTime::currentTime();
description(this, i18n("Receiving file over KDE-Connect"), description(this, i18n("Receiving file over KDE-Connect"),
@ -84,90 +82,32 @@ void FileTransferJob::startTransfer()
QString(mDeviceName)), QString(mDeviceName)),
QPair<QString, QString>(i18nc("File transfer destination", "To"), mDestination.toLocalFile())); QPair<QString, QString>(i18nc("File transfer destination", "To"), mDestination.toLocalFile()));
mDestinationJob = KIO::open(mDestination, QIODevice::WriteOnly); mReply = Daemon::instance()->networkAccessManager()->put(QNetworkRequest(mDestination), mOrigin.data());
QFile(mDestination.toLocalFile()).open(QIODevice::WriteOnly | QIODevice::Truncate); //KIO won't create the file if it doesn't exist connect(mReply, &QNetworkReply::uploadProgress, this, [this](qint64 bytesSent, qint64 /*bytesTotal*/) {
connect(mDestinationJob, SIGNAL(open(KIO::Job*)), this, SLOT(open(KIO::Job*))); setProcessedAmount(Bytes, bytesSent);
connect(mDestinationJob, SIGNAL(result(KJob*)), this, SLOT(openFinished(KJob*))); emitSpeed(bytesSent/mTime.elapsed());
});
//Open destination file connect(mReply, &QNetworkReply::finished, this, &FileTransferJob::transferFinished);
mDestinationJob->start();
} }
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 //TODO: MD5-check the file
if (mSize > -1 && mWritten != mSize) { if (mReply->error()) {
qCDebug(KDECONNECT_CORE) << "Received incomplete file (" << mWritten << " of " << mSize << " bytes)"; qCDebug(KDECONNECT_CORE) << "Couldn't transfer the file successfully" << mReply->errorString();
setError(1); setError(mReply->error());
setErrorText(i18n("Received incomplete file")); setErrorText(i18n("Received incomplete file: %1", mReply->errorString()));
} else { } else {
qCDebug(KDECONNECT_CORE) << "Finished transfer" << mDestinationJob->url(); qCDebug(KDECONNECT_CORE) << "Finished transfer" << mDestination;
} }
mDestinationJob->close();
mDestinationJob->deleteLater();
emitResult(); emitResult();
} }
bool FileTransferJob::doKill() bool FileTransferJob::doKill()
{ {
if (mDestinationJob) { if (mReply) {
mDestinationJob->close(); mReply->close();
} }
if (mOrigin) { if (mOrigin) {
mOrigin->close(); mOrigin->close();

View file

@ -1,5 +1,6 @@
/* /*
* Copyright 2013 Albert Vaca <albertvaka@gmail.com> * Copyright 2013 Albert Vaca <albertvaka@gmail.com>
* Copyright 2015 Aleix Pol i Gonzalez <aleixpol@kde.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
@ -28,39 +29,48 @@
#include <KJob> #include <KJob>
#include <QUrl> #include <QUrl>
#include <KIO/FileJob> #include <QNetworkAccessManager>
#include <KIO/Job> #include <QNetworkReply>
#include <QBuffer>
/**
* @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 class FileTransferJob
: public KJob : public KJob
{ {
Q_OBJECT Q_OBJECT
public: 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<QIODevice>& origin, qint64 size, const QUrl &destination); FileTransferJob(const QSharedPointer<QIODevice>& origin, qint64 size, const QUrl &destination);
virtual void start(); virtual void start() Q_DECL_OVERRIDE;
QUrl destination() const { return mDestination; } QUrl destination() const { return mDestination; }
void setDeviceName(const QString &deviceName) { mDeviceName = deviceName; } void setDeviceName(const QString &deviceName) { mDeviceName = deviceName; }
public Q_SLOTS: private Q_SLOTS:
void doStart(); void doStart();
void readyRead();
void open(KIO::Job*);
void sourceFinished();
void openFinished(KJob*);
protected: protected:
virtual bool doKill(); bool doKill() Q_DECL_OVERRIDE;
private: private:
void startTransfer(); void startTransfer();
void transferFinished();
QSharedPointer<QIODevice> mOrigin; QSharedPointer<QIODevice> mOrigin;
KIO::FileJob* mDestinationJob; QNetworkReply* mReply;
QString mDeviceName; QString mDeviceName;
QUrl mDestination; QUrl mDestination;
QTime mTime; QTime mTime;
qulonglong mSpeedBytes; qulonglong mSpeedBytes;
qint64 mSize;
qint64 mWritten; qint64 mWritten;
}; };

View file

@ -1,11 +1,11 @@
project(kdeconnectd) project(kdeconnectd)
find_package(KF5 REQUIRED COMPONENTS Notifications) find_package(KF5 REQUIRED COMPONENTS Notifications KIO)
add_definitions(-DTRANSLATION_DOMAIN="kdeconnect-kded") add_definitions(-DTRANSLATION_DOMAIN="kdeconnect-kded")
add_executable(kdeconnectd kdeconnectd.cpp) 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(kdeconnectd.desktop.cmake ${CMAKE_CURRENT_BINARY_DIR}/kdeconnectd.desktop)
configure_file(org.kde.kdeconnect.service.in ${CMAKE_CURRENT_BINARY_DIR}/org.kde.kdeconnect.service) configure_file(org.kde.kdeconnect.service.in ${CMAKE_CURRENT_BINARY_DIR}/org.kde.kdeconnect.service)

View file

@ -25,10 +25,12 @@
#include <QSocketNotifier> #include <QSocketNotifier>
#include <QApplication> #include <QApplication>
#include <QNetworkAccessManager>
#include <KDBusService> #include <KDBusService>
#include <KNotification> #include <KNotification>
#include <KLocalizedString> #include <KLocalizedString>
#include <KIO/AccessManager>
#include "core/daemon.h" #include "core/daemon.h"
#include "core/device.h" #include "core/device.h"
@ -68,6 +70,7 @@ class DesktopDaemon : public Daemon
public: public:
DesktopDaemon(QObject* parent = Q_NULLPTR) DesktopDaemon(QObject* parent = Q_NULLPTR)
: Daemon(parent) : Daemon(parent)
, m_nam(Q_NULLPTR)
{} {}
void requestPairing(Device* d) Q_DECL_OVERRIDE void requestPairing(Device* d) Q_DECL_OVERRIDE
@ -87,6 +90,17 @@ public:
{ {
KNotification::event(KNotification::Error, title, description); 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[]) int main(int argc, char* argv[])