diff --git a/src/core/transport_request.rs b/src/core/transport_request.rs index 77f6cc0a..7fc4d47a 100644 --- a/src/core/transport_request.rs +++ b/src/core/transport_request.rs @@ -123,6 +123,7 @@ impl TransportRequest { { // Request configured endpoint. let response = transport.send(self.clone()).await?; + Self::deserialize( response.clone(), Box::new(move |bytes| deserializer.deserialize(bytes)), diff --git a/src/dx/presence/builders/here_now.rs b/src/dx/presence/builders/here_now.rs index b5c33e65..edba0152 100644 --- a/src/dx/presence/builders/here_now.rs +++ b/src/dx/presence/builders/here_now.rs @@ -3,6 +3,8 @@ //! The [`HereNowRequestBuilder`] lets you make and execute a Here Now request //! that will associate a user with a channel. +use core::ops::Deref; + use derive_builder::Builder; use crate::{ @@ -59,10 +61,6 @@ pub struct HereNowRequest { )] pub(in crate::dx::presence) channel_groups: Vec, - /// Identifier of the user for which to retrieve occupancy information. - #[builder(field(vis = "pub(in crate::dx::presence)"), setter(strip_option, into))] - pub(in crate::dx::presence) user_id: String, - /// Whether to include UUIDs of users subscribed to the channel(s). #[builder( field(vis = "pub(in crate::dx::presence)"), @@ -92,8 +90,6 @@ impl HereNowRequestBuilder { builders::validate_configuration(&self.pubnub_client).and_then(|_| { if channels_len == groups_len && channels_len == 0 { Err("Either channels or channel groups should be provided".into()) - } else if self.user_id.is_none() { - Err("User id is missing".into()) } else { Ok(()) } @@ -126,11 +122,15 @@ impl HereNowRequest { query.insert("disable_uuids".into(), "1".into()); }); + query.insert( + "uuid".into(), + self.pubnub_client.config.user_id.deref().clone(), + ); + Ok(TransportRequest { path: format!( - "/v2/presence/sub-key/{sub_key}/channel/{}/uuid/{}/data", + "/v2/presence/sub-key/{sub_key}/channel/{}", url_encoded_channels(&self.channels), - url_encode_extended(self.user_id.as_bytes(), UrlEncodeExtension::NonChannelPath) ), query_parameters: query, method: TransportMethod::Get, @@ -147,13 +147,27 @@ where { /// Build and call asynchronous request. pub async fn execute(self) -> Result { + let name_replacement = self + .channels + .as_ref() + .map(|channels| (channels.len() == 1).then(|| channels[0].clone())) + .flatten(); + let request = self.request()?; let transport_request = request.transport_request()?; let client = request.pubnub_client.clone(); let deserializer = client.deserializer.clone(); + transport_request .send::(&client.transport, deserializer) .await + .map(|mut result: HereNowResult| { + name_replacement.is_some().then(|| { + result.channels[0].name = name_replacement.expect("Cannot be None"); + }); + + result + }) } } diff --git a/src/dx/presence/result.rs b/src/dx/presence/result.rs index 86e12a2a..6d2ff9a3 100644 --- a/src/dx/presence/result.rs +++ b/src/dx/presence/result.rs @@ -480,7 +480,7 @@ pub struct HereNowResponseChannelIdentifier { pub occupancy: u32, /// List of users in channel. - pub uuids: Vec, + pub uuids: Option>, } /// Possible variants of user identifier in here now response. @@ -492,6 +492,12 @@ pub enum HereNowResponseUserIdentifier { /// User identifier is a string. String(String), + /// User identifier is a map of uuids + Map { + /// User identifier. + uuid: String, + }, + /// User identifier is a map of channel names to their states. WithState { /// User identifier. @@ -519,20 +525,28 @@ impl TryFrom for HereNowResult { let occupants = single .payload .uuids - .iter() - .map(|uuid| match uuid { - HereNowResponseUserIdentifier::String(uuid) => HereNowUser { - user_id: uuid.clone(), - state: None, - }, - HereNowResponseUserIdentifier::WithState { uuid, state } => { - HereNowUser { - user_id: uuid.clone(), - state: Some(state.clone()), - } - } + .map(|maybe_uuids| { + maybe_uuids + .iter() + .map(|uuid| match uuid { + HereNowResponseUserIdentifier::String(uuid) => HereNowUser { + user_id: uuid.clone(), + state: None, + }, + HereNowResponseUserIdentifier::Map { uuid } => HereNowUser { + user_id: uuid.clone(), + state: None, + }, + HereNowResponseUserIdentifier::WithState { uuid, state } => { + HereNowUser { + user_id: uuid.clone(), + state: Some(state.clone()), + } + } + }) + .collect() }) - .collect(); + .unwrap_or_default(); let channels = vec![HereNowChannel { name: "".into(), @@ -559,20 +573,33 @@ impl TryFrom for HereNowResult { let occupants = channel .uuids - .into_iter() - .map(|uuid| match uuid { - HereNowResponseUserIdentifier::String(uuid) => HereNowUser { - user_id: uuid.clone(), - state: None, - }, - HereNowResponseUserIdentifier::WithState { uuid, state } => { - HereNowUser { - user_id: uuid.clone(), - state: Some(state.clone()), - } - } + .map(|maybe_uuids| { + maybe_uuids + .into_iter() + .map(|uuid| match uuid { + HereNowResponseUserIdentifier::String(uuid) => { + HereNowUser { + user_id: uuid.clone(), + state: None, + } + } + HereNowResponseUserIdentifier::Map { uuid } => { + HereNowUser { + user_id: uuid.clone(), + state: None, + } + } + HereNowResponseUserIdentifier::WithState { + uuid, + state, + } => HereNowUser { + user_id: uuid.clone(), + state: Some(state.clone()), + }, + }) + .collect() }) - .collect(); + .unwrap_or_default(); HereNowChannel { name,