Preview of the proposed up-rust native-frame-model branch (up-rust b6b99c6d, up-spec f0e9b17) — not released documentation. branch · write-up

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}