signer-daemon 0.2.3

Signer daemon package.
Documentation
use std::collections::HashSet;

use serde::{Deserialize, Serialize};
use signer_core::{SignerSigned, SignerUserPublic};

use crate::{
  model::viewobject::{Envelope, MessageVO, UserVO},
  reqwest_auth::ReqwestAuth as _,
};

use super::SignerDaemon;

impl SignerDaemon {
  pub async fn remote_pull_message(&self, addr: &str) -> anyhow::Result<()> {
    let user = self.user.lock().await.clone();
    let client = reqwest::Client::new();
    let r = client
      .get(&format!("{}/envelopes", addr))
      .with_signer_auth(&user)
      .send()
      .await?
      .error_for_status()?;

    let json = r.json::<GetEnvelopesResponse>().await?;

    let mut success_set: HashSet<i32> = HashSet::new();
    for e in json.data {
      let message = match e.envelope.open(&user) {
        Ok(val) => val.message,
        Err(_) => continue,
      };

      self.put_message(message).await?;
      success_set.insert(e.id);
    }

    client
      .patch(&format!("{}/envelopes/check", addr))
      .with_signer_auth(&user)
      .json(&serde_json::json!({
        "ids": success_set.into_iter().collect::<Vec<i32>>()
      }))
      .send()
      .await?
      .error_for_status()?;

    Ok(())
  }

  pub async fn remote_push_message(
    &self,
    destinations: Vec<String>,
    data: Vec<MessageVO>,
  ) -> anyhow::Result<()> {
    let mut envelopes = Vec::new();
    for i in data {
      let envelope = Envelope::create(&self, &i, destinations.clone()).await?;
      envelopes.push(envelope);
    }

    let user = self.user.lock().await.clone();
    for e in envelopes {
      e.send(&user).await?;
    }

    Ok(())
  }

  pub async fn remote_pull_user(
    &self,
    addr: &str,
    user_key: &str,
  ) -> anyhow::Result<()> {
    let user = self.user.lock().await.clone();
    let client = reqwest::Client::new();
    let r = client
      .get(&format!("{}/users/{}", addr, user_key))
      .with_signer_auth(&user)
      .send()
      .await?
      .error_for_status()?;

    let json = r.json::<SignerSigned<SignerUserPublic>>().await?;
    let up = json.verify_to_value()?;
    let user_vo = UserVO {
      pub_key: up.pub_key.clone(),
      user_public: serde_json::to_string(&up)?,
      signed_user_public: serde_json::to_string(&json)?,
    };

    self.put_user(user_vo).await?;

    self.wait_apply().await?;

    Ok(())
  }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
struct GetEnvelopesResponse {
  data: Vec<EnvelopeBox>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
struct EnvelopeBox {
  id: i32,
  envelope: Envelope,
}

#[cfg(test)]
mod tests {
  use signer_core::SignerUser;

  use crate::SignerDaemon;

  #[tokio::test]
  async fn test_pull_user() -> anyhow::Result<()> {
    let u = SignerUser::generete("alice")?;
    let peer = uuid::Uuid::new_v4().to_string();
    let daemon = SignerDaemon::from_memory(&u, &peer).await?;
    daemon.wait_apply().await?;

    daemon
      .ping_server("http://localhost:8080/api/signer")
      .await?;

    daemon
      .remote_pull_user("http://localhost:8080/api/signer", &u.public.pub_key)
      .await?;

    let target = daemon.get_user(&u.public.pub_key).await?;

    assert!(target.is_some());

    Ok(())
  }
}