signer-daemon 0.3.2

Signer daemon package.
Documentation
use std::fs;

use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
use signer_core::{SignerUser, SignerUserPublic};

use crate::{
    SignerDaemonCore, SignerDaemonOption, SignerDaemonState, UserStore,
    entity::{server, user},
    model::viewobject::UserVO,
};

use super::SignerDaemon;

impl SignerDaemon {
    pub(crate) async fn sync_user_public(&mut self) -> crate::DaemonResult<()> {
        let mut syncer = UserInfoSynchronizer::new(self.core.clone(), self.option.clone());
        syncer.sync(&mut self.state).await?;

        Ok(())
    }
}

pub struct UserInfoSynchronizer {
    core: SignerDaemonCore,
    user_store: UserStore,
    option: SignerDaemonOption,
}

impl UserInfoSynchronizer {
    pub fn new(core: SignerDaemonCore, option: SignerDaemonOption) -> Self {
        Self {
            core: core.clone(),
            user_store: UserStore::new(core.clone(), option.clone()),
            option,
        }
    }

    pub async fn sync(&mut self, state: &mut SignerDaemonState) -> crate::DaemonResult<()> {
        let mem_up = &state.user.public;
        let json_up = match &self.option.user_file_path {
            Some(path) => {
                let u: SignerUser = serde_json::from_str(&fs::read_to_string(path)?)?;
                Some(u.public)
            }
            None => None,
        };
        let db_up: Option<SignerUserPublic> = match user::Entity::find()
            .filter(user::Column::PubKey.eq(&mem_up.pub_key))
            .one(&self.core.db)
            .await?
        {
            None => None,
            Some(m) => Some(serde_json::from_str(&m.user_public)?),
        };

        // 从内存、user.json、数据库中获取最新的 UserPublic 信息
        let mut up: SignerUserPublic = {
            let mut up = mem_up.clone();
            if let Some(json_up) = &json_up {
                if json_up.update_time > up.update_time {
                    up = json_up.clone();
                }
            }
            if let Some(db_up) = &db_up {
                if db_up.update_time > up.update_time {
                    up = db_up.clone();
                }
            }
            up
        };

        // 检查 AllowEndpoints 是否需要更新
        {
            let servers = server::Entity::find().all(&self.core.db).await?;
            let mut allow_endpoints = servers.into_iter().map(|s| s.addr).collect::<Vec<String>>();
            allow_endpoints.sort();

            if allow_endpoints != up.allow_endpoints {
                up.allow_endpoints = allow_endpoints;
                up.update_time = chrono::Utc::now().timestamp_millis();
            }
        }

        // 将更新后的数据按需合并至内存、user.json、数据库
        {
            if up.update_time > mem_up.update_time {
                tracing::debug!("已更新内存中的用户信息");
                state.user.public = up.clone();
            }
            if let Some(json_up) = json_up {
                if up.update_time > json_up.update_time {
                    tracing::debug!("已更新配置文件中的用户信息");
                    let p = self.option.user_file_path.as_ref().unwrap();
                    let mut u: SignerUser = serde_json::from_str(&fs::read_to_string(p)?)?;
                    u.public = up.clone();
                    fs::write(p, serde_json::to_string(&u)?)?;
                }
            }

            let db_need_update = match db_up {
                None => true,
                Some(db_up) => up.update_time > db_up.update_time,
            };
            if db_need_update {
                tracing::debug!("已更新数据库中的用户信息");
                self.user_store
                    .put(state, UserVO::from_signer_user(state.user.clone()).await?)
                    .await?;
            }
        }

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use crate::model::viewobject::ServerVO;

    use super::*;
    use tokio;

    #[tokio::test]
    async fn test_sync_user_public() -> crate::DaemonResult<()> {
        // 使用 generate 方法生成随机的 SignerUser 并设置初始数据
        let random_user = SignerUser::generete("test_user").unwrap();
        let daemon = SignerDaemon::from_memory(&random_user, "test").await?;
        let daemon_write = &mut *daemon.write().await;

        daemon_write
            .store
            .server
            .put(
                &mut daemon_write.state,
                ServerVO {
                    addr: "http://localhost:8080".into(),
                    enable: true,
                    limitation_set: "".into(),
                },
            )
            .await?;

        // 创建同步器
        let mut syncer =
            UserInfoSynchronizer::new(daemon_write.core.clone(), daemon_write.option.clone());

        syncer.sync(&mut daemon_write.state).await?;

        // 验证用户信息是否已更新
        assert!(
            daemon_write.state.user.public.update_time > 0,
            "用户信息未正确更新"
        );

        // 从数据库中查询用户信息
        let db_user = user::Entity::find()
            .filter(user::Column::PubKey.eq(&daemon_write.state.user.public.pub_key))
            .one(&daemon_write.core.db)
            .await?
            .expect("数据库中未找到用户信息");

        // 解析数据库中的用户信息
        let db_user_public: SignerUserPublic = serde_json::from_str(&db_user.user_public)?;

        // 验证数据库中的信息与内存中的一致
        assert_eq!(
            db_user_public.update_time, daemon_write.state.user.public.update_time,
            "数据库中的 update_time 与内存中的不一致"
        );

        Ok(())
    }
}