1use enumflags2::{BitFlags, bitflags};
4use event_listener::{Event, EventListener};
5use futures_core::{ready, stream};
6use ordered_stream::{FromFuture, Join, Map, OrderedStream, PollResult, join as join_streams};
7use std::{
8 collections::{HashMap, HashSet},
9 fmt,
10 future::Future,
11 ops::Deref,
12 pin::Pin,
13 sync::{Arc, OnceLock, RwLock, RwLockReadGuard},
14 task::{Context, Poll},
15};
16use tracing::{Instrument, debug, info_span, instrument, trace, warn};
17
18use zbus_names::{BusName, InterfaceName, MemberName, UniqueName};
19use zvariant::{ObjectPath, OwnedValue, Str, Value};
20
21use crate::{
22 AsyncDrop, Connection, Error, Executor, MatchRule, MessageStream, OwnedMatchRule, Result, Task,
23 fdo::{self, IntrospectableProxy, NameOwnerChanged, PropertiesChangedStream, PropertiesProxy},
24 message::{Flags, Message, Sequence, Type},
25};
26
27mod builder;
28pub use builder::{Builder, CacheProperties};
29
30mod defaults;
31pub use defaults::Defaults;
32
33#[derive(Clone, Debug)]
68pub struct Proxy<'a> {
69 pub(crate) inner: Arc<ProxyInner<'a>>,
70}
71
72pub(crate) struct ProxyInnerStatic {
75 pub(crate) conn: Connection,
76 dest_owner_change_match_rule: OnceLock<OwnedMatchRule>,
77}
78
79impl fmt::Debug for ProxyInnerStatic {
80 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81 f.debug_struct("ProxyInnerStatic")
82 .field(
83 "dest_owner_change_match_rule",
84 &self.dest_owner_change_match_rule,
85 )
86 .finish_non_exhaustive()
87 }
88}
89
90#[derive(Debug)]
91pub(crate) struct ProxyInner<'a> {
92 inner_without_borrows: ProxyInnerStatic,
93 pub(crate) destination: BusName<'a>,
94 pub(crate) path: ObjectPath<'a>,
95 pub(crate) interface: InterfaceName<'a>,
96
97 property_cache: Option<OnceLock<(Arc<PropertiesCache>, Task<()>)>>,
99 uncached_properties: HashSet<Str<'a>>,
102}
103
104impl Drop for ProxyInnerStatic {
105 fn drop(&mut self) {
106 if let Some(rule) = self.dest_owner_change_match_rule.take() {
107 self.conn.queue_remove_match(rule);
108 }
109 }
110}
111
112pub struct PropertyChanged<'a, T> {
116 name: &'a str,
117 properties: Arc<PropertiesCache>,
118 proxy: Proxy<'a>,
119 phantom: std::marker::PhantomData<T>,
120}
121
122impl<T> PropertyChanged<'_, T> {
123 pub fn name(&self) -> &str {
125 self.name
126 }
127
128 pub async fn get_raw(&self) -> Result<impl Deref<Target = Value<'static>> + '_> {
134 struct Wrapper<'w> {
135 name: &'w str,
136 values: RwLockReadGuard<'w, HashMap<String, PropertyValue>>,
137 }
138
139 impl Deref for Wrapper<'_> {
140 type Target = Value<'static>;
141
142 fn deref(&self) -> &Self::Target {
143 self.values
144 .get(self.name)
145 .expect("PropertyStream with no corresponding property")
146 .value
147 .as_ref()
148 .expect("PropertyStream with no corresponding property")
149 }
150 }
151
152 {
153 let values = self.properties.values.read().expect("lock poisoned");
154 if values
155 .get(self.name)
156 .expect("PropertyStream with no corresponding property")
157 .value
158 .is_some()
159 {
160 return Ok(Wrapper {
161 name: self.name,
162 values,
163 });
164 }
165 }
166
167 let properties_proxy = self.proxy.properties_proxy();
169 let value = properties_proxy
170 .get(self.proxy.inner.interface.clone(), self.name)
171 .await
172 .map_err(crate::Error::from)?;
173
174 {
176 let mut values = self.properties.values.write().expect("lock poisoned");
177
178 values
179 .get_mut(self.name)
180 .expect("PropertyStream with no corresponding property")
181 .value = Some(value);
182 }
183
184 Ok(Wrapper {
185 name: self.name,
186 values: self.properties.values.read().expect("lock poisoned"),
187 })
188 }
189}
190
191impl<T> PropertyChanged<'_, T>
192where
193 T: TryFrom<zvariant::OwnedValue>,
194 T::Error: Into<crate::Error>,
195{
196 pub async fn get(&self) -> Result<T> {
202 self.get_raw()
203 .await
204 .and_then(|v| T::try_from(OwnedValue::try_from(&*v)?).map_err(Into::into))
205 }
206}
207
208#[derive(Debug)]
212pub struct PropertyStream<'a, T> {
213 name: &'a str,
214 proxy: Proxy<'a>,
215 changed_listener: EventListener,
216 phantom: std::marker::PhantomData<T>,
217}
218
219impl<'a, T> stream::Stream for PropertyStream<'a, T>
220where
221 T: Unpin,
222{
223 type Item = PropertyChanged<'a, T>;
224
225 fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
226 let m = self.get_mut();
227 let properties = match m.proxy.get_property_cache() {
228 Some(properties) => properties.clone(),
229 None => return Poll::Ready(None),
231 };
232 ready!(Pin::new(&mut m.changed_listener).poll(cx));
233
234 m.changed_listener = properties
235 .values
236 .read()
237 .expect("lock poisoned")
238 .get(m.name)
239 .expect("PropertyStream with no corresponding property")
240 .event
241 .listen();
242
243 Poll::Ready(Some(PropertyChanged {
244 name: m.name,
245 properties,
246 proxy: m.proxy.clone(),
247 phantom: std::marker::PhantomData,
248 }))
249 }
250}
251
252#[derive(Debug)]
253pub(crate) struct PropertiesCache {
254 values: RwLock<HashMap<String, PropertyValue>>,
255 caching_result: RwLock<CachingResult>,
256}
257
258#[derive(Debug)]
259enum CachingResult {
260 Caching { ready: Event },
261 Cached { result: Result<()> },
262}
263
264impl PropertiesCache {
265 #[instrument(skip_all, level = "trace")]
266 fn new(
267 proxy: PropertiesProxy<'static>,
268 interface: InterfaceName<'static>,
269 executor: &Executor<'_>,
270 uncached_properties: HashSet<zvariant::Str<'static>>,
271 ) -> (Arc<Self>, Task<()>) {
272 let cache = Arc::new(PropertiesCache {
273 values: Default::default(),
274 caching_result: RwLock::new(CachingResult::Caching {
275 ready: Event::new(),
276 }),
277 });
278
279 let cache_clone = cache.clone();
280 let task_name = format!("{interface} proxy caching");
281 let proxy_caching = async move {
282 let result = cache_clone
283 .init(proxy, interface, uncached_properties)
284 .await;
285 let (prop_changes, interface, uncached_properties) = {
286 let mut caching_result = cache_clone.caching_result.write().expect("lock poisoned");
287 let ready = match &*caching_result {
288 CachingResult::Caching { ready } => ready,
289 _ => unreachable!(),
292 };
293 match result {
294 Ok((prop_changes, interface, uncached_properties)) => {
295 ready.notify(usize::MAX);
296 *caching_result = CachingResult::Cached { result: Ok(()) };
297
298 (prop_changes, interface, uncached_properties)
299 }
300 Err(e) => {
301 warn!(
302 "Failed to populate properties cache via GetAll: {e}. \
303 Property change streams will not produce values."
304 );
305 ready.notify(usize::MAX);
306 *caching_result = CachingResult::Cached { result: Err(e) };
307
308 return;
309 }
310 }
311 };
312
313 if let Err(e) = cache_clone
314 .keep_updated(prop_changes, interface, uncached_properties)
315 .await
316 {
317 debug!("Error keeping properties cache updated: {e}");
318 }
319 }
320 .instrument(info_span!("{}", task_name));
321 let task = executor.spawn(proxy_caching, &task_name);
322
323 (cache, task)
324 }
325
326 async fn init(
328 &self,
329 proxy: PropertiesProxy<'static>,
330 interface: InterfaceName<'static>,
331 uncached_properties: HashSet<zvariant::Str<'static>>,
332 ) -> Result<(
333 PropertiesChangedStream,
334 InterfaceName<'static>,
335 HashSet<zvariant::Str<'static>>,
336 )> {
337 use ordered_stream::OrderedStreamExt;
338
339 let prop_changes = proxy.receive_properties_changed().await?.map(Either::Left);
340
341 let get_all = proxy
342 .inner()
343 .connection()
344 .call_method_raw(
345 Some(proxy.inner().destination()),
346 proxy.inner().path(),
347 Some(proxy.inner().interface()),
348 "GetAll",
349 BitFlags::empty(),
350 &interface,
351 )
352 .await
353 .map(|r| FromFuture::from(r.expect("no reply")).map(Either::Right))?;
354
355 let mut join = join_streams(prop_changes, get_all);
356
357 loop {
358 match join.next().await {
359 Some(Either::Left(_update)) => {
360 }
362 Some(Either::Right(populate)) => {
363 populate?.body().deserialize().map(|values| {
364 self.update_cache(&uncached_properties, &values, &[], &interface);
365 })?;
366 break;
367 }
368 None => break,
369 }
370 }
371 if let Some((Either::Left(update), _)) = Pin::new(&mut join).take_buffered() {
372 if let Ok(args) = update.args() {
375 if args.interface_name == interface {
376 self.update_cache(
377 &uncached_properties,
378 &args.changed_properties,
379 &args.invalidated_properties,
380 &interface,
381 );
382 }
383 }
384 }
385 let prop_changes = join.into_inner().0.into_inner();
389
390 Ok((prop_changes, interface, uncached_properties))
391 }
392
393 #[instrument(skip_all, level = "trace")]
395 async fn keep_updated(
396 &self,
397 mut prop_changes: PropertiesChangedStream,
398 interface: InterfaceName<'static>,
399 uncached_properties: HashSet<zvariant::Str<'static>>,
400 ) -> Result<()> {
401 use futures_lite::StreamExt;
402
403 trace!("Listening for property changes on {interface}...");
404 while let Some(update) = prop_changes.next().await {
405 if let Ok(args) = update.args() {
406 if args.interface_name == interface {
407 self.update_cache(
408 &uncached_properties,
409 &args.changed_properties,
410 &args.invalidated_properties,
411 &interface,
412 );
413 }
414 }
415 }
416
417 Ok(())
418 }
419
420 fn update_cache(
421 &self,
422 uncached_properties: &HashSet<Str<'_>>,
423 changed: &HashMap<&str, Value<'_>>,
424 invalidated: &[&str],
425 interface: &InterfaceName<'_>,
426 ) {
427 let mut values = self.values.write().expect("lock poisoned");
428
429 for inval in invalidated {
430 if uncached_properties.contains(&Str::from(*inval)) {
431 debug!(
432 "Ignoring invalidation of uncached property `{}.{}`",
433 interface, inval
434 );
435 continue;
436 }
437 trace!("Property `{interface}.{inval}` invalidated");
438
439 if let Some(entry) = values.get_mut(*inval) {
440 entry.value = None;
441 entry.event.notify(usize::MAX);
442 }
443 }
444
445 for (property_name, value) in changed {
446 if uncached_properties.contains(&Str::from(*property_name)) {
447 debug!(
448 "Ignoring update of uncached property `{}.{}`",
449 interface, property_name
450 );
451 continue;
452 }
453 trace!("Property `{interface}.{property_name}` updated");
454
455 let entry = values.entry(property_name.to_string()).or_default();
456
457 let value = match OwnedValue::try_from(value) {
458 Ok(value) => value,
459 Err(e) => {
460 debug!(
461 "Failed to convert property `{interface}.{property_name}` to OwnedValue: {e}"
462 );
463 continue;
464 }
465 };
466 entry.value = Some(value);
467 entry.event.notify(usize::MAX);
468 }
469 }
470
471 pub(crate) async fn ready(&self) -> Result<()> {
473 let listener = match &*self.caching_result.read().expect("lock poisoned") {
474 CachingResult::Caching { ready } => ready.listen(),
475 CachingResult::Cached { result } => return result.clone(),
476 };
477 listener.await;
478
479 match &*self.caching_result.read().expect("lock poisoned") {
481 CachingResult::Caching { .. } => unreachable!(),
484 CachingResult::Cached { result } => result.clone(),
485 }
486 }
487}
488
489impl<'a> ProxyInner<'a> {
490 pub(crate) fn new(
491 conn: Connection,
492 destination: BusName<'a>,
493 path: ObjectPath<'a>,
494 interface: InterfaceName<'a>,
495 cache: CacheProperties,
496 uncached_properties: HashSet<Str<'a>>,
497 ) -> Self {
498 let property_cache = match cache {
499 CacheProperties::Yes | CacheProperties::Lazily => Some(OnceLock::new()),
500 CacheProperties::No => None,
501 };
502 Self {
503 inner_without_borrows: ProxyInnerStatic {
504 conn,
505 dest_owner_change_match_rule: OnceLock::new(),
506 },
507 destination,
508 path,
509 interface,
510 property_cache,
511 uncached_properties,
512 }
513 }
514
515 pub(crate) async fn subscribe_dest_owner_change(&self) -> Result<()> {
519 if !self.inner_without_borrows.conn.is_bus() {
520 return Ok(());
522 }
523
524 let well_known_name = match &self.destination {
525 BusName::WellKnown(well_known_name) => well_known_name,
526 BusName::Unique(_) => return Ok(()),
527 };
528
529 if self
530 .inner_without_borrows
531 .dest_owner_change_match_rule
532 .get()
533 .is_some()
534 {
535 return Ok(());
537 }
538
539 let conn = &self.inner_without_borrows.conn;
540 let signal_rule: OwnedMatchRule = MatchRule::builder()
541 .msg_type(Type::Signal)
542 .sender("org.freedesktop.DBus")?
543 .path("/org/freedesktop/DBus")?
544 .interface("org.freedesktop.DBus")?
545 .member("NameOwnerChanged")?
546 .add_arg(well_known_name.as_str())?
547 .build()
548 .to_owned()
549 .into();
550
551 conn.add_match(
552 signal_rule.clone(),
553 Some(MAX_NAME_OWNER_CHANGED_SIGNALS_QUEUED),
554 )
555 .await?;
556
557 if self
558 .inner_without_borrows
559 .dest_owner_change_match_rule
560 .set(signal_rule.clone())
561 .is_err()
562 {
563 conn.remove_match(signal_rule).await?;
565 }
566
567 Ok(())
568 }
569}
570
571const MAX_NAME_OWNER_CHANGED_SIGNALS_QUEUED: usize = 8;
572
573impl<'a> Proxy<'a> {
574 pub async fn new<D, P, I>(
576 conn: &Connection,
577 destination: D,
578 path: P,
579 interface: I,
580 ) -> Result<Proxy<'a>>
581 where
582 D: TryInto<BusName<'a>>,
583 P: TryInto<ObjectPath<'a>>,
584 I: TryInto<InterfaceName<'a>>,
585 D::Error: Into<Error>,
586 P::Error: Into<Error>,
587 I::Error: Into<Error>,
588 {
589 Builder::new(conn)
590 .destination(destination)?
591 .path(path)?
592 .interface(interface)?
593 .build()
594 .await
595 }
596
597 pub async fn new_owned<D, P, I>(
600 conn: Connection,
601 destination: D,
602 path: P,
603 interface: I,
604 ) -> Result<Proxy<'a>>
605 where
606 D: TryInto<BusName<'static>>,
607 P: TryInto<ObjectPath<'static>>,
608 I: TryInto<InterfaceName<'static>>,
609 D::Error: Into<Error>,
610 P::Error: Into<Error>,
611 I::Error: Into<Error>,
612 {
613 Builder::new(&conn)
614 .destination(destination)?
615 .path(path)?
616 .interface(interface)?
617 .build()
618 .await
619 }
620
621 pub fn connection(&self) -> &Connection {
623 &self.inner.inner_without_borrows.conn
624 }
625
626 pub fn destination(&self) -> &BusName<'a> {
628 &self.inner.destination
629 }
630
631 pub fn path(&self) -> &ObjectPath<'a> {
633 &self.inner.path
634 }
635
636 pub fn interface(&self) -> &InterfaceName<'a> {
638 &self.inner.interface
639 }
640
641 pub async fn introspect(&self) -> fdo::Result<String> {
646 let proxy = IntrospectableProxy::builder(&self.inner.inner_without_borrows.conn)
647 .destination(&self.inner.destination)?
648 .path(&self.inner.path)?
649 .build()
650 .await?;
651
652 proxy.introspect().await
653 }
654
655 fn properties_proxy(&self) -> PropertiesProxy<'_> {
656 PropertiesProxy::builder(&self.inner.inner_without_borrows.conn)
657 .destination(self.inner.destination.as_ref())
659 .unwrap()
660 .path(self.inner.path.as_ref())
662 .unwrap()
663 .cache_properties(CacheProperties::No)
665 .build_internal()
666 .unwrap()
667 .into()
668 }
669
670 fn owned_properties_proxy(&self) -> PropertiesProxy<'static> {
671 PropertiesProxy::builder(&self.inner.inner_without_borrows.conn)
672 .destination(self.inner.destination.to_owned())
674 .unwrap()
675 .path(self.inner.path.to_owned())
677 .unwrap()
678 .cache_properties(CacheProperties::No)
680 .build_internal()
681 .unwrap()
682 .into()
683 }
684
685 pub(crate) fn get_property_cache(&self) -> Option<&Arc<PropertiesCache>> {
690 let cache = self.inner.property_cache.as_ref()?;
691 let (cache, _) = &cache.get_or_init(|| {
692 let proxy = self.owned_properties_proxy();
693 let interface = self.interface().to_owned();
694 let uncached_properties: HashSet<zvariant::Str<'static>> = self
695 .inner
696 .uncached_properties
697 .iter()
698 .map(|s| s.to_owned())
699 .collect();
700 let executor = self.connection().executor();
701
702 PropertiesCache::new(proxy, interface, executor, uncached_properties)
703 });
704
705 Some(cache)
706 }
707
708 pub fn cached_property<T>(&self, property_name: &str) -> Result<Option<T>>
715 where
716 T: TryFrom<OwnedValue>,
717 T::Error: Into<Error>,
718 {
719 self.cached_property_raw(property_name)
720 .as_deref()
721 .map(|v| T::try_from(OwnedValue::try_from(v)?).map_err(Into::into))
722 .transpose()
723 }
724
725 pub fn cached_property_raw<'p>(
730 &'p self,
731 property_name: &'p str,
732 ) -> Option<impl Deref<Target = Value<'static>> + 'p> {
733 if let Some(values) = self
734 .inner
735 .property_cache
736 .as_ref()
737 .and_then(OnceLock::get)
738 .map(|c| c.0.values.read().expect("lock poisoned"))
739 {
740 values
742 .get(property_name)
743 .and_then(|e| e.value.as_ref())?;
745
746 struct Wrapper<'a> {
747 values: RwLockReadGuard<'a, HashMap<String, PropertyValue>>,
748 property_name: &'a str,
749 }
750
751 impl Deref for Wrapper<'_> {
752 type Target = Value<'static>;
753
754 fn deref(&self) -> &Self::Target {
755 self.values
756 .get(self.property_name)
757 .and_then(|e| e.value.as_ref())
758 .map(|v| v.deref())
759 .expect("inexistent property")
760 }
761 }
762
763 Some(Wrapper {
764 values,
765 property_name,
766 })
767 } else {
768 None
769 }
770 }
771
772 async fn get_proxy_property(&self, property_name: &str) -> Result<OwnedValue> {
773 Ok(self
774 .properties_proxy()
775 .get(self.inner.interface.as_ref(), property_name)
776 .await?)
777 }
778
779 pub async fn get_property<T>(&self, property_name: &str) -> Result<T>
784 where
785 T: TryFrom<OwnedValue>,
786 T::Error: Into<Error>,
787 {
788 if let Some(cache) = self.get_property_cache() {
789 cache.ready().await?;
790 }
791 if let Some(value) = self.cached_property(property_name)? {
792 return Ok(value);
793 }
794
795 let value = self.get_proxy_property(property_name).await?;
796 value.try_into().map_err(Into::into)
797 }
798
799 pub async fn set_property<'t, T>(&self, property_name: &str, value: T) -> fdo::Result<()>
803 where
804 T: 't + Into<Value<'t>>,
805 {
806 self.properties_proxy()
807 .set(self.inner.interface.as_ref(), property_name, value.into())
808 .await
809 }
810
811 pub async fn call_method<'m, M, B>(&self, method_name: M, body: &B) -> Result<Message>
819 where
820 M: TryInto<MemberName<'m>>,
821 M::Error: Into<Error>,
822 B: serde::ser::Serialize + zvariant::DynamicType,
823 {
824 self.inner
825 .inner_without_borrows
826 .conn
827 .call_method(
828 Some(&self.inner.destination),
829 self.inner.path.as_str(),
830 Some(&self.inner.interface),
831 method_name,
832 body,
833 )
834 .await
835 }
836
837 pub async fn call<'m, M, B, R>(&self, method_name: M, body: &B) -> Result<R>
843 where
844 M: TryInto<MemberName<'m>>,
845 M::Error: Into<Error>,
846 B: serde::ser::Serialize + zvariant::DynamicType,
847 R: for<'d> zvariant::DynamicDeserialize<'d>,
848 {
849 let reply = self.call_method(method_name, body).await?;
850
851 reply.body().deserialize()
852 }
853
854 pub async fn call_with_flags<'m, M, B, R>(
864 &self,
865 method_name: M,
866 flags: BitFlags<MethodFlags>,
867 body: &B,
868 ) -> Result<Option<R>>
869 where
870 M: TryInto<MemberName<'m>>,
871 M::Error: Into<Error>,
872 B: serde::ser::Serialize + zvariant::DynamicType,
873 R: for<'d> zvariant::DynamicDeserialize<'d>,
874 {
875 let flags = flags.iter().map(Flags::from).collect::<BitFlags<_>>();
876 match self
877 .inner
878 .inner_without_borrows
879 .conn
880 .call_method_raw(
881 Some(self.destination()),
882 self.path(),
883 Some(self.interface()),
884 method_name,
885 flags,
886 body,
887 )
888 .await?
889 {
890 Some(reply) => reply.await?.body().deserialize().map(Some),
891 None => Ok(None),
892 }
893 }
894
895 pub async fn call_noreply<'m, M, B>(&self, method_name: M, body: &B) -> Result<()>
899 where
900 M: TryInto<MemberName<'m>>,
901 M::Error: Into<Error>,
902 B: serde::ser::Serialize + zvariant::DynamicType,
903 {
904 self.call_with_flags::<_, _, ()>(method_name, MethodFlags::NoReplyExpected.into(), body)
905 .await?;
906 Ok(())
907 }
908
909 pub async fn receive_signal<'m, M>(&self, signal_name: M) -> Result<SignalStream<'m>>
917 where
918 M: TryInto<MemberName<'m>>,
919 M::Error: Into<Error>,
920 {
921 self.receive_signal_with_args(signal_name, &[]).await
922 }
923
924 pub async fn receive_signal_with_args<'m, M>(
933 &self,
934 signal_name: M,
935 args: &[(u8, &str)],
936 ) -> Result<SignalStream<'m>>
937 where
938 M: TryInto<MemberName<'m>>,
939 M::Error: Into<Error>,
940 {
941 let signal_name = signal_name.try_into().map_err(Into::into)?;
942 self.receive_signals(Some(signal_name), args).await
943 }
944
945 async fn receive_signals<'m>(
946 &self,
947 signal_name: Option<MemberName<'m>>,
948 args: &[(u8, &str)],
949 ) -> Result<SignalStream<'m>> {
950 self.inner.subscribe_dest_owner_change().await?;
951
952 SignalStream::new(self.clone(), signal_name, args).await
953 }
954
955 pub async fn receive_all_signals(&self) -> Result<SignalStream<'static>> {
957 self.receive_signals(None, &[]).await
958 }
959
960 pub async fn receive_property_changed<'name: 'a, T>(
968 &self,
969 name: &'name str,
970 ) -> PropertyStream<'a, T> {
971 let properties = self.get_property_cache();
972 let changed_listener = if let Some(properties) = &properties {
973 let mut values = properties.values.write().expect("lock poisoned");
974 let entry = values
975 .entry(name.to_string())
976 .or_insert_with(PropertyValue::default);
977 let listener = entry.event.listen();
978 if entry.value.is_some() {
979 entry.event.notify(1);
980 }
981 listener
982 } else {
983 Event::new().listen()
984 };
985
986 PropertyStream {
987 name,
988 proxy: self.clone(),
989 changed_listener,
990 phantom: std::marker::PhantomData,
991 }
992 }
993
994 pub async fn receive_owner_changed(&self) -> Result<OwnerChangedStream<'a>> {
1006 use ordered_stream::OrderedStreamExt;
1007 let dbus_proxy = fdo::DBusProxy::builder(self.connection())
1008 .cache_properties(CacheProperties::No)
1009 .build()
1010 .await?;
1011 Ok(OwnerChangedStream {
1012 stream: dbus_proxy
1013 .receive_name_owner_changed_with_args(&[(0, self.destination().as_str())])
1014 .await?
1015 .map(Box::new(move |signal| {
1016 let args = signal.args().unwrap();
1017
1018 args.new_owner().as_ref().map(|owner| owner.to_owned())
1019 })),
1020 name: self.destination().clone(),
1021 })
1022 }
1023}
1024
1025#[derive(Debug, Default)]
1026struct PropertyValue {
1027 value: Option<OwnedValue>,
1028 event: Event,
1029}
1030
1031#[bitflags]
1033#[repr(u8)]
1034#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1035pub enum MethodFlags {
1036 NoReplyExpected = 0x1,
1045
1046 NoAutoStart = 0x2,
1054
1055 AllowInteractiveAuth = 0x4,
1061}
1062
1063impl From<MethodFlags> for Flags {
1064 fn from(method_flag: MethodFlags) -> Self {
1065 match method_flag {
1066 MethodFlags::NoReplyExpected => Self::NoReplyExpected,
1067 MethodFlags::NoAutoStart => Self::NoAutoStart,
1068 MethodFlags::AllowInteractiveAuth => Self::AllowInteractiveAuth,
1069 }
1070 }
1071}
1072
1073type OwnerChangedStreamMap = Map<
1074 fdo::NameOwnerChangedStream,
1075 Box<dyn FnMut(fdo::NameOwnerChanged) -> Option<UniqueName<'static>> + Send + Sync + Unpin>,
1076>;
1077
1078pub struct OwnerChangedStream<'a> {
1082 stream: OwnerChangedStreamMap,
1083 name: BusName<'a>,
1084}
1085
1086impl<'a> OwnerChangedStream<'a> {
1087 pub fn name(&self) -> &BusName<'a> {
1089 &self.name
1090 }
1091}
1092
1093impl stream::Stream for OwnerChangedStream<'_> {
1094 type Item = Option<UniqueName<'static>>;
1095
1096 fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
1097 OrderedStream::poll_next_before(self, cx, None).map(|res| res.into_data())
1098 }
1099}
1100
1101impl OrderedStream for OwnerChangedStream<'_> {
1102 type Data = Option<UniqueName<'static>>;
1103 type Ordering = Sequence;
1104
1105 fn poll_next_before(
1106 self: Pin<&mut Self>,
1107 cx: &mut Context<'_>,
1108 before: Option<&Self::Ordering>,
1109 ) -> Poll<PollResult<Self::Ordering, Self::Data>> {
1110 Pin::new(&mut self.get_mut().stream).poll_next_before(cx, before)
1111 }
1112}
1113
1114#[derive(Debug)]
1121pub struct SignalStream<'a> {
1122 stream: Join<MessageStream, Option<MessageStream>>,
1123 src_unique_name: Option<UniqueName<'static>>,
1124 signal_name: Option<MemberName<'a>>,
1125}
1126
1127impl<'a> SignalStream<'a> {
1128 pub fn name(&self) -> Option<&MemberName<'a>> {
1130 self.signal_name.as_ref()
1131 }
1132
1133 async fn new(
1134 proxy: Proxy<'_>,
1135 signal_name: Option<MemberName<'a>>,
1136 args: &[(u8, &str)],
1137 ) -> Result<SignalStream<'a>> {
1138 let mut rule_builder = MatchRule::builder()
1139 .msg_type(Type::Signal)
1140 .sender(proxy.destination())?
1141 .path(proxy.path())?
1142 .interface(proxy.interface())?;
1143 if let Some(name) = &signal_name {
1144 rule_builder = rule_builder.member(name)?;
1145 }
1146 for (i, arg) in args {
1147 rule_builder = rule_builder.arg(*i, *arg)?;
1148 }
1149 let signal_rule: OwnedMatchRule = rule_builder.build().to_owned().into();
1150 let conn = proxy.connection();
1151
1152 let (src_unique_name, stream) = match proxy.destination().to_owned() {
1153 BusName::Unique(name) => (
1154 Some(name),
1155 join_streams(
1156 MessageStream::for_match_rule(signal_rule, conn, None).await?,
1157 None,
1158 ),
1159 ),
1160 BusName::WellKnown(name) => {
1161 use ordered_stream::OrderedStreamExt;
1162
1163 let name_owner_changed_rule = MatchRule::builder()
1164 .msg_type(Type::Signal)
1165 .sender("org.freedesktop.DBus")?
1166 .path("/org/freedesktop/DBus")?
1167 .interface("org.freedesktop.DBus")?
1168 .member("NameOwnerChanged")?
1169 .add_arg(name.as_str())?
1170 .build();
1171 let name_owner_changed_stream = MessageStream::for_match_rule(
1172 name_owner_changed_rule,
1173 conn,
1174 Some(MAX_NAME_OWNER_CHANGED_SIGNALS_QUEUED),
1175 )
1176 .await?
1177 .map(Either::Left);
1178
1179 let get_name_owner = conn
1180 .call_method_raw(
1181 Some("org.freedesktop.DBus"),
1182 "/org/freedesktop/DBus",
1183 Some("org.freedesktop.DBus"),
1184 "GetNameOwner",
1185 BitFlags::empty(),
1186 &name,
1187 )
1188 .await
1189 .map(|r| FromFuture::from(r.expect("no reply")).map(Either::Right))?;
1190
1191 let mut join = join_streams(name_owner_changed_stream, get_name_owner);
1192
1193 let mut src_unique_name = loop {
1194 match join.next().await {
1195 Some(Either::Left(Ok(msg))) => {
1196 let signal = NameOwnerChanged::from_message(msg)
1197 .expect("`NameOwnerChanged` signal stream got wrong message");
1198 {
1199 break signal
1200 .args()
1201 .expect("`NameOwnerChanged` signal has no args")
1204 .new_owner()
1205 .as_ref()
1206 .map(UniqueName::to_owned);
1207 }
1208 }
1209 Some(Either::Left(Err(_))) => (),
1210 Some(Either::Right(Ok(response))) => {
1211 break Some(
1212 response.body().deserialize::<UniqueName<'_>>()?.to_owned(),
1213 );
1214 }
1215 Some(Either::Right(Err(e))) => {
1216 debug!("Failed to get owner of {name}: {e}");
1218
1219 break None;
1220 }
1221 None => {
1222 return Err(Error::InputOutput(
1223 std::io::Error::new(
1224 std::io::ErrorKind::BrokenPipe,
1225 "connection closed",
1226 )
1227 .into(),
1228 ));
1229 }
1230 }
1231 };
1232
1233 let (stream, _, queued) = join.into_inner();
1235 if let Some(msg) = queued.and_then(|e| match e.0 {
1236 Either::Left(Ok(msg)) => Some(msg),
1237 Either::Left(Err(_)) | Either::Right(_) => None,
1238 }) {
1239 if let Some(signal) = NameOwnerChanged::from_message(msg) {
1240 if let Ok(args) = signal.args() {
1241 match (args.name(), args.new_owner().deref()) {
1242 (BusName::WellKnown(n), Some(new_owner)) if n == &name => {
1243 src_unique_name = Some(new_owner.to_owned());
1244 }
1245 _ => (),
1246 }
1247 }
1248 }
1249 }
1250 let name_owner_changed_stream = stream.into_inner();
1251
1252 let stream = join_streams(
1253 MessageStream::for_match_rule(signal_rule, conn, None).await?,
1254 Some(name_owner_changed_stream),
1255 );
1256
1257 (src_unique_name, stream)
1258 }
1259 };
1260
1261 Ok(SignalStream {
1262 stream,
1263 src_unique_name,
1264 signal_name,
1265 })
1266 }
1267
1268 fn filter(&mut self, msg: &Message) -> Result<bool> {
1269 let header = msg.header();
1270 let sender = header.sender();
1271 if sender == self.src_unique_name.as_ref() {
1272 return Ok(true);
1273 }
1274
1275 if let Some(signal) = NameOwnerChanged::from_message(msg.clone()) {
1277 let args = signal.args()?;
1278 self.src_unique_name = args.new_owner().as_ref().map(|n| n.to_owned());
1279 }
1280
1281 Ok(false)
1282 }
1283}
1284
1285impl stream::Stream for SignalStream<'_> {
1286 type Item = Message;
1287
1288 fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
1289 OrderedStream::poll_next_before(self, cx, None).map(|res| res.into_data())
1290 }
1291}
1292
1293impl OrderedStream for SignalStream<'_> {
1294 type Data = Message;
1295 type Ordering = Sequence;
1296
1297 fn poll_next_before(
1298 self: Pin<&mut Self>,
1299 cx: &mut Context<'_>,
1300 before: Option<&Self::Ordering>,
1301 ) -> Poll<PollResult<Self::Ordering, Self::Data>> {
1302 let this = self.get_mut();
1303 loop {
1304 match ready!(OrderedStream::poll_next_before(
1305 Pin::new(&mut this.stream),
1306 cx,
1307 before
1308 )) {
1309 PollResult::Item { data, ordering } => {
1310 if let Ok(msg) = data {
1311 if let Ok(true) = this.filter(&msg) {
1312 return Poll::Ready(PollResult::Item {
1313 data: msg,
1314 ordering,
1315 });
1316 }
1317 }
1318 }
1319 PollResult::Terminated => return Poll::Ready(PollResult::Terminated),
1320 PollResult::NoneBefore => return Poll::Ready(PollResult::NoneBefore),
1321 }
1322 }
1323 }
1324}
1325
1326impl stream::FusedStream for SignalStream<'_> {
1327 fn is_terminated(&self) -> bool {
1328 ordered_stream::FusedOrderedStream::is_terminated(&self.stream)
1329 }
1330}
1331
1332#[async_trait::async_trait]
1333impl AsyncDrop for SignalStream<'_> {
1334 async fn async_drop(self) {
1335 let (signals, names, _buffered) = self.stream.into_inner();
1336 signals.async_drop().await;
1337 if let Some(names) = names {
1338 names.async_drop().await;
1339 }
1340 }
1341}
1342
1343#[cfg(feature = "blocking-api")]
1344impl<'a> From<crate::blocking::Proxy<'a>> for Proxy<'a> {
1345 fn from(proxy: crate::blocking::Proxy<'a>) -> Self {
1346 proxy.into_inner()
1347 }
1348}
1349
1350pub trait ProxyImpl<'c>
1353where
1354 Self: Sized,
1355{
1356 fn builder(conn: &Connection) -> Builder<'c, Self>;
1358
1359 fn into_inner(self) -> Proxy<'c>;
1361
1362 fn inner(&self) -> &Proxy<'c>;
1364}
1365
1366enum Either<L, R> {
1367 Left(L),
1368 Right(R),
1369}
1370
1371#[cfg(test)]
1372mod tests {
1373 use super::*;
1374 use crate::{connection, interface, object_server::SignalEmitter, proxy, utils::block_on};
1375 use futures_util::StreamExt;
1376 use ntest::timeout;
1377 use test_log::test;
1378
1379 #[test]
1380 #[timeout(15000)]
1381 fn signal() {
1382 block_on(test_signal()).unwrap();
1383 }
1384
1385 async fn test_signal() -> Result<()> {
1386 let conn = Connection::session().await?;
1389 let dest_conn = Connection::session().await?;
1390 let unique_name = dest_conn.unique_name().unwrap().clone();
1391
1392 let well_known = "org.freedesktop.zbus.async.ProxySignalStreamTest";
1393 let proxy: Proxy<'_> = Builder::new(&conn)
1394 .destination(well_known)?
1395 .path("/does/not/matter")?
1396 .interface("does.not.matter")?
1397 .build()
1398 .await?;
1399 let mut owner_changed_stream = proxy.receive_owner_changed().await?;
1400
1401 let proxy = fdo::DBusProxy::new(&dest_conn).await?;
1402 let mut name_acquired_stream = proxy
1403 .inner()
1404 .receive_signal_with_args("NameAcquired", &[(0, well_known)])
1405 .await?;
1406
1407 let prop_stream = proxy
1408 .inner()
1409 .receive_property_changed("SomeProp")
1410 .await
1411 .filter_map(|changed| async move {
1412 let v: Option<u32> = changed.get().await.ok();
1413 dbg!(v)
1414 });
1415 drop(proxy);
1416 drop(prop_stream);
1417
1418 dest_conn.request_name(well_known).await?;
1419
1420 let (new_owner, acquired_signal) =
1421 futures_util::join!(owner_changed_stream.next(), name_acquired_stream.next(),);
1422
1423 assert_eq!(&new_owner.unwrap().unwrap(), &*unique_name);
1424
1425 let acquired_signal = acquired_signal.unwrap();
1426 assert_eq!(
1427 acquired_signal.body().deserialize::<&str>().unwrap(),
1428 well_known
1429 );
1430
1431 let proxy = Proxy::new(&conn, &unique_name, "/does/not/matter", "does.not.matter").await?;
1432 let mut unique_name_changed_stream = proxy.receive_owner_changed().await?;
1433
1434 drop(dest_conn);
1435 name_acquired_stream.async_drop().await;
1436
1437 let new_owner = owner_changed_stream.next().await;
1439 assert!(new_owner.unwrap().is_none());
1440
1441 let new_unique_owner = unique_name_changed_stream.next().await;
1442 assert!(new_unique_owner.unwrap().is_none());
1443
1444 Ok(())
1445 }
1446
1447 #[test]
1448 #[timeout(15000)]
1449 fn signal_stream_deadlock() {
1450 block_on(test_signal_stream_deadlock()).unwrap();
1451 }
1452
1453 async fn test_signal_stream_deadlock() -> Result<()> {
1461 #[proxy(
1462 gen_blocking = false,
1463 default_path = "/org/zbus/Test",
1464 default_service = "org.zbus.Test.MR501",
1465 interface = "org.zbus.Test"
1466 )]
1467 trait Test {
1468 #[zbus(signal)]
1469 fn my_signal(&self, msg: &str) -> Result<()>;
1470 }
1471
1472 struct TestIface;
1473
1474 #[interface(name = "org.zbus.Test")]
1475 impl TestIface {
1476 #[zbus(signal)]
1477 async fn my_signal(context: &SignalEmitter<'_>, msg: &'static str) -> Result<()>;
1478 }
1479
1480 let test_iface = TestIface;
1481 let server_conn = connection::Builder::session()?
1482 .name("org.zbus.Test.MR501")?
1483 .serve_at("/org/zbus/Test", test_iface)?
1484 .build()
1485 .await?;
1486
1487 let client_conn = connection::Builder::session()?
1488 .max_queued(1)
1489 .build()
1490 .await?;
1491
1492 let test_proxy = TestProxy::new(&client_conn).await?;
1493 let test_prop_proxy = PropertiesProxy::builder(&client_conn)
1494 .destination("org.zbus.Test.MR501")?
1495 .path("/org/zbus/Test")?
1496 .build()
1497 .await?;
1498
1499 let (tx, mut rx) = tokio::sync::mpsc::channel(1);
1500
1501 let handle = {
1502 let tx = tx.clone();
1503 let conn = server_conn.clone();
1504 let server_fut = async move {
1505 use std::time::Duration;
1506
1507 #[cfg(not(feature = "tokio"))]
1508 use async_io::Timer;
1509
1510 #[cfg(feature = "tokio")]
1511 use tokio::time::sleep;
1512
1513 let iface_ref = conn
1514 .object_server()
1515 .interface::<_, TestIface>("/org/zbus/Test")
1516 .await
1517 .unwrap();
1518
1519 let context = iface_ref.signal_emitter();
1520 while !tx.is_closed() {
1521 for _ in 0..10 {
1522 TestIface::my_signal(context, "This is a test")
1523 .await
1524 .unwrap();
1525 }
1526
1527 #[cfg(not(feature = "tokio"))]
1528 Timer::after(Duration::from_millis(5)).await;
1529
1530 #[cfg(feature = "tokio")]
1531 sleep(Duration::from_millis(5)).await;
1532 }
1533 };
1534 server_conn.executor().spawn(server_fut, "server_task")
1535 };
1536
1537 let signal_fut = async {
1538 let mut signal_stream = test_proxy.receive_my_signal().await.unwrap();
1539
1540 tx.send(()).await.unwrap();
1541
1542 while let Some(_signal) = signal_stream.next().await {}
1543 };
1544
1545 let prop_fut = async move {
1546 rx.recv().await.unwrap();
1547 let _prop_stream = test_prop_proxy.receive_properties_changed().await.unwrap();
1548 };
1549
1550 futures_util::pin_mut!(signal_fut);
1551 futures_util::pin_mut!(prop_fut);
1552
1553 futures_util::future::select(signal_fut, prop_fut).await;
1554
1555 handle.await?;
1556
1557 Ok(())
1558 }
1559}