Skip to main content

steamkit/base/gc/
packet_base_gc.rs

1//! Game coordinator messages as received from the network, before the body is parsed.
2
3use crate::base::generated::steam_language_internal::{
4    MsgGCHdr, MsgGCHdrProtoBuf, SteamSerializableDeserialize,
5};
6use crate::base::msg_base::Reader;
7use crate::error::SteamError;
8use crate::types::job_id::JobID;
9
10/// A game coordinator message received from the network.
11pub trait IPacketGCMsg: Send + Sync {
12    /// Whether this packet message is protobuf backed.
13    fn is_proto(&self) -> bool;
14
15    /// The network message type of this packet message.
16    fn msg_type(&self) -> u32;
17
18    /// The target job id of this packet message.
19    fn target_job_id(&self) -> JobID;
20
21    /// The source job id of this packet message.
22    fn source_job_id(&self) -> JobID;
23
24    /// The raw bytes of the message.
25    fn get_data(&self) -> &[u8];
26}
27
28/// Returns the message type of `msg`, or an `InvalidArgument` error naming
29/// `name` if there is no message.
30pub fn get_msg_type_with_null_check(
31    msg: Option<&dyn IPacketGCMsg>,
32    name: &str,
33) -> Result<u32, SteamError> {
34    match msg {
35        Some(msg) => Ok(msg.msg_type()),
36        None => Err(SteamError::InvalidArgument(format!(
37            "{name} must not be null"
38        ))),
39    }
40}
41
42/// A protobuf-backed game coordinator packet.
43pub struct PacketClientGCMsgProtobuf {
44    msg_type: u32,
45    target_job_id: JobID,
46    source_job_id: JobID,
47    /// The parsed header of this packet.
48    pub(crate) header: MsgGCHdrProtoBuf,
49    payload: Vec<u8>,
50}
51
52impl PacketClientGCMsgProtobuf {
53    /// Parses the protobuf header of `data` so the job ids can be read.
54    pub fn new(e_msg: u32, data: Vec<u8>) -> Result<Self, SteamError> {
55        let mut reader = Reader::new(&data);
56        let header = MsgGCHdrProtoBuf::read(&mut reader)?;
57        Ok(PacketClientGCMsgProtobuf {
58            msg_type: e_msg,
59            target_job_id: JobID::from_value(header.proto.job_id_target.unwrap_or(u64::MAX)),
60            source_job_id: JobID::from_value(header.proto.job_id_source.unwrap_or(u64::MAX)),
61            header,
62            payload: data,
63        })
64    }
65
66    /// The header of this packet message.
67    pub fn header(&self) -> &MsgGCHdrProtoBuf {
68        &self.header
69    }
70}
71
72impl IPacketGCMsg for PacketClientGCMsgProtobuf {
73    fn is_proto(&self) -> bool {
74        true
75    }
76
77    fn msg_type(&self) -> u32 {
78        self.msg_type
79    }
80
81    fn target_job_id(&self) -> JobID {
82        self.target_job_id
83    }
84
85    fn source_job_id(&self) -> JobID {
86        self.source_job_id
87    }
88
89    fn get_data(&self) -> &[u8] {
90        &self.payload
91    }
92}
93
94/// A game coordinator packet with a plain header.
95pub struct PacketClientGCMsg {
96    msg_type: u32,
97    target_job_id: JobID,
98    source_job_id: JobID,
99    /// The parsed header of this packet.
100    pub(crate) header: MsgGCHdr,
101    payload: Vec<u8>,
102}
103
104impl PacketClientGCMsg {
105    /// Parses the GC header of `data` so the job ids can be read.
106    pub fn new(e_msg: u32, data: Vec<u8>) -> Result<Self, SteamError> {
107        let mut reader = Reader::new(&data);
108        let header = MsgGCHdr::read(&mut reader)?;
109        Ok(PacketClientGCMsg {
110            msg_type: e_msg,
111            target_job_id: JobID::from_value(header.target_job_id),
112            source_job_id: JobID::from_value(header.source_job_id),
113            header,
114            payload: data,
115        })
116    }
117
118    /// The header of this packet message.
119    pub fn header(&self) -> &MsgGCHdr {
120        &self.header
121    }
122}
123
124impl IPacketGCMsg for PacketClientGCMsg {
125    fn is_proto(&self) -> bool {
126        false
127    }
128
129    fn msg_type(&self) -> u32 {
130        self.msg_type
131    }
132
133    fn target_job_id(&self) -> JobID {
134        self.target_job_id
135    }
136
137    fn source_job_id(&self) -> JobID {
138        self.source_job_id
139    }
140
141    fn get_data(&self) -> &[u8] {
142        &self.payload
143    }
144}