#include "AppController.h" #include #include #include #include #include #include #include AppController::AppController(QObject* parent) : QObject(parent) , m_settings(new LocalSend::Settings(this)) , m_security(new LocalSend::SecurityContext(this)) , m_discovery(new LocalSend::DiscoveryManager(this)) , m_server(new LocalSend::HttpServer(this)) , m_sessions(new LocalSend::SessionManager(this)) { } AppController::~AppController() { stopDiscovery(); } void AppController::initialize() { m_security->initialize(); LocalSend::InfoDto info = buildInfoDto(); m_server->setLocalInfo(info, m_security->fingerprint()); m_discovery->setLocalInfo(info, m_security->fingerprint(), m_settings->port(), m_settings->https() ? LocalSend::ProtocolType::Https : LocalSend::ProtocolType::Http); if (m_server->start(m_settings->port(), m_settings->https())) { emit serverRunningChanged(); } connect(m_discovery, &LocalSend::DiscoveryManager::deviceDiscovered, this, &AppController::onDeviceDiscovered); connect(m_discovery, &LocalSend::DiscoveryManager::deviceLost, this, &AppController::onDeviceLost); connect(m_server, &LocalSend::HttpServer::registerRequest, this, &AppController::onRegisterRequest); connect(m_server, &LocalSend::HttpServer::prepareUploadRequest, this, &AppController::onPrepareUploadRequest); connect(m_server, &LocalSend::HttpServer::uploadRequest, this, &AppController::onUploadRequest); connect(m_sessions, &LocalSend::SessionManager::receiveSessionAccepted, this, &AppController::onSessionAccepted); connect(m_sessions, &LocalSend::SessionManager::receiveSessionDeclined, this, &AppController::onSessionDeclined); connect(m_sessions, &LocalSend::SessionManager::receiveProgress, this, &AppController::onReceiveProgress); connect(m_sessions, &LocalSend::SessionManager::receiveSessionCompleted, this, &AppController::onReceiveCompleted); startDiscovery(); } LocalSend::InfoDto AppController::buildInfoDto() const { LocalSend::InfoDto info; info.alias = m_settings->alias(); info.version = m_settings->version(); info.deviceModel = m_settings->deviceModel(); info.deviceType = m_settings->deviceType(); info.download = false; return info; } QString AppController::alias() const { return m_settings->alias(); } void AppController::setAlias(const QString& alias) { if (m_settings->alias() != alias) { m_settings->setAlias(alias); emit aliasChanged(); } } quint16 AppController::port() const { return m_settings->port(); } void AppController::setPort(quint16 port) { if (m_settings->port() != port) { m_settings->setPort(port); emit portChanged(); } } QString AppController::downloadPath() const { return m_settings->downloadDir(); } void AppController::setDownloadPath(const QString& path) { if (m_settings->downloadDir() != path) { m_settings->setDownloadDir(path); emit downloadPathChanged(); } } bool AppController::quickSave() const { return m_settings->quickSave(); } void AppController::setQuickSave(bool enabled) { if (m_settings->quickSave() != enabled) { m_settings->setQuickSave(enabled); emit quickSaveChanged(); } } QVariantList AppController::devices() const { QVariantList result; for (const LocalSend::Device& device : m_devices) { QVariantMap map; map[QStringLiteral("ip")] = device.ip; map[QStringLiteral("port")] = device.port; map[QStringLiteral("alias")] = device.alias; map[QStringLiteral("fingerprint")] = device.fingerprint; map[QStringLiteral("deviceModel")] = device.deviceModel; map[QStringLiteral("deviceType")] = LocalSend::deviceTypeToString(device.deviceType); result.append(map); } return result; } bool AppController::serverRunning() const { return m_server->isRunning(); } void AppController::startDiscovery() { m_discovery->start(); } void AppController::stopDiscovery() { m_discovery->stop(); } void AppController::refreshDevices() { m_discovery->startScan(); } void AppController::acceptReceive(const QString& sessionId) { qDebug() << "[AppController] acceptReceive called with sessionId:" << sessionId; LocalSend::ReceiveSession session = m_sessions->receiveSession(sessionId); if (session.sessionId.isEmpty()) { qWarning() << "[AppController] Session not found for sessionId:" << sessionId; return; } QString baseDir = downloadPath(); QDir dir(baseDir); if (!dir.exists()) { dir.mkpath(QStringLiteral(".")); } QMap destinationPaths; for (auto it = session.files.constBegin(); it != session.files.constEnd(); ++it) { QString filePath = generateUniqueFilePath(baseDir, it->file.fileName); destinationPaths.insert(it.key(), filePath); qDebug() << "[AppController] File" << it.key() << "->" << filePath; } m_sessions->acceptReceiveSession(sessionId, destinationPaths); } void AppController::declineReceive(const QString& sessionId) { qDebug() << "[AppController] declineReceive called with sessionId:" << sessionId; m_sessions->declineReceiveSession(sessionId); } QString AppController::generateUniqueFilePath(const QString& baseDir, const QString& fileName) const { QString filePath = baseDir + QDir::separator() + fileName; QFileInfo info(filePath); if (!info.exists()) { return filePath; } QString baseName = info.completeBaseName(); QString suffix = info.suffix(); int counter = 1; while (info.exists()) { QString newName = QString(QStringLiteral("%1 (%2)")).arg(baseName).arg(counter); if (!suffix.isEmpty()) { newName += QStringLiteral(".") + suffix; } filePath = baseDir + QDir::separator() + newName; info.setFile(filePath); counter++; } return filePath; } void AppController::onDeviceDiscovered(const LocalSend::Device& device) { m_devices.insert(device.fingerprint, device); emit devicesChanged(); } void AppController::onDeviceLost(const QString& fingerprint) { m_devices.remove(fingerprint); emit devicesChanged(); } void AppController::onRegisterRequest(const LocalSend::RegisterDto& dto, const QHostAddress& sender) { qDebug() << "[AppController] onRegisterRequest from:" << sender.toString() << "alias:" << dto.alias << "fingerprint:" << dto.fingerprint; LocalSend::Device device; device.ip = sender.toString(); device.port = dto.port; device.protocol = dto.protocol; device.alias = dto.alias; device.fingerprint = dto.fingerprint; device.deviceModel = dto.deviceModel; device.deviceType = dto.deviceType; device.version = dto.version; device.download = dto.download; device.lastSeen = QDateTime::currentDateTime(); m_devices.insert(device.fingerprint, device); emit devicesChanged(); } void AppController::onPrepareUploadRequest(const QString& httpSessionId, const LocalSend::PrepareUploadRequestDto& dto, const QHostAddress& sender) { qDebug() << "[AppController] onPrepareUploadRequest received, httpSessionId:" << httpSessionId; LocalSend::Device device; device.ip = sender.toString(); device.alias = dto.info.alias; device.fingerprint = dto.info.fingerprint; device.deviceModel = dto.info.deviceModel; device.deviceType = dto.info.deviceType; device.version = dto.info.version; QString sessionId = m_sessions->createReceiveSession(device, dto.files, httpSessionId); qDebug() << "[AppController] Created receive session, sessionId:" << sessionId; QVariantList filesList; for (auto it = dto.files.constBegin(); it != dto.files.constEnd(); ++it) { QVariantMap file; file[QStringLiteral("id")] = it.key(); file[QStringLiteral("fileName")] = it.value().fileName; file[QStringLiteral("size")] = it.value().size; file[QStringLiteral("fileType")] = it.value().fileType; filesList.append(file); } emit receiveRequest(sessionId, dto.info.alias, sender.toString(), filesList); } void AppController::onUploadRequest(const QString& sessionId, const QString& fileId, const QString& token, const QByteArray& data) { LocalSend::ReceiveSession session = m_sessions->receiveSession(sessionId); if (session.sessionId.isEmpty()) { return; } if (!session.files.contains(fileId)) { return; } const LocalSend::FileTransfer& transfer = session.files[fileId]; if (transfer.token != token) { emit receiveError(sessionId, QStringLiteral("Invalid token")); return; } QString filePath = transfer.destinationPath; if (filePath.isEmpty()) { emit receiveError(sessionId, QStringLiteral("No destination path")); return; } QFile file(filePath); if (!file.open(QIODevice::WriteOnly)) { emit receiveError(sessionId, QStringLiteral("Cannot open file: ") + file.errorString()); return; } qint64 written = file.write(data); file.close(); if (written != data.size()) { m_sessions->failReceiveFile(sessionId, fileId); emit receiveError(sessionId, QStringLiteral("Write error")); return; } m_sessions->updateReceiveProgress(sessionId, fileId, written); if (written >= transfer.file.size) { m_sessions->completeReceiveFile(sessionId, fileId); } } void AppController::onSessionAccepted(const QString& sessionId, const QMap& tokens) { qDebug() << "[AppController] onSessionAccepted, sessionId:" << sessionId; qDebug() << "[AppController] Tokens:" << tokens; m_server->respondToPrepareUpload(sessionId, true, tokens); } void AppController::onSessionDeclined(const QString& sessionId) { qDebug() << "[AppController] onSessionDeclined, sessionId:" << sessionId; m_server->respondToPrepareUpload(sessionId, false); } void AppController::onReceiveProgress(const QString& sessionId, const QString& fileId, double progress) { emit receiveProgress(sessionId, fileId, progress); } void AppController::onReceiveCompleted(const QString& sessionId) { emit receiveCompleted(sessionId); }