gonets/SRV/services/connect_service.py
2025-06-26 17:49:21 +05:00

159 lines
No EOL
9.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import subprocess
import logging
from typing import Tuple, Optional
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
logger = logging.getLogger(__name__)
class WifiConnectionService:
"""Сервис для управления подключением к Wi-Fi сетям с использованием nmcli.
Предоставляет методы для подключения, отключения и проверки статуса Wi-Fi соединений.
"""
def __init__(self):
"""Инициализирует сервис Wi-Fi.
Автоматически определяет доступный Wi-Fi-интерфейс и сохраняет его имя.
"""
self.interface = self._get_wifi_interface()
def _get_wifi_interface(self) -> str:
"""Автоматически определяет Wi-Fi-интерфейс.
Returns:
str: Название Wi-Fi-интерфейса (например, "wlan0") или пустая строка,
если интерфейс не найден или Wi-Fi отключён.
Raises:
Exception: Если произошла ошибка при выполнении команд nmcli.
"""
try:
result = subprocess.run(["nmcli", "radio", "wifi"], capture_output=True, text=True)
if "enabled" in result.stdout.lower():
interfaces = subprocess.run(["nmcli", "device", "status"], capture_output=True, text=True).stdout
for line in interfaces.splitlines():
if "wifi" in line.lower() and "connected" in line.lower():
iface = line.split()[0]
logger.info(f"Используется Wi-Fi-интерфейс: {iface}")
return iface
logger.warning("Wi-Fi-интерфейс не найден или не подключён")
return "wlan0"
logger.error("Wi-Fi радио отключено")
return ""
except Exception as e:
logger.error(f"Ошибка при определении Wi-Fi-интерфейса: {str(e)}")
return ""
def connect(self, ssid: str, password: str) -> Tuple[bool, Optional[str]]:
"""Подключается к Wi-Fi сети по SSID и паролю.
Args:
ssid (str): Идентификатор сети Wi-Fi.
password (str): Пароль для подключения.
Returns:
Tuple[bool, Optional[str]]: Кортеж (успех, сообщение об ошибке).
- Успех: (True, None).
- Ошибка: (False, сообщение об ошибке).
Raises:
subprocess.CalledProcessError: Если команда nmcli завершилась с ошибкой.
Exception: Если произошла неизвестная ошибка при выполнении.
"""
try:
if not self.interface:
return False, "Wi-Fi-интерфейс не доступен"
result = subprocess.run(["nmcli", "-f", "SSID", "device", "wifi", "list"], capture_output=True, text=True)
if ssid not in result.stdout:
return False, f"Сеть с SSID {ssid} не найдена в списке доступных сетей"
cmd = ["nmcli", "device", "wifi", "connect", ssid, "password", password]
process = subprocess.run(cmd, capture_output=True, text=True, check=False)
if process.returncode != 0:
error_msg = process.stderr.lower()
if "secrets were required" in error_msg or "authentication failed" in error_msg or "802-11-wireless-security.psk: недействительное свойство" in process.stderr:
return False, f"Ошибка подключения к {ssid}: Неверный пароль"
elif "no network with ssid" in error_msg:
return False, f"Ошибка подключения к {ssid}: Сеть с SSID {ssid} недоступна или неверно указана"
else:
return False, f"Ошибка подключения к {ssid}: {process.stderr}"
logger.info(f"Успешное подключение к сети {ssid}")
return True, None
except subprocess.CalledProcessError as e:
logger.error(f"Ошибка подключения к {ssid}: {e.stderr}")
error_msg = e.stderr.lower()
if "secrets were required" in error_msg or "authentication failed" in error_msg or "802-11-wireless-security.psk: недействительное свойство" in e.stderr:
return False, f"Ошибка подключения к {ssid}: Неверный пароль"
elif "no network with ssid" in error_msg:
return False, f"Ошибка подключения к {ssid}: Сеть с SSID {ssid} недоступна или неверно указана"
return False, f"Ошибка подключения к {ssid}: {e.stderr}"
except Exception as e:
logger.error(f"Неизвестная ошибка при подключении к {ssid}: {str(e)}")
return False, f"Ошибка подключения к {ssid}: Неизвестная ошибка - {str(e)}"
def disconnect(self, ssid: str) -> Tuple[bool, Optional[str]]:
"""Отключается от Wi-Fi сети по указанному SSID.
Args:
ssid (str): Идентификатор сети Wi-Fi для отключения.
Returns:
Tuple[bool, Optional[str]]: Кортеж (успех, сообщение об ошибке).
- Успех: (True, None или сообщение, если подключение не найдено).
- Ошибка: (False, сообщение об ошибке).
Raises:
subprocess.CalledProcessError: Если команда nmcli завершилась с ошибкой.
Exception: Если произошла неизвестная ошибка при выполнении.
"""
try:
if not self.interface:
return False, "Wi-Fi-интерфейс не доступен"
result = subprocess.run(["nmcli", "connection", "show", "--active"], capture_output=True, text=True)
active_connections = result.stdout.strip().splitlines()
if not active_connections:
logger.info(f"Нет активных подключений для SSID {ssid}")
return True, f"Нет активного подключения для SSID {ssid}"
for conn in active_connections:
conn_details = conn.split()
if len(conn_details) > 1:
conn_name = conn_details[0]
conn_info = subprocess.run(["nmcli", "connection", "show", conn_name], capture_output=True, text=True).stdout
if "802-11-wireless.ssid:" in conn_info and ssid in conn_info:
subprocess.run(["nmcli", "connection", "down", conn_name], capture_output=True, text=True, check=True)
logger.info(f"Отключено соединение с SSID {ssid}")
return True, None
logger.warning(f"Активное подключение с SSID {ssid} не найдено")
return True, f"Активное подключение с SSID {ssid} не найдено"
except subprocess.CalledProcessError as e:
logger.error(f"Ошибка при отключении от {ssid}: {e.stderr}")
return False, f"Ошибка отключения от {ssid}: {e.stderr}"
except Exception as e:
logger.error(f"Неизвестная ошибка при отключении от {ssid}: {str(e)}")
return False, f"Ошибка отключения от {ssid}: {str(e)}"
def get_status(self) -> Tuple[bool, Optional[str]]:
"""Проверяет статус текущего подключения к Wi-Fi.
Returns:
Tuple[bool, Optional[str]]: Кортеж (успех, SSID или сообщение об ошибке).
- Успех: (True, SSID текущей сети).
- Ошибка или отсутствие подключения: (False, сообщение об ошибке).
Raises:
Exception: Если произошла ошибка при выполнении команды nmcli.
"""
try:
if not self.interface:
return False, "Wi-Fi-интерфейс не доступен"
result = subprocess.run(["nmcli", "connection", "show", "--active"], capture_output=True, text=True)
if result.stdout.strip():
ssid = result.stdout.splitlines()[1].split()[0]
logger.info(f"Текущая сеть: {ssid}")
return True, ssid
return False, "Не подключено к Wi-Fi"
except Exception as e:
logger.error(f"Ошибка при проверке статуса: {str(e)}")
return False, f"Ошибка проверки статуса: {str(e)}"