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}