nextcloud-desktop/src/libsync/discoveryphase.h

206 lines
6.3 KiB
C
Raw Normal View History

/*
* Copyright (C) by Olivier Goffart <ogoffart@woboq.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#pragma once
#include <QObject>
#include <QElapsedTimer>
#include <QStringList>
#include <csync.h>
#include <QMap>
#include "networkjobs.h"
#include <QMutex>
#include <QWaitCondition>
#include <deque>
#include "syncoptions.h"
2014-11-10 00:34:07 +03:00
namespace OCC {
class Account;
/**
* The Discovery Phase was once called "update" phase in csync terms.
* Its goal is to look at the files in one of the remote and check compared to the db
* if the files are new, or changed.
*/
2017-05-17 11:55:42 +03:00
struct DiscoveryDirectoryResult
{
QString path;
QString msg;
int code = EIO;
std::deque<std::unique_ptr<csync_file_stat_t>> list;
2015-01-20 20:49:49 +03:00
};
2015-06-29 19:56:09 +03:00
/**
* @brief The DiscoverySingleDirectoryJob class
*
* Run in the main thread, reporting to the DiscoveryJobMainThread object
*
2015-06-29 19:56:09 +03:00
* @ingroup libsync
*/
2017-05-17 11:55:42 +03:00
class DiscoverySingleDirectoryJob : public QObject
{
Q_OBJECT
public:
explicit DiscoverySingleDirectoryJob(const AccountPtr &account, const QString &path, QObject *parent = nullptr);
// Specify thgat this is the root and we need to check the data-fingerprint
void setIsRootPath() { _isRootPath = true; }
void start();
void abort();
std::deque<std::unique_ptr<csync_file_stat_t>> &&takeResults() { return std::move(_results); }
// This is not actually a network job, it is just a job
signals:
void firstDirectoryPermissions(RemotePermissions);
void etagConcatenation(const QString &);
void etag(const QString &);
void finishedWithResult();
void finishedWithError(int csyncErrnoCode, const QString &msg);
private slots:
2017-05-17 11:55:42 +03:00
void directoryListingIteratedSlot(QString, const QMap<QString, QString> &);
void lsJobFinishedWithoutErrorSlot();
2017-05-17 11:55:42 +03:00
void lsJobFinishedWithErrorSlot(QNetworkReply *);
private:
std::deque<std::unique_ptr<csync_file_stat_t>> _results;
QString _subPath;
QString _etagConcatenation;
QString _firstEtag;
AccountPtr _account;
// The first result is for the directory itself and need to be ignored.
// This flag is true if it was already ignored.
bool _ignoredFirst;
// Set to true if this is the root path and we need to check the data-fingerprint
bool _isRootPath;
// If this directory is an external storage (The first item has 'M' in its permission)
bool _isExternalStorage;
// If set, the discovery will finish with an error
QString _error;
QPointer<LsColJob> _lsColJob;
public:
QByteArray _dataFingerprint;
};
// Lives in main thread. Deleted by the SyncEngine
class DiscoveryJob;
2017-05-17 11:55:42 +03:00
class DiscoveryMainThread : public QObject
{
Q_OBJECT
QPointer<DiscoveryJob> _discoveryJob;
QPointer<DiscoverySingleDirectoryJob> _singleDirJob;
2015-05-21 15:50:30 +03:00
QString _pathPrefix; // remote path
AccountPtr _account;
2015-01-20 20:49:49 +03:00
DiscoveryDirectoryResult *_currentDiscoveryDirectoryResult;
2015-05-21 15:50:30 +03:00
qint64 *_currentGetSizeResult;
bool _firstFolderProcessed;
public:
2017-05-17 11:55:42 +03:00
DiscoveryMainThread(AccountPtr account)
: QObject()
, _account(account)
, _currentDiscoveryDirectoryResult(nullptr)
, _currentGetSizeResult(nullptr)
2017-05-17 11:55:42 +03:00
, _firstFolderProcessed(false)
{
}
void abort();
QByteArray _dataFingerprint;
public slots:
// From DiscoveryJob:
2017-05-17 11:55:42 +03:00
void doOpendirSlot(const QString &url, DiscoveryDirectoryResult *);
void doGetSizeSlot(const QString &path, qint64 *result);
// From Job:
void singleDirectoryJobResultSlot();
void singleDirectoryJobFinishedWithErrorSlot(int csyncErrnoCode, const QString &msg);
void singleDirectoryJobFirstDirectoryPermissionsSlot(RemotePermissions);
2015-05-21 15:50:30 +03:00
void slotGetSizeFinishedWithError();
2017-05-17 11:55:42 +03:00
void slotGetSizeResult(const QVariantMap &);
signals:
void etag(const QString &);
void etagConcatenation(const QString &);
2017-05-17 11:55:42 +03:00
public:
2017-05-17 11:55:42 +03:00
void setupHooks(DiscoveryJob *discoveryJob, const QString &pathPrefix);
};
2015-06-29 19:56:09 +03:00
/**
* @brief The DiscoveryJob class
*
* Lives in the other thread, deletes itself in !start()
*
2015-06-29 19:56:09 +03:00
* @ingroup libsync
*/
2017-05-17 11:55:42 +03:00
class DiscoveryJob : public QObject
{
Q_OBJECT
friend class DiscoveryMainThread;
2017-05-17 11:55:42 +03:00
CSYNC *_csync_ctx;
QElapsedTimer _lastUpdateProgressCallbackCall;
/**
2015-05-21 15:50:30 +03:00
* return true if the given path should be ignored,
* false if the path should be synced
*/
bool isInSelectiveSyncBlackList(const QByteArray &path) const;
static int isInSelectiveSyncBlackListCallback(void *, const QByteArray &);
bool checkSelectiveSyncNewFolder(const QString &path, RemotePermissions rp);
static int checkSelectiveSyncNewFolderCallback(void *data, const QByteArray &path, RemotePermissions rm);
// Just for progress
2017-05-17 11:55:42 +03:00
static void update_job_update_callback(bool local,
const char *dirname,
void *userdata);
// For using QNAM to get the directory listings
2017-05-17 11:55:42 +03:00
static csync_vio_handle_t *remote_vio_opendir_hook(const char *url,
void *userdata);
static std::unique_ptr<csync_file_stat_t> remote_vio_readdir_hook(csync_vio_handle_t *dhandle,
2017-05-17 11:55:42 +03:00
void *userdata);
static void remote_vio_closedir_hook(csync_vio_handle_t *dhandle,
void *userdata);
QMutex _vioMutex;
QWaitCondition _vioWaitCondition;
public:
explicit DiscoveryJob(CSYNC *ctx, QObject *parent = nullptr)
2017-05-17 11:55:42 +03:00
: QObject(parent)
, _csync_ctx(ctx)
{
}
QStringList _selectiveSyncBlackList;
2015-05-21 15:50:30 +03:00
QStringList _selectiveSyncWhiteList;
SyncOptions _syncOptions;
Q_INVOKABLE void start();
signals:
void finished(int result);
void folderDiscovered(bool local, QString folderUrl);
// After the discovery job has been woken up again (_vioWaitCondition)
2017-05-17 11:55:42 +03:00
void doOpendirSignal(QString url, DiscoveryDirectoryResult *);
2015-05-21 15:50:30 +03:00
void doGetSizeSignal(const QString &path, qint64 *result);
// A new folder was discovered and was not synced because of the confirmation feature
void newBigFolder(const QString &folder, bool isExternal);
};
}