#include #include "clientagent.h" #include "serveragent.h" #include "distfolder.h" DistFolder::DistFolder(const QUuid& uuid, const QString& localPath, QObject *parent) : QObject(parent), _uuid(uuid), _localPath(localPath), _mtime(), _mtimeChanged(false), _watcher(new Watcher(localPath, this)), _server(new Server(this)), _discoverer(new Discoverer(uuid, _server->serverPort(), QString("Files on %1").arg(_localPath.canonicalPath()), this)), _syncFlags(Agent::SYNC_NORMAL), _numAgents(0) { Q_ASSERT(_localPath.isReadable()); connect(_watcher, SIGNAL(pathAdded(QString)), SLOT(handlePathAdded(QString))); connect(_watcher, SIGNAL(pathChanged(QString)), SLOT(handlePathChanged(QString))); connect(_watcher, SIGNAL(pathRemoved(QString)), SLOT(handlePathRemoved(QString))); updateLastModTime(); connect(_discoverer, SIGNAL(foundMoreRecentHost(QHostAddress,uint,QDateTime)), SLOT(handleMoreRecentHost(QHostAddress,uint,QDateTime))); connect(_server, SIGNAL(newConnection()), SLOT(handleNewConnection())); qDebug() << "Ready Folder UUID:" << _uuid; } bool DistFolder::readOnlySync() const { return _syncFlags & Agent::SYNC_READ_ONLY; } void DistFolder::setReadOnlySync(bool read_only) { if (read_only) { qDebug() << "Enabling read only sync"; _syncFlags |= Agent::SYNC_READ_ONLY; } else { _syncFlags &= ~Agent::SYNC_READ_ONLY; } } bool DistFolder::pullMode() const { return _syncFlags & Agent::SYNC_PULL; } void DistFolder::setPullMode(bool pull_mode) { if (pull_mode) { qDebug() << "Enabling pull sync"; _syncFlags |= Agent::SYNC_PULL; } else { _syncFlags &= ~Agent::SYNC_PULL; } updateLastModTime(); } bool DistFolder::compress() const { return _syncFlags & Agent::SYNC_COMPRESS; } void DistFolder::setCompress(bool compress) { if (compress) { qDebug() << "Enabling compression"; _syncFlags |= Agent::SYNC_COMPRESS; } else { _syncFlags &= ~Agent::SYNC_COMPRESS; } } QDateTime DistFolder::scanLastModTime() { return scanLastModTime(_localPath); } void DistFolder::updateLastModTime(const QDateTime& dt) { QDateTime curMtime = _mtime; if (pullMode()) { _mtime = QDateTime::fromTime_t(0); // Force being the puller for the next sync } else { if (dt.isNull()) { _mtime = scanLastModTime(); } else if (dt > _mtime) { _mtime = dt; } } if (_mtime != curMtime) { if (_numAgents > 0) { _mtimeChanged = true; } else { _discoverer->setLastModifiedTime(_mtime); _mtimeChanged = false; } } } QDateTime DistFolder::scanLastModTime(const QDir& dir) { QFileInfoList list = dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot); QDateTime max = QFileInfo(dir.absolutePath()).lastModified(); foreach (const QFileInfo &info, list) { QDateTime mtime; if (info.isDir()) { mtime = scanLastModTime(QDir(info.absoluteFilePath())); } else { mtime = info.lastModified(); } if (mtime > max) { max = mtime; } } return max; } void DistFolder::handleNewConnection() { qDebug() << "Incoming connection"; ServerAgent *agent = new ServerAgent(static_cast(_server->nextPendingConnection()), _localPath, _syncFlags, this); connect(agent, SIGNAL(destroyed()), SLOT(handleDestroyedAgent())); _numAgents++; qDebug() << "Num agents" << _numAgents; } void DistFolder::handlePathAdded(const QString &path) { QFileInfo info(path); qDebug() << "added: " << path; if (info.lastModified() > _mtime) { updateLastModTime(info.lastModified()); } } void DistFolder::handlePathChanged(const QString &path) { QFileInfo info(path); qDebug() << "changed: " << path; if (info.lastModified() > _mtime) { updateLastModTime(info.lastModified()); } } void DistFolder::handlePathRemoved(const QString &path) { QFileInfo info(path); qDebug() << "removed: " << path; // Find a parent that has not been removed const QString base_path = _localPath.absolutePath(); do { info = QFileInfo(info.absolutePath()); } while (!info.exists() && // Until it exists and as long as we are under the base dir. info.absoluteFilePath().startsWith(base_path)); if (info.lastModified() > _mtime) { updateLastModTime(info.lastModified()); } } void DistFolder::handleMoreRecentHost(const QHostAddress &address, uint port, const QDateTime &dateTime) { Q_UNUSED(dateTime); if (_numAgents == 0) { qDebug() << "Trying to connect to" << address.toString() << port; ClientAgent *agent = new ClientAgent(address, port, _localPath, _syncFlags, this); connect(agent, SIGNAL(destroyed()), SLOT(handleDestroyedAgent())); connect(agent, SIGNAL(finished()), SLOT(handleClientFinished())); _numAgents++; qDebug() << "Num agents" << _numAgents; } else { qDebug() << "Busy but a more recent host was found"; // TODO } } void DistFolder::handleClientFinished() { if (pullMode()) { // Stop pulling once a succesful sync is done qDebug() << "Stopping pull mode"; setPullMode(false); } } void DistFolder::handleDestroyedAgent() { _numAgents--; qDebug() << "Num agents" << _numAgents; if (_numAgents == 0) { // All sync agents have finished if (_mtimeChanged) { _discoverer->setLastModifiedTime(_mtime); _mtimeChanged = false; } } }