amqp_worker 0.5.1

AMQP Worker to listen and provide trait to process message
Documentation
use crate::config;
use crate::MessageError;
use std::path::Path;
use std::thread;

#[derive(Default, Debug, Serialize, Deserialize)]
pub struct Requirement {
  paths: Option<Vec<String>>,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum Parameter {
  #[serde(rename = "array_of_strings")]
  ArrayOfStringsParam {
    id: String,
    default: Option<Vec<String>>,
    value: Option<Vec<String>>,
  },
  #[serde(rename = "boolean")]
  BooleanParam {
    id: String,
    default: Option<bool>,
    value: Option<bool>,
  },
  #[serde(rename = "credential")]
  CredentialParam {
    id: String,
    default: Option<String>,
    value: Option<String>,
  },
  #[serde(rename = "integer")]
  IntegerParam {
    id: String,
    default: Option<i64>,
    value: Option<i64>,
  },
  #[serde(rename = "requirements")]
  RequirementParam {
    id: String,
    default: Option<Requirement>,
    value: Option<Requirement>,
  },
  #[serde(rename = "string")]
  StringParam {
    id: String,
    default: Option<String>,
    value: Option<String>,
  },
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Job {
  pub job_id: u64,
  pub parameters: Vec<Parameter>,
}

#[derive(Debug)]
pub struct Credential {
  pub key: String,
}

#[derive(Debug, Serialize)]
struct Session {
  email: String,
  password: String,
}

#[derive(Debug, Serialize)]
struct SessionBody {
  session: Session,
}

#[derive(Debug, Deserialize)]
struct SessionResponseBody {
  access_token: String,
}

#[derive(Debug, Deserialize)]
struct DataResponseBody {
  id: u32,
  key: String,
  value: String,
  inserted_at: String,
}

#[derive(Debug, Deserialize)]
struct ValueResponseBody {
  data: DataResponseBody,
}

impl Credential {
  pub fn request_value(&self, job: &Job) -> Result<String, MessageError> {
    let backend_endpoint = config::get_backend_hostname();
    let backend_username = config::get_backend_username();
    let backend_password = config::get_backend_password();

    let session_url = format!("{}/sessions", backend_endpoint);
    let credential_url = format!("{}/credentials/{}", backend_endpoint, self.key);
    let job_id = job.job_id;

    let request_thread = thread::spawn(move || {
      let client = reqwest::Client::builder().build().unwrap();

      let session_body = SessionBody {
        session: Session {
          email: backend_username,
          password: backend_password,
        },
      };

      let mut response = client
        .post(&session_url)
        .json(&session_body)
        .send()
        .map_err(|e| MessageError::ProcessingError(job_id, e.to_string()))?;

      let r: SessionResponseBody = response
        .json()
        .map_err(|e| MessageError::ProcessingError(job_id, e.to_string()))?;
      let token = r.access_token;

      let mut response = client
        .get(&credential_url)
        // .bearer_auth(token)
        .header("Authorization", token)
        .send()
        .map_err(|e| MessageError::ProcessingError(job_id, e.to_string()))?;

      let resp_value: ValueResponseBody = response
        .json()
        .map_err(|e| MessageError::ProcessingError(job_id, e.to_string()))?;

      Ok(resp_value.data.value)
    });

    request_thread
      .join()
      .map_err(|e| MessageError::ProcessingError(job.job_id, format!("{:?}", e)))?
  }
}

impl Job {
  pub fn new(message: &str) -> Result<Self, MessageError> {
    let parsed: Result<Job, _> = serde_json::from_str(message);
    parsed
      .map_err(|e| MessageError::RuntimeError(format!("unable to parse input message: {:?}", e)))
  }

  pub fn get_boolean_parameter(&self, key: &str) -> Option<bool> {
    for param in self.parameters.iter() {
      if let Parameter::BooleanParam { id, default, value } = param {
        if id == key {
          if let Some(ref v) = value {
            return Some(*v);
          } else {
            return *default;
          }
        }
      }
    }
    None
  }

  pub fn get_credential_parameter(&self, key: &str) -> Option<Credential> {
    for param in self.parameters.iter() {
      if let Parameter::CredentialParam { id, default, value } = param {
        if id == key {
          if let Some(ref v) = value {
            return Some(Credential { key: v.to_string() });
          } else {
            return default.clone().map(|key| Credential { key });
          }
        }
      }
    }
    None
  }

  pub fn get_integer_parameter(&self, key: &str) -> Option<i64> {
    for param in self.parameters.iter() {
      if let Parameter::IntegerParam { id, default, value } = param {
        if id == key {
          if let Some(ref v) = value {
            return Some(*v);
          } else {
            return *default;
          }
        }
      }
    }
    None
  }

  pub fn get_string_parameter(&self, key: &str) -> Option<String> {
    for param in self.parameters.iter() {
      if let Parameter::StringParam { id, default, value } = param {
        if id == key {
          if let Some(ref v) = value {
            return Some(v.to_string());
          } else {
            return default.clone();
          }
        }
      }
    }
    None
  }

  pub fn get_array_of_strings_parameter(&self, key: &str) -> Option<Vec<String>> {
    for param in self.parameters.iter() {
      if let Parameter::ArrayOfStringsParam { id, default, value } = param {
        if id == key {
          if let Some(ref v) = value {
            return Some(v.clone());
          } else {
            return default.clone();
          }
        }
      }
    }
    None
  }

  pub fn check_requirements(&self) -> Result<(), MessageError> {
    for param in self.parameters.iter() {
      if let Parameter::RequirementParam { id, value, .. } = param {
        if id == "requirements" {
          if let Some(Requirement { paths: Some(paths) }) = value {
            for path in paths.iter() {
              let p = Path::new(path);
              if !p.exists() {
                return Err(MessageError::RequirementsError(format!(
                  "Warning: Required file does not exists: {:?}",
                  p
                )));
              }
            }
          }
        }
      }
    }
    Ok(())
  }
}