252 lines
11 KiB
Python
252 lines
11 KiB
Python
from typing import List, Dict, Tuple, Union, Optional
|
||
from sdbus_async.networkmanager import (
|
||
NetworkManager,
|
||
NetworkDeviceGeneric,
|
||
IPv4Config,
|
||
IPv6Config,
|
||
NetworkManagerSettings,
|
||
NetworkDeviceWireless,
|
||
AccessPoint,
|
||
DeviceType,
|
||
)
|
||
from sdbus import sd_bus_open_system
|
||
from models.network import (
|
||
NetworkInterface,
|
||
IPv4Route,
|
||
IPv6Route,
|
||
IPConfig,
|
||
IndividualIPConfig,
|
||
NetworkInterfacesContainer,
|
||
WiFiDevice,
|
||
)
|
||
import subprocess
|
||
|
||
|
||
class NetworkService:
|
||
"""Сервис для взаимодействия с NetworkManager через D-Bus"""
|
||
|
||
def __init__(self):
|
||
self.system_bus = sd_bus_open_system()
|
||
self.nm = NetworkManager(self.system_bus)
|
||
self.nm_settings = NetworkManagerSettings(self.system_bus)
|
||
|
||
async def get_ip_method(self, device: NetworkDeviceGeneric, ip_type: str) -> str:
|
||
"""Получает метод IP для устройства"""
|
||
try:
|
||
config = await device.get_applied_connection()
|
||
settings = config[0].get(ip_type, {})
|
||
return str(settings.get("method", ("s", "unknown"))[1])
|
||
except Exception:
|
||
return "unknown"
|
||
|
||
async def get_connection_name(self, device: NetworkDeviceGeneric) -> str:
|
||
"""Извлекает имя соединения (GENERAL.CONNECTION) для устройства"""
|
||
try:
|
||
applied_connection = await device.get_applied_connection()
|
||
connection_settings = applied_connection[0]
|
||
connection_info = connection_settings.get("connection", {})
|
||
return str(connection_info.get("id", ("s", "unknown"))[1])
|
||
except Exception as e:
|
||
# print(f"Ошибка при получении соединения для устройства {await device.interface}: {e}")
|
||
# срёт ошибки дл отключенных интерфейсов
|
||
# добавить потом условия для отключенных интерфейсов
|
||
return "unknown"
|
||
|
||
async def get_ip_config(
|
||
self, device: NetworkDeviceGeneric, ip_version: str
|
||
) -> List[IndividualIPConfig]:
|
||
"""Получает конфигурацию IP для устройства"""
|
||
configs = []
|
||
device_ip = await getattr(device, f"ip{ip_version}_config")
|
||
if device_ip != "/":
|
||
ip_config = globals()[f"IPv{ip_version}Config"](device_ip, self.system_bus)
|
||
address_data = await ip_config.address_data
|
||
for address in address_data:
|
||
config = IndividualIPConfig(
|
||
address=str(address["address"][1]),
|
||
routes=[
|
||
globals()[f"IPv{ip_version}Route"](
|
||
destination=route.get(
|
||
"dest", ("s", "0.0.0.0" if ip_version == "4" else "::")
|
||
)[1],
|
||
prefix=route.get("prefix", ("u", 0))[1],
|
||
next_hop=route.get(
|
||
"next-hop",
|
||
("s", "0.0.0.0" if ip_version == "4" else "::"),
|
||
)[1],
|
||
metric=route.get("metric", ("u", 0))[1],
|
||
)
|
||
for route in await ip_config.route_data
|
||
],
|
||
method=await self.get_ip_method(device, f"ipv{ip_version}"),
|
||
gateway=str(await ip_config.gateway),
|
||
dns=[
|
||
str(ns["address"][1]) if ip_version == "4" else str(ns)
|
||
for ns in await getattr(
|
||
ip_config,
|
||
"nameserver_data" if ip_version == "4" else "nameservers",
|
||
)
|
||
],
|
||
)
|
||
configs.append(config)
|
||
return configs
|
||
|
||
async def get_wifi_info(
|
||
self, wifi_device: NetworkDeviceWireless
|
||
) -> Dict[str, Optional[Union[str, int]]]:
|
||
"""Получает информацию о Wi-Fi устройстве"""
|
||
active_ap = await wifi_device.active_access_point
|
||
wifi_info = {
|
||
"ssid": None,
|
||
"bssid": None,
|
||
"bitrate": await wifi_device.bitrate,
|
||
"strength": None,
|
||
"frequency": None,
|
||
"mode": None,
|
||
}
|
||
if active_ap != "/":
|
||
ap = AccessPoint(active_ap, self.system_bus)
|
||
wifi_info.update(
|
||
{
|
||
"ssid": await ap.ssid,
|
||
"bssid": await ap.hw_address,
|
||
"strength": await ap.strength,
|
||
"frequency": await ap.frequency,
|
||
"mode": await ap.mode,
|
||
}
|
||
)
|
||
return wifi_info
|
||
|
||
async def get_network_interfaces(
|
||
self, initial_positions: Dict[str, Tuple[int, int]] = None
|
||
) -> List[Union[NetworkInterface, WiFiDevice]]:
|
||
"""Получает список сетевых интерфейсов"""
|
||
devices_paths = await self.nm.get_devices()
|
||
network_interfaces = []
|
||
initial_positions = initial_positions or {}
|
||
|
||
for device_path in devices_paths:
|
||
generic_device = NetworkDeviceGeneric(device_path, self.system_bus)
|
||
interface_name = str(await generic_device.interface)
|
||
device_type = DeviceType(await generic_device.device_type).name
|
||
|
||
if device_type == "LOOPBACK":
|
||
continue
|
||
|
||
device_state = str(await generic_device.state)
|
||
if device_state == "10":
|
||
continue
|
||
|
||
common_data = {
|
||
"name": interface_name,
|
||
"type": device_type,
|
||
"device_state": device_state,
|
||
"active_connection": await self.get_connection_name(generic_device),
|
||
"mac_address": str(await generic_device.hw_address),
|
||
"device_mtu": str(await generic_device.mtu),
|
||
"ipv4": IPConfig(
|
||
configurations=await self.get_ip_config(generic_device, "4")
|
||
),
|
||
"ipv6": IPConfig(
|
||
configurations=await self.get_ip_config(generic_device, "6")
|
||
),
|
||
"x": initial_positions.get(interface_name, (100, 100))[0],
|
||
"y": initial_positions.get(interface_name, (100, 100))[1],
|
||
}
|
||
|
||
if device_type == "WIFI":
|
||
wifi_device = NetworkDeviceWireless(device_path, self.system_bus)
|
||
wifi_info = await self.get_wifi_info(wifi_device)
|
||
network_interfaces.append(WiFiDevice(**common_data, **wifi_info))
|
||
else:
|
||
network_interfaces.append(NetworkInterface(**common_data))
|
||
|
||
return network_interfaces
|
||
|
||
async def get_hostname(self) -> Dict[str, str]:
|
||
"""Возвращает имя хоста из команды hostname в формате JSON"""
|
||
try:
|
||
result = subprocess.run(
|
||
["hostname"], capture_output=True, text=True, check=True
|
||
)
|
||
hostname = result.stdout.strip()
|
||
return {"hostname": hostname}
|
||
except subprocess.CalledProcessError as e:
|
||
raise RuntimeError(f"Failed to execute hostname: {e}")
|
||
except Exception as e:
|
||
raise RuntimeError(f"Error processing hostname output: {e}")
|
||
|
||
async def get_interfaces_by_state(
|
||
self, state: str, initial_positions: Dict[str, Tuple[int, int]] = None
|
||
) -> List[NetworkInterface]:
|
||
"""
|
||
Получает список интерфейсов по состоянию
|
||
"""
|
||
all_interfaces = await self.get_network_interfaces(initial_positions)
|
||
return [
|
||
interface for interface in all_interfaces if interface.device_state == state
|
||
]
|
||
|
||
async def get_interfaces_container(
|
||
self,
|
||
state: Optional[str] = None,
|
||
initial_positions: Dict[str, Tuple[int, int]] = None,
|
||
container_x: int = 0,
|
||
container_y: int = 0,
|
||
) -> NetworkInterfacesContainer:
|
||
"""Получает объект, содержащий список интерфейсов и координаты контейнера"""
|
||
if state:
|
||
interfaces = await self.get_interfaces_by_state(state, initial_positions)
|
||
else:
|
||
interfaces = await self.get_network_interfaces(initial_positions)
|
||
return NetworkInterfacesContainer(
|
||
interfaces=interfaces, container_x=container_x, container_y=container_y
|
||
)
|
||
|
||
async def get_network_interfaces_container(
|
||
self,
|
||
initial_positions: Optional[Dict[str, Tuple[int, int]]] = None,
|
||
) -> NetworkInterfacesContainer:
|
||
"""Получает контейнер с сетевыми интерфейсами и координатами контейнера"""
|
||
interfaces = await self.get_network_interfaces(initial_positions)
|
||
return NetworkInterfacesContainer(
|
||
interfaces=interfaces, container_x=0, container_y=0
|
||
)
|
||
|
||
async def get_activated_interfaces(
|
||
self, initial_positions: Dict[str, Tuple[int, int]] = None
|
||
) -> List[NetworkInterface]:
|
||
"""Получает список активных сетевых интерфейсов"""
|
||
return await self.get_interfaces_by_state("100", initial_positions)
|
||
|
||
async def get_deactivated_interfaces(
|
||
self, initial_positions: Dict[str, Tuple[int, int]] = None
|
||
) -> List[NetworkInterface]:
|
||
"""Получает список неактивных сетевых интерфейсов"""
|
||
all_interfaces = await self.get_network_interfaces(initial_positions)
|
||
return [
|
||
interface for interface in all_interfaces if interface.device_state != "100"
|
||
]
|
||
|
||
async def get_activated_interfaces_container(
|
||
self,
|
||
initial_positions: Dict[str, Tuple[int, int]] = None,
|
||
container_x: int = 0,
|
||
container_y: int = 0,
|
||
) -> NetworkInterfacesContainer:
|
||
"""Получает объект, содержащий список активных интерфейсов и координаты контейнера"""
|
||
return await self.get_interfaces_container(
|
||
"100", initial_positions, container_x, container_y
|
||
)
|
||
|
||
async def get_deactivated_interfaces_container(
|
||
self,
|
||
initial_positions: Dict[str, Tuple[int, int]] = None,
|
||
container_x: int = 0,
|
||
container_y: int = 0,
|
||
) -> NetworkInterfacesContainer:
|
||
"""Получает объект, содержащий список неактивных интерфейсов и координаты контейнера"""
|
||
interfaces = await self.get_deactivated_interfaces(initial_positions)
|
||
return NetworkInterfacesContainer(
|
||
interfaces=interfaces, container_x=container_x, container_y=container_y
|
||
)
|