mod control;
mod messages;
mod nav;
use bytes::Bytes;
use futures::{SinkExt, StreamExt};
use obex_core::client::ObexClient;
use obex_core::{wrap, ObexTransport};
use tokio::io::{AsyncRead, AsyncWrite};
use crate::MapError;
const MAP_UUID: [u8; 16] = [
0xbb, 0x58, 0x2b, 0x40, 0x42, 0x0c, 0x11, 0xdb, 0xb0, 0xde, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66,
];
const MAX_BODY_BYTES: usize = 4 * 1024 * 1024;
pub struct MapClient<T> {
obex: ObexClient,
transport: ObexTransport<T>,
depth: u8,
}
impl<T: AsyncRead + AsyncWrite + Unpin> MapClient<T> {
pub async fn connect(stream: T) -> Result<Self, MapError> {
let mut transport = wrap(stream);
let mut obex = ObexClient::new();
let req = ObexClient::connect_request(&MAP_UUID, None)?;
transport.send(req).await?;
let rsp = Self::recv(&mut transport).await?;
obex.handle_connect_response(&rsp)?;
Ok(Self { obex, transport, depth: 0 })
}
async fn recv(transport: &mut ObexTransport<T>) -> Result<Bytes, MapError> {
transport.next().await.ok_or(MapError::UnexpectedEof)?.map_err(MapError::Transport)
}
async fn collect_body(&mut self) -> Result<Vec<u8>, MapError> {
let mut body = Vec::with_capacity(512);
loop {
let rsp_bytes = Self::recv(&mut self.transport).await?;
let rsp = ObexClient::parse_response(&rsp_bytes)?;
if rsp.opcode.is_continue() {
if let Some(chunk) = rsp.body_payload() {
let new_len =
body.len().checked_add(chunk.len()).ok_or(MapError::ResponseTooLarge)?;
if new_len > MAX_BODY_BYTES {
return Err(MapError::ResponseTooLarge);
}
body.extend_from_slice(chunk);
}
let cont = self.obex.get_continue_request()?;
self.transport.send(cont).await?;
} else if rsp.opcode.is_ok() {
if let Some(chunk) = rsp.body_payload() {
let new_len =
body.len().checked_add(chunk.len()).ok_or(MapError::ResponseTooLarge)?;
if new_len > MAX_BODY_BYTES {
return Err(MapError::ResponseTooLarge);
}
body.extend_from_slice(chunk);
}
break;
} else {
return Err(MapError::ServerError(rsp.opcode.to_byte()));
}
}
Ok(body)
}
}