cmdproto 0.1.0

Protobuf message definitions for WebSocket-based applications
Documentation
use prost::Message;

mod error;

mod proto {
    include!(concat!(env!("OUT_DIR"), "/cmdproto.rs"));

    pub mod msg {
        include!(concat!(env!("OUT_DIR"), "/cmdproto.msg.rs"));
    }
}

pub use error::{Error, Result};
pub use proto::msg::*;
pub use proto::{Cmd, PacketToc, PacketTos};

/// 将内层消息打包成 client → server Packet bytes,直接送给 WebSocket
pub fn encode_tos<T: Message>(cmd: u32, seq: u32, msg: &T) -> Result<Vec<u8>> {
    let packet = PacketTos {
        cmd,
        seq,
        payload: msg.encode_to_vec(),
    };
    Ok(packet.encode_to_vec())
}

/// 将内层消息打包成 server → client Packet bytes,直接送给 WebSocket
pub fn encode_toc<T: Message>(cmd: u32, seq: u32, error_code: u32, msg: &T) -> Result<Vec<u8>> {
    let packet = PacketToc {
        cmd,
        seq,
        error_code,
        payload: msg.encode_to_vec(),
    };
    Ok(packet.encode_to_vec())
}

/// 从 WebSocket 收到的 bytes 解出 client → server Packet
pub fn decode_packet_tos(data: &[u8]) -> Result<PacketTos> {
    Ok(PacketTos::decode(data)?)
}

/// 从 WebSocket 收到的 bytes 解出 server → client Packet
pub fn decode_packet_toc(data: &[u8]) -> Result<PacketToc> {
    Ok(PacketToc::decode(data)?)
}

/// 从 PacketTos.payload 或 PacketToc.payload 解出具体消息
pub fn decode_payload<T: Message + Default>(payload: &[u8]) -> Result<T> {
    Ok(T::decode(payload)?)
}

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

    #[test]
    fn roundtrip_1001() {
        let req = M1001Tos {
            username: "alice".into(),
            password: "secret".into(),
        };
        let bytes = encode_tos(Cmd::Cmd1001 as u32, 1, &req).unwrap();

        let packet = decode_packet_tos(&bytes).unwrap();
        assert_eq!(packet.cmd, 1001);
        assert_eq!(packet.seq, 1);

        let decoded: M1001Tos = decode_payload(&packet.payload).unwrap();
        assert_eq!(decoded.username, "alice");
        assert_eq!(decoded.password, "secret");
    }

    #[test]
    fn roundtrip_1001_toc() {
        let resp = M1001Toc {
            code: 0,
            token: "token".into(),
            message: "ok".into(),
        };
        let bytes = encode_toc(Cmd::Cmd1001 as u32, 1, 7, &resp).unwrap();

        let packet = decode_packet_toc(&bytes).unwrap();
        assert_eq!(packet.cmd, 1001);
        assert_eq!(packet.seq, 1);
        assert_eq!(packet.error_code, 7);

        let decoded: M1001Toc = decode_payload(&packet.payload).unwrap();
        assert_eq!(decoded.code, 0);
        assert_eq!(decoded.token, "token");
        assert_eq!(decoded.message, "ok");
    }
}