use crate::bytes_helper::u16_from_le_bytes;
use log::trace;
use std::{
io::{BufReader, Read, Result, Write},
net::{SocketAddr, TcpStream},
time::Duration,
};
#[macro_use]
#[cfg(test)]
pub(crate) mod tests;
mod basic;
pub use basic::*;
pub mod helper;
pub mod ip;
pub mod stock;
pub type BufTcp = BufReader<TcpStream>;
#[derive(Debug)]
pub struct Tcp {
stream: TcpStream,
buffer: BufTcp,
recv: [u8; RECV_SIZE],
}
impl Tcp {
pub fn new() -> Result<Self> {
let (stream, buffer, recv) = tcpstream()?;
let mut tcp = Self {
stream,
buffer,
recv,
};
send_packs(&mut tcp, false)?;
Ok(tcp)
}
pub fn new_with_ip(ip: &SocketAddr) -> Result<Self> {
let (stream, buffer, recv) = tcpstream_ip(ip)?;
let mut tcp = Self {
stream,
buffer,
recv,
};
send_packs(&mut tcp, false)?;
Ok(tcp)
}
pub fn send_recv(&mut self, send: &[u8]) -> Result<(usize, usize)> {
Ok((self.stream.write(send)?, self.buffer.read(&mut self.recv)?))
}
pub fn into_inner(self) -> (TcpStream, BufTcp, [u8; RECV_SIZE]) {
(self.stream, self.buffer, self.recv)
}
pub fn get_ref(&self) -> (&TcpStream, &BufTcp, &[u8]) {
(&self.stream, &self.buffer, &self.recv)
}
pub fn get_ref_recv(&self) -> &[u8] {
&self.recv
}
}
pub trait Tdx {
const SEND: &'static [u8];
const TAG: &'static str;
const LEN: usize = Self::SEND.len();
type Item: ?Sized;
fn send(&mut self) -> &[u8];
fn recv(&mut self, tcp: &mut Tcp) -> Result<Vec<u8>> {
send_recv_decompress(tcp, self.send(), Self::TAG)
}
fn parse(&mut self, response: Vec<u8>);
fn recv_parsed(&mut self, tcp: &mut Tcp) -> Result<&Self::Item> {
let response = self.recv(tcp)?;
self.parse(response);
Ok(self.result())
}
fn result(&self) -> &Self::Item;
}
pub fn send_recv_decompress(tcp: &mut Tcp, send: &[u8], tag: &str) -> Result<Vec<u8>> {
let (mut buf, deflate_size, inflate_size) = send_recv(tcp, send, tag)?;
if deflate_size != inflate_size {
buf = miniz_oxide::inflate::decompress_to_vec_zlib(&buf).unwrap();
trace!("解压后数据:\n{:?}\n", buf);
debug_assert_eq!(buf.len(), inflate_size as usize);
} else {
trace!("无需解压\n");
};
Ok(buf)
}
pub fn send_recv(tcp: &mut Tcp, send: &[u8], tag: &str) -> Result<(Vec<u8>, u16, u16)> {
tcp.send_recv(send)?;
trace!("{}\nsend: {:?}\nrecv[16B]: {:?}", tag, send, tcp);
let deflate_size = u16_from_le_bytes(&tcp.recv, 12); let mut buf = vec![0; deflate_size as usize];
tcp.buffer.read_exact(&mut buf)?;
let inflate_size = u16_from_le_bytes(&tcp.recv, 14); #[rustfmt::skip]
trace!("\n解压前:#{:?}# -> {},解压后:#{:?}# -> {}\n剩余数据(即解压前):{:x?}\n",
&tcp.recv[12..14], deflate_size, &tcp.recv[14..16], inflate_size, buf);
Ok((buf, deflate_size, inflate_size))
}
pub const TIMEOUT: Duration = Duration::from_millis(100);
pub fn tcpstream() -> Result<(TcpStream, BufTcp, [u8; RECV_SIZE])> {
tcpstream_ip(&ip::STOCK_IP[0])
}
pub fn tcpstream_ip(ip: &SocketAddr) -> Result<(TcpStream, BufTcp, [u8; RECV_SIZE])> {
let stream = TcpStream::connect_timeout(ip, TIMEOUT)?;
stream.set_read_timeout(Some(TIMEOUT))?;
stream.set_write_timeout(Some(TIMEOUT))?;
let recv = [0; RECV_SIZE];
let buffer = BufReader::new(stream.try_clone()?);
Ok((stream, buffer, recv))
}