signer-remote 0.4.1

Signer remote communication package.
Documentation
// 引入必要的模块和类型
use crate::{
    SignerSummary,
    error::{RemoteError, RemoteResult},
};
use signer_core::{SignerKeys, SignerUser};
use signer_crdt::SignerMeta; // 修正导入路径

// 为模块内部定义一个别名,以匹配代码中的使用习惯
type SignerRemoteError = RemoteError;

/// 生成一个新的随机用户账户。
/// 这通常用于没有现有账户的设备。
pub fn generate_new_account() -> RemoteResult<(SignerKeys, SignerUser)> {
    // 1. 生成新的密钥对
    let keys = SignerKeys::generate()
        .map_err(|e| SignerRemoteError::Internal(format!("生成密钥对失败: {}", e)))?;

    // 2. 创建一个默认的 SignerUser 对象
    // 注意:这里创建的 User 对象是临时的,没有实际的服务器关联。
    // 它主要用于在设备配对过程中标识自己。
    let user = SignerUser {
        pub_key: keys.pub_key.clone(),
        username: "New User".to_string(), // 可以是一个默认名称或空字符串
        update_time: chrono::Utc::now().timestamp(),
        ..Default::default()
    };

    Ok((keys, user))
}

/// 为给定的密钥创建一个内存中的 SignerMeta 实例。
/// 这允许无账户设备在连接到 Hub 之前拥有一个有效的上下文。
pub async fn create_memory_meta(keys: SignerKeys) -> RemoteResult<SignerMeta> {
    let meta = SignerMeta::from_mem(keys)
        .await
        .map_err(|e| SignerRemoteError::Internal(format!("创建内存 Meta 失败: {}", e)))?;
    Ok(meta)
}

/// 准备传输数据。
/// 主设备在选择目标设备后,需要准备要传输的 `SignerSummary`。
/// 这包括获取当前用户的完整信息并将其打包。
///
/// # 参数
/// * `current_meta` - 主设备当前的 `SignerMeta`,包含有效的密钥和数据库连接。
///
/// # 返回
/// * `SignerSummary` - 包含了主设备核心密钥和用户信息的结构体。
pub async fn prepare_transfer_data(current_meta: &SignerMeta) -> RemoteResult<SignerSummary> {
    // 1. 从当前 Meta 中获取密钥
    let keys = current_meta.keys.clone();

    // 2. 从数据库获取当前用户的完整信息
    // 注意:SignerMeta::get_current_user() 会查询数据库以获取签名的用户信息。
    // 这确保了我们传输的是最新、最完整的用户数据。
    let user = current_meta
        .get_current_user()
        .await
        .map_err(|e| SignerRemoteError::Internal(format!("获取当前用户信息失败: {}", e)))?;

    // 3. 创建 SignerSummary
    let summary = SignerSummary { keys, user };

    Ok(summary)
}

/// 接收并应用传输的数据。
/// 当接收方设备收到 `SignerSummary` 后,需要将其保存并初始化自己的环境。
///
/// # 参数
/// * `received_summary` - 从发送方解密得到的 `SignerSummary`。
/// * `storage_path` - 用于保存密钥和数据库文件的本地路径。
///
/// # 返回
/// * `SignerMeta` - 新创建的、基于接收到的数据的 `SignerMeta` 实例。
pub async fn receive_and_apply_transfer_data(
    received_summary: SignerSummary,
    storage_path: &str,
) -> RemoteResult<SignerMeta> {
    // 1. 将接收到的密钥保存到文件系统
    // 这使得设备在下次启动时能够加载这些密钥。
    SignerMeta::save_fs_raw_keys(&received_summary.keys, storage_path).map_err(|e| {
        SignerRemoteError::Internal(format!(
            "步骤1失败 - 保存密钥到文件系统失败 (路径: {}, 公钥: {}): {}",
            storage_path,
            &received_summary.keys.pub_key[..8],
            e
        ))
    })?;

    // 2. 使用保存的密钥从文件系统创建新的 SignerMeta
    // 这会初始化一个新的数据库连接。
    let new_meta = SignerMeta::from_fs(storage_path).await.map_err(|e| {
        SignerRemoteError::Internal(format!(
            "步骤2失败 - 从文件系统创建SignerMeta失败 (路径: {}): {}",
            storage_path, e
        ))
    })?;

    // 3. 创建并保存 UserVO 到数据库中
    // 这一步是关键的,确保用户数据能够被正确存储和查询
    use signer_crdt::UserVO;
    let vo = UserVO::from_user_data(&received_summary.keys, &received_summary.user)
        .await
        .map_err(|e| {
            SignerRemoteError::Internal(format!(
                "步骤3失败 - 从用户数据创建UserVO失败 (用户名: {}): {}",
                received_summary.user.username, e
            ))
        })?;

    vo.put(&new_meta).await.map_err(|e| {
        SignerRemoteError::Internal(format!(
            "步骤3失败 - 保存UserVO到数据库失败 (用户名: {}): {}",
            received_summary.user.username, e
        ))
    })?;

    // 注意:此时,新的设备已经拥有了正确的密钥、数据库环境和用户数据。
    // 下一步通常是连接到 `received_summary.user.allow_endpoints` 中指定的服务器,
    // 并开始同步 CRDT 数据。这部分逻辑通常在 App 层实现。

    Ok(new_meta)
}