bloop-protocol 1.0.0

Core implementation of the Bloop wire protocol
docs.rs failed to build bloop-protocol-1.0.0
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.

Bloop Protocol

Core implementation of the Bloop wire protocol (version 3), the binary request-response protocol spoken between Bloop clients (e.g. Bloop Boxes) and Bloop servers over TLS.

This crate is the single source of truth for the wire format. Server and client frameworks, as well as custom clients, build on it instead of hand-implementing framing and message layouts. The written specification lives in the protocol-spec repository.

Layers

  • Frames (frame): every message is message_type: u8 followed by a little-endian u32 payload length and the payload. read_frame and write_frame move RawMessage values over async streams, with a configurable maximum payload length on the read side.
  • Payload codec (codec): the Encode and Decode traits map values onto the packed payload layout. Implementations exist for the spec's primitives (integers, strings, UUIDs, IP addresses, NFC UIDs, data hashes); message structs derive both.
  • Message sets (set, message): a MessageSet dispatches raw frames into typed messages by opcode. ClientMessage and ServerMessage cover the standard protocol and take an extension set as a type parameter for custom messages.

Defining custom messages

Extensions own the opcode range 0x80 and above. A custom message is a derived struct; a message set groups them per wire direction:

use bloop_protocol::{ClientMessage, Decode, Encode, MessageSet, NfcUid, Payload};

#[derive(Debug, Encode, Decode, Payload)]
#[bloop(opcode = 0x82)]
struct RegisterTag {
    name: String,
    nfc_uid: NfcUid,
}

#[derive(Debug, MessageSet)]
enum CustomRequest {
    RegisterTag(RegisterTag),
}

// Plugs into the standard client-to-server set:
type Request = ClientMessage<CustomRequest>;

Fields encode in declaration order. Collections carry their count prefix width explicitly, matching the spec's two widths:

#[derive(Debug, Encode, Decode, Payload)]
#[bloop(opcode = 0x81)]
struct TagList {
    #[bloop(count = u8)]
    tags: Vec<TagEntry>,

    #[bloop(count = u32)]
    blob: Vec<u8>,
}

The MessageSet derive checks at compile time that opcodes are unique and, for extension sets, outside the reserved standard range. The standard ClientMessage/ServerMessage enums are built with the same derive: a variant holding a generic parameter (their Custom(Ext)) acts as a catch-all that delegates to the plugged-in extension set.

Reading and writing frames

use bloop_protocol::{ClientMessage, MessageSet, read_frame, write_frame};

// Client side: encode and send, then await the response.
let frame = message.encode()?;
write_frame(&mut stream, &frame).await?;

// Server side: read and dispatch.
let frame = read_frame(&mut stream, MAX_PAYLOAD_LEN).await?;
let message = ClientMessage::<CustomRequest>::decode(&frame)?;

Unknown opcodes and malformed payloads are distinct errors (MessageSetError::UnknownOpcode vs Malformed), so a server can answer an unexpected message gracefully instead of dropping the connection.

Features

Feature Description
hex Hex parsing (FromHex) for NFC UIDs and data hashes
md5 Conversion from md5::Digest into DataHash
serde Serde support, representing NFC UIDs and data hashes as hex strings (implies hex)

Workspace

  • bloop-protocol: the protocol implementation.
  • bloop-protocol-derive: the Encode, Decode, Payload and MessageSet derive macros, re-exported by bloop-protocol.