#pragma once #include "nvcomputer.h" #include "nvpairingmanager.h" #include #include #include #include #include #include #include #include #include #include class MdnsPendingComputer : public QObject { Q_OBJECT public: explicit MdnsPendingComputer(QMdnsEngine::Server* server, QMdnsEngine::Cache* cache, const QMdnsEngine::Service& service) : m_Hostname(service.hostname()), m_Resolver(server, m_Hostname, cache) { connect(&m_Resolver, &QMdnsEngine::Resolver::resolved, this, &MdnsPendingComputer::handleResolvedAddress); } QString hostname() { return m_Hostname; } private slots: void handleResolvedTimeout() { Q_ASSERT(!m_Addresses.isEmpty()); emit resolvedHost(this, m_Addresses); } void handleResolvedAddress(const QHostAddress& address) { qInfo() << "Resolved" << hostname() << "to" << address; m_Addresses.push_back(address); // Now that we got an address, start a timer to wait for more // addresses to come in before reporting them if (m_Addresses.count() == 1) { QTimer::singleShot(1000, this, SLOT(handleResolvedTimeout())); } } signals: void resolvedHost(MdnsPendingComputer*,QVector&); private: QByteArray m_Hostname; QMdnsEngine::Resolver m_Resolver; QVector m_Addresses; }; class ComputerPollingEntry { public: ComputerPollingEntry() : m_ActiveThread(nullptr) { } virtual ~ComputerPollingEntry() { interrupt(); // interrupt() should have taken care of this Q_ASSERT(m_ActiveThread == nullptr); for (QThread* thread : m_InactiveList) { thread->wait(); delete thread; } } bool isActive() { cleanInactiveList(); return m_ActiveThread != nullptr; } void setActiveThread(QThread* thread) { cleanInactiveList(); Q_ASSERT(!isActive()); m_ActiveThread = thread; } void interrupt() { cleanInactiveList(); if (m_ActiveThread != nullptr) { // Interrupt the active thread m_ActiveThread->requestInterruption(); // Place it on the inactive list awaiting death m_InactiveList.append(m_ActiveThread); m_ActiveThread = nullptr; } } private: void cleanInactiveList() { QMutableListIterator i(m_InactiveList); // Reap any threads that have finished while (i.hasNext()) { i.next(); QThread* thread = i.value(); if (thread->isFinished()) { delete thread; i.remove(); } } } QThread* m_ActiveThread; QList m_InactiveList; }; class ComputerManager : public QObject { Q_OBJECT friend class DeferredHostDeletionTask; friend class PendingAddTask; public: explicit ComputerManager(QObject *parent = nullptr); virtual ~ComputerManager(); Q_INVOKABLE void startPolling(); Q_INVOKABLE void stopPollingAsync(); Q_INVOKABLE void addNewHost(QString address, bool mdns, QHostAddress mdnsIpv6Address = QHostAddress()); void pairHost(NvComputer* computer, QString pin); void quitRunningApp(NvComputer* computer); QVector getComputers(); // computer is deleted inside this call void deleteHost(NvComputer* computer); signals: void computerStateChanged(NvComputer* computer); void pairingCompleted(NvComputer* computer, QString error); void computerAddCompleted(QVariant success); void quitAppCompleted(QVariant error); private slots: void handleAboutToQuit(); void handleComputerStateChanged(NvComputer* computer); void handleMdnsServiceResolved(MdnsPendingComputer* computer, QVector& addresses); private: void saveHosts(); QHostAddress getBestGlobalAddressV6(QVector& addresses); void startPollingComputer(NvComputer* computer); int m_PollingRef; QReadWriteLock m_Lock; QMap m_KnownHosts; QMap m_PollEntries; QMdnsEngine::Server m_MdnsServer; QMdnsEngine::Browser* m_MdnsBrowser; QMdnsEngine::Cache m_MdnsCache; QVector m_PendingResolution; };