File size: 2,095 Bytes
7c3e988
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
use serde::Serialize;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;

#[derive(Clone)]
pub struct AppState {
    pub latest: Arc<RwLock<HashMap<String, Quote>>>,
    pub codes: Arc<Vec<String>>,
    pub started_at: String,
}

impl AppState {
    pub fn new(codes: Vec<String>, 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<String>,
    pub previous_close: Option<String>,
    pub open: Option<String>,
    pub price: Option<String>,
    pub high: Option<String>,
    pub low: Option<String>,
    pub bid1: Option<String>,
    pub ask1: Option<String>,
    pub volume: Option<String>,
    pub amount: Option<String>,
    pub trade_date: Option<String>,
    pub trade_time: Option<String>,
    pub status: Option<String>,
    pub raw_fields: String,
    pub fields: Vec<String>,
}

pub fn quote_from_record(record: &str, received_at: String) -> Option<Quote> {
    let (code, raw_fields) = record.split_once('=')?;
    let fields: Vec<String> = 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,
    })
}