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, ResetRequest,
23    ResetResponse, SubscribeAttributes, SubscriberInfo, Subscription, SubscriptionRequest,
24    SubscriptionResponse, SubscriptionStatus, 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 SubscriptionResponse contains a valid SubscriptionStatus, 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/// The resource identifier of uSubscription's _reset_ operation.
134pub const RESOURCE_ID_RESET: u16 = 0x0009;
135
136/// The resource identifier of uSubscription's _subscription change_ topic.
137pub const RESOURCE_ID_SUBSCRIPTION_CHANGE: u16 = 0x8000;
138
139/// Gets a UUri referring to one of the local uSubscription service's resources.
140///
141/// # Examples
142///
143/// ```rust
144/// use up_rust::core::usubscription;
145///
146/// let uuri = usubscription::usubscription_uri(usubscription::RESOURCE_ID_SUBSCRIBE);
147/// assert_eq!(uuri.resource_id, 0x0001);
148/// ```
149pub fn usubscription_uri(resource_id: u16) -> UUri {
150    UUri::try_from_parts(
151        "",
152        USUBSCRIPTION_TYPE_ID,
153        USUBSCRIPTION_VERSION_MAJOR,
154        resource_id,
155    )
156    .unwrap()
157}
158
159/// The uProtocol Application Layer client interface to the uSubscription service.
160///
161/// Please refer to the [uSubscription service specification](https://github.com/eclipse-uprotocol/up-spec/blob/main/up-l3/usubscription/v3/README.adoc)
162/// for details.
163#[cfg_attr(test, automock)]
164#[async_trait]
165pub trait USubscription: Send + Sync {
166    /// Subscribes to a topic, using a [`SubscriptionRequest`]
167    ///
168    /// # Parameters
169    ///
170    /// * `subscription_request` - A request to subscribe
171    ///
172    /// # Returns
173    ///
174    /// * [`SubscriptionResponse`] detailing if subscription was successful with other metadata
175    async fn subscribe(
176        &self,
177        subscription_request: SubscriptionRequest,
178    ) -> Result<SubscriptionResponse, UStatus>;
179
180    /// Unsubscribes from a topic, using an [`UnsubscribeRequest`]
181    ///
182    /// # Parameters
183    ///
184    /// * `unsubscribe_request` - A request to unsubscribe
185    ///
186    /// # Returns
187    ///
188    /// * [`UStatus`] detailing if unsubscription was successful and if not why not
189    async fn unsubscribe(&self, unsubscribe_request: UnsubscribeRequest) -> Result<(), UStatus>;
190
191    /// Fetches all subscriptions for a given topic or subscriber contained inside a [`FetchSubscriptionsRequest`]
192    ///
193    /// # Parameters
194    ///
195    /// * `fetch_subscriptions_request` - A request to fetch subscriptions given a topic or subscriber
196    ///
197    /// # Returns
198    ///
199    /// * [`FetchSubscriptionsResponse`] detailing the zero or more subscriptions' info
200    async fn fetch_subscriptions(
201        &self,
202        fetch_subscriptions_request: FetchSubscriptionsRequest,
203    ) -> Result<FetchSubscriptionsResponse, UStatus>;
204
205    /// Registers for notifications relevant to a given topic inside a [`NotificationsRequest`]
206    /// changing in subscription status.
207    ///
208    /// # Parameters
209    ///
210    /// * `notifications_register_request` - A request to receive changes to subscription status
211    ///
212    /// # Returns
213    ///
214    /// * [`UStatus`] detailing if notification registration was successful and if not why not
215    async fn register_for_notifications(
216        &self,
217        notifications_register_request: NotificationsRequest,
218    ) -> Result<(), UStatus>;
219
220    /// Unregisters from notifications relevant to a given topic inside a [`NotificationsRequest`]
221    /// changing in subscription status.
222    ///
223    /// # Parameters
224    ///
225    /// * `notifications_unregister_request` - A request to no longer receive changes to subscription status
226    ///
227    /// # Returns
228    ///
229    /// * [`UStatus`] detailing if notification unregistration was successful and if not why not
230    async fn unregister_for_notifications(
231        &self,
232        notifications_unregister_request: NotificationsRequest,
233    ) -> Result<(), UStatus>;
234
235    /// Fetches a list of subscribers that are currently subscribed to a given topic in a [`FetchSubscribersRequest`]
236    ///
237    /// # Parameters
238    ///
239    /// * `fetch_subscribers_request` - Request containing topic for which we'd like all subscribers' info
240    ///
241    /// # Returns
242    ///
243    /// * [`FetchSubscriptionsResponse`] detailing subscriber info for the provided topic
244    async fn fetch_subscribers(
245        &self,
246        fetch_subscribers_request: FetchSubscribersRequest,
247    ) -> Result<FetchSubscribersResponse, UStatus>;
248
249    /// Flushes all stored subscription information, including any persistently stored subscriptions
250    ///
251    /// # Returns
252    ///
253    /// * [`ResetResponse`] with result of the operation
254    async fn reset(&self, reset_request: ResetRequest) -> Result<ResetResponse, UStatus>;
255}