summaryrefslogtreecommitdiff
path: root/distfoldd/distfolder.cc
diff options
context:
space:
mode:
Diffstat (limited to 'distfoldd/distfolder.cc')
-rw-r--r--distfoldd/distfolder.cc200
1 files changed, 200 insertions, 0 deletions
diff --git a/distfoldd/distfolder.cc b/distfoldd/distfolder.cc
new file mode 100644
index 0000000..211aafe
--- /dev/null
+++ b/distfoldd/distfolder.cc
@@ -0,0 +1,200 @@
+#include <QtCore/QStringList>
+
+#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<QSslSocket*>(_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;
+ }
+ }
+}