1use std::sync::Arc;
2
3use derive_more::Debug;
4use futures::{Stream, StreamExt};
5use tokio_util::sync::CancellationToken;
6use tracing::{instrument, warn};
7use wayle_core::Property;
8use wayle_traits::{Reactive, ServiceMonitoring, Static};
9use zbus::{Connection, zvariant::OwnedObjectPath};
10
11use super::{
12 core::access_point::types::{AccessPointParams, LiveAccessPointParams},
13 error::Error,
14 types::connectivity::ConnectionType,
15 wifi::Wifi,
16 wired::Wired,
17};
18use crate::{
19 core::{
20 access_point::AccessPoint,
21 config::{
22 dhcp4_config::{Dhcp4Config, Dhcp4ConfigParams},
23 dhcp6_config::{Dhcp6Config, Dhcp6ConfigParams},
24 ip4_config::{Ip4Config, Ip4ConfigParams},
25 ip6_config::{Ip6Config, Ip6ConfigParams},
26 },
27 connection::{ActiveConnection, ActiveConnectionParams, LiveActiveConnectionParams},
28 device::{
29 Device, DeviceParams, LiveDeviceParams,
30 wifi::{DeviceWifi, DeviceWifiParams, LiveDeviceWifiParams},
31 wired::{DeviceWired, DeviceWiredParams, LiveDeviceWiredParams},
32 },
33 settings::{LiveSettingsParams, Settings},
34 settings_connection::{
35 ConnectionSettings, ConnectionSettingsParams, LiveConnectionSettingsParams,
36 },
37 },
38 discovery::NetworkServiceDiscovery,
39 proxy::manager::NetworkManagerProxy,
40 types::states::NMState,
41 wifi::LiveWifiParams,
42 wired::LiveWiredParams,
43};
44
45#[derive(Debug)]
47pub struct NetworkService {
48 #[debug(skip)]
49 pub(crate) zbus_connection: Connection,
50 #[debug(skip)]
51 pub(crate) cancellation_token: CancellationToken,
52 pub settings: Arc<Settings>,
54 pub wifi: Property<Option<Arc<Wifi>>>,
56 pub wired: Property<Option<Arc<Wired>>>,
58 pub primary: Property<ConnectionType>,
60}
61
62impl NetworkService {
63 #[instrument]
75 pub async fn new() -> Result<Self, Error> {
76 let connection = Connection::system().await.map_err(|err| {
77 Error::ServiceInitializationFailed(format!("D-Bus connection failed: {err}"))
78 })?;
79
80 let cancellation_token = CancellationToken::new();
81
82 let settings = Settings::get_live(LiveSettingsParams {
83 zbus_connection: &connection,
84 cancellation_token: &cancellation_token,
85 })
86 .await
87 .map_err(|err| {
88 Error::ServiceInitializationFailed(format!("cannot initialize Settings: {err}"))
89 })?;
90
91 let wifi_device_path = NetworkServiceDiscovery::wifi_device_path(&connection).await?;
92 let wired_device_path = NetworkServiceDiscovery::wired_device_path(&connection).await?;
93
94 let wifi = if let Some(path) = wifi_device_path {
95 match Wifi::get_live(LiveWifiParams {
96 connection: &connection,
97 device_path: path.clone(),
98 cancellation_token: &cancellation_token,
99 settings: settings.clone(),
100 })
101 .await
102 {
103 Ok(wifi) => Some(wifi),
104 Err(e) => {
105 warn!(error = %e, path = %path, "cannot create WiFi service");
106 None
107 }
108 }
109 } else {
110 None
111 };
112
113 let wired = if let Some(path) = wired_device_path {
114 match Wired::get_live(LiveWiredParams {
115 connection: &connection,
116 device_path: path.clone(),
117 cancellation_token: &cancellation_token,
118 })
119 .await
120 {
121 Ok(wired) => Some(wired),
122 Err(e) => {
123 warn!(error = %e, path = %path, "cannot create wired service");
124 None
125 }
126 }
127 } else {
128 None
129 };
130
131 let primary = Property::new(ConnectionType::None);
132
133 let service = Self {
134 zbus_connection: connection.clone(),
135 cancellation_token,
136 settings,
137 wifi: Property::new(wifi),
138 wired: Property::new(wired),
139 primary,
140 };
141
142 service.start_monitoring().await?;
143
144 Ok(service)
145 }
146
147 #[instrument(skip(self, path), fields(path = ?path), err)]
154 pub async fn connection(&self, path: OwnedObjectPath) -> Result<ActiveConnection, Error> {
155 ActiveConnection::get(ActiveConnectionParams {
156 connection: &self.zbus_connection,
157 path,
158 })
159 .await
160 }
161
162 #[instrument(skip(self, path), fields(path = ?path), err)]
170 pub async fn connection_monitored(
171 &self,
172 path: OwnedObjectPath,
173 ) -> Result<Arc<ActiveConnection>, Error> {
174 ActiveConnection::get_live(LiveActiveConnectionParams {
175 connection: &self.zbus_connection,
176 path,
177 cancellation_token: &self.cancellation_token,
178 })
179 .await
180 }
181
182 #[instrument(skip(self, path), fields(path = ?path), err)]
188 pub async fn access_point(&self, path: OwnedObjectPath) -> Result<AccessPoint, Error> {
189 AccessPoint::get(AccessPointParams {
190 connection: &self.zbus_connection,
191 path,
192 })
193 .await
194 }
195
196 #[instrument(skip(self, path), fields(path = ?path), err)]
203 pub async fn access_point_monitored(
204 &self,
205 path: OwnedObjectPath,
206 ) -> Result<Arc<AccessPoint>, Error> {
207 AccessPoint::get_live(LiveAccessPointParams {
208 connection: &self.zbus_connection,
209 path,
210 cancellation_token: &self.cancellation_token,
211 })
212 .await
213 }
214
215 #[instrument(skip(self, path), fields(path = ?path), err)]
221 pub async fn connection_settings(
222 &self,
223 path: OwnedObjectPath,
224 ) -> Result<ConnectionSettings, Error> {
225 ConnectionSettings::get(ConnectionSettingsParams {
226 connection: &self.zbus_connection,
227 path,
228 })
229 .await
230 }
231
232 #[instrument(skip(self, path), fields(path = ?path), err)]
239 pub async fn connection_settings_monitored(
240 &self,
241 path: OwnedObjectPath,
242 ) -> Result<Arc<ConnectionSettings>, Error> {
243 ConnectionSettings::get_live(LiveConnectionSettingsParams {
244 connection: &self.zbus_connection,
245 path,
246 cancellation_token: &self.cancellation_token,
247 })
248 .await
249 }
250
251 #[instrument(skip(self, path), fields(path = ?path), err)]
257 pub async fn device(&self, path: OwnedObjectPath) -> Result<Device, Error> {
258 Device::get(DeviceParams {
259 connection: &self.zbus_connection,
260 object_path: path,
261 })
262 .await
263 }
264
265 #[instrument(skip(self, path), fields(path = ?path), err)]
272 pub async fn device_monitored(&self, path: OwnedObjectPath) -> Result<Arc<Device>, Error> {
273 Device::get_live(LiveDeviceParams {
274 connection: &self.zbus_connection,
275 object_path: path,
276 cancellation_token: &self.cancellation_token,
277 })
278 .await
279 }
280
281 #[instrument(skip(self, path), fields(path = ?path), err)]
287 pub async fn device_wifi(&self, path: OwnedObjectPath) -> Result<DeviceWifi, Error> {
288 DeviceWifi::get(DeviceWifiParams {
289 connection: &self.zbus_connection,
290 device_path: path,
291 })
292 .await
293 }
294
295 #[instrument(skip(self, path), fields(path = ?path), err)]
302 pub async fn device_wifi_monitored(
303 &self,
304 path: OwnedObjectPath,
305 ) -> Result<Arc<DeviceWifi>, Error> {
306 DeviceWifi::get_live(LiveDeviceWifiParams {
307 connection: &self.zbus_connection,
308 device_path: path,
309 cancellation_token: &self.cancellation_token,
310 })
311 .await
312 }
313
314 #[instrument(skip(self, path), fields(path = ?path), err)]
320 pub async fn device_wired(&self, path: OwnedObjectPath) -> Result<DeviceWired, Error> {
321 DeviceWired::get(DeviceWiredParams {
322 connection: &self.zbus_connection,
323 device_path: path,
324 })
325 .await
326 }
327
328 #[instrument(skip(self, path), fields(path = ?path), err)]
335 pub async fn device_wired_monitored(
336 &self,
337 path: OwnedObjectPath,
338 ) -> Result<Arc<DeviceWired>, Error> {
339 DeviceWired::get_live(LiveDeviceWiredParams {
340 connection: &self.zbus_connection,
341 device_path: path,
342 cancellation_token: &self.cancellation_token,
343 })
344 .await
345 }
346
347 #[instrument(skip(self, path), fields(path = ?path), err)]
353 pub async fn ip4_config(&self, path: OwnedObjectPath) -> Result<Ip4Config, Error> {
354 Ip4Config::get(Ip4ConfigParams {
355 connection: &self.zbus_connection,
356 path,
357 })
358 .await
359 }
360
361 #[instrument(skip(self, path), fields(path = ?path), err)]
367 pub async fn ip6_config(&self, path: OwnedObjectPath) -> Result<Ip6Config, Error> {
368 Ip6Config::get(Ip6ConfigParams {
369 connection: &self.zbus_connection,
370 path,
371 })
372 .await
373 }
374
375 #[instrument(skip(self, path), fields(path = ?path), err)]
381 pub async fn dhcp4_config(&self, path: OwnedObjectPath) -> Result<Dhcp4Config, Error> {
382 Dhcp4Config::get(Dhcp4ConfigParams {
383 connection: &self.zbus_connection,
384 path,
385 })
386 .await
387 }
388
389 #[instrument(skip(self, path), fields(path = ?path), err)]
395 pub async fn dhcp6_config(&self, path: OwnedObjectPath) -> Result<Dhcp6Config, Error> {
396 Dhcp6Config::get(Dhcp6ConfigParams {
397 connection: &self.zbus_connection,
398 path,
399 })
400 .await
401 }
402
403 pub async fn check_permissions_signal(&self) -> Result<impl Stream<Item = ()>, Error> {
408 let proxy = NetworkManagerProxy::new(&self.zbus_connection).await?;
409 let stream = proxy.receive_check_permissions().await?;
410
411 Ok(stream.filter_map(|_signal| async move { Some(()) }))
412 }
413
414 pub async fn state_changed_signal(&self) -> Result<impl Stream<Item = NMState>, Error> {
419 let proxy = NetworkManagerProxy::new(&self.zbus_connection).await?;
420 let stream = proxy.receive_state_changed().await?;
421
422 Ok(stream.filter_map(|signal| async move {
423 signal.args().ok().map(|args| NMState::from_u32(args.state))
424 }))
425 }
426
427 pub async fn device_added_signal(&self) -> Result<impl Stream<Item = OwnedObjectPath>, Error> {
432 let proxy = NetworkManagerProxy::new(&self.zbus_connection).await?;
433 let stream = proxy.receive_device_added().await?;
434
435 Ok(stream
436 .filter_map(|signal| async move { signal.args().ok().map(|args| args.device_path) }))
437 }
438
439 pub async fn device_removed_signal(
444 &self,
445 ) -> Result<impl Stream<Item = OwnedObjectPath>, Error> {
446 let proxy = NetworkManagerProxy::new(&self.zbus_connection).await?;
447 let stream = proxy.receive_device_removed().await?;
448
449 Ok(stream
450 .filter_map(|signal| async move { signal.args().ok().map(|args| args.device_path) }))
451 }
452}
453
454impl Drop for NetworkService {
455 fn drop(&mut self) {
456 self.cancellation_token.cancel();
457 }
458}