connection-layer 0.0.2

Datagram Connection Hash Layer
Documentation
use crate::client_to_host::{ClientToHostCommands, ConnectRequest};
use crate::host_to_client::HostToClientCommands;
use crate::{verify_hash, write_to_stream, ConnectionId, ConnectionSecretSeed, RequestId, Version};
use datagram::{DatagramDecoder, DatagramEncoder};
use flood_rs::in_stream::InOctetStream;
use flood_rs::out_stream::OutOctetStream;
use flood_rs::{Deserialize, ReadOctetStream, Serialize};
use log::{debug, trace};
use std::io;

pub struct ConnectionInfo {
    pub connection_id: ConnectionId,
    pub seed: ConnectionSecretSeed,
}


pub struct ConnectionLayerClientCodec {
    pub connection_info: Option<ConnectionInfo>,
    pub request_id: RequestId,
}

impl ConnectionLayerClientCodec {
    pub fn new(request_id: RequestId) -> Self {
        Self {
            connection_info: None,
            request_id,
        }
    }
}


impl DatagramEncoder for ConnectionLayerClientCodec {
    fn encode(&mut self, buf: &[u8]) -> io::Result<Vec<u8>> {
        let mut stream = OutOctetStream::new();
        match &self.connection_info {
            None => {
                ConnectionId { value: 0 }.to_stream(&mut stream)?;
                let connect_request = ConnectRequest {
                    request_id: self.request_id,
                    version: Version { major: 0, minor: 2 },
                };
                debug!("client sending connect request {connect_request:?}");
                ClientToHostCommands::Connect(connect_request).serialize(&mut stream)?;
                trace!("send request {}", hexify::format_hex(stream.octets_ref()));
            }
            Some(connection_info) => {
                trace!(
                    "client sending payload connection_id: {} size: {}",
                    connection_info.connection_id.value,
                    buf.len()
                );

                write_to_stream(
                    &mut stream,
                    connection_info.connection_id,
                    connection_info.seed,
                    buf,
                )?
            }
        }
        flood_rs::WriteOctetStream::write(&mut stream, buf)?;

        Ok(stream.octets().to_vec())
    }
}

impl DatagramDecoder for ConnectionLayerClientCodec {
    fn decode(&mut self, buf: &[u8]) -> io::Result<Vec<u8>> {
        let mut in_stream = InOctetStream::new(buf);
        let connection_id = ConnectionId::from_stream(&mut in_stream)?;

        match &self.connection_info {
            None => {
                let command = HostToClientCommands::deserialize(&mut in_stream)?;
                match command {
                    HostToClientCommands::Connect(connect_response) => {
                        debug!("client received connect response {connect_response:?}");
                        self.connection_info = Some(ConnectionInfo {
                            connection_id: connect_response.connection_id,
                            seed: connect_response.seed,
                        })
                    }
                }
                Ok(buf[in_stream.cursor.position() as usize..].to_vec())
            }
            Some(connection_info) => {
                if connection_id != connection_info.connection_id {
                    Err(io::Error::new(io::ErrorKind::InvalidData, "problem"))
                } else {
                    let murmur = in_stream.read_u32()?;
                    verify_hash(murmur, connection_info.seed, &buf[5..])?;
                    debug!(
                        "client received payload size:{} connection:{}",
                        buf.len() - 5,
                        connection_id.value
                    );
                    Ok(buf[5..].to_vec())
                }
            }
        }
    }
}