Skip to main content

imsg_session/
lifecycle.rs

1//! Connection lifecycle: RFCOMM connect, OBEX session establishment, and teardown, given an
2//! already-resolved device address and channel (SDP lookup happens in `imsg-transport::discover`).
3
4use std::time::Duration;
5
6use map_core::client::MapClient;
7use pbap_core::client::PbapClient;
8use tokio::io::{AsyncRead, AsyncWrite};
9use transport::rfcomm::DEFAULT_BT_CONNECTED_GATE;
10
11use crate::SessionError;
12
13/// OBEX CONNECT + enable MAP notifications. Caller must hold the returned client — iOS drops
14/// notification registration on OBEX DISCONNECT.
15///
16/// # Errors
17///
18/// Returns [`SessionError::Map`] on OBEX protocol error or server refusal.
19pub async fn establish_map_session<T: AsyncRead + AsyncWrite + Unpin>(
20    stream: T,
21) -> Result<MapClient<T>, SessionError> {
22    let mut client = MapClient::connect(stream).await.inspect_err(|e| {
23        tracing::warn!("MAP session: OBEX CONNECT failed: {e}");
24    })?;
25    tracing::debug!("MAP session: OBEX CONNECT ok, registering notifications");
26    client.set_notification_registration(true).await.inspect_err(|e| {
27        tracing::warn!("MAP session: notification registration failed: {e}");
28    })?;
29    tracing::debug!("MAP session: notification registration ok");
30    Ok(client)
31}
32
33/// RFCOMM connect to `addr`:`channel` (gating on `BT_CONNECTED` up to `bt_gate`, requesting
34/// `security` if given) then [`establish_map_session`].
35///
36/// # Errors
37///
38/// Returns [`SessionError::Transport`] on RFCOMM failure or `BT_CONNECTED` timeout,
39/// [`SessionError::Map`] on OBEX failure.
40pub async fn connect_map(
41    addr: bluer::Address,
42    channel: u8,
43    bt_gate: Duration,
44    security: Option<bluer::rfcomm::Security>,
45) -> Result<MapClient<bluer::rfcomm::Stream>, SessionError> {
46    let stream = transport::rfcomm::connect(addr, channel, bt_gate, security).await?;
47    establish_map_session(stream).await
48}
49
50/// RFCOMM connect to `addr`:`channel` then PBAP OBEX CONNECT.
51///
52/// # Errors
53///
54/// Returns [`SessionError::Transport`] on RFCOMM failure, [`SessionError::Pbap`] on OBEX failure.
55pub async fn connect_pbap(
56    addr: bluer::Address,
57    channel: u8,
58) -> Result<PbapClient<bluer::rfcomm::Stream>, SessionError> {
59    let stream = transport::rfcomm::connect(addr, channel, DEFAULT_BT_CONNECTED_GATE, None).await?;
60    let client = PbapClient::connect(stream).await?;
61    Ok(client)
62}