use crate::{
codec::{Decodable, Encodable},
error::DecodeResult,
reader::TdfReader,
};
use bytes::{Buf, BufMut, Bytes, BytesMut};
use std::{fmt::Debug, hash::Hash, sync::Arc};
use std::{io, ops::Deref};
use tokio_util::codec::{Decoder, Encoder};
pub trait PacketComponents: Debug + Hash + Eq + Sized {
fn values(&self) -> (u16, u16);
fn from_values(component: u16, command: u16, notify: bool) -> Option<Self>;
fn from_header(header: &PacketHeader) -> Option<Self> {
Self::from_values(
header.component,
header.command,
matches!(&header.ty, PacketType::Notify),
)
}
}
pub trait PacketComponent: Debug + Hash + Eq + Sized {
fn command(&self) -> u16;
fn from_value(value: u16, notify: bool) -> Option<Self>;
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u8)]
pub enum PacketType {
Request = 0x00,
Response = 0x10,
Notify = 0x20,
Error = 0x30,
}
impl From<u8> for PacketType {
fn from(value: u8) -> Self {
match value {
0x00 => PacketType::Request,
0x10 => PacketType::Response,
0x20 => PacketType::Notify,
0x30 => PacketType::Error,
_ => PacketType::Request,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct PacketHeader {
pub component: u16,
pub command: u16,
pub error: u16,
pub ty: PacketType,
pub id: u16,
}
impl PacketHeader {
pub const fn notify(component: u16, command: u16) -> Self {
Self {
component,
command,
error: 0,
ty: PacketType::Notify,
id: 0,
}
}
pub const fn request(id: u16, component: u16, command: u16) -> Self {
Self {
component,
command,
error: 0,
ty: PacketType::Request,
id,
}
}
pub const fn response(&self) -> Self {
self.with_type(PacketType::Response)
}
pub const fn with_type(&self, ty: PacketType) -> Self {
Self {
component: self.component,
command: self.command,
error: self.error,
ty,
id: self.id,
}
}
pub const fn with_error(&self, error: u16) -> Self {
Self {
component: self.component,
command: self.command,
error,
ty: PacketType::Error,
id: self.id,
}
}
pub fn path_matches(&self, other: &PacketHeader) -> bool {
self.component.eq(&other.component) && self.command.eq(&other.command)
}
pub fn write(&self, dst: &mut BytesMut, length: usize) {
let is_extended = length > 0xFFFF;
dst.put_u16(length as u16);
dst.put_u16(self.component);
dst.put_u16(self.command);
dst.put_u16(self.error);
dst.put_u8(self.ty as u8);
dst.put_u8(if is_extended { 0x10 } else { 0x00 });
dst.put_u16(self.id);
if is_extended {
dst.put_u8(((length & 0xFF000000) >> 24) as u8);
dst.put_u8(((length & 0x00FF0000) >> 16) as u8);
}
}
pub fn read(src: &mut BytesMut) -> Option<(PacketHeader, usize)> {
if src.len() < 12 {
return None;
}
let mut length = src.get_u16() as usize;
let component = src.get_u16();
let command = src.get_u16();
let error = src.get_u16();
let ty = src.get_u8();
let is_extended = src.get_u8() == 0x10;
let id = src.get_u16();
if is_extended {
if src.len() < 2 {
return None;
}
length += src.get_u16() as usize;
}
let ty = PacketType::from(ty);
let header = PacketHeader {
component,
command,
error,
ty,
id,
};
Some((header, length))
}
}
#[derive(Debug, Clone)]
pub struct Packet {
pub header: PacketHeader,
pub contents: Bytes,
}
impl Packet {
pub fn raw(header: PacketHeader, contents: Vec<u8>) -> Self {
Self {
header,
contents: Bytes::from(contents),
}
}
pub const fn raw_empty(header: PacketHeader) -> Self {
Self {
header,
contents: Bytes::new(),
}
}
pub fn response<C: Encodable>(packet: &Packet, contents: C) -> Self {
Self {
header: packet.header.response(),
contents: Bytes::from(contents.encode_bytes()),
}
}
pub fn respond<C: Encodable>(&self, contents: C) -> Self {
Self::response(self, contents)
}
pub fn response_raw(packet: &Packet, contents: Vec<u8>) -> Self {
Self {
header: packet.header.response(),
contents: Bytes::from(contents),
}
}
pub const fn response_empty(packet: &Packet) -> Self {
Self {
header: packet.header.response(),
contents: Bytes::new(),
}
}
pub const fn respond_empty(&self) -> Self {
Self::response_empty(self)
}
pub fn error<C: Encodable>(packet: &Packet, error: u16, contents: C) -> Self {
Self {
header: packet.header.with_error(error),
contents: Bytes::from(contents.encode_bytes()),
}
}
pub fn respond_error<C: Encodable>(&self, error: u16, contents: C) -> Self {
Self::error(self, error, contents)
}
pub fn error_raw(packet: &Packet, error: u16, contents: Vec<u8>) -> Self {
Self {
header: packet.header.with_error(error),
contents: Bytes::from(contents),
}
}
pub const fn error_empty(packet: &Packet, error: u16) -> Packet {
Self {
header: packet.header.with_error(error),
contents: Bytes::new(),
}
}
pub const fn respond_error_empty(&self, error: u16) -> Packet {
Self::error_empty(self, error)
}
pub fn notify<C: Encodable, T: PacketComponents>(component: T, contents: C) -> Packet {
let (component, command) = component.values();
Self {
header: PacketHeader::notify(component, command),
contents: Bytes::from(contents.encode_bytes()),
}
}
pub fn notify_raw<T: PacketComponents>(component: T, contents: Vec<u8>) -> Packet {
let (component, command) = component.values();
Self {
header: PacketHeader::notify(component, command),
contents: Bytes::from(contents),
}
}
pub fn notify_empty<T: PacketComponents>(component: T) -> Packet {
let (component, command) = component.values();
Self {
header: PacketHeader::notify(component, command),
contents: Bytes::new(),
}
}
pub fn request<C: Encodable, T: PacketComponents>(
id: u16,
component: T,
contents: C,
) -> Packet {
let (component, command) = component.values();
Self {
header: PacketHeader::request(id, component, command),
contents: Bytes::from(contents.encode_bytes()),
}
}
pub fn request_raw<T: PacketComponents>(id: u16, component: T, contents: Vec<u8>) -> Packet {
let (component, command) = component.values();
Self {
header: PacketHeader::request(id, component, command),
contents: Bytes::from(contents),
}
}
pub fn request_empty<T: PacketComponents>(id: u16, component: T) -> Packet {
let (component, command) = component.values();
Self {
header: PacketHeader::request(id, component, command),
contents: Bytes::new(),
}
}
pub fn decode<C: Decodable>(&self) -> DecodeResult<C> {
let mut reader = TdfReader::new(&self.contents);
C::decode(&mut reader)
}
pub fn read(src: &mut BytesMut) -> Option<Self> {
let (header, length) = PacketHeader::read(src)?;
if src.len() < length {
return None;
}
let contents = src.split_to(length);
Some(Self {
header,
contents: contents.freeze(),
})
}
pub fn write(&self, dst: &mut BytesMut) {
let contents = &self.contents;
self.header.write(dst, contents.len());
dst.extend_from_slice(contents);
}
}
pub struct PacketCodec;
impl Decoder for PacketCodec {
type Error = io::Error;
type Item = Packet;
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
let mut read_src = src.clone();
let result = Packet::read(&mut read_src);
if result.is_some() {
*src = read_src;
}
Ok(result)
}
}
impl Encoder<Packet> for PacketCodec {
type Error = io::Error;
fn encode(&mut self, item: Packet, dst: &mut BytesMut) -> Result<(), Self::Error> {
item.write(dst);
Ok(())
}
}
impl Encoder<&Packet> for PacketCodec {
type Error = io::Error;
fn encode(&mut self, item: &Packet, dst: &mut BytesMut) -> Result<(), Self::Error> {
item.write(dst);
Ok(())
}
}
impl Encoder<Arc<Packet>> for PacketCodec {
type Error = io::Error;
fn encode(&mut self, item: Arc<Packet>, dst: &mut BytesMut) -> Result<(), Self::Error> {
item.write(dst);
Ok(())
}
}
pub struct Request<T: FromRequest> {
pub req: T,
pub header: PacketHeader,
}
impl<T: FromRequest> Deref for Request<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.req
}
}
impl<T: FromRequest> Request<T> {
pub fn response<E>(&self, res: E) -> Response
where
E: Encodable,
{
Response(Packet {
header: self.header.response(),
contents: Bytes::from(res.encode_bytes()),
})
}
}
pub struct PacketBody(Bytes);
impl<T> From<T> for PacketBody
where
T: Encodable,
{
fn from(value: T) -> Self {
let bytes = value.encode_bytes();
let bytes = Bytes::from(bytes);
PacketBody(bytes)
}
}
pub struct Response(Packet);
impl IntoResponse for Response {
fn into_response(self, _req: &Packet) -> Packet {
self.0
}
}
impl IntoResponse for PacketBody {
fn into_response(self, req: &Packet) -> Packet {
Packet {
header: req.header.response(),
contents: self.0,
}
}
}
impl<T: FromRequest> FromRequest for Request<T> {
fn from_request(req: &Packet) -> DecodeResult<Self> {
let inner = T::from_request(req)?;
let header = req.header;
Ok(Self { req: inner, header })
}
}
pub trait FromRequest: Sized + Send + 'static {
fn from_request(req: &Packet) -> DecodeResult<Self>;
}
impl<D> FromRequest for D
where
D: Decodable + Send + 'static,
{
fn from_request(req: &Packet) -> DecodeResult<Self> {
req.decode()
}
}
pub trait IntoResponse: 'static {
fn into_response(self, req: &Packet) -> Packet;
}
impl IntoResponse for () {
fn into_response(self, req: &Packet) -> Packet {
req.respond_empty()
}
}
impl<E> IntoResponse for E
where
E: Encodable + 'static,
{
fn into_response(self, req: &Packet) -> Packet {
req.respond(self)
}
}
impl<S, E> IntoResponse for Result<S, E>
where
S: IntoResponse,
E: IntoResponse,
{
fn into_response(self, req: &Packet) -> Packet {
match self {
Ok(value) => value.into_response(req),
Err(value) => value.into_response(req),
}
}
}
impl<S> IntoResponse for Option<S>
where
S: IntoResponse,
{
fn into_response(self, req: &Packet) -> Packet {
match self {
Some(value) => value.into_response(req),
None => req.respond_empty(),
}
}
}
pub struct PacketDebug<'a, C> {
pub packet: &'a Packet,
pub component: Option<&'a C>,
pub minified: bool,
}
impl<'a, C> Debug for PacketDebug<'a, C>
where
C: PacketComponents,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let header = &self.packet.header;
if let Some(component) = self.component {
writeln!(f, "Component: {:?}", component)?;
} else {
writeln!(f, "Component: {:#06x}", header.component)?;
writeln!(f, "Command: {:#06x}", header.command)?;
}
writeln!(f, "Type: {:?}", header.ty)?;
if !matches!(&header.ty, PacketType::Notify) {
writeln!(f, "ID: {}", &header.id)?;
}
if let PacketType::Error = &header.ty {
writeln!(f, "Error: {:#06x}", &header.error)?;
}
if self.minified {
return Ok(());
}
let mut reader = TdfReader::new(&self.packet.contents);
let mut out = String::new();
out.push_str("{\n");
if let Err(err) = reader.stringify(&mut out) {
writeln!(f, "Content: Content was malformed")?;
writeln!(f, "Error: {:?}", err)?;
writeln!(f, "Partial Content: {}", out)?;
writeln!(f, "Raw: {:?}", &self.packet.contents)?;
return Ok(());
}
if out.len() == 2 {
out.pop();
}
out.push('}');
write!(f, "Content: {}", out)
}
}