Skip to main content

flare_core/common/
utils.rs

1//! 工具函数模块
2//!
3//! 提供常用的工具函数和辅助方法
4
5use crate::common::error::Result;
6
7/// 生成唯一 ID(基于时间戳和随机数)
8pub fn generate_id() -> String {
9    use std::sync::atomic::{AtomicU64, Ordering};
10    static COUNTER: AtomicU64 = AtomicU64::new(0);
11
12    let timestamp = crate::common::platform::wall_clock_ms();
13    let counter = COUNTER.fetch_add(1, Ordering::Relaxed);
14    format!("{}-{:016x}", timestamp, counter)
15}
16
17/// 生成简短 ID(仅用于测试或临时标识)
18pub fn generate_short_id() -> String {
19    use std::sync::atomic::{AtomicU32, Ordering};
20    static COUNTER: AtomicU32 = AtomicU32::new(0);
21
22    let counter = COUNTER.fetch_add(1, Ordering::Relaxed);
23    format!("{:08x}", counter)
24}
25
26/// 获取当前时间戳(毫秒)
27pub fn current_timestamp_ms() -> u64 {
28    crate::common::platform::wall_clock_ms()
29}
30
31/// 获取当前时间戳(秒)
32pub fn current_timestamp_secs() -> u64 {
33    crate::common::platform::wall_clock_secs()
34}
35
36/// 验证字符串是否为有效的连接 ID
37///
38/// 连接 ID 应该只包含字母、数字、连字符和下划线
39pub fn is_valid_connection_id(id: &str) -> bool {
40    !id.is_empty()
41        && id.len() <= 128
42        && id
43            .chars()
44            .all(|c| c.is_alphanumeric() || c == '-' || c == '_')
45}
46
47/// 验证字符串是否为有效的用户 ID
48///
49/// 用户 ID 应该只包含字母、数字、连字符、下划线和 @ 符号
50pub fn is_valid_user_id(id: &str) -> bool {
51    !id.is_empty()
52        && id.len() <= 64
53        && id
54            .chars()
55            .all(|c| c.is_alphanumeric() || c == '-' || c == '_' || c == '@' || c == '.')
56}
57
58/// 截断字符串到指定长度(如果超过)
59pub fn truncate_string(s: &str, max_len: usize) -> String {
60    if s.len() <= max_len {
61        s.to_string()
62    } else {
63        format!("{}...", &s[..max_len.saturating_sub(3)])
64    }
65}
66
67/// 将字节数组转换为十六进制字符串
68pub fn bytes_to_hex(bytes: &[u8]) -> String {
69    bytes.iter().map(|b| format!("{:02x}", b)).collect()
70}
71
72/// 将十六进制字符串转换为字节数组
73pub fn hex_to_bytes(hex: &str) -> Result<Vec<u8>> {
74    (0..hex.len())
75        .step_by(2)
76        .map(|i| {
77            u8::from_str_radix(&hex[i..i + 2], 16).map_err(|e| {
78                crate::common::error::FlareError::protocol_error(format!(
79                    "Invalid hex string: {}",
80                    e
81                ))
82            })
83        })
84        .collect()
85}
86
87/// 计算数据的哈希值(简单实现)
88///
89/// 注意:这是一个简单的哈希实现,用于非安全场景
90/// 如果需要加密安全的哈希,请使用外部库(如 sha2)
91pub fn simple_hash(data: &[u8]) -> u64 {
92    // 简单的 FNV-1a 哈希算法
93    const FNV_OFFSET_BASIS: u64 = 0xcbf29ce484222325;
94    const FNV_PRIME: u64 = 0x100000001b3;
95
96    let mut hash = FNV_OFFSET_BASIS;
97    for &byte in data {
98        hash ^= byte as u64;
99        hash = hash.wrapping_mul(FNV_PRIME);
100    }
101    hash
102}
103
104/// 安全地比较两个字节数组(防止时序攻击)
105pub fn constant_time_eq(a: &[u8], b: &[u8]) -> bool {
106    if a.len() != b.len() {
107        return false;
108    }
109
110    a.iter()
111        .zip(b.iter())
112        .map(|(x, y)| x ^ y)
113        .fold(0u8, |acc, x| acc | x)
114        == 0
115}
116
117#[cfg(test)]
118mod tests {
119    use super::*;
120
121    #[test]
122    fn test_generate_id() {
123        let id1 = generate_id();
124        let id2 = generate_id();
125        assert_ne!(id1, id2);
126        assert!(!id1.is_empty());
127    }
128
129    #[test]
130    fn test_is_valid_connection_id() {
131        assert!(is_valid_connection_id("conn-123"));
132        assert!(is_valid_connection_id("conn_456"));
133        assert!(!is_valid_connection_id("conn 123")); // 包含空格
134        assert!(!is_valid_connection_id("")); // 空字符串
135    }
136
137    #[test]
138    fn test_is_valid_user_id() {
139        assert!(is_valid_user_id("user-123"));
140        assert!(is_valid_user_id("user@example.com"));
141        assert!(!is_valid_user_id("user 123")); // 包含空格
142        assert!(!is_valid_user_id("")); // 空字符串
143    }
144
145    #[test]
146    fn test_truncate_string() {
147        assert_eq!(truncate_string("hello", 10), "hello");
148        assert_eq!(truncate_string("hello world", 5), "he...");
149    }
150
151    #[test]
152    fn test_bytes_to_hex() {
153        assert_eq!(bytes_to_hex(&[0x12, 0x34, 0xAB]), "1234ab");
154    }
155
156    #[test]
157    fn test_hex_to_bytes() {
158        assert_eq!(hex_to_bytes("1234ab").unwrap(), vec![0x12, 0x34, 0xAB]);
159        assert!(hex_to_bytes("invalid").is_err());
160    }
161
162    #[test]
163    fn test_constant_time_eq() {
164        assert!(constant_time_eq(b"hello", b"hello"));
165        assert!(!constant_time_eq(b"hello", b"world"));
166        assert!(!constant_time_eq(b"hello", b"hell"));
167    }
168}