device_id/
lib.rs

1//! 设备ID管理模块
2
3use cache_dir::{get_cache_dir, NoSuchDirectoryError};
4use std::{
5    fs::File,
6    io::{Error as IoError, Read, Write},
7    sync::LazyLock,
8};
9use tracing::error;
10use uuid::Error as UuidError;
11pub use uuid::Uuid;
12
13/// 定义可能出现的错误类型
14#[allow(dead_code)]
15#[derive(Debug)]
16enum DeviceIdError {
17    /// 缓存目录不存在
18    NoCacheDir(NoSuchDirectoryError),
19    /// 文件打开失败
20    NoFile(IoError),
21    /// 数据无效
22    DataInvalid(UuidError),
23}
24
25/// 常量,存储UUID的文件名
26const ID_FILE_NAME: &str = "device.id";
27
28fn try_get_device_id() -> Result<Uuid, DeviceIdError> {
29    let path = get_cache_dir()
30        .map_err(DeviceIdError::NoCacheDir)?
31        .join(ID_FILE_NAME);
32    let mut file = File::open(path).map_err(DeviceIdError::NoFile)?;
33    let mut buf = Vec::with_capacity(16);
34    file.read_to_end(&mut buf).map_err(DeviceIdError::NoFile)?;
35    Ok(Uuid::from_slice(&buf).map_err(DeviceIdError::DataInvalid)?)
36}
37
38static ID_FILE: LazyLock<Uuid> = LazyLock::new(|| {
39    try_get_device_id().map_or_else(
40        |e| {
41            error!(
42                ?e,
43                "Can't restore the device id from file. Using new device id."
44            );
45            let new = Uuid::new_v4();
46            const ERROR_MSG: &str =
47                "Can't save device id to file, it will not be restored next time.";
48            match get_cache_dir() {
49                Ok(path) => match File::create(path.join(ID_FILE_NAME)) {
50                    Ok(mut file) => match file.write_all(new.as_bytes()) {
51                        Ok(_) => (),
52                        Err(e) => error!(?e, ERROR_MSG),
53                    },
54                    Err(e) => error!(?e, ERROR_MSG),
55                },
56                Err(e) => error!(?e, ERROR_MSG),
57            }
58            new
59        },
60        |i| i,
61    )
62});
63
64/// 获取设备ID的函数。
65///
66/// 尝试从文件中恢复设备ID,如果失败则生成一个新的设备ID并保存到文件中。
67///
68/// # 返回值
69///
70/// 返回一个 `Uuid` 类型的设备ID。
71///
72/// # 错误处理
73///
74/// 如果从文件中恢复设备ID失败,会记录错误信息并生成一个新的设备ID。
75/// 如果保存新的设备ID到文件时也失败,会记录错误信息,在这种情况下下次将没有机会使用这个设备ID。
76///
77/// # 示例
78///
79/// ```rust
80/// use device_id::get_device_id;
81/// let device_id = get_device_id();
82/// println!("Device ID: {}", device_id);
83/// ```
84pub fn get_device_id() -> Uuid {
85    ID_FILE.clone()
86}