|
| 1 | +pub use crate::up_core_api::usubscription::{ |
| 2 | + subscription_status::State, EventDeliveryConfig, FetchSubscribersRequest, |
| 3 | + FetchSubscriptionsRequest, FetchSubscriptionsResponse, NotificationsRequest, |
| 4 | + SubscribeAttributes, SubscriberInfo, SubscriptionRequest, SubscriptionResponse, |
| 5 | + SubscriptionStatus, UnsubscribeRequest, |
| 6 | +}; |
| 7 | +use crate::UStatus; |
| 8 | +use async_trait::async_trait; |
| 9 | + |
| 10 | +/// `USubscription` is the uP-L3 client interface to the uSubscription service. |
| 11 | +/// |
| 12 | +/// A client would use a concrete implementation of `USubscription` typically to subscribe to |
| 13 | +/// a topic of interest and then unsubscribe when finished. |
| 14 | +/// |
| 15 | +/// Implementations of `USubscription` can be transport-specific to allow for flexibility and optimizations. |
| 16 | +/// |
| 17 | +/// # Examples |
| 18 | +/// |
| 19 | +/// ## Typical usage |
| 20 | +/// |
| 21 | +/// ``` |
| 22 | +/// # use async_trait::async_trait; |
| 23 | +/// # use std::future::Future; |
| 24 | +/// # use up_rust::{UMessage, Number, UAuthority, UEntity, UResource, UStatus, UUri, UListener}; |
| 25 | +/// # |
| 26 | +/// # mod up_client_foo { |
| 27 | +/// # use std::sync::Arc; |
| 28 | +/// # use up_rust::{UTransport, UListener, UStatus, UMessage, UUri}; |
| 29 | +/// # use async_trait::async_trait; |
| 30 | +/// # pub struct UPClientFoo; |
| 31 | +/// # |
| 32 | +/// # #[async_trait] |
| 33 | +/// # impl UTransport for UPClientFoo { |
| 34 | +/// # async fn send(&self, message: UMessage) -> Result<(), UStatus> { |
| 35 | +/// # todo!() |
| 36 | +/// # } |
| 37 | +/// # |
| 38 | +/// # async fn receive(&self, topic: UUri) -> Result<UMessage, UStatus> { |
| 39 | +/// # todo!() |
| 40 | +/// # } |
| 41 | +/// # |
| 42 | +/// # async fn register_listener(&self, topic: UUri, listener: Arc<dyn UListener>) -> Result<(), UStatus> { |
| 43 | +/// # Ok(()) |
| 44 | +/// # } |
| 45 | +/// # |
| 46 | +/// # async fn unregister_listener(&self, topic: UUri, listener: Arc<dyn UListener>) -> Result<(), UStatus> { |
| 47 | +/// # Ok(()) |
| 48 | +/// # } |
| 49 | +/// # } |
| 50 | +/// # |
| 51 | +/// # impl UPClientFoo { |
| 52 | +/// # pub fn new() -> Self { |
| 53 | +/// # Self |
| 54 | +/// # } |
| 55 | +/// # } |
| 56 | +/// # } |
| 57 | +/// # |
| 58 | +/// # mod usubscription_foo { |
| 59 | +/// # use async_trait::async_trait; |
| 60 | +/// # use protobuf::EnumOrUnknown; |
| 61 | +/// # use up_rust::{UStatus, UCode, |
| 62 | +/// # core::usubscription::{USubscription, FetchSubscribersRequest, FetchSubscriptionsRequest, |
| 63 | +/// # FetchSubscriptionsResponse, NotificationsRequest, SubscriptionRequest, |
| 64 | +/// # SubscriptionResponse, UnsubscribeRequest, SubscriptionStatus, State, |
| 65 | +/// # EventDeliveryConfig}, |
| 66 | +/// # }; |
| 67 | +/// # |
| 68 | +/// # pub struct USubscriptionFoo; |
| 69 | +/// # |
| 70 | +/// # #[async_trait] |
| 71 | +/// # impl USubscription for USubscriptionFoo { |
| 72 | +/// # async fn subscribe(&self, subscription_request: SubscriptionRequest) -> Result<SubscriptionResponse, UStatus> { |
| 73 | +/// # let subscription_status = SubscriptionStatus { |
| 74 | +/// # state: EnumOrUnknown::from(State::SUBSCRIBED), |
| 75 | +/// # code: EnumOrUnknown::from(UCode::OK), |
| 76 | +/// # message: "Subscription success".to_string(), |
| 77 | +/// # ..Default::default() |
| 78 | +/// # }; |
| 79 | +/// # |
| 80 | +/// # let event_delivery_config = EventDeliveryConfig { |
| 81 | +/// # id: "SUBSCRIPTION_TOPIC".to_string(), |
| 82 | +/// # type_: "Foo/Vehicle/EventHubs".to_string(), |
| 83 | +/// # attributes: Default::default(), |
| 84 | +/// # ..Default::default() |
| 85 | +/// # }; |
| 86 | +/// # |
| 87 | +/// # let subscription_response = SubscriptionResponse { |
| 88 | +/// # status: Some(subscription_status).into(), |
| 89 | +/// # config: Default::default(), |
| 90 | +/// # topic: Default::default(), |
| 91 | +/// # ..Default::default() |
| 92 | +/// # }; |
| 93 | +/// # |
| 94 | +/// # Ok(subscription_response) |
| 95 | +/// # } |
| 96 | +/// # |
| 97 | +/// # async fn unsubscribe(&self, unsubscribe_request: UnsubscribeRequest) -> Result<(), UStatus> { |
| 98 | +/// # Ok(()) |
| 99 | +/// # } |
| 100 | +/// # |
| 101 | +/// # async fn fetch_subscriptions(&self, fetch_subscriptions_request: FetchSubscriptionsRequest) -> Result<FetchSubscriptionsResponse, UStatus> { |
| 102 | +/// # todo!() |
| 103 | +/// # } |
| 104 | +/// # |
| 105 | +/// # async fn register_for_notifications(&self, notifications_request: NotificationsRequest) -> Result<(), UStatus> { |
| 106 | +/// # todo!() |
| 107 | +/// # } |
| 108 | +/// # |
| 109 | +/// # async fn unregister_for_notifications(&self, notifications_request: NotificationsRequest) -> Result<(), UStatus> { |
| 110 | +/// # todo!() |
| 111 | +/// # } |
| 112 | +/// # |
| 113 | +/// # async fn fetch_subscribers(&self, fetch_subscribers_request: FetchSubscribersRequest) -> Result<FetchSubscriptionsResponse, UStatus> { |
| 114 | +/// # todo!() |
| 115 | +/// # } |
| 116 | +/// # } |
| 117 | +/// # |
| 118 | +/// # impl USubscriptionFoo { |
| 119 | +/// # pub fn new() -> Self { |
| 120 | +/// # Self |
| 121 | +/// # } |
| 122 | +/// # } |
| 123 | +/// # } |
| 124 | +/// # |
| 125 | +/// # #[derive(Clone)] |
| 126 | +/// # pub struct MyListener; |
| 127 | +/// # |
| 128 | +/// # #[async_trait] |
| 129 | +/// # impl UListener for MyListener { |
| 130 | +/// # async fn on_receive(&self, msg: UMessage) { |
| 131 | +/// # todo!() |
| 132 | +/// # } |
| 133 | +/// # |
| 134 | +/// # async fn on_error(&self, err: UStatus) { |
| 135 | +/// # todo!() |
| 136 | +/// # } |
| 137 | +/// # |
| 138 | +/// # } |
| 139 | +/// # |
| 140 | +/// # impl MyListener { |
| 141 | +/// # pub fn new() -> Self { |
| 142 | +/// # Self |
| 143 | +/// # } |
| 144 | +/// # } |
| 145 | +/// # |
| 146 | +/// # #[async_std::main] |
| 147 | +/// # pub async fn main() -> Result<(), UStatus> { |
| 148 | +/// # |
| 149 | +/// # let my_uuri = Default::default(); |
| 150 | +/// # |
| 151 | +/// # let door_uuri = UUri { |
| 152 | +/// # authority: Some(UAuthority { |
| 153 | +/// # name: Some("device_a".to_string()), |
| 154 | +/// # number: Some(Number::Ip(vec![192, 168, 1, 200])), |
| 155 | +/// # ..Default::default() |
| 156 | +/// # }).into(), |
| 157 | +/// # entity: Some(UEntity{ |
| 158 | +/// # name: "body_access".to_string(), |
| 159 | +/// # id: Some(1), |
| 160 | +/// # version_major: Some(1), |
| 161 | +/// # ..Default::default()}).into(), |
| 162 | +/// # resource: Some(UResource { |
| 163 | +/// # name: "door".to_string(), |
| 164 | +/// # instance: Some("open_status".to_string()), |
| 165 | +/// # message: None, |
| 166 | +/// # id: Some(2), |
| 167 | +/// # ..Default::default()}).into(), |
| 168 | +/// # ..Default::default()}; |
| 169 | +/// # |
| 170 | +/// # let my_listener = Arc::new(MyListener::new()); |
| 171 | +/// # |
| 172 | +/// # let up_client = up_client_foo::UPClientFoo::new(); |
| 173 | +/// # |
| 174 | +/// use std::sync::Arc; |
| 175 | +/// use up_rust::{UCode, UTransport, |
| 176 | +/// core::usubscription::{USubscription, UnsubscribeRequest, SubscribeAttributes, |
| 177 | +/// SubscriberInfo, SubscriptionRequest, SubscriptionResponse}, |
| 178 | +/// }; |
| 179 | +/// |
| 180 | +/// let usub = usubscription_foo::USubscriptionFoo::new(); |
| 181 | +/// |
| 182 | +/// let subscriber_info = SubscriberInfo { |
| 183 | +/// uri: my_uuri, |
| 184 | +/// ..Default::default() |
| 185 | +/// }; |
| 186 | +/// |
| 187 | +/// let subscribe_attributes = SubscribeAttributes { |
| 188 | +/// sample_period_ms: Some(5000), // we want to hear about this every 5 seconds |
| 189 | +/// ..Default::default() |
| 190 | +/// }; |
| 191 | +/// |
| 192 | +/// let subscription_request = SubscriptionRequest { |
| 193 | +/// topic: Some(door_uuri.clone()).into(), |
| 194 | +/// subscriber: Some(subscriber_info.clone()).into(), |
| 195 | +/// attributes: Some(subscribe_attributes).into(), |
| 196 | +/// ..Default::default() |
| 197 | +/// }; |
| 198 | +/// |
| 199 | +/// let subscription_response = usub.subscribe(subscription_request).await?; |
| 200 | +/// let success_code = subscription_response.status.code.enum_value_or(UCode::UNKNOWN); |
| 201 | +/// if success_code == UCode::OK { |
| 202 | +/// let register_success = up_client.register_listener(door_uuri.clone(), my_listener.clone()).await; |
| 203 | +/// } else { |
| 204 | +/// match success_code { |
| 205 | +/// UCode::NOT_FOUND => { /* handle topic not found */ } |
| 206 | +/// _ => { /* handle other error conditions */ } |
| 207 | +/// } |
| 208 | +/// } |
| 209 | +/// // sometime later when done with this topic |
| 210 | +/// let unsubscribe_request = UnsubscribeRequest { |
| 211 | +/// topic: Some(door_uuri.clone()).into(), |
| 212 | +/// subscriber: Some(subscriber_info.clone()).into(), |
| 213 | +/// ..Default::default() |
| 214 | +/// }; |
| 215 | +/// let unsubscribe_result = usub.unsubscribe(unsubscribe_request).await?; |
| 216 | +/// let unregister_success = up_client.register_listener(door_uuri.clone(), my_listener.clone()).await; |
| 217 | +/// # |
| 218 | +/// # Ok(()) |
| 219 | +/// # } |
| 220 | +/// ``` |
| 221 | +/// |
| 222 | +/// For more information, please refer to the [uProtocol Specification](https://github.com/eclipse-uprotocol/up-spec/blob/main/up-l3/usubscription/v3/README.adoc) |
| 223 | +/// and [uProtocol APIs](https://github.com/eclipse-uprotocol/up-spec/blob/main/up-core-api/uprotocol/core/usubscription/v3/usubscription.proto) |
| 224 | +#[async_trait] |
| 225 | +pub trait USubscription: Send + Sync { |
| 226 | + /// Subscribe to a topic, using a [`SubscriptionRequest`] |
| 227 | + /// |
| 228 | + /// # Parameters |
| 229 | + /// |
| 230 | + /// * `subscription_request` - A request to subscribe |
| 231 | + /// |
| 232 | + /// # Returns |
| 233 | + /// |
| 234 | + /// * [`SubscriptionResponse`] detailing if subscription was successful with other metadata |
| 235 | + async fn subscribe( |
| 236 | + &self, |
| 237 | + subscription_request: SubscriptionRequest, |
| 238 | + ) -> Result<SubscriptionResponse, UStatus>; |
| 239 | + |
| 240 | + /// Unsubscribe to a topic, using an [`UnsubscribeRequest`] |
| 241 | + /// |
| 242 | + /// # Parameters |
| 243 | + /// |
| 244 | + /// * `unsubscribe_request` - A request to unsubscribe |
| 245 | + /// |
| 246 | + /// # Returns |
| 247 | + /// |
| 248 | + /// * [`UStatus`] detailing if unsubscription was successful and if not why not |
| 249 | + async fn unsubscribe(&self, unsubscribe_request: UnsubscribeRequest) -> Result<(), UStatus>; |
| 250 | + |
| 251 | + /// Fetch all subscriptions for a given topic or subscriber contained inside a [`FetchSubscriptionsRequest`] |
| 252 | + /// |
| 253 | + /// # Parameters |
| 254 | + /// |
| 255 | + /// * `fetch_subscriptions_request` - A request to fetch subscriptions given a topic or subscriber |
| 256 | + /// |
| 257 | + /// # Returns |
| 258 | + /// |
| 259 | + /// * [`FetchSubscriptionsResponse`] detailing the zero or more subscriptions' info |
| 260 | + async fn fetch_subscriptions( |
| 261 | + &self, |
| 262 | + fetch_subscriptions_request: FetchSubscriptionsRequest, |
| 263 | + ) -> Result<FetchSubscriptionsResponse, UStatus>; |
| 264 | + |
| 265 | + /// Register for notifications relevant to a given topic inside a [`NotificationsRequest`] |
| 266 | + /// changing in subscription status. |
| 267 | + /// |
| 268 | + /// # Parameters |
| 269 | + /// |
| 270 | + /// * `notifications_register_request` - A request to receive changes to subscription status |
| 271 | + /// |
| 272 | + /// # Returns |
| 273 | + /// |
| 274 | + /// * [`UStatus`] detailing if notification registration was successful and if not why not |
| 275 | + async fn register_for_notifications( |
| 276 | + &self, |
| 277 | + notifications_register_request: NotificationsRequest, |
| 278 | + ) -> Result<(), UStatus>; |
| 279 | + |
| 280 | + /// Unregister for notifications relevant to a given topic inside a [`NotificationsRequest`] |
| 281 | + /// changing in subscription status. |
| 282 | + /// |
| 283 | + /// # Parameters |
| 284 | + /// |
| 285 | + /// * `notifications_unregister_request` - A request to no longer receive changes to subscription status |
| 286 | + /// |
| 287 | + /// # Returns |
| 288 | + /// |
| 289 | + /// * [`UStatus`] detailing if notification unregistration was successful and if not why not |
| 290 | + async fn unregister_for_notifications( |
| 291 | + &self, |
| 292 | + notifications_unregister_request: NotificationsRequest, |
| 293 | + ) -> Result<(), UStatus>; |
| 294 | + |
| 295 | + /// Fetch a list of subscribers that are currently subscribed to a given topic in a [`FetchSubscribersRequest`] |
| 296 | + /// |
| 297 | + /// # Parameters |
| 298 | + /// |
| 299 | + /// * `fetch_subscribers_request` - Request containing topic for which we'd like all subscribers' info |
| 300 | + /// |
| 301 | + /// # Returns |
| 302 | + /// |
| 303 | + /// * [`FetchSubscriptionsResponse`] detailing subscriber info for the provided topic |
| 304 | + async fn fetch_subscribers( |
| 305 | + &self, |
| 306 | + fetch_subscribers_request: FetchSubscribersRequest, |
| 307 | + ) -> Result<FetchSubscriptionsResponse, UStatus>; |
| 308 | +} |
0 commit comments