use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
use uuid::Uuid;
use crate::entities::User;
mod api_key_store;
mod artifact_store;
mod audit_log_store;
mod log_store;
mod run_store;
mod secret_store;
mod user_store;
#[derive(Debug, Default)]
pub(super) struct State {
pub(super) runs: HashMap<Uuid, crate::entities::Run>,
pub(super) idempotency_keys: HashMap<String, Uuid>,
pub(super) steps: HashMap<Uuid, crate::entities::Step>,
pub(super) step_dependencies: Vec<crate::entities::StepDependency>,
pub(super) artifacts: HashMap<Uuid, crate::entities::Artifact>,
pub(super) users: HashMap<Uuid, User>,
pub(super) api_keys: HashMap<Uuid, crate::entities::ApiKey>,
pub(super) secrets: HashMap<String, EncryptedSecret>,
pub(super) audit_logs: Vec<crate::entities::AuditLogEntry>,
pub(super) log_entries: Vec<crate::entities::LogEntry>,
}
#[derive(Debug, Clone)]
pub(super) struct EncryptedSecret {
pub(super) id: Uuid,
pub(super) key: String,
#[cfg(feature = "secret-store")]
pub(super) encrypted_value: Vec<u8>,
#[cfg(feature = "secret-store")]
pub(super) nonce: Vec<u8>,
#[cfg(feature = "secret-store")]
pub(super) key_version: i32,
pub(super) created_at: chrono::DateTime<chrono::Utc>,
pub(super) updated_at: chrono::DateTime<chrono::Utc>,
}
#[derive(Debug, Clone)]
pub struct InMemoryStore {
pub(super) state: Arc<RwLock<State>>,
#[cfg(feature = "secret-store")]
pub(super) key_ring: Option<Arc<crate::crypto::KeyRing>>,
}
impl InMemoryStore {
pub fn new() -> Self {
Self {
state: Arc::new(RwLock::new(State::default())),
#[cfg(feature = "secret-store")]
key_ring: None,
}
}
#[cfg(feature = "secret-store")]
pub fn set_master_key(&mut self, key: crate::crypto::MasterKey) {
self.set_key_ring(crate::crypto::KeyRing::single(key));
}
#[cfg(feature = "secret-store")]
pub fn set_key_ring(&mut self, ring: crate::crypto::KeyRing) {
self.key_ring = Some(Arc::new(ring));
}
pub async fn set_run_created_at(
&self,
run_id: Uuid,
created_at: chrono::DateTime<chrono::Utc>,
) {
let mut state = self.state.write().await;
if let Some(run) = state.runs.get_mut(&run_id) {
run.created_at = created_at;
}
}
}
impl Default for InMemoryStore {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use std::collections::HashMap;
use serde_json::json;
use crate::entities::{NewRun, TriggerKind};
use super::InMemoryStore;
pub(crate) fn new_run_req(name: &str) -> NewRun {
NewRun {
created_by: None,
workflow_name: name.to_string(),
trigger: TriggerKind::Manual,
payload: json!({}),
max_retries: 3,
handler_version: None,
labels: HashMap::new(),
scheduled_at: None,
idempotency_key: None,
max_cost_usd: None,
}
}
pub(crate) async fn create_terminal_run(
store: &InMemoryStore,
name: &str,
status: crate::entities::RunStatus,
) -> crate::entities::Run {
use crate::store::RunStore;
let run = store
.create_run(new_run_req(name))
.await
.unwrap()
.into_run();
store
.update_run_status(run.id, crate::entities::RunStatus::Running)
.await
.unwrap();
store.update_run_status(run.id, status).await.unwrap();
store.get_run(run.id).await.unwrap().unwrap()
}
}