1 | use static_assertions::assert_impl_all; |
2 | use std::convert::TryInto; |
3 | #[cfg (not(feature = "tokio" ))] |
4 | use std::net::TcpStream; |
5 | #[cfg (all(unix, not(feature = "tokio" )))] |
6 | use std::os::unix::net::UnixStream; |
7 | #[cfg (feature = "tokio" )] |
8 | use tokio::net::TcpStream; |
9 | #[cfg (all(unix, feature = "tokio" ))] |
10 | use tokio::net::UnixStream; |
11 | #[cfg (windows)] |
12 | use uds_windows::UnixStream; |
13 | |
14 | use zvariant::{ObjectPath, Str}; |
15 | |
16 | use 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 ] |
27 | pub struct ConnectionBuilder<'a>(crate::ConnectionBuilder<'a>); |
28 | |
29 | assert_impl_all!(ConnectionBuilder<'_>: Send, Sync, Unpin); |
30 | |
31 | impl<'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 | |