Skip to main content

yggdrasil/utils/
server.rs

1//! 服务端共享工具(仅 `feature = "server"` 编译)。
2//!
3//! 集中跨模块重复的服务端常量与工具函数(issue #7 重复常量去重)。
4
5#![cfg(feature = "server")]
6
7use sha2::{Digest, Sha256};
8
9/// 明文 token / 任意字符串 → SHA-256 hex。
10///
11/// 此前 `auth/session.rs` 与 `mcp/auth.rs` 各有一份逐字相同的实现。
12pub fn sha256_hex(input: &str) -> String {
13    let mut hasher = Sha256::new();
14    hasher.update(input.as_bytes());
15    hex::encode(hasher.finalize())
16}
17
18/// 邮箱格式正则(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`)。
19///
20/// 此前 `api/auth.rs` 与 `api/comments/helpers.rs` 各有一份逐字相同的 LazyLock。
21pub static EMAIL_REGEX: std::sync::LazyLock<regex::Regex> = std::sync::LazyLock::new(|| {
22    regex::Regex::new(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$")
23        .expect("EMAIL_REGEX 正则模式应在编译期通过校验")
24});
25
26/// 上传文件大小上限(5 MiB)。
27///
28/// 此前 `api/upload.rs` 与 `mcp/tools/media.rs` 各定义一份相同的常量。
29pub const MAX_FILE_SIZE: usize = 5 * 1024 * 1024;
30
31/// 启动期数据库迁移超时窗口(秒),由 `MIGRATE_STARTUP_TIMEOUT_SECS` 控制,默认 30。
32///
33/// 此前 `main.rs` 与 `db/pool.rs`(`get_conn_for_startup`、`ensure_database_exists` 两处)
34/// 各有一份逐字相同的 `.ok().and_then(parse).unwrap_or(30)` 解析链。
35pub fn parse_migrate_startup_timeout() -> u64 {
36    std::env::var("MIGRATE_STARTUP_TIMEOUT_SECS")
37        .ok()
38        .and_then(|s| s.parse::<u64>().ok())
39        .unwrap_or(30)
40}
41
42/// 转义 SQL `LIKE` 模式串中的特殊字符(`\`、`%`、`_`),配合 `ESCAPE '\\'` 使用。
43///
44/// 此前 `api/posts/list.rs`(逐字符循环)与 `api/posts/search.rs`、`mcp/tools/read.rs`
45///(replace 链)各有一份实现;统一为等价且更简洁的 replace 链风格。
46pub fn escape_like_pattern(s: &str) -> String {
47    s.replace('\\', "\\\\")
48        .replace('%', "\\%")
49        .replace('_', "\\_")
50}