MauiKit File Browsing

syncing.cpp
1#include "syncing.h"
2#include "fmstatic.h"
3
4#include <QDir>
5#include <QEventLoop>
6#include <QFileInfo>
7#include <QTimer>
8#include <QDebug>
9
10#include "WebDAVClient.hpp"
11#include "WebDAVItem.hpp"
12#include "WebDAVReply.hpp"
13
14#include <KLocalizedString>
15
17{
18 this->setCredentials(this->host, this->user, this->password);
19}
20
21void Syncing::listContent(const QUrl &path, const QStringList &filters, const int &depth)
22{
23 this->currentPath = path;
24
25 auto url = QUrl(path).path().replace(user, QStringLiteral(""));
26 this->listDirOutputHandler(this->client->listDir(url, static_cast<ListDepthEnum>(depth)), filters);
27}
28
29void Syncing::setCredentials(const QString &server, const QString &user, const QString &password)
30{
31 this->host = server;
32 this->user = user;
33 this->password = password;
34
35 this->client = new WebDAVClient(this->host, this->user, this->password);
36}
37
38void Syncing::listDirOutputHandler(WebDAVReply *reply, const QStringList &filters)
39{
40 connect(reply, &WebDAVReply::listDirResponse, this, [=](QNetworkReply *, QList<WebDAVItem> items) {
41 // qDebug() << "URL :" << listDirReply->url();
42 // qDebug() << "Received List of" << items.length() << "items";
43 // qDebug() << endl << "---------------------------------------";
44 FMH::MODEL_LIST list;
45 for (WebDAVItem item : items) {
46 const auto url = QUrl(item.getHref()).toString();
47
48 QString path = QString(FMStatic::PATHTYPE_URI[FMStatic::PATHTYPE_KEY::CLOUD_PATH] + this->user + QStringLiteral("/")) + QString(url).replace(QStringLiteral("/remote.php/webdav/"), QStringLiteral(""));
49
50 auto displayName = item.getContentType().isEmpty() ? QString(url).replace(QStringLiteral("/remote.php/webdav/"), QStringLiteral("")).replace(QStringLiteral("/"), QStringLiteral("")) : QString(path).right(path.length() - path.lastIndexOf(QStringLiteral("/")) - 1);
51
52 // qDebug()<< "PATHS:" << path << this->currentPath;
53
54 if (QString(url).replace(QStringLiteral("/remote.php/webdav/"), QStringLiteral("")).isEmpty() || path == this->currentPath.toString())
55 continue;
56
57 // qDebug()<< "FILTERING "<< filters << QString(displayName).right(displayName.length() - displayName.lastIndexOf("."));
58 if (!filters.isEmpty() && !filters.contains(QStringLiteral("*") + QString(displayName).right(displayName.length() - displayName.lastIndexOf(QStringLiteral(".")))))
59 continue;
60
61 list << FMH::MODEL {{FMH::MODEL_KEY::LABEL, displayName},
62 {FMH::MODEL_KEY::NAME, item.getDisplayName()},
63 {FMH::MODEL_KEY::DATE, item.getCreationDate().toString(Qt::TextDate)},
64 {FMH::MODEL_KEY::MODIFIED, item.getLastModified()},
65 {FMH::MODEL_KEY::MIME, item.getContentType().isEmpty() ? QStringLiteral("inode/directory") : item.getContentType()},
66 {FMH::MODEL_KEY::ICON, FMStatic::getIconName(QUrl(url))},
67 {FMH::MODEL_KEY::SIZE, QString::number(item.getContentLength())},
68 {FMH::MODEL_KEY::PATH, path},
69 {FMH::MODEL_KEY::URL, url},
70 {FMH::MODEL_KEY::THUMBNAIL, item.getContentType().isEmpty() ? url : this->getCacheFile(QUrl(url)).toString()}};
71 }
72 Q_EMIT this->listReady(list, this->currentPath);
73 });
74 connect(reply, &WebDAVReply::error, this, [=](QNetworkReply::NetworkError err) {
75 // qDebug() << "ERROR" << err;
76 this->emitError(err);
77 });
78}
79
80QUrl Syncing::getCacheFile(const QUrl &path)
81{
82// const auto directory = FM::resolveUserCloudCachePath(this->host, this->user);
83 const auto directory = QStringLiteral("");
84 const auto file = directory + path.toString().replace(QStringLiteral("remote.php/webdav/"), QStringLiteral(""));
85
86 qDebug() << "resolving file" << file;
87
88 if (FMH::fileExists(QUrl(file)))
89 return QUrl(file);
90 else
91 return path;
92}
93
94void Syncing::download(const QUrl &path)
95{
96 QString url = QString(path.toString()).replace(QStringLiteral("remote.php/webdav/"), QStringLiteral(""));
97
98 WebDAVReply *reply = this->client->downloadFrom(url);
99 qDebug() << "CURRENT CREDENTIALS" << this->host << this->user;
100 connect(reply, &WebDAVReply::downloadResponse, this, [=](QNetworkReply *reply)
101 {
102 if (!reply->error())
103 {
104 qDebug() << "\nDownload Success"
105 << "\nURL :" << reply->url() << "\nSize :" << reply->size();
106 auto file = reply->readAll();
107 const auto directory = FMStatic::CloudCachePath + QStringLiteral("opendesktop/") + this->user;
108
109 QDir dir(directory);
110
111 if (!dir.exists())
112 dir.mkpath(QStringLiteral("."));
113
114 this->saveTo(file, QUrl(directory + url));
115 } else {
116 qDebug() << "ERROR(DOWNLOAD)" << reply->error() << reply->url() << url;
117 Q_EMIT this->error(reply->errorString());
118 }
119 });
120
121 connect(reply, &WebDAVReply::downloadProgressResponse, this, [=](qint64 bytesReceived, qint64 bytesTotal) {
122 int percent = ((float)bytesReceived / bytesTotal) * 100;
123
124 qDebug() << "\nReceived : " << bytesReceived << "\nTotal : " << bytesTotal << "\nPercent : " << percent;
125
126 Q_EMIT this->progress(percent);
127 });
128
129 connect(reply, &WebDAVReply::error, this, [=](QNetworkReply::NetworkError err) {
130 qDebug() << "ERROR" << err;
131 });
132}
133
134void Syncing::upload(const QUrl &path, const QUrl &filePath)
135{
136 if (!FMH::fileExists(filePath))
137 return;
138
139 qDebug() << "Copy to cloud. File exists" << path << filePath;
140
141 this->mFile.setFileName(filePath.toString());
142
143 if (this->mFile.open(QIODevice::ReadOnly)) {
144 qDebug() << "Copy to cloud. File could be opened";
145
146 WebDAVReply *reply = this->client->uploadTo(path.toString(), QFileInfo(filePath.toString()).fileName(), &this->mFile);
147
148 connect(reply, &WebDAVReply::uploadFinished, this, [=](QNetworkReply *reply) {
149 if (!reply->error()) {
150 qDebug() << "\nUpload Success"
151 << "\nURL :" << reply->url() << "\nSize :" << reply->size();
152
153 auto cachePath = this->saveToCache(filePath.toString(), path);
154
155 auto item = FMStatic::getFileInfoModel(QUrl(cachePath));
156 // item[FMH::MODEL_KEY::PATH] = this->currentPath+"/"+QFileInfo(filePath).fileName()+"/";
157
158 Q_EMIT this->uploadReady(item, this->currentPath);
159 } else {
160 qDebug() << "ERROR(UPLOAD)" << reply->error();
161 Q_EMIT this->error(reply->errorString());
162 }
163
164 if (!this->uploadQueue.isEmpty()) {
165 qDebug() << "UPLOAD QUEUE" << this->uploadQueue;
166 this->upload(path, QUrl(this->uploadQueue.takeLast()));
167 }
168 });
169
170 connect(reply, &WebDAVReply::error, this, [=](QNetworkReply::NetworkError err) {
171 qDebug() << "ERROR" << err;
172 this->emitError(err);
173 });
174 }
175}
176
177void Syncing::createDir(const QUrl &path, const QString &name)
178{
179 WebDAVReply *reply = this->client->createDir(path.toString(), name);
180
181 connect(reply, &WebDAVReply::createDirFinished, this, [=](QNetworkReply *reply) {
182 if (!reply->error()) {
183 qDebug() << "\nDir Created"
184 << "\nURL :" << reply->url();
185 FMH::MODEL dir = {{FMH::MODEL_KEY::LABEL, name},
186 {FMH::MODEL_KEY::DATE, QDateTime::currentDateTime().toString(Qt::TextDate)},
187 {FMH::MODEL_KEY::MIME, QStringLiteral("inode/directory")},
188 {FMH::MODEL_KEY::ICON, QStringLiteral("folder")},
189 {FMH::MODEL_KEY::PATH, this->currentPath.toString() + QStringLiteral("/") + name + QStringLiteral("/")}};
190 Q_EMIT this->dirCreated(dir, this->currentPath);
191 } else {
192 qDebug() << "ERROR(CREATE DIR)" << reply->error();
193 Q_EMIT this->error(reply->errorString());
194 }
195 });
196
197 connect(reply, &WebDAVReply::error, this, [=](QNetworkReply::NetworkError err) {
198 qDebug() << "ERROR" << err;
199 this->emitError(err);
200 });
201}
202
203void Syncing::emitError(const QNetworkReply::NetworkError &err)
204{
205 switch (err) {
207 Q_EMIT this->error(i18n("The remote server requires authentication to serve the content but the credentials provided were not accepted (if any)"));
208 break;
209
211 Q_EMIT this->error(i18n("the remote server refused the connection (the server is not accepting requests"));
212 break;
213
215 Q_EMIT this->error(i18n("the remote server closed the connection prematurely, before the entire reply was received and processed"));
216 break;
217
219 Q_EMIT this->error(i18n("the remote host name was not found (invalid hostname)"));
220 break;
221
223 Q_EMIT this->error(i18n("the connection to the remote server timed out"));
224 break;
225
227 Q_EMIT this->error(i18n("the operation was canceled via calls to abort() or close() before it was finished."));
228 break;
229
231 Q_EMIT this->error(i18n("the SSL/TLS handshake failed and the encrypted channel could not be established. The sslErrors() signal should have been emitted."));
232 break;
233
235 Q_EMIT this->error(
236 i18n("the connection was broken due to disconnection from the network, however the system has initiated roaming to another access point. The request should be resubmitted and will be processed as soon as the connection is re-established."));
237 break;
238
240 Q_EMIT this->error(i18n("the connection was broken due to disconnection from the network or failure to start the network."));
241 break;
242
244 Q_EMIT this->error(i18n("the background request is not currently allowed due to platform policy."));
245 break;
246
248 Q_EMIT this->error(i18n("while following redirects, the maximum limit was reached. The limit is by default set to 50 or as set by QNetworkRequest::setMaxRedirectsAllowed(). (This value was introduced in 5.6.)"));
249 break;
250
252 Q_EMIT this->error(i18n("while following redirects, the network access API detected a redirect from a encrypted protocol (https) to an unencrypted one (http)."));
253 break;
254
256 Q_EMIT this->error(i18n("the connection to the proxy server was refused (the proxy server is not accepting requests)"));
257 break;
258
260 Q_EMIT this->error(i18n("the proxy server closed the connection prematurely, before the entire reply was received and processed"));
261 break;
262
264 Q_EMIT this->error(i18n("the proxy host name was not found (invalid proxy hostname)"));
265 break;
266
268 Q_EMIT this->error(i18n("the connection to the proxy timed out or the proxy did not reply in time to the request sent"));
269 break;
270
272 Q_EMIT this->error(i18n("the proxy requires authentication in order to honour the request but did not accept any credentials offered (if any)"));
273 break;
274
276 Q_EMIT this->error(i18n("the access to the remote content was denied (similar to HTTP error 403)"));
277 break;
278
280 Q_EMIT this->error(i18n("the operation requested on the remote content is not permitted"));
281 break;
282
284 Q_EMIT this->error(i18n("the remote content was not found at the server (similar to HTTP error 404)"));
285 break;
286
288 Q_EMIT this->error(i18n("the request needed to be sent again, but this failed for example because the upload data could not be read a second time."));
289 break;
290
292 Q_EMIT this->error(i18n("the server is unable to handle the request at this time."));
293 break;
294
295 default:
296 Q_EMIT this->error(i18n("There was an unknown error with the remote server or your internet connection."));
297 }
298}
299
300void Syncing::saveTo(const QByteArray &array, const QUrl &path)
301{
302 QFile file(path.toLocalFile());
303
304 if (!file.exists()) {
305 QDir dir;
306 uint cut = path.toString().length() - path.toString().lastIndexOf(QStringLiteral("/")) - 1;
307 auto newPath = path.toString().right(cut);
308 dir.mkdir(path.toString().replace(newPath, QStringLiteral("")));
309 qDebug() << newPath << cut;
310
311 } else
312 file.remove();
313
314 file.open(QIODevice::WriteOnly);
315 file.write(array);
316 file.close();
317
318 Q_EMIT this->itemReady(FMStatic::getFileInfoModel(path), this->currentPath, this->signalType);
319 // Q_EMIT this->itemReady(FMH::getFileInfoModel(path));
320}
321
322QString Syncing::saveToCache(const QString &file, const QUrl &where)
323{
324 const auto directory = FMStatic::CloudCachePath + QStringLiteral("opendesktop/") + this->user + QStringLiteral("/") + where.toString();
325
326 QDir dir(directory);
327
328 if (!dir.exists())
329 dir.mkpath(QStringLiteral("."));
330
331 const auto newPath = directory + QStringLiteral("/") + QFileInfo(file).fileName();
332
333 if (QFile::copy(file, newPath))
334 return newPath;
335
336 return QString();
337}
338
339void Syncing::resolveFile(const FMH::MODEL &item, const Syncing::SIGNAL_TYPE &signalType)
340{
341 this->signalType = signalType;
342
343 const auto url = item[FMH::MODEL_KEY::URL];
344 const auto file = this->getCacheFile(QUrl(url));
345
346 if (FMH::fileExists(file)) {
347 const auto cacheFile = FMStatic::getFileInfoModel(file);
348
349 const auto dateCacheFile = QDateTime::fromString(cacheFile[FMH::MODEL_KEY::DATE], Qt::TextDate);
350 const auto dateCloudFile = QDateTime::fromString(QString(item[FMH::MODEL_KEY::MODIFIED]).replace(QStringLiteral("GMT"), QStringLiteral("")).simplified(), QStringLiteral("ddd, dd MMM yyyy hh:mm:ss"));
351
352 qDebug() << "FILE EXISTS ON CACHE" << dateCacheFile << dateCloudFile << QString(item[FMH::MODEL_KEY::MODIFIED]).replace(QStringLiteral("GMT"), QStringLiteral("")).simplified() << file;
353
354 if (dateCloudFile > dateCacheFile)
355 this->download(QUrl(url));
356 else
357 Q_EMIT this->itemReady(cacheFile, this->currentPath, this->signalType);
358
359 } else
360 this->download(QUrl(url));
361}
362
363void Syncing::setCopyTo(const QUrl &path)
364{
365 if (this->copyTo == path)
366 return;
367
368 this->copyTo = path;
369}
370
372{
373 return this->copyTo;
374}
375
377{
378 return this->user;
379}
380
382{
383 this->uploadQueue = list;
384}
385
static const QString getIconName(const QUrl &path)
Returns the icon name for certain file.
Definition fmstatic.cpp:618
static const QHash< PATHTYPE_KEY, QString > PATHTYPE_URI
Similar to PATHTYPE_SCHEME, but mapped with the complete scheme.
Definition fmstatic.h:369
static const FMH::MODEL getFileInfoModel(const QUrl &path)
getFileInfoModel
Definition fmstatic.cpp:560
static const QString CloudCachePath
Standard Cloud Cache location path
Definition fmstatic.h:398
@ CLOUD_PATH
A remote cloud server path.
Definition fmstatic.h:301
void setCredentials(const QString &server, const QString &user, const QString &password)
setCredentials
Definition syncing.cpp:29
QStringList uploadQueue
uploadQueue
Definition syncing.h:28
void download(const QUrl &path)
download
Definition syncing.cpp:94
void uploadReady(FMH::MODEL item, QUrl url)
uploadReady
Syncing(QObject *parent=nullptr)
Syncing.
Definition syncing.cpp:16
void upload(const QUrl &path, const QUrl &filePath)
upload
Definition syncing.cpp:134
void listContent(const QUrl &path, const QStringList &filters, const int &depth=1)
listContent
Definition syncing.cpp:21
void progress(int percent)
progress
void error(QString message)
error
void listReady(FMH::MODEL_LIST data, QUrl url)
listReady
QString localToAbstractCloudPath(const QString &url)
localToAbstractCloudPath
Definition syncing.cpp:386
void createDir(const QUrl &path, const QString &name)
createDir
Definition syncing.cpp:177
QUrl getCopyTo() const
getCopyTo
Definition syncing.cpp:371
QString getUser() const
getUser
Definition syncing.cpp:376
void setCopyTo(const QUrl &path)
setCopyTo
Definition syncing.cpp:363
void itemReady(FMH::MODEL item, QUrl url, Syncing::SIGNAL_TYPE &signalType)
itemReady
void setUploadQueue(const QStringList &list)
setUploadQueue
Definition syncing.cpp:381
void dirCreated(FMH::MODEL item, QUrl url)
dirCreated
void resolveFile(const FMH::MODEL &item, const Syncing::SIGNAL_TYPE &signalType)
resolveFile
Definition syncing.cpp:339
Represents an item in a remote cloud location.
Wraps the available actions for a remote item.
QString i18n(const char *text, const TYPE &arg...)
bool fileExists(const QUrl &path)
QString path(const QString &relativePath)
KIOCORE_EXPORT QString dir(const QString &fileClass)
QAction * cut(const QObject *recvr, const char *slot, QObject *parent)
QDateTime currentDateTime()
QDateTime fromString(QStringView string, QStringView format, QCalendar cal)
QString toString(QStringView format, QCalendar cal) const const
bool copy(const QString &fileName, const QString &newName)
bool open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags)
void setFileName(const QString &name)
QString fileName() const const
bool isEmpty() const const
value_type takeLast()
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool isEmpty() const const
qsizetype lastIndexOf(QChar ch, Qt::CaseSensitivity cs) const const
qsizetype length() const const
QString number(double n, char format, int precision)
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
QString right(qsizetype n) const const
QString simplified() const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
TextDate
QString path(ComponentFormattingOptions options) const const
QString toString(FormattingOptions options) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 4 2024 16:32:33 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.