use crate::core::{Result, SolanaRecoverError};
use crate::core::unified_scanner::{UnifiedWalletScanner, UnifiedScannerConfig, PerformanceMode};
use crate::rpc::{ConnectionPoolTrait};
use std::sync::Arc;
#[async_trait::async_trait]
pub trait CacheTrait: Send + Sync {
async fn get(&self, key: &str) -> Result<Option<Vec<u8>>>;
async fn set(&self, key: &str, value: Vec<u8>, ttl: Option<std::time::Duration>) -> Result<()>;
async fn delete(&self, key: &str) -> Result<()>;
}
pub trait MetricsTrait: Send + Sync {
fn increment_counter(&self, name: &str, tags: &[(&str, &str)]);
fn record_histogram(&self, name: &str, value: f64, tags: &[(&str, &str)]);
fn set_gauge(&self, name: &str, value: f64, tags: &[(&str, &str)]);
}
#[async_trait::async_trait]
pub trait RateLimiterTrait: Send + Sync {
async fn check_rate_limit(&self, key: &str, limit: u32, window: std::time::Duration) -> Result<bool>;
}
pub struct ScannerBuilder {
connection_pool: Option<Arc<dyn ConnectionPoolTrait>>,
cache: Option<Arc<dyn CacheTrait>>,
metrics: Option<Arc<dyn MetricsTrait>>,
rate_limiter: Option<Arc<dyn RateLimiterTrait>>,
config: Option<UnifiedScannerConfig>,
}
impl Default for ScannerBuilder {
fn default() -> Self {
Self::new()
}
}
impl ScannerBuilder {
pub fn new() -> Self {
Self {
connection_pool: None,
cache: None,
metrics: None,
rate_limiter: None,
config: None,
}
}
pub fn with_connection_pool(mut self, pool: Arc<dyn ConnectionPoolTrait>) -> Self {
self.connection_pool = Some(pool);
self
}
pub fn with_cache(mut self, cache: Arc<dyn CacheTrait>) -> Self {
self.cache = Some(cache);
self
}
pub fn with_metrics(mut self, metrics: Arc<dyn MetricsTrait>) -> Self {
self.metrics = Some(metrics);
self
}
pub fn with_rate_limiter(mut self, rate_limiter: Arc<dyn RateLimiterTrait>) -> Self {
self.rate_limiter = Some(rate_limiter);
self
}
pub fn with_config(mut self, config: UnifiedScannerConfig) -> Self {
self.config = Some(config);
self
}
pub fn with_performance_mode(mut self, mode: PerformanceMode) -> Self {
let mut config = self.config.unwrap_or_default();
config.performance_mode = mode;
self.config = Some(config);
self
}
pub fn build(self) -> Result<UnifiedWalletScanner> {
let connection_pool = self.connection_pool.ok_or_else(|| {
SolanaRecoverError::InternalError("Connection pool is required".to_string())
})?;
let config = self.config.unwrap_or_default();
let scanner = UnifiedWalletScanner::new(connection_pool, config);
Ok(scanner)
}
pub fn build_ultra_fast(self) -> Result<UnifiedWalletScanner> {
self.with_performance_mode(PerformanceMode::UltraFast).build()
}
pub fn build_balanced(self) -> Result<UnifiedWalletScanner> {
self.with_performance_mode(PerformanceMode::Balanced).build()
}
pub fn build_resource_efficient(self) -> Result<UnifiedWalletScanner> {
self.with_performance_mode(PerformanceMode::ResourceEfficient).build()
}
}
pub struct ScannerContainer {
connection_pool: Arc<dyn ConnectionPoolTrait>,
cache: Option<Arc<dyn CacheTrait>>,
metrics: Option<Arc<dyn MetricsTrait>>,
rate_limiter: Option<Arc<dyn RateLimiterTrait>>,
}
impl ScannerContainer {
pub fn new(connection_pool: Arc<dyn ConnectionPoolTrait>) -> Self {
Self {
connection_pool,
cache: None,
metrics: None,
rate_limiter: None,
}
}
pub fn with_cache(mut self, cache: Arc<dyn CacheTrait>) -> Self {
self.cache = Some(cache);
self
}
pub fn with_metrics(mut self, metrics: Arc<dyn MetricsTrait>) -> Self {
self.metrics = Some(metrics);
self
}
pub fn with_rate_limiter(mut self, rate_limiter: Arc<dyn RateLimiterTrait>) -> Self {
self.rate_limiter = Some(rate_limiter);
self
}
pub fn builder(&self) -> ScannerBuilder {
let builder = ScannerBuilder::new()
.with_connection_pool(self.connection_pool.clone());
let builder = if let Some(cache) = &self.cache {
builder.with_cache(cache.clone())
} else {
builder
};
let builder = if let Some(metrics) = &self.metrics {
builder.with_metrics(metrics.clone())
} else {
builder
};
let builder = if let Some(rate_limiter) = &self.rate_limiter {
builder.with_rate_limiter(rate_limiter.clone())
} else {
builder
};
builder
}
}
pub struct ScannerFactory;
impl ScannerFactory {
pub fn create_ultra_fast(connection_pool: Arc<dyn ConnectionPoolTrait>) -> Result<UnifiedWalletScanner> {
ScannerBuilder::new()
.with_connection_pool(connection_pool)
.with_performance_mode(PerformanceMode::UltraFast)
.build()
}
pub fn create_balanced(connection_pool: Arc<dyn ConnectionPoolTrait>) -> Result<UnifiedWalletScanner> {
ScannerBuilder::new()
.with_connection_pool(connection_pool)
.with_performance_mode(PerformanceMode::Balanced)
.build()
}
pub fn create_resource_efficient(connection_pool: Arc<dyn ConnectionPoolTrait>) -> Result<UnifiedWalletScanner> {
ScannerBuilder::new()
.with_connection_pool(connection_pool)
.with_performance_mode(PerformanceMode::ResourceEfficient)
.build()
}
pub fn create_with_config(
connection_pool: Arc<dyn ConnectionPoolTrait>,
config: UnifiedScannerConfig,
) -> Result<UnifiedWalletScanner> {
ScannerBuilder::new()
.with_connection_pool(connection_pool)
.with_config(config)
.build()
}
}
#[cfg(test)]
mod tests {
use super::*;
struct MockConnectionPool;
#[async_trait::async_trait]
impl ConnectionPoolTrait for MockConnectionPool {
async fn get_client(&self) -> crate::core::Result<Arc<crate::rpc::RpcClientWrapper>> {
Err(crate::core::errors::SolanaRecoverError::RpcClientError("Mock connection pool".to_string()))
}
}
struct MockCache;
#[async_trait::async_trait]
impl CacheTrait for MockCache {
async fn get(&self, _key: &str) -> Result<Option<Vec<u8>>> {
Ok(None)
}
async fn set(&self, _key: &str, _value: Vec<u8>, _ttl: Option<std::time::Duration>) -> Result<()> {
Ok(())
}
async fn delete(&self, _key: &str) -> Result<()> {
Ok(())
}
}
#[test]
fn test_scanner_builder_requires_connection_pool() {
let result = ScannerBuilder::new().build();
assert!(result.is_err());
}
#[test]
fn test_scanner_builder_with_connection_pool() {
let connection_pool = Arc::new(MockConnectionPool);
let result = ScannerBuilder::new()
.with_connection_pool(connection_pool)
.build();
assert!(result.is_ok());
}
#[test]
fn test_scanner_factory() {
let connection_pool = Arc::new(MockConnectionPool);
let ultra_fast_result = ScannerFactory::create_ultra_fast(connection_pool.clone());
assert!(ultra_fast_result.is_ok());
let balanced_result = ScannerFactory::create_balanced(connection_pool.clone());
assert!(balanced_result.is_ok());
let resource_efficient_result = ScannerFactory::create_resource_efficient(connection_pool);
assert!(resource_efficient_result.is_ok());
}
#[test]
fn test_scanner_container() {
let connection_pool = Arc::new(MockConnectionPool);
let cache = Arc::new(MockCache);
let container = ScannerContainer::new(connection_pool)
.with_cache(cache);
let builder = container.builder();
let result = builder.build();
assert!(result.is_ok());
}
}