obfs4 0.1.0-alpha.1

Pure rust implementation of the obfs4 pluggable transport
Documentation
use crate::{framing::*, proto::IAT};

use tokio::io::AsyncWrite;
use tokio::time;
use tokio_util::bytes::BytesMut;

///
pub struct FrameBuilder(FrameBuilderV<V1>);

const SEND_QUEUE_BUF_SIZE: usize = usize::pow(2, 15);

impl FrameBuilder {
    pub fn new(iat_mode: IAT) -> Self {
        Self {
            0: FrameBuilderV {
                iat_mode,
                write_queue: BytesMut::with_capacity(SEND_QUEUE_BUF_SIZE),
                _ver: V1 {
                    non_payload_queue: vec![],
                    last_heartbeat: time::Instant::now(),
                },
            },
        }
    }

    pub fn downgrade(mut self) -> FrameBuilderV<V0> {
        self.0.downgrade()
    }
}

///
struct V0 {}

///
struct V1 {
    non_payload_queue: Vec<Messages>,

    last_heartbeat: time::Instant,
}

trait FrameSenderVersion {}
impl FrameSenderVersion for V0 {}
impl FrameSenderVersion for V1 {}

///
struct FrameBuilderV<S: FrameSenderVersion> {
    ///
    iat_mode: IAT,

    ///
    write_queue: BytesMut,

    ///
    _ver: S,
}

impl FrameBuilderV<V1> {
    pub fn downgrade(self) -> FrameBuilderV<V0> {
        FrameBuilderV {
            iat_mode: self.iat_mode,
            write_queue: self.write_queue,
            _ver: V0 {},
        }
    }
}

impl AsyncWrite for FrameBuilderV<V1> {
    fn poll_write(
        self: std::pin::Pin<&mut Self>,
        cx: &mut std::task::Context<'_>,
        buf: &[u8],
    ) -> std::task::Poll<Result<usize, std::io::Error>> {
        todo!()
    }

    fn poll_flush(
        self: std::pin::Pin<&mut Self>,
        cx: &mut std::task::Context<'_>,
    ) -> std::task::Poll<Result<(), std::io::Error>> {
        todo!()
    }

    fn poll_shutdown(
        self: std::pin::Pin<&mut Self>,
        cx: &mut std::task::Context<'_>,
    ) -> std::task::Poll<Result<(), std::io::Error>> {
        todo!()
    }
}

impl FrameBuilderV<V0> {
    pub fn build_and_marshall() {}
}

impl AsyncWrite for FrameBuilderV<V0> {
    fn poll_write(
        self: std::pin::Pin<&mut Self>,
        cx: &mut std::task::Context<'_>,
        buf: &[u8],
    ) -> std::task::Poll<Result<usize, std::io::Error>> {
        todo!()
    }

    fn poll_flush(
        self: std::pin::Pin<&mut Self>,
        cx: &mut std::task::Context<'_>,
    ) -> std::task::Poll<Result<(), std::io::Error>> {
        todo!()
    }

    fn poll_shutdown(
        self: std::pin::Pin<&mut Self>,
        cx: &mut std::task::Context<'_>,
    ) -> std::task::Poll<Result<(), std::io::Error>> {
        todo!()
    }
}

#[cfg(test)]
mod testing {
    use super::*;
    use tokio::io::AsyncWriteExt;

    const MAX_FRAME_LENGTH: usize = MAX_SEGMENT_LENGTH - LENGTH_LENGTH;

    #[tokio::test]
    async fn build_frame_v0() {
        let test_msg_lengths = [0, 1, 2, MAX_FRAME_PAYLOAD_LENGTH, MAX_FRAME_LENGTH, MAX_SEGMENT_LENGTH,];

        let mut fb = FrameBuilder::new(IAT::Off).downgrade();

        for length in test_msg_lengths {
            let msg = vec![0_u8; length];

            fb.write_all(&msg).await.unwrap();
        }
    }

}