playit-agent-proto 1.2.0

Contains the protocol messages for a playit.gg agent
Documentation
use std::fmt::{Debug, Formatter};
use std::io::{Error, ErrorKind, Read, Write};
use std::net::SocketAddr;

use byteorder::{BigEndian, ReadBytesExt};
use message_encoding::MessageEncoding;

use crate::control_messages::ControlResponse;
use crate::rpc::ControlRpcMessage;

#[derive(Debug, Eq, PartialEq, Clone)]
pub enum ControlFeed {
    Response(ControlRpcMessage<ControlResponse>),
    NewClient(NewClient),
}

#[derive(Debug, Eq, PartialEq, Clone)]
pub struct NewClient {
    pub connect_addr: SocketAddr,
    pub peer_addr: SocketAddr,
    pub claim_instructions: ClaimInstructions,
    pub tunnel_server_id: u64,
    pub data_center_id: u32,
}

#[derive(Eq, PartialEq, Clone)]
pub struct ClaimInstructions {
    pub address: SocketAddr,
    pub token: Vec<u8>,
}

impl Debug for ClaimInstructions {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "ClaimInstructions {{ address: {}, token: {} }}", self.address, hex::encode(&self.token))
    }
}

impl MessageEncoding for ControlFeed {
    fn write_to<T: Write>(&self, out: &mut T) -> std::io::Result<usize> {
        let mut sum = 0;

        match self {
            ControlFeed::Response(res) => {
                sum += 1u32.write_to(out)?;
                sum += res.write_to(out)?;
            }
            ControlFeed::NewClient(client) => {
                sum += 2u32.write_to(out)?;
                sum += client.write_to(out)?;
            }
        }

        Ok(sum)
    }

    fn read_from<T: Read>(read: &mut T) -> std::io::Result<Self> {
        match read.read_u32::<BigEndian>()? {
            1 => Ok(ControlFeed::Response(ControlRpcMessage::read_from(read)?)),
            2 => Ok(ControlFeed::NewClient(NewClient::read_from(read)?)),
            _ => Err(Error::new(ErrorKind::Other, "invalid ControlFeed id")),
        }
    }
}

impl MessageEncoding for NewClient {
    fn write_to<T: Write>(&self, out: &mut T) -> std::io::Result<usize> {
        let mut sum = 0;
        sum += self.connect_addr.write_to(out)?;
        sum += self.peer_addr.write_to(out)?;
        sum += self.claim_instructions.write_to(out)?;
        sum += self.tunnel_server_id.write_to(out)?;
        sum += self.data_center_id.write_to(out)?;
        Ok(sum)
    }

    fn read_from<T: Read>(read: &mut T) -> std::io::Result<Self> {
        Ok(NewClient {
            connect_addr: SocketAddr::read_from(read)?,
            peer_addr: SocketAddr::read_from(read)?,
            claim_instructions: ClaimInstructions::read_from(read)?,
            tunnel_server_id: read.read_u64::<BigEndian>()?,
            data_center_id: read.read_u32::<BigEndian>()?,
        })
    }
}

impl MessageEncoding for ClaimInstructions {
    fn write_to<T: Write>(&self, out: &mut T) -> std::io::Result<usize> {
        let mut sum = 0;
        sum += self.address.write_to(out)?;
        sum += self.token.write_to(out)?;
        Ok(sum)
    }

    fn read_from<T: Read>(read: &mut T) -> std::io::Result<Self> {
        Ok(ClaimInstructions {
            address: SocketAddr::read_from(read)?,
            token: Vec::read_from(read)?,
        })
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn parse_control() {
        let data = "0000000204d1198d10046804d053c766cc4904d1198c029306000000000000004c2\
        c003cd1198d100468d053c766cc49cba8329c930664e9431200000000000000010000000000298c05779c\
        9306000000000e00000000000065b2000171012de0fdb1b6d5de58be82911b07bc00000000000065b20000000e";

        let bytes = hex::decode(data).unwrap();
        let mut reader = &bytes[..];
        let req = ControlFeed::read_from(&mut reader).unwrap();
        println!("{:?}", req);
    }
}