| // Copyright 2023 Google LLC | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | use crate::types::*; | 
 |  | 
 | use bt_common::{PeerId, Uuid}; | 
 | use futures::{Future, Stream}; | 
 |  | 
 | pub enum ServiceKind { | 
 |     Primary, | 
 |     Secondary, | 
 | } | 
 |  | 
 | // A short definition of a service that is either being published or has been discovered on a | 
 | // peer. | 
 | pub struct PeerServiceDefinition { | 
 |     /// Service Handle | 
 |     /// When publishing services, unique among all services published with [`Server::publish`]. | 
 |     pub id: u64, | 
 |     /// Whether the service is marked as Primary in the GATT server. | 
 |     pub kind: ServiceKind, | 
 |     /// The UUID identifying the type of service that this is. | 
 |     pub uuid: Uuid, | 
 | } | 
 |  | 
 | /// GATT Client connected to a particular peer. | 
 | /// Holding a struct that implements this should attempt to maintain a LE connection to the peer. | 
 | pub trait Client { | 
 |     type PeerServiceHandleT: PeerServiceHandle; | 
 |     type ServiceResultFut: Future<Output = Result<Vec<Self::PeerServiceHandleT>>> + 'static; | 
 |  | 
 |     /// The ID of the peer this is connected to. | 
 |     fn peer_id(&self) -> PeerId; | 
 |  | 
 |     /// Find services by UUID on the peer. | 
 |     /// This may cause as much as a full discovery of all services on the peer if the stack deems it | 
 |     /// appropriate. | 
 |     /// Service information should be up to date at the time returned. | 
 |     fn find_service(&self, uuid: Uuid) -> Self::ServiceResultFut; | 
 | } | 
 |  | 
 | pub trait PeerServiceHandle { | 
 |     type PeerServiceT: PeerService; | 
 |     type ConnectFut: Future<Output = Result<Self::PeerServiceT>>; | 
 |  | 
 |     fn uuid(&self) -> Uuid; | 
 |     fn is_primary(&self) -> bool; | 
 |     fn connect(&self) -> Self::ConnectFut; | 
 | } | 
 |  | 
 | pub struct CharacteristicNotification { | 
 |     pub handle: Handle, | 
 |     pub value: Vec<u8>, | 
 |     pub maybe_truncated: bool, | 
 | } | 
 |  | 
 | /// A connection to a GATT Service on a Peer. | 
 | /// All operations are done synchronously. | 
 | pub trait PeerService { | 
 |     type CharacteristicsFut: Future<Output = Result<Vec<Characteristic>>>; | 
 |     type NotificationStream: Stream<Item = Result<CharacteristicNotification>>; | 
 |     type ReadFut<'a>: Future<Output = Result<(usize, bool)>> + 'a; | 
 |     type WriteFut<'a>: Future<Output = Result<()>> + 'a; | 
 |  | 
 |     /// Discover characteristics on this service. | 
 |     /// If `uuid` is provided, only the characteristics matching `uuid` will be returned. | 
 |     /// This operation may use either the Discovery All Characteristics of a Service or | 
 |     /// Discovery Characteristic by UUID procedures, regardless of `uuid`. | 
 |     fn discover_characteristics(&self, uuid: Option<Uuid>) -> Self::CharacteristicsFut; | 
 |  | 
 |     /// Read a characteristic into a buffer, given the handle within the service. | 
 |     /// On success, returns the size read and whether the value may have been truncated. | 
 |     /// By default this will try to use a long read if the `buf` is larger than a normal read will | 
 |     /// allow (22 bytes) or if the offset is non-zero. | 
 |     fn read_characteristic<'a>( | 
 |         &self, | 
 |         handle: &Handle, | 
 |         offset: u16, | 
 |         buf: &'a mut [u8], | 
 |     ) -> Self::ReadFut<'a>; | 
 |  | 
 |     fn write_characteristic<'a>( | 
 |         &self, | 
 |         handle: &Handle, | 
 |         mode: WriteMode, | 
 |         offset: u16, | 
 |         buf: &'a [u8], | 
 |     ) -> Self::WriteFut<'a>; | 
 |  | 
 |     fn read_descriptor<'a>( | 
 |         &self, | 
 |         handle: &Handle, | 
 |         offset: u16, | 
 |         buf: &'a mut [u8], | 
 |     ) -> Self::ReadFut<'a>; | 
 |  | 
 |     fn write_descriptor<'a>( | 
 |         &self, | 
 |         handle: &Handle, | 
 |         offset: u16, | 
 |         buf: &'a [u8], | 
 |     ) -> Self::WriteFut<'a>; | 
 |  | 
 |     /// Subscribe to updates on a Characteristic. | 
 |     /// Either notifications or indications will be enabled depending on the properties available, | 
 |     /// with indications preferred if they are supported. | 
 |     /// Fails if the Characteristic doesn't support indications or notifications. | 
 |     /// Errors are delivered through an Err item in the stream. | 
 |     /// This will often write to the Client Characteristic Configuration descriptor for the | 
 |     /// Characteristic subscribed to. | 
 |     /// Updates sent from the peer wlil be delivered to the Stream returned. | 
 |     fn subscribe(&self, handle: &Handle) -> Self::NotificationStream; | 
 | } | 
 |  | 
 | /// Convenience class for communicating with characteristics on a remote peer. | 
 | pub struct ServiceCharacteristic<'a, PeerServiceT> { | 
 |     service: &'a PeerServiceT, | 
 |     characteristic: Characteristic, | 
 |     uuid: Uuid, | 
 | } | 
 |  | 
 | impl<'a, PeerServiceT: PeerService> ServiceCharacteristic<'a, PeerServiceT> { | 
 |     pub async fn find( | 
 |         service: &'a PeerServiceT, | 
 |         uuid: Uuid, | 
 |     ) -> Result<Vec<ServiceCharacteristic<'a, PeerServiceT>>> { | 
 |         let chrs = service.discover_characteristics(Some(uuid)).await?; | 
 |         Ok(chrs | 
 |             .into_iter() | 
 |             .map(|characteristic| Self { | 
 |                 service, | 
 |                 characteristic, | 
 |                 uuid, | 
 |             }) | 
 |             .collect()) | 
 |     } | 
 | } | 
 |  | 
 | impl<'a, PeerServiceT> ServiceCharacteristic<'a, PeerServiceT> { | 
 |     pub fn uuid(&self) -> Uuid { | 
 |         self.uuid | 
 |     } | 
 |  | 
 |     pub fn handle(&self) -> &Handle { | 
 |         &self.characteristic.handle | 
 |     } | 
 |  | 
 |     pub fn characteristic(&self) -> &Characteristic { | 
 |         &self.characteristic | 
 |     } | 
 | } | 
 |  | 
 | impl<'a, PeerServiceT: PeerService> ServiceCharacteristic<'a, PeerServiceT> { | 
 |     pub async fn read(&self, buf: &mut [u8]) -> Result<usize> { | 
 |         self.service | 
 |             .read_characteristic(self.handle(), 0, buf) | 
 |             .await | 
 |             .map(|(bytes, _)| bytes) | 
 |     } | 
 | } |