1use static_assertions::assert_impl_all;
2use std::convert::TryInto;
3#[cfg(not(feature = "tokio"))]
4use std::net::TcpStream;
5#[cfg(all(unix, not(feature = "tokio")))]
6use std::os::unix::net::UnixStream;
7#[cfg(feature = "tokio")]
8use tokio::net::TcpStream;
9#[cfg(all(unix, feature = "tokio"))]
10use tokio::net::UnixStream;
11#[cfg(windows)]
12use uds_windows::UnixStream;
13
14use zvariant::{ObjectPath, Str};
15
16use crate::{
17 address::Address,
18 blocking::Connection,
19 names::{UniqueName, WellKnownName},
20 utils::block_on,
21 AuthMechanism, Error, Guid, Interface, Result,
22};
23
24/// A builder for [`zbus::blocking::Connection`].
25#[derive(Debug)]
26#[must_use]
27pub struct ConnectionBuilder<'a>(crate::ConnectionBuilder<'a>);
28
29assert_impl_all!(ConnectionBuilder<'_>: Send, Sync, Unpin);
30
31impl<'a> ConnectionBuilder<'a> {
32 /// Create a builder for the session/user message bus connection.
33 pub fn session() -> Result<Self> {
34 crate::ConnectionBuilder::session().map(Self)
35 }
36
37 /// Create a builder for the system-wide message bus connection.
38 pub fn system() -> Result<Self> {
39 crate::ConnectionBuilder::system().map(Self)
40 }
41
42 /// Create a builder for connection that will use the given [D-Bus bus address].
43 ///
44 /// [D-Bus bus address]: https://dbus.freedesktop.org/doc/dbus-specification.html#addresses
45 pub fn address<A>(address: A) -> Result<Self>
46 where
47 A: TryInto<Address>,
48 A::Error: Into<Error>,
49 {
50 crate::ConnectionBuilder::address(address).map(Self)
51 }
52
53 /// Create a builder for connection that will use the given unix stream.
54 ///
55 /// If the default `async-io` feature is disabled, this method will expect
56 /// [`tokio::net::UnixStream`](https://docs.rs/tokio/latest/tokio/net/struct.UnixStream.html)
57 /// argument.
58 pub fn unix_stream(stream: UnixStream) -> Self {
59 Self(crate::ConnectionBuilder::unix_stream(stream))
60 }
61
62 /// Create a builder for connection that will use the given TCP stream.
63 ///
64 /// If the default `async-io` feature is disabled, this method will expect
65 /// [`tokio::net::TcpStream`](https://docs.rs/tokio/latest/tokio/net/struct.TcpStream.html)
66 /// argument.
67 pub fn tcp_stream(stream: TcpStream) -> Self {
68 Self(crate::ConnectionBuilder::tcp_stream(stream))
69 }
70
71 /// Specify the mechanisms to use during authentication.
72 pub fn auth_mechanisms(self, auth_mechanisms: &[AuthMechanism]) -> Self {
73 Self(self.0.auth_mechanisms(auth_mechanisms))
74 }
75
76 /// The cookie context to use during authentication.
77 ///
78 /// This is only used when the `cookie` authentication mechanism is enabled and only valid for
79 /// server connection.
80 ///
81 /// If not specified, the default cookie context of `org_freedesktop_general` will be used.
82 ///
83 /// # Errors
84 ///
85 /// If the given string is not a valid cookie context.
86 pub fn cookie_context<C>(self, context: C) -> Result<Self>
87 where
88 C: Into<Str<'a>>,
89 {
90 self.0.cookie_context(context).map(Self)
91 }
92
93 /// The ID of the cookie to use during authentication.
94 ///
95 /// This is only used when the `cookie` authentication mechanism is enabled and only valid for
96 /// server connection.
97 ///
98 /// If not specified, the first cookie found in the cookie context file will be used.
99 pub fn cookie_id(self, id: usize) -> Self {
100 Self(self.0.cookie_id(id))
101 }
102
103 /// The to-be-created connection will be a peer-to-peer connection.
104 pub fn p2p(self) -> Self {
105 Self(self.0.p2p())
106 }
107
108 /// The to-be-created connection will be a server using the given GUID.
109 ///
110 /// The to-be-created connection will wait for incoming client authentication handshake and
111 /// negotiation messages, for peer-to-peer communications after successful creation.
112 pub fn server(self, guid: &'a Guid) -> Self {
113 Self(self.0.server(guid))
114 }
115
116 /// Set the capacity of the main (unfiltered) queue.
117 ///
118 /// Since typically you'd want to set this at instantiation time, you can set it through the
119 /// builder.
120 ///
121 /// # Example
122 ///
123 /// ```
124 /// # use std::error::Error;
125 /// # use zbus::blocking::ConnectionBuilder;
126 /// #
127 /// let conn = ConnectionBuilder::session()?
128 /// .max_queued(30)
129 /// .build()?;
130 /// assert_eq!(conn.max_queued(), 30);
131 ///
132 /// // Do something useful with `conn`..
133 /// # Ok::<_, Box<dyn Error + Send + Sync>>(())
134 /// ```
135 pub fn max_queued(self, max: usize) -> Self {
136 Self(self.0.max_queued(max))
137 }
138
139 /// Register a D-Bus [`Interface`] to be served at a given path.
140 ///
141 /// This is similar to [`zbus::blocking::ObjectServer::at`], except that it allows you to have
142 /// your interfaces available immediately after the connection is established. Typically, this
143 /// is exactly what you'd want. Also in contrast to [`zbus::blocking::ObjectServer::at`], this
144 /// method will replace any previously added interface with the same name at the same path.
145 pub fn serve_at<P, I>(self, path: P, iface: I) -> Result<Self>
146 where
147 I: Interface,
148 P: TryInto<ObjectPath<'a>>,
149 P::Error: Into<Error>,
150 {
151 self.0.serve_at(path, iface).map(Self)
152 }
153
154 /// Register a well-known name for this connection on the bus.
155 ///
156 /// This is similar to [`zbus::blocking::Connection::request_name`], except the name is
157 /// requested as part of the connection setup ([`ConnectionBuilder::build`]), immediately after
158 /// interfaces registered (through [`ConnectionBuilder::serve_at`]) are advertised. Typically
159 /// this is exactly what you want.
160 pub fn name<W>(self, well_known_name: W) -> Result<Self>
161 where
162 W: TryInto<WellKnownName<'a>>,
163 W::Error: Into<Error>,
164 {
165 self.0.name(well_known_name).map(Self)
166 }
167
168 /// Sets the unique name of the connection.
169 ///
170 /// # Panics
171 ///
172 /// This method panics if the to-be-created connection is not a peer-to-peer connection.
173 /// It will always panic if the connection is to a message bus as it's the bus that assigns
174 /// peers their unique names. This is mainly provided for bus implementations. All other users
175 /// should not need to use this method.
176 pub fn unique_name<U>(self, unique_name: U) -> Result<Self>
177 where
178 U: TryInto<UniqueName<'a>>,
179 U::Error: Into<Error>,
180 {
181 self.0.unique_name(unique_name).map(Self)
182 }
183
184 /// Build the connection, consuming the builder.
185 ///
186 /// # Errors
187 ///
188 /// Until server-side bus connection is supported, attempting to build such a connection will
189 /// result in [`Error::Unsupported`] error.
190 pub fn build(self) -> Result<Connection> {
191 block_on(self.0.build()).map(Into::into)
192 }
193}
194