blaze_pk/
packet.rs

1//! Packet implementation for creating [`Packet`]s along with types
2//! used by the router for creating and decoding contents / responses
3//!
4//! Also contains the decoding and encoding logic for tokio codec
5//! [`PacketCodec`]
6
7use crate::{
8    codec::{Decodable, Encodable},
9    error::DecodeResult,
10    reader::TdfReader,
11};
12use bytes::{Buf, BufMut, Bytes, BytesMut};
13use std::{fmt::Debug, hash::Hash, sync::Arc};
14use std::{io, ops::Deref};
15use tokio_util::codec::{Decoder, Encoder};
16
17/// Trait implemented by structures that can be used as packet components
18pub trait PacketComponents: Debug + Hash + Eq + Sized {
19    /// Converts the packet component into the ID of the
20    /// component, and command
21    fn values(&self) -> (u16, u16);
22
23    /// Decodes the packet component using the provided component id,
24    /// command id, and whether the packet is a notify packet
25    ///
26    /// `component` The packet component
27    /// `command`   The packet command
28    /// `notify`    Whether the packet is a notify packet
29    fn from_values(component: u16, command: u16, notify: bool) -> Option<Self>;
30
31    /// Decodes the packet component using the details stored in the provided
32    /// packet header
33    ///
34    /// `header` The packet header to decode from
35    fn from_header(header: &PacketHeader) -> Option<Self> {
36        Self::from_values(
37            header.component,
38            header.command,
39            matches!(&header.ty, PacketType::Notify),
40        )
41    }
42}
43
44/// Trait for implementing packet target details
45pub trait PacketComponent: Debug + Hash + Eq + Sized {
46    // Converts the component command value into its u16 value
47    fn command(&self) -> u16;
48
49    /// Finds a component with the matching value based on whether
50    /// the packet is a notify packet or not
51    ///
52    /// `value`  The component value
53    /// `notify` Whether the packet was a notify packet
54    fn from_value(value: u16, notify: bool) -> Option<Self>;
55}
56
57/// The different types of packets
58#[derive(Debug, Copy, Clone, PartialEq, Eq)]
59#[repr(u8)]
60pub enum PacketType {
61    /// ID counted request packets (0x00)
62    Request = 0x00,
63    /// Packets responding to requests (0x10)
64    Response = 0x10,
65    /// Unique packets coming from the server (0x20)
66    Notify = 0x20,
67    /// Error packets (0x30)
68    Error = 0x30,
69}
70
71/// From u8 implementation to convert bytes back into
72/// PacketTypes
73impl From<u8> for PacketType {
74    fn from(value: u8) -> Self {
75        match value {
76            0x00 => PacketType::Request,
77            0x10 => PacketType::Response,
78            0x20 => PacketType::Notify,
79            0x30 => PacketType::Error,
80            // Default type fallback to request
81            _ => PacketType::Request,
82        }
83    }
84}
85
86/// Structure of packet header which comes before the
87/// packet content and describes it.
88#[derive(Debug, Copy, Clone, PartialEq, Eq)]
89pub struct PacketHeader {
90    /// The component of this packet
91    pub component: u16,
92    /// The command of this packet
93    pub command: u16,
94    /// A possible error this packet contains (zero is none)
95    pub error: u16,
96    /// The type of this packet
97    pub ty: PacketType,
98    /// The unique ID of this packet (Notify packets this is just zero)
99    pub id: u16,
100}
101
102impl PacketHeader {
103    /// Creates a notify header for the provided component and command
104    ///
105    /// `component` The component to use
106    /// `command`   The command to use
107    pub const fn notify(component: u16, command: u16) -> Self {
108        Self {
109            component,
110            command,
111            error: 0,
112            ty: PacketType::Notify,
113            id: 0,
114        }
115    }
116
117    /// Creates a request header for the provided id, component
118    /// and command
119    ///
120    /// `id`        The packet ID
121    /// `component` The component to use
122    /// `command`   The command to use
123    pub const fn request(id: u16, component: u16, command: u16) -> Self {
124        Self {
125            component,
126            command,
127            error: 0,
128            ty: PacketType::Request,
129            id,
130        }
131    }
132
133    /// Creates a response to the provided packet header by
134    /// changing the type of the header
135    pub const fn response(&self) -> Self {
136        self.with_type(PacketType::Response)
137    }
138
139    /// Copies the header contents changing its Packet Type
140    ///
141    /// `ty` The new packet type
142    pub const fn with_type(&self, ty: PacketType) -> Self {
143        Self {
144            component: self.component,
145            command: self.command,
146            error: self.error,
147            ty,
148            id: self.id,
149        }
150    }
151
152    /// Copies the header contents changing its Packet Type
153    pub const fn with_error(&self, error: u16) -> Self {
154        Self {
155            component: self.component,
156            command: self.command,
157            error,
158            ty: PacketType::Error,
159            id: self.id,
160        }
161    }
162
163    /// Checks if the component and command of this packet header matches
164    /// that of the other packet header
165    ///
166    /// `other` The packet header to compare to
167    pub fn path_matches(&self, other: &PacketHeader) -> bool {
168        self.component.eq(&other.component) && self.command.eq(&other.command)
169    }
170
171    /// Encodes the contents of this header appending to the
172    /// output source
173    ///
174    /// `dst`    The dst to append the bytes to
175    /// `length` The length of the content after the header
176    pub fn write(&self, dst: &mut BytesMut, length: usize) {
177        let is_extended = length > 0xFFFF;
178        dst.put_u16(length as u16);
179        dst.put_u16(self.component);
180        dst.put_u16(self.command);
181        dst.put_u16(self.error);
182        dst.put_u8(self.ty as u8);
183        dst.put_u8(if is_extended { 0x10 } else { 0x00 });
184        dst.put_u16(self.id);
185        if is_extended {
186            dst.put_u8(((length & 0xFF000000) >> 24) as u8);
187            dst.put_u8(((length & 0x00FF0000) >> 16) as u8);
188        }
189    }
190
191    /// Attempts to read the packet header from the provided
192    /// source bytes returning None if there aren't enough bytes
193    ///
194    /// `src` The bytes to read from
195    pub fn read(src: &mut BytesMut) -> Option<(PacketHeader, usize)> {
196        if src.len() < 12 {
197            return None;
198        }
199
200        let mut length = src.get_u16() as usize;
201        let component = src.get_u16();
202        let command = src.get_u16();
203        let error = src.get_u16();
204        let ty = src.get_u8();
205        // If we encounter 0x10 here then the packet contains extended length
206        // bytes so its longer than a u16::MAX length
207        let is_extended = src.get_u8() == 0x10;
208        let id = src.get_u16();
209
210        if is_extended {
211            // We need another two bytes for the extended length
212            if src.len() < 2 {
213                return None;
214            }
215            length += src.get_u16() as usize;
216        }
217
218        let ty = PacketType::from(ty);
219        let header = PacketHeader {
220            component,
221            command,
222            error,
223            ty,
224            id,
225        };
226        Some((header, length))
227    }
228}
229
230/// Structure for Blaze packets contains the contents of the packet
231/// and the header for identification.
232///
233/// Packets can be cloned with little memory usage increase because
234/// the content is stored as Bytes.
235#[derive(Debug, Clone)]
236pub struct Packet {
237    /// The packet header
238    pub header: PacketHeader,
239    /// The packet encoded byte contents
240    pub contents: Bytes,
241}
242
243impl Packet {
244    /// Creates a packet from its raw components
245    ///
246    /// `header`   The packet header
247    /// `contents` The encoded packet contents
248    pub fn raw(header: PacketHeader, contents: Vec<u8>) -> Self {
249        Self {
250            header,
251            contents: Bytes::from(contents),
252        }
253    }
254
255    /// Creates a packet from its raw components
256    /// where the contents are empty
257    ///
258    /// `header` The packet header
259    pub const fn raw_empty(header: PacketHeader) -> Self {
260        Self {
261            header,
262            contents: Bytes::new(),
263        }
264    }
265
266    /// Creates a packet responding to the provided packet.
267    /// Clones the header of the request packet and changes
268    /// the type to repsonse
269    ///
270    /// `packet`   The packet to respond to
271    /// `contents` The contents to encode for the packet
272    pub fn response<C: Encodable>(packet: &Packet, contents: C) -> Self {
273        Self {
274            header: packet.header.response(),
275            contents: Bytes::from(contents.encode_bytes()),
276        }
277    }
278
279    /// Creates a packet responding to the current packet.
280    /// Clones the header of the request packet and changes
281    /// the type to repsonse
282    ///
283    /// `packet`   The packet to respond to
284    /// `contents` The contents to encode for the packet
285    pub fn respond<C: Encodable>(&self, contents: C) -> Self {
286        Self::response(self, contents)
287    }
288
289    /// Creates a response packet responding to the provided packet
290    /// but with raw contents that have already been encoded.
291    ///
292    /// `packet`   The packet to respond to
293    /// `contents` The raw encoded packet contents
294    pub fn response_raw(packet: &Packet, contents: Vec<u8>) -> Self {
295        Self {
296            header: packet.header.response(),
297            contents: Bytes::from(contents),
298        }
299    }
300
301    /// Creates a response packet responding to the provided packet
302    /// but with empty contents.
303    ///
304    /// `packet` The packet to respond to
305    pub const fn response_empty(packet: &Packet) -> Self {
306        Self {
307            header: packet.header.response(),
308            contents: Bytes::new(),
309        }
310    }
311
312    /// Creates a response packet responding to the provided packet
313    /// but with empty contents.
314    ///
315    /// `packet`   The packet to respond to
316    /// `contents` The contents to encode for the packet
317    pub const fn respond_empty(&self) -> Self {
318        Self::response_empty(self)
319    }
320
321    /// Creates a error respond packet responding to the provided
322    /// packet with the provided error and contents
323    ///
324    /// `packet`   The packet to respond to
325    /// `error`    The response error value
326    /// `contents` The response contents
327    pub fn error<C: Encodable>(packet: &Packet, error: u16, contents: C) -> Self {
328        Self {
329            header: packet.header.with_error(error),
330            contents: Bytes::from(contents.encode_bytes()),
331        }
332    }
333
334    /// Creates a error respond packet responding to the provided
335    /// packet with the provided error and contents
336    ///
337    /// `packet`   The packet to respond to
338    /// `error`    The response error value
339    /// `contents` The response contents
340    pub fn respond_error<C: Encodable>(&self, error: u16, contents: C) -> Self {
341        Self::error(self, error, contents)
342    }
343
344    /// Creates a error respond packet responding to the provided
345    /// packet with the provided error and raw encoded contents
346    ///
347    /// `packet`   The packet to respond to
348    /// `error`    The response error value
349    /// `contents` The raw encoded contents
350    pub fn error_raw(packet: &Packet, error: u16, contents: Vec<u8>) -> Self {
351        Self {
352            header: packet.header.with_error(error),
353            contents: Bytes::from(contents),
354        }
355    }
356
357    /// Creates a error respond packet responding to the provided
358    /// packet with the provided error with empty contents
359    ///
360    /// `packet`   The packet to respond to
361    /// `error`    The response error value
362    pub const fn error_empty(packet: &Packet, error: u16) -> Packet {
363        Self {
364            header: packet.header.with_error(error),
365            contents: Bytes::new(),
366        }
367    }
368
369    /// Creates a error respond packet responding to the provided
370    /// packet with the provided error with empty contents
371    ///
372    /// `packet`   The packet to respond to
373    /// `error`    The response error value
374    pub const fn respond_error_empty(&self, error: u16) -> Packet {
375        Self::error_empty(self, error)
376    }
377
378    /// Creates a notify packet for the provided component with the
379    /// provided contents.
380    ///
381    /// `component` The packet component to use for the header
382    /// `contents`  The contents of the packet to encode
383    pub fn notify<C: Encodable, T: PacketComponents>(component: T, contents: C) -> Packet {
384        let (component, command) = component.values();
385        Self {
386            header: PacketHeader::notify(component, command),
387            contents: Bytes::from(contents.encode_bytes()),
388        }
389    }
390
391    /// Creates a notify packet for the provided component with the
392    /// provided raw encoded contents.
393    ///
394    /// `component` The packet component
395    /// `contents`  The encoded packet contents
396    pub fn notify_raw<T: PacketComponents>(component: T, contents: Vec<u8>) -> Packet {
397        let (component, command) = component.values();
398        Self {
399            header: PacketHeader::notify(component, command),
400            contents: Bytes::from(contents),
401        }
402    }
403
404    /// Creates a notify packet for the provided component with
405    /// empty contents
406    ///
407    /// `component` The packet component
408    pub fn notify_empty<T: PacketComponents>(component: T) -> Packet {
409        let (component, command) = component.values();
410        Self {
411            header: PacketHeader::notify(component, command),
412            contents: Bytes::new(),
413        }
414    }
415
416    /// Creates a new request packet from the provided id, component, and contents
417    ///
418    /// `id`        The packet id
419    /// `component` The packet component
420    /// `contents`  The packet contents
421    pub fn request<C: Encodable, T: PacketComponents>(
422        id: u16,
423        component: T,
424        contents: C,
425    ) -> Packet {
426        let (component, command) = component.values();
427        Self {
428            header: PacketHeader::request(id, component, command),
429            contents: Bytes::from(contents.encode_bytes()),
430        }
431    }
432
433    /// Creates a new request packet from the provided id, component
434    /// with raw encoded contents
435    ///
436    /// `id`        The packet id
437    /// `component` The packet component
438    /// `contents`  The raw encoded contents
439    pub fn request_raw<T: PacketComponents>(id: u16, component: T, contents: Vec<u8>) -> Packet {
440        let (component, command) = component.values();
441        Self {
442            header: PacketHeader::request(id, component, command),
443            contents: Bytes::from(contents),
444        }
445    }
446
447    /// Creates a new request packet from the provided id, component
448    /// with empty contents
449    ///
450    /// `id`        The packet id
451    /// `component` The packet component
452    /// `contents`  The packet contents
453    pub fn request_empty<T: PacketComponents>(id: u16, component: T) -> Packet {
454        let (component, command) = component.values();
455        Self {
456            header: PacketHeader::request(id, component, command),
457            contents: Bytes::new(),
458        }
459    }
460
461    /// Attempts to decode the contents bytes of this packet into the
462    /// provided Codec type value.
463    pub fn decode<C: Decodable>(&self) -> DecodeResult<C> {
464        let mut reader = TdfReader::new(&self.contents);
465        C::decode(&mut reader)
466    }
467
468    /// Attempts to read a packet from the provided
469    /// bytes source
470    ///
471    /// `src` The bytes to read from
472    pub fn read(src: &mut BytesMut) -> Option<Self> {
473        let (header, length) = PacketHeader::read(src)?;
474
475        if src.len() < length {
476            return None;
477        }
478
479        let contents = src.split_to(length);
480        Some(Self {
481            header,
482            contents: contents.freeze(),
483        })
484    }
485
486    /// Writes the contents and header of the packet
487    /// onto the dst source of bytes
488    ///
489    /// `dst` The destination buffer
490    pub fn write(&self, dst: &mut BytesMut) {
491        let contents = &self.contents;
492        self.header.write(dst, contents.len());
493        dst.extend_from_slice(contents);
494    }
495}
496
497/// Tokio codec for encoding and decoding packets
498pub struct PacketCodec;
499
500/// Decoder implementation
501impl Decoder for PacketCodec {
502    type Error = io::Error;
503    type Item = Packet;
504
505    fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
506        let mut read_src = src.clone();
507        let result = Packet::read(&mut read_src);
508
509        if result.is_some() {
510            *src = read_src;
511        }
512
513        Ok(result)
514    }
515}
516
517/// Encoder implementation for owned packets
518impl Encoder<Packet> for PacketCodec {
519    type Error = io::Error;
520
521    fn encode(&mut self, item: Packet, dst: &mut BytesMut) -> Result<(), Self::Error> {
522        item.write(dst);
523        Ok(())
524    }
525}
526
527/// Encoder implementation for borrowed packets
528impl Encoder<&Packet> for PacketCodec {
529    type Error = io::Error;
530
531    fn encode(&mut self, item: &Packet, dst: &mut BytesMut) -> Result<(), Self::Error> {
532        item.write(dst);
533        Ok(())
534    }
535}
536
537/// Encoder implementation for arc reference packets
538impl Encoder<Arc<Packet>> for PacketCodec {
539    type Error = io::Error;
540
541    fn encode(&mut self, item: Arc<Packet>, dst: &mut BytesMut) -> Result<(), Self::Error> {
542        item.write(dst);
543        Ok(())
544    }
545}
546
547/// Structure wrapping a from request type to include a packet
548/// header to allow the response type to be created
549pub struct Request<T: FromRequest> {
550    /// The decoded request type
551    pub req: T,
552    /// The packet header from the request
553    pub header: PacketHeader,
554}
555
556/// Deref implementation so that the request fields can be
557/// directly accessed
558impl<T: FromRequest> Deref for Request<T> {
559    type Target = T;
560
561    fn deref(&self) -> &Self::Target {
562        &self.req
563    }
564}
565
566impl<T: FromRequest> Request<T> {
567    /// Creates a response from the provided response type value
568    /// returning a Response structure which can be used as a Route
569    /// repsonse
570    ///
571    /// `res` The into response type implementation
572    pub fn response<E>(&self, res: E) -> Response
573    where
574        E: Encodable,
575    {
576        Response(Packet {
577            header: self.header.response(),
578            contents: Bytes::from(res.encode_bytes()),
579        })
580    }
581}
582
583/// Wrapping structure for raw Bytes structures that can
584/// be used as packet response
585pub struct PacketBody(Bytes);
586
587impl<T> From<T> for PacketBody
588where
589    T: Encodable,
590{
591    fn from(value: T) -> Self {
592        let bytes = value.encode_bytes();
593        let bytes = Bytes::from(bytes);
594        PacketBody(bytes)
595    }
596}
597
598/// Type for route responses that have already been turned into
599/// packets usually for lifetime reasons
600pub struct Response(Packet);
601
602impl IntoResponse for Response {
603    /// Simply provide the already compute response
604    fn into_response(self, _req: &Packet) -> Packet {
605        self.0
606    }
607}
608
609impl IntoResponse for PacketBody {
610    fn into_response(self, req: &Packet) -> Packet {
611        Packet {
612            header: req.header.response(),
613            contents: self.0,
614        }
615    }
616}
617
618impl<T: FromRequest> FromRequest for Request<T> {
619    fn from_request(req: &Packet) -> DecodeResult<Self> {
620        let inner = T::from_request(req)?;
621        let header = req.header;
622        Ok(Self { req: inner, header })
623    }
624}
625
626/// Trait implementing by structures which can be created from a request
627/// packet and is used for the arguments on routing functions
628pub trait FromRequest: Sized + Send + 'static {
629    /// Takes the value from the request returning a decode result of
630    /// whether the value could be created
631    ///
632    /// `req` The request packet
633    fn from_request(req: &Packet) -> DecodeResult<Self>;
634}
635
636impl<D> FromRequest for D
637where
638    D: Decodable + Send + 'static,
639{
640    fn from_request(req: &Packet) -> DecodeResult<Self> {
641        req.decode()
642    }
643}
644
645/// Trait for a type that can be converted into a packet
646/// response using the header from the request packet
647pub trait IntoResponse: 'static {
648    /// Into packet conversion
649    fn into_response(self, req: &Packet) -> Packet;
650}
651
652/// Empty response implementation for unit types to allow
653/// functions to have no return type
654impl IntoResponse for () {
655    fn into_response(self, req: &Packet) -> Packet {
656        req.respond_empty()
657    }
658}
659
660/// Into response imeplementation for encodable responses
661/// which just calls res.respond
662impl<E> IntoResponse for E
663where
664    E: Encodable + 'static,
665{
666    fn into_response(self, req: &Packet) -> Packet {
667        req.respond(self)
668    }
669}
670
671/// Into response implementation on result turning whichever
672/// portion of the result into a response
673impl<S, E> IntoResponse for Result<S, E>
674where
675    S: IntoResponse,
676    E: IntoResponse,
677{
678    fn into_response(self, req: &Packet) -> Packet {
679        match self {
680            Ok(value) => value.into_response(req),
681            Err(value) => value.into_response(req),
682        }
683    }
684}
685
686/// Into response implementation for option type turning
687/// None responses into an empty response
688impl<S> IntoResponse for Option<S>
689where
690    S: IntoResponse,
691{
692    fn into_response(self, req: &Packet) -> Packet {
693        match self {
694            Some(value) => value.into_response(req),
695            None => req.respond_empty(),
696        }
697    }
698}
699
700/// Wrapper over a packet structure to provde debug logging
701/// with names resolved for the component
702pub struct PacketDebug<'a, C> {
703    /// Reference to the packet itself
704    pub packet: &'a Packet,
705    /// The component derived from the packet header
706    pub component: Option<&'a C>,
707    /// Decide whether to display the contents of the packet
708    pub minified: bool,
709}
710
711impl<'a, C> Debug for PacketDebug<'a, C>
712where
713    C: PacketComponents,
714{
715    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
716        // Append basic header information
717        let header = &self.packet.header;
718        if let Some(component) = self.component {
719            writeln!(f, "Component: {:?}", component)?;
720        } else {
721            writeln!(f, "Component: {:#06x}", header.component)?;
722            writeln!(f, "Command: {:#06x}", header.command)?;
723        }
724
725        writeln!(f, "Type: {:?}", header.ty)?;
726
727        if !matches!(&header.ty, PacketType::Notify) {
728            writeln!(f, "ID: {}", &header.id)?;
729        }
730
731        if let PacketType::Error = &header.ty {
732            writeln!(f, "Error: {:#06x}", &header.error)?;
733        }
734
735        // Skip remaining if the message shouldn't contain its content
736        if self.minified {
737            return Ok(());
738        }
739
740        let mut reader = TdfReader::new(&self.packet.contents);
741        let mut out = String::new();
742
743        out.push_str("{\n");
744
745        // Stringify the content or append error instead
746        if let Err(err) = reader.stringify(&mut out) {
747            writeln!(f, "Content: Content was malformed")?;
748            writeln!(f, "Error: {:?}", err)?;
749            writeln!(f, "Partial Content: {}", out)?;
750            writeln!(f, "Raw: {:?}", &self.packet.contents)?;
751            return Ok(());
752        }
753
754        if out.len() == 2 {
755            // Remove new line if nothing else was appended
756            out.pop();
757        }
758
759        out.push('}');
760
761        write!(f, "Content: {}", out)
762    }
763}