move repos into monorepo
This commit is contained in:
286
bin/supervisor/src/store.rs
Normal file
286
bin/supervisor/src/store.rs
Normal file
@@ -0,0 +1,286 @@
|
||||
//! In-memory storage layer for Supervisor
|
||||
//!
|
||||
//! Provides CRUD operations for:
|
||||
//! - API Keys
|
||||
//! - Runners
|
||||
//! - Jobs
|
||||
|
||||
use crate::auth::{ApiKey, ApiKeyScope};
|
||||
use crate::error::{SupervisorError, SupervisorResult};
|
||||
use hero_job::Job;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
/// In-memory storage for all supervisor data
|
||||
pub struct Store {
|
||||
/// API keys (key_value -> ApiKey)
|
||||
api_keys: HashMap<String, ApiKey>,
|
||||
/// Registered runner IDs
|
||||
runners: HashSet<String>,
|
||||
/// In-memory job storage (job_id -> Job)
|
||||
jobs: HashMap<String, Job>,
|
||||
}
|
||||
|
||||
impl Store {
|
||||
/// Create a new store
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
api_keys: HashMap::new(),
|
||||
runners: HashSet::new(),
|
||||
jobs: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== API Key Operations ====================
|
||||
|
||||
/// Create an API key with a specific value
|
||||
pub fn key_create(&mut self, key: ApiKey) -> ApiKey {
|
||||
self.api_keys.insert(key.name.clone(), key.clone());
|
||||
key
|
||||
}
|
||||
|
||||
/// Create a new API key with generated UUID
|
||||
pub fn key_create_new(&mut self, name: String, scope: ApiKeyScope) -> ApiKey {
|
||||
let key = ApiKey::new(name, scope);
|
||||
self.api_keys.insert(key.name.clone(), key.clone());
|
||||
key
|
||||
}
|
||||
|
||||
/// Get an API key by its value
|
||||
pub fn key_get(&self, key_name: &str) -> Option<&ApiKey> {
|
||||
self.api_keys.get(key_name)
|
||||
}
|
||||
|
||||
/// Delete an API key
|
||||
pub fn key_delete(&mut self, key_name: &str) -> Option<ApiKey> {
|
||||
self.api_keys.remove(key_name)
|
||||
}
|
||||
|
||||
/// List all API keys
|
||||
pub fn key_list(&self) -> Vec<ApiKey> {
|
||||
self.api_keys.values().cloned().collect()
|
||||
}
|
||||
|
||||
/// List API keys by scope
|
||||
pub fn key_list_by_scope(&self, scope: ApiKeyScope) -> Vec<ApiKey> {
|
||||
self.api_keys
|
||||
.values()
|
||||
.filter(|k| k.scope == scope)
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
|
||||
// ==================== Runner Operations ====================
|
||||
|
||||
/// Add a runner
|
||||
pub fn runner_add(&mut self, runner_id: String) -> SupervisorResult<()> {
|
||||
self.runners.insert(runner_id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Remove a runner
|
||||
pub fn runner_remove(&mut self, runner_id: &str) -> SupervisorResult<()> {
|
||||
self.runners.remove(runner_id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Check if a runner exists
|
||||
pub fn runner_exists(&self, runner_id: &str) -> bool {
|
||||
self.runners.contains(runner_id)
|
||||
}
|
||||
|
||||
/// List all runner IDs
|
||||
pub fn runner_list_all(&self) -> Vec<String> {
|
||||
self.runners.iter().cloned().collect()
|
||||
}
|
||||
|
||||
// ==================== Job Operations ====================
|
||||
|
||||
/// Store a job in memory
|
||||
pub fn job_store(&mut self, job: Job) -> SupervisorResult<()> {
|
||||
self.jobs.insert(job.id.clone(), job);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get a job from memory
|
||||
pub fn job_get(&self, job_id: &str) -> SupervisorResult<Job> {
|
||||
self.jobs
|
||||
.get(job_id)
|
||||
.cloned()
|
||||
.ok_or_else(|| SupervisorError::JobNotFound {
|
||||
job_id: job_id.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Delete a job from memory
|
||||
pub fn job_delete(&mut self, job_id: &str) -> SupervisorResult<()> {
|
||||
self.jobs
|
||||
.remove(job_id)
|
||||
.ok_or_else(|| SupervisorError::JobNotFound {
|
||||
job_id: job_id.to_string(),
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// List all job IDs
|
||||
pub fn job_list(&self) -> Vec<String> {
|
||||
self.jobs.keys().cloned().collect()
|
||||
}
|
||||
|
||||
/// Check if a job exists
|
||||
pub fn job_exists(&self, job_id: &str) -> bool {
|
||||
self.jobs.contains_key(job_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Store {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
api_keys: self.api_keys.clone(),
|
||||
runners: self.runners.clone(),
|
||||
jobs: self.jobs.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use hero_job::JobBuilder;
|
||||
|
||||
fn create_test_store() -> Store {
|
||||
Store::new()
|
||||
}
|
||||
|
||||
fn create_test_job(id: &str, runner: &str) -> Job {
|
||||
let mut job = JobBuilder::new()
|
||||
.caller_id("test_caller")
|
||||
.context_id("test_context")
|
||||
.runner(runner)
|
||||
.executor("test")
|
||||
.payload("test payload")
|
||||
.build()
|
||||
.unwrap();
|
||||
job.id = id.to_string(); // Set ID manually
|
||||
job
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_api_key_operations() {
|
||||
let mut store = create_test_store();
|
||||
|
||||
// Create key
|
||||
let key = store.key_create_new("test_key".to_string(), ApiKeyScope::Admin);
|
||||
assert_eq!(key.name, "test_key");
|
||||
assert_eq!(key.scope, ApiKeyScope::Admin);
|
||||
|
||||
// Get key
|
||||
let retrieved = store.key_get(&key.key);
|
||||
assert!(retrieved.is_some());
|
||||
assert_eq!(retrieved.unwrap().name, "test_key");
|
||||
|
||||
// List keys
|
||||
let keys = store.key_list();
|
||||
assert_eq!(keys.len(), 1);
|
||||
|
||||
// List by scope
|
||||
let admin_keys = store.key_list_by_scope(ApiKeyScope::Admin);
|
||||
assert_eq!(admin_keys.len(), 1);
|
||||
|
||||
// Delete key
|
||||
let removed = store.key_delete(&key.key);
|
||||
assert!(removed.is_some());
|
||||
assert!(store.key_get(&key.key).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_runner_operations() {
|
||||
let mut store = create_test_store();
|
||||
|
||||
// Add runner
|
||||
assert!(store.runner_add("runner1".to_string()).is_ok());
|
||||
assert!(store.runner_exists("runner1"));
|
||||
|
||||
// List runners
|
||||
let runners = store.runner_list_all();
|
||||
assert_eq!(runners.len(), 1);
|
||||
assert!(runners.contains(&"runner1".to_string()));
|
||||
|
||||
// List all runners
|
||||
let all_runners = store.runner_list_all();
|
||||
assert_eq!(all_runners.len(), 1);
|
||||
|
||||
// Remove runner
|
||||
assert!(store.runner_remove("runner1").is_ok());
|
||||
assert!(!store.runner_exists("runner1"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_job_operations() {
|
||||
let mut store = create_test_store();
|
||||
let job = create_test_job("job1", "runner1");
|
||||
|
||||
// Store job
|
||||
assert!(store.job_store(job.clone()).is_ok());
|
||||
assert!(store.job_exists("job1"));
|
||||
|
||||
// Get job
|
||||
let retrieved = store.job_get("job1");
|
||||
assert!(retrieved.is_ok());
|
||||
assert_eq!(retrieved.unwrap().id, "job1");
|
||||
|
||||
// List jobs
|
||||
let jobs = store.job_list();
|
||||
assert_eq!(jobs.len(), 1);
|
||||
assert!(jobs.contains(&"job1".to_string()));
|
||||
|
||||
// Delete job
|
||||
assert!(store.job_delete("job1").is_ok());
|
||||
assert!(!store.job_exists("job1"));
|
||||
assert!(store.job_get("job1").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_job_not_found() {
|
||||
let store = create_test_store();
|
||||
let result = store.job_get("nonexistent");
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multiple_jobs() {
|
||||
let mut store = create_test_store();
|
||||
|
||||
// Add multiple jobs
|
||||
for i in 1..=3 {
|
||||
let job = create_test_job(&format!("job{}", i), "runner1");
|
||||
assert!(store.job_store(job).is_ok());
|
||||
}
|
||||
|
||||
// Verify all exist
|
||||
assert_eq!(store.job_list().len(), 3);
|
||||
assert!(store.job_exists("job1"));
|
||||
assert!(store.job_exists("job2"));
|
||||
assert!(store.job_exists("job3"));
|
||||
|
||||
// Delete one
|
||||
assert!(store.job_delete("job2").is_ok());
|
||||
assert_eq!(store.job_list().len(), 2);
|
||||
assert!(!store.job_exists("job2"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_store_clone() {
|
||||
let mut store = create_test_store();
|
||||
store.runner_add("runner1".to_string()).unwrap();
|
||||
|
||||
let job = create_test_job("job1", "runner1");
|
||||
store.job_store(job).unwrap();
|
||||
|
||||
// Clone the store
|
||||
let cloned = store.clone();
|
||||
|
||||
// Verify cloned data
|
||||
assert!(cloned.runner_exists("runner1"));
|
||||
assert!(cloned.job_exists("job1"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user