Skip to main content

imsg_session/
lifecycle.rs

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