use super::{u16_from_le_bytes, Result, Tdx};
pub type Heartbeat = SecurityCount;
#[derive(Debug)]
pub struct SecurityCount {
send: Box<[u8]>,
market: u16,
count: u16,
}
impl SecurityCount {
pub fn new(market: u16) -> Self {
let mut send = [0; Self::LEN];
send.copy_from_slice(Self::SEND);
if market != 0 {
send[12..14].copy_from_slice(&market.to_le_bytes());
}
Self {
send: send.into(),
market,
count: 0,
}
}
pub fn market(&mut self, market: u16) {
self.market = market;
self.send[12..14].copy_from_slice(&market.to_le_bytes());
}
}
impl Tdx for SecurityCount {
type Item = u16;
const SEND: &'static [u8] = &[
0x0c, 0x0c, 0x18, 0x6c, 0x00, 0x01, 0x08, 0x00, 0x08, 0x00, 0x4e, 0x04, 0x00, 0x00, 0x75,
0xc7, 0x33, 0x01,
];
const TAG: &'static str = "heartbeat";
fn send(&mut self) -> &[u8] {
&self.send
}
fn parse(&mut self, response: Vec<u8>) {
self.count = u16_from_le_bytes(&response, 0);
}
fn result(&self) -> &Self::Item {
&self.count
}
}
#[derive(Debug, Clone)]
pub struct SecurityList {
pub send: Box<[u8]>,
pub market: u16,
pub start: u16,
pub count: usize,
pub response: Vec<u8>,
pub data: Box<[SecurityListData]>,
}
impl Default for SecurityList {
fn default() -> Self {
Self {
send: {
let mut arr = [0; Self::LEN];
arr.copy_from_slice(Self::SEND);
arr.into()
},
market: 0,
start: 1,
count: 0,
response: Vec::new(),
data: [].into(),
}
}
}
impl SecurityList {
pub fn new(market: u16, start: u16) -> Self {
Self {
send: {
let mut arr = [0; Self::LEN];
arr.copy_from_slice(Self::SEND);
arr[12..14].copy_from_slice(&market.to_le_bytes());
arr[14..16].copy_from_slice(&start.to_le_bytes());
arr.into()
},
market,
start,
count: 0,
response: Vec::new(),
data: [].into(),
}
}
}
impl Tdx for SecurityList {
type Item = [SecurityListData];
const SEND: &'static [u8] = &[
0x0c, 0x01, 0x18, 0x64, 0x01, 0x01, 0x06, 0x00, 0x06, 0x00, 0x50, 0x04, 0x00, 0x00, 0x00,
0x00,
];
const TAG: &'static str = "股票、指数列表";
fn send(&mut self) -> &[u8] {
&self.send
}
fn parse(&mut self, v: Vec<u8>) {
self.count = u16_from_le_bytes(&v, 0) as usize;
self.data = v[2..]
.chunks_exact(29)
.map(SecurityListData::parse)
.collect();
debug_assert_eq!(self.count, self.data.len());
self.response = v;
}
fn result(&self) -> &Self::Item {
&self.data
}
}
#[test]
fn connection() -> Result<()> {
SecurityList::default().recv_parsed(&mut crate::tcp::Tcp::new()?)?;
Ok(())
}
#[derive(Debug, Clone, serde::Serialize)]
pub struct SecurityListData {
pub code: String,
pub name: String,
}
impl SecurityListData {
pub fn parse(bytes: &[u8]) -> Self {
let code = unsafe { std::str::from_utf8_unchecked(&bytes[0..6]) }.into();
let (name, encoding_used, had_errors) = encoding_rs::GBK.decode(&bytes[8..16]);
debug_assert_eq!(encoding_used, encoding_rs::GBK);
debug_assert!(!had_errors);
Self {
code,
name: name.into(),
}
}
}
pub const PACK1: &[u8] = &[
0x0c, 0x02, 0x18, 0x93, 0x00, 0x01, 0x03, 0x00, 0x03, 0x00, 0x0d, 0x00, 0x01,
];
pub const PACK2: &[u8] = &[
0x0c, 0x02, 0x18, 0x94, 0x00, 0x01, 0x03, 0x00, 0x03, 0x00, 0x0d, 0x00, 0x02,
];
pub const PACK3: &[u8] = &[
0x0c, 0x03, 0x18, 0x99, 0x00, 0x01, 0x20, 0x00, 0x20, 0x00, 0xdb, 0x0f, 0xd5, 0xd0, 0xc9, 0xcc,
0xd6, 0xa4, 0xa8, 0xaf, 0x00, 0x00, 0x00, 0x8f, 0xc2, 0x25, 0x40, 0x13, 0x00, 0x00, 0xd5, 0x00,
0xc9, 0xcc, 0xbd, 0xf0, 0xd7, 0xea, 0x00, 0x00, 0x00, 0x02,
];
pub const RECV_SIZE: usize = 16;
pub fn send_packs(tcp: &mut super::Tcp, decompress: bool) -> Result<()> {
use super::{send_recv, send_recv_decompress};
if decompress {
send_recv_decompress(tcp, PACK1, "PACK1")?;
send_recv_decompress(tcp, PACK2, "PACK2")?;
send_recv_decompress(tcp, PACK3, "PACK3")?;
} else {
send_recv(tcp, PACK1, "PACK1")?;
send_recv(tcp, PACK2, "PACK2")?;
send_recv(tcp, PACK3, "PACK3")?;
}
Ok(())
}