up_rust/core/
usubscription.rs

1/********************************************************************************
2 * Copyright (c) 2024 Contributors to the Eclipse Foundation
3 *
4 * See the NOTICE file(s) distributed with this work for additional
5 * information regarding copyright ownership.
6 *
7 * This program and the accompanying materials are made available under the
8 * terms of the Apache License Version 2.0 which is available at
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * SPDX-License-Identifier: Apache-2.0
12 ********************************************************************************/
13
14use async_trait::async_trait;
15use core::hash::{Hash, Hasher};
16#[cfg(test)]
17use mockall::automock;
18
19pub use crate::up_core_api::usubscription::{
20    fetch_subscriptions_request::Request, subscription_status::State, EventDeliveryConfig,
21    FetchSubscribersRequest, FetchSubscribersResponse, FetchSubscriptionsRequest,
22    FetchSubscriptionsResponse, NotificationsRequest, NotificationsResponse, SubscribeAttributes,
23    SubscriberInfo, Subscription, SubscriptionRequest, SubscriptionResponse, SubscriptionStatus,
24    UnsubscribeRequest, UnsubscribeResponse, Update,
25};
26
27use crate::{UStatus, UUri};
28
29impl Hash for SubscriberInfo {
30    /// Creates a hash value based on the URI property.
31    ///
32    /// # Examples
33    ///
34    /// ```rust
35    /// use std::hash::{DefaultHasher, Hash, Hasher};
36    /// use up_rust::UUri;
37    /// use up_rust::core::usubscription::SubscriberInfo;
38    ///
39    /// let mut hasher = DefaultHasher::new();
40    /// let info = SubscriberInfo {
41    ///     uri: Some(UUri::try_from_parts("", 0x1000, 0x01, 0x9a00).unwrap()).into(),
42    ///     ..Default::default()
43    /// };
44    ///
45    /// info.hash(&mut hasher);
46    /// let hash_one = hasher.finish();
47    ///
48    /// let mut hasher = DefaultHasher::new();
49    /// let info = SubscriberInfo {
50    ///     uri: Some(UUri::try_from_parts("", 0x1000, 0x02, 0xf100).unwrap()).into(),
51    ///     ..Default::default()
52    /// };
53    ///
54    /// info.hash(&mut hasher);
55    /// let hash_two = hasher.finish();
56    ///
57    /// assert_ne!(hash_one, hash_two);
58    /// ```
59    fn hash<H: Hasher>(&self, state: &mut H) {
60        self.uri.hash(state);
61    }
62}
63
64impl Eq for SubscriberInfo {}
65
66/// Checks if a given [`SubscriberInfo`] contains any information.
67///
68/// # Returns
69///
70/// `true` if the given instance is equal to [`SubscriberInfo::default`], `false` otherwise.
71///
72/// # Examples
73///
74/// ```rust
75/// use up_rust::UUri;
76/// use up_rust::core::usubscription::SubscriberInfo;
77///
78/// let mut info = SubscriberInfo::default();
79/// assert!(info.is_empty());
80///
81/// info.uri = Some(UUri::try_from_parts("", 0x1000, 0x01, 0x9a00).unwrap()).into();
82/// assert!(!info.is_empty());
83/// ```
84impl SubscriberInfo {
85    pub fn is_empty(&self) -> bool {
86        self.eq(&SubscriberInfo::default())
87    }
88}
89
90impl SubscriptionResponse {
91    /// Checks if this `SubscriptionResponse` is in a specific state (`usubscription::State``).
92    ///
93    /// Returns `true` if SubscriptionReponse contains a valied SusbcriptionStatus, which has a
94    /// state property that is equal to state passed as argument.
95    ///
96    /// # Examples
97    ///
98    /// ```rust
99    /// use up_rust::core::usubscription::{SubscriptionResponse, SubscriptionStatus, State};
100    ///
101    /// let subscription_response = SubscriptionResponse {
102    ///     status: Some(SubscriptionStatus {
103    ///         state: State::SUBSCRIBED.into(),
104    ///         ..Default::default()
105    ///         }).into(),
106    ///     ..Default::default()
107    /// };
108    /// assert!(subscription_response.is_state(State::SUBSCRIBED));
109    /// ```
110    pub fn is_state(&self, state: State) -> bool {
111        self.status
112            .as_ref()
113            .is_some_and(|ss| ss.state.enum_value().is_ok_and(|s| s.eq(&state)))
114    }
115}
116
117/// The uEntity (type) identifier of the uSubscription service.
118pub const USUBSCRIPTION_TYPE_ID: u32 = 0x0000_0000;
119/// The (latest) major version of the uSubscription service.
120pub const USUBSCRIPTION_VERSION_MAJOR: u8 = 0x03;
121/// The resource identifier of uSubscription's _subscribe_ operation.
122pub const RESOURCE_ID_SUBSCRIBE: u16 = 0x0001;
123/// The resource identifier of uSubscription's _unsubscribe_ operation.
124pub const RESOURCE_ID_UNSUBSCRIBE: u16 = 0x0002;
125/// The resource identifier of uSubscription's _fetch subscriptions_ operation.
126pub const RESOURCE_ID_FETCH_SUBSCRIPTIONS: u16 = 0x0003;
127/// The resource identifier of uSubscription's _register for notifications_ operation.
128pub const RESOURCE_ID_REGISTER_FOR_NOTIFICATIONS: u16 = 0x0006;
129/// The resource identifier of uSubscription's _unregister for notifications_ operation.
130pub const RESOURCE_ID_UNREGISTER_FOR_NOTIFICATIONS: u16 = 0x0007;
131/// The resource identifier of uSubscription's _fetch subscribers_ operation.
132pub const RESOURCE_ID_FETCH_SUBSCRIBERS: u16 = 0x0008;
133
134/// The resource identifier of uSubscription's _subscription change_ topic.
135pub const RESOURCE_ID_SUBSCRIPTION_CHANGE: u16 = 0x8000;
136
137/// Gets a UUri referring to one of the local uSubscription service's resources.
138///
139/// # Examples
140///
141/// ```rust
142/// use up_rust::core::usubscription;
143///
144/// let uuri = usubscription::usubscription_uri(usubscription::RESOURCE_ID_SUBSCRIBE);
145/// assert_eq!(uuri.resource_id, 0x0001);
146/// ```
147pub fn usubscription_uri(resource_id: u16) -> UUri {
148    UUri::try_from_parts(
149        "",
150        USUBSCRIPTION_TYPE_ID,
151        USUBSCRIPTION_VERSION_MAJOR,
152        resource_id,
153    )
154    .unwrap()
155}
156
157/// The uProtocol Application Layer client interface to the uSubscription service.
158///
159/// Please refer to the [uSubscription service specification](https://github.com/eclipse-uprotocol/up-spec/blob/main/up-l3/usubscription/v3/README.adoc)
160/// for details.
161#[cfg_attr(test, automock)]
162#[async_trait]
163pub trait USubscription: Send + Sync {
164    /// Subscribe to a topic, using a [`SubscriptionRequest`]
165    ///
166    /// # Parameters
167    ///
168    /// * `subscription_request` - A request to subscribe
169    ///
170    /// # Returns
171    ///
172    /// * [`SubscriptionResponse`] detailing if subscription was successful with other metadata
173    async fn subscribe(
174        &self,
175        subscription_request: SubscriptionRequest,
176    ) -> Result<SubscriptionResponse, UStatus>;
177
178    /// Unsubscribe to a topic, using an [`UnsubscribeRequest`]
179    ///
180    /// # Parameters
181    ///
182    /// * `unsubscribe_request` - A request to unsubscribe
183    ///
184    /// # Returns
185    ///
186    /// * [`UStatus`] detailing if unsubscription was successful and if not why not
187    async fn unsubscribe(&self, unsubscribe_request: UnsubscribeRequest) -> Result<(), UStatus>;
188
189    /// Fetch all subscriptions for a given topic or subscriber contained inside a [`FetchSubscriptionsRequest`]
190    ///
191    /// # Parameters
192    ///
193    /// * `fetch_subscriptions_request` - A request to fetch subscriptions given a topic or subscriber
194    ///
195    /// # Returns
196    ///
197    /// * [`FetchSubscriptionsResponse`] detailing the zero or more subscriptions' info
198    async fn fetch_subscriptions(
199        &self,
200        fetch_subscriptions_request: FetchSubscriptionsRequest,
201    ) -> Result<FetchSubscriptionsResponse, UStatus>;
202
203    /// Register for notifications relevant to a given topic inside a [`NotificationsRequest`]
204    /// changing in subscription status.
205    ///
206    /// # Parameters
207    ///
208    /// * `notifications_register_request` - A request to receive changes to subscription status
209    ///
210    /// # Returns
211    ///
212    /// * [`UStatus`] detailing if notification registration was successful and if not why not
213    async fn register_for_notifications(
214        &self,
215        notifications_register_request: NotificationsRequest,
216    ) -> Result<(), UStatus>;
217
218    /// Unregister for notifications relevant to a given topic inside a [`NotificationsRequest`]
219    /// changing in subscription status.
220    ///
221    /// # Parameters
222    ///
223    /// * `notifications_unregister_request` - A request to no longer receive changes to subscription status
224    ///
225    /// # Returns
226    ///
227    /// * [`UStatus`] detailing if notification unregistration was successful and if not why not
228    async fn unregister_for_notifications(
229        &self,
230        notifications_unregister_request: NotificationsRequest,
231    ) -> Result<(), UStatus>;
232
233    /// Fetch a list of subscribers that are currently subscribed to a given topic in a [`FetchSubscribersRequest`]
234    ///
235    /// # Parameters
236    ///
237    /// * `fetch_subscribers_request` - Request containing topic for which we'd like all subscribers' info
238    ///
239    /// # Returns
240    ///
241    /// * [`FetchSubscriptionsResponse`] detailing subscriber info for the provided topic
242    async fn fetch_subscribers(
243        &self,
244        fetch_subscribers_request: FetchSubscribersRequest,
245    ) -> Result<FetchSubscribersResponse, UStatus>;
246}