enigma-protocol 0.1.0

High-level orchestrator that composes the Enigma crates into a production-ready messaging protocol
Documentation
use crate::error::Result;
use crate::tests::setup_clients;
use crate::types::{AttachmentKind, ClientEvent};

#[tokio::test]
async fn attachment_flow_is_ordered() -> Result<()> {
    let mut pair = setup_clients()?;
    let size = 200 * 1024;
    let mut payload = vec![0u8; size];
    for (i, byte) in payload.iter_mut().enumerate() {
        *byte = (i % 251) as u8;
    }
    let chunk_size = 8 * 1024;
    let chunks = ((payload.len() + chunk_size - 1) / chunk_size) as u32;
    let attachment_id = pair
        .alice
        .send_attachment_bytes(
            "bob",
            AttachmentKind::File,
            Some("blob.bin"),
            Some("application/octet-stream"),
            &payload,
            chunk_size,
        )
        .await?;
    let mut received_chunks = 0u32;
    let mut completed = false;
    let mut next_chunk_index = 0u32;
    while !completed {
        let event = pair.bob.poll_once().await?.expect("event");
        match event {
            ClientEvent::MessageReceived { message, .. } => match message.msg_type {
                enigma_packet::MessageType::AttachmentInit => {
                    if let enigma_packet::MessageMeta::AttachmentInit(meta) = message.meta {
                        assert_eq!(meta.chunk_count, chunks);
                        assert_eq!(meta.total_size, payload.len() as u64);
                        assert_eq!(meta.attachment_id, attachment_id);
                    } else {
                        panic!("missing attachment init meta");
                    }
                }
                enigma_packet::MessageType::AttachmentChunk => {
                    if let enigma_packet::MessageMeta::AttachmentChunk(meta) = message.meta {
                        assert_eq!(meta.index, next_chunk_index);
                        let start = (meta.index as usize) * chunk_size;
                        let end = usize::min(start + message.payload.len(), payload.len());
                        assert_eq!(&message.payload[..end - start], &payload[start..end]);
                        next_chunk_index += 1;
                    } else {
                        panic!("missing chunk meta");
                    }
                }
                enigma_packet::MessageType::AttachmentEnd => {
                    if let enigma_packet::MessageMeta::AttachmentEnd {
                        attachment_id: end_id,
                        chunk_count,
                        total_size,
                        ..
                    } = message.meta
                    {
                        assert_eq!(end_id, attachment_id);
                        assert_eq!(chunk_count, chunks);
                        assert_eq!(total_size, payload.len() as u64);
                    } else {
                        panic!("missing attachment end meta");
                    }
                }
                _ => {}
            },
            ClientEvent::AttachmentProgress {
                attachment_id: id,
                received_chunks: progress,
                total_chunks,
                ..
            } => {
                assert_eq!(id, attachment_id);
                assert_eq!(total_chunks, chunks);
                received_chunks = progress;
            }
            ClientEvent::AttachmentCompleted {
                attachment_id: id,
                total_size,
                ..
            } => {
                assert_eq!(id, attachment_id);
                assert_eq!(total_size, payload.len() as u64);
                completed = true;
            }
        }
    }
    assert_eq!(received_chunks, chunks);
    Ok(())
}