diff --git a/ci/valgrind-check/src/pub_sub/bin/z_pub_sub.rs b/ci/valgrind-check/src/pub_sub/bin/z_pub_sub.rs index f3b1dd0efe..ad96d0b2b0 100644 --- a/ci/valgrind-check/src/pub_sub/bin/z_pub_sub.rs +++ b/ci/valgrind-check/src/pub_sub/bin/z_pub_sub.rs @@ -13,7 +13,7 @@ // use std::time::Duration; -use zenoh::{config::Config, key_expr::KeyExpr, prelude::*}; +use zenoh::{config::Config, key_expr::KeyExpr}; #[tokio::main] async fn main() { diff --git a/ci/valgrind-check/src/queryable_get/bin/z_queryable_get.rs b/ci/valgrind-check/src/queryable_get/bin/z_queryable_get.rs index 8ea7be201b..e82ecba477 100644 --- a/ci/valgrind-check/src/queryable_get/bin/z_queryable_get.rs +++ b/ci/valgrind-check/src/queryable_get/bin/z_queryable_get.rs @@ -16,7 +16,6 @@ use std::{convert::TryFrom, time::Duration}; use zenoh::{ config::Config, key_expr::KeyExpr, - prelude::*, query::{QueryTarget, Selector}, }; diff --git a/commons/zenoh-config/src/lib.rs b/commons/zenoh-config/src/lib.rs index 2d9ba0beee..b57c62edde 100644 --- a/commons/zenoh-config/src/lib.rs +++ b/commons/zenoh-config/src/lib.rs @@ -224,9 +224,8 @@ pub fn client, T: Into>(peers: I) -> Config #[test] fn config_keys() { - use validated_struct::ValidatedMap; let c = Config::default(); - dbg!(c.keys()); + dbg!(Vec::from_iter(c.keys())); } validated_struct::validator! { @@ -659,6 +658,40 @@ fn config_deser() { } impl Config { + pub fn insert<'d, D: serde::Deserializer<'d>>( + &mut self, + key: &str, + value: D, + ) -> Result<(), validated_struct::InsertionError> + where + validated_struct::InsertionError: From, + { + ::insert(self, key, value) + } + + pub fn get( + &self, + key: &str, + ) -> Result<::Accessor, GetError> { + ::get(self, key) + } + + pub fn get_json(&self, key: &str) -> Result { + ::get_json(self, key) + } + + pub fn insert_json5( + &mut self, + key: &str, + value: &str, + ) -> Result<(), validated_struct::InsertionError> { + ::insert_json5(self, key, value) + } + + pub fn keys(&self) -> impl Iterator { + ::keys(self).into_iter() + } + pub fn set_plugin_validator(&mut self, validator: Weak) { self.plugins.validator = validator; } @@ -778,7 +811,6 @@ impl std::fmt::Display for Config { #[test] fn config_from_json() { - use validated_struct::ValidatedMap; let from_str = serde_json::Deserializer::from_str; let mut config = Config::from_deserializer(&mut from_str(r#"{}"#)).unwrap(); config @@ -944,6 +976,52 @@ where self.lock().keys() } } +impl Notifier +where + T: for<'a> ValidatedMapAssociatedTypes<'a, Accessor = &'a dyn Any>, +{ + pub fn insert<'d, D: serde::Deserializer<'d>>( + &self, + key: &str, + value: D, + ) -> Result<(), validated_struct::InsertionError> + where + validated_struct::InsertionError: From, + { + self.lock().insert(key, value)?; + self.notify(key); + Ok(()) + } + + pub fn get( + &self, + key: &str, + ) -> Result<::Accessor, GetError> { + let guard = zlock!(self.inner.inner); + // SAFETY: MutexGuard pins the mutex behind which the value is held. + let subref = guard.get(key.as_ref())? as *const _; + Ok(GetGuard { + _guard: guard, + subref, + }) + } + + pub fn get_json(&self, key: &str) -> Result { + self.lock().get_json(key) + } + + pub fn insert_json5( + &self, + key: &str, + value: &str, + ) -> Result<(), validated_struct::InsertionError> { + self.insert(key, &mut json5::Deserializer::from_str(value)?) + } + + pub fn keys(&self) -> impl Iterator { + self.lock().keys().into_iter() + } +} pub struct GetGuard<'a, T> { _guard: MutexGuard<'a, T>, diff --git a/examples/examples/z_alloc_shm.rs b/examples/examples/z_alloc_shm.rs index 1f2f544a25..09ea264f03 100644 --- a/examples/examples/z_alloc_shm.rs +++ b/examples/examples/z_alloc_shm.rs @@ -12,7 +12,6 @@ // ZettaScale Zenoh Team, // use zenoh::{ - prelude::*, shm::{ AllocAlignment, BlockOn, Deallocate, Defragment, GarbageCollect, PosixShmProviderBackend, ShmProviderBuilder, POSIX_PROTOCOL_ID, @@ -27,7 +26,7 @@ async fn main() { run().await.unwrap() } -async fn run() -> ZResult<()> { +async fn run() -> zenoh::Result<()> { // create an SHM backend... // NOTE: For extended PosixShmProviderBackend API please check z_posix_shm_provider.rs let backend = PosixShmProviderBackend::builder() diff --git a/examples/examples/z_bytes_shm.rs b/examples/examples/z_bytes_shm.rs index 6ae69407d0..1db1680be7 100644 --- a/examples/examples/z_bytes_shm.rs +++ b/examples/examples/z_bytes_shm.rs @@ -13,11 +13,11 @@ // use zenoh::{ bytes::ZBytes, - prelude::*, shm::{ zshm, zshmmut, PosixShmProviderBackend, ShmProviderBuilder, ZShm, ZShmMut, POSIX_PROTOCOL_ID, }, + Wait, }; fn main() { diff --git a/examples/examples/z_forward.rs b/examples/examples/z_forward.rs index 8654a8f420..e1925a5477 100644 --- a/examples/examples/z_forward.rs +++ b/examples/examples/z_forward.rs @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // use clap::Parser; -use zenoh::{key_expr::KeyExpr, prelude::*, Config}; +use zenoh::{key_expr::KeyExpr, Config}; use zenoh_examples::CommonArgs; use zenoh_ext::SubscriberForward; diff --git a/examples/examples/z_get_liveliness.rs b/examples/examples/z_get_liveliness.rs index f057d81ba2..b0c4006e13 100644 --- a/examples/examples/z_get_liveliness.rs +++ b/examples/examples/z_get_liveliness.rs @@ -14,7 +14,7 @@ use std::time::Duration; use clap::Parser; -use zenoh::{key_expr::KeyExpr, prelude::*, Config}; +use zenoh::{key_expr::KeyExpr, Config}; use zenoh_examples::CommonArgs; #[tokio::main] diff --git a/examples/examples/z_info.rs b/examples/examples/z_info.rs index d7859b5de2..3cd6669dae 100644 --- a/examples/examples/z_info.rs +++ b/examples/examples/z_info.rs @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // use clap::Parser; -use zenoh::{prelude::*, session::ZenohId}; +use zenoh::session::ZenohId; use zenoh_examples::CommonArgs; #[tokio::main] diff --git a/examples/examples/z_liveliness.rs b/examples/examples/z_liveliness.rs index 2f102d1f93..8e86ef05c4 100644 --- a/examples/examples/z_liveliness.rs +++ b/examples/examples/z_liveliness.rs @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // use clap::Parser; -use zenoh::{key_expr::KeyExpr, prelude::*, Config}; +use zenoh::{key_expr::KeyExpr, Config}; use zenoh_examples::CommonArgs; #[tokio::main] diff --git a/examples/examples/z_ping.rs b/examples/examples/z_ping.rs index cd40945ad8..9f715ea153 100644 --- a/examples/examples/z_ping.rs +++ b/examples/examples/z_ping.rs @@ -14,7 +14,7 @@ use std::time::{Duration, Instant}; use clap::Parser; -use zenoh::{bytes::ZBytes, key_expr::keyexpr, prelude::*, qos::CongestionControl, Config}; +use zenoh::{bytes::ZBytes, key_expr::keyexpr, qos::CongestionControl, Config, Wait}; use zenoh_examples::CommonArgs; fn main() { diff --git a/examples/examples/z_ping_shm.rs b/examples/examples/z_ping_shm.rs index 3f0434e905..969bd6cbb5 100644 --- a/examples/examples/z_ping_shm.rs +++ b/examples/examples/z_ping_shm.rs @@ -17,7 +17,6 @@ use clap::Parser; use zenoh::{ bytes::ZBytes, key_expr::keyexpr, - prelude::*, qos::CongestionControl, shm::{PosixShmProviderBackend, ShmProviderBuilder, POSIX_PROTOCOL_ID}, Config, Wait, diff --git a/examples/examples/z_pong.rs b/examples/examples/z_pong.rs index 2867d7cea6..4199968f5d 100644 --- a/examples/examples/z_pong.rs +++ b/examples/examples/z_pong.rs @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // use clap::Parser; -use zenoh::{key_expr::keyexpr, prelude::*, qos::CongestionControl, Config}; +use zenoh::{key_expr::keyexpr, qos::CongestionControl, Config, Wait}; use zenoh_examples::CommonArgs; fn main() { @@ -21,7 +21,7 @@ fn main() { let (config, express) = parse_args(); - let session = zenoh::open(config).wait().unwrap().into_arc(); + let session = zenoh::open(config).wait().unwrap(); // The key expression to read the data from let key_expr_ping = keyexpr::new("test/ping").unwrap(); diff --git a/examples/examples/z_pub.rs b/examples/examples/z_pub.rs index cc97a99971..4472aa9f6a 100644 --- a/examples/examples/z_pub.rs +++ b/examples/examples/z_pub.rs @@ -14,7 +14,7 @@ use std::time::Duration; use clap::Parser; -use zenoh::{bytes::Encoding, key_expr::KeyExpr, prelude::*, Config}; +use zenoh::{bytes::Encoding, key_expr::KeyExpr, Config}; use zenoh_examples::CommonArgs; #[tokio::main] diff --git a/examples/examples/z_pub_shm.rs b/examples/examples/z_pub_shm.rs index 9c6311f59d..fb1900b1d7 100644 --- a/examples/examples/z_pub_shm.rs +++ b/examples/examples/z_pub_shm.rs @@ -14,7 +14,6 @@ use clap::Parser; use zenoh::{ key_expr::KeyExpr, - prelude::*, shm::{ BlockOn, GarbageCollect, PosixShmProviderBackend, ShmProviderBuilder, POSIX_PROTOCOL_ID, }, @@ -25,7 +24,7 @@ use zenoh_examples::CommonArgs; const N: usize = 10; #[tokio::main] -async fn main() -> Result<(), ZError> { +async fn main() -> zenoh::Result<()> { // Initiate logging zenoh::init_log_from_env_or("error"); diff --git a/examples/examples/z_pub_shm_thr.rs b/examples/examples/z_pub_shm_thr.rs index 699b6df341..539127fb8a 100644 --- a/examples/examples/z_pub_shm_thr.rs +++ b/examples/examples/z_pub_shm_thr.rs @@ -14,7 +14,6 @@ use clap::Parser; use zenoh::{ bytes::ZBytes, - prelude::*, qos::CongestionControl, shm::{PosixShmProviderBackend, ShmProviderBuilder, POSIX_PROTOCOL_ID}, Config, Wait, diff --git a/examples/examples/z_pub_thr.rs b/examples/examples/z_pub_thr.rs index 9014f78763..dc18715e2a 100644 --- a/examples/examples/z_pub_thr.rs +++ b/examples/examples/z_pub_thr.rs @@ -17,8 +17,8 @@ use std::convert::TryInto; use clap::Parser; use zenoh::{ bytes::ZBytes, - prelude::*, qos::{CongestionControl, Priority}, + Wait, }; use zenoh_examples::CommonArgs; diff --git a/examples/examples/z_pull.rs b/examples/examples/z_pull.rs index e04e1a6b32..c677b545b8 100644 --- a/examples/examples/z_pull.rs +++ b/examples/examples/z_pull.rs @@ -14,7 +14,7 @@ use std::time::Duration; use clap::Parser; -use zenoh::{handlers::RingChannel, key_expr::KeyExpr, prelude::*, Config}; +use zenoh::{handlers::RingChannel, key_expr::KeyExpr, Config}; use zenoh_examples::CommonArgs; #[tokio::main] diff --git a/examples/examples/z_queryable.rs b/examples/examples/z_queryable.rs index 7ea3b7b5a1..b3b5ca9bf0 100644 --- a/examples/examples/z_queryable.rs +++ b/examples/examples/z_queryable.rs @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // use clap::Parser; -use zenoh::{key_expr::KeyExpr, prelude::*, Config}; +use zenoh::{key_expr::KeyExpr, Config}; use zenoh_examples::CommonArgs; #[tokio::main] diff --git a/examples/examples/z_queryable_shm.rs b/examples/examples/z_queryable_shm.rs index a515671197..db00ddb118 100644 --- a/examples/examples/z_queryable_shm.rs +++ b/examples/examples/z_queryable_shm.rs @@ -15,7 +15,6 @@ use clap::Parser; use zenoh::{ bytes::ZBytes, key_expr::KeyExpr, - prelude::*, shm::{ zshm, BlockOn, GarbageCollect, PosixShmProviderBackend, ShmProviderBuilder, POSIX_PROTOCOL_ID, diff --git a/examples/examples/z_storage.rs b/examples/examples/z_storage.rs index 2cce1640b7..9f6f50b16f 100644 --- a/examples/examples/z_storage.rs +++ b/examples/examples/z_storage.rs @@ -19,7 +19,6 @@ use clap::Parser; use futures::select; use zenoh::{ key_expr::{keyexpr, KeyExpr}, - prelude::*, sample::{Sample, SampleKind}, Config, }; diff --git a/examples/examples/z_sub.rs b/examples/examples/z_sub.rs index 8f48dee25c..26fc768737 100644 --- a/examples/examples/z_sub.rs +++ b/examples/examples/z_sub.rs @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // use clap::Parser; -use zenoh::{key_expr::KeyExpr, prelude::*, Config}; +use zenoh::{key_expr::KeyExpr, Config}; use zenoh_examples::CommonArgs; #[tokio::main] diff --git a/examples/examples/z_sub_liveliness.rs b/examples/examples/z_sub_liveliness.rs index be729e34d1..79c0cd5b1a 100644 --- a/examples/examples/z_sub_liveliness.rs +++ b/examples/examples/z_sub_liveliness.rs @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // use clap::Parser; -use zenoh::{key_expr::KeyExpr, prelude::*, sample::SampleKind, Config}; +use zenoh::{key_expr::KeyExpr, sample::SampleKind, Config}; use zenoh_examples::CommonArgs; #[tokio::main] diff --git a/examples/examples/z_sub_shm.rs b/examples/examples/z_sub_shm.rs index 215268501d..a4660485dc 100644 --- a/examples/examples/z_sub_shm.rs +++ b/examples/examples/z_sub_shm.rs @@ -14,7 +14,7 @@ use clap::Parser; #[cfg(all(feature = "shared-memory", feature = "unstable"))] use zenoh::shm::zshm; -use zenoh::{bytes::ZBytes, config::Config, key_expr::KeyExpr, prelude::*}; +use zenoh::{bytes::ZBytes, config::Config, key_expr::KeyExpr}; use zenoh_examples::CommonArgs; #[tokio::main] diff --git a/examples/examples/z_sub_thr.rs b/examples/examples/z_sub_thr.rs index 7098a52134..bbc4541cd1 100644 --- a/examples/examples/z_sub_thr.rs +++ b/examples/examples/z_sub_thr.rs @@ -14,7 +14,7 @@ use std::time::Instant; use clap::Parser; -use zenoh::{prelude::*, Config}; +use zenoh::{Config, Wait}; use zenoh_examples::CommonArgs; struct Stats { @@ -87,9 +87,7 @@ fn main() { } }) .wait() - .unwrap() - // Make the subscriber run in background, until the session is closed. - .background(); + .unwrap(); println!("Press CTRL-C to quit..."); std::thread::park(); diff --git a/examples/src/lib.rs b/examples/src/lib.rs index bb6b025b2b..20409b4f85 100644 --- a/examples/src/lib.rs +++ b/examples/src/lib.rs @@ -3,7 +3,7 @@ //! Check ../README.md for usage. //! -use zenoh::config::{Config, ValidatedMap}; +use zenoh::config::Config; #[derive(clap::ValueEnum, Clone, Copy, PartialEq, Eq, Hash, Debug)] pub enum Wai { diff --git a/plugins/zenoh-backend-example/src/lib.rs b/plugins/zenoh-backend-example/src/lib.rs index b9e670b799..4899bed6b0 100644 --- a/plugins/zenoh-backend-example/src/lib.rs +++ b/plugins/zenoh-backend-example/src/lib.rs @@ -15,7 +15,7 @@ use std::collections::{hash_map::Entry, HashMap}; use async_trait::async_trait; use tokio::sync::RwLock; -use zenoh::{internal::Value, key_expr::OwnedKeyExpr, prelude::*, time::Timestamp}; +use zenoh::{internal::Value, key_expr::OwnedKeyExpr, time::Timestamp, Result as ZResult}; use zenoh_backend_traits::{ config::{StorageConfig, VolumeConfig}, Capability, History, Persistence, Storage, StorageInsertionResult, StoredData, Volume, diff --git a/plugins/zenoh-backend-traits/src/lib.rs b/plugins/zenoh-backend-traits/src/lib.rs index a75d934050..cd2238dc6a 100644 --- a/plugins/zenoh-backend-traits/src/lib.rs +++ b/plugins/zenoh-backend-traits/src/lib.rs @@ -29,12 +29,12 @@ //! ``` //! use std::sync::Arc; //! use async_trait::async_trait; -//! use zenoh::{key_expr::OwnedKeyExpr, prelude::*, time::Timestamp, internal::Value}; +//! use zenoh::{key_expr::OwnedKeyExpr, time::Timestamp, internal::Value}; //! use zenoh_backend_traits::*; //! use zenoh_backend_traits::config::*; //! //! #[no_mangle] -//! pub fn create_volume(config: VolumeConfig) -> ZResult> { +//! pub fn create_volume(config: VolumeConfig) -> zenoh::Result> { //! Ok(Box::new(MyVolumeType { config })) //! } //! @@ -62,7 +62,7 @@ //! } //! } //! -//! async fn create_storage(&self, properties: StorageConfig) -> ZResult> { +//! async fn create_storage(&self, properties: StorageConfig) -> zenoh::Result> { //! // The properties are the ones passed via a PUT in the admin space for Storage creation. //! Ok(Box::new(MyStorage::new(properties).await?)) //! } @@ -74,7 +74,7 @@ //! } //! //! impl MyStorage { -//! async fn new(config: StorageConfig) -> ZResult { +//! async fn new(config: StorageConfig) -> zenoh::Result { //! Ok(MyStorage { config }) //! } //! } @@ -88,7 +88,7 @@ //! self.config.to_json_value() //! } //! -//! async fn put(&mut self, key: Option, value: Value, timestamp: Timestamp) -> ZResult { +//! async fn put(&mut self, key: Option, value: Value, timestamp: Timestamp) -> zenoh::Result { //! // the key will be None if it exactly matched with the strip_prefix //! // create a storage specific special structure to store it //! // Store the data with timestamp @@ -99,14 +99,14 @@ //! // return Ok(StorageInsertionResult::Outdated); //! } //! -//! async fn delete(&mut self, key: Option, timestamp: Timestamp) -> ZResult { +//! async fn delete(&mut self, key: Option, timestamp: Timestamp) -> zenoh::Result { //! // @TODO: //! // delete the actual entry from storage //! return Ok(StorageInsertionResult::Deleted); //! } //! //! // When receiving a GET operation -//! async fn get(&mut self, key_expr: Option, parameters: &str) -> ZResult> { +//! async fn get(&mut self, key_expr: Option, parameters: &str) -> zenoh::Result> { //! // @TODO: //! // get the data associated with key_expr and return it //! // NOTE: in case parameters is not empty something smarter should be done with returned data... @@ -114,7 +114,7 @@ //! } //! //! // To get all entries in the datastore -//! async fn get_all_entries(&self) -> ZResult, Timestamp)>> { +//! async fn get_all_entries(&self) -> zenoh::Result, Timestamp)>> { //! // @TODO: get the list of (key, timestamp) in the datastore //! Ok(Vec::new()) //! } diff --git a/plugins/zenoh-plugin-example/src/lib.rs b/plugins/zenoh-plugin-example/src/lib.rs index aa943c12e3..9fc53c1c80 100644 --- a/plugins/zenoh-plugin-example/src/lib.rs +++ b/plugins/zenoh-plugin-example/src/lib.rs @@ -34,9 +34,8 @@ use zenoh::{ zlock, }, key_expr::{keyexpr, KeyExpr}, - prelude::ZResult, sample::Sample, - session::SessionDeclarations, + Result as ZResult, }; use zenoh_plugin_trait::{plugin_long_version, plugin_version, Plugin, PluginControl}; diff --git a/plugins/zenoh-plugin-rest/examples/z_serve_sse.rs b/plugins/zenoh-plugin-rest/examples/z_serve_sse.rs index 849800de73..fd81ff279f 100644 --- a/plugins/zenoh-plugin-rest/examples/z_serve_sse.rs +++ b/plugins/zenoh-plugin-rest/examples/z_serve_sse.rs @@ -14,9 +14,7 @@ use std::time::Duration; use clap::{arg, Command}; -use zenoh::{ - config::Config, key_expr::keyexpr, qos::CongestionControl, session::SessionDeclarations, -}; +use zenoh::{config::Config, key_expr::keyexpr, qos::CongestionControl}; const HTML: &str = r#"
diff --git a/plugins/zenoh-plugin-rest/src/lib.rs b/plugins/zenoh-plugin-rest/src/lib.rs index f0d1cc65f0..90dd6002df 100644 --- a/plugins/zenoh-plugin-rest/src/lib.rs +++ b/plugins/zenoh-plugin-rest/src/lib.rs @@ -44,10 +44,10 @@ use zenoh::{ zerror, }, key_expr::{keyexpr, KeyExpr}, - prelude::*, query::{Parameters, QueryConsolidation, Reply, Selector, ZenohParameters}, sample::{Sample, SampleKind}, - session::{Session, SessionDeclarations}, + session::Session, + Result as ZResult, }; use zenoh_plugin_trait::{plugin_long_version, plugin_version, Plugin, PluginControl}; diff --git a/plugins/zenoh-plugin-storage-manager/src/replica/align_queryable.rs b/plugins/zenoh-plugin-storage-manager/src/replica/align_queryable.rs index 737ce79144..1baad55db6 100644 --- a/plugins/zenoh-plugin-storage-manager/src/replica/align_queryable.rs +++ b/plugins/zenoh-plugin-storage-manager/src/replica/align_queryable.rs @@ -21,8 +21,8 @@ use std::{ }; use zenoh::{ - internal::Value, key_expr::OwnedKeyExpr, prelude::*, query::Parameters, sample::Sample, - time::Timestamp, Session, + internal::Value, key_expr::OwnedKeyExpr, query::Parameters, sample::Sample, time::Timestamp, + Session, }; use super::{digest::*, Snapshotter}; diff --git a/plugins/zenoh-plugin-storage-manager/src/replica/mod.rs b/plugins/zenoh-plugin-storage-manager/src/replica/mod.rs index 4766914e21..a9302cd8cf 100644 --- a/plugins/zenoh-plugin-storage-manager/src/replica/mod.rs +++ b/plugins/zenoh-plugin-storage-manager/src/replica/mod.rs @@ -24,7 +24,7 @@ use std::{ use flume::{Receiver, Sender}; use futures::{pin_mut, select, FutureExt}; use tokio::{sync::RwLock, time::interval}; -use zenoh::{key_expr::keyexpr, prelude::*}; +use zenoh::key_expr::keyexpr; use zenoh_backend_traits::config::{ReplicaConfig, StorageConfig}; use crate::{backends_mgt::StoreIntercept, storages_mgt::StorageMessage}; diff --git a/plugins/zenoh-plugin-storage-manager/src/replica/storage.rs b/plugins/zenoh-plugin-storage-manager/src/replica/storage.rs index 956cd57f8d..6fafe04abd 100644 --- a/plugins/zenoh-plugin-storage-manager/src/replica/storage.rs +++ b/plugins/zenoh-plugin-storage-manager/src/replica/storage.rs @@ -35,7 +35,7 @@ use zenoh::{ }, query::{ConsolidationMode, QueryTarget}, sample::{Sample, SampleBuilder, SampleKind}, - session::{Session, SessionDeclarations}, + session::Session, time::{Timestamp, NTP64}, }; use zenoh_backend_traits::{ diff --git a/plugins/zenoh-plugin-storage-manager/tests/operations.rs b/plugins/zenoh-plugin-storage-manager/tests/operations.rs index 483b87e223..c3ddf67d2e 100644 --- a/plugins/zenoh-plugin-storage-manager/tests/operations.rs +++ b/plugins/zenoh-plugin-storage-manager/tests/operations.rs @@ -20,8 +20,7 @@ use std::{borrow::Cow, str::FromStr, thread::sleep}; use tokio::runtime::Runtime; use zenoh::{ - internal::zasync_executor_init, prelude::*, query::Reply, sample::Sample, time::Timestamp, - Config, Session, + internal::zasync_executor_init, query::Reply, sample::Sample, time::Timestamp, Config, Session, }; use zenoh_plugin_trait::Plugin; diff --git a/plugins/zenoh-plugin-storage-manager/tests/wildcard.rs b/plugins/zenoh-plugin-storage-manager/tests/wildcard.rs index 6a6e36b2fd..b4c7ddd8f2 100644 --- a/plugins/zenoh-plugin-storage-manager/tests/wildcard.rs +++ b/plugins/zenoh-plugin-storage-manager/tests/wildcard.rs @@ -21,8 +21,7 @@ use std::{borrow::Cow, str::FromStr, thread::sleep}; // use std::collections::HashMap; use tokio::runtime::Runtime; use zenoh::{ - internal::zasync_executor_init, prelude::*, query::Reply, sample::Sample, time::Timestamp, - Config, Session, + internal::zasync_executor_init, query::Reply, sample::Sample, time::Timestamp, Config, Session, }; use zenoh_plugin_trait::Plugin; diff --git a/zenoh-ext/examples/examples/z_query_sub.rs b/zenoh-ext/examples/examples/z_query_sub.rs index 0931d289fe..0d01cb20c7 100644 --- a/zenoh-ext/examples/examples/z_query_sub.rs +++ b/zenoh-ext/examples/examples/z_query_sub.rs @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // use clap::{arg, Parser}; -use zenoh::{config::Config, prelude::*, query::ReplyKeyExpr}; +use zenoh::{config::Config, query::ReplyKeyExpr}; use zenoh_ext::*; use zenoh_ext_examples::CommonArgs; diff --git a/zenoh-ext/src/group.rs b/zenoh-ext/src/group.rs index f8de27d662..c842c9eed6 100644 --- a/zenoh-ext/src/group.rs +++ b/zenoh-ext/src/group.rs @@ -29,10 +29,9 @@ use zenoh::{ bytes::ZBytesReader, internal::{bail, Condition, TaskController}, key_expr::{keyexpr, KeyExpr, OwnedKeyExpr}, - prelude::*, pubsub::Publisher, qos::Priority, - Session, + Error as ZError, Result as ZResult, Session, }; const GROUP_PREFIX: &str = "zenoh/ext/net/group"; diff --git a/zenoh-ext/src/publication_cache.rs b/zenoh-ext/src/publication_cache.rs index 9c1536c2a1..af548a3b6c 100644 --- a/zenoh-ext/src/publication_cache.rs +++ b/zenoh-ext/src/publication_cache.rs @@ -25,14 +25,13 @@ use zenoh::{ pubsub::FlumeSubscriber, query::{Query, Queryable, ZenohParameters}, sample::{Locality, Sample}, - session::{SessionDeclarations, SessionRef}, - Error, Resolvable, Resolve, Result as ZResult, + Error, Resolvable, Resolve, Result as ZResult, Session, }; /// The builder of PublicationCache, allowing to configure it. #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] pub struct PublicationCacheBuilder<'a, 'b, 'c> { - session: SessionRef<'a>, + session: &'a Session, pub_key_expr: ZResult>, queryable_prefix: Option>>, queryable_origin: Option, @@ -43,7 +42,7 @@ pub struct PublicationCacheBuilder<'a, 'b, 'c> { impl<'a, 'b, 'c> PublicationCacheBuilder<'a, 'b, 'c> { pub(crate) fn new( - session: SessionRef<'a>, + session: &'a Session, pub_key_expr: ZResult>, ) -> PublicationCacheBuilder<'a, 'b, 'c> { PublicationCacheBuilder { @@ -95,8 +94,8 @@ impl<'a, 'b, 'c> PublicationCacheBuilder<'a, 'b, 'c> { } } -impl<'a> Resolvable for PublicationCacheBuilder<'a, '_, '_> { - type To = ZResult>; +impl Resolvable for PublicationCacheBuilder<'_, '_, '_> { + type To = ZResult; } impl Wait for PublicationCacheBuilder<'_, '_, '_> { @@ -105,7 +104,7 @@ impl Wait for PublicationCacheBuilder<'_, '_, '_> { } } -impl<'a> IntoFuture for PublicationCacheBuilder<'a, '_, '_> { +impl IntoFuture for PublicationCacheBuilder<'_, '_, '_> { type Output = ::To; type IntoFuture = Ready<::To>; @@ -114,14 +113,14 @@ impl<'a> IntoFuture for PublicationCacheBuilder<'a, '_, '_> { } } -pub struct PublicationCache<'a> { - local_sub: FlumeSubscriber<'a>, - _queryable: Queryable<'a, flume::Receiver>, +pub struct PublicationCache { + local_sub: FlumeSubscriber, + _queryable: Queryable>, task: TerminatableTask, } -impl<'a> PublicationCache<'a> { - fn new(conf: PublicationCacheBuilder<'a, '_, '_>) -> ZResult> { +impl PublicationCache { + fn new(conf: PublicationCacheBuilder<'_, '_, '_>) -> ZResult { let key_expr = conf.pub_key_expr?; // the queryable_prefix (optional), and the key_expr for PublicationCache's queryable ("[]/") let (queryable_prefix, queryable_key_expr): (Option, KeyExpr) = @@ -258,7 +257,7 @@ impl<'a> PublicationCache<'a> { /// Undeclare this [`PublicationCache`]`. #[inline] - pub fn undeclare(self) -> impl Resolve> + 'a { + pub fn undeclare(self) -> impl Resolve> { ResolveFuture::new(async move { let PublicationCache { _queryable, diff --git a/zenoh-ext/src/querying_subscriber.rs b/zenoh-ext/src/querying_subscriber.rs index 813d2963db..9796109510 100644 --- a/zenoh-ext/src/querying_subscriber.rs +++ b/zenoh-ext/src/querying_subscriber.rs @@ -30,9 +30,8 @@ use zenoh::{ pubsub::Subscriber, query::{QueryConsolidation, QueryTarget, ReplyKeyExpr, Selector}, sample::{Locality, Sample, SampleBuilder}, - session::{SessionDeclarations, SessionRef}, time::Timestamp, - Error, Resolvable, Resolve, Result as ZResult, + Error, Resolvable, Resolve, Result as ZResult, Session, }; use crate::ExtractSample; @@ -40,7 +39,7 @@ use crate::ExtractSample; /// The builder of [`FetchingSubscriber`], allowing to configure it. #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] pub struct QueryingSubscriberBuilder<'a, 'b, KeySpace, Handler> { - pub(crate) session: SessionRef<'a>, + pub(crate) session: &'a Session, pub(crate) key_expr: ZResult>, pub(crate) key_space: KeySpace, pub(crate) origin: Locality, @@ -50,10 +49,17 @@ pub struct QueryingSubscriberBuilder<'a, 'b, KeySpace, Handler> { pub(crate) query_accept_replies: ReplyKeyExpr, pub(crate) query_timeout: Duration, pub(crate) handler: Handler, + pub(crate) undeclare_on_drop: bool, } impl<'a, 'b, KeySpace> QueryingSubscriberBuilder<'a, 'b, KeySpace, DefaultHandler> { /// Add callback to [`FetchingSubscriber`]. + /// + /// Subscriber will not be undeclared when dropped, with the callback running + /// in background until the session is closed. + /// + /// It is in fact just a convenient shortcut for + /// `.with(my_callback).undeclare_on_drop(false)`. #[inline] pub fn callback( self, @@ -62,37 +68,17 @@ impl<'a, 'b, KeySpace> QueryingSubscriberBuilder<'a, 'b, KeySpace, DefaultHandle where Callback: Fn(Sample) + Send + Sync + 'static, { - let QueryingSubscriberBuilder { - session, - key_expr, - key_space, - origin, - query_selector, - query_target, - query_consolidation, - query_accept_replies, - query_timeout, - handler: _, - } = self; - QueryingSubscriberBuilder { - session, - key_expr, - key_space, - origin, - query_selector, - query_target, - query_consolidation, - query_accept_replies, - query_timeout, - handler: callback, - } + self.with(callback).undeclare_on_drop(false) } /// Add callback to [`FetchingSubscriber`]. /// /// Using this guarantees that your callback will never be called concurrently. /// If your callback is also accepted by the [`callback`](QueryingSubscriberBuilder::callback) - /// method, we suggest you use it instead of `callback_mut` + /// method, we suggest you use it instead of `callback_mut`. + /// + /// Subscriber will not be undeclared when dropped, with the callback running + /// in background until the session is closed. #[inline] pub fn callback_mut( self, @@ -124,6 +110,7 @@ impl<'a, 'b, KeySpace> QueryingSubscriberBuilder<'a, 'b, KeySpace, DefaultHandle query_accept_replies, query_timeout, handler: _, + undeclare_on_drop, } = self; QueryingSubscriberBuilder { session, @@ -136,11 +123,12 @@ impl<'a, 'b, KeySpace> QueryingSubscriberBuilder<'a, 'b, KeySpace, DefaultHandle query_accept_replies, query_timeout, handler, + undeclare_on_drop, } } } -impl<'a, 'b, Handler> QueryingSubscriberBuilder<'a, 'b, crate::UserSpace, Handler> { +impl<'b, Handler> QueryingSubscriberBuilder<'_, 'b, crate::UserSpace, Handler> { /// Change the subscription reliability. #[cfg(feature = "unstable")] #[deprecated( @@ -219,21 +207,33 @@ impl<'a, 'b, Handler> QueryingSubscriberBuilder<'a, 'b, crate::UserSpace, Handle } } -impl<'a, 'b, KeySpace, Handler> QueryingSubscriberBuilder<'a, 'b, KeySpace, Handler> { +impl QueryingSubscriberBuilder<'_, '_, KeySpace, Handler> { /// Change the timeout to be used for queries. #[inline] pub fn query_timeout(mut self, query_timeout: Duration) -> Self { self.query_timeout = query_timeout; self } + + /// Set whether the subscriber will be undeclared when dropped. + /// + /// The method is usually used in combination with a callback like in + /// [`callback`](Self::callback) method, or a channel sender. + /// Be careful when using it, as subscribers not undeclared will consume + /// resources until the session is closed. + #[inline] + pub fn undeclare_on_drop(mut self, undeclare_on_drop: bool) -> Self { + self.undeclare_on_drop = undeclare_on_drop; + self + } } -impl<'a, KeySpace, Handler> Resolvable for QueryingSubscriberBuilder<'a, '_, KeySpace, Handler> +impl Resolvable for QueryingSubscriberBuilder<'_, '_, KeySpace, Handler> where Handler: IntoHandler<'static, Sample>, Handler::Handler: Send, { - type To = ZResult>; + type To = ZResult>; } impl Wait for QueryingSubscriberBuilder<'_, '_, KeySpace, Handler> @@ -278,13 +278,14 @@ where .wait(), }, handler: self.handler, + undeclare_on_drop: self.undeclare_on_drop, phantom: std::marker::PhantomData, } .wait() } } -impl<'a, KeySpace, Handler> IntoFuture for QueryingSubscriberBuilder<'a, '_, KeySpace, Handler> +impl IntoFuture for QueryingSubscriberBuilder<'_, '_, KeySpace, Handler> where KeySpace: Into + Clone, Handler: IntoHandler<'static, Sample> + Send, @@ -370,12 +371,13 @@ pub struct FetchingSubscriberBuilder< > where TryIntoSample: ExtractSample, { - pub(crate) session: SessionRef<'a>, + pub(crate) session: &'a Session, pub(crate) key_expr: ZResult>, pub(crate) key_space: KeySpace, pub(crate) origin: Locality, pub(crate) fetch: Fetch, pub(crate) handler: Handler, + pub(crate) undeclare_on_drop: bool, pub(crate) phantom: std::marker::PhantomData, } @@ -400,6 +402,7 @@ where origin: self.origin, fetch: self.fetch, handler: self.handler, + undeclare_on_drop: self.undeclare_on_drop, phantom: std::marker::PhantomData, } } @@ -416,6 +419,12 @@ where TryIntoSample: ExtractSample, { /// Add callback to [`FetchingSubscriber`]. + /// + /// Subscriber will not be undeclared when dropped, with the callback running + /// in background until the session is closed. + /// + /// It is in fact just a convenient shortcut for + /// `.with(my_callback).undeclare_on_drop(false)`. #[inline] pub fn callback( self, @@ -424,31 +433,17 @@ where where Callback: Fn(Sample) + Send + Sync + 'static, { - let FetchingSubscriberBuilder { - session, - key_expr, - key_space, - origin, - fetch, - handler: _, - phantom, - } = self; - FetchingSubscriberBuilder { - session, - key_expr, - key_space, - origin, - fetch, - handler: callback, - phantom, - } + self.with(callback).undeclare_on_drop(false) } /// Add callback to [`FetchingSubscriber`]. /// /// Using this guarantees that your callback will never be called concurrently. /// If your callback is also accepted by the [`callback`](FetchingSubscriberBuilder::callback) - /// method, we suggest you use it instead of `callback_mut` + /// method, we suggest you use it instead of `callback_mut`. + /// + /// Subscriber will not be undeclared when dropped, with the callback running + /// in background until the session is closed. #[inline] pub fn callback_mut( self, @@ -483,6 +478,7 @@ where origin, fetch, handler: _, + undeclare_on_drop, phantom, } = self; FetchingSubscriberBuilder { @@ -492,18 +488,17 @@ where origin, fetch, handler, + undeclare_on_drop, phantom, } } } impl< - 'a, - 'b, Handler, Fetch: FnOnce(Box) -> ZResult<()>, TryIntoSample, - > FetchingSubscriberBuilder<'a, 'b, crate::UserSpace, Handler, Fetch, TryIntoSample> + > FetchingSubscriberBuilder<'_, '_, crate::UserSpace, Handler, Fetch, TryIntoSample> where TryIntoSample: ExtractSample, { @@ -551,18 +546,39 @@ where } impl< - 'a, KeySpace, Handler, Fetch: FnOnce(Box) -> ZResult<()>, TryIntoSample, - > Resolvable for FetchingSubscriberBuilder<'a, '_, KeySpace, Handler, Fetch, TryIntoSample> + > FetchingSubscriberBuilder<'_, '_, KeySpace, Handler, Fetch, TryIntoSample> +where + TryIntoSample: ExtractSample, +{ + /// Set whether the subscriber will be undeclared when dropped. + /// + /// The method is usually used in combination with a callback like in + /// [`callback`](Self::callback) method, or a channel sender. + /// Be careful when using it, as subscribers not undeclared will consume + /// resources until the session is closed. + #[inline] + pub fn undeclare_on_drop(mut self, undeclare_on_drop: bool) -> Self { + self.undeclare_on_drop = undeclare_on_drop; + self + } +} + +impl< + KeySpace, + Handler, + Fetch: FnOnce(Box) -> ZResult<()>, + TryIntoSample, + > Resolvable for FetchingSubscriberBuilder<'_, '_, KeySpace, Handler, Fetch, TryIntoSample> where Handler: IntoHandler<'static, Sample>, Handler::Handler: Send, TryIntoSample: ExtractSample, { - type To = ZResult>; + type To = ZResult>; } impl< @@ -583,12 +599,11 @@ where } impl< - 'a, KeySpace, Handler, Fetch: FnOnce(Box) -> ZResult<()> + Send + Sync, TryIntoSample, - > IntoFuture for FetchingSubscriberBuilder<'a, '_, KeySpace, Handler, Fetch, TryIntoSample> + > IntoFuture for FetchingSubscriberBuilder<'_, '_, KeySpace, Handler, Fetch, TryIntoSample> where KeySpace: Into, Handler: IntoHandler<'static, Sample> + Send, @@ -615,7 +630,7 @@ where /// ```no_run /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; +/// use zenoh::Wait; /// use zenoh_ext::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); @@ -634,28 +649,29 @@ where /// } /// # } /// ``` -pub struct FetchingSubscriber<'a, Handler> { - subscriber: Subscriber<'a, ()>, +pub struct FetchingSubscriber { + subscriber: Subscriber<()>, callback: Arc, state: Arc>, handler: Handler, } -impl std::ops::Deref for FetchingSubscriber<'_, Handler> { +impl std::ops::Deref for FetchingSubscriber { type Target = Handler; fn deref(&self) -> &Self::Target { &self.handler } } -impl std::ops::DerefMut for FetchingSubscriber<'_, Handler> { +impl std::ops::DerefMut for FetchingSubscriber { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.handler } } -impl<'a, Handler> FetchingSubscriber<'a, Handler> { +impl FetchingSubscriber { fn new< + 'a, KeySpace, InputHandler, Fetch: FnOnce(Box) -> ZResult<()> + Send + Sync, @@ -711,14 +727,16 @@ impl<'a, Handler> FetchingSubscriber<'a, Handler> { crate::KeySpace::User => conf .session .declare_subscriber(&key_expr) - .callback(sub_callback) + .with(sub_callback) + .undeclare_on_drop(conf.undeclare_on_drop) .allowed_origin(conf.origin) .wait()?, crate::KeySpace::Liveliness => conf .session .liveliness() .declare_subscriber(&key_expr) - .callback(sub_callback) + .with(sub_callback) + .undeclare_on_drop(conf.undeclare_on_drop) .wait()?, }; @@ -737,7 +755,7 @@ impl<'a, Handler> FetchingSubscriber<'a, Handler> { /// Undeclare this [`FetchingSubscriber`]`. #[inline] - pub fn undeclare(self) -> impl Resolve> + 'a { + pub fn undeclare(self) -> impl Resolve> { self.subscriber.undeclare() } @@ -756,7 +774,7 @@ impl<'a, Handler> FetchingSubscriber<'a, Handler> { /// ```no_run /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; + /// use zenoh::Wait; /// use zenoh_ext::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); @@ -834,7 +852,7 @@ impl Drop for RepliesHandler { /// ```no_run /// # #[tokio::main] /// # async fn main() { -/// # use zenoh::prelude::*; +/// # use zenoh::Wait; /// # use zenoh_ext::*; /// # /// # let session = zenoh::open(zenoh::config::peer()).await.unwrap(); diff --git a/zenoh-ext/src/session_ext.rs b/zenoh-ext/src/session_ext.rs index 606f00743b..7c68f88ddb 100644 --- a/zenoh-ext/src/session_ext.rs +++ b/zenoh-ext/src/session_ext.rs @@ -11,65 +11,23 @@ // Contributors: // ZettaScale Zenoh Team, // -use std::{convert::TryInto, sync::Arc}; -use zenoh::{ - key_expr::KeyExpr, - session::{Session, SessionRef}, - Error, -}; +use zenoh::{key_expr::KeyExpr, session::Session, Error}; use super::PublicationCacheBuilder; /// Some extensions to the [`zenoh::Session`](zenoh::Session) pub trait SessionExt<'s, 'a> { - fn declare_publication_cache<'b, 'c, TryIntoKeyExpr>( - &'s self, - pub_key_expr: TryIntoKeyExpr, - ) -> PublicationCacheBuilder<'a, 'b, 'c> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into; -} - -impl<'s, 'a> SessionExt<'s, 'a> for SessionRef<'a> { - fn declare_publication_cache<'b, 'c, TryIntoKeyExpr>( - &'s self, - pub_key_expr: TryIntoKeyExpr, - ) -> PublicationCacheBuilder<'a, 'b, 'c> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into, - { - PublicationCacheBuilder::new(self.clone(), pub_key_expr.try_into().map_err(Into::into)) - } -} - -impl<'a> SessionExt<'a, 'a> for Session { - fn declare_publication_cache<'b, 'c, TryIntoKeyExpr>( - &'a self, - pub_key_expr: TryIntoKeyExpr, - ) -> PublicationCacheBuilder<'a, 'b, 'c> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into, - { - SessionRef::Borrow(self).declare_publication_cache(pub_key_expr) - } -} - -impl<'s> SessionExt<'s, 'static> for Arc { /// Examples: /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// use zenoh::config::ModeDependentValue::Unique; /// use zenoh_ext::SessionExt; /// /// let mut config = zenoh::config::default(); /// config.timestamping.set_enabled(Some(Unique(true))); - /// let session = zenoh::open(config).await.unwrap().into_arc(); + /// let session = zenoh::open(config).await.unwrap(); /// let publication_cache = session.declare_publication_cache("key/expression").await.unwrap(); /// tokio::task::spawn(async move { /// publication_cache.key_expr(); @@ -79,11 +37,21 @@ impl<'s> SessionExt<'s, 'static> for Arc { fn declare_publication_cache<'b, 'c, TryIntoKeyExpr>( &'s self, pub_key_expr: TryIntoKeyExpr, - ) -> PublicationCacheBuilder<'static, 'b, 'c> + ) -> PublicationCacheBuilder<'a, 'b, 'c> + where + TryIntoKeyExpr: TryInto>, + >>::Error: Into; +} + +impl<'a> SessionExt<'a, 'a> for Session { + fn declare_publication_cache<'b, 'c, TryIntoKeyExpr>( + &'a self, + pub_key_expr: TryIntoKeyExpr, + ) -> PublicationCacheBuilder<'a, 'b, 'c> where TryIntoKeyExpr: TryInto>, >>::Error: Into, { - SessionRef::Shared(self.clone()).declare_publication_cache(pub_key_expr) + PublicationCacheBuilder::new(self, pub_key_expr.try_into().map_err(Into::into)) } } diff --git a/zenoh-ext/src/subscriber_ext.rs b/zenoh-ext/src/subscriber_ext.rs index cfd810185a..a48c4fe500 100644 --- a/zenoh-ext/src/subscriber_ext.rs +++ b/zenoh-ext/src/subscriber_ext.rs @@ -32,7 +32,7 @@ pub trait SubscriberForward<'a, S> { type Output; fn forward(&'a mut self, sink: S) -> Self::Output; } -impl<'a, S> SubscriberForward<'a, S> for Subscriber<'_, flume::Receiver> +impl<'a, S> SubscriberForward<'a, S> for Subscriber> where S: futures::sink::Sink, { @@ -60,7 +60,7 @@ pub trait SubscriberBuilderExt<'a, 'b, Handler> { /// ```no_run /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; + /// use zenoh::Wait; /// use zenoh_ext::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); @@ -104,7 +104,6 @@ pub trait SubscriberBuilderExt<'a, 'b, Handler> { /// ```no_run /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// use zenoh_ext::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); @@ -138,7 +137,7 @@ impl<'a, 'b, Handler> SubscriberBuilderExt<'a, 'b, Handler> for SubscriberBuilde /// ```no_run /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; + /// use zenoh::Wait; /// use zenoh_ext::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); @@ -174,6 +173,7 @@ impl<'a, 'b, Handler> SubscriberBuilderExt<'a, 'b, Handler> for SubscriberBuilde origin: self.origin, fetch, handler: self.handler, + undeclare_on_drop: true, phantom: std::marker::PhantomData, } } @@ -193,7 +193,6 @@ impl<'a, 'b, Handler> SubscriberBuilderExt<'a, 'b, Handler> for SubscriberBuilde /// ```no_run /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// use zenoh_ext::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); @@ -221,6 +220,7 @@ impl<'a, 'b, Handler> SubscriberBuilderExt<'a, 'b, Handler> for SubscriberBuilde query_consolidation: QueryConsolidation::from(zenoh::query::ConsolidationMode::None), query_accept_replies: ReplyKeyExpr::default(), query_timeout: Duration::from_secs(10), + undeclare_on_drop: true, handler: self.handler, } } @@ -246,7 +246,7 @@ impl<'a, 'b, Handler> SubscriberBuilderExt<'a, 'b, Handler> /// ```no_run /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; + /// use zenoh::Wait; /// use zenoh_ext::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); @@ -284,6 +284,7 @@ impl<'a, 'b, Handler> SubscriberBuilderExt<'a, 'b, Handler> origin: Locality::default(), fetch, handler: self.handler, + undeclare_on_drop: true, phantom: std::marker::PhantomData, } } @@ -304,7 +305,6 @@ impl<'a, 'b, Handler> SubscriberBuilderExt<'a, 'b, Handler> /// ```no_run /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// use zenoh_ext::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); @@ -330,6 +330,7 @@ impl<'a, 'b, Handler> SubscriberBuilderExt<'a, 'b, Handler> query_consolidation: QueryConsolidation::DEFAULT, query_accept_replies: ReplyKeyExpr::MatchingQuery, query_timeout: Duration::from_secs(10), + undeclare_on_drop: true, handler: self.handler, } } diff --git a/zenoh-ext/tests/liveliness.rs b/zenoh-ext/tests/liveliness.rs index b1c231006d..d211505c4c 100644 --- a/zenoh-ext/tests/liveliness.rs +++ b/zenoh-ext/tests/liveliness.rs @@ -15,13 +15,14 @@ use zenoh::{ config::{self, EndPoint, WhatAmI}, sample::SampleKind, + Wait, }; #[tokio::test(flavor = "multi_thread", worker_threads = 4)] async fn test_liveliness_querying_subscriber_clique() { use std::time::Duration; - use zenoh::{internal::ztimeout, prelude::*}; + use zenoh::internal::ztimeout; use zenoh_ext::SubscriberBuilderExt; const TIMEOUT: Duration = Duration::from_secs(60); @@ -99,7 +100,7 @@ async fn test_liveliness_querying_subscriber_clique() { async fn test_liveliness_querying_subscriber_brokered() { use std::time::Duration; - use zenoh::{internal::ztimeout, prelude::*}; + use zenoh::internal::ztimeout; use zenoh_ext::SubscriberBuilderExt; const TIMEOUT: Duration = Duration::from_secs(60); @@ -205,7 +206,7 @@ async fn test_liveliness_querying_subscriber_brokered() { async fn test_liveliness_fetching_subscriber_clique() { use std::time::Duration; - use zenoh::{internal::ztimeout, prelude::*}; + use zenoh::internal::ztimeout; use zenoh_ext::SubscriberBuilderExt; const TIMEOUT: Duration = Duration::from_secs(60); @@ -287,7 +288,7 @@ async fn test_liveliness_fetching_subscriber_clique() { async fn test_liveliness_fetching_subscriber_brokered() { use std::time::Duration; - use zenoh::{internal::ztimeout, prelude::*}; + use zenoh::internal::ztimeout; use zenoh_ext::SubscriberBuilderExt; const TIMEOUT: Duration = Duration::from_secs(60); diff --git a/zenoh/src/api/admin.rs b/zenoh/src/api/admin.rs index 8c20a275c1..060bb78c43 100644 --- a/zenoh/src/api/admin.rs +++ b/zenoh/src/api/admin.rs @@ -32,9 +32,9 @@ use super::{ key_expr::KeyExpr, queryable::Query, sample::{DataInfo, Locality, SampleKind}, - session::Session, subscriber::SubscriberKind, }; +use crate::api::session::WeakSession; lazy_static::lazy_static!( static ref KE_STARSTAR: &'static keyexpr = unsafe { keyexpr::from_str_unchecked("**") }; @@ -44,10 +44,10 @@ lazy_static::lazy_static!( static ref KE_LINK: &'static keyexpr = unsafe { keyexpr::from_str_unchecked("link") }; ); -pub(crate) fn init(session: &Session) { - if let Ok(own_zid) = keyexpr::new(&session.zid().to_string()) { +pub(crate) fn init(session: WeakSession) { + if let Ok(own_zid) = keyexpr::new(&session.runtime.zid().to_string()) { let admin_key = KeyExpr::from(*KE_PREFIX / own_zid / *KE_SESSION / *KE_STARSTAR) - .to_wire(session) + .to_wire(&session) .to_owned(); let _admin_qabl = session.declare_queryable_inner( @@ -56,13 +56,13 @@ pub(crate) fn init(session: &Session) { Locality::SessionLocal, Arc::new({ let session = session.clone(); - move |q| super::admin::on_admin_query(&session, q) + move |q| on_admin_query(&session, q) }), ); } } -pub(crate) fn on_admin_query(session: &Session, query: Query) { +pub(crate) fn on_admin_query(session: &WeakSession, query: Query) { fn reply_peer(own_zid: &keyexpr, query: &Query, peer: TransportPeer) { let zid = peer.zid.to_string(); if let Ok(zid) = keyexpr::new(&zid) { @@ -104,7 +104,7 @@ pub(crate) fn on_admin_query(session: &Session, query: Query) { } } - if let Ok(own_zid) = keyexpr::new(&session.zid().to_string()) { + if let Ok(own_zid) = keyexpr::new(&session.runtime.zid().to_string()) { for transport in zenoh_runtime::ZRuntime::Net .block_in_place(session.runtime.manager().get_transports_unicast()) { @@ -124,14 +124,12 @@ pub(crate) fn on_admin_query(session: &Session, query: Query) { #[derive(Clone)] pub(crate) struct Handler { - pub(crate) session: Arc, + pub(crate) session: WeakSession, } impl Handler { - pub(crate) fn new(session: Session) -> Self { - Self { - session: Arc::new(session), - } + pub(crate) fn new(session: WeakSession) -> Self { + Self { session } } } @@ -157,7 +155,7 @@ impl TransportMulticastEventHandler for Handler { &self, peer: zenoh_transport::TransportPeer, ) -> ZResult> { - if let Ok(own_zid) = keyexpr::new(&self.session.zid().to_string()) { + if let Ok(own_zid) = keyexpr::new(&self.session.runtime.zid().to_string()) { if let Ok(zid) = keyexpr::new(&peer.zid.to_string()) { let expr = WireExpr::from( &(*KE_PREFIX / own_zid / *KE_SESSION / *KE_TRANSPORT_UNICAST / zid), @@ -200,7 +198,7 @@ impl TransportMulticastEventHandler for Handler { pub(crate) struct PeerHandler { pub(crate) expr: WireExpr<'static>, - pub(crate) session: Arc, + pub(crate) session: WeakSession, } impl TransportPeerEventHandler for PeerHandler { diff --git a/zenoh/src/api/builders/publisher.rs b/zenoh/src/api/builders/publisher.rs index d361272f66..ba8ac98947 100644 --- a/zenoh/src/api/builders/publisher.rs +++ b/zenoh/src/api/builders/publisher.rs @@ -21,14 +21,16 @@ use zenoh_protocol::{core::CongestionControl, network::Mapping}; use super::sample::TimestampBuilderTrait; #[cfg(feature = "unstable")] use crate::api::sample::SourceInfo; -use crate::api::{ - builders::sample::{EncodingBuilderTrait, QoSBuilderTrait, SampleBuilderTrait}, - bytes::{OptionZBytes, ZBytes}, - encoding::Encoding, - key_expr::KeyExpr, - publisher::{Priority, Publisher}, - sample::{Locality, SampleKind}, - session::SessionRef, +use crate::{ + api::{ + builders::sample::{EncodingBuilderTrait, QoSBuilderTrait, SampleBuilderTrait}, + bytes::{OptionZBytes, ZBytes}, + encoding::Encoding, + key_expr::KeyExpr, + publisher::{Priority, Publisher}, + sample::{Locality, SampleKind}, + }, + Session, }; pub type SessionPutBuilder<'a, 'b> = @@ -57,7 +59,7 @@ pub struct PublicationBuilderDelete; /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::{bytes::Encoding, prelude::*, qos::CongestionControl}; +/// use zenoh::{bytes::Encoding, qos::CongestionControl}; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// session @@ -237,7 +239,7 @@ impl IntoFuture for PublicationBuilder, PublicationBuil /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::{prelude::*, qos::CongestionControl}; +/// use zenoh::qos::CongestionControl; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session @@ -249,8 +251,8 @@ impl IntoFuture for PublicationBuilder, PublicationBuil /// ``` #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] #[derive(Debug)] -pub struct PublisherBuilder<'a, 'b: 'a> { - pub(crate) session: SessionRef<'a>, +pub struct PublisherBuilder<'a, 'b> { + pub(crate) session: &'a Session, pub(crate) key_expr: ZResult>, pub(crate) encoding: Encoding, pub(crate) congestion_control: CongestionControl, @@ -264,7 +266,7 @@ pub struct PublisherBuilder<'a, 'b: 'a> { impl<'a, 'b> Clone for PublisherBuilder<'a, 'b> { fn clone(&self) -> Self { Self { - session: self.session.clone(), + session: self.session, key_expr: match &self.key_expr { Ok(k) => Ok(k.clone()), Err(e) => Err(zerror!("Cloned KE Error: {}", e).into()), @@ -329,9 +331,11 @@ impl<'a, 'b> PublisherBuilder<'a, 'b> { } // internal function for performing the publication - fn create_one_shot_publisher(self) -> ZResult> { + fn create_one_shot_publisher(self) -> ZResult> { Ok(Publisher { - session: self.session, + #[cfg(feature = "unstable")] + session_id: self.session.0.runtime.zid(), + session: self.session.downgrade(), id: 0, // This is a one shot Publisher key_expr: self.key_expr?, encoding: self.encoding, @@ -349,15 +353,15 @@ impl<'a, 'b> PublisherBuilder<'a, 'b> { } impl<'a, 'b> Resolvable for PublisherBuilder<'a, 'b> { - type To = ZResult>; + type To = ZResult>; } impl<'a, 'b> Wait for PublisherBuilder<'a, 'b> { fn wait(self) -> ::To { let mut key_expr = self.key_expr?; - if !key_expr.is_fully_optimized(&self.session) { - let session_id = self.session.id; - let expr_id = self.session.declare_prefix(key_expr.as_str()).wait(); + if !key_expr.is_fully_optimized(&self.session.0) { + let session_id = self.session.0.id; + let expr_id = self.session.0.declare_prefix(key_expr.as_str()).wait()?; let prefix_len = key_expr .len() .try_into() @@ -385,23 +389,27 @@ impl<'a, 'b> Wait for PublisherBuilder<'a, 'b> { } } } - self.session - .declare_publisher_inner(key_expr.clone(), self.destination) - .map(|id| Publisher { - session: self.session, - id, - key_expr, - encoding: self.encoding, - congestion_control: self.congestion_control, - priority: self.priority, - is_express: self.is_express, - destination: self.destination, - #[cfg(feature = "unstable")] - reliability: self.reliability, - #[cfg(feature = "unstable")] - matching_listeners: Default::default(), - undeclare_on_drop: true, - }) + let id = self + .session + .0 + .declare_publisher_inner(key_expr.clone(), self.destination)?; + Ok(Publisher { + #[cfg(feature = "unstable")] + session_id: self.session.0.runtime.zid(), + session: self.session.downgrade(), + id, + key_expr, + encoding: self.encoding, + congestion_control: self.congestion_control, + priority: self.priority, + is_express: self.is_express, + destination: self.destination, + #[cfg(feature = "unstable")] + reliability: self.reliability, + #[cfg(feature = "unstable")] + matching_listeners: Default::default(), + undeclare_on_drop: true, + }) } } diff --git a/zenoh/src/api/handlers/callback.rs b/zenoh/src/api/handlers/callback.rs index 4f49e7c41f..7e609949ef 100644 --- a/zenoh/src/api/handlers/callback.rs +++ b/zenoh/src/api/handlers/callback.rs @@ -30,11 +30,31 @@ where F: Fn(T) + Send + Sync + 'a, { type Handler = (); + fn into_handler(self) -> (Callback<'a, T>, Self::Handler) { (Dyn::from(self), ()) } } +impl<'a, T, F, H> IntoHandler<'a, T> for (F, H) +where + F: Fn(T) + Send + Sync + 'a, +{ + type Handler = H; + + fn into_handler(self) -> (Callback<'a, T>, Self::Handler) { + (Dyn::from(self.0), self.1) + } +} + +impl<'a, T, H> IntoHandler<'a, T> for (Callback<'static, T>, H) { + type Handler = H; + + fn into_handler(self) -> (Callback<'a, T>, Self::Handler) { + self + } +} + impl IntoHandler<'static, T> for (flume::Sender, flume::Receiver) { type Handler = flume::Receiver; diff --git a/zenoh/src/api/info.rs b/zenoh/src/api/info.rs index 32bed0eb53..a63797c86c 100644 --- a/zenoh/src/api/info.rs +++ b/zenoh/src/api/info.rs @@ -19,7 +19,7 @@ use zenoh_config::wrappers::ZenohId; use zenoh_core::{Resolvable, Wait}; use zenoh_protocol::core::WhatAmI; -use super::session::SessionRef; +use crate::net::runtime::Runtime; /// A builder retuned by [`SessionInfo::zid()`](SessionInfo::zid) that allows /// to access the [`ZenohId`] of the current zenoh [`Session`](crate::Session). @@ -28,16 +28,14 @@ use super::session::SessionRef; /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let zid = session.info().zid().await; /// # } /// ``` #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] -#[derive(Debug)] pub struct ZenohIdBuilder<'a> { - pub(crate) session: SessionRef<'a>, + runtime: &'a Runtime, } impl<'a> Resolvable for ZenohIdBuilder<'a> { @@ -46,7 +44,7 @@ impl<'a> Resolvable for ZenohIdBuilder<'a> { impl<'a> Wait for ZenohIdBuilder<'a> { fn wait(self) -> Self::To { - self.session.runtime.zid() + self.runtime.zid() } } @@ -67,7 +65,6 @@ impl<'a> IntoFuture for ZenohIdBuilder<'a> { /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let mut routers_zid = session.info().routers_zid().await; @@ -75,9 +72,8 @@ impl<'a> IntoFuture for ZenohIdBuilder<'a> { /// # } /// ``` #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] -#[derive(Debug)] pub struct RoutersZenohIdBuilder<'a> { - pub(crate) session: SessionRef<'a>, + runtime: &'a Runtime, } impl<'a> Resolvable for RoutersZenohIdBuilder<'a> { @@ -88,7 +84,7 @@ impl<'a> Wait for RoutersZenohIdBuilder<'a> { fn wait(self) -> Self::To { Box::new( zenoh_runtime::ZRuntime::Application - .block_in_place(self.session.runtime.manager().get_transports_unicast()) + .block_in_place(self.runtime.manager().get_transports_unicast()) .into_iter() .filter_map(|s| { s.get_whatami() @@ -116,7 +112,6 @@ impl<'a> IntoFuture for RoutersZenohIdBuilder<'a> { /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let zid = session.info().zid().await; @@ -125,9 +120,8 @@ impl<'a> IntoFuture for RoutersZenohIdBuilder<'a> { /// # } /// ``` #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] -#[derive(Debug)] pub struct PeersZenohIdBuilder<'a> { - pub(crate) session: SessionRef<'a>, + runtime: &'a Runtime, } impl<'a> Resolvable for PeersZenohIdBuilder<'a> { @@ -138,7 +132,7 @@ impl<'a> Wait for PeersZenohIdBuilder<'a> { fn wait(self) -> ::To { Box::new( zenoh_runtime::ZRuntime::Application - .block_in_place(self.session.runtime.manager().get_transports_unicast()) + .block_in_place(self.runtime.manager().get_transports_unicast()) .into_iter() .filter_map(|s| { s.get_whatami() @@ -159,32 +153,30 @@ impl<'a> IntoFuture for PeersZenohIdBuilder<'a> { } } -/// Struct returned by [`Session::info()`](crate::session::SessionDeclarations::info) which allows +/// Struct returned by [`Session::info()`](crate::Session::info) which allows /// to access information about the current zenoh [`Session`](crate::Session). /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let info = session.info(); /// let zid = info.zid().await; /// # } /// ``` -pub struct SessionInfo<'a> { - pub(crate) session: SessionRef<'a>, +pub struct SessionInfo { + pub(crate) runtime: Runtime, } -impl SessionInfo<'_> { +impl SessionInfo { /// Return the [`ZenohId`] of the current zenoh [`Session`](crate::Session). /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let zid = session.info().zid().await; @@ -192,7 +184,7 @@ impl SessionInfo<'_> { /// ``` pub fn zid(&self) -> ZenohIdBuilder<'_> { ZenohIdBuilder { - session: self.session.clone(), + runtime: &self.runtime, } } @@ -203,7 +195,6 @@ impl SessionInfo<'_> { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let mut routers_zid = session.info().routers_zid().await; @@ -212,7 +203,7 @@ impl SessionInfo<'_> { /// ``` pub fn routers_zid(&self) -> RoutersZenohIdBuilder<'_> { RoutersZenohIdBuilder { - session: self.session.clone(), + runtime: &self.runtime, } } @@ -222,7 +213,6 @@ impl SessionInfo<'_> { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let mut peers_zid = session.info().peers_zid().await; @@ -231,7 +221,7 @@ impl SessionInfo<'_> { /// ``` pub fn peers_zid(&self) -> PeersZenohIdBuilder<'_> { PeersZenohIdBuilder { - session: self.session.clone(), + runtime: &self.runtime, } } } diff --git a/zenoh/src/api/key_expr.rs b/zenoh/src/api/key_expr.rs index fc472e0db3..fff40a5286 100644 --- a/zenoh/src/api/key_expr.rs +++ b/zenoh/src/api/key_expr.rs @@ -25,7 +25,7 @@ use zenoh_protocol::{ }; use zenoh_result::ZResult; -use super::session::{Session, UndeclarableSealed}; +use super::session::{Session, SessionInner, UndeclarableSealed}; use crate::net::primitives::Primitives; #[derive(Clone, Debug)] @@ -492,7 +492,7 @@ impl<'a> KeyExpr<'a> { //pub(crate) fn is_optimized(&self, session: &Session) -> bool { // matches!(&self.0, KeyExprInner::Wire { expr_id, session_id, .. } | KeyExprInner::BorrowedWire { expr_id, session_id, .. } if *expr_id != 0 && session.id == *session_id) //} - pub(crate) fn is_fully_optimized(&self, session: &Session) -> bool { + pub(crate) fn is_fully_optimized(&self, session: &SessionInner) -> bool { match &self.0 { KeyExprInner::Wire { key_expr, @@ -509,7 +509,7 @@ impl<'a> KeyExpr<'a> { _ => false, } } - pub(crate) fn to_wire(&'a self, session: &Session) -> WireExpr<'a> { + pub(crate) fn to_wire(&'a self, session: &SessionInner) -> WireExpr<'a> { match &self.0 { KeyExprInner::Wire { key_expr, @@ -549,8 +549,10 @@ impl<'a> KeyExpr<'a> { } } -impl<'a> UndeclarableSealed<&'a Session, KeyExprUndeclaration<'a>> for KeyExpr<'a> { - fn undeclare_inner(self, session: &'a Session) -> KeyExprUndeclaration<'a> { +impl<'a> UndeclarableSealed<&'a Session> for KeyExpr<'a> { + type Undeclaration = KeyExprUndeclaration<'a>; + + fn undeclare_inner(self, session: &'a Session) -> Self::Undeclaration { KeyExprUndeclaration { session, expr: self, @@ -564,7 +566,6 @@ impl<'a> UndeclarableSealed<&'a Session, KeyExprUndeclaration<'a>> for KeyExpr<' /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let key_expr = session.declare_keyexpr("key/expression").await.unwrap(); @@ -592,7 +593,7 @@ impl Wait for KeyExprUndeclaration<'_> { session_id, .. } if *prefix_len as usize == key_expr.len() => { - if *session_id == session.id { + if *session_id == session.0.id { *expr_id } else { return Err(zerror!("Failed to undeclare {}, as it was declared by an other Session", expr).into()) @@ -605,7 +606,7 @@ impl Wait for KeyExprUndeclaration<'_> { session_id, .. } if *prefix_len as usize == key_expr.len() => { - if *session_id == session.id { + if *session_id == session.0.id { *expr_id } else { return Err(zerror!("Failed to undeclare {}, as it was declared by an other Session", expr).into()) @@ -614,10 +615,10 @@ impl Wait for KeyExprUndeclaration<'_> { _ => return Err(zerror!("Failed to undeclare {}, make sure you use the result of `Session::declare_keyexpr` to call `Session::undeclare`", expr).into()), }; tracing::trace!("undeclare_keyexpr({:?})", expr_id); - let mut state = zwrite!(session.state); + let mut state = zwrite!(session.0.state); state.local_resources.remove(&expr_id); - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); primitives.send_declare(zenoh_protocol::network::Declare { interest_id: None, diff --git a/zenoh/src/api/liveliness.rs b/zenoh/src/api/liveliness.rs index e9a12400fd..58d6ea7a71 100644 --- a/zenoh/src/api/liveliness.rs +++ b/zenoh/src/api/liveliness.rs @@ -19,6 +19,7 @@ use std::{ time::Duration, }; +use tracing::error; use zenoh_config::unwrap_or_default; use zenoh_core::{Resolvable, Resolve, Result as ZResult, Wait}; @@ -27,10 +28,11 @@ use super::{ key_expr::KeyExpr, query::Reply, sample::{Locality, Sample}, - session::{Session, SessionRef, UndeclarableSealed}, + session::{Session, UndeclarableSealed}, subscriber::{Subscriber, SubscriberInner}, Id, }; +use crate::api::session::WeakSession; /// A structure with functions to declare a /// [`LivelinessToken`](LivelinessToken), query @@ -49,7 +51,6 @@ use super::{ /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let liveliness = session @@ -64,7 +65,6 @@ use super::{ /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let replies = session.liveliness().get("key/**").await.unwrap(); @@ -80,7 +80,7 @@ use super::{ /// ```no_run /// # #[tokio::main] /// # async fn main() { -/// use zenoh::{prelude::*, sample::SampleKind}; +/// use zenoh::sample::SampleKind; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let subscriber = session.liveliness().declare_subscriber("key/**").await.unwrap(); @@ -94,7 +94,7 @@ use super::{ /// ``` #[zenoh_macros::unstable] pub struct Liveliness<'a> { - pub(crate) session: SessionRef<'a>, + pub(crate) session: &'a Session, } #[zenoh_macros::unstable] @@ -109,7 +109,6 @@ impl<'a> Liveliness<'a> { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let liveliness = session @@ -129,7 +128,7 @@ impl<'a> Liveliness<'a> { >>::Error: Into, { LivelinessTokenBuilder { - session: self.session.clone(), + session: self.session, key_expr: TryIntoKeyExpr::try_into(key_expr).map_err(Into::into), } } @@ -144,7 +143,7 @@ impl<'a> Liveliness<'a> { /// ```no_run /// # #[tokio::main] /// # async fn main() { - /// use zenoh::{prelude::*, sample::SampleKind}; + /// use zenoh::sample::SampleKind; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let subscriber = session.liveliness().declare_subscriber("key/expression").await.unwrap(); @@ -166,10 +165,11 @@ impl<'a> Liveliness<'a> { >>::Error: Into, { LivelinessSubscriberBuilder { - session: self.session.clone(), + session: self.session, key_expr: TryIntoKeyExpr::try_into(key_expr).map_err(Into::into), handler: DefaultHandler::default(), history: false, + undeclare_on_drop: true, } } @@ -183,7 +183,6 @@ impl<'a> Liveliness<'a> { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let replies = session.liveliness().get("key/expression").await.unwrap(); @@ -205,11 +204,11 @@ impl<'a> Liveliness<'a> { { let key_expr = key_expr.try_into().map_err(Into::into); let timeout = { - let conf = self.session.runtime.config().lock(); + let conf = self.session.0.runtime.config().lock(); Duration::from_millis(unwrap_or_default!(conf.queries_default_timeout())) }; LivelinessGetBuilder { - session: &self.session, + session: self.session, key_expr, timeout, handler: DefaultHandler::default(), @@ -223,7 +222,6 @@ impl<'a> Liveliness<'a> { /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let liveliness = session @@ -237,13 +235,13 @@ impl<'a> Liveliness<'a> { #[zenoh_macros::unstable] #[derive(Debug)] pub struct LivelinessTokenBuilder<'a, 'b> { - pub(crate) session: SessionRef<'a>, + pub(crate) session: &'a Session, pub(crate) key_expr: ZResult>, } #[zenoh_macros::unstable] -impl<'a> Resolvable for LivelinessTokenBuilder<'a, '_> { - type To = ZResult>; +impl Resolvable for LivelinessTokenBuilder<'_, '_> { + type To = ZResult; } #[zenoh_macros::unstable] @@ -253,9 +251,10 @@ impl Wait for LivelinessTokenBuilder<'_, '_> { let session = self.session; let key_expr = self.key_expr?.into_owned(); session + .0 .declare_liveliness_inner(&key_expr) .map(|tok_state| LivelinessToken { - session, + session: self.session.downgrade(), state: tok_state, undeclare_on_drop: true, }) @@ -289,13 +288,12 @@ pub(crate) struct LivelinessTokenState { /// that declared the token has Zenoh connectivity with the Zenoh application /// that monitors it. /// -/// `LivelinessTokens` are automatically undeclared when dropped. +/// Liveliness tokens are automatically undeclared when dropped. /// /// # Examples /// ```no_run /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let liveliness = session @@ -307,19 +305,18 @@ pub(crate) struct LivelinessTokenState { /// ``` #[zenoh_macros::unstable] #[derive(Debug)] -pub struct LivelinessToken<'a> { - pub(crate) session: SessionRef<'a>, - pub(crate) state: Arc, +pub struct LivelinessToken { + session: WeakSession, + state: Arc, undeclare_on_drop: bool, } -/// A [`Resolvable`] returned when undeclaring a [`LivelinessToken`](LivelinessToken). +/// A [`Resolvable`] returned when undeclaring a [`LivelinessToken`]. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let liveliness = session @@ -333,26 +330,22 @@ pub struct LivelinessToken<'a> { /// ``` #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] #[zenoh_macros::unstable] -pub struct LivelinessTokenUndeclaration<'a> { - token: LivelinessToken<'a>, -} +pub struct LivelinessTokenUndeclaration(LivelinessToken); #[zenoh_macros::unstable] -impl Resolvable for LivelinessTokenUndeclaration<'_> { +impl Resolvable for LivelinessTokenUndeclaration { type To = ZResult<()>; } #[zenoh_macros::unstable] -impl Wait for LivelinessTokenUndeclaration<'_> { +impl Wait for LivelinessTokenUndeclaration { fn wait(mut self) -> ::To { - // set the flag first to avoid double panic if this function panic - self.token.undeclare_on_drop = false; - self.token.session.undeclare_liveliness(self.token.state.id) + self.0.undeclare_impl() } } #[zenoh_macros::unstable] -impl<'a> IntoFuture for LivelinessTokenUndeclaration<'a> { +impl IntoFuture for LivelinessTokenUndeclaration { type Output = ::To; type IntoFuture = Ready<::To>; @@ -362,18 +355,13 @@ impl<'a> IntoFuture for LivelinessTokenUndeclaration<'a> { } #[zenoh_macros::unstable] -impl<'a> LivelinessToken<'a> { - /// Undeclare a [`LivelinessToken`]. - /// - /// LivelinessTokens are automatically closed when dropped, - /// but you may want to use this function to handle errors or - /// undeclare the LivelinessToken asynchronously. +impl LivelinessToken { + /// Undeclare the [`LivelinessToken`]. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let liveliness = session @@ -386,33 +374,33 @@ impl<'a> LivelinessToken<'a> { /// # } /// ``` #[inline] - pub fn undeclare(self) -> impl Resolve> + 'a { + pub fn undeclare(self) -> impl Resolve> { UndeclarableSealed::undeclare_inner(self, ()) } - /// Keep this liveliness token in background, until the session is closed. - #[inline] - #[zenoh_macros::unstable] - pub fn background(mut self) { - // It's not necessary to undeclare this resource when session close, as other sessions - // will clean all resources related to the closed one. - // So we can just never undeclare it. + fn undeclare_impl(&mut self) -> ZResult<()> { + // set the flag first to avoid double panic if this function panic self.undeclare_on_drop = false; + self.session.undeclare_liveliness(self.state.id) } } #[zenoh_macros::unstable] -impl<'a> UndeclarableSealed<(), LivelinessTokenUndeclaration<'a>> for LivelinessToken<'a> { - fn undeclare_inner(self, _: ()) -> LivelinessTokenUndeclaration<'a> { - LivelinessTokenUndeclaration { token: self } +impl UndeclarableSealed<()> for LivelinessToken { + type Undeclaration = LivelinessTokenUndeclaration; + + fn undeclare_inner(self, _: ()) -> Self::Undeclaration { + LivelinessTokenUndeclaration(self) } } #[zenoh_macros::unstable] -impl Drop for LivelinessToken<'_> { +impl Drop for LivelinessToken { fn drop(&mut self) { if self.undeclare_on_drop { - let _ = self.session.undeclare_liveliness(self.state.id); + if let Err(error) = self.undeclare_impl() { + error!(error); + } } } } @@ -423,7 +411,6 @@ impl Drop for LivelinessToken<'_> { /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let subscriber = session @@ -437,21 +424,27 @@ impl Drop for LivelinessToken<'_> { #[zenoh_macros::unstable] #[derive(Debug)] pub struct LivelinessSubscriberBuilder<'a, 'b, Handler> { - pub session: SessionRef<'a>, + pub session: &'a Session, pub key_expr: ZResult>, pub handler: Handler, pub history: bool, + pub undeclare_on_drop: bool, } #[zenoh_macros::unstable] impl<'a, 'b> LivelinessSubscriberBuilder<'a, 'b, DefaultHandler> { /// Receive the samples for this liveliness subscription with a callback. /// + /// Liveliness subscriber will not be undeclared when dropped, + /// with the callback running in background until the session is closed. + /// + /// It is in fact just a convenient shortcut for + /// `.with(my_callback).undeclare_on_drop(false)`. + /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let subscriber = session @@ -471,30 +464,21 @@ impl<'a, 'b> LivelinessSubscriberBuilder<'a, 'b, DefaultHandler> { where Callback: Fn(Sample) + Send + Sync + 'static, { - let LivelinessSubscriberBuilder { - session, - key_expr, - handler: _, - history, - } = self; - LivelinessSubscriberBuilder { - session, - key_expr, - handler: callback, - history, - } + self.with(callback).undeclare_on_drop(false) } /// Receive the samples for this liveliness subscription with a mutable callback. /// /// Using this guarantees that your callback will never be called concurrently. - /// If your callback is also accepted by the [`callback`](LivelinessSubscriberBuilder::callback) method, we suggest you use it instead of `callback_mut` + /// If your callback is also accepted by the [`callback`](LivelinessSubscriberBuilder::callback) method, we suggest you use it instead of `callback_mut`. + /// + /// Liveliness subscriber will not be undeclared when dropped, + /// with the callback running in background until the session is closed. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let mut n = 0; @@ -524,7 +508,6 @@ impl<'a, 'b> LivelinessSubscriberBuilder<'a, 'b, DefaultHandler> { /// ```no_run /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let subscriber = session @@ -549,33 +532,36 @@ impl<'a, 'b> LivelinessSubscriberBuilder<'a, 'b, DefaultHandler> { key_expr, handler: _, history, + undeclare_on_drop, } = self; LivelinessSubscriberBuilder { session, key_expr, handler, history, + undeclare_on_drop, } } } -#[zenoh_macros::unstable] impl LivelinessSubscriberBuilder<'_, '_, Handler> { + /// Set whether the liveliness subscriber will be undeclared when dropped. + /// + /// The method is usually used in combination with a callback like in + /// [`callback`](Self::callback) method, or a channel sender. + /// Be careful when using it, as liveliness subscribers not undeclared will consume + /// resources until the session is closed. + #[inline] + pub fn undeclare_on_drop(mut self, undeclare_on_drop: bool) -> Self { + self.undeclare_on_drop = undeclare_on_drop; + self + } + #[inline] #[zenoh_macros::unstable] - pub fn history(self, history: bool) -> Self { - let LivelinessSubscriberBuilder { - session, - key_expr, - handler, - history: _, - } = self; - LivelinessSubscriberBuilder { - session, - key_expr, - handler, - history, - } + pub fn history(mut self, history: bool) -> Self { + self.history = history; + self } } @@ -585,11 +571,11 @@ where Handler: IntoHandler<'static, Sample> + Send, Handler::Handler: Send, { - type To = ZResult>; + type To = ZResult>; } #[zenoh_macros::unstable] -impl<'a, Handler> Wait for LivelinessSubscriberBuilder<'a, '_, Handler> +impl Wait for LivelinessSubscriberBuilder<'_, '_, Handler> where Handler: IntoHandler<'static, Sample> + Send, Handler::Handler: Send, @@ -602,6 +588,7 @@ where let session = self.session; let (callback, handler) = self.handler.into_handler(); session + .0 .declare_liveliness_subscriber_inner( &key_expr, Locality::default(), @@ -609,11 +596,13 @@ where callback, ) .map(|sub_state| Subscriber { - subscriber: SubscriberInner { - session, + inner: SubscriberInner { + #[cfg(feature = "unstable")] + session_id: session.zid(), + session: self.session.downgrade(), state: sub_state, kind: SubscriberKind::LivelinessSubscriber, - undeclare_on_drop: true, + undeclare_on_drop: self.undeclare_on_drop, }, handler, }) @@ -621,7 +610,7 @@ where } #[zenoh_macros::unstable] -impl<'a, Handler> IntoFuture for LivelinessSubscriberBuilder<'a, '_, Handler> +impl IntoFuture for LivelinessSubscriberBuilder<'_, '_, Handler> where Handler: IntoHandler<'static, Sample> + Send, Handler::Handler: Send, @@ -642,7 +631,6 @@ where /// # #[tokio::main] /// # async fn main() { /// # use std::convert::TryFrom; -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let tokens = session @@ -674,7 +662,6 @@ impl<'a, 'b> LivelinessGetBuilder<'a, 'b, DefaultHandler> { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let queryable = session @@ -690,30 +677,18 @@ impl<'a, 'b> LivelinessGetBuilder<'a, 'b, DefaultHandler> { where Callback: Fn(Reply) + Send + Sync + 'static, { - let LivelinessGetBuilder { - session, - key_expr, - timeout, - handler: _, - } = self; - LivelinessGetBuilder { - session, - key_expr, - timeout, - handler: callback, - } + self.with(callback) } /// Receive the replies for this liveliness query with a mutable callback. /// /// Using this guarantees that your callback will never be called concurrently. - /// If your callback is also accepted by the [`callback`](LivelinessGetBuilder::callback) method, we suggest you use it instead of `callback_mut` + /// If your callback is also accepted by the [`callback`](LivelinessGetBuilder::callback) method, we suggest you use it instead of `callback_mut`. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let mut n = 0; @@ -742,7 +717,6 @@ impl<'a, 'b> LivelinessGetBuilder<'a, 'b, DefaultHandler> { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let replies = session @@ -776,7 +750,7 @@ impl<'a, 'b> LivelinessGetBuilder<'a, 'b, DefaultHandler> { } } -impl<'a, 'b, Handler> LivelinessGetBuilder<'a, 'b, Handler> { +impl LivelinessGetBuilder<'_, '_, Handler> { /// Set query timeout. #[inline] pub fn timeout(mut self, timeout: Duration) -> Self { @@ -801,6 +775,7 @@ where fn wait(self) -> ::To { let (callback, receiver) = self.handler.into_handler(); self.session + .0 .liveliness_query(&self.key_expr?, self.timeout, callback) .map(|_| receiver) } diff --git a/zenoh/src/api/publisher.rs b/zenoh/src/api/publisher.rs index 0c52d24857..fcd4ce59d3 100644 --- a/zenoh/src/api/publisher.rs +++ b/zenoh/src/api/publisher.rs @@ -21,6 +21,7 @@ use std::{ }; use futures::Sink; +use tracing::error; use zenoh_core::{zread, Resolvable, Resolve, Wait}; use zenoh_protocol::{ core::{CongestionControl, Reliability}, @@ -34,11 +35,9 @@ use { handlers::{Callback, DefaultHandler, IntoHandler}, sample::SourceInfo, }, - std::{ - collections::HashSet, - sync::{Arc, Mutex}, - }, + std::{collections::HashSet, sync::Arc, sync::Mutex}, zenoh_config::wrappers::EntityGlobalId, + zenoh_config::ZenohId, zenoh_protocol::core::EntityGlobalIdProto, }; @@ -51,10 +50,10 @@ use super::{ encoding::Encoding, key_expr::KeyExpr, sample::{DataInfo, Locality, QoS, Sample, SampleFields, SampleKind}, - session::{SessionRef, UndeclarableSealed}, + session::UndeclarableSealed, }; use crate::{ - api::{subscriber::SubscriberKind, Id}, + api::{session::WeakSession, subscriber::SubscriberKind, Id}, net::primitives::Primitives, }; @@ -74,35 +73,6 @@ impl fmt::Debug for PublisherState { } } -#[zenoh_macros::unstable] -#[derive(Clone)] -pub enum PublisherRef<'a> { - Borrow(&'a Publisher<'a>), - Shared(std::sync::Arc>), -} - -#[zenoh_macros::unstable] -impl<'a> std::ops::Deref for PublisherRef<'a> { - type Target = Publisher<'a>; - - fn deref(&self) -> &Self::Target { - match self { - PublisherRef::Borrow(b) => b, - PublisherRef::Shared(s) => s, - } - } -} - -#[zenoh_macros::unstable] -impl std::fmt::Debug for PublisherRef<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - PublisherRef::Borrow(b) => Publisher::fmt(b, f), - PublisherRef::Shared(s) => Publisher::fmt(s, f), - } - } -} - /// A publisher that allows to send data through a stream. /// /// Publishers are automatically undeclared when dropped. @@ -111,9 +81,8 @@ impl std::fmt::Debug for PublisherRef<'_> { /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// -/// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); +/// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression").await.unwrap(); /// publisher.put("value").await.unwrap(); /// # } @@ -126,9 +95,8 @@ impl std::fmt::Debug for PublisherRef<'_> { /// # #[tokio::main] /// # async fn main() { /// use futures::StreamExt; -/// use zenoh::prelude::*; /// -/// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); +/// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let mut subscriber = session.declare_subscriber("key/expression").await.unwrap(); /// let publisher = session.declare_publisher("another/key/expression").await.unwrap(); /// subscriber.stream().map(Ok).forward(publisher).await.unwrap(); @@ -136,7 +104,9 @@ impl std::fmt::Debug for PublisherRef<'_> { /// ``` #[derive(Debug)] pub struct Publisher<'a> { - pub(crate) session: SessionRef<'a>, + #[cfg(feature = "unstable")] + pub(crate) session_id: ZenohId, + pub(crate) session: WeakSession, pub(crate) id: Id, pub(crate) key_expr: KeyExpr<'a>, pub(crate) encoding: Encoding, @@ -158,7 +128,6 @@ impl<'a> Publisher<'a> { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression") @@ -170,7 +139,7 @@ impl<'a> Publisher<'a> { #[zenoh_macros::unstable] pub fn id(&self) -> EntityGlobalId { EntityGlobalIdProto { - zid: self.session.zid().into(), + zid: self.session_id.into(), eid: self.id, } .into() @@ -206,51 +175,14 @@ impl<'a> Publisher<'a> { self.reliability } - /// Consumes the given `Publisher`, returning a thread-safe reference-counting - /// pointer to it (`Arc`). This is equivalent to `Arc::new(Publisher)`. - /// - /// This is useful to share ownership of the `Publisher` between several threads - /// and tasks. It also allows to create [`MatchingListener`] with static - /// lifetime that can be moved to several threads and tasks. - /// - /// Note: the given zenoh `Publisher` will be undeclared when the last reference to - /// it is dropped. - /// - /// # Examples - /// ```no_run - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let publisher = session.declare_publisher("key/expression").await.unwrap().into_arc(); - /// let matching_listener = publisher.matching_listener().await.unwrap(); - /// - /// tokio::task::spawn(async move { - /// while let Ok(matching_status) = matching_listener.recv_async().await { - /// if matching_status.matching_subscribers() { - /// println!("Publisher has matching subscribers."); - /// } else { - /// println!("Publisher has NO MORE matching subscribers."); - /// } - /// } - /// }).await; - /// # } - /// ``` - #[zenoh_macros::unstable] - pub fn into_arc(self) -> std::sync::Arc { - std::sync::Arc::new(self) - } - /// Put data. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); + /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression").await.unwrap(); /// publisher.put("value").await.unwrap(); /// # } @@ -279,9 +211,8 @@ impl<'a> Publisher<'a> { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); + /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression").await.unwrap(); /// publisher.delete().await.unwrap(); /// # } @@ -306,9 +237,8 @@ impl<'a> Publisher<'a> { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); + /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression").await.unwrap(); /// let matching_subscribers: bool = publisher /// .matching_status() @@ -334,7 +264,6 @@ impl<'a> Publisher<'a> { /// ```no_run /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression").await.unwrap(); @@ -349,20 +278,20 @@ impl<'a> Publisher<'a> { /// # } /// ``` #[zenoh_macros::unstable] - pub fn matching_listener(&self) -> MatchingListenerBuilder<'_, DefaultHandler> { + pub fn matching_listener(&self) -> MatchingListenerBuilder<'_, 'a, DefaultHandler> { MatchingListenerBuilder { - publisher: PublisherRef::Borrow(self), + publisher: self, handler: DefaultHandler::default(), + undeclare_on_drop: true, } } - /// Undeclares the [`Publisher`], informing the network that it needn't optimize publications for its key expression anymore. + /// Undeclare the [`Publisher`], informing the network that it needn't optimize publications for its key expression anymore. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression").await.unwrap(); @@ -373,107 +302,25 @@ impl<'a> Publisher<'a> { UndeclarableSealed::undeclare_inner(self, ()) } - #[cfg(feature = "unstable")] - fn undeclare_matching_listeners(&self) -> ZResult<()> { - let ids: Vec = zlock!(self.matching_listeners).drain().collect(); - for id in ids { - self.session.undeclare_matches_listener_inner(id)? + fn undeclare_impl(&mut self) -> ZResult<()> { + // set the flag first to avoid double panic if this function panic + self.undeclare_on_drop = false; + #[cfg(feature = "unstable")] + { + let ids: Vec = zlock!(self.matching_listeners).drain().collect(); + for id in ids { + self.session.undeclare_matches_listener_inner(id)? + } } - Ok(()) + self.session.undeclare_publisher_inner(self.id) } } -/// Functions to create zenoh entities with `'static` lifetime. -/// -/// This trait contains functions to create zenoh entities like -/// [`MatchingListener`] with a `'static` lifetime. -/// This is useful to move zenoh entities to several threads and tasks. -/// -/// This trait is implemented for `Arc`. -/// -/// # Examples -/// ```no_run -/// # #[tokio::main] -/// # async fn main() { -/// use zenoh::prelude::*; -/// -/// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); -/// let publisher = session.declare_publisher("key/expression").await.unwrap().into_arc(); -/// let matching_listener = publisher.matching_listener().await.unwrap(); -/// -/// tokio::task::spawn(async move { -/// while let Ok(matching_status) = matching_listener.recv_async().await { -/// if matching_status.matching_subscribers() { -/// println!("Publisher has matching subscribers."); -/// } else { -/// println!("Publisher has NO MORE matching subscribers."); -/// } -/// } -/// }).await; -/// # } -/// ``` -#[zenoh_macros::unstable] -pub trait PublisherDeclarations { - /// # Examples - /// ```no_run - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let publisher = session.declare_publisher("key/expression").await.unwrap().into_arc(); - /// let matching_listener = publisher.matching_listener().await.unwrap(); - /// - /// tokio::task::spawn(async move { - /// while let Ok(matching_status) = matching_listener.recv_async().await { - /// if matching_status.matching_subscribers() { - /// println!("Publisher has matching subscribers."); - /// } else { - /// println!("Publisher has NO MORE matching subscribers."); - /// } - /// } - /// }).await; - /// # } - /// ``` - #[zenoh_macros::unstable] - fn matching_listener(&self) -> MatchingListenerBuilder<'static, DefaultHandler>; -} +impl<'a> UndeclarableSealed<()> for Publisher<'a> { + type Undeclaration = PublisherUndeclaration<'a>; -#[zenoh_macros::unstable] -impl PublisherDeclarations for std::sync::Arc> { - /// # Examples - /// ```no_run - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let publisher = session.declare_publisher("key/expression").await.unwrap().into_arc(); - /// let matching_listener = publisher.matching_listener().await.unwrap(); - /// - /// tokio::task::spawn(async move { - /// while let Ok(matching_status) = matching_listener.recv_async().await { - /// if matching_status.matching_subscribers() { - /// println!("Publisher has matching subscribers."); - /// } else { - /// println!("Publisher has NO MORE matching subscribers."); - /// } - /// } - /// }).await; - /// # } - /// ``` - #[zenoh_macros::unstable] - fn matching_listener(&self) -> MatchingListenerBuilder<'static, DefaultHandler> { - MatchingListenerBuilder { - publisher: PublisherRef::Shared(self.clone()), - handler: DefaultHandler::default(), - } - } -} - -impl<'a> UndeclarableSealed<(), PublisherUndeclaration<'a>> for Publisher<'a> { - fn undeclare_inner(self, _: ()) -> PublisherUndeclaration<'a> { - PublisherUndeclaration { publisher: self } + fn undeclare_inner(self, _: ()) -> Self::Undeclaration { + PublisherUndeclaration(self) } } @@ -483,7 +330,6 @@ impl<'a> UndeclarableSealed<(), PublisherUndeclaration<'a>> for Publisher<'a> { /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression").await.unwrap(); @@ -491,9 +337,7 @@ impl<'a> UndeclarableSealed<(), PublisherUndeclaration<'a>> for Publisher<'a> { /// # } /// ``` #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] -pub struct PublisherUndeclaration<'a> { - publisher: Publisher<'a>, -} +pub struct PublisherUndeclaration<'a>(Publisher<'a>); impl Resolvable for PublisherUndeclaration<'_> { type To = ZResult<()>; @@ -501,13 +345,7 @@ impl Resolvable for PublisherUndeclaration<'_> { impl Wait for PublisherUndeclaration<'_> { fn wait(mut self) -> ::To { - // set the flag first to avoid double panic if this function panic - self.publisher.undeclare_on_drop = false; - #[cfg(feature = "unstable")] - self.publisher.undeclare_matching_listeners()?; - self.publisher - .session - .undeclare_publisher_inner(self.publisher.id) + self.0.undeclare_impl() } } @@ -523,9 +361,9 @@ impl IntoFuture for PublisherUndeclaration<'_> { impl Drop for Publisher<'_> { fn drop(&mut self) { if self.undeclare_on_drop { - #[cfg(feature = "unstable")] - let _ = self.undeclare_matching_listeners(); - let _ = self.session.undeclare_publisher_inner(self.id); + if let Err(error) = self.undeclare_impl() { + error!(error); + } } } } @@ -581,11 +419,7 @@ impl Publisher<'_> { attachment: Option, ) -> ZResult<()> { tracing::trace!("write({:?}, [...])", &self.key_expr); - let primitives = zread!(self.session.state) - .primitives - .as_ref() - .unwrap() - .clone(); + let primitives = zread!(self.session.state).primitives()?; let timestamp = if timestamp.is_none() { self.session.runtime.new_timestamp() } else { @@ -759,9 +593,8 @@ impl TryFrom for Priority { /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// -/// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); +/// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression").await.unwrap(); /// let matching_status = publisher.matching_status().await.unwrap(); /// # } @@ -780,9 +613,8 @@ impl MatchingStatus { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); + /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression").await.unwrap(); /// let matching_subscribers: bool = publisher /// .matching_status() @@ -799,20 +631,20 @@ impl MatchingStatus { /// A builder for initializing a [`MatchingListener`]. #[zenoh_macros::unstable] #[derive(Debug)] -pub struct MatchingListenerBuilder<'a, Handler> { - pub(crate) publisher: PublisherRef<'a>, +pub struct MatchingListenerBuilder<'a, 'b, Handler> { + pub(crate) publisher: &'a Publisher<'b>, pub handler: Handler, + pub(crate) undeclare_on_drop: bool, } #[zenoh_macros::unstable] -impl<'a> MatchingListenerBuilder<'a, DefaultHandler> { +impl<'a, 'b> MatchingListenerBuilder<'a, 'b, DefaultHandler> { /// Receive the MatchingStatuses for this listener with a callback. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression").await.unwrap(); @@ -831,18 +663,11 @@ impl<'a> MatchingListenerBuilder<'a, DefaultHandler> { /// ``` #[inline] #[zenoh_macros::unstable] - pub fn callback(self, callback: Callback) -> MatchingListenerBuilder<'a, Callback> + pub fn callback(self, callback: Callback) -> MatchingListenerBuilder<'a, 'b, Callback> where Callback: Fn(MatchingStatus) + Send + Sync + 'static, { - let MatchingListenerBuilder { - publisher, - handler: _, - } = self; - MatchingListenerBuilder { - publisher, - handler: callback, - } + self.with(callback).undeclare_on_drop(false) } /// Receive the MatchingStatuses for this listener with a mutable callback. @@ -851,7 +676,6 @@ impl<'a> MatchingListenerBuilder<'a, DefaultHandler> { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let mut n = 0; /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); @@ -868,7 +692,7 @@ impl<'a> MatchingListenerBuilder<'a, DefaultHandler> { pub fn callback_mut( self, callback: CallbackMut, - ) -> MatchingListenerBuilder<'a, impl Fn(MatchingStatus) + Send + Sync + 'static> + ) -> MatchingListenerBuilder<'a, 'b, impl Fn(MatchingStatus) + Send + Sync + 'static> where CallbackMut: FnMut(MatchingStatus) + Send + Sync + 'static, { @@ -881,7 +705,6 @@ impl<'a> MatchingListenerBuilder<'a, DefaultHandler> { /// ```no_run /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression").await.unwrap(); @@ -901,54 +724,75 @@ impl<'a> MatchingListenerBuilder<'a, DefaultHandler> { /// ``` #[inline] #[zenoh_macros::unstable] - pub fn with(self, handler: Handler) -> MatchingListenerBuilder<'a, Handler> + pub fn with(self, handler: Handler) -> MatchingListenerBuilder<'a, 'b, Handler> where Handler: IntoHandler<'static, MatchingStatus>, { let MatchingListenerBuilder { publisher, handler: _, + undeclare_on_drop, } = self; - MatchingListenerBuilder { publisher, handler } + MatchingListenerBuilder { + publisher, + handler, + undeclare_on_drop, + } + } +} + +#[zenoh_macros::unstable] +impl MatchingListenerBuilder<'_, '_, Handler> { + /// Set whether the matching listener will be undeclared when dropped. + /// + /// The method is usually used in combination with a callback like in + /// [`callback`](Self::callback) method, or a channel sender. + /// Be careful when using it, as matching listeners not undeclared will consume + /// resources until the publisher is undeclared. + #[inline] + pub fn undeclare_on_drop(mut self, undeclare_on_drop: bool) -> Self { + self.undeclare_on_drop = undeclare_on_drop; + self } } #[zenoh_macros::unstable] -impl<'a, Handler> Resolvable for MatchingListenerBuilder<'a, Handler> +impl Resolvable for MatchingListenerBuilder<'_, '_, Handler> where Handler: IntoHandler<'static, MatchingStatus> + Send, Handler::Handler: Send, { - type To = ZResult>; + type To = ZResult>; } #[zenoh_macros::unstable] -impl<'a, Handler> Wait for MatchingListenerBuilder<'a, Handler> +impl Wait for MatchingListenerBuilder<'_, '_, Handler> where Handler: IntoHandler<'static, MatchingStatus> + Send, Handler::Handler: Send, { #[zenoh_macros::unstable] fn wait(self) -> ::To { - let (callback, receiver) = self.handler.into_handler(); + let (callback, handler) = self.handler.into_handler(); let state = self .publisher .session - .declare_matches_listener_inner(&self.publisher, callback)?; + .declare_matches_listener_inner(self.publisher, callback)?; zlock!(self.publisher.matching_listeners).insert(state.id); Ok(MatchingListener { - listener: MatchingListenerInner { - publisher: self.publisher, + inner: MatchingListenerInner { + session: self.publisher.session.clone(), + matching_listeners: self.publisher.matching_listeners.clone(), state, - undeclare_on_drop: true, + undeclare_on_drop: self.undeclare_on_drop, }, - receiver, + handler, }) } } #[zenoh_macros::unstable] -impl<'a, Handler> IntoFuture for MatchingListenerBuilder<'a, Handler> +impl IntoFuture for MatchingListenerBuilder<'_, '_, Handler> where Handler: IntoHandler<'static, MatchingStatus> + Send, Handler::Handler: Send, @@ -965,15 +809,15 @@ where #[zenoh_macros::unstable] pub(crate) struct MatchingListenerState { pub(crate) id: Id, - pub(crate) current: std::sync::Mutex, + pub(crate) current: Mutex, pub(crate) key_expr: KeyExpr<'static>, pub(crate) destination: Locality, pub(crate) callback: Callback<'static, MatchingStatus>, } #[zenoh_macros::unstable] -impl std::fmt::Debug for MatchingListenerState { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { +impl fmt::Debug for MatchingListenerState { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("MatchingListener") .field("id", &self.id) .field("key_expr", &self.key_expr) @@ -982,35 +826,24 @@ impl std::fmt::Debug for MatchingListenerState { } #[zenoh_macros::unstable] -pub(crate) struct MatchingListenerInner<'a> { - pub(crate) publisher: PublisherRef<'a>, - pub(crate) state: std::sync::Arc, - undeclare_on_drop: bool, -} - -#[zenoh_macros::unstable] -impl<'a> MatchingListenerInner<'a> { - #[inline] - pub fn undeclare(self) -> MatchingListenerUndeclaration<'a> { - UndeclarableSealed::undeclare_inner(self, ()) - } -} - -#[zenoh_macros::unstable] -impl<'a> UndeclarableSealed<(), MatchingListenerUndeclaration<'a>> for MatchingListenerInner<'a> { - fn undeclare_inner(self, _: ()) -> MatchingListenerUndeclaration<'a> { - MatchingListenerUndeclaration { subscriber: self } - } +pub(crate) struct MatchingListenerInner { + pub(crate) session: WeakSession, + pub(crate) matching_listeners: Arc>>, + pub(crate) state: Arc, + pub(crate) undeclare_on_drop: bool, } /// A listener that sends notifications when the [`MatchingStatus`] of a /// publisher changes. /// +/// Callback matching listeners will run in background until the publisher is undeclared, +/// or until it is undeclared. +/// On the other hand, matching listener with a handler are automatically undeclared when dropped. +/// /// # Examples /// ```no_run /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression").await.unwrap(); @@ -1025,23 +858,19 @@ impl<'a> UndeclarableSealed<(), MatchingListenerUndeclaration<'a>> for MatchingL /// # } /// ``` #[zenoh_macros::unstable] -pub struct MatchingListener<'a, Receiver> { - pub(crate) listener: MatchingListenerInner<'a>, - pub(crate) receiver: Receiver, +pub struct MatchingListener { + pub(crate) inner: MatchingListenerInner, + pub(crate) handler: Handler, } #[zenoh_macros::unstable] -impl<'a, Receiver> MatchingListener<'a, Receiver> { - /// Close a [`MatchingListener`]. - /// - /// MatchingListeners are automatically closed when dropped, but you may want to use this function to handle errors or - /// close the MatchingListener asynchronously. +impl MatchingListener { + /// Undeclare the [`MatchingListener`]. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let publisher = session.declare_publisher("key/expression").await.unwrap(); @@ -1050,66 +879,64 @@ impl<'a, Receiver> MatchingListener<'a, Receiver> { /// # } /// ``` #[inline] - pub fn undeclare(self) -> MatchingListenerUndeclaration<'a> { - self.listener.undeclare() + pub fn undeclare(self) -> MatchingListenerUndeclaration + where + Handler: Send, + { + self.undeclare_inner(()) } - /// Make the matching listener run in background, until the publisher is undeclared. - #[inline] - #[zenoh_macros::unstable] - pub fn background(mut self) { - // The matching listener will be undeclared as part of publisher undeclaration. - self.listener.undeclare_on_drop = false; + fn undeclare_impl(&mut self) -> ZResult<()> { + // set the flag first to avoid double panic if this function panic + self.inner.undeclare_on_drop = false; + zlock!(self.inner.matching_listeners).remove(&self.inner.state.id); + self.inner + .session + .undeclare_matches_listener_inner(self.inner.state.id) } } #[zenoh_macros::unstable] -impl<'a, T> UndeclarableSealed<(), MatchingListenerUndeclaration<'a>> for MatchingListener<'a, T> { - fn undeclare_inner(self, _: ()) -> MatchingListenerUndeclaration<'a> { - UndeclarableSealed::undeclare_inner(self.listener, ()) +impl UndeclarableSealed<()> for MatchingListener { + type Undeclaration = MatchingListenerUndeclaration; + + fn undeclare_inner(self, _: ()) -> Self::Undeclaration { + MatchingListenerUndeclaration(self) } } #[zenoh_macros::unstable] -impl std::ops::Deref for MatchingListener<'_, Receiver> { - type Target = Receiver; +impl std::ops::Deref for MatchingListener { + type Target = Handler; fn deref(&self) -> &Self::Target { - &self.receiver + &self.handler } } #[zenoh_macros::unstable] -impl std::ops::DerefMut for MatchingListener<'_, Receiver> { +impl std::ops::DerefMut for MatchingListener { fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.receiver + &mut self.handler } } #[zenoh_macros::unstable] -pub struct MatchingListenerUndeclaration<'a> { - subscriber: MatchingListenerInner<'a>, -} +pub struct MatchingListenerUndeclaration(MatchingListener); #[zenoh_macros::unstable] -impl Resolvable for MatchingListenerUndeclaration<'_> { +impl Resolvable for MatchingListenerUndeclaration { type To = ZResult<()>; } #[zenoh_macros::unstable] -impl Wait for MatchingListenerUndeclaration<'_> { +impl Wait for MatchingListenerUndeclaration { fn wait(mut self) -> ::To { - // set the flag first to avoid double panic if this function panic - self.subscriber.undeclare_on_drop = false; - zlock!(self.subscriber.publisher.matching_listeners).remove(&self.subscriber.state.id); - self.subscriber - .publisher - .session - .undeclare_matches_listener_inner(self.subscriber.state.id) + self.0.undeclare_impl() } } #[zenoh_macros::unstable] -impl IntoFuture for MatchingListenerUndeclaration<'_> { +impl IntoFuture for MatchingListenerUndeclaration { type Output = ::To; type IntoFuture = Ready<::To>; @@ -1118,25 +945,12 @@ impl IntoFuture for MatchingListenerUndeclaration<'_> { } } -#[zenoh_macros::unstable] -impl Drop for MatchingListenerInner<'_> { - fn drop(&mut self) { - if self.undeclare_on_drop { - zlock!(self.publisher.matching_listeners).remove(&self.state.id); - let _ = self - .publisher - .session - .undeclare_matches_listener_inner(self.state.id); - } - } -} - #[cfg(test)] mod tests { use zenoh_config::Config; use zenoh_core::Wait; - use crate::api::{sample::SampleKind, session::SessionDeclarations}; + use crate::api::sample::SampleKind; #[cfg(feature = "internal")] #[test] diff --git a/zenoh/src/api/query.rs b/zenoh/src/api/query.rs index 922f88e1a4..ae55d5ab8d 100644 --- a/zenoh/src/api/query.rs +++ b/zenoh/src/api/query.rs @@ -178,7 +178,7 @@ impl QueryState { /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::{prelude::*, query::{ConsolidationMode, QueryTarget}}; +/// use zenoh::{query::{ConsolidationMode, QueryTarget}}; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let replies = session @@ -265,7 +265,6 @@ impl<'a, 'b> SessionGetBuilder<'a, 'b, DefaultHandler> { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let queryable = session @@ -280,46 +279,18 @@ impl<'a, 'b> SessionGetBuilder<'a, 'b, DefaultHandler> { where Callback: Fn(Reply) + Send + Sync + 'static, { - let SessionGetBuilder { - session, - selector, - target, - consolidation, - qos, - destination, - timeout, - value, - attachment, - #[cfg(feature = "unstable")] - source_info, - handler: _, - } = self; - SessionGetBuilder { - session, - selector, - target, - consolidation, - qos, - destination, - timeout, - value, - attachment, - #[cfg(feature = "unstable")] - source_info, - handler: callback, - } + self.with(callback) } /// Receive the replies for this query with a mutable callback. /// /// Using this guarantees that your callback will never be called concurrently. - /// If your callback is also accepted by the [`callback`](crate::session::SessionGetBuilder::callback) method, we suggest you use it instead of `callback_mut` + /// If your callback is also accepted by the [`callback`](crate::session::SessionGetBuilder::callback) method, we suggest you use it instead of `callback_mut`. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let mut n = 0; @@ -347,7 +318,6 @@ impl<'a, 'b> SessionGetBuilder<'a, 'b, DefaultHandler> { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let replies = session @@ -492,6 +462,7 @@ where parameters, } = self.selector?; self.session + .0 .query( &key_expr, ¶meters, diff --git a/zenoh/src/api/queryable.rs b/zenoh/src/api/queryable.rs index 92d27ffa87..951600d1e6 100644 --- a/zenoh/src/api/queryable.rs +++ b/zenoh/src/api/queryable.rs @@ -18,6 +18,7 @@ use std::{ sync::Arc, }; +use tracing::error; use uhlc::Timestamp; use zenoh_core::{Resolvable, Resolve, Wait}; use zenoh_protocol::{ @@ -28,30 +29,33 @@ use zenoh_protocol::{ use zenoh_result::ZResult; #[zenoh_macros::unstable] use { - super::{query::ReplyKeyExpr, sample::SourceInfo}, - zenoh_config::wrappers::EntityGlobalId, + crate::api::{query::ReplyKeyExpr, sample::SourceInfo}, + zenoh_config::wrappers::{EntityGlobalId, ZenohId}, zenoh_protocol::core::EntityGlobalIdProto, }; #[zenoh_macros::unstable] -use super::selector::ZenohParameters; -use super::{ - builders::sample::{ - EncodingBuilderTrait, QoSBuilderTrait, SampleBuilder, SampleBuilderTrait, - TimestampBuilderTrait, +use crate::api::selector::ZenohParameters; +use crate::{ + api::{ + builders::sample::{ + EncodingBuilderTrait, QoSBuilderTrait, SampleBuilder, SampleBuilderTrait, + TimestampBuilderTrait, + }, + bytes::{OptionZBytes, ZBytes}, + encoding::Encoding, + handlers::{locked, DefaultHandler, IntoHandler}, + key_expr::KeyExpr, + publisher::Priority, + sample::{Locality, QoSBuilder, Sample, SampleKind}, + selector::Selector, + session::{UndeclarableSealed, WeakSession}, + value::Value, + Id, }, - bytes::{OptionZBytes, ZBytes}, - encoding::Encoding, - handlers::{locked, DefaultHandler, IntoHandler}, - key_expr::KeyExpr, - publisher::Priority, - sample::{Locality, QoSBuilder, Sample, SampleKind}, - selector::Selector, - session::{SessionRef, UndeclarableSealed}, - value::Value, - Id, + net::primitives::Primitives, + Session, }; -use crate::net::primitives::Primitives; pub(crate) struct QueryInner { pub(crate) key_expr: KeyExpr<'static>, @@ -539,43 +543,14 @@ impl fmt::Debug for QueryableState { } } -/// An entity able to reply to queries through a callback. -/// -/// CallbackQueryables can be created from a zenoh [`Session`](crate::Session) -/// with the [`declare_queryable`](crate::Session::declare_queryable) function -/// and the [`callback`](QueryableBuilder::callback) function -/// of the resulting builder. -/// -/// Queryables are automatically undeclared when dropped. -/// -/// # Examples -/// ```no_run -/// # #[tokio::main] -/// # async fn main() { -/// use futures::prelude::*; -/// use zenoh::prelude::*; -/// -/// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); -/// let queryable = session.declare_queryable("key/expression").await.unwrap(); -/// while let Ok(query) = queryable.recv_async().await { -/// println!(">> Handling query '{}'", query.selector()); -/// query.reply("key/expression", "value") -/// .await -/// .unwrap(); -/// } -/// # } -/// ``` #[derive(Debug)] -pub(crate) struct CallbackQueryable<'a> { - pub(crate) session: SessionRef<'a>, +pub(crate) struct QueryableInner { + #[cfg(feature = "unstable")] + pub(crate) session_id: ZenohId, + pub(crate) session: WeakSession, pub(crate) state: Arc, - undeclare_on_drop: bool, -} - -impl<'a> UndeclarableSealed<(), QueryableUndeclaration<'a>> for CallbackQueryable<'a> { - fn undeclare_inner(self, _: ()) -> QueryableUndeclaration<'a> { - QueryableUndeclaration { queryable: self } - } + // Queryable is undeclared on drop unless its handler is a ZST, i.e. it is callback-only + pub(crate) undeclare_on_drop: bool, } /// A [`Resolvable`] returned when undeclaring a queryable. @@ -584,7 +559,6 @@ impl<'a> UndeclarableSealed<(), QueryableUndeclaration<'a>> for CallbackQueryabl /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let queryable = session.declare_queryable("key/expression").await.unwrap(); @@ -592,25 +566,19 @@ impl<'a> UndeclarableSealed<(), QueryableUndeclaration<'a>> for CallbackQueryabl /// # } /// ``` #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] -pub struct QueryableUndeclaration<'a> { - queryable: CallbackQueryable<'a>, -} +pub struct QueryableUndeclaration(Queryable); -impl Resolvable for QueryableUndeclaration<'_> { +impl Resolvable for QueryableUndeclaration { type To = ZResult<()>; } -impl Wait for QueryableUndeclaration<'_> { +impl Wait for QueryableUndeclaration { fn wait(mut self) -> ::To { - // set the flag first to avoid double panic if this function panic - self.queryable.undeclare_on_drop = false; - self.queryable - .session - .close_queryable(self.queryable.state.id) + self.0.undeclare_impl() } } -impl<'a> IntoFuture for QueryableUndeclaration<'a> { +impl IntoFuture for QueryableUndeclaration { type Output = ::To; type IntoFuture = Ready<::To>; @@ -619,21 +587,12 @@ impl<'a> IntoFuture for QueryableUndeclaration<'a> { } } -impl Drop for CallbackQueryable<'_> { - fn drop(&mut self) { - if self.undeclare_on_drop { - let _ = self.session.close_queryable(self.state.id); - } - } -} - /// A builder for initializing a [`Queryable`]. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let queryable = session.declare_queryable("key/expression").await.unwrap(); @@ -642,21 +601,27 @@ impl Drop for CallbackQueryable<'_> { #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] #[derive(Debug)] pub struct QueryableBuilder<'a, 'b, Handler> { - pub(crate) session: SessionRef<'a>, + pub(crate) session: &'a Session, pub(crate) key_expr: ZResult>, pub(crate) complete: bool, pub(crate) origin: Locality, pub(crate) handler: Handler, + pub(crate) undeclare_on_drop: bool, } impl<'a, 'b> QueryableBuilder<'a, 'b, DefaultHandler> { - /// Receive the queries for this Queryable with a callback. + /// Receive the queries for this queryable with a callback. + /// + /// Queryable will not be undeclared when dropped, with the callback running + /// in background until the session is closed. + /// + /// It is in fact just a convenient shortcut for + /// `.with(my_callback).undeclare_on_drop(false)`. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let queryable = session @@ -671,32 +636,21 @@ impl<'a, 'b> QueryableBuilder<'a, 'b, DefaultHandler> { where Callback: Fn(Query) + Send + Sync + 'static, { - let QueryableBuilder { - session, - key_expr, - complete, - origin, - handler: _, - } = self; - QueryableBuilder { - session, - key_expr, - complete, - origin, - handler: callback, - } + self.with(callback).undeclare_on_drop(false) } /// Receive the queries for this Queryable with a mutable callback. /// /// Using this guarantees that your callback will never be called concurrently. - /// If your callback is also accepted by the [`callback`](QueryableBuilder::callback) method, we suggest you use it instead of `callback_mut` + /// If your callback is also accepted by the [`callback`](QueryableBuilder::callback) method, we suggest you use it instead of `callback_mut`. + /// + /// Queryable will not be undeclared when dropped, with the callback running + /// in background until the session is closed. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let mut n = 0; @@ -724,7 +678,6 @@ impl<'a, 'b> QueryableBuilder<'a, 'b, DefaultHandler> { /// ```no_run /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let queryable = session @@ -748,6 +701,7 @@ impl<'a, 'b> QueryableBuilder<'a, 'b, DefaultHandler> { complete, origin, handler: _, + undeclare_on_drop, } = self; QueryableBuilder { session, @@ -755,8 +709,18 @@ impl<'a, 'b> QueryableBuilder<'a, 'b, DefaultHandler> { complete, origin, handler, + undeclare_on_drop, } } +} + +impl QueryableBuilder<'_, '_, Handler> { + /// Change queryable completeness. + #[inline] + pub fn complete(mut self, complete: bool) -> Self { + self.complete = complete; + self + } /// Restrict the matching queries that will be receive by this [`Queryable`] /// to the ones that have the given [`Locality`](crate::prelude::Locality). @@ -766,12 +730,16 @@ impl<'a, 'b> QueryableBuilder<'a, 'b, DefaultHandler> { self.origin = origin; self } -} -impl<'a, 'b, Handler> QueryableBuilder<'a, 'b, Handler> { - /// Change queryable completeness. + + /// Set whether the queryable will be undeclared when dropped. + /// + /// The method is usually used in combination with a callback like in + /// [`callback`](Self::callback) method, or a channel sender. + /// Be careful when using it, as queryables not undeclared will consume + /// resources until the session is closed. #[inline] - pub fn complete(mut self, complete: bool) -> Self { - self.complete = complete; + pub fn undeclare_on_drop(mut self, undeclare_on_drop: bool) -> Self { + self.undeclare_on_drop = undeclare_on_drop; self } } @@ -779,17 +747,41 @@ impl<'a, 'b, Handler> QueryableBuilder<'a, 'b, Handler> { /// A queryable that provides data through a [`Handler`](crate::handlers::IntoHandler). /// /// Queryables can be created from a zenoh [`Session`](crate::Session) -/// with the [`declare_queryable`](crate::session::SessionDeclarations::declare_queryable) function -/// and the [`with`](QueryableBuilder::with) function -/// of the resulting builder. +/// with the [`declare_queryable`](crate::Session::declare_queryable) function. /// -/// Queryables are automatically undeclared when dropped. +/// Callback queryables will run in background until the session is closed, +/// or until it is undeclared. +/// On the other hand, queryables with a handler are automatically undeclared when dropped. /// /// # Examples +/// +/// Using callback: +/// ```no_run +/// # #[tokio::main] +/// # async fn main() { +/// use futures::prelude::*; +/// +/// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); +/// let (tx, rx) = flume::bounded(32); +/// session +/// .declare_queryable("key/expression") +/// .callback(move |query| tx.send(query).unwrap()) +/// .await +/// .unwrap(); +/// // queryable run in background until the session is closed +/// tokio::spawn(async move { +/// while let Ok(query) = rx.recv_async().await { +/// println!(">> Handling query '{}'", query.selector()); +/// query.reply("key/expression", "value").await.unwrap(); +/// } +/// }); +/// # } +/// ``` +/// +/// Using channel handler: /// ```no_run /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let queryable = session @@ -803,23 +795,23 @@ impl<'a, 'b, Handler> QueryableBuilder<'a, 'b, Handler> { /// .await /// .unwrap(); /// } +/// // queryable is undeclared at the end of the scope /// # } /// ``` #[non_exhaustive] #[derive(Debug)] -pub struct Queryable<'a, Handler> { - pub(crate) queryable: CallbackQueryable<'a>, +pub struct Queryable { + pub(crate) inner: QueryableInner, pub(crate) handler: Handler, } -impl<'a, Handler> Queryable<'a, Handler> { +impl Queryable { /// Returns the [`EntityGlobalId`] of this Queryable. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let queryable = session.declare_queryable("key/expression") @@ -831,8 +823,8 @@ impl<'a, Handler> Queryable<'a, Handler> { #[zenoh_macros::unstable] pub fn id(&self) -> EntityGlobalId { EntityGlobalIdProto { - zid: self.queryable.session.zid().into(), - eid: self.queryable.state.id, + zid: self.inner.session_id.into(), + eid: self.inner.state.id, } .into() } @@ -851,29 +843,54 @@ impl<'a, Handler> Queryable<'a, Handler> { &mut self.handler } + /// Undeclare the [`Queryable`]. + /// + /// # Examples + /// ``` + /// # #[tokio::main] + /// # async fn main() { + /// + /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); + /// let queryable = session.declare_queryable("key/expression") + /// .await + /// .unwrap(); + /// queryable.undeclare().await.unwrap(); + /// # } + /// ``` #[inline] - pub fn undeclare(self) -> impl Resolve> + 'a { + pub fn undeclare(self) -> impl Resolve> + where + Handler: Send, + { UndeclarableSealed::undeclare_inner(self, ()) } - /// Make the queryable run in background, until the session is closed. - #[inline] - #[zenoh_macros::unstable] - pub fn background(mut self) { - // It's not necessary to undeclare this resource when session close, as other sessions - // will clean all resources related to the closed one. - // So we can just never undeclare it. - self.queryable.undeclare_on_drop = false; + fn undeclare_impl(&mut self) -> ZResult<()> { + // set the flag first to avoid double panic if this function panic + self.inner.undeclare_on_drop = false; + self.inner.session.close_queryable(self.inner.state.id) + } +} + +impl Drop for Queryable { + fn drop(&mut self) { + if self.inner.undeclare_on_drop { + if let Err(error) = self.undeclare_impl() { + error!(error); + } + } } } -impl<'a, T> UndeclarableSealed<(), QueryableUndeclaration<'a>> for Queryable<'a, T> { - fn undeclare_inner(self, _: ()) -> QueryableUndeclaration<'a> { - UndeclarableSealed::undeclare_inner(self.queryable, ()) +impl UndeclarableSealed<()> for Queryable { + type Undeclaration = QueryableUndeclaration; + + fn undeclare_inner(self, _: ()) -> Self::Undeclaration { + QueryableUndeclaration(self) } } -impl Deref for Queryable<'_, Handler> { +impl Deref for Queryable { type Target = Handler; fn deref(&self) -> &Self::Target { @@ -881,21 +898,21 @@ impl Deref for Queryable<'_, Handler> { } } -impl DerefMut for Queryable<'_, Handler> { +impl DerefMut for Queryable { fn deref_mut(&mut self) -> &mut Self::Target { self.handler_mut() } } -impl<'a, Handler> Resolvable for QueryableBuilder<'a, '_, Handler> +impl Resolvable for QueryableBuilder<'_, '_, Handler> where Handler: IntoHandler<'static, Query> + Send, Handler::Handler: Send, { - type To = ZResult>; + type To = ZResult>; } -impl<'a, Handler> Wait for QueryableBuilder<'a, '_, Handler> +impl Wait for QueryableBuilder<'_, '_, Handler> where Handler: IntoHandler<'static, Query> + Send, Handler::Handler: Send, @@ -904,24 +921,27 @@ where let session = self.session; let (callback, receiver) = self.handler.into_handler(); session + .0 .declare_queryable_inner( - &self.key_expr?.to_wire(&session), + &self.key_expr?.to_wire(&session.0), self.complete, self.origin, callback, ) .map(|qable_state| Queryable { - queryable: CallbackQueryable { - session, + inner: QueryableInner { + #[cfg(feature = "unstable")] + session_id: session.zid(), + session: self.session.downgrade(), state: qable_state, - undeclare_on_drop: true, + undeclare_on_drop: self.undeclare_on_drop, }, handler: receiver, }) } } -impl<'a, Handler> IntoFuture for QueryableBuilder<'a, '_, Handler> +impl IntoFuture for QueryableBuilder<'_, '_, Handler> where Handler: IntoHandler<'static, Query> + Send, Handler::Handler: Send, diff --git a/zenoh/src/api/scouting.rs b/zenoh/src/api/scouting.rs index 4f08530533..0a41294548 100644 --- a/zenoh/src/api/scouting.rs +++ b/zenoh/src/api/scouting.rs @@ -37,7 +37,7 @@ use crate::{ /// ```no_run /// # #[tokio::main] /// # async fn main() { -/// use zenoh::{config::WhatAmI, prelude::*}; +/// use zenoh::config::WhatAmI; /// /// let receiver = zenoh::scout(WhatAmI::Peer | WhatAmI::Router, zenoh::config::default()) /// .await @@ -62,7 +62,7 @@ impl ScoutBuilder { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::{config::WhatAmI, prelude::*}; + /// use zenoh::config::WhatAmI; /// /// let scout = zenoh::scout(WhatAmI::Peer | WhatAmI::Router, zenoh::config::default()) /// .callback(|hello| { println!("{}", hello); }) @@ -75,16 +75,7 @@ impl ScoutBuilder { where Callback: Fn(Hello) + Send + Sync + 'static, { - let ScoutBuilder { - what, - config, - handler: _, - } = self; - ScoutBuilder { - what, - config, - handler: callback, - } + self.with(callback) } /// Receive the [`Hello`] messages from this scout with a mutable callback. @@ -96,7 +87,7 @@ impl ScoutBuilder { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::{config::WhatAmI, prelude::*}; + /// use zenoh::config::WhatAmI; /// /// let mut n = 0; /// let scout = zenoh::scout(WhatAmI::Peer | WhatAmI::Router, zenoh::config::default()) @@ -122,7 +113,7 @@ impl ScoutBuilder { /// ```no_run /// # #[tokio::main] /// # async fn main() { - /// use zenoh::{config::WhatAmI, prelude::*}; + /// use zenoh::config::WhatAmI; /// /// let receiver = zenoh::scout(WhatAmI::Peer | WhatAmI::Router, zenoh::config::default()) /// .with(flume::bounded(32)) @@ -189,7 +180,7 @@ where /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::{config::WhatAmI, prelude::*}; +/// use zenoh::config::WhatAmI; /// /// let scout = zenoh::scout(WhatAmI::Peer | WhatAmI::Router, zenoh::config::default()) /// .callback(|hello| { println!("{}", hello); }) @@ -209,7 +200,7 @@ impl ScoutInner { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::{config::WhatAmI, prelude::*}; + /// use zenoh::config::WhatAmI; /// /// let scout = zenoh::scout(WhatAmI::Peer | WhatAmI::Router, zenoh::config::default()) /// .callback(|hello| { println!("{}", hello); }) @@ -244,7 +235,7 @@ impl fmt::Debug for ScoutInner { /// ```no_run /// # #[tokio::main] /// # async fn main() { -/// use zenoh::{config::WhatAmI, prelude::*}; +/// use zenoh::config::WhatAmI; /// /// let receiver = zenoh::scout(WhatAmI::Peer | WhatAmI::Router, zenoh::config::default()) /// .with(flume::bounded(32)) @@ -277,7 +268,7 @@ impl Scout { /// ```no_run /// # #[tokio::main] /// # async fn main() { - /// use zenoh::{config::WhatAmI, prelude::*}; + /// use zenoh::config::WhatAmI; /// /// let scout = zenoh::scout(WhatAmI::Router, zenoh::config::default()) /// .with(flume::bounded(32)) @@ -359,7 +350,7 @@ fn _scout( /// ```no_run /// # #[tokio::main] /// # async fn main() { -/// use zenoh::{config::WhatAmI, prelude::*}; +/// use zenoh::config::WhatAmI; /// /// let receiver = zenoh::scout(WhatAmI::Peer | WhatAmI::Router, zenoh::config::default()) /// .await diff --git a/zenoh/src/api/session.rs b/zenoh/src/api/session.rs index 2e059710c9..b147edbb01 100644 --- a/zenoh/src/api/session.rs +++ b/zenoh/src/api/session.rs @@ -19,12 +19,12 @@ use std::{ ops::Deref, sync::{ atomic::{AtomicU16, Ordering}, - Arc, RwLock, + Arc, Mutex, RwLock, }, time::{Duration, SystemTime, UNIX_EPOCH}, }; -use tracing::{error, trace, warn}; +use tracing::{error, info, trace, warn}; use uhlc::{Timestamp, HLC}; use zenoh_buffers::ZBuf; use zenoh_collections::SingleOrVec; @@ -174,6 +174,14 @@ impl SessionState { } impl SessionState { + #[inline] + pub(crate) fn primitives(&self) -> ZResult> { + self.primitives + .as_ref() + .cloned() + .ok_or_else(|| zerror!("session closed").into()) + } + #[inline] fn get_local_res(&self, id: &ExprId) -> Option<&Resource> { self.local_resources.get(id) @@ -359,140 +367,149 @@ impl Resource { } } -#[derive(Clone)] -pub enum SessionRef<'a> { - Borrow(&'a Session), - Shared(Arc), +/// A trait implemented by types that can be undeclared. +pub trait UndeclarableSealed { + type Undeclaration: Resolve> + Send; + fn undeclare_inner(self, session: S) -> Self::Undeclaration; } -impl<'s, 'a> SessionDeclarations<'s, 'a> for SessionRef<'a> { - fn declare_subscriber<'b, TryIntoKeyExpr>( - &'s self, - key_expr: TryIntoKeyExpr, - ) -> SubscriberBuilder<'a, 'b, DefaultHandler> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into, - { - SubscriberBuilder { - session: self.clone(), - key_expr: TryIntoKeyExpr::try_into(key_expr).map_err(Into::into), - origin: Locality::default(), - handler: DefaultHandler::default(), - } - } - fn declare_queryable<'b, TryIntoKeyExpr>( - &'s self, - key_expr: TryIntoKeyExpr, - ) -> QueryableBuilder<'a, 'b, DefaultHandler> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into, - { - QueryableBuilder { - session: self.clone(), - key_expr: key_expr.try_into().map_err(Into::into), - complete: false, - origin: Locality::default(), - handler: DefaultHandler::default(), - } - } - fn declare_publisher<'b, TryIntoKeyExpr>( - &'s self, - key_expr: TryIntoKeyExpr, - ) -> PublisherBuilder<'a, 'b> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into, - { - PublisherBuilder { - session: self.clone(), - key_expr: key_expr.try_into().map_err(Into::into), - encoding: Encoding::default(), - congestion_control: CongestionControl::DEFAULT, - priority: Priority::DEFAULT, - is_express: false, - #[cfg(feature = "unstable")] - reliability: Reliability::DEFAULT, - destination: Locality::default(), - } +impl<'a, T> UndeclarableSealed<&'a Session> for T +where + T: UndeclarableSealed<()>, +{ + type Undeclaration = >::Undeclaration; + + fn undeclare_inner(self, _session: &'a Session) -> Self::Undeclaration { + self.undeclare_inner(()) } - #[zenoh_macros::unstable] - fn liveliness(&'s self) -> Liveliness<'a> { - Liveliness { - session: self.clone(), - } +} + +// NOTE: `UndeclarableInner` is only pub(crate) to hide the `undeclare_inner` method. So we don't +// care about the `private_bounds` lint in this particular case. +#[allow(private_bounds)] +/// A trait implemented by types that can be undeclared. +pub trait Undeclarable: UndeclarableSealed {} + +impl Undeclarable for T where T: UndeclarableSealed {} + +pub(crate) struct SessionInner { + /// See [`WeakSession`] doc + weak_counter: Mutex, + pub(crate) runtime: Runtime, + pub(crate) state: RwLock, + pub(crate) id: u16, + owns_runtime: bool, + task_controller: TaskController, +} + +impl fmt::Debug for SessionInner { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Session") + .field("id", &self.runtime.zid()) + .finish() } - fn info(&'s self) -> SessionInfo<'a> { - SessionInfo { - session: self.clone(), - } +} + +/// The entrypoint of the zenoh API. +/// +/// Zenoh session is instantiated using [`zenoh::open`](crate::open) and it can be used to declare various +/// entities like publishers, subscribers, or querybables, as well as issuing queries. +/// +/// Session is an `Arc`-like type, it can be cloned, and it is closed when the last instance +/// is dropped (see [`Session::close`]). +/// +/// # Examples +/// ``` +/// # #[tokio::main] +/// # async fn main() { +/// +/// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); +/// session.put("key/expression", "value").await.unwrap(); +/// # } +pub struct Session(pub(crate) Arc); + +impl Session { + pub(crate) fn downgrade(&self) -> WeakSession { + WeakSession::new(&self.0) } } -impl Deref for SessionRef<'_> { - type Target = Session; +impl fmt::Debug for Session { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} - fn deref(&self) -> &Self::Target { - match self { - SessionRef::Borrow(b) => b, - SessionRef::Shared(s) => s, - } +impl Clone for Session { + fn clone(&self) -> Self { + let _weak = self.0.weak_counter.lock().unwrap(); + Self(self.0.clone()) } } -impl fmt::Debug for SessionRef<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - SessionRef::Borrow(b) => Session::fmt(b, f), - SessionRef::Shared(s) => Session::fmt(s, f), +impl Drop for Session { + fn drop(&mut self) { + let weak = self.0.weak_counter.lock().unwrap(); + if Arc::strong_count(&self.0) == *weak + /* the `Arc` currently dropped */ 1 { + drop(weak); + if let Err(error) = self.close().wait() { + tracing::error!(error) + } } } } -pub(crate) trait UndeclarableSealed> -where - O: Resolve + Send, -{ - fn undeclare_inner(self, session: S) -> O; +/// `WeakSession` provides a weak-like semantic to the arc-like session, without using [`Weak`]. +/// It allows notably to establish reference cycles inside the session, for the primitive +/// implementation. +/// When all `Session` instance are dropped, [`Session::close`] is be called and cleans +/// the reference cycles, allowing the underlying `Arc` to be properly reclaimed. +/// +/// The pseudo-weak algorithm relies on a counter wrapped in a mutex. It was indeed the simplest +/// to implement it, because atomic manipulations to achieve this semantic would not have been +/// trivial at all — what could happen if a pseudo-weak is cloned while the last session instance +/// is dropped? With a mutex, it's simple, and it works perfectly fine, as we don't care about the +/// performance penalty when it comes to session entities cloning/dropping. +/// +/// (Although it was planed to be used initially, `Weak` was in fact causing errors in the session +/// closing, because the primitive implementation seemed to be used in the closing operation.) +pub(crate) struct WeakSession(Arc); + +impl WeakSession { + fn new(session: &Arc) -> Self { + let mut weak = session.weak_counter.lock().unwrap(); + *weak += 1; + Self(session.clone()) + } } -impl<'a, O, T, G> UndeclarableSealed<&'a Session, O, T> for G -where - O: Resolve + Send, - G: UndeclarableSealed<(), O, T>, -{ - fn undeclare_inner(self, _: &'a Session) -> O { - self.undeclare_inner(()) +impl Clone for WeakSession { + fn clone(&self) -> Self { + let mut weak = self.0.weak_counter.lock().unwrap(); + *weak += 1; + Self(self.0.clone()) } } -// NOTE: `UndeclarableInner` is only pub(crate) to hide the `undeclare_inner` method. So we don't -// care about the `private_bounds` lint in this particular case. -#[allow(private_bounds)] -/// A trait implemented by types that can be undeclared. -pub trait Undeclarable: UndeclarableSealed -where - O: Resolve + Send, -{ +impl fmt::Debug for WeakSession { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } } -impl Undeclarable for U -where - O: Resolve + Send, - U: UndeclarableSealed, -{ +impl Deref for WeakSession { + type Target = Arc; + + fn deref(&self) -> &Self::Target { + &self.0 + } } -/// A zenoh session. -/// -pub struct Session { - pub(crate) runtime: Runtime, - pub(crate) state: Arc>, - pub(crate) id: u16, - close_on_drop: bool, - owns_runtime: bool, - task_controller: TaskController, +impl Drop for WeakSession { + fn drop(&mut self) { + let mut weak = self.0.weak_counter.lock().unwrap(); + *weak -= 1; + } } static SESSION_ID_COUNTER: AtomicU16 = AtomicU16::new(0); @@ -501,144 +518,103 @@ impl Session { runtime: Runtime, aggregated_subscribers: Vec, aggregated_publishers: Vec, + owns_runtime: bool, ) -> impl Resolve { ResolveClosure::new(move || { let router = runtime.router(); - let state = Arc::new(RwLock::new(SessionState::new( + let state = RwLock::new(SessionState::new( aggregated_subscribers, aggregated_publishers, - ))); - let session = Session { + )); + let session = Session(Arc::new(SessionInner { + weak_counter: Mutex::new(0), runtime: runtime.clone(), - state: state.clone(), + state, id: SESSION_ID_COUNTER.fetch_add(1, Ordering::SeqCst), - close_on_drop: true, - owns_runtime: false, + owns_runtime, task_controller: TaskController::default(), - }; + })); - runtime.new_handler(Arc::new(admin::Handler::new(session.clone()))); + runtime.new_handler(Arc::new(admin::Handler::new(session.downgrade()))); - let primitives = Some(router.new_primitives(Arc::new(session.clone()))); - zwrite!(state).primitives = primitives; + let primitives = Some(router.new_primitives(Arc::new(session.downgrade()))); + zwrite!(session.0.state).primitives = primitives; - admin::init(&session); + admin::init(session.downgrade()); session }) } - /// Consumes the given `Session`, returning a thread-safe reference-counting - /// pointer to it (`Arc`). This is equivalent to `Arc::new(session)`. - /// - /// This is useful to share ownership of the `Session` between several threads - /// and tasks. It also allows to create [`Subscriber`](crate::pubsub::Subscriber) and - /// [`Queryable`](crate::query::Queryable) with static lifetime that can be moved to several - /// threads and tasks - /// - /// Note: the given zenoh `Session` will be closed when the last reference to - /// it is dropped. - /// - /// # Examples - /// ```no_run - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let subscriber = session.declare_subscriber("key/expression") - /// .await - /// .unwrap(); - /// tokio::task::spawn(async move { - /// while let Ok(sample) = subscriber.recv_async().await { - /// println!("Received: {:?}", sample); - /// } - /// }).await; - /// # } - /// ``` - pub fn into_arc(self) -> Arc { - Arc::new(self) + /// Returns the identifier of the current session. `zid()` is a convenient shortcut. + /// See [`Session::info()`](`Session::info()`) and [`SessionInfo::zid()`](`SessionInfo::zid()`) for more details. + pub fn zid(&self) -> ZenohId { + self.info().zid().wait() + } + + pub fn hlc(&self) -> Option<&HLC> { + self.0.runtime.hlc() } - /// Consumes and leaks the given `Session`, returning a `'static` mutable - /// reference to it. The given `Session` will live for the remainder of - /// the program's life. Dropping the returned reference will cause a memory - /// leak. + /// Close the zenoh [`Session`](Session). + /// + /// Every subscriber and queryable declared will stop receiving data, and further attempt to + /// publish or query with the session or publishers will result in an error. Undeclaring an + /// entity after session closing is a no-op. Session state can be checked with + /// [`Session::is_closed`]. /// - /// This is useful to move entities (like [`Subscriber`](crate::pubsub::Subscriber)) which - /// lifetimes are bound to the session lifetime in several threads or tasks. + /// Session are automatically closed when all its instances are dropped, same as `Arc`. + /// You may still want to use this function to handle errors or close the session + /// asynchronously. + ///
+ /// Closing the session can also save bandwidth, as it avoids propagating the undeclaration + /// of the remaining entities. /// - /// Note: the given zenoh `Session` cannot be closed any more. At process - /// termination the zenoh session will terminate abruptly. If possible prefer - /// using [`Session::into_arc()`](Session::into_arc). /// /// # Examples /// ```no_run /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// - /// let session = zenoh::Session::leak(zenoh::open(zenoh::config::peer()).await.unwrap()); - /// let subscriber = session.declare_subscriber("key/expression").await.unwrap(); - /// tokio::task::spawn(async move { + /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); + /// let subscriber = session + /// .declare_subscriber("key/expression") + /// .await + /// .unwrap(); + /// let subscriber_task = tokio::spawn(async move { /// while let Ok(sample) = subscriber.recv_async().await { - /// println!("Received: {:?}", sample); + /// println!("Received: {} {:?}", sample.key_expr(), sample.payload()); /// } - /// }).await; + /// }); + /// session.close().await.unwrap(); + /// // subscriber task will end as `subscriber.recv_async()` will return `Err` + /// // subscriber undeclaration has not been sent on the wire + /// subscriber_task.await.unwrap(); /// # } /// ``` - pub fn leak(s: Self) -> &'static mut Self { - Box::leak(Box::new(s)) - } - - /// Returns the identifier of the current session. `zid()` is a convenient shortcut. - /// See [`Session::info()`](`Session::info()`) and [`SessionInfo::zid()`](`SessionInfo::zid()`) for more details. - pub fn zid(&self) -> ZenohId { - self.info().zid().wait() + pub fn close(&self) -> impl Resolve> + '_ { + self.0.close() } - pub fn hlc(&self) -> Option<&HLC> { - self.runtime.hlc() - } - - /// Close the zenoh [`Session`](Session). - /// - /// Sessions are automatically closed when dropped, but you may want to use this function to handle errors or - /// close the Session asynchronously. + /// Check if the session has been closed. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); + /// assert!(!session.is_closed()); /// session.close().await.unwrap(); + /// assert!(session.is_closed()); /// # } - /// ``` - pub fn close(mut self) -> impl Resolve> { - ResolveFuture::new(async move { - trace!("close()"); - // set the flag first to avoid double panic if this function panic - self.close_on_drop = false; - self.task_controller.terminate_all(Duration::from_secs(10)); - if self.owns_runtime { - self.runtime.close().await?; - } - let mut state = zwrite!(self.state); - // clean up to break cyclic references from self.state to itself - let primitives = state.primitives.take(); - state.queryables.clear(); - drop(state); - primitives.as_ref().unwrap().send_close(); - Ok(()) - }) + pub fn is_closed(&self) -> bool { + zread!(self.0.state).primitives.is_none() } - pub fn undeclare<'a, T, O>(&'a self, decl: T) -> O + pub fn undeclare<'a, T>(&'a self, decl: T) -> impl Resolve> + 'a where - O: Resolve>, - T: Undeclarable<&'a Self, O, ZResult<()>>, + T: Undeclarable<&'a Session> + 'a, { UndeclarableSealed::undeclare_inner(decl, self) } @@ -655,7 +631,6 @@ impl Session { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let peers = session.config().get("connect/endpoints").unwrap(); @@ -666,14 +641,13 @@ impl Session { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let _ = session.config().insert_json5("connect/endpoints", r#"["tcp/127.0.0.1/7447"]"#); /// # } /// ``` pub fn config(&self) -> &Notifier { - self.runtime.config() + self.0.runtime.config() } /// Get a new Timestamp from a Zenoh session [`Session`](Session). @@ -685,7 +659,6 @@ impl Session { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let timestamp = session.new_timestamp(); @@ -698,49 +671,176 @@ impl Session { // Called in the case that the runtime is not initialized with an hlc // UNIX_EPOCH is Returns a Timespec::zero(), Unwrap Should be permissable here let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().into(); - Timestamp::new(now, self.runtime.zid().into()) + Timestamp::new(now, self.0.runtime.zid().into()) } } } + + /// Wrap the session into an `Arc`. + #[deprecated(since = "1.0.0", note = "use `Session` directly instead")] + pub fn into_arc(self) -> Arc { + Arc::new(self) + } } -impl<'a> SessionDeclarations<'a, 'a> for Session { - fn info(&self) -> SessionInfo { - SessionRef::Borrow(self).info() +impl Session { + /// Get information about the zenoh [`Session`](Session). + /// + /// # Examples + /// ``` + /// # #[tokio::main] + /// # async fn main() { + /// + /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); + /// let info = session.info(); + /// # } + /// ``` + pub fn info(&self) -> SessionInfo { + SessionInfo { + runtime: self.0.runtime.clone(), + } } - fn declare_subscriber<'b, TryIntoKeyExpr>( - &'a self, + + /// Create a [`Subscriber`](crate::pubsub::Subscriber) for the given key expression. + /// + /// # Arguments + /// + /// * `key_expr` - The resourkey expression to subscribe to + /// + /// # Examples + /// ```no_run + /// # #[tokio::main] + /// # async fn main() { + /// + /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); + /// let subscriber = session.declare_subscriber("key/expression") + /// .await + /// .unwrap(); + /// tokio::task::spawn(async move { + /// while let Ok(sample) = subscriber.recv_async().await { + /// println!("Received: {:?}", sample); + /// } + /// }).await; + /// # } + /// ``` + pub fn declare_subscriber<'b, TryIntoKeyExpr>( + &self, key_expr: TryIntoKeyExpr, - ) -> SubscriberBuilder<'a, 'b, DefaultHandler> + ) -> SubscriberBuilder<'_, 'b, DefaultHandler> where TryIntoKeyExpr: TryInto>, >>::Error: Into, { - SessionRef::Borrow(self).declare_subscriber(key_expr) + SubscriberBuilder { + session: self, + key_expr: TryIntoKeyExpr::try_into(key_expr).map_err(Into::into), + origin: Locality::default(), + handler: DefaultHandler::default(), + undeclare_on_drop: true, + } } - fn declare_queryable<'b, TryIntoKeyExpr>( - &'a self, + + /// Create a [`Queryable`](crate::query::Queryable) for the given key expression. + /// + /// # Arguments + /// + /// * `key_expr` - The key expression matching the queries the + /// [`Queryable`](crate::query::Queryable) will reply to + /// + /// # Examples + /// ```no_run + /// # #[tokio::main] + /// # async fn main() { + /// + /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); + /// let queryable = session.declare_queryable("key/expression") + /// .await + /// .unwrap(); + /// tokio::task::spawn(async move { + /// while let Ok(query) = queryable.recv_async().await { + /// query.reply( + /// "key/expression", + /// "value", + /// ).await.unwrap(); + /// } + /// }).await; + /// # } + /// ``` + pub fn declare_queryable<'b, TryIntoKeyExpr>( + &self, key_expr: TryIntoKeyExpr, - ) -> QueryableBuilder<'a, 'b, DefaultHandler> + ) -> QueryableBuilder<'_, 'b, DefaultHandler> where TryIntoKeyExpr: TryInto>, >>::Error: Into, { - SessionRef::Borrow(self).declare_queryable(key_expr) + QueryableBuilder { + session: self, + key_expr: key_expr.try_into().map_err(Into::into), + complete: false, + origin: Locality::default(), + handler: DefaultHandler::default(), + undeclare_on_drop: true, + } } - fn declare_publisher<'b, TryIntoKeyExpr>( - &'a self, + + /// Create a [`Publisher`](crate::pubsub::Publisher) for the given key expression. + /// + /// # Arguments + /// + /// * `key_expr` - The key expression matching resources to write + /// + /// # Examples + /// ``` + /// # #[tokio::main] + /// # async fn main() { + /// + /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); + /// let publisher = session.declare_publisher("key/expression") + /// .await + /// .unwrap(); + /// publisher.put("value").await.unwrap(); + /// # } + /// ``` + pub fn declare_publisher<'b, TryIntoKeyExpr>( + &self, key_expr: TryIntoKeyExpr, - ) -> PublisherBuilder<'a, 'b> + ) -> PublisherBuilder<'_, 'b> where TryIntoKeyExpr: TryInto>, >>::Error: Into, { - SessionRef::Borrow(self).declare_publisher(key_expr) + PublisherBuilder { + session: self, + key_expr: key_expr.try_into().map_err(Into::into), + encoding: Encoding::default(), + congestion_control: CongestionControl::DEFAULT, + priority: Priority::DEFAULT, + is_express: false, + #[cfg(feature = "unstable")] + reliability: Reliability::DEFAULT, + destination: Locality::default(), + } } + + /// Obtain a [`Liveliness`] struct tied to this Zenoh [`Session`]. + /// + /// # Examples + /// ``` + /// # #[tokio::main] + /// # async fn main() { + /// + /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); + /// let liveliness = session + /// .liveliness() + /// .declare_token("key/expression") + /// .await + /// .unwrap(); + /// # } + /// ``` #[zenoh_macros::unstable] - fn liveliness(&'a self) -> Liveliness { - SessionRef::Borrow(self).liveliness() + pub fn liveliness(&self) -> Liveliness<'_> { + Liveliness { session: self } } } @@ -754,7 +854,6 @@ impl Session { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let key_expr = session.declare_keyexpr("key/expression").await.unwrap(); @@ -769,18 +868,11 @@ impl Session { >>::Error: Into, { let key_expr: ZResult = key_expr.try_into().map_err(Into::into); - self._declare_keyexpr(key_expr) - } - - fn _declare_keyexpr<'a, 'b: 'a>( - &'a self, - key_expr: ZResult>, - ) -> impl Resolve>> + 'a { - let sid = self.id; + let sid = self.0.id; ResolveClosure::new(move || { let key_expr: KeyExpr = key_expr?; let prefix_len = key_expr.len() as u32; - let expr_id = self.declare_prefix(key_expr.as_str()).wait(); + let expr_id = self.0.declare_prefix(key_expr.as_str()).wait()?; let key_expr = match key_expr.0 { KeyExprInner::Borrowed(key_expr) | KeyExprInner::BorrowedWire { key_expr, .. } => { KeyExpr(KeyExprInner::BorrowedWire { @@ -816,7 +908,7 @@ impl Session { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::{bytes::Encoding, prelude::*}; + /// use zenoh::bytes::Encoding; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// session @@ -860,7 +952,6 @@ impl Session { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// session.delete("key/expression").await.unwrap(); @@ -897,7 +988,6 @@ impl Session { /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let replies = session.get("key/expression").await.unwrap(); @@ -916,7 +1006,7 @@ impl Session { { let selector = selector.try_into().map_err(Into::into); let timeout = { - let conf = self.runtime.config().lock(); + let conf = self.0.runtime.config().lock(); Duration::from_millis(unwrap_or_default!(conf.queries_default_timeout())) }; let qos: QoS = request::ext::QoSType::REQUEST.into(); @@ -938,17 +1028,6 @@ impl Session { } impl Session { - pub(crate) fn clone(&self) -> Self { - Self { - runtime: self.runtime.clone(), - state: self.state.clone(), - id: self.id, - close_on_drop: false, - owns_runtime: self.owns_runtime, - task_controller: self.task_controller.clone(), - } - } - #[allow(clippy::new_ret_no_self)] pub(super) fn new( config: Config, @@ -966,28 +1045,52 @@ impl Session { } let mut runtime = runtime.build().await?; - let mut session = Self::init( + let session = Self::init( runtime.clone(), aggregated_subscribers, aggregated_publishers, + true, ) .await; - session.owns_runtime = true; runtime.start().await?; Ok(session) }) } +} +impl SessionInner { + fn close(&self) -> impl Resolve> + '_ { + ResolveFuture::new(async move { + let Some(primitives) = zwrite!(self.state).primitives.take() else { + return Ok(()); + }; + if self.owns_runtime { + info!(zid = %self.runtime.zid(), "close session"); + } + self.task_controller.terminate_all(Duration::from_secs(10)); + if self.owns_runtime { + self.runtime.close().await?; + } else { + primitives.send_close(); + } + zwrite!(self.state).queryables.clear(); + Ok(()) + }) + } - pub(crate) fn declare_prefix<'a>(&'a self, prefix: &'a str) -> impl Resolve + 'a { + pub(crate) fn declare_prefix<'a>( + &'a self, + prefix: &'a str, + ) -> impl Resolve> + 'a { ResolveClosure::new(move || { trace!("declare_prefix({:?})", prefix); let mut state = zwrite!(self.state); + let primitives = state.primitives()?; match state .local_resources .iter() .find(|(_expr_id, res)| res.name() == prefix) { - Some((expr_id, _res)) => *expr_id, + Some((expr_id, _res)) => Ok(*expr_id), None => { let expr_id = state.expr_id_counter.fetch_add(1, Ordering::SeqCst); let mut res = Resource::new(Box::from(prefix)); @@ -1004,7 +1107,6 @@ impl Session { } } state.local_resources.insert(expr_id, res); - let primitives = state.primitives.as_ref().unwrap().clone(); drop(state); primitives.send_declare(Declare { interest_id: None, @@ -1020,7 +1122,7 @@ impl Session { }, }), }); - expr_id + Ok(expr_id) } } }) @@ -1077,7 +1179,7 @@ impl Session { state.publishers.insert(id, pub_state); if let Some(res) = declared_pub { - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); primitives.send_interest(Interest { id, @@ -1102,7 +1204,7 @@ impl Session { if !state.publishers.values().any(|p| { p.destination != Locality::SessionLocal && p.remote_id == pub_state.remote_id }) { - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); primitives.send_interest(Interest { id: pub_state.remote_id, @@ -1122,7 +1224,7 @@ impl Session { } pub(crate) fn declare_subscriber_inner( - &self, + self: &Arc, key_expr: &KeyExpr, origin: Locality, callback: Callback<'static, Sample>, @@ -1205,7 +1307,7 @@ impl Session { } if let Some(key_expr) = declared_sub { - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); // If key_expr is a pure Expr, remap it to optimal Rid or RidWithSuffix // let key_expr = if !key_expr.is_optimized(self) { @@ -1251,7 +1353,11 @@ impl Session { Ok(sub_state) } - pub(crate) fn undeclare_subscriber_inner(&self, sid: Id, kind: SubscriberKind) -> ZResult<()> { + pub(crate) fn undeclare_subscriber_inner( + self: &Arc, + sid: Id, + kind: SubscriberKind, + ) -> ZResult<()> { let mut state = zwrite!(self.state); if let Some(sub_state) = state.subscribers_mut(kind).remove(&sid) { trace!("undeclare_subscriber({:?})", sub_state); @@ -1278,7 +1384,7 @@ impl Session { if !state.subscribers(kind).values().any(|s| { s.origin != Locality::SessionLocal && s.remote_id == sub_state.remote_id }) { - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); primitives.send_declare(Declare { interest_id: None, @@ -1301,7 +1407,7 @@ impl Session { } else { #[cfg(feature = "unstable")] if kind == SubscriberKind::LivelinessSubscriber { - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); primitives.send_interest(Interest { @@ -1343,7 +1449,7 @@ impl Session { state.queryables.insert(id, qable_state.clone()); if origin != Locality::SessionLocal { - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); let qabl_info = QueryableInfoType { complete, @@ -1369,7 +1475,7 @@ impl Session { if let Some(qable_state) = state.queryables.remove(&qid) { trace!("undeclare_queryable({:?})", qable_state); if qable_state.origin != Locality::SessionLocal { - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); primitives.send_declare(Declare { interest_id: None, @@ -1404,7 +1510,7 @@ impl Session { }); state.tokens.insert(tok_state.id, tok_state.clone()); - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); primitives.send_declare(Declare { interest_id: None, @@ -1467,7 +1573,7 @@ impl Session { } } - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); primitives.send_interest(Interest { @@ -1496,7 +1602,7 @@ impl Session { let key_expr = &tok_state.key_expr; let twin_tok = state.tokens.values().any(|s| s.key_expr == *key_expr); if !twin_tok { - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); primitives.send_declare(Declare { interest_id: None, @@ -1587,14 +1693,14 @@ impl Session { } #[zenoh_macros::unstable] - pub(crate) fn update_status_up(&self, state: &SessionState, key_expr: &KeyExpr) { + pub(crate) fn update_status_up(self: &Arc, state: &SessionState, key_expr: &KeyExpr) { for msub in state.matching_listeners.values() { if key_expr.intersects(&msub.key_expr) { // Cannot hold session lock when calling tables (matching_status()) // TODO: check which ZRuntime should be used self.task_controller .spawn_with_rt(zenoh_runtime::ZRuntime::Net, { - let session = self.clone(); + let session = WeakSession::new(self); let msub = msub.clone(); async move { match msub.current.lock() { @@ -1625,14 +1731,14 @@ impl Session { } #[zenoh_macros::unstable] - pub(crate) fn update_status_down(&self, state: &SessionState, key_expr: &KeyExpr) { + pub(crate) fn update_status_down(self: &Arc, state: &SessionState, key_expr: &KeyExpr) { for msub in state.matching_listeners.values() { if key_expr.intersects(&msub.key_expr) { // Cannot hold session lock when calling tables (matching_status()) // TODO: check which ZRuntime should be used self.task_controller .spawn_with_rt(zenoh_runtime::ZRuntime::Net, { - let session = self.clone(); + let session = WeakSession::new(self); let msub = msub.clone(); async move { match msub.current.lock() { @@ -1753,7 +1859,7 @@ impl Session { #[allow(clippy::too_many_arguments)] pub(crate) fn query( - &self, + self: &Arc, key_expr: &KeyExpr<'_>, parameters: &Parameters<'_>, target: QueryTarget, @@ -1788,13 +1894,13 @@ impl Session { let token = self.task_controller.get_cancellation_token(); self.task_controller .spawn_with_rt(zenoh_runtime::ZRuntime::Net, { - let state = self.state.clone(); + let session = WeakSession::new(self); #[cfg(feature = "unstable")] let zid = self.runtime.zid(); async move { tokio::select! { _ = tokio::time::sleep(timeout) => { - let mut state = zwrite!(state); + let mut state = zwrite!(session.state); if let Some(query) = state.queries.remove(&qid) { std::mem::drop(state); tracing::debug!("Timeout on query {}! Send error and close.", qid); @@ -1829,7 +1935,7 @@ impl Session { }, ); - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); if destination != Locality::SessionLocal { @@ -1883,7 +1989,7 @@ impl Session { #[cfg(feature = "unstable")] pub(crate) fn liveliness_query( - &self, + self: &Arc, key_expr: &KeyExpr<'_>, timeout: Duration, callback: Callback<'static, Reply>, @@ -1894,12 +2000,12 @@ impl Session { let token = self.task_controller.get_cancellation_token(); self.task_controller .spawn_with_rt(zenoh_runtime::ZRuntime::Net, { - let state = self.state.clone(); + let session = WeakSession::new(self); let zid = self.runtime.zid(); async move { tokio::select! { _ = tokio::time::sleep(timeout) => { - let mut state = zwrite!(state); + let mut state = zwrite!(session.state); if let Some(query) = state.liveliness_queries.remove(&id) { std::mem::drop(state); tracing::debug!("Timeout on liveliness query {}! Send error and close.", id); @@ -1921,7 +2027,7 @@ impl Session { .liveliness_queries .insert(id, LivelinessQueryState { callback }); - let primitives = state.primitives.as_ref().unwrap().clone(); + let primitives = state.primitives()?; drop(state); primitives.send_interest(Interest { @@ -1939,7 +2045,7 @@ impl Session { #[allow(clippy::too_many_arguments)] pub(crate) fn handle_query( - &self, + self: &Arc, local: bool, key_expr: &WireExpr, parameters: &str, @@ -1951,6 +2057,9 @@ impl Session { ) { let (primitives, key_expr, queryables) = { let state = zread!(self.state); + let Ok(primitives) = state.primitives() else { + return; + }; match state.wireexpr_to_keyexpr(key_expr, local) { Ok(key_expr) => { let queryables = state @@ -1976,11 +2085,7 @@ impl Session { ) .map(|(id, qable)| (*id, qable.callback.clone())) .collect::)>>(); - ( - state.primitives.as_ref().unwrap().clone(), - key_expr.into_owned(), - queryables, - ) + (primitives, key_expr.into_owned(), queryables) } Err(err) => { error!("Received Query for unknown key_expr: {}", err); @@ -1997,7 +2102,7 @@ impl Session { qid, zid: zid.into(), primitives: if local { - Arc::new(self.clone()) + Arc::new(WeakSession::new(self)) } else { primitives }, @@ -2016,161 +2121,7 @@ impl Session { } } -impl<'s> SessionDeclarations<'s, 'static> for Arc { - /// Create a [`Subscriber`](crate::pubsub::Subscriber) for the given key expression. - /// - /// # Arguments - /// - /// * `key_expr` - The resourkey expression to subscribe to - /// - /// # Examples - /// ```no_run - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let subscriber = session.declare_subscriber("key/expression") - /// .await - /// .unwrap(); - /// tokio::task::spawn(async move { - /// while let Ok(sample) = subscriber.recv_async().await { - /// println!("Received: {:?}", sample); - /// } - /// }).await; - /// # } - /// ``` - fn declare_subscriber<'b, TryIntoKeyExpr>( - &'s self, - key_expr: TryIntoKeyExpr, - ) -> SubscriberBuilder<'static, 'b, DefaultHandler> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into, - { - SubscriberBuilder { - session: SessionRef::Shared(self.clone()), - key_expr: key_expr.try_into().map_err(Into::into), - origin: Locality::default(), - handler: DefaultHandler::default(), - } - } - - /// Create a [`Queryable`](crate::query::Queryable) for the given key expression. - /// - /// # Arguments - /// - /// * `key_expr` - The key expression matching the queries the - /// [`Queryable`](crate::query::Queryable) will reply to - /// - /// # Examples - /// ```no_run - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let queryable = session.declare_queryable("key/expression") - /// .await - /// .unwrap(); - /// tokio::task::spawn(async move { - /// while let Ok(query) = queryable.recv_async().await { - /// query.reply( - /// "key/expression", - /// "value", - /// ).await.unwrap(); - /// } - /// }).await; - /// # } - /// ``` - fn declare_queryable<'b, TryIntoKeyExpr>( - &'s self, - key_expr: TryIntoKeyExpr, - ) -> QueryableBuilder<'static, 'b, DefaultHandler> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into, - { - QueryableBuilder { - session: SessionRef::Shared(self.clone()), - key_expr: key_expr.try_into().map_err(Into::into), - complete: false, - origin: Locality::default(), - handler: DefaultHandler::default(), - } - } - - /// Create a [`Publisher`](crate::pubsub::Publisher) for the given key expression. - /// - /// # Arguments - /// - /// * `key_expr` - The key expression matching resources to write - /// - /// # Examples - /// ``` - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let publisher = session.declare_publisher("key/expression") - /// .await - /// .unwrap(); - /// publisher.put("value").await.unwrap(); - /// # } - /// ``` - fn declare_publisher<'b, TryIntoKeyExpr>( - &'s self, - key_expr: TryIntoKeyExpr, - ) -> PublisherBuilder<'static, 'b> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into, - { - PublisherBuilder { - session: SessionRef::Shared(self.clone()), - key_expr: key_expr.try_into().map_err(Into::into), - encoding: Encoding::default(), - congestion_control: CongestionControl::DEFAULT, - priority: Priority::DEFAULT, - is_express: false, - #[cfg(feature = "unstable")] - reliability: Reliability::DEFAULT, - destination: Locality::default(), - } - } - - /// Obtain a [`Liveliness`] struct tied to this Zenoh [`Session`]. - /// - /// # Examples - /// ``` - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let liveliness = session - /// .liveliness() - /// .declare_token("key/expression") - /// .await - /// .unwrap(); - /// # } - /// ``` - #[zenoh_macros::unstable] - fn liveliness(&'s self) -> Liveliness<'static> { - Liveliness { - session: SessionRef::Shared(self.clone()), - } - } - - fn info(&'s self) -> SessionInfo<'static> { - SessionInfo { - session: SessionRef::Shared(self.clone()), - } - } -} - -impl Primitives for Session { +impl Primitives for WeakSession { fn send_interest(&self, msg: zenoh_protocol::network::Interest) { trace!("recv Interest {} {:?}", msg.id, msg.wire_expr); } @@ -2663,174 +2614,7 @@ impl Primitives for Session { } } -impl Drop for Session { - fn drop(&mut self) { - if self.close_on_drop { - let _ = self.clone().close().wait(); - } - } -} - -impl fmt::Debug for Session { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Session").field("id", &self.zid()).finish() - } -} - -/// Functions to create zenoh entities -/// -/// This trait contains functions to create zenoh entities like -/// [`Subscriber`](crate::pubsub::Subscriber), and -/// [`Queryable`](crate::query::Queryable) -/// -/// This trait is implemented by [`Session`](crate::session::Session) itself and -/// by wrappers [`SessionRef`](crate::session::SessionRef) and [`Arc`](std::sync::Arc) -/// -/// # Examples -/// ```no_run -/// # #[tokio::main] -/// # async fn main() { -/// use zenoh::prelude::*; -/// -/// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); -/// let subscriber = session.declare_subscriber("key/expression") -/// .await -/// .unwrap(); -/// tokio::task::spawn(async move { -/// while let Ok(sample) = subscriber.recv_async().await { -/// println!("Received: {:?}", sample); -/// } -/// }).await; -/// # } -/// ``` -pub trait SessionDeclarations<'s, 'a> { - /// Create a [`Subscriber`](crate::pubsub::Subscriber) for the given key expression. - /// - /// # Arguments - /// - /// * `key_expr` - The resourkey expression to subscribe to - /// - /// # Examples - /// ```no_run - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let subscriber = session.declare_subscriber("key/expression") - /// .await - /// .unwrap(); - /// tokio::task::spawn(async move { - /// while let Ok(sample) = subscriber.recv_async().await { - /// println!("Received: {:?}", sample); - /// } - /// }).await; - /// # } - /// ``` - fn declare_subscriber<'b, TryIntoKeyExpr>( - &'s self, - key_expr: TryIntoKeyExpr, - ) -> SubscriberBuilder<'a, 'b, DefaultHandler> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into; - - /// Create a [`Queryable`](crate::query::Queryable) for the given key expression. - /// - /// # Arguments - /// - /// * `key_expr` - The key expression matching the queries the - /// [`Queryable`](crate::query::Queryable) will reply to - /// - /// # Examples - /// ```no_run - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let queryable = session.declare_queryable("key/expression") - /// .await - /// .unwrap(); - /// tokio::task::spawn(async move { - /// while let Ok(query) = queryable.recv_async().await { - /// query.reply( - /// "key/expression", - /// "value", - /// ).await.unwrap(); - /// } - /// }).await; - /// # } - /// ``` - fn declare_queryable<'b, TryIntoKeyExpr>( - &'s self, - key_expr: TryIntoKeyExpr, - ) -> QueryableBuilder<'a, 'b, DefaultHandler> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into; - - /// Create a [`Publisher`](crate::pubsub::Publisher) for the given key expression. - /// - /// # Arguments - /// - /// * `key_expr` - The key expression matching resources to write - /// - /// # Examples - /// ``` - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let publisher = session.declare_publisher("key/expression") - /// .await - /// .unwrap(); - /// publisher.put("value").await.unwrap(); - /// # } - /// ``` - fn declare_publisher<'b, TryIntoKeyExpr>( - &'s self, - key_expr: TryIntoKeyExpr, - ) -> PublisherBuilder<'a, 'b> - where - TryIntoKeyExpr: TryInto>, - >>::Error: Into; - - /// Obtain a [`Liveliness`] struct tied to this Zenoh [`Session`]. - /// - /// # Examples - /// ``` - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap().into_arc(); - /// let liveliness = session - /// .liveliness() - /// .declare_token("key/expression") - /// .await - /// .unwrap(); - /// # } - /// ``` - #[zenoh_macros::unstable] - fn liveliness(&'s self) -> Liveliness<'a>; - /// Get information about the zenoh [`Session`](Session). - /// - /// # Examples - /// ``` - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::prelude::*; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); - /// let info = session.info(); - /// # } - /// ``` - fn info(&'s self) -> SessionInfo<'a>; -} - -impl crate::net::primitives::EPrimitives for Session { +impl crate::net::primitives::EPrimitives for WeakSession { #[inline] fn send_interest(&self, ctx: crate::net::routing::RoutingContext) { (self as &dyn Primitives).send_interest(ctx.msg) @@ -2876,7 +2660,6 @@ impl crate::net::primitives::EPrimitives for Session { /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// # } @@ -2886,7 +2669,7 @@ impl crate::net::primitives::EPrimitives for Session { /// # #[tokio::main] /// # async fn main() { /// use std::str::FromStr; -/// use zenoh::{session::ZenohId, prelude::*}; +/// use zenoh::session::ZenohId; /// /// let mut config = zenoh::config::peer(); /// config.set_id(ZenohId::from_str("221b72df20924c15b8794c6bdb471150").unwrap()); @@ -2914,7 +2697,6 @@ where /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// # } @@ -3030,6 +2812,7 @@ impl Wait for InitBuilder { self.runtime, self.aggregated_subscribers, self.aggregated_publishers, + false, ) .wait()) } diff --git a/zenoh/src/api/subscriber.rs b/zenoh/src/api/subscriber.rs index 74f7605d8b..ac5202ed85 100644 --- a/zenoh/src/api/subscriber.rs +++ b/zenoh/src/api/subscriber.rs @@ -18,20 +18,27 @@ use std::{ sync::Arc, }; +use tracing::error; use zenoh_core::{Resolvable, Wait}; use zenoh_result::ZResult; #[cfg(feature = "unstable")] -use {zenoh_config::wrappers::EntityGlobalId, zenoh_protocol::core::EntityGlobalIdProto}; - -use super::{ - handlers::{locked, Callback, DefaultHandler, IntoHandler}, - key_expr::KeyExpr, - sample::{Locality, Sample}, - session::{SessionRef, UndeclarableSealed}, - Id, +use { + zenoh_config::wrappers::{EntityGlobalId, ZenohId}, + zenoh_protocol::core::EntityGlobalIdProto, }; + #[cfg(feature = "unstable")] use crate::pubsub::Reliability; +use crate::{ + api::{ + handlers::{locked, Callback, DefaultHandler, IntoHandler}, + key_expr::KeyExpr, + sample::{Locality, Sample}, + session::{UndeclarableSealed, WeakSession}, + Id, + }, + Session, +}; pub(crate) struct SubscriberState { pub(crate) id: Id, @@ -50,78 +57,23 @@ impl fmt::Debug for SubscriberState { } } -/// A subscriber that provides data through a callback. -/// -/// CallbackSubscribers can be created from a zenoh [`Session`](crate::Session) -/// with the [`declare_subscriber`](crate::SessionDeclarations::declare_subscriber) function -/// and the [`callback`](SubscriberBuilder::callback) function -/// of the resulting builder. -/// -/// Subscribers are automatically undeclared when dropped. -/// -/// # Examples -/// ``` -/// # #[tokio::main] -/// # async fn main() { -/// use zenoh::prelude::*; -/// -/// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); -/// let subscriber = session -/// .declare_subscriber("key/expression") -/// .callback(|sample| { println!("Received: {} {:?}", sample.key_expr(), sample.payload()) }) -/// .await -/// .unwrap(); -/// # } -/// ``` #[derive(Debug)] -pub(crate) struct SubscriberInner<'a> { - pub(crate) session: SessionRef<'a>, +pub(crate) struct SubscriberInner { + #[cfg(feature = "unstable")] + pub(crate) session_id: ZenohId, + pub(crate) session: WeakSession, pub(crate) state: Arc, pub(crate) kind: SubscriberKind, + // Subscriber is undeclared on drop unless its handler is a ZST, i.e. it is callback-only pub(crate) undeclare_on_drop: bool, } -impl<'a> SubscriberInner<'a> { - /// Close a [`CallbackSubscriber`](CallbackSubscriber). - /// - /// `CallbackSubscribers` are automatically closed when dropped, but you may want to use this function to handle errors or - /// close the `CallbackSubscriber` asynchronously. - /// - /// # Examples - /// ``` - /// # #[tokio::main] - /// # async fn main() { - /// use zenoh::{prelude::*, sample::Sample}; - /// - /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); - /// # fn data_handler(_sample: Sample) { }; - /// let subscriber = session - /// .declare_subscriber("key/expression") - /// .callback(data_handler) - /// .await - /// .unwrap(); - /// subscriber.undeclare().await.unwrap(); - /// # } - /// ``` - #[inline] - pub fn undeclare(self) -> SubscriberUndeclaration<'a> { - UndeclarableSealed::undeclare_inner(self, ()) - } -} - -impl<'a> UndeclarableSealed<(), SubscriberUndeclaration<'a>> for SubscriberInner<'a> { - fn undeclare_inner(self, _: ()) -> SubscriberUndeclaration<'a> { - SubscriberUndeclaration { subscriber: self } - } -} - /// A [`Resolvable`] returned when undeclaring a subscriber. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let subscriber = session @@ -132,25 +84,19 @@ impl<'a> UndeclarableSealed<(), SubscriberUndeclaration<'a>> for SubscriberInner /// # } /// ``` #[must_use = "Resolvables do nothing unless you resolve them using the `res` method from either `SyncResolve` or `AsyncResolve`"] -pub struct SubscriberUndeclaration<'a> { - subscriber: SubscriberInner<'a>, -} +pub struct SubscriberUndeclaration(Subscriber); -impl Resolvable for SubscriberUndeclaration<'_> { +impl Resolvable for SubscriberUndeclaration { type To = ZResult<()>; } -impl Wait for SubscriberUndeclaration<'_> { +impl Wait for SubscriberUndeclaration { fn wait(mut self) -> ::To { - // set the flag first to avoid double panic if this function panic - self.subscriber.undeclare_on_drop = false; - self.subscriber - .session - .undeclare_subscriber_inner(self.subscriber.state.id, self.subscriber.kind) + self.0.undeclare_impl() } } -impl IntoFuture for SubscriberUndeclaration<'_> { +impl IntoFuture for SubscriberUndeclaration { type Output = ::To; type IntoFuture = Ready<::To>; @@ -159,23 +105,12 @@ impl IntoFuture for SubscriberUndeclaration<'_> { } } -impl Drop for SubscriberInner<'_> { - fn drop(&mut self) { - if self.undeclare_on_drop { - let _ = self - .session - .undeclare_subscriber_inner(self.state.id, self.kind); - } - } -} - /// A builder for initializing a [`FlumeSubscriber`]. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let subscriber = session @@ -189,9 +124,9 @@ impl Drop for SubscriberInner<'_> { #[derive(Debug)] pub struct SubscriberBuilder<'a, 'b, Handler> { #[cfg(feature = "unstable")] - pub session: SessionRef<'a>, + pub session: &'a Session, #[cfg(not(feature = "unstable"))] - pub(crate) session: SessionRef<'a>, + pub(crate) session: &'a Session, #[cfg(feature = "unstable")] pub key_expr: ZResult>, @@ -207,16 +142,26 @@ pub struct SubscriberBuilder<'a, 'b, Handler> { pub handler: Handler, #[cfg(not(feature = "unstable"))] pub(crate) handler: Handler, + + #[cfg(feature = "unstable")] + pub undeclare_on_drop: bool, + #[cfg(not(feature = "unstable"))] + pub(crate) undeclare_on_drop: bool, } impl<'a, 'b> SubscriberBuilder<'a, 'b, DefaultHandler> { /// Receive the samples for this subscription with a callback. /// + /// Subscriber will not be undeclared when dropped, with the callback running + /// in background until the session is closed. + /// + /// It is in fact just a convenient shortcut for + /// `.with(my_callback).undeclare_on_drop(false)`. + /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let subscriber = session @@ -231,30 +176,21 @@ impl<'a, 'b> SubscriberBuilder<'a, 'b, DefaultHandler> { where Callback: Fn(Sample) + Send + Sync + 'static, { - let SubscriberBuilder { - session, - key_expr, - origin, - handler: _, - } = self; - SubscriberBuilder { - session, - key_expr, - origin, - handler: callback, - } + self.with(callback).undeclare_on_drop(false) } /// Receive the samples for this subscription with a mutable callback. /// /// Using this guarantees that your callback will never be called concurrently. - /// If your callback is also accepted by the [`callback`](SubscriberBuilder::callback) method, we suggest you use it instead of `callback_mut` + /// If your callback is also accepted by the [`callback`](SubscriberBuilder::callback) method, we suggest you use it instead of `callback_mut`. + /// + /// Subscriber will not be undeclared when dropped, with the callback running + /// in background until the session is closed. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let mut n = 0; @@ -282,7 +218,6 @@ impl<'a, 'b> SubscriberBuilder<'a, 'b, DefaultHandler> { /// ```no_run /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let subscriber = session @@ -305,17 +240,19 @@ impl<'a, 'b> SubscriberBuilder<'a, 'b, DefaultHandler> { key_expr, origin, handler: _, + undeclare_on_drop, } = self; SubscriberBuilder { session, key_expr, origin, handler, + undeclare_on_drop, } } } -impl<'a, 'b, Handler> SubscriberBuilder<'a, 'b, Handler> { +impl SubscriberBuilder<'_, '_, Handler> { /// Change the subscription reliability. #[cfg(feature = "unstable")] #[deprecated( @@ -327,7 +264,7 @@ impl<'a, 'b, Handler> SubscriberBuilder<'a, 'b, Handler> { self } - /// Change the subscription reliability to `Reliable`. + /// Change the subscription reliability to `Reliable`. #[cfg(feature = "unstable")] #[deprecated( since = "1.0.0", @@ -357,18 +294,30 @@ impl<'a, 'b, Handler> SubscriberBuilder<'a, 'b, Handler> { self.origin = origin; self } + + /// Set whether the subscriber will be undeclared when dropped. + /// + /// The method is usually used in combination with a callback like in + /// [`callback`](Self::callback) method, or a channel sender. + /// Be careful when using it, as subscribers not undeclared will consume + /// resources until the session is closed. + #[inline] + pub fn undeclare_on_drop(mut self, undeclare_on_drop: bool) -> Self { + self.undeclare_on_drop = undeclare_on_drop; + self + } } // Push mode -impl<'a, Handler> Resolvable for SubscriberBuilder<'a, '_, Handler> +impl Resolvable for SubscriberBuilder<'_, '_, Handler> where Handler: IntoHandler<'static, Sample> + Send, Handler::Handler: Send, { - type To = ZResult>; + type To = ZResult>; } -impl<'a, Handler> Wait for SubscriberBuilder<'a, '_, Handler> +impl Wait for SubscriberBuilder<'_, '_, Handler> where Handler: IntoHandler<'static, Sample> + Send, Handler::Handler: Send, @@ -378,20 +327,23 @@ where let session = self.session; let (callback, receiver) = self.handler.into_handler(); session + .0 .declare_subscriber_inner(&key_expr, self.origin, callback) .map(|sub_state| Subscriber { - subscriber: SubscriberInner { - session, + inner: SubscriberInner { + #[cfg(feature = "unstable")] + session_id: session.zid(), + session: session.downgrade(), state: sub_state, kind: SubscriberKind::Subscriber, - undeclare_on_drop: true, + undeclare_on_drop: self.undeclare_on_drop, }, handler: receiver, }) } } -impl<'a, Handler> IntoFuture for SubscriberBuilder<'a, '_, Handler> +impl IntoFuture for SubscriberBuilder<'_, '_, Handler> where Handler: IntoHandler<'static, Sample> + Send, Handler::Handler: Send, @@ -407,17 +359,33 @@ where /// A subscriber that provides data through a [`Handler`](crate::handlers::IntoHandler). /// /// Subscribers can be created from a zenoh [`Session`](crate::Session) -/// with the [`declare_subscriber`](crate::session::SessionDeclarations::declare_subscriber) function -/// and the [`with`](SubscriberBuilder::with) function -/// of the resulting builder. +/// with the [`declare_subscriber`](crate::Session::declare_subscriber) function. /// -/// Subscribers are automatically undeclared when dropped. +/// Callback subscribers will run in background until the session is closed, +/// or until it is undeclared. +/// On the other hand, subscribers with a handler are automatically undeclared when dropped. /// /// # Examples +/// +/// Using callback: +/// ```no_run +/// # #[tokio::main] +/// # async fn main() { +/// +/// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); +/// session +/// .declare_subscriber("key/expression") +/// .callback(|sample| { println!("Received: {} {:?}", sample.key_expr(), sample.payload()) }) +/// .await +/// .unwrap(); +/// // subscriber run in background until the session is closed +/// # } +/// ``` +/// +/// Using channel handler: /// ```no_run /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let subscriber = session @@ -428,23 +396,23 @@ where /// while let Ok(sample) = subscriber.recv_async().await { /// println!("Received: {} {:?}", sample.key_expr(), sample.payload()); /// } +/// // subscriber is undeclared at the end of the scope /// # } /// ``` #[non_exhaustive] #[derive(Debug)] -pub struct Subscriber<'a, Handler> { - pub(crate) subscriber: SubscriberInner<'a>, +pub struct Subscriber { + pub(crate) inner: SubscriberInner, pub(crate) handler: Handler, } -impl<'a, Handler> Subscriber<'a, Handler> { +impl Subscriber { /// Returns the [`EntityGlobalId`] of this Subscriber. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let subscriber = session.declare_subscriber("key/expression") @@ -456,15 +424,15 @@ impl<'a, Handler> Subscriber<'a, Handler> { #[zenoh_macros::unstable] pub fn id(&self) -> EntityGlobalId { EntityGlobalIdProto { - zid: self.subscriber.session.zid().into(), - eid: self.subscriber.state.id, + zid: self.inner.session_id.into(), + eid: self.inner.state.id, } .into() } /// Returns the [`KeyExpr`] this Subscriber subscribes to. pub fn key_expr(&self) -> &KeyExpr<'static> { - &self.subscriber.state.key_expr + &self.inner.state.key_expr } /// Returns a reference to this subscriber's handler. @@ -481,16 +449,12 @@ impl<'a, Handler> Subscriber<'a, Handler> { &mut self.handler } - /// Close a [`Subscriber`]. - /// - /// Subscribers are automatically closed when dropped, but you may want to use this function to handle errors or - /// close the Subscriber asynchronously. + /// Undeclare the [`Subscriber`]. /// /// # Examples /// ``` /// # #[tokio::main] /// # async fn main() { - /// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let subscriber = session.declare_subscriber("key/expression") @@ -500,42 +464,55 @@ impl<'a, Handler> Subscriber<'a, Handler> { /// # } /// ``` #[inline] - pub fn undeclare(self) -> SubscriberUndeclaration<'a> { - self.subscriber.undeclare() + pub fn undeclare(self) -> SubscriberUndeclaration + where + Handler: Send, + { + self.undeclare_inner(()) } - /// Make the subscriber run in background, until the session is closed. - #[inline] - #[zenoh_macros::unstable] - pub fn background(mut self) { - // It's not necessary to undeclare this resource when session close, as other sessions - // will clean all resources related to the closed one. - // So we can just never undeclare it. - self.subscriber.undeclare_on_drop = false; + fn undeclare_impl(&mut self) -> ZResult<()> { + // set the flag first to avoid double panic if this function panic + self.inner.undeclare_on_drop = false; + self.inner + .session + .undeclare_subscriber_inner(self.inner.state.id, self.inner.kind) } } -impl<'a, T> UndeclarableSealed<(), SubscriberUndeclaration<'a>> for Subscriber<'a, T> { - fn undeclare_inner(self, _: ()) -> SubscriberUndeclaration<'a> { - UndeclarableSealed::undeclare_inner(self.subscriber, ()) +impl Drop for Subscriber { + fn drop(&mut self) { + if self.inner.undeclare_on_drop { + if let Err(error) = self.undeclare_impl() { + error!(error); + } + } + } +} + +impl UndeclarableSealed<()> for Subscriber { + type Undeclaration = SubscriberUndeclaration; + + fn undeclare_inner(self, _: ()) -> Self::Undeclaration { + SubscriberUndeclaration(self) } } -impl Deref for Subscriber<'_, Handler> { +impl Deref for Subscriber { type Target = Handler; fn deref(&self) -> &Self::Target { self.handler() } } -impl DerefMut for Subscriber<'_, Handler> { +impl DerefMut for Subscriber { fn deref_mut(&mut self) -> &mut Self::Target { self.handler_mut() } } /// A [`Subscriber`] that provides data through a `flume` channel. -pub type FlumeSubscriber<'a> = Subscriber<'a, flume::Receiver>; +pub type FlumeSubscriber = Subscriber>; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(crate) enum SubscriberKind { diff --git a/zenoh/src/lib.rs b/zenoh/src/lib.rs index 9a3cefa96f..3fa24e3c36 100644 --- a/zenoh/src/lib.rs +++ b/zenoh/src/lib.rs @@ -34,7 +34,6 @@ //! ### Publishing Data //! The example below shows how to produce a value for a key expression. //! ``` -//! use zenoh::prelude::*; //! //! #[tokio::main] //! async fn main() { @@ -48,7 +47,6 @@ //! The example below shows how to consume values for a key expressions. //! ```no_run //! use futures::prelude::*; -//! use zenoh::prelude::*; //! //! #[tokio::main] //! async fn main() { @@ -65,7 +63,6 @@ //! resources whose key match the given *key expression*. //! ``` //! use futures::prelude::*; -//! use zenoh::prelude::*; //! //! #[tokio::main] //! async fn main() { @@ -128,6 +125,7 @@ pub use crate::{ session::{open, Session}, }; +#[deprecated(since = "1.0.0")] pub mod prelude; /// [Key expression](https://github.com/eclipse-zenoh/roadmap/blob/main/rfcs/ALL/Key%20Expressions.md) are Zenoh's address space. @@ -197,7 +195,7 @@ pub mod session { builders::publisher::{SessionDeleteBuilder, SessionPutBuilder}, info::{PeersZenohIdBuilder, RoutersZenohIdBuilder, SessionInfo, ZenohIdBuilder}, query::SessionGetBuilder, - session::{open, OpenBuilder, Session, SessionDeclarations, SessionRef, Undeclarable}, + session::{open, OpenBuilder, Session, Undeclarable}, }; } @@ -234,7 +232,6 @@ pub mod pubsub { #[zenoh_macros::unstable] pub use crate::api::publisher::{ MatchingListener, MatchingListenerBuilder, MatchingListenerUndeclaration, MatchingStatus, - PublisherDeclarations, PublisherRef, }; pub use crate::api::{ builders::publisher::{ @@ -298,7 +295,6 @@ pub mod scouting { /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let liveliness = session @@ -313,7 +309,6 @@ pub mod scouting { /// ``` /// # #[tokio::main] /// # async fn main() { -/// use zenoh::prelude::*; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let replies = session.liveliness().get("key/**").await.unwrap(); @@ -329,7 +324,7 @@ pub mod scouting { /// ```no_run /// # #[tokio::main] /// # async fn main() { -/// use zenoh::{prelude::*, sample::SampleKind}; +/// use zenoh::sample::SampleKind; /// /// let session = zenoh::open(zenoh::config::peer()).await.unwrap(); /// let subscriber = session.liveliness().declare_subscriber("key/**").await.unwrap(); diff --git a/zenoh/src/net/routing/dispatcher/resource.rs b/zenoh/src/net/routing/dispatcher/resource.rs index 595bdd0a8d..2931dfdd0f 100644 --- a/zenoh/src/net/routing/dispatcher/resource.rs +++ b/zenoh/src/net/routing/dispatcher/resource.rs @@ -339,6 +339,7 @@ impl Resource { r.parent.take(); r.children.clear(); r.nonwild_prefix.take(); + r.context.take(); r.session_ctxs.clear(); } diff --git a/zenoh/src/net/runtime/adminspace.rs b/zenoh/src/net/runtime/adminspace.rs index b29401e23e..e38847c249 100644 --- a/zenoh/src/net/runtime/adminspace.rs +++ b/zenoh/src/net/runtime/adminspace.rs @@ -19,7 +19,7 @@ use std::{ use serde_json::json; use tracing::{error, trace}; use zenoh_buffers::buffer::SplitBuffer; -use zenoh_config::{unwrap_or_default, wrappers::ZenohId, ConfigValidator, ValidatedMap, WhatAmI}; +use zenoh_config::{unwrap_or_default, wrappers::ZenohId, ConfigValidator, WhatAmI}; use zenoh_core::Wait; #[cfg(feature = "plugins")] use zenoh_plugin_trait::{PluginControl, PluginStatus}; @@ -398,8 +398,7 @@ impl Primitives for AdminSpace { key, json ); - if let Err(e) = (&self.context.runtime.state.config).insert_json5(key, json) - { + if let Err(e) = self.context.runtime.state.config.insert_json5(key, json) { error!( "Error inserting conf value @/{}/{}/config/{} : {} - {}", self.context.runtime.state.zid, diff --git a/zenoh/src/net/runtime/mod.rs b/zenoh/src/net/runtime/mod.rs index f50d597247..1a02513494 100644 --- a/zenoh/src/net/runtime/mod.rs +++ b/zenoh/src/net/runtime/mod.rs @@ -279,13 +279,10 @@ impl Runtime { // the task responsible for resource clean up was aborted earlier than expected. // This should be resolved by identfying correspodning task, and placing // cancellation token manually inside it. - self.router() - .tables - .tables - .write() - .unwrap() - .root_res - .close(); + let router = self.router(); + let mut tables = router.tables.tables.write().unwrap(); + tables.root_res.close(); + tables.faces.clear(); Ok(()) } diff --git a/zenoh/src/prelude.rs b/zenoh/src/prelude.rs index 7adf400679..572788a834 100644 --- a/zenoh/src/prelude.rs +++ b/zenoh/src/prelude.rs @@ -21,23 +21,9 @@ //! Examples: //! //! ``` -//!use zenoh::prelude::*; +//! use zenoh::prelude::*; //! ``` -mod _prelude { - #[zenoh_macros::unstable] - pub use crate::api::publisher::PublisherDeclarations; - #[zenoh_macros::unstable] - pub use crate::api::selector::ZenohParameters; - pub use crate::{ - api::session::{SessionDeclarations, Undeclarable}, - config::ValidatedMap, - Error as ZError, Resolvable, Resolve, Result as ZResult, - }; -} - -pub use _prelude::*; - #[allow(deprecated)] pub use crate::AsyncResolve; #[allow(deprecated)] @@ -45,16 +31,14 @@ pub use crate::SyncResolve; pub use crate::Wait; /// Prelude to import when using Zenoh's sync API. -#[deprecated(since = "1.0.0", note = "use `zenoh::prelude` instead")] +#[deprecated(since = "1.0.0", note = "use `zenoh::Wait` instead")] pub mod sync { - pub use super::_prelude::*; #[allow(deprecated)] pub use crate::SyncResolve; } /// Prelude to import when using Zenoh's async API. -#[deprecated(since = "1.0.0", note = "use `zenoh::prelude` instead")] +#[deprecated(since = "1.0.0")] pub mod r#async { - pub use super::_prelude::*; #[allow(deprecated)] pub use crate::AsyncResolve; } diff --git a/zenoh/tests/acl.rs b/zenoh/tests/acl.rs index 2505a81983..285e68b254 100644 --- a/zenoh/tests/acl.rs +++ b/zenoh/tests/acl.rs @@ -22,7 +22,6 @@ mod test { use zenoh::{ config, config::{EndPoint, WhatAmI}, - prelude::*, sample::SampleKind, Config, Session, }; diff --git a/zenoh/tests/attachments.rs b/zenoh/tests/attachments.rs index 38b1fea136..dd9e287428 100644 --- a/zenoh/tests/attachments.rs +++ b/zenoh/tests/attachments.rs @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // #![cfg(feature = "unstable")] -use zenoh::{bytes::ZBytes, config::Config, prelude::*}; +use zenoh::{bytes::ZBytes, config::Config, Wait}; #[test] fn attachment_pubsub() { @@ -61,7 +61,6 @@ fn attachment_pubsub() { #[test] fn attachment_queries() { - use zenoh::prelude::*; let zenoh = zenoh::open(Config::default()).wait().unwrap(); let _sub = zenoh .declare_queryable("test/attachment") diff --git a/zenoh/tests/authentication.rs b/zenoh/tests/authentication.rs index f9fb7a3b0e..63ddfcc03c 100644 --- a/zenoh/tests/authentication.rs +++ b/zenoh/tests/authentication.rs @@ -24,7 +24,6 @@ mod test { use zenoh::{ config, config::{EndPoint, WhatAmI}, - prelude::*, Config, Session, }; use zenoh_core::{zlock, ztimeout}; diff --git a/zenoh/tests/bytes.rs b/zenoh/tests/bytes.rs index a8c9c7f17a..c9a2e016f4 100644 --- a/zenoh/tests/bytes.rs +++ b/zenoh/tests/bytes.rs @@ -14,11 +14,11 @@ #![cfg(all(feature = "shared-memory", feature = "unstable"))] use zenoh::{ bytes::ZBytes, - prelude::*, shm::{ zshm, zshmmut, PosixShmProviderBackend, ShmProviderBuilder, ZShm, ZShmMut, POSIX_PROTOCOL_ID, }, + Wait, }; #[test] diff --git a/zenoh/tests/connection_retry.rs b/zenoh/tests/connection_retry.rs index 78814556f7..6bb655851b 100644 --- a/zenoh/tests/connection_retry.rs +++ b/zenoh/tests/connection_retry.rs @@ -12,11 +12,9 @@ // ZettaScale Zenoh Team, // use zenoh::{ - config::{ConnectionRetryConf, EndPoint}, - prelude::*, - Config, + config::{ConnectionRetryConf, EndPoint, ModeDependent}, + Config, Wait, }; -use zenoh_config::ModeDependent; #[test] fn retry_config_overriding() { diff --git a/zenoh/tests/events.rs b/zenoh/tests/events.rs index 11a6e18b53..e3a4d61656 100644 --- a/zenoh/tests/events.rs +++ b/zenoh/tests/events.rs @@ -52,7 +52,6 @@ async fn close_session(session: Session) { #[tokio::test(flavor = "multi_thread", worker_threads = 4)] async fn zenoh_events() { - use zenoh::prelude::SessionDeclarations; let session = open_session(&["tcp/127.0.0.1:18447"], &[]).await; let zid = session.zid(); let sub1 = diff --git a/zenoh/tests/handler.rs b/zenoh/tests/handler.rs index 640ed33b89..d87917a0dd 100644 --- a/zenoh/tests/handler.rs +++ b/zenoh/tests/handler.rs @@ -13,7 +13,7 @@ // use std::{thread, time::Duration}; -use zenoh::{handlers::RingChannel, prelude::*, Config}; +use zenoh::{handlers::RingChannel, Config, Wait}; #[test] fn pubsub_with_ringbuffer() { diff --git a/zenoh/tests/interceptors.rs b/zenoh/tests/interceptors.rs index 1f3981b66e..57ba51d5ba 100644 --- a/zenoh/tests/interceptors.rs +++ b/zenoh/tests/interceptors.rs @@ -24,8 +24,7 @@ use std::{ use zenoh::{ config::{DownsamplingItemConf, DownsamplingRuleConf, InterceptorFlow}, key_expr::KeyExpr, - prelude::*, - Config, + Config, Wait, }; // Tokio's time granularity on different platforms diff --git a/zenoh/tests/liveliness.rs b/zenoh/tests/liveliness.rs index 3f1d38af23..ff0bb4ee99 100644 --- a/zenoh/tests/liveliness.rs +++ b/zenoh/tests/liveliness.rs @@ -19,7 +19,7 @@ use zenoh_core::ztimeout; async fn test_liveliness_subscriber_clique() { use std::time::Duration; - use zenoh::{config, prelude::*, sample::SampleKind}; + use zenoh::{config, sample::SampleKind}; use zenoh_config::WhatAmI; use zenoh_link::EndPoint; const TIMEOUT: Duration = Duration::from_secs(60); @@ -83,7 +83,7 @@ async fn test_liveliness_subscriber_clique() { async fn test_liveliness_query_clique() { use std::time::Duration; - use zenoh::{config, prelude::*, sample::SampleKind}; + use zenoh::{config, sample::SampleKind}; use zenoh_config::WhatAmI; use zenoh_link::EndPoint; const TIMEOUT: Duration = Duration::from_secs(60); @@ -140,7 +140,7 @@ async fn test_liveliness_query_clique() { async fn test_liveliness_subscriber_brokered() { use std::time::Duration; - use zenoh::{config, prelude::*, sample::SampleKind}; + use zenoh::{config, sample::SampleKind}; use zenoh_config::WhatAmI; use zenoh_link::EndPoint; @@ -219,7 +219,7 @@ async fn test_liveliness_subscriber_brokered() { async fn test_liveliness_query_brokered() { use std::time::Duration; - use zenoh::{config, prelude::*, sample::SampleKind}; + use zenoh::{config, sample::SampleKind}; use zenoh_config::WhatAmI; use zenoh_link::EndPoint; const TIMEOUT: Duration = Duration::from_secs(60); @@ -290,7 +290,7 @@ async fn test_liveliness_query_brokered() { async fn test_liveliness_subscriber_local() { use std::time::Duration; - use zenoh::{config, prelude::*, sample::SampleKind}; + use zenoh::{config, sample::SampleKind}; use zenoh_config::WhatAmI; const TIMEOUT: Duration = Duration::from_secs(60); const SLEEP: Duration = Duration::from_secs(1); @@ -333,7 +333,7 @@ async fn test_liveliness_subscriber_local() { async fn test_liveliness_query_local() { use std::time::Duration; - use zenoh::{config, prelude::*, sample::SampleKind}; + use zenoh::{config, sample::SampleKind}; use zenoh_config::WhatAmI; const TIMEOUT: Duration = Duration::from_secs(60); const SLEEP: Duration = Duration::from_secs(1); diff --git a/zenoh/tests/matching.rs b/zenoh/tests/matching.rs index b2a180552d..d7825e85b8 100644 --- a/zenoh/tests/matching.rs +++ b/zenoh/tests/matching.rs @@ -15,7 +15,7 @@ use std::{str::FromStr, time::Duration}; use flume::RecvTimeoutError; -use zenoh::{config, config::Locator, prelude::*, sample::Locality, Session}; +use zenoh::{config, config::Locator, sample::Locality, Result as ZResult, Session}; use zenoh_core::ztimeout; const TIMEOUT: Duration = Duration::from_secs(60); diff --git a/zenoh/tests/qos.rs b/zenoh/tests/qos.rs index 8d7d7e7322..2ba3226310 100644 --- a/zenoh/tests/qos.rs +++ b/zenoh/tests/qos.rs @@ -15,7 +15,6 @@ use std::time::Duration; use zenoh::{ bytes::Encoding, - prelude::*, qos::{CongestionControl, Priority}, }; use zenoh_core::ztimeout; diff --git a/zenoh/tests/routing.rs b/zenoh/tests/routing.rs index 0c4c0b42f1..e9c8fd899f 100644 --- a/zenoh/tests/routing.rs +++ b/zenoh/tests/routing.rs @@ -22,7 +22,6 @@ use std::{ use tokio_util::sync::CancellationToken; use zenoh::{ config::{ModeDependentValue, WhatAmI, WhatAmIMatcher}, - prelude::*, qos::CongestionControl, Config, Result, Session, }; @@ -56,7 +55,7 @@ enum Task { impl Task { async fn run( &self, - session: Arc, + session: Session, remaining_checkpoints: Arc, token: CancellationToken, ) -> Result<()> { @@ -386,7 +385,7 @@ impl Recipe { // In case of client can't connect to some peers/routers loop { if let Ok(session) = ztimeout!(zenoh::open(config.clone())) { - break session.into_arc(); + break session; } else { tokio::time::sleep(Duration::from_secs(1)).await; } @@ -421,7 +420,7 @@ impl Recipe { // node_task_tracker.wait().await; // Close the session once all the task associated with the node are done. - ztimeout!(Arc::try_unwrap(session).unwrap().close())?; + ztimeout!(session.close())?; println!("Node: {} is closed.", &node.name); Result::Ok(()) diff --git a/zenoh/tests/session.rs b/zenoh/tests/session.rs index 1195bd2099..04f3bde4f9 100644 --- a/zenoh/tests/session.rs +++ b/zenoh/tests/session.rs @@ -23,9 +23,7 @@ use std::{ use zenoh::internal::runtime::{Runtime, RuntimeBuilder}; #[cfg(feature = "unstable")] use zenoh::pubsub::Reliability; -use zenoh::{ - config, key_expr::KeyExpr, prelude::*, qos::CongestionControl, sample::SampleKind, Session, -}; +use zenoh::{config, key_expr::KeyExpr, qos::CongestionControl, sample::SampleKind, Session}; use zenoh_core::ztimeout; #[cfg(not(feature = "unstable"))] use zenoh_protocol::core::Reliability; diff --git a/zenoh/tests/shm.rs b/zenoh/tests/shm.rs index 7b0c3aaaba..8e1205f711 100644 --- a/zenoh/tests/shm.rs +++ b/zenoh/tests/shm.rs @@ -22,14 +22,13 @@ use std::{ use zenoh::{ config, - prelude::*, pubsub::Reliability, qos::CongestionControl, shm::{ zshm, BlockOn, GarbageCollect, PosixShmProviderBackend, ShmProviderBuilder, POSIX_PROTOCOL_ID, }, - Session, + Session, Wait, }; use zenoh_core::ztimeout; diff --git a/zenoh/tests/unicity.rs b/zenoh/tests/unicity.rs index 5163420131..de63b0a97e 100644 --- a/zenoh/tests/unicity.rs +++ b/zenoh/tests/unicity.rs @@ -24,7 +24,6 @@ use zenoh::{ config, config::{EndPoint, WhatAmI}, key_expr::KeyExpr, - prelude::*, qos::CongestionControl, Session, }; diff --git a/zenohd/src/main.rs b/zenohd/src/main.rs index 9ce0a64333..85a063e3a2 100644 --- a/zenohd/src/main.rs +++ b/zenohd/src/main.rs @@ -18,7 +18,7 @@ use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilte #[cfg(feature = "loki")] use url::Url; use zenoh::{ - config::{Config, EndPoint, ModeDependentValue, PermissionsConf, ValidatedMap, WhatAmI}, + config::{Config, EndPoint, ModeDependentValue, PermissionsConf, WhatAmI}, Result, }; use zenoh_util::LibSearchDirs;