inv_sig_helper/src/opcode.rs
2024-07-21 13:37:34 +01:00

152 lines
4.4 KiB
Rust

use std::io::ErrorKind;
use tokio_util::{
bytes::{Buf, BufMut},
codec::{Decoder, Encoder},
};
use crate::{jobs::JobOpcode, player::FetchUpdateStatus};
#[derive(Copy, Clone)]
pub struct OpcodeDecoder {}
pub struct Opcode {
pub opcode: JobOpcode,
pub request_id: u32,
pub signature: String,
}
pub struct OpcodeResponse {
pub opcode: JobOpcode,
pub request_id: u32,
pub update_status: Result<(), FetchUpdateStatus>,
pub signature: String,
pub signature_timestamp: u64,
pub has_player: u8,
pub player_id: u32,
pub last_player_update: u64,
}
impl Default for OpcodeResponse {
fn default() -> Self {
OpcodeResponse {
opcode: JobOpcode::ForceUpdate,
request_id: 0,
update_status: Ok(()),
signature: String::new(),
signature_timestamp: 0,
has_player: 0,
player_id: 0,
last_player_update: 0,
}
}
}
impl Decoder for OpcodeDecoder {
type Item = Opcode;
type Error = std::io::Error;
fn decode(
&mut self,
src: &mut tokio_util::bytes::BytesMut,
) -> Result<Option<Self::Item>, Self::Error> {
println!("Decoder length: {}", src.len());
if 5 > src.len() {
return Ok(None);
}
let opcode_byte: u8 = src[0];
let opcode: JobOpcode = opcode_byte.into();
let request_id: u32 = u32::from_be_bytes(src[1..5].try_into().unwrap());
match opcode {
JobOpcode::ForceUpdate
| JobOpcode::GetSignatureTimestamp
| JobOpcode::PlayerStatus
| JobOpcode::PlayerUpdateTimestamp => {
src.advance(5);
Ok(Some(Opcode {
opcode,
request_id,
signature: Default::default(),
}))
}
JobOpcode::DecryptSignature | JobOpcode::DecryptNSignature => {
if 7 > src.len() {
return Ok(None);
}
let sig_size: u16 = ((src[5] as u16) << 8) | src[6] as u16;
if (usize::from(sig_size) + 7) > src.len() {
return Ok(None);
}
let sig: String =
match String::from_utf8(src[7..(usize::from(sig_size) + 7)].to_vec()) {
Ok(x) => x,
Err(x) => {
return Err(std::io::Error::new(
ErrorKind::InvalidData,
x.utf8_error(),
));
}
};
src.advance(7 + sig.len());
Ok(Some(Opcode {
opcode,
request_id,
signature: sig,
}))
}
_ => Err(std::io::Error::new(ErrorKind::InvalidInput, "")),
}
}
}
impl Encoder<OpcodeResponse> for OpcodeDecoder {
type Error = std::io::Error;
fn encode(
&mut self,
item: OpcodeResponse,
dst: &mut tokio_util::bytes::BytesMut,
) -> Result<(), Self::Error> {
dst.put_u32(item.request_id);
match item.opcode {
JobOpcode::ForceUpdate => {
dst.put_u32(2);
match item.update_status {
Ok(_x) => dst.put_u16(0xF44F),
Err(FetchUpdateStatus::PlayerAlreadyUpdated) => dst.put_u16(0xFFFF),
Err(_x) => dst.put_u16(0x0000),
}
}
JobOpcode::DecryptSignature | JobOpcode::DecryptNSignature => {
dst.put_u32(2 + u32::try_from(item.signature.len()).unwrap());
dst.put_u16(u16::try_from(item.signature.len()).unwrap());
if !item.signature.is_empty() {
dst.put_slice(item.signature.as_bytes());
}
}
JobOpcode::GetSignatureTimestamp => {
dst.put_u32(8);
dst.put_u64(item.signature_timestamp);
}
JobOpcode::PlayerStatus => {
dst.put_u32(5);
dst.put_u8(item.has_player);
dst.put_u32(item.player_id);
}
JobOpcode::PlayerUpdateTimestamp => {
dst.put_u32(8);
dst.put_u64(item.last_player_update);
}
_ => {}
}
Ok(())
}
}