use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::time::Duration;
use crate::error::{CCSwarmError, Result};
pub trait Identifiable {
fn id(&self) -> &str;
fn name(&self) -> &str {
self.id()
}
}
pub trait Describable: Identifiable {
fn description(&self) -> Option<&str> {
None
}
fn metadata(&self) -> HashMap<String, String> {
HashMap::new()
}
fn created_at(&self) -> chrono::DateTime<chrono::Utc>;
fn updated_at(&self) -> chrono::DateTime<chrono::Utc>;
}
pub trait Stateful {
type State: Clone + PartialEq + std::fmt::Debug;
fn state(&self) -> &Self::State;
fn is_operational(&self) -> bool;
fn state_history(&self) -> Vec<(Self::State, chrono::DateTime<chrono::Utc>)> {
Vec::new()
}
}
pub trait Configurable {
type Config: Clone + Serialize + for<'de> Deserialize<'de>;
fn config(&self) -> &Self::Config;
fn update_config(&mut self, config: Self::Config) -> Result<()>;
fn validate_config(config: &Self::Config) -> Result<()>;
fn default_config() -> Self::Config;
}
#[async_trait]
pub trait Monitorable {
type HealthStatus: Clone + std::fmt::Debug + Serialize;
type Metrics: Clone + std::fmt::Debug + Serialize;
async fn health_check(&self) -> Result<Self::HealthStatus>;
async fn metrics(&self) -> Result<Self::Metrics>;
async fn historical_metrics(
&self,
since: chrono::DateTime<chrono::Utc>,
) -> Result<Vec<(chrono::DateTime<chrono::Utc>, Self::Metrics)>> {
let _ = since;
Ok(Vec::new())
}
}
#[async_trait]
pub trait Executable {
type Input: Send + Sync;
type Output: Send + Sync;
type Context: Send + Sync;
async fn execute(&mut self, input: Self::Input, context: Self::Context)
-> Result<Self::Output>;
fn can_execute(&self, input: &Self::Input) -> bool;
fn estimated_duration(&self, input: &Self::Input) -> Option<Duration> {
let _ = input;
None
}
}
#[async_trait]
pub trait Pausable {
async fn pause(&mut self) -> Result<()>;
async fn resume(&mut self) -> Result<()>;
fn is_paused(&self) -> bool;
}
#[async_trait]
pub trait Shutdownable {
async fn shutdown(&mut self) -> Result<()>;
async fn force_shutdown(&mut self) -> Result<()> {
self.shutdown().await
}
fn is_shutting_down(&self) -> bool;
fn shutdown_timeout(&self) -> Duration {
Duration::from_secs(30)
}
}
pub trait Validatable {
type ValidationResult: std::fmt::Debug;
fn validate(&self) -> Result<Self::ValidationResult>;
fn auto_fix(&mut self) -> Result<Vec<String>> {
Ok(Vec::new())
}
}
#[async_trait]
pub trait EventEmitter {
type Event: Clone + Send + Sync + std::fmt::Debug;
async fn emit_event(&self, event: Self::Event) -> Result<()>;
async fn subscribe(&self) -> Result<tokio::sync::mpsc::Receiver<Self::Event>>;
}
#[async_trait]
pub trait Cacheable {
type Key: Clone + Eq + std::hash::Hash + Send + Sync;
type Value: Clone + Send + Sync;
async fn get(&self, key: &Self::Key) -> Option<Self::Value>;
async fn set(&mut self, key: Self::Key, value: Self::Value) -> Result<()>;
async fn remove(&mut self, key: &Self::Key) -> Result<Option<Self::Value>>;
async fn clear(&mut self) -> Result<()>;
async fn stats(&self) -> CacheStats;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CacheStats {
pub hits: u64,
pub misses: u64,
pub entries: usize,
pub memory_usage: usize,
pub hit_rate: f64,
}
impl CacheStats {
pub fn new() -> Self {
Self {
hits: 0,
misses: 0,
entries: 0,
memory_usage: 0,
hit_rate: 0.0,
}
}
pub fn calculate_hit_rate(&mut self) {
let total = self.hits + self.misses;
self.hit_rate = if total > 0 {
self.hits as f64 / total as f64
} else {
0.0
};
}
}
impl Default for CacheStats {
fn default() -> Self {
Self::new()
}
}
#[async_trait]
pub trait Retryable {
type Operation: Send + Sync;
type Result: Send + Sync;
async fn retry_with_backoff<F, Fut>(
&self,
operation: F,
max_attempts: u32,
initial_delay: Duration,
max_delay: Duration,
) -> Result<Self::Result>
where
F: Fn() -> Fut + Send + Sync,
Fut: std::future::Future<Output = Result<Self::Result>> + Send;
fn default_retry_config() -> RetryConfig {
RetryConfig::default()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RetryConfig {
pub max_attempts: u32,
pub initial_delay: Duration,
pub max_delay: Duration,
pub backoff_multiplier: f64,
pub jitter: bool,
}
impl Default for RetryConfig {
fn default() -> Self {
Self {
max_attempts: 3,
initial_delay: Duration::from_millis(100),
max_delay: Duration::from_secs(30),
backoff_multiplier: 2.0,
jitter: true,
}
}
}
#[async_trait]
pub trait Cleanupable {
async fn cleanup(&mut self) -> Result<CleanupReport>;
fn needs_cleanup(&self) -> bool {
false
}
fn cleanup_schedule(&self) -> Option<Duration> {
None
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CleanupReport {
pub items_cleaned: usize,
pub bytes_freed: usize,
pub duration: Duration,
pub errors: Vec<String>,
}
impl CleanupReport {
pub fn new() -> Self {
Self {
items_cleaned: 0,
bytes_freed: 0,
duration: Duration::from_millis(0),
errors: Vec::new(),
}
}
pub fn with_items(mut self, count: usize) -> Self {
self.items_cleaned = count;
self
}
pub fn with_bytes_freed(mut self, bytes: usize) -> Self {
self.bytes_freed = bytes;
self
}
pub fn with_duration(mut self, duration: Duration) -> Self {
self.duration = duration;
self
}
pub fn add_error<S: Into<String>>(mut self, error: S) -> Self {
self.errors.push(error.into());
self
}
}
impl Default for CleanupReport {
fn default() -> Self {
Self::new()
}
}
#[allow(async_fn_in_trait)]
pub trait Persistable: Serialize + for<'de> Deserialize<'de> {
fn to_bytes(&self) -> Result<Vec<u8>> {
serde_json::to_vec(self).map_err(CCSwarmError::from)
}
fn from_bytes(bytes: &[u8]) -> Result<Self>
where
Self: Sized,
{
serde_json::from_slice(bytes).map_err(CCSwarmError::from)
}
async fn save_to_file<P: AsRef<std::path::Path> + Send>(&self, path: P) -> Result<()> {
let bytes = self.to_bytes()?;
tokio::fs::write(path, bytes)
.await
.map_err(CCSwarmError::from)
}
async fn load_from_file<P: AsRef<std::path::Path> + Send>(path: P) -> Result<Self>
where
Self: Sized,
{
let bytes = tokio::fs::read(path).await.map_err(CCSwarmError::from)?;
Self::from_bytes(&bytes)
}
}
impl<T> Persistable for T where T: Serialize + for<'de> Deserialize<'de> {}
#[macro_export]
macro_rules! generate_id {
($prefix:expr) => {
format!("{}-{}", $prefix, uuid::Uuid::new_v4())
};
() => {
uuid::Uuid::new_v4().to_string()
};
}
#[macro_export]
macro_rules! with_timestamp {
($entity:expr) => {{
let now = chrono::Utc::now();
$entity.created_at = now;
$entity.updated_at = now;
$entity
}};
}
#[macro_export]
macro_rules! impl_entity_traits {
($type:ty, $id_field:ident, $name_field:ident) => {
impl $crate::traits::Identifiable for $type {
fn id(&self) -> &str {
&self.$id_field
}
fn name(&self) -> &str {
&self.$name_field
}
}
};
($type:ty, $id_field:ident) => {
impl $crate::traits::Identifiable for $type {
fn id(&self) -> &str {
&self.$id_field
}
}
};
}