From c3a1946675855b299a2b36550cdf2c2f69d153aa Mon Sep 17 00:00:00 2001 From: "Javier S. Pedro" Date: Mon, 17 Sep 2012 23:03:03 +0200 Subject: initial import --- distfoldd/clientagent.cc | 174 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 distfoldd/clientagent.cc (limited to 'distfoldd/clientagent.cc') diff --git a/distfoldd/clientagent.cc b/distfoldd/clientagent.cc new file mode 100644 index 0000000..f77a21a --- /dev/null +++ b/distfoldd/clientagent.cc @@ -0,0 +1,174 @@ +#include + +#include "clientagent.h" + +ClientAgent::ClientAgent(const QHostAddress& addr, uint port, const QDir& local_dir, SyncFlags flags, QObject *parent) : + Agent(new QSslSocket, local_dir, flags, parent) +{ + qDebug() << "Starting client agent at" << QDateTime::currentDateTime(); + _socket->setParent(this); // Can't set parent until QObject constructed + _socket->connectToHostEncrypted(addr.toString(), port); + sendMessage(MSG_HELLO); + _state = STATE_HELLO; +} + +void ClientAgent::handleMessage(MessageType msg, const QByteArray &data) +{ + qDebug() << "Client::handleMessage" << msg << data.size(); + switch (msg) { + case MSG_HELLO_REPLY: + Q_ASSERT(_state == STATE_HELLO); + qDebug() << "Hello reply"; + _state = STATE_FILE_LIST; + sendFileList(); + break; + case MSG_FILE_ACTIONS_REPLY: + Q_ASSERT(_state == STATE_FILE_LIST); + handleActionInfoList(decodeActionInfoList(data)); + break; + case MSG_PULL_FILE_REPLY: + Q_ASSERT(_state == STATE_FILE_ACTIONS && !_pendingActions.empty()); + handlePulledFile(data); + break; + default: + qWarning() << "Unknown message"; + break; + } +} + +void ClientAgent::sendFileList() +{ + QFileInfoList list = scanFiles(QDir(wireToLocalPath(_subPath))); + sendMessage(MSG_FILE_LIST, encodeFileInfoList(list)); +} + +void ClientAgent::handleActionInfoList(const RemoteActionInfoList &list) +{ + foreach (const RemoteActionInfo& info, list) { + switch (info.action()) { + case ACTION_NONE: + qDebug() << " = " << info.fileInfo().name(); + break; + case ACTION_PULL: + qDebug() << " < " << info.fileInfo().name(); + break; + case ACTION_PULL_METADATA: + qDebug() << " " << info.fileInfo().name(); + break; + case ACTION_PUSH_METADATA: + qDebug() << " >m" << info.fileInfo().name(); + break; + case ACTION_PUSH_DELETE: + qDebug() << " >d" << info.fileInfo().name(); + break; + } + } + + _pendingActions = list; + _state = STATE_FILE_ACTIONS; + executeNextAction(); +} + +void ClientAgent::executeNextAction() +{ + if (_pendingActions.empty()) { + qDebug() << "Done"; + emit finished(); + sendMessage(MSG_BYE); + _socket->flush(); + _socket->close(); + return; + } + + qDebug() << "Remaining actions" << _pendingActions.count(); + + const RemoteActionInfo& info = _pendingActions.first(); + const QString wire_path = info.fileInfo().name(); + const QString local_path = wireToLocalPath(wire_path); + switch (info.action()) { + case ACTION_PULL: + if (_flags & SYNC_READ_ONLY) break; + if (info.fileInfo().isDir()) { + if (!QDir().mkpath(local_path)) { + qWarning() << "Failed to create local path" << local_path; + } + } else { + sendMessage(MSG_PULL_FILE, encodeFileName(wire_path)); + return; // Wait for the pulled file message. + } + break; + case ACTION_PULL_METADATA: + if (_flags & SYNC_READ_ONLY) break; + setLocalFileDateTime(local_path, info.fileInfo().lastModified()); + break; + case ACTION_PULL_DELETE: + handleDeleteFile(wire_path); + break; + case ACTION_PUSH: + handlePushFile(wire_path); + break; + case ACTION_PUSH_METADATA: + sendMessage(MSG_PUSH_FILE_METADATA, + encodeFileInfoList(QFileInfoList() << QFileInfo(local_path))); + break; + case ACTION_PUSH_DELETE: + sendMessage(MSG_DELETE_FILE, encodeFileName(wire_path)); + break; + default: + qWarning() << "Unknown action" << info.action(); + break; + } + _pendingActions.removeFirst(); + executeNextAction(); +} + +void ClientAgent::handlePulledFile(const QByteArray &data) +{ + const RemoteActionInfo& info = _pendingActions.takeFirst(); + if (_flags & SYNC_READ_ONLY) return; + QString local_path(wireToLocalPath(info.fileInfo().name())); + QFile file(local_path); + if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + file.write(Compressor::decompress(data)); + file.close(); + setLocalFileDateTime(local_path, info.fileInfo().lastModified()); + } else { + qWarning() << "Failed to open" << file.fileName() << "for writing"; + } + executeNextAction(); +} + +void ClientAgent::handlePushFile(const QString &path) +{ + QFile file(wireToLocalPath(path)); + if (file.open(QIODevice::ReadOnly)) { + QByteArray file_data = file.readAll(); + if (_flags & SYNC_COMPRESS) file_data = Compressor::compress(file_data); + QByteArray ba = encodeFileNameItem(path) + file_data; + sendMessage(MSG_PUSH_FILE, ba); + } else { + qWarning() << "Failed to open file" << file.fileName() << "for reading"; + } +} + +void ClientAgent::handleDeleteFile(const QString &wire_path) +{ + if (_flags & SYNC_READ_ONLY) return; + QFileInfo local(wireToLocalPath(wire_path)); + QString local_path = local.absoluteFilePath(); + if (local.isDir()) { + if (!QDir().rmdir(local_path)) { + qWarning() << "Failed to remove local dir" << local_path; + } + } else { + if (!QDir().remove(local_path)) { + qWarning() << "Failed to remove local file" << local_path; + } + } +} -- cgit v1.2.3