use crate::nft::errors::{NftError, NftResult};
use crate::nft::types::*;
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::Arc;
#[async_trait]
pub trait NftProcessingStrategy: Send + Sync {
fn name(&self) -> &str;
fn description(&self) -> &str;
fn priority(&self) -> u8;
fn applies_to(&self, context: &StrategyContext) -> bool;
async fn execute(&self, context: StrategyContext) -> NftResult<StrategyResult>;
fn required_capabilities(&self) -> Vec<StrategyCapability>;
fn estimated_execution_time_ms(&self) -> u64;
}
#[derive(Debug, Clone)]
pub struct StrategyContext {
pub wallet_address: Option<String>,
pub mint_addresses: Vec<String>,
pub performance_mode: PerformanceMode,
pub security_level: SecurityLevel,
pub options: StrategyOptions,
pub resources: ResourceConstraints,
pub metadata: HashMap<String, serde_json::Value>,
}
#[derive(Debug, Clone)]
pub struct StrategyResult {
pub strategy_name: String,
pub status: StrategyStatus,
pub processed_nfts: Vec<NftInfo>,
pub insights: Vec<StrategyInsight>,
pub metrics: StrategyMetrics,
pub execution_time_ms: u64,
pub additional_data: HashMap<String, serde_json::Value>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum StrategyStatus {
Success,
PartialSuccess,
Failure,
Skipped,
Timeout,
}
#[derive(Debug, Clone)]
pub struct StrategyInsight {
pub insight_type: String,
pub message: String,
pub confidence: f64,
pub related_nfts: Vec<String>,
pub data: HashMap<String, serde_json::Value>,
}
#[derive(Debug, Clone)]
pub struct StrategyMetrics {
pub items_processed: u64,
pub items_successful: u64,
pub items_failed: u64,
pub cache_hits: u64,
pub network_requests: u64,
pub memory_usage_bytes: u64,
}
#[derive(Debug, Clone)]
pub struct StrategyOptions {
pub enable_metadata: bool,
pub enable_valuation: bool,
pub enable_security_validation: bool,
pub enable_portfolio_analysis: bool,
pub enable_batch_processing: bool,
pub max_concurrent_operations: Option<usize>,
pub timeout_seconds: Option<u64>,
pub custom_options: HashMap<String, serde_json::Value>,
}
impl Default for StrategyOptions {
fn default() -> Self {
Self {
enable_metadata: true,
enable_valuation: true,
enable_security_validation: true,
enable_portfolio_analysis: true,
enable_batch_processing: true,
max_concurrent_operations: None,
timeout_seconds: None,
custom_options: HashMap::new(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum SecurityLevel {
Minimal,
Standard,
Strict,
Paranoid,
}
#[derive(Debug, Clone)]
pub struct ResourceConstraints {
pub max_memory_mb: Option<u64>,
pub max_cpu_percent: Option<f64>,
pub max_requests_per_second: Option<u64>,
pub max_execution_time_seconds: Option<u64>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum StrategyCapability {
MetadataFetching,
Valuation,
SecurityValidation,
PortfolioAnalysis,
BatchProcessing,
Caching,
ParallelProcessing,
RealTimeProcessing,
}
#[derive(Clone)]
pub struct StrategyManager {
strategies: Vec<Arc<dyn NftProcessingStrategy>>,
registry: Arc<StrategyRegistry>,
metrics: Arc<StrategyManagerMetrics>,
}
#[derive(Clone)]
pub struct StrategyRegistry {
strategies: Arc<std::sync::RwLock<HashMap<String, Arc<dyn NftProcessingStrategy>>>>,
metadata: Arc<std::sync::RwLock<HashMap<String, StrategyMetadata>>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StrategyMetadata {
pub name: String,
pub description: String,
pub version: String,
pub author: String,
pub tags: Vec<String>,
pub required_capabilities: Vec<StrategyCapability>,
pub supported_performance_modes: Vec<PerformanceMode>,
pub estimated_resource_usage: ResourceUsageEstimate,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResourceUsageEstimate {
pub memory_per_item_kb: u64,
pub cpu_per_item_percent: f64,
pub network_requests_per_item: u64,
pub execution_time_per_item_ms: u64,
}
#[derive(Debug, Default)]
pub struct StrategyManagerMetrics {
pub total_executions: Arc<std::sync::atomic::AtomicU64>,
pub successful_executions: Arc<std::sync::atomic::AtomicU64>,
pub failed_executions: Arc<std::sync::atomic::AtomicU64>,
pub avg_execution_time_ms: Arc<std::sync::atomic::AtomicU64>,
pub executions_by_strategy: Arc<std::sync::RwLock<HashMap<String, u64>>>,
}
pub struct UltraFastStrategy {
metadata: StrategyMetadata,
}
pub struct BalancedStrategy {
metadata: StrategyMetadata,
}
pub struct ThoroughStrategy {
metadata: StrategyMetadata,
}
pub struct SecurityFocusedStrategy {
metadata: StrategyMetadata,
}
pub struct ValuationFocusedStrategy {
metadata: StrategyMetadata,
}
pub struct CustomStrategy {
metadata: StrategyMetadata,
config: CustomStrategyConfig,
}
#[derive(Debug, Clone)]
pub struct CustomStrategyConfig {
pub name: String,
pub processing_steps: Vec<ProcessingStep>,
pub step_config: HashMap<String, serde_json::Value>,
pub error_handling: ErrorHandlingConfig,
}
#[derive(Debug, Clone)]
pub struct ProcessingStep {
pub name: String,
pub step_type: ProcessingStepType,
pub order: u32,
pub config: serde_json::Value,
pub required_capabilities: Vec<StrategyCapability>,
}
#[derive(Debug, Clone)]
pub enum ProcessingStepType {
MetadataFetch,
Validation,
Valuation,
SecurityCheck,
PortfolioAnalysis,
Custom { step_name: String },
}
#[derive(Debug, Clone)]
pub struct ErrorHandlingConfig {
pub continue_on_error: bool,
pub max_retry_attempts: u32,
pub retry_delay_ms: u64,
pub fallback_strategy: Option<String>,
}
impl StrategyManager {
pub fn new() -> Self {
let registry = Arc::new(StrategyRegistry::new());
let metrics = Arc::new(StrategyManagerMetrics::default());
let mut manager = Self {
strategies: Vec::new(),
registry,
metrics,
};
manager.register_builtin_strategies();
manager
}
pub fn register_strategy(&mut self, strategy: Arc<dyn NftProcessingStrategy>) {
self.registry.register_strategy(strategy.clone());
self.strategies.push(strategy);
}
pub async fn execute_strategy(&self, context: StrategyContext) -> NftResult<StrategyResult> {
let start_time = std::time::Instant::now();
self.metrics.total_executions.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
let applicable_strategies: Vec<&Arc<dyn NftProcessingStrategy>> = self.strategies
.iter()
.filter(|strategy| strategy.applies_to(&context))
.collect();
if applicable_strategies.is_empty() {
return Err(NftError::Strategy {
message: "No applicable strategies found".to_string(),
strategy_name: None,
context: Some(format!("Performance mode: {:?}", context.performance_mode)),
});
}
let best_strategy = applicable_strategies
.iter()
.max_by_key(|strategy| strategy.priority())
.unwrap();
let result = best_strategy.execute(context).await;
let execution_time_ms = start_time.elapsed().as_millis() as u64;
self.metrics.avg_execution_time_ms.fetch_add(execution_time_ms, std::sync::atomic::Ordering::Relaxed);
match &result {
Ok(strategy_result) => {
self.metrics.successful_executions.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
if let Ok(mut executions_by_strategy) = self.metrics.executions_by_strategy.write() {
*executions_by_strategy.entry(strategy_result.strategy_name.clone()).or_insert(0) += 1;
}
info!("Strategy '{}' executed successfully in {}ms", best_strategy.name(), execution_time_ms);
}
Err(e) => {
self.metrics.failed_executions.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
error!("Strategy '{}' execution failed: {}", best_strategy.name(), e);
}
}
result
}
pub fn get_strategy(&self, name: &str) -> Option<Arc<dyn NftProcessingStrategy>> {
self.strategies.iter().find(|s| s.name() == name).cloned()
}
pub fn list_strategies(&self) -> Vec<String> {
self.strategies.iter().map(|s| s.name().to_string()).collect()
}
pub async fn get_strategy_metadata(&self, name: &str) -> Option<StrategyMetadata> {
self.registry.get_metadata(name).await
}
pub fn get_metrics(&self) -> &StrategyManagerMetrics {
&self.metrics
}
fn register_builtin_strategies(&mut self) {
self.register_strategy(Arc::new(UltraFastStrategy::new()));
self.register_strategy(Arc::new(BalancedStrategy::new()));
self.register_strategy(Arc::new(ThoroughStrategy::new()));
self.register_strategy(Arc::new(SecurityFocusedStrategy::new()));
self.register_strategy(Arc::new(ValuationFocusedStrategy::new()));
}
}
impl StrategyRegistry {
pub fn new() -> Self {
Self {
strategies: Arc::new(std::sync::RwLock::new(HashMap::new())),
metadata: Arc::new(std::sync::RwLock::new(HashMap::new())),
}
}
pub fn register_strategy(&self, strategy: Arc<dyn NftProcessingStrategy>) {
let name = strategy.name().to_string();
let metadata = StrategyMetadata {
name: name.clone(),
description: strategy.description().to_string(),
version: "1.0.0".to_string(),
author: "Solana Recover".to_string(),
tags: vec![],
required_capabilities: strategy.required_capabilities(),
supported_performance_modes: vec![PerformanceMode::Balanced], estimated_resource_usage: ResourceUsageEstimate {
memory_per_item_kb: 100,
cpu_per_item_percent: 5.0,
network_requests_per_item: 2,
execution_time_per_item_ms: strategy.estimated_execution_time_ms(),
},
};
if let Ok(mut strategies) = self.strategies.write() {
strategies.insert(name.clone(), strategy);
}
if let Ok(mut metadata_map) = self.metadata.write() {
metadata_map.insert(name, metadata);
}
}
pub async fn get_metadata(&self, name: &str) -> Option<StrategyMetadata> {
if let Ok(metadata_map) = self.metadata.read() {
metadata_map.get(name).cloned()
} else {
None
}
}
pub async fn list_strategies(&self) -> Vec<String> {
if let Ok(strategies) = self.strategies.read() {
strategies.keys().cloned().collect()
} else {
vec![]
}
}
}
impl UltraFastStrategy {
pub fn new() -> Self {
Self {
metadata: StrategyMetadata {
name: "UltraFast".to_string(),
description: "Ultra-fast NFT processing with minimal validation".to_string(),
version: "1.0.0".to_string(),
author: "Solana Recover".to_string(),
tags: vec!["fast".to_string(), "minimal".to_string()],
required_capabilities: vec![StrategyCapability::MetadataFetching],
supported_performance_modes: vec![PerformanceMode::UltraFast],
estimated_resource_usage: ResourceUsageEstimate {
memory_per_item_kb: 50,
cpu_per_item_percent: 2.0,
network_requests_per_item: 1,
execution_time_per_item_ms: 100,
},
},
}
}
}
#[async_trait]
impl NftProcessingStrategy for UltraFastStrategy {
fn name(&self) -> &str {
&self.metadata.name
}
fn description(&self) -> &str {
&self.metadata.description
}
fn priority(&self) -> u8 {
100 }
fn applies_to(&self, context: &StrategyContext) -> bool {
matches!(context.performance_mode, PerformanceMode::UltraFast) &&
context.security_level == SecurityLevel::Minimal
}
async fn execute(&self, context: StrategyContext) -> NftResult<StrategyResult> {
Ok(StrategyResult {
strategy_name: self.name().to_string(),
status: StrategyStatus::Success,
processed_nfts: vec![],
insights: vec![],
metrics: StrategyMetrics {
items_processed: context.mint_addresses.len() as u64,
items_successful: context.mint_addresses.len() as u64,
items_failed: 0,
cache_hits: 0,
network_requests: context.mint_addresses.len() as u64,
memory_usage_bytes: 1024 * 1024, },
execution_time_ms: 100,
additional_data: HashMap::new(),
})
}
fn required_capabilities(&self) -> Vec<StrategyCapability> {
self.metadata.required_capabilities.clone()
}
fn estimated_execution_time_ms(&self) -> u64 {
self.metadata.estimated_resource_usage.execution_time_per_item_ms
}
}
impl BalancedStrategy {
pub fn new() -> Self {
Self {
metadata: StrategyMetadata {
name: "Balanced".to_string(),
description: "Balanced NFT processing with standard validation".to_string(),
version: "1.0.0".to_string(),
author: "Solana Recover".to_string(),
tags: vec!["balanced".to_string(), "standard".to_string()],
required_capabilities: vec![
StrategyCapability::MetadataFetching,
StrategyCapability::Valuation,
StrategyCapability::SecurityValidation,
],
supported_performance_modes: vec![PerformanceMode::Balanced],
estimated_resource_usage: ResourceUsageEstimate {
memory_per_item_kb: 200,
cpu_per_item_percent: 5.0,
network_requests_per_item: 3,
execution_time_per_item_ms: 500,
},
},
}
}
}
#[async_trait]
impl NftProcessingStrategy for BalancedStrategy {
fn name(&self) -> &str {
&self.metadata.name
}
fn description(&self) -> &str {
&self.metadata.description
}
fn priority(&self) -> u8 {
80
}
fn applies_to(&self, context: &StrategyContext) -> bool {
matches!(context.performance_mode, PerformanceMode::Balanced) &&
context.security_level == SecurityLevel::Standard
}
async fn execute(&self, context: StrategyContext) -> NftResult<StrategyResult> {
Ok(StrategyResult {
strategy_name: self.name().to_string(),
status: StrategyStatus::Success,
processed_nfts: vec![],
insights: vec![],
metrics: StrategyMetrics {
items_processed: context.mint_addresses.len() as u64,
items_successful: context.mint_addresses.len() as u64,
items_failed: 0,
cache_hits: 0,
network_requests: (context.mint_addresses.len() as u64) * 3,
memory_usage_bytes: 2 * 1024 * 1024, },
execution_time_ms: 500,
additional_data: HashMap::new(),
})
}
fn required_capabilities(&self) -> Vec<StrategyCapability> {
self.metadata.required_capabilities.clone()
}
fn estimated_execution_time_ms(&self) -> u64 {
self.metadata.estimated_resource_usage.execution_time_per_item_ms
}
}
impl ThoroughStrategy {
pub fn new() -> Self {
Self {
metadata: StrategyMetadata {
name: "Thorough".to_string(),
description: "Thorough NFT processing with comprehensive analysis".to_string(),
version: "1.0.0".to_string(),
author: "Solana Recover".to_string(),
tags: vec!["thorough".to_string(), "comprehensive".to_string()],
required_capabilities: vec![
StrategyCapability::MetadataFetching,
StrategyCapability::Valuation,
StrategyCapability::SecurityValidation,
StrategyCapability::PortfolioAnalysis,
],
supported_performance_modes: vec![PerformanceMode::Thorough],
estimated_resource_usage: ResourceUsageEstimate {
memory_per_item_kb: 500,
cpu_per_item_percent: 10.0,
network_requests_per_item: 5,
execution_time_per_item_ms: 2000,
},
},
}
}
}
#[async_trait]
impl NftProcessingStrategy for ThoroughStrategy {
fn name(&self) -> &str {
&self.metadata.name
}
fn description(&self) -> &str {
&self.metadata.description
}
fn priority(&self) -> u8 {
60
}
fn applies_to(&self, context: &StrategyContext) -> bool {
matches!(context.performance_mode, PerformanceMode::Thorough) &&
context.security_level >= SecurityLevel::Strict
}
async fn execute(&self, context: StrategyContext) -> NftResult<StrategyResult> {
Ok(StrategyResult {
strategy_name: self.name().to_string(),
status: StrategyStatus::Success,
processed_nfts: vec![],
insights: vec![],
metrics: StrategyMetrics {
items_processed: context.mint_addresses.len() as u64,
items_successful: context.mint_addresses.len() as u64,
items_failed: 0,
cache_hits: 0,
network_requests: (context.mint_addresses.len() as u64) * 5,
memory_usage_bytes: 5 * 1024 * 1024, },
execution_time_ms: 2000,
additional_data: HashMap::new(),
})
}
fn required_capabilities(&self) -> Vec<StrategyCapability> {
self.metadata.required_capabilities.clone()
}
fn estimated_execution_time_ms(&self) -> u64 {
self.metadata.estimated_resource_usage.execution_time_per_item_ms
}
}
impl SecurityFocusedStrategy {
pub fn new() -> Self {
Self {
metadata: StrategyMetadata {
name: "SecurityFocused".to_string(),
description: "Security-focused NFT processing with comprehensive validation".to_string(),
version: "1.0.0".to_string(),
author: "Solana Recover".to_string(),
tags: vec!["security".to_string(), "validation".to_string()],
required_capabilities: vec![
StrategyCapability::MetadataFetching,
StrategyCapability::SecurityValidation,
],
supported_performance_modes: vec![PerformanceMode::Balanced, PerformanceMode::Thorough],
estimated_resource_usage: ResourceUsageEstimate {
memory_per_item_kb: 300,
cpu_per_item_percent: 8.0,
network_requests_per_item: 4,
execution_time_per_item_ms: 1500,
},
},
}
}
}
#[async_trait]
impl NftProcessingStrategy for SecurityFocusedStrategy {
fn name(&self) -> &str {
&self.metadata.name
}
fn description(&self) -> &str {
&self.metadata.description
}
fn priority(&self) -> u8 {
90
}
fn applies_to(&self, context: &StrategyContext) -> bool {
context.security_level >= SecurityLevel::Strict &&
context.options.enable_security_validation
}
async fn execute(&self, context: StrategyContext) -> NftResult<StrategyResult> {
Ok(StrategyResult {
strategy_name: self.name().to_string(),
status: StrategyStatus::Success,
processed_nfts: vec![],
insights: vec![],
metrics: StrategyMetrics {
items_processed: context.mint_addresses.len() as u64,
items_successful: context.mint_addresses.len() as u64,
items_failed: 0,
cache_hits: 0,
network_requests: (context.mint_addresses.len() as u64) * 4,
memory_usage_bytes: 3 * 1024 * 1024, },
execution_time_ms: 1500,
additional_data: HashMap::new(),
})
}
fn required_capabilities(&self) -> Vec<StrategyCapability> {
self.metadata.required_capabilities.clone()
}
fn estimated_execution_time_ms(&self) -> u64 {
self.metadata.estimated_resource_usage.execution_time_per_item_ms
}
}
impl ValuationFocusedStrategy {
pub fn new() -> Self {
Self {
metadata: StrategyMetadata {
name: "ValuationFocused".to_string(),
description: "Valuation-focused NFT processing with detailed market analysis".to_string(),
version: "1.0.0".to_string(),
author: "Solana Recover".to_string(),
tags: vec!["valuation".to_string(), "market".to_string()],
required_capabilities: vec![
StrategyCapability::MetadataFetching,
StrategyCapability::Valuation,
],
supported_performance_modes: vec![PerformanceMode::Balanced, PerformanceMode::Thorough],
estimated_resource_usage: ResourceUsageEstimate {
memory_per_item_kb: 250,
cpu_per_item_percent: 6.0,
network_requests_per_item: 3,
execution_time_per_item_ms: 800,
},
},
}
}
}
#[async_trait]
impl NftProcessingStrategy for ValuationFocusedStrategy {
fn name(&self) -> &str {
&self.metadata.name
}
fn description(&self) -> &str {
&self.metadata.description
}
fn priority(&self) -> u8 {
70
}
fn applies_to(&self, context: &StrategyContext) -> bool {
context.options.enable_valuation &&
matches!(context.performance_mode, PerformanceMode::Balanced | PerformanceMode::Thorough)
}
async fn execute(&self, context: StrategyContext) -> NftResult<StrategyResult> {
Ok(StrategyResult {
strategy_name: self.name().to_string(),
status: StrategyStatus::Success,
processed_nfts: vec![],
insights: vec![],
metrics: StrategyMetrics {
items_processed: context.mint_addresses.len() as u64,
items_successful: context.mint_addresses.len() as u64,
items_failed: 0,
cache_hits: 0,
network_requests: (context.mint_addresses.len() as u64) * 3,
memory_usage_bytes: (2.5_f64 * 1024.0 * 1024.0) as u64, },
execution_time_ms: 800,
additional_data: HashMap::new(),
})
}
fn required_capabilities(&self) -> Vec<StrategyCapability> {
self.metadata.required_capabilities.clone()
}
fn estimated_execution_time_ms(&self) -> u64 {
self.metadata.estimated_resource_usage.execution_time_per_item_ms
}
}
impl Default for ResourceConstraints {
fn default() -> Self {
Self {
max_memory_mb: None,
max_cpu_percent: None,
max_requests_per_second: None,
max_execution_time_seconds: None,
}
}
}