//! 从应用目录 `resources/data/oem` 读取 OEM 编号。 use std::path::{Path, PathBuf}; use serde_json::Value; use tauri::{AppHandle, Manager, path::BaseDirectory}; pub const DEFAULT_OEM_ID: i64 = 1; /// 相对可执行文件目录的 OEM 配置路径:`resources/data/oem`。 pub const OEM_RESOURCE_RELATIVE: &[&str] = &["resources", "data", "oem"]; /// 开发时源码树中的 OEM 配置路径。 pub const OEM_DEV_RELATIVE: &str = "src-tauri/resources/data/oem"; pub fn read_oem_id_file(path: &Path) -> i64 { let content = match std::fs::read_to_string(path) { Ok(s) => s, Err(_) => return DEFAULT_OEM_ID, }; parse_oem_id_content(&content).unwrap_or(DEFAULT_OEM_ID) } /// 解析 OEM 配置文件路径(打包资源 → 应用目录 → 开发目录)。 pub fn resolve_oem_id_path(handle: &AppHandle) -> Option { if let Ok(path) = handle.path().resolve("data/oem", BaseDirectory::Resource) { if path.is_file() { return Some(path); } } locate_oem_id_file() } /// 读取当前应用的 OEM 编号。 pub fn load_oem_id(handle: &AppHandle) -> i64 { resolve_oem_id_path(handle) .map(|path| read_oem_id_file(&path)) .unwrap_or(DEFAULT_OEM_ID) } /// 按可执行文件旁 `resources/data/oem` 或开发目录定位配置文件。 pub fn locate_oem_id_file() -> Option { if let Ok(path) = std::env::var("AICLIENT_OEM_FILE") { let custom = PathBuf::from(path); if custom.is_file() { return Some(custom); } } if let Ok(exe) = std::env::current_exe() { if let Some(dir) = exe.parent() { let bundled = dir.join(path_from_parts(OEM_RESOURCE_RELATIVE)); if bundled.is_file() { return Some(bundled); } } } let dev = PathBuf::from(OEM_DEV_RELATIVE); if dev.is_file() { return Some(dev); } None } fn path_from_parts(parts: &[&str]) -> PathBuf { let mut path = PathBuf::new(); for part in parts { path.push(part); } path } fn parse_oem_id_content(content: &str) -> Option { let trimmed = content.trim(); if trimmed.is_empty() { return None; } if let Ok(value) = serde_json::from_str::(trimmed) { if let Some(id) = value.get("oem_id").and_then(|v| v.as_i64()) { if id >= 1 { return Some(id); } } if let Some(id) = value.as_i64() { if id >= 1 { return Some(id); } } } let first_line = trimmed.lines().next()?.trim(); let id: i64 = first_line.parse().ok()?; if id >= 1 { Some(id) } else { None } } #[cfg(test)] mod tests { use super::*; #[test] fn parse_integer_line() { assert_eq!(parse_oem_id_content("2\n"), Some(2)); } #[test] fn parse_json_object() { assert_eq!(parse_oem_id_content(r#"{"oem_id":3}"#), Some(3)); } #[test] fn invalid_defaults_none() { assert_eq!(parse_oem_id_content("abc"), None); assert_eq!(parse_oem_id_content(""), None); } }