Show progress when sending a file from desktop

Summary:
Show progress when sending a file from the desktop

BUG: 355044

Test Plan:
Complete transfer:
-Right click on a big file in dolphin
-Select Send to xx via KDE Connect
-Open the Notifications widget and verify progress is shown correctly

Stop transfer:
-Right click on a big file in dolphin
-Select Send to xx via KDE Connect
-Open The Notifications widget and press the stop/kill button
-Observe that the file upload is stopped

Reviewers: #kde_connect, nicolasfella

Reviewed By: #kde_connect, nicolasfella

Subscribers: apol, broulik, nicolasfella, kdeconnect

Tags: #kde_connect

Differential Revision: https://phabricator.kde.org/D16279
This commit is contained in:
Erik Duisters 2018-11-21 19:58:44 +01:00
parent 2de96e86ac
commit 2c9fde483a
4 changed files with 83 additions and 20 deletions

View file

@ -41,6 +41,7 @@ target_link_libraries(kdeconnectcore
PUBLIC PUBLIC
Qt5::Network Qt5::Network
KF5::CoreAddons KF5::CoreAddons
KF5::KIOCore
qca-qt5 qca-qt5
PRIVATE PRIVATE
Qt5::DBus Qt5::DBus

View file

@ -24,9 +24,11 @@
#include "core_debug.h" #include "core_debug.h"
#include "kdeconnectconfig.h" #include "kdeconnectconfig.h"
#include "backends/linkprovider.h" #include "backends/linkprovider.h"
#include "uploadjob.h"
#include "socketlinereader.h" #include "socketlinereader.h"
#include "lanlinkprovider.h" #include "lanlinkprovider.h"
#include <kio/global.h>
#include <KJobTrackerInterface>
#include <plugins/share/shareplugin.h>
LanDeviceLink::LanDeviceLink(const QString& deviceId, LinkProvider* parent, QSslSocket* socket, ConnectionStarted connectionSource) LanDeviceLink::LanDeviceLink(const QString& deviceId, LinkProvider* parent, QSslSocket* socket, ConnectionStarted connectionSource)
: DeviceLink(deviceId, parent) : DeviceLink(deviceId, parent)
@ -98,6 +100,9 @@ bool LanDeviceLink::sendPacket(NetworkPacket& np)
UploadJob* LanDeviceLink::sendPayload(const NetworkPacket& np) UploadJob* LanDeviceLink::sendPayload(const NetworkPacket& np)
{ {
UploadJob* job = new UploadJob(np.payload(), deviceId()); UploadJob* job = new UploadJob(np.payload(), deviceId());
if (np.type() == PACKET_TYPE_SHARE_REQUEST && np.payloadSize() >= 0) {
KIO::getJobTracker()->registerJob(job);
}
job->start(); job->start();
return job; return job;
} }

View file

@ -25,6 +25,8 @@
#include "lanlinkprovider.h" #include "lanlinkprovider.h"
#include "kdeconnectconfig.h" #include "kdeconnectconfig.h"
#include "core_debug.h" #include "core_debug.h"
#include <device.h>
#include <daemon.h>
UploadJob::UploadJob(const QSharedPointer<QIODevice>& source, const QString& deviceId) UploadJob::UploadJob(const QSharedPointer<QIODevice>& source, const QString& deviceId)
: KJob() : KJob()
@ -34,8 +36,8 @@ UploadJob::UploadJob(const QSharedPointer<QIODevice>& source, const QString& dev
, m_port(0) , m_port(0)
, m_deviceId(deviceId) // We will use this info if link is on ssl, to send encrypted payload , m_deviceId(deviceId) // We will use this info if link is on ssl, to send encrypted payload
{ {
connect(m_input.data(), &QIODevice::readyRead, this, &UploadJob::startUploading);
connect(m_input.data(), &QIODevice::aboutToClose, this, &UploadJob::aboutToClose); connect(m_input.data(), &QIODevice::aboutToClose, this, &UploadJob::aboutToClose);
setCapabilities(Killable);
} }
void UploadJob::start() void UploadJob::start()
@ -53,6 +55,10 @@ void UploadJob::start()
} }
} }
connect(m_server, &QTcpServer::newConnection, this, &UploadJob::newConnection); connect(m_server, &QTcpServer::newConnection, this, &UploadJob::newConnection);
Q_EMIT description(this, i18n("Sending file to %1", Daemon::instance()->getDevice(this->m_deviceId)->name()),
{ i18nc("File transfer origin", "From"), m_input.staticCast<QFile>().data()->fileName() }
);
} }
void UploadJob::newConnection() void UploadJob::newConnection()
@ -68,7 +74,6 @@ void UploadJob::newConnection()
connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketFailed(QAbstractSocket::SocketError))); connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketFailed(QAbstractSocket::SocketError)));
connect(m_socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(sslErrors(QList<QSslError>))); connect(m_socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(sslErrors(QList<QSslError>)));
connect(m_socket, &QSslSocket::encrypted, this, &UploadJob::startUploading); connect(m_socket, &QSslSocket::encrypted, this, &UploadJob::startUploading);
// connect(mSocket, &QAbstractSocket::stateChanged, [](QAbstractSocket::SocketState state){ qDebug() << "statechange" << state; });
LanLinkProvider::configureSslSocket(m_socket, m_deviceId, true); LanLinkProvider::configureSslSocket(m_socket, m_deviceId, true);
@ -77,32 +82,66 @@ void UploadJob::newConnection()
void UploadJob::startUploading() void UploadJob::startUploading()
{ {
while ( m_input->bytesAvailable() > 0 ) bytesUploaded = 0;
{ setProcessedAmount(Bytes, bytesUploaded);
qint64 bytes = qMin(m_input->bytesAvailable(), (qint64)4096); setTotalAmount(Bytes, m_input.data()->size());
int w = m_socket->write(m_input->read(bytes));
if (w<0) { connect(m_socket, &QSslSocket::encryptedBytesWritten, this, &UploadJob::encryptedBytesWritten);
qCWarning(KDECONNECT_CORE) << "error when writing data to upload" << bytes << m_input->bytesAvailable();
break; if (!m_timer.isValid()) {
} m_timer.start();
else }
{
while ( m_socket->flush() ); uploadNextPacket();
}
void UploadJob::uploadNextPacket()
{
qint64 bytesAvailable = m_input->bytesAvailable();
if ( bytesAvailable > 0) {
qint64 bytesToSend = qMin(m_input->bytesAvailable(), (qint64)4096);
bytesUploading = m_socket->write(m_input->read(bytesToSend));
if (bytesUploading < 0) {
qCWarning(KDECONNECT_CORE) << "error when writing data to upload" << bytesToSend << m_input->bytesAvailable();
} }
} }
m_input->close();
if (bytesAvailable <= 0 || bytesUploading < 0) {
m_input->close();
disconnect(m_socket, &QSslSocket::encryptedBytesWritten, this, &UploadJob::encryptedBytesWritten);
}
}
void UploadJob::encryptedBytesWritten(qint64 bytes)
{
Q_UNUSED(bytes);
bytesUploaded += bytesUploading;
if (m_socket->encryptedBytesToWrite() == 0) {
setProcessedAmount(Bytes, bytesUploaded);
const auto elapsed = m_timer.elapsed();
if (elapsed > 0) {
emitSpeed((1000 * bytesUploaded) / elapsed);
}
uploadNextPacket();
}
} }
void UploadJob::aboutToClose() void UploadJob::aboutToClose()
{ {
// qDebug() << "closing..."; qWarning() << "aboutToClose()";
m_socket->disconnectFromHost(); m_socket->disconnectFromHost();
} }
void UploadJob::cleanup() void UploadJob::cleanup()
{ {
qWarning() << "cleanup()";
m_socket->close(); m_socket->close();
// qDebug() << "closed!";
emitResult(); emitResult();
} }
@ -114,16 +153,24 @@ QVariantMap UploadJob::transferInfo()
void UploadJob::socketFailed(QAbstractSocket::SocketError error) void UploadJob::socketFailed(QAbstractSocket::SocketError error)
{ {
qWarning() << "error uploading" << error; qWarning() << "socketFailed() " << error;
m_socket->close();
setError(2); setError(2);
emitResult(); emitResult();
m_socket->close();
} }
void UploadJob::sslErrors(const QList<QSslError>& errors) void UploadJob::sslErrors(const QList<QSslError>& errors)
{ {
qWarning() << "ssl errors" << errors; qWarning() << "sslErrors() " << errors;
setError(1); setError(1);
emitResult(); emitResult();
m_socket->close(); m_socket->close();
} }
bool UploadJob::doKill()
{
if (m_input) {
m_input->close();
}
return true;
}

View file

@ -28,6 +28,8 @@
#include <QSharedPointer> #include <QSharedPointer>
#include <QSslSocket> #include <QSslSocket>
#include "server.h" #include "server.h"
#include <QElapsedTimer>
#include <QTimer>
class KDECONNECTCORE_EXPORT UploadJob class KDECONNECTCORE_EXPORT UploadJob
: public KJob : public KJob
@ -46,13 +48,21 @@ private:
QSslSocket* m_socket; QSslSocket* m_socket;
quint16 m_port; quint16 m_port;
const QString m_deviceId; const QString m_deviceId;
qint64 bytesUploading;
qint64 bytesUploaded;
QElapsedTimer m_timer;
const static quint16 MIN_PORT = 1739; const static quint16 MIN_PORT = 1739;
const static quint16 MAX_PORT = 1764; const static quint16 MAX_PORT = 1764;
protected:
bool doKill() override;
private Q_SLOTS: private Q_SLOTS:
void startUploading(); void startUploading();
void uploadNextPacket();
void newConnection(); void newConnection();
void encryptedBytesWritten(qint64 bytes);
void aboutToClose(); void aboutToClose();
void cleanup(); void cleanup();