File size: 4,841 Bytes
cd872f9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
mod checksum;
pub use checksum::*;
mod tokens;
pub use tokens::*;

use super::models::userinfo::{StripeProfile, TokenProfile, UsageProfile, UserProfile};
use crate::app::{
    constant::{FALSE, TRUE},
    lazy::{TOKEN_DELIMITER, TOKEN_DELIMITER_LEN},
};

pub fn parse_bool_from_env(key: &str, default: bool) -> bool {
    std::env::var(key)
        .ok()
        .map(|v| match v.to_lowercase().as_str() {
            TRUE | "1" => true,
            FALSE | "0" => false,
            _ => default,
        })
        .unwrap_or(default)
}

pub fn parse_string_from_env(key: &str, default: &str) -> String {
    std::env::var(key).unwrap_or_else(|_| default.to_string())
}

pub fn parse_ascii_char_from_env(key: &str, default: char) -> char {
    std::env::var(key)
        .ok()
        .and_then(|v| {
            let chars: Vec<char> = v.chars().collect();
            if chars.len() == 1 && chars[0].is_ascii() {
                Some(chars[0])
            } else {
                None
            }
        })
        .unwrap_or(default)
}

pub fn parse_usize_from_env(key: &str, default: usize) -> usize {
    std::env::var(key)
        .ok()
        .and_then(|v| v.parse().ok())
        .unwrap_or(default)
}

pub async fn get_token_profile(auth_token: &str) -> Option<TokenProfile> {
    let user_id = extract_user_id(auth_token)?;

    // 构建请求客户端
    let client = super::client::build_usage_client(&user_id, auth_token);

    // 发送请求并获取响应
    // let response = client.send().await.ok()?;
    // let bytes = response.bytes().await?;
    // println!("Raw response bytes: {:?}", bytes);
    // let usage = serde_json::from_str::<UsageProfile>(&text).ok()?;
    let usage = client
        .send()
        .await
        .ok()?
        .json::<UsageProfile>()
        .await
        .ok()?;

    let user = get_user_profile(auth_token).await?;

    // 从 Stripe 获取用户资料
    let stripe = get_stripe_profile(auth_token).await?;

    // 映射响应数据到 TokenProfile
    Some(TokenProfile {
        usage,
        user,
        stripe,
    })
}

pub async fn get_stripe_profile(auth_token: &str) -> Option<StripeProfile> {
    let client = super::client::build_profile_client(auth_token);
    let response = client
        .send()
        .await
        .ok()?
        .json::<StripeProfile>()
        .await
        .ok()?;
    Some(response)
}

pub async fn get_user_profile(auth_token: &str) -> Option<UserProfile> {
    let user_id = extract_user_id(auth_token)?;

    // 构建请求客户端
    let client = super::client::build_userinfo_client(&user_id, auth_token);

    // 发送请求并获取响应
    let user_profile = client.send().await.ok()?.json::<UserProfile>().await.ok()?;

    Some(user_profile)
}

pub fn validate_token_and_checksum(auth_token: &str) -> Option<(String, String)> {
    // 找最后一个逗号
    let comma_pos = auth_token.rfind(*TOKEN_DELIMITER)?;
    let (token_part, checksum) = auth_token.split_at(comma_pos);
    let checksum = &checksum[*TOKEN_DELIMITER_LEN..]; // 跳过逗号

    // 解析 token - 为了向前兼容,忽略最后一个:或%3A前的内容
    let colon_pos = token_part.rfind(':');
    let encoded_colon_pos = token_part.rfind("%3A");

    let token = match (colon_pos, encoded_colon_pos) {
        (None, None) => token_part, // 最简单的构成: token,checksum
        (Some(pos1), None) => &token_part[(pos1 + 1)..],
        (None, Some(pos2)) => &token_part[(pos2 + 3)..],
        (Some(pos1), Some(pos2)) => {
            let pos = pos1.max(pos2);
            let start = if pos == pos2 { pos + 3 } else { pos + 1 };
            &token_part[start..]
        }
    };

    // 验证 token 和 checksum 有效性
    if validate_token(token) && validate_checksum(checksum) {
        Some((token.to_string(), checksum.to_string()))
    } else {
        None
    }
}

pub fn extract_token(auth_token: &str) -> Option<String> {
    // 解析 token
    let token_part = match auth_token.rfind(*TOKEN_DELIMITER) {
        Some(pos) => &auth_token[..pos],
        None => auth_token,
    };

    // 向前兼容
    let colon_pos = token_part.rfind(':');
    let encoded_colon_pos = token_part.rfind("%3A");

    let token = match (colon_pos, encoded_colon_pos) {
        (None, None) => token_part,
        (Some(pos1), None) => &token_part[(pos1 + 1)..],
        (None, Some(pos2)) => &token_part[(pos2 + 3)..],
        (Some(pos1), Some(pos2)) => {
            let pos = pos1.max(pos2);
            let start = if pos == pos2 { pos + 3 } else { pos + 1 };
            &token_part[start..]
        }
    };

    // 验证 token 有效性
    if validate_token(token) {
        Some(token.to_string())
    } else {
        None
    }
}

pub fn format_time_ms(seconds: f64) -> f64 {
    (seconds * 1000.0).round() / 1000.0
}