Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
// SPDX-FileCopyrightText: 2024-2026 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later

Expand Down Expand Up @@ -360,7 +360,9 @@ void ActiveAccountNetwork::onStateChanged(NetworkManager::ActiveConnection::Stat
QSharedPointer<NetworkManager::Device> device;
for (auto devUni : activeConnection->devices()) {
NetworkManager::Device::Ptr dev = NetworkManager::findNetworkInterface(devUni);
if (!dev.isNull() && (device->type() == NetworkManager::Device::Type::Wifi && device->type() == NetworkManager::Device::Type::Ethernet)) {
// 判空的是 dev,不是尚未赋值的 device;类型条件是“有线或无线”
if (!dev.isNull() && (dev->type() == NetworkManager::Device::Type::Wifi
|| dev->type() == NetworkManager::Device::Type::Ethernet)) {
device = dev;
break;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,136 +1,145 @@
// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
// SPDX-FileCopyrightText: 2024-2026 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later

#include "networkhandler.h"
#include "networkconfig.h"
#include "accountmanager.h"
#include "constants.h"

Check warning on line 8 in network-service-plugin/src/accountnetwork/system/accountnetwork/networkhandler.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "constants.h" not found.

#include <NetworkManagerQt/Manager>
#include <NetworkManagerQt/ActiveConnection>
#include <NetworkManagerQt/WirelessDevice>
#include <NetworkManagerQt/WirelessSetting>
#include <NetworkManagerQt/WirelessSecuritySetting>
#include <NetworkManagerQt/WiredSetting>
#include <NetworkManagerQt/ActiveConnection>
#include <QTimer>

Check warning on line 10 in network-service-plugin/src/accountnetwork/system/accountnetwork/networkhandler.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QTimer> not found. Please note: Cppcheck does not need standard library headers to get proper results.

#include <iterator>

Check warning on line 12 in network-service-plugin/src/accountnetwork/system/accountnetwork/networkhandler.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <iterator> not found. Please note: Cppcheck does not need standard library headers to get proper results.

#include <NetworkManagerQt/Device>

Check warning on line 14 in network-service-plugin/src/accountnetwork/system/accountnetwork/networkhandler.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <NetworkManagerQt/Device> not found. Please note: Cppcheck does not need standard library headers to get proper results.

using namespace accountnetwork::systemservice;
using network::systemservice::DeviceSnapshot;
using network::systemservice::NetworkManagerProxy;

NetworkHandler::NetworkHandler(AccountManager *accountManager, NetworkConfig *conf, QObject *parent)
: QObject(parent)
, m_accountManager(accountManager)
, m_networkConfig(conf)
{
initDevices();
initConnection();
// 代理在 NM 线程,本对象在插件线程 —— AutoConnection 自动变成队列投递
NetworkManagerProxy *proxy = NetworkManagerProxy::instance();
m_devicesConnection = connect(proxy, &NetworkManagerProxy::devicesChanged,
this, &NetworkHandler::onDevicesChanged);
m_idConnection = connect(proxy, &NetworkManagerProxy::activeConnectionIdReady,
this, &NetworkHandler::onActiveConnectionIdReady);
onDevicesChanged();
}

void NetworkHandler::disconnectNetwork()
NetworkHandler::~NetworkHandler()
{
NetworkManager::Device::List devices = NetworkManager::networkInterfaces();
for (NetworkManager::Device::Ptr device : devices) {
if (device->type() != NetworkManager::Device::Type::Ethernet
&& device->type() != NetworkManager::Device::Type::Wifi)
continue;

NetworkManager::ActiveConnection::Ptr activeConnection = device->activeConnection();
if (activeConnection) {
QDBusPendingReply<> reply = NetworkManager::deactivateConnection(activeConnection->path());
reply.waitForFinished();
}
}
disconnect(m_devicesConnection);
disconnect(m_idConnection);
}

NetworkHandler::~NetworkHandler() = default;

void NetworkHandler::initDevices()
void NetworkHandler::disconnectNetwork()
{
NetworkManager::Device::List devices = NetworkManager::networkInterfaces();
for (NetworkManager::Device::Ptr device : devices) {
if (device->type() != NetworkManager::Device::Type::Wifi
&& device->type() != NetworkManager::Device::Type::Ethernet)
// D-Bus 调用的入口,运行在插件线程;写操作经代理排队到 NM 线程
NetworkManagerProxy *proxy = NetworkManagerProxy::instance();
const QList<DeviceSnapshot> devices = proxy->devices();
for (const DeviceSnapshot &device : devices) {
if (device.type != NetworkManager::Device::Type::Ethernet
&& device.type != NetworkManager::Device::Type::Wifi)
continue;

connect(device.data(), &NetworkManager::Device::activeConnectionChanged, device.data(), [ this, device ] {
deviceActiveHandler(device);
});
deviceActiveHandler(device);
}
}
if (device.activeConnectionUni.isEmpty())
continue;

void NetworkHandler::initConnection()
{
connect(NetworkManager::notifier(), &NetworkManager::Notifier::deviceAdded, this, &NetworkHandler::onDeviceAdded);
proxy->deactivateConnection(device.activeConnectionUni);
}
}

QString NetworkHandler::getSaveId(const QSharedPointer<NetworkManager::ActiveConnection> &activeConnection, bool isWireless)
// 代理每次刷新缓存都会发 devicesChanged(含设备状态变化)。
// 原实现通过 ActiveConnection::stateChanged 在 Activated 时记录配置,
// 这里等价地按“设备已激活且活跃连接变化”触发,避免重复写配置文件。
void NetworkHandler::onDevicesChanged()
{
// 这里只保存需要加密的网络
if (activeConnection.isNull())
return QString();

NetworkManager::ConnectionSettings::Ptr connectionSettings = activeConnection->connection()->settings();
if (isWireless) {
NetworkManager::WirelessSetting::Ptr wsSetting = connectionSettings->setting(NetworkManager::Setting::SettingType::Wireless)
.dynamicCast<NetworkManager::WirelessSetting>();
if (wsSetting) {
// 获取当前无线网络的ssid作为无线网络的ID,保存到配置文件中
return wsSetting->ssid();
}
return QString();
}
NetworkManagerProxy *proxy = NetworkManagerProxy::instance();
const QList<DeviceSnapshot> devices = proxy->devices();

// 如果是有线网络,则直接保存id
return connectionSettings->id();
}
QSet<QString> aliveDevices;
QSet<QString> aliveConnections;
aliveDevices.reserve(devices.size());
aliveConnections.reserve(devices.size());

QSharedPointer<NetworkManager::Device> NetworkHandler::getDeviceByInterfaceName(const QString &interfaceName) const
{
NetworkManager::Device::List devices = NetworkManager::networkInterfaces();
auto it = std::find_if(devices.begin(), devices.end(), [ interfaceName ](NetworkManager::Device::Ptr device) {
return interfaceName == device->interfaceName();
});
for (const DeviceSnapshot &device : devices) {
if (device.type != NetworkManager::Device::Type::Wifi
&& device.type != NetworkManager::Device::Type::Ethernet) {
continue;
}
aliveDevices.insert(device.uni);
if (!device.activeConnectionUni.isEmpty()) {
aliveConnections.insert(device.activeConnectionUni);
}

if (it == devices.end())
return nullptr;
// 只在设备真正激活后才记录;activeConnectionUni 在 Activating 阶段就已写入
if (device.state != NetworkManager::Device::Activated || device.activeConnectionUni.isEmpty()) {
continue;
}
// 同一条活跃连接只记录一次
if (m_savedConnections.value(device.uni) == device.activeConnectionUni) {
continue;
}
// 已经问过代理、结果还没回来
if (m_pendingQueries.contains(device.activeConnectionUni)) {
continue;
}
m_pendingQueries.insert(device.activeConnectionUni);
proxy->requestActiveConnectionId(device.activeConnectionUni,
device.type == NetworkManager::Device::Type::Wifi);
}

return (*it);
// 清理已消失的设备和查询
for (auto it = m_savedConnections.begin(); it != m_savedConnections.end();) {
it = aliveDevices.contains(it.key()) ? std::next(it) : m_savedConnections.erase(it);
}
for (auto it = m_pendingQueries.begin(); it != m_pendingQueries.end();) {
it = aliveConnections.contains(*it) ? std::next(it) : m_pendingQueries.erase(it);
}
}

void NetworkHandler::deviceActiveHandler(const QSharedPointer<NetworkManager::Device> &device)
void NetworkHandler::onActiveConnectionIdReady(const QString &activeConnectionUni, const QString &saveId)
{
NetworkManager::ActiveConnection::Ptr activeConnection = device->activeConnection();
if (activeConnection.isNull())
m_pendingQueries.remove(activeConnectionUni);
if (saveId.isEmpty() || m_accountManager->account().isEmpty()) {
// 设备稳定在 Activated 时不会再发 devicesChanged,只等就永远不会重试;
// 做有限次退避重试,避免账户网络映射静默丢失。
scheduleRetry();
return;
}

qCDebug(DSM) << "active connection changed:" << activeConnection->id();
connect(activeConnection.data(), &NetworkManager::ActiveConnection::stateChanged, activeConnection.data(), [ device, this, activeConnection ](NetworkManager::ActiveConnection::State state) {
if (state == NetworkManager::ActiveConnection::State::Activated) {
QString id = getSaveId(activeConnection, (device->type() == NetworkManager::Device::Type::Wifi));
qCDebug(DSM) << activeConnection->id() << "activated:" << id << "device:" << device->interfaceName()
<< "account name:" << m_accountManager->account();
// 连接成功的情况下,记录当前连接的网络的信息
if (!id.isEmpty() && !m_accountManager->account().isEmpty()) {
m_networkConfig->saveNetwork(m_accountManager->account(), id, device->interfaceName());
}
const QString account = m_accountManager->account();

// 用最新快照而非缓存的 m_devices:查询往返期间设备状态可能已经变了
const QList<DeviceSnapshot> devices = NetworkManagerProxy::instance()->devices();
for (const DeviceSnapshot &device : devices) {
if (device.activeConnectionUni != activeConnectionUni
|| device.state != NetworkManager::Device::Activated) {
continue;
}
});
qCDebug(DSM) << "activated:" << saveId << "device:" << device.interfaceName
<< "account name:" << account;
m_networkConfig->saveNetwork(account, saveId, device.interfaceName);
m_savedConnections.insert(device.uni, activeConnectionUni);
m_retryCount = 0;
return;
}
}

void NetworkHandler::onDeviceAdded(const QString &uni)
void NetworkHandler::scheduleRetry()
{
NetworkManager::Device::Ptr device = NetworkManager::findNetworkInterface(uni);
if (device.isNull())
if (m_retryScheduled || m_retryCount >= kMaxRetries) {
return;

if (device->type() != NetworkManager::Device::Type::Wifi
&& device->type() != NetworkManager::Device::Type::Ethernet)
return;

connect(device.data(), &NetworkManager::Device::activeConnectionChanged, device.data(), [ this, device ] {
deviceActiveHandler(device);
}
m_retryScheduled = true;
QTimer::singleShot(kRetryIntervalMs, this, [this] {
m_retryScheduled = false;
++m_retryCount;
onDevicesChanged();
});

deviceActiveHandler(device);
}
Original file line number Diff line number Diff line change
@@ -1,48 +1,62 @@
// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
// SPDX-FileCopyrightText: 2024-2026 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later

#ifndef NETWORKHANDLER_H
#define NETWORKHANDLER_H

#include <QObject>
#include "system/nmaccess.h"

Check warning on line 8 in network-service-plugin/src/accountnetwork/system/accountnetwork/networkhandler.h

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "system/nmaccess.h" not found.

namespace NetworkManager {
class ActiveConnection;
class Device;
}
#include <QHash>

Check warning on line 10 in network-service-plugin/src/accountnetwork/system/accountnetwork/networkhandler.h

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QHash> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QMetaObject>

Check warning on line 11 in network-service-plugin/src/accountnetwork/system/accountnetwork/networkhandler.h

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QMetaObject> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QObject>

Check warning on line 12 in network-service-plugin/src/accountnetwork/system/accountnetwork/networkhandler.h

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QObject> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QSet>

Check warning on line 13 in network-service-plugin/src/accountnetwork/system/accountnetwork/networkhandler.h

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QSet> not found. Please note: Cppcheck does not need standard library headers to get proper results.

namespace accountnetwork {
namespace systemservice {

class AccountManager;
class NetworkConfig;

// 账户网络的设备状态记录。
//
// 全程运行在插件线程:AccountManager / NetworkConfig 都是插件线程的对象,
// 在这里读写才不需要加锁。一切 NetworkManagerQt 访问都经 NetworkManagerProxy
// 完成——设备状态读快照,活跃连接 ID 走 requestActiveConnectionId() 异步取回。
class NetworkHandler : public QObject
{
Q_OBJECT

public:
NetworkHandler(AccountManager *accountManager, NetworkConfig *conf, QObject *parent = Q_NULLPTR);
~NetworkHandler();
void disconnectNetwork();

private:
void initDevices();
void initConnection();
QString getSaveId(const QSharedPointer<NetworkManager::ActiveConnection> &activeConnection, bool isWireless);
QSharedPointer<NetworkManager::Device> getDeviceByInterfaceName(const QString &interfaceName) const;
void deviceActiveHandler(const QSharedPointer<NetworkManager::Device> &device);
// 可在任意线程调用;写操作由代理排队到 NM 线程
void disconnectNetwork();

private slots:
void onDeviceAdded(const QString &uni);
private Q_SLOTS:

Check warning on line 37 in network-service-plugin/src/accountnetwork/system/accountnetwork/networkhandler.h

View workflow job for this annotation

GitHub Actions / cppcheck

There is an unknown macro here somewhere. Configuration is required. If Q_SLOTS is a macro then please configure it.
void onDevicesChanged();
void onActiveConnectionIdReady(const QString &activeConnectionUni, const QString &saveId);

private:
void scheduleRetry();

AccountManager *m_accountManager;
NetworkConfig *m_networkConfig;
// 设备 uni -> 已记录的活跃连接,避免每次缓存刷新都重写配置文件
QHash<QString, QString> m_savedConnections;
// 已向代理发出、尚未回来的活跃连接查询
QSet<QString> m_pendingQueries;
QMetaObject::Connection m_devicesConnection;
QMetaObject::Connection m_idConnection;
// 取不到连接 ID 时的有限次退避重试
static constexpr int kMaxRetries = 3;
static constexpr int kRetryIntervalMs = 5000;
int m_retryCount = 0;
bool m_retryScheduled = false;
};

}
}

#endif // NETWORKSERVICE_H
#endif // NETWORKHANDLER_H
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
// SPDX-FileCopyrightText: 2024-2026 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later

Expand Down Expand Up @@ -26,8 +26,6 @@ OwnerNetController::OwnerNetController(QObject *parent)
connect(m_accountManager, &AccountManager::accountRemoved, this, &OwnerNetController::onAccountRemoved);
}

OwnerNetController::~OwnerNetController() = default;

QVariantMap OwnerNetController::authenInfo() const
{
return m_server->authenInfo(m_accountManager->account());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
// SPDX-FileCopyrightText: 2024-2026 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later

Expand All @@ -21,7 +21,6 @@ class OwnerNetController : public QObject

public:
OwnerNetController(QObject *parent = Q_NULLPTR);
~OwnerNetController();
QVariantMap authenInfo() const;
QMap<QString, QString> accountNetwork() const;

Expand All @@ -38,6 +37,7 @@ private slots:
NetworkConfig *m_networkConfig;
AccountManager *m_accountManager;
InterfaceServer *m_server;
// 与插件线程其他成员同线程;NM 访问全部经 NetworkManagerProxy。
NetworkHandler *m_networkHandler;
};

Expand Down
Loading
Loading