Skip to content

Commit

Permalink
rewrite Network Service async stuff in asyncio style
Browse files Browse the repository at this point in the history
  • Loading branch information
linkfrg committed Feb 18, 2025
1 parent 0331c4e commit cbd34c2
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 132 deletions.
129 changes: 39 additions & 90 deletions ignis/services/network/access_point.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from gi.repository import GObject, GLib # type: ignore
from ignis.gobject import IgnisGObject
from typing import Literal
from collections.abc import Callable
from ignis.app import IgnisApp
from .util import filter_connections
from ._imports import NM
Expand Down Expand Up @@ -237,25 +236,18 @@ def is_connected(self) -> bool:

return self._point.connection_valid(ac.get_connection())

def commit_changes_async(self, callback: Callable | None = None) -> None:
async def commit_changes_async(self) -> None:
"""
Asynchronously commit changes to the connection.
Args:
callback: A function to call when the changes committing is complete. The function will receive ``self`` and a boolean value: ``True`` on success, ``False`` on failure.
"""

def finish(x, res, conn):
is_success = conn.commit_changes_finish(res)
if callback:
callback(self, is_success)

for conn in self._connections:
conn.commit_changes_async(True, None, finish, conn)
await conn.commit_changes_async(True) # type: ignore

def connect_to(
self, password: str | None = None, callback: Callable | None = None
) -> None:
async def connect_to(self, password: str | None = None) -> NM.ActiveConnection:
"""
Asynchronously connect to this access point.
Expand All @@ -265,11 +257,11 @@ def connect_to(
"""

if len(self._connections) > 0:
self.__connect_existing_connection(password, callback)
return await self.__connect_existing_connection(password)
else:
self.__create_new_connection(password, callback)
return await self.__create_new_connection(password)

def connect_to_graphical(self, callback: Callable | None = None) -> None:
async def connect_to_graphical(self) -> None:
"""
Display a graphical dialog to connect to the access point.
The dialog will be shown only if the access point requires a password.
Expand All @@ -279,31 +271,22 @@ def connect_to_graphical(self, callback: Callable | None = None) -> None:
callback: A function to call when connection is established or added. The function will receive ``self`` and an instance of :class:`NM.ActiveConnection` as arguments.
"""

def callback_wrapper(x, conn):
return self.__connect_to_graphical_callback(conn, callback)

if len(self._connections) > 0:
self.connect_to(callback=callback_wrapper)
conn = await self.connect_to()
self.__connect_to_graphical_callback(conn)
else:
self.__invoke_wifi_dialog(callback=callback_wrapper)
self.__invoke_wifi_dialog()

def disconnect_from(self, callback: Callable | None = None) -> None:
async def disconnect_from(self) -> None:
"""
Asynchronously disconnect from this access point.
Args:
callback: A function to call when the connection deactivation is complete. The function will receive ``self`` and a boolean value: ``True`` on success, ``False`` on failure.
"""

def finish(x, res) -> None:
is_success = self._client.deactivate_connection_finish(res)
if callback:
callback(self, is_success)

self._client.deactivate_connection_async(
await self._client.deactivate_connection_async( # type: ignore
self._device.get_active_connection(),
None,
finish,
)

def clear_secrets(self) -> None:
Expand All @@ -317,50 +300,34 @@ def clear_secrets(self) -> None:
for conn in self._connections:
conn.remove_setting(NM.SettingWirelessSecurity)

def forget(self, callback: Callable | None = None) -> None:
async def forget(self) -> None:
"""
Forget (delete) the stored connection.
Args:
callback: A function to call when the connection deletion is complete. The function will receive ``self`` and a boolean value: ``True`` on success, ``False`` on failure.
"""

def finish(x, res, conn):
is_success = conn.delete_finish(res)
if callback:
callback(self, is_success)

for conn in self._connections:
conn.delete_async(None, finish, conn)

def __connect_existing_connection(
self, password: str | None = None, callback: Callable | None = None
) -> None:
def finish(x, res) -> None:
conn = self._client.activate_connection_finish(res)
if callback:
callback(self, conn)

def activate_conn():
for conn in self._connections:
self._client.activate_connection_async(
conn,
self._device,
self._point.get_path(),
None,
finish,
)
return
await conn.delete_async() # type: ignore

async def __connect_existing_connection( # type: ignore
self, password: str | None = None
) -> NM.ActiveConnection:
if password is not None:
self.psk = password
self.commit_changes_async(callback=lambda *_: activate_conn())
else:
activate_conn()
await self.commit_changes_async()

def __create_new_connection(
self, password: str | None = None, callback: Callable | None = None
) -> None:
for conn in self._connections:
return await self._client.activate_connection_async( # type: ignore
conn,
self._device,
self._point.get_path(),
)

async def __create_new_connection(
self, password: str | None = None
) -> NM.ActiveConnection:
connection = NM.RemoteConnection()

# WiFi settings
Expand Down Expand Up @@ -397,61 +364,43 @@ def __create_new_connection(
proxy_setting = NM.SettingProxy.new()
connection.add_setting(proxy_setting)

def finish(x, res) -> None:
conn = self._client.add_and_activate_connection_finish(res)
self.__sync_connections()
if callback:
callback(self, conn)

self._client.add_and_activate_connection_async(
conn = await self._client.add_and_activate_connection_async( # type: ignore
connection,
self._device,
self._point.get_path(),
None,
finish,
)
self.__sync_connections()
return conn

def __connect_to_graphical_callback(
self, conn: NM.ActiveConnection, user_callback: Callable | None = None
) -> None:
def __connect_to_graphical_callback(self, conn: NM.ActiveConnection) -> None:
id_ = conn.connect(
"state-changed",
lambda x,
new_state,
reason,
user_callback=user_callback: self.__check_new_state(
conn=x, new_state=new_state, reason=reason, user_callback=user_callback
lambda x, new_state, reason: self.__check_new_state(
conn=x, new_state=new_state, reason=reason
),
)
self._state_changed_ids[conn] = id_

if user_callback:
user_callback(self, conn)

def __check_new_state(
self, conn, new_state, reason, user_callback: Callable | None = None
) -> None:
def __check_new_state(self, conn, new_state, reason) -> None:
if new_state != NM.ActiveConnectionState.ACTIVATING:
id_ = self._state_changed_ids.pop(conn, None)
if id_:
conn.disconnect(id_)

if reason == NM.ActiveConnectionStateReason.DEVICE_DISCONNECTED:

def callback_wrapper(x, conn):
return self.__connect_to_graphical_callback(conn, user_callback)

self.__invoke_wifi_dialog(callback=callback_wrapper)
self.__invoke_wifi_dialog()

if (
new_state == NM.ActiveConnectionState.ACTIVATED
and self._connect_dialog is not None
):
self._connect_dialog.destroy()

def __invoke_wifi_dialog(self, callback: Callable | None = None) -> None:
def __invoke_wifi_dialog(self) -> None:
if self._connect_dialog not in app.windows:
self._connect_dialog = WifiConnectDialog(self, callback=callback)
self._connect_dialog = WifiConnectDialog(
self, self.__connect_to_graphical_callback
)


class ActiveAccessPoint(WifiAccessPoint):
Expand Down
18 changes: 4 additions & 14 deletions ignis/services/network/ethernet_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,36 +87,26 @@ def name(self) -> str | None:
"""
return self._name

def connect_to(self) -> None:
async def connect_to(self) -> None:
"""
Connect this Ethernet device to the network.
"""

def finish(x, res) -> None:
self._client.activate_connection_finish(res)

self._client.activate_connection_async(
await self._client.activate_connection_async( # type: ignore
self._connection,
self._device,
None,
None,
finish,
)

def disconnect_from(self) -> None:
async def disconnect_from(self) -> None:
"""
Disconnect this Ethernet device from the network.
"""
if not self.is_connected:
return

def finish(x, res) -> None:
self._client.deactivate_connection_finish(res)

self._client.deactivate_connection_async(
await self._client.deactivate_connection_async( # type: ignore
self._device.get_active_connection(),
None,
finish,
)

def __update_is_connected(self, *args) -> None:
Expand Down
24 changes: 7 additions & 17 deletions ignis/services/network/vpn.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,45 +48,35 @@ def name(self) -> str | None:
"""
return self._connection.get_id()

def toggle_connection(self) -> None:
async def toggle_connection(self) -> None:
"""
Toggle this VPN depending on it's `is_connected` property
"""
if self.is_connected:
self.disconnect_from()
await self.disconnect_from()
else:
self.connect_to()
await self.connect_to()

def connect_to(self) -> None:
async def connect_to(self) -> None:
"""
Connect to this VPN.
"""

def finish(x, res) -> None:
self._client.activate_connection_finish(res)

self._client.activate_connection_async(
await self._client.activate_connection_async(
self._connection, # type: ignore
None,
None,
None,
finish,
)

def disconnect_from(self) -> None:
async def disconnect_from(self) -> None:
"""
Disconnect from this VPN.
"""

def finish(x, res) -> None:
self._client.deactivate_connection_finish(res)

for conn in self._client.get_active_connections():
if conn.get_uuid() == self._connection.get_uuid():
self._client.deactivate_connection_async(
await self._client.deactivate_connection_async( # type: ignore
conn,
None,
finish,
)

def __update_is_connected(self, *args) -> None:
Expand Down
17 changes: 11 additions & 6 deletions ignis/services/network/wifi_connect_dialog.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import asyncio
from ignis.widgets import Widget
from .util import get_wifi_connect_window_name
from collections.abc import Callable
Expand All @@ -10,7 +11,9 @@ class WifiConnectDialog(Widget.RegularWindow):

def __init__(self, access_point, callback: Callable | None = None) -> None:
self._password_entry = Widget.Entry(
visibility=False, hexpand=True, on_accept=lambda x: self.__connect_to()
visibility=False,
hexpand=True,
on_accept=lambda x: asyncio.create_task(self.__connect_to()),
)
self._access_point = access_point
self._callback = callback
Expand Down Expand Up @@ -75,17 +78,19 @@ def __init__(self, access_point, callback: Callable | None = None) -> None:
"text", lambda value: len(value) >= 8
),
label="Connect",
on_click=lambda x: self.__connect_to(),
on_click=lambda x: asyncio.create_task(
self.__connect_to()
),
),
],
),
],
),
)

def __connect_to(self) -> None:
async def __connect_to(self) -> None:
if len(self._password_entry.text) >= 8:
self._access_point.connect_to(
self._password_entry.text, callback=self._callback
)
conn = await self._access_point.connect_to(self._password_entry.text)
if self._callback:
self._callback(conn)
self.unrealize()
7 changes: 2 additions & 5 deletions ignis/services/network/wifi_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,18 +84,15 @@ def is_connected(self) -> bool:
"""
return bool(self._device.get_active_connection())

def scan(self) -> None:
async def scan(self) -> None:
"""
Scan for Wi-Fi networks.
"""

def finish(x, res) -> None:
self._device.request_scan_finish(res)

if self.state == "unavailable":
return

self._device.request_scan_async(None, finish)
await self._device.request_scan_async() # type: ignore

def __add_access_point(
self, device, access_point: NM.AccessPoint, emit: bool = True
Expand Down

0 comments on commit cbd34c2

Please sign in to comment.