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}