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