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