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;
15#[cfg(test)]
16use mockall::automock;
17
18use crate::{communication::SubscriptionStatus, UStatus, UUri};
19
20#[cfg(feature = "communication-api")]
21mod usubscription_client;
22#[cfg(feature = "communication-api")]
23pub use usubscription_client::RpcClientUSubscription;
24
25/// The uEntity (type) identifier of the uSubscription service.
26pub const USUBSCRIPTION_TYPE_ID: u32 = 0x0000_0000;
27/// The (latest) major version of the uSubscription service.
28pub const USUBSCRIPTION_VERSION_MAJOR: u8 = 0x03;
29/// The resource identifier of uSubscription's _subscribe_ operation.
30pub const RESOURCE_ID_SUBSCRIBE: u16 = 0x0001;
31/// The resource identifier of uSubscription's _unsubscribe_ operation.
32pub const RESOURCE_ID_UNSUBSCRIBE: u16 = 0x0002;
33/// The resource identifier of uSubscription's _fetch subscriptions_ operation.
34pub const RESOURCE_ID_FETCH_SUBSCRIPTIONS: u16 = 0x0003;
35/// The resource identifier of uSubscription's _register for notifications_ operation.
36pub const RESOURCE_ID_REGISTER_FOR_NOTIFICATIONS: u16 = 0x0006;
37/// The resource identifier of uSubscription's _unregister for notifications_ operation.
38pub const RESOURCE_ID_UNREGISTER_FOR_NOTIFICATIONS: u16 = 0x0007;
39/// The resource identifier of uSubscription's _fetch subscribers_ operation.
40pub const RESOURCE_ID_FETCH_SUBSCRIBERS: u16 = 0x0008;
41/// The resource identifier of uSubscription's _reset_ operation.
42pub const RESOURCE_ID_RESET: u16 = 0x0009;
43
44/// The resource identifier of uSubscription's _subscription change_ topic.
45pub const RESOURCE_ID_SUBSCRIPTION_CHANGE: u16 = 0x8000;
46
47#[derive(Clone, Debug, PartialEq)]
48#[repr(C)]
49/// One active subscription as reported by the uSubscription service.
50pub struct SubscriptionInfo {
51 topic: UUri,
52 subscriber: UUri,
53 status: SubscriptionStatus,
54 expiration: Option<u64>,
55 min_sample_period: Option<u32>,
56}
57
58impl SubscriptionInfo {
59 /// Creates a new info object.
60 ///
61 /// # Arguments
62 /// * `topic` - The topic of the subscription.
63 /// * `subscriber` - The uEntity that has established the subscription.
64 /// * `status` - The status of the subscription.
65 /// * `expiration` - The point in time at which the subscription expires (milliseconds since Unix epoch).
66 /// If not specified, the subscription is valid until explicitly unsubscribed.
67 /// * `min_sample_period` - The minimum duration (in seconds) between two events that should be maintained
68 /// for remote only topics. Device dispatchers use this attribute to reduce the publication
69 /// rates of events sent between devices.
70 /// This attribute is commonly used for mobile/cloud components subscribing to vehicle topics that are published
71 /// at a high rate. If the desired sampling period set by the subscriber is lower than the original
72 /// publisher's publication period, the attribute is ignored. If not specified, the sampling period is set
73 /// by the publisher.
74 #[must_use]
75 pub fn new(
76 topic: UUri,
77 subscriber: UUri,
78 status: SubscriptionStatus,
79 expiration: Option<u64>,
80 min_sample_period: Option<u32>,
81 ) -> Self {
82 Self {
83 topic,
84 subscriber,
85 status,
86 expiration,
87 min_sample_period,
88 }
89 }
90
91 #[must_use]
92 /// Returns the subscribed topic.
93 pub fn topic(&self) -> &UUri {
94 &self.topic
95 }
96
97 #[must_use]
98 /// Returns the subscriber's URI.
99 pub fn subscriber(&self) -> &UUri {
100 &self.subscriber
101 }
102
103 #[must_use]
104 /// Returns the subscription's current status.
105 pub fn status(&self) -> &SubscriptionStatus {
106 &self.status
107 }
108
109 #[must_use]
110 /// Returns the subscription's expiration time, if bounded.
111 pub fn expiration(&self) -> &Option<u64> {
112 &self.expiration
113 }
114
115 #[must_use]
116 /// Returns the minimum sample period, if rate-limited.
117 pub fn min_sample_period(&self) -> &Option<u32> {
118 &self.min_sample_period
119 }
120
121 /// Checks for a specific subscription status.
122 ///
123 /// # Examples
124 ///
125 /// ```rust
126 /// use up_rust::{communication::SubscriptionStatus, UUri};
127 /// use up_rust::core::usubscription::SubscriptionInfo;
128 ///
129 /// let subscription_info = SubscriptionInfo::new(
130 /// UUri::try_from("/A100/1/9000").unwrap(),
131 /// UUri::try_from("//subscriber/ABCD/1/0").unwrap(),
132 /// SubscriptionStatus::Subscribed,
133 /// None,
134 /// None,
135 /// );
136 /// assert!(subscription_info.has_status(SubscriptionStatus::Subscribed));
137 /// assert!(!subscription_info.has_status(SubscriptionStatus::Unsubscribed));
138 /// ```
139 #[must_use]
140 pub fn has_status(&self, state: SubscriptionStatus) -> bool {
141 self.status == state
142 }
143}
144
145/// Potential reasons for resetting the uSubscription service.
146#[derive(Debug, PartialEq)]
147#[repr(C)]
148pub enum ResetReason {
149 /// No reason specified.
150 Unspecified,
151 /// The service state was factory reset.
152 FactoryReset,
153 /// The service detected corrupted subscription data.
154 CorruptedData,
155}
156
157/// Gets a UUri referring to one of the local uSubscription service's resources.
158///
159/// # Examples
160///
161/// ```rust
162/// use up_rust::core::usubscription;
163///
164/// let uuri = usubscription::usubscription_uri(usubscription::RESOURCE_ID_SUBSCRIBE);
165/// assert_eq!(uuri.resource_id(), 0x0001);
166/// ```
167#[must_use]
168pub fn usubscription_uri(resource_id: u16) -> UUri {
169 UUri::try_from_parts(
170 "",
171 USUBSCRIPTION_TYPE_ID,
172 USUBSCRIPTION_VERSION_MAJOR,
173 resource_id,
174 )
175 .unwrap()
176}
177
178/// The uProtocol Application Layer client interface to the uSubscription service.
179///
180/// Please refer to the [uSubscription service specification](https://github.com/eclipse-uprotocol/up-spec/blob/main/up-l3/usubscription/v3/README.adoc)
181/// for details.
182///
183/// **Note** that in contrast to the uSubscription service specification, the functions defined in this trait only
184/// support commonly used input and output parameters of the operations defined in the specification. This is mainly
185/// due to the fact, that for many of the other parameters defined in the specification, it is not entirely clear if
186/// and how they should be used in practice. The next version of the uSubscription service specification will
187/// include a more detailed description of the operations and their parameters, which will then be reflected in the
188/// next version of this trait.
189#[cfg_attr(test, automock)]
190#[async_trait]
191pub trait USubscription: Send + Sync {
192 /// Subscribes to a topic.
193 ///
194 /// # Parameters
195 ///
196 /// * `topic` - The topic to subscribe to.
197 /// * `expiration` - The point in time at which the subscription expires (milliseconds since Unix epoch).
198 /// If not specified, the subscription is valid until explicitly unsubscribed.
199 /// * `min_sample_period` - The minimum duration (in seconds) between two events that should be maintained
200 /// for remote only topics. Device dispatchers use this attribute to reduce the
201 /// publication rates of events sent between devices.
202 /// This attribute is commonly used for mobile/cloud components subscribing to vehicle topics that are published
203 /// at a high rate. If the desired sampling period set by the subscriber is lower than the original publisher's
204 /// publication period, the attribute is ignored.
205 /// If not specified, the sampling period is set by the publisher.
206 ///
207 /// # Returns
208 ///
209 /// The outcome of the attempt to establish the subscription.
210 async fn subscribe(
211 &self,
212 topic: &UUri,
213 expiration: Option<u64>,
214 min_sample_period: Option<u32>,
215 ) -> Result<SubscriptionStatus, UStatus>;
216
217 /// Unsubscribes this client from a topic.
218 ///
219 /// # Parameters
220 ///
221 /// * `topic` - The topic to unsubscribe from.
222 ///
223 /// # Errors
224 ///
225 /// Returns an error if the attempt to unsubscribe has failed.
226 async fn unsubscribe(&self, topic: &UUri) -> Result<(), UStatus>;
227
228 /// Gets all (currently) active subscriptions for a given topic.
229 ///
230 /// # Parameters
231 ///
232 /// * `topic` - The topic to fetch subscriptions for.
233 ///
234 /// # Errors
235 ///
236 /// Returns an error if the attempt to retrieve the subscriptions has failed.
237 async fn fetch_subscriptions_by_topic(
238 &self,
239 topic: &UUri,
240 ) -> Result<Vec<SubscriptionInfo>, UStatus>;
241
242 /// Gets a uEntity's (currently) active subscriptions.
243 ///
244 /// # Parameters
245 ///
246 /// * `subscriber` - The uEntity to get the subscriptions for.
247 ///
248 /// # Errors
249 ///
250 /// Returns an error if the attempt to retrieve the subscriptions has failed.
251 async fn fetch_subscriptions_by_subscriber(
252 &self,
253 subscriber: &UUri,
254 ) -> Result<Vec<SubscriptionInfo>, UStatus>;
255
256 /// Registers this client for notifications about changes to the subscription status for a given topic.
257 ///
258 /// # Parameters
259 ///
260 /// * `topic` - The topic to receive changes to subscription status for.
261 ///
262 /// # Errors
263 ///
264 /// Returns an error if the attempt to register for notifications has failed.
265 async fn register_for_notifications(&self, topic: &UUri) -> Result<(), UStatus>;
266
267 /// Unregisters this client from notifications about changes to the subscription status for a given topic.
268 ///
269 /// # Parameters
270 ///
271 /// * `topic` - The topic to no longer receive changes to subscription status for.
272 ///
273 /// # Errors
274 ///
275 /// Returns an error if the attempt to unregister from notifications has failed.
276 async fn unregister_for_notifications(&self, topic: &UUri) -> Result<(), UStatus>;
277
278 /// Fetches a list of subscribers that are currently subscribed to a given topic.
279 ///
280 /// # Parameters
281 ///
282 /// * `topic` - The topic to fetch subscriptions for.
283 ///
284 /// # Returns
285 ///
286 /// A list of URIs representing the uEntities that are subscribed to the given topic.
287 ///
288 /// # Errors
289 ///
290 /// Returns an error if the attempt to fetch subscribers has failed.
291 async fn fetch_subscribers(&self, topic: &UUri) -> Result<Vec<UUri>, UStatus>;
292
293 /// Flushes all stored subscription information, including any persistently stored subscriptions.
294 ///
295 /// # Parameters
296 ///
297 /// * `reason` - The reason for the reset.
298 /// * `message` - An optional human-readable message providing additional context about the reset.
299 ///
300 /// # Errors
301 ///
302 /// Returns an error if the attempt to reset has failed.
303 async fn reset(&self, reason: ResetReason, message: Option<String>) -> Result<(), UStatus>;
304}