imsg_obex/lib.rs
1//! Sans-IO OBEX packet codec, framing, and client/server state machines.
2
3// Not covered by the workspace's `todo`/`unimplemented`/`panic` denials — scoped here rather
4// than workspace-wide since other crates (e.g. `cli`) still rely on `unreachable!()`.
5#![deny(clippy::unreachable)]
6
7use thiserror::Error;
8use tokio::io::{AsyncRead, AsyncWrite};
9use tokio_util::codec::Framed;
10
11/// OBEX client state machine — encodes requests and processes responses.
12pub mod client;
13/// OBEX length-prefix framing codec for [`tokio_util::codec::Framed`].
14pub mod codec;
15/// OBEX header types; wire tag bytes 0x01–0xCB.
16pub mod headers;
17/// Wire packet representation — opcode, fixed extra-byte section, and header list; plus codec errors.
18pub mod packet;
19/// OBEX server state machine — decodes requests and encodes responses.
20pub mod server;
21
22pub use codec::ObexCodec;
23
24/// OBEX framing errors — invalid length, unexpected EOF, and external transport failures.
25#[derive(Debug, Error)]
26pub enum TransportError {
27 /// OS-level socket error; check `kind()` for connection-refused, permission-denied, etc.
28 #[error("I/O: {0}")]
29 Io(#[from] std::io::Error),
30 /// Declared packet length is below the 3-byte OBEX minimum.
31 #[error("declared packet length {declared} is below the 3-byte OBEX minimum")]
32 InvalidLength {
33 /// The value read from wire bytes 1–2.
34 declared: usize,
35 },
36 /// Stream closed before a complete packet arrived.
37 #[error("unexpected end of stream")]
38 UnexpectedEof,
39 /// External transport driver error (QUIC, TLS, or other); carries the driver error message.
40 #[error("transport driver: {0}")]
41 External(String),
42}
43
44/// OBEX-framed async transport over any [`AsyncRead`] + [`AsyncWrite`] stream.
45///
46/// Yields and accepts complete OBEX packets as [`bytes::Bytes`]. Obtain via
47/// [`wrap`]; use `futures::SinkExt` / `futures::StreamExt` to send and receive.
48pub type ObexTransport<T> = Framed<T, ObexCodec>;
49
50/// Buffers reads until a complete OBEX packet arrives.
51pub fn wrap<T: AsyncRead + AsyncWrite>(inner: T) -> ObexTransport<T> {
52 Framed::new(inner, ObexCodec)
53}