Skip to content

Commit c9d2bfe

Browse files
authored
feat(#260,#463): add high-level add_connection wrappers (#465)
2 parents b93c59b + 5525243 commit c9d2bfe

11 files changed

Lines changed: 447 additions & 72 deletions

File tree

docs/src/advanced/connection-options.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ let settings = ConnectionBuilder::new("802-11-wireless", "MyNetwork")
8686
.build();
8787
```
8888

89-
The high-level `NetworkManager` API uses `ConnectionOptions::default()` internally. For custom options, build a settings dictionary with the builder APIs and submit it via [`dbus_connection()`](../api/network-manager.md#advanced-d-bus-access). See [Submitting Builder Output](../api/builders.md#submitting-builder-output).
89+
The high-level `NetworkManager` API uses `ConnectionOptions::default()` internally. For custom options, build a settings dictionary with the builder APIs and submit it via [`add_connection`](../api/network-manager.md#saving-profiles-without-activating) or [`add_and_activate_connection`](../api/network-manager.md#activating-builder-output).
9090

9191
## Next Steps
9292

docs/src/advanced/dbus.md

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,14 @@ This creates a persistent D-Bus connection that's shared across all operations.
4040

4141
For builder workflows and other low-level D-Bus calls, nmrs exposes the same
4242
connection through [`NetworkManager::dbus_connection()`](../api/network-manager.md#advanced-d-bus-access).
43-
Pair it with [`nmrs::raw`](../api/raw.md) (`zbus` / `zvariant` re-exports) so
44-
the types returned by builders are compatible with the connection nmrs manages.
43+
Pair it with [`nmrs::raw`](../api/raw.md) (`zbus` / `zvariant` re-exports) when
44+
you need D-Bus methods that nmrs does not wrap yet.
4545

46-
Most applications should keep using the high-level `NetworkManager` methods.
47-
Reach for `dbus_connection()` only when you need to call NetworkManager D-Bus
48-
methods that nmrs does not wrap yet (for example `AddAndActivateConnection`
49-
with custom builder output).
46+
For builder output, prefer the high-level
47+
[`add_connection`](../api/network-manager.md#saving-profiles-without-activating)
48+
and
49+
[`add_and_activate_connection`](../api/network-manager.md#activating-builder-output)
50+
methods instead of calling D-Bus directly.
5051

5152
### Method Calls
5253

@@ -106,7 +107,11 @@ methods.
106107

107108
Advanced callers can define their own minimal `#[zbus::proxy]` traits on top of
108109
[`dbus_connection()`](../api/network-manager.md#advanced-d-bus-access) and
109-
[`nmrs::raw`](../api/raw.md). See [Submitting Builder Output](../api/builders.md#submitting-builder-output).
110+
[`nmrs::raw`](../api/raw.md). For builder output, use
111+
[`add_connection`](../api/network-manager.md#saving-profiles-without-activating)
112+
or
113+
[`add_and_activate_connection`](../api/network-manager.md#activating-builder-output)
114+
first.
110115

111116
## D-Bus Errors
112117

docs/src/api/builders.md

Lines changed: 37 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# Builders Module
22

3-
The `builders` module provides low-level APIs for constructing NetworkManager connection settings. Most users should use the high-level `NetworkManager` API instead — these builders are for advanced use cases where you need fine-grained control over the settings dictionary before calling NetworkManager D-Bus methods directly.
3+
The `builders` module provides low-level APIs for constructing NetworkManager connection settings. Most users should use the high-level `NetworkManager` API instead — these builders are for advanced use cases where you need fine-grained control over the settings dictionary.
44

5-
To submit builder output, use [`NetworkManager::dbus_connection()`](./network-manager.md#advanced-d-bus-access) together with [`nmrs::raw`](./raw.md) (`zbus` / `zvariant` re-exports). See [Submitting Builder Output](#submitting-builder-output) below.
5+
To submit builder output, use [`NetworkManager::add_connection`](./network-manager.md#saving-profiles-without-activating) or [`NetworkManager::add_and_activate_connection`](./network-manager.md#activating-builder-output). See [Submitting Builder Output](#submitting-builder-output) below.
66

77
## ConnectionBuilder
88

@@ -153,64 +153,60 @@ For standard connections, the `NetworkManager` API handles everything automatica
153153
## Submitting Builder Output
154154

155155
Builders produce a NetworkManager settings dictionary
156-
(`HashMap<&str, HashMap<&str, zvariant::Value>>`). To activate that profile you
157-
need the same system D-Bus connection nmrs already manages, plus compatible
158-
`zbus` / `zvariant` types from [`nmrs::raw`](./raw.md).
156+
(`HashMap<&str, HashMap<&str, zvariant::Value>>`). Pass that map to
157+
[`NetworkManager::add_connection`](./network-manager.md#saving-profiles-without-activating)
158+
to save a profile, or
159+
[`NetworkManager::add_and_activate_connection`](./network-manager.md#activating-builder-output)
160+
to create and bring it up immediately.
159161

160162
### Wi-Fi hotspot (AP mode)
161163

162-
This is the workflow for cases such as [#260](https://github.com/freedesktop-rs/nmrs/issues/260) where the high-level `connect()` API does not expose every builder knob (for example `WifiMode::Ap`):
164+
This closes the workflow requested in [#260](https://github.com/freedesktop-rs/nmrs/issues/260) — use `WifiMode::Ap` with the high-level API:
163165

164166
```rust
165167
use nmrs::builders::{WifiConnectionBuilder, WifiMode};
166-
use nmrs::raw::{zbus, zvariant};
167-
use nmrs::{NetworkManager, Result};
168-
169-
#[zbus::proxy(
170-
interface = "org.freedesktop.NetworkManager",
171-
default_service = "org.freedesktop.NetworkManager",
172-
default_path = "/org/freedesktop/NetworkManager"
173-
)]
174-
trait Nm {
175-
fn add_and_activate_connection(
176-
&self,
177-
connection: std::collections::HashMap<
178-
&str,
179-
std::collections::HashMap<&str, zvariant::Value<'_>>,
180-
>,
181-
device: zvariant::OwnedObjectPath,
182-
specific_object: zvariant::OwnedObjectPath,
183-
) -> zbus::Result<(zvariant::OwnedObjectPath, zvariant::OwnedObjectPath)>;
184-
}
168+
use nmrs::NetworkManager;
185169

186-
async fn start_hotspot(nm: &NetworkManager, interface: &str) -> Result<()> {
170+
async fn start_hotspot(nm: &NetworkManager, interface: &str) -> nmrs::Result<()> {
187171
let settings = WifiConnectionBuilder::new("Hotspot")
188172
.wpa_psk("password")
189173
.mode(WifiMode::Ap)
190174
.ipv4_shared()
191175
.ipv6_ignore()
192176
.build();
193177

194-
let device = nm.get_device_by_interface(interface).await?;
195-
let proxy = NmProxy::new(nm.dbus_connection()).await?;
196-
proxy
197-
.add_and_activate_connection(settings, device, "/".into())
198-
.await?;
199-
178+
nm.add_and_activate_connection(settings, Some(interface), None).await?;
200179
Ok(())
201180
}
202181
```
203182

204-
Notes:
205-
206-
- Use `"/"` as `specific_object` for AP mode and other cases where there is no target access point.
207-
- For client (infrastructure) mode, resolve an access-point object path first (nmrs does this internally in `connect()`).
208-
- Map D-Bus errors to `ConnectionError::Dbus` (or handle them in your own error type).
209-
- nmrs does not yet provide a high-level wrapper for `AddConnection` / `AddAndActivateConnection`; `dbus_connection()` is the supported escape hatch.
183+
`specific_object` defaults to `"/"`, which is correct for AP mode.
210184

211185
### Saving without activating
212186

213-
To persist a profile without bringing it up immediately, define a proxy method for `AddConnection` instead and pass the same `settings` map. nmrs uses that D-Bus call internally when saving VPN profiles.
187+
To persist a profile without bringing it up immediately — the workflow from [#463](https://github.com/freedesktop-rs/nmrs/issues/463):
188+
189+
```rust
190+
use nmrs::builders::build_wifi_connection;
191+
use nmrs::{ConnectionOptions, NetworkManager, WifiSecurity};
192+
193+
let nm = NetworkManager::new().await?;
194+
let settings = build_wifi_connection(
195+
"GuestWiFi",
196+
&WifiSecurity::WpaPsk { psk: "password".into() },
197+
&ConnectionOptions::new(true),
198+
);
199+
let profile = nm.add_connection(settings).await?;
200+
```
201+
202+
Activate the saved profile later with `activate_connection` via D-Bus, or use the existing high-level `connect()` APIs when the profile matches a visible network.
203+
204+
### Advanced: direct D-Bus access
205+
206+
If you need an NetworkManager D-Bus method that nmrs does not wrap yet, combine
207+
[`dbus_connection()`](./network-manager.md#advanced-d-bus-access) with
208+
[`nmrs::raw`](./raw.md) and define your own `#[zbus::proxy]` trait on top of
209+
the builder output.
214210

215211
## OpenVpnBuilder
216212

@@ -254,6 +250,6 @@ See [docs.rs/nmrs](https://docs.rs/nmrs) for complete builder documentation.
254250

255251
## See Also
256252

257-
- [Raw Module](./raw.md)`zbus` / `zvariant` re-exports for advanced D-Bus work
258-
- [NetworkManager API](./network-manager.md#advanced-d-bus-access)`dbus_connection()`
253+
- [NetworkManager API](./network-manager.md#activating-builder-output)`add_connection()` / `add_and_activate_connection()`
254+
- [Raw Module](./raw.md)`zbus` / `zvariant` re-exports for unwrapped D-Bus calls
259255
- [D-Bus Architecture](../advanced/dbus.md) – how settings reach NetworkManager

docs/src/api/network-manager.md

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,48 @@ let nm = NetworkManager::with_config(config).await?;
2121
let config = nm.timeout_config();
2222
```
2323

24+
## Saving Profiles Without Activating
25+
26+
```rust
27+
use nmrs::builders::build_wifi_connection;
28+
use nmrs::{ConnectionOptions, NetworkManager, WifiSecurity};
29+
30+
let nm = NetworkManager::new().await?;
31+
let settings = build_wifi_connection(
32+
"GuestWiFi",
33+
&WifiSecurity::WpaPsk { psk: "password".into() },
34+
&ConnectionOptions::new(true),
35+
);
36+
let profile = nm.add_connection(settings).await?;
37+
```
38+
39+
| Method | Returns | Description |
40+
|--------|---------|-------------|
41+
| `add_connection(settings)` | `Result<OwnedObjectPath>` | Save a profile via `Settings.AddConnection` without activating it ([#463](https://github.com/freedesktop-rs/nmrs/issues/463)) |
42+
43+
## Activating Builder Output
44+
45+
```rust
46+
use nmrs::builders::{WifiConnectionBuilder, WifiMode};
47+
use nmrs::NetworkManager;
48+
49+
let nm = NetworkManager::new().await?;
50+
let settings = WifiConnectionBuilder::new("Hotspot")
51+
.wpa_psk("password")
52+
.mode(WifiMode::Ap)
53+
.ipv4_shared()
54+
.build();
55+
56+
nm.add_and_activate_connection(settings, Some("wlan0"), None).await?;
57+
```
58+
59+
| Method | Returns | Description |
60+
|--------|---------|-------------|
61+
| `add_and_activate_connection(settings, interface, specific_object)` | `Result<(OwnedObjectPath, OwnedObjectPath)>` | Create and activate a profile in one step ([#260](https://github.com/freedesktop-rs/nmrs/issues/260)) |
62+
63+
- `interface`: device name such as `"wlan0"`, or `None` to auto-pick the first device matching `connection.type`
64+
- `specific_object`: access-point path for client Wi-Fi, or `None` for AP mode / Ethernet / VPN (`"/"`)
65+
2466
## Advanced D-Bus Access
2567

2668
```rust
@@ -34,8 +76,10 @@ let conn = nm.dbus_connection(); // &zbus::Connection
3476
| `dbus_connection()` | `&zbus::Connection` | Shared system bus connection for advanced D-Bus calls |
3577

3678
Use this with [`nmrs::raw`](./raw.md) and the [builders](./builders.md) module
37-
when you need to call NetworkManager methods such as `AddConnection` or
38-
`AddAndActivateConnection` directly. See [Submitting Builder Output](./builders.md#submitting-builder-output).
79+
only when you need NetworkManager methods that nmrs does not wrap yet. For
80+
builder output, prefer
81+
[`add_connection`](./network-manager.md#saving-profiles-without-activating) and
82+
[`add_and_activate_connection`](./network-manager.md#activating-builder-output).
3983

4084
## Wi-Fi Methods
4185

docs/src/api/raw.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ pub mod raw {
99
}
1010
```
1111

12-
Use it together with [`NetworkManager::dbus_connection()`](./network-manager.md#advanced-d-bus-access) when you need to call NetworkManager D-Bus methods directly — for example after building a settings dictionary with the [`builders`](./builders.md) module.
12+
Use it together with [`NetworkManager::dbus_connection()`](./network-manager.md#advanced-d-bus-access)
13+
when you need D-Bus methods that nmrs does not wrap yet. For builder output,
14+
prefer [`add_connection`](./network-manager.md#saving-profiles-without-activating)
15+
and [`add_and_activate_connection`](./network-manager.md#activating-builder-output).
1316

1417
## Why it exists
1518

@@ -28,8 +31,8 @@ output and with the connection returned by `dbus_connection()`.
2831
3. Create a zbus proxy on that connection using `nmrs::raw::zbus`.
2932
4. Call `AddConnection` or `AddAndActivateConnection` on NetworkManager.
3033

31-
See [Submitting Builder Output](./builders.md#submitting-builder-output) for a
32-
full Wi-Fi hotspot example and [D-Bus Architecture](../advanced/dbus.md) for
34+
See [Submitting Builder Output](./builders.md#submitting-builder-output) for the
35+
preferred high-level workflow and [D-Bus Architecture](../advanced/dbus.md) for
3336
background on how nmrs talks to NetworkManager.
3437

3538
## What is not exposed

nmrs/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ All notable changes to the `nmrs` crate will be documented in this file.
77
- Expose existing secrets on SecretRequest for re-auth prefill ([#460](https://github.com/freedesktop-rs/nmrs/pull/460))
88
- `MonitorHandle` returned by `monitor_network_changes` and `monitor_device_changes` for graceful shutdown ([#461](https://github.com/freedesktop-rs/nmrs/pull/461))
99
- `NetworkManager::dbus_connection()` and `nmrs::raw` (`zbus` / `zvariant` re-exports) for advanced builder workflows ([#462](https://github.com/freedesktop-rs/nmrs/pull/464))
10-
- mdbook docs for `dbus_connection()`, `nmrs::raw`, and submitting builder output ([#462](https://github.com/freedesktop-rs/nmrs/pull/464))
10+
- `NetworkManager::add_connection()` and `NetworkManager::add_and_activate_connection()` for submitting builder output without custom zbus proxies ([#260](https://github.com/freedesktop-rs/nmrs/issues/260), [#465](https://github.com/freedesktop-rs/nmrs/pull/465))
11+
- mdbook docs for builder submission workflow, `add_connection()`, and `add_and_activate_connection()` ([#462](https://github.com/freedesktop-rs/nmrs/pull/464))
1112

1213
### Fixed
1314
- `monitor_network_changes` now detects hotplugged Wi-Fi devices instead of only monitoring devices present at startup ([#461](https://github.com/freedesktop-rs/nmrs/pull/461))

nmrs/src/api/builders/mod.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,10 @@
3535
//! need fine-grained control over the raw settings dictionary before
3636
//! handing it to NetworkManager's `AddConnection` or
3737
//! `AddAndActivateConnection` D-Bus methods via
38-
//! [`NetworkManager::dbus_connection`](crate::NetworkManager::dbus_connection)
39-
//! and [`raw`](crate::raw).
38+
//! [`NetworkManager::add_connection`](crate::NetworkManager::add_connection),
39+
//! [`NetworkManager::add_and_activate_connection`](crate::NetworkManager::add_and_activate_connection),
40+
//! [`NetworkManager::dbus_connection`](crate::NetworkManager::dbus_connection),
41+
//! or [`raw`](crate::raw).
4042
//!
4143
//! # Examples
4244
//!
@@ -71,8 +73,7 @@
7173
//! .build();
7274
//!
7375
//! let _conn = nm.dbus_connection();
74-
//! // Use `settings` with NetworkManager's AddAndActivateConnection on `_conn`
75-
//! // via `nmrs::raw::zbus` proxies.
76+
//! // Prefer `nm.add_and_activate_connection(settings, Some("wlan0"), None)` instead.
7677
//! # Ok(())
7778
//! # }
7879
//! ```
@@ -98,9 +99,9 @@
9899
//! .expect("WireGuardBuilder is fully configured");
99100
//! ```
100101
//!
101-
//! The returned settings can then be passed to NetworkManager's
102-
//! `AddConnection` or `AddAndActivateConnection` D-Bus methods through
103-
//! [`NetworkManager::dbus_connection`](crate::NetworkManager::dbus_connection).
102+
//! The returned settings can then be passed to
103+
//! [`NetworkManager::add_connection`](crate::NetworkManager::add_connection) or
104+
//! [`NetworkManager::add_and_activate_connection`](crate::NetworkManager::add_and_activate_connection).
104105
105106
pub mod bluetooth;
106107
pub mod connection_builder;

0 commit comments

Comments
 (0)