use serde::Serialize; use std::collections::HashMap; use std::sync::Arc; use tokio::sync::RwLock; #[derive(Clone)] pub struct AppState { pub latest: Arc>>, pub codes: Arc>, pub started_at: String, } impl AppState { pub fn new(codes: Vec, started_at: String) -> Self { Self { latest: Arc::new(RwLock::new(HashMap::new())), codes: Arc::new(codes), started_at, } } } #[derive(Clone, Debug, Serialize)] pub struct Quote { pub received_at: String, pub code: String, pub name: Option, pub previous_close: Option, pub open: Option, pub price: Option, pub high: Option, pub low: Option, pub bid1: Option, pub ask1: Option, pub volume: Option, pub amount: Option, pub trade_date: Option, pub trade_time: Option, pub status: Option, pub raw_fields: String, pub fields: Vec, } pub fn quote_from_record(record: &str, received_at: String) -> Option { let (code, raw_fields) = record.split_once('=')?; let fields: Vec = raw_fields .split(',') .map(|s| s.trim_matches('"').to_string()) .collect(); let get = |idx: usize| fields.get(idx).cloned().filter(|s| !s.is_empty()); // Sina WS fields used by this project: // 名称, 昨收, 今开, 当前价, 最高, 最低, 买一价, 卖一价, 成交量, 成交额, // 买5档×(量,价)×5, 卖5档×(量,价)×5, 日期, 时间, 状态 Some(Quote { received_at, code: code.to_string(), name: get(0), previous_close: get(1), open: get(2), price: get(3), high: get(4), low: get(5), bid1: get(6), ask1: get(7), volume: get(8), amount: get(9), trade_date: get(30), trade_time: get(31), status: get(32), raw_fields: raw_fields.to_string(), fields, }) }