mirror of
https://github.com/andwati/telecom-platform.git
synced 2026-10-30 16:42:15 +00:00
refactor: Reorganize charging and errors modules into proper directory structure
- Move charging module files into charging/ directory (types.rs, engine.rs, credit_management.rs, rating_billing.rs) - Move error module files into errors/ directory (types.rs, helpers.rs) - Create mod.rs files for charging and errors modules with simplified exports - Update import paths to use super:: for intra-module references - Remove charging_new/errors_new aliases and use charging/errors directly - Simplify module
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
pub mod sync;
|
||||
pub mod types;
|
||||
pub mod monitoring;
|
||||
pub mod operations;
|
||||
@@ -0,0 +1,172 @@
|
||||
use tracing::{info, debug};
|
||||
use std::time::SystemTime;
|
||||
|
||||
use crate::errors::{ChargingError, ChargingResult, ErrorContext};
|
||||
use super::types::{SystemStats, HealthStatus};
|
||||
|
||||
impl super::ChargingEngine {
|
||||
pub async fn get_system_statistics(&self) -> ChargingResult<SystemStats> {
|
||||
let mut conn = self.redis_client.get_async_connection().await
|
||||
.context("Failed to get Redis connection")?;
|
||||
|
||||
let active_sessions: u64 = conn.get("stats:active_sessions").await.unwrap_or(0);
|
||||
let total_accounts: u64 = conn.keys("account:*").await.unwrap_or_default().len() as u64;
|
||||
let blocked_users: u64 = conn.keys("block:*").await.unwrap_or_default().len() as u64;
|
||||
let low_balance_alerts: u64 = conn.keys("alert:low_balance:*").await.unwrap_or_default().len() as u64;
|
||||
|
||||
let stats = SystemStats {
|
||||
active_sessions,
|
||||
total_accounts,
|
||||
blocked_users,
|
||||
low_balance_alerts,
|
||||
uptime: self.get_uptime().await?,
|
||||
};
|
||||
|
||||
Ok(stats)
|
||||
}
|
||||
|
||||
async fn get_uptime(&self) -> ChargingResult<u64> {
|
||||
// This would track the actual uptime in a real implementation
|
||||
// For now, return a placeholder
|
||||
Ok(SystemTime::now()
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_secs())
|
||||
}
|
||||
|
||||
pub async fn health_check(&self) -> ChargingResult<HealthStatus> {
|
||||
let mut conn = self.redis_client.get_async_connection().await
|
||||
.context("Failed to get Redis connection")?;
|
||||
|
||||
// Test Redis connection
|
||||
let _: String = conn.get("health_check").await.unwrap_or_else(|_| "ok".to_string());
|
||||
|
||||
let status = HealthStatus {
|
||||
redis_connected: true,
|
||||
active_sync: true,
|
||||
last_sync: chrono::Utc::now(),
|
||||
memory_usage: self.get_memory_usage().await?,
|
||||
};
|
||||
|
||||
Ok(status)
|
||||
}
|
||||
|
||||
async fn get_memory_usage(&self) -> ChargingResult<u64> {
|
||||
// This would get actual memory usage in a real implementation
|
||||
// For now, return a placeholder
|
||||
Ok(50_000_000) // 50MB placeholder
|
||||
}
|
||||
|
||||
pub async fn get_performance_metrics(&self) -> ChargingResult<PerformanceMetrics> {
|
||||
let mut conn = self.redis_client.get_async_connection().await
|
||||
.context("Failed to get Redis connection")?;
|
||||
|
||||
// Get Redis info
|
||||
let info: String = redis::cmd("INFO").query_async(&mut conn).await.unwrap_or_default();
|
||||
|
||||
// Parse Redis info for metrics (simplified)
|
||||
let connected_clients = self.extract_metric(&info, "connected_clients");
|
||||
let used_memory = self.extract_metric(&info, "used_memory");
|
||||
let total_commands_processed = self.extract_metric(&info, "total_commands_processed");
|
||||
|
||||
let metrics = PerformanceMetrics {
|
||||
connected_clients,
|
||||
used_memory,
|
||||
total_commands_processed,
|
||||
requests_per_second: self.calculate_rps().await?,
|
||||
average_response_time: self.calculate_avg_response_time().await?,
|
||||
};
|
||||
|
||||
Ok(metrics)
|
||||
}
|
||||
|
||||
fn extract_metric(&self, info: &str, metric: &str) -> u64 {
|
||||
info.lines()
|
||||
.find(|line| line.starts_with(metric))
|
||||
.and_then(|line| line.split(':').nth(1))
|
||||
.and_then(|value| value.parse::<u64>().ok())
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
async fn calculate_rps(&self) -> ChargingResult<f64> {
|
||||
// This would calculate actual requests per second
|
||||
// For now, return a placeholder
|
||||
Ok(100.0)
|
||||
}
|
||||
|
||||
async fn calculate_avg_response_time(&self) -> ChargingResult<f64> {
|
||||
// This would calculate actual average response time
|
||||
// For now, return a placeholder
|
||||
Ok(5.0) // 5ms
|
||||
}
|
||||
|
||||
pub async fn get_error_statistics(&self) -> ChargingResult<ErrorStats> {
|
||||
let mut conn = self.redis_client.get_async_connection().await
|
||||
.context("Failed to get Redis connection")?;
|
||||
|
||||
let pattern = "error:*".to_string();
|
||||
let keys: Vec<String> = conn.keys(&pattern).await
|
||||
.context("Failed to get error keys")?;
|
||||
|
||||
let mut total_errors = 0u64;
|
||||
let mut error_types = std::collections::HashMap::new();
|
||||
|
||||
for key in keys {
|
||||
if let Ok(count) = conn.get::<_, u64>(&key).await {
|
||||
total_errors += count;
|
||||
|
||||
let error_type = key.split(':').nth(1).unwrap_or("unknown");
|
||||
*error_types.entry(error_type.to_string()).or_insert(0) += count;
|
||||
}
|
||||
}
|
||||
|
||||
let stats = ErrorStats {
|
||||
total_errors,
|
||||
error_types,
|
||||
last_error: self.get_last_error().await?,
|
||||
};
|
||||
|
||||
Ok(stats)
|
||||
}
|
||||
|
||||
async fn get_last_error(&self) -> ChargingResult<Option<String>> {
|
||||
let mut conn = self.redis_client.get_async_connection().await
|
||||
.context("Failed to get Redis connection")?;
|
||||
|
||||
let last_error: Option<String> = conn.get("last_error").await.unwrap_or(None);
|
||||
Ok(last_error)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SystemStats {
|
||||
pub active_sessions: u64,
|
||||
pub total_accounts: u64,
|
||||
pub blocked_users: u64,
|
||||
pub low_balance_alerts: u64,
|
||||
pub uptime: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct HealthStatus {
|
||||
pub redis_connected: bool,
|
||||
pub active_sync: bool,
|
||||
pub last_sync: chrono::DateTime<chrono::Utc>,
|
||||
pub memory_usage: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PerformanceMetrics {
|
||||
pub connected_clients: u64,
|
||||
pub used_memory: u64,
|
||||
pub total_commands_processed: u64,
|
||||
pub requests_per_second: f64,
|
||||
pub average_response_time: f64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ErrorStats {
|
||||
pub total_errors: u64,
|
||||
pub error_types: std::collections::HashMap<String, u64>,
|
||||
pub last_error: Option<String>,
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
use tokio::time::interval;
|
||||
use tracing::{info, warn, error, debug};
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::errors::{ChargingError, ChargingResult, ErrorContext};
|
||||
|
||||
impl super::ChargingEngine {
|
||||
pub async fn start_background_sync(&self) -> ChargingResult<()> {
|
||||
let mut interval_timer = interval(self.sync_interval);
|
||||
|
||||
info!("Starting background sync with interval: {:?}", self.sync_interval);
|
||||
|
||||
loop {
|
||||
interval_timer.tick().await;
|
||||
|
||||
if let Err(e) = self.perform_sync().await {
|
||||
error!("Background sync failed: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn perform_sync(&self) -> ChargingResult<()> {
|
||||
debug!("Performing background sync");
|
||||
|
||||
// Sync 1: Clean up expired blocks
|
||||
self.cleanup_expired_blocks().await?;
|
||||
|
||||
// Sync 2: Update usage statistics
|
||||
self.update_usage_statistics().await?;
|
||||
|
||||
// Sync 3: Check for low balance alerts
|
||||
self.check_low_balance_alerts().await?;
|
||||
|
||||
// Sync 4: Apply monthly fees (once per day)
|
||||
self.apply_monthly_fees_if_needed().await?;
|
||||
|
||||
debug!("Background sync completed successfully");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn cleanup_expired_blocks(&self) -> ChargingResult<()> {
|
||||
let mut conn = self.redis_client.get_async_connection().await
|
||||
.context("Failed to get Redis connection")?;
|
||||
|
||||
let pattern = "block:*".to_string();
|
||||
let keys: Vec<String> = conn.keys(&pattern).await
|
||||
.context("Failed to get block keys")?;
|
||||
|
||||
let mut cleaned_count = 0;
|
||||
|
||||
for key in keys {
|
||||
let ttl: i64 = conn.ttl(&key).await.unwrap_or(-1);
|
||||
if ttl == -1 || ttl == -2 {
|
||||
// Key has no expiration or doesn't exist
|
||||
let _: () = conn.del(&key).await.unwrap_or(());
|
||||
cleaned_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if cleaned_count > 0 {
|
||||
info!("Cleaned up {} expired blocks", cleaned_count);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn update_usage_statistics(&self) -> ChargingResult<()> {
|
||||
let mut conn = self.redis_client.get_async_connection().await
|
||||
.context("Failed to get Redis connection")?;
|
||||
|
||||
// Get total active sessions
|
||||
let pattern = "session:*".to_string();
|
||||
let keys: Vec<String> = conn.keys(&pattern).await
|
||||
.context("Failed to get session keys")?;
|
||||
|
||||
let active_sessions = keys.len();
|
||||
|
||||
// Store statistics
|
||||
let stats_key = "stats:active_sessions";
|
||||
let _: () = conn.set(stats_key, active_sessions).await.unwrap_or(());
|
||||
|
||||
debug!("Updated usage statistics: {} active sessions", active_sessions);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn check_low_balance_alerts(&self) -> ChargingResult<()> {
|
||||
let mut conn = self.redis_client.get_async_connection().await
|
||||
.context("Failed to get Redis connection")?;
|
||||
|
||||
let pattern = "credit:*".to_string();
|
||||
let keys: Vec<String> = conn.keys(&pattern).await
|
||||
.context("Failed to get credit keys")?;
|
||||
|
||||
let low_balance_threshold = 100_000_000; // 100MB in bytes
|
||||
let mut low_balance_count = 0;
|
||||
|
||||
for key in keys {
|
||||
if let Ok(balance) = conn.get::<_, u64>(&key).await {
|
||||
if balance < low_balance_threshold {
|
||||
low_balance_count += 1;
|
||||
warn!("Low balance alert for {}: {} bytes remaining", key, balance);
|
||||
|
||||
// Store alert
|
||||
let alert_key = format!("alert:low_balance:{}", key);
|
||||
let _: () = conn.setex(&alert_key, 3600, "low_balance").await.unwrap_or(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if low_balance_count > 0 {
|
||||
info!("Generated {} low balance alerts", low_balance_count);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn apply_monthly_fees_if_needed(&self) -> ChargingResult<()> {
|
||||
let mut conn = self.redis_client.get_async_connection().await
|
||||
.context("Failed to get Redis connection")?;
|
||||
|
||||
let last_fee_key = "last_monthly_fee";
|
||||
let last_fee: Option<String> = conn.get(last_fee_key).await.unwrap_or(None);
|
||||
|
||||
let now = chrono::Utc::now();
|
||||
let current_month = format!("{}-{}", now.year(), now.month());
|
||||
|
||||
if let Some(last_month) = last_fee {
|
||||
if last_month == current_month {
|
||||
return Ok(()); // Monthly fees already applied this month
|
||||
}
|
||||
}
|
||||
|
||||
// Apply monthly fees
|
||||
let processed = self.apply_monthly_fees().await?;
|
||||
|
||||
// Update last fee timestamp
|
||||
let _: () = conn.set(last_fee_key, current_month).await.unwrap_or(());
|
||||
|
||||
info!("Applied monthly fees to {} accounts for {}", processed, current_month);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
use tokio::time::{interval, sleep};
|
||||
use tracing::{info, warn, error, debug};
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::errors::{ChargingError, ChargingResult, ErrorContext};
|
||||
|
||||
impl super::ChargingEngine {
|
||||
pub async fn start_background_sync(&self) -> ChargingResult<()> {
|
||||
let mut interval_timer = interval(self.sync_interval);
|
||||
|
||||
info!("Starting background sync with interval: {:?}", self.sync_interval);
|
||||
|
||||
loop {
|
||||
interval_timer.tick().await;
|
||||
|
||||
if let Err(e) = self.perform_sync().await {
|
||||
error!("Background sync failed: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn perform_sync(&self) -> ChargingResult<()> {
|
||||
debug!("Performing background sync");
|
||||
|
||||
// Sync 1: Clean up expired blocks
|
||||
self.cleanup_expired_blocks().await?;
|
||||
|
||||
// Sync 2: Update usage statistics
|
||||
self.update_usage_statistics().await?;
|
||||
|
||||
// Sync 3: Check for low balance alerts
|
||||
self.check_low_balance_alerts().await?;
|
||||
|
||||
// Sync 4: Apply monthly fees (once per day)
|
||||
self.apply_monthly_fees_if_needed().await?;
|
||||
|
||||
debug!("Background sync completed successfully");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn cleanup_expired_blocks(&self) -> ChargingResult<()> {
|
||||
let mut conn = self.redis_client.get_async_connection().await
|
||||
.context("Failed to get Redis connection")?;
|
||||
|
||||
let pattern = "block:*".to_string();
|
||||
let keys: Vec<String> = conn.keys(&pattern).await
|
||||
.context("Failed to get block keys")?;
|
||||
|
||||
let mut cleaned_count = 0;
|
||||
|
||||
for key in keys {
|
||||
let ttl: i64 = conn.ttl(&key).await.unwrap_or(-1);
|
||||
if ttl == -1 || ttl == -2 {
|
||||
// Key has no expiration or doesn't exist
|
||||
let _: () = conn.del(&key).await.unwrap_or(());
|
||||
cleaned_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if cleaned_count > 0 {
|
||||
info!("Cleaned up {} expired blocks", cleaned_count);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn update_usage_statistics(&self) -> ChargingResult<()> {
|
||||
let mut conn = self.redis_client.get_async_connection().await
|
||||
.context("Failed to get Redis connection")?;
|
||||
|
||||
// Get total active sessions
|
||||
let pattern = "session:*".to_string();
|
||||
let keys: Vec<String> = conn.keys(&pattern).await
|
||||
.context("Failed to get session keys")?;
|
||||
|
||||
let active_sessions = keys.len();
|
||||
|
||||
// Store statistics
|
||||
let stats_key = "stats:active_sessions";
|
||||
let _: () = conn.set(stats_key, active_sessions).await.unwrap_or(());
|
||||
|
||||
debug!("Updated usage statistics: {} active sessions", active_sessions);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn check_low_balance_alerts(&self) -> ChargingResult<()> {
|
||||
let mut conn = self.redis_client.get_async_connection().await
|
||||
.context("Failed to get Redis connection")?;
|
||||
|
||||
let pattern = "credit:*".to_string();
|
||||
let keys: Vec<String> = conn.keys(&pattern).await
|
||||
.context("Failed to get credit keys")?;
|
||||
|
||||
let low_balance_threshold = 100_000_000; // 100MB in bytes
|
||||
let mut low_balance_count = 0;
|
||||
|
||||
for key in keys {
|
||||
if let Ok(balance) = conn.get::<_, u64>(&key).await {
|
||||
if balance < low_balance_threshold {
|
||||
low_balance_count += 1;
|
||||
warn!("Low balance alert for {}: {} bytes remaining", key, balance);
|
||||
|
||||
// Store alert
|
||||
let alert_key = format!("alert:low_balance:{}", key);
|
||||
let _: () = conn.setex(&alert_key, 3600, "low_balance").await.unwrap_or(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if low_balance_count > 0 {
|
||||
info!("Generated {} low balance alerts", low_balance_count);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn apply_monthly_fees_if_needed(&self) -> ChargingResult<()> {
|
||||
let mut conn = self.redis_client.get_async_connection().await
|
||||
.context("Failed to get Redis connection")?;
|
||||
|
||||
let last_fee_key = "last_monthly_fee";
|
||||
let last_fee: Option<String> = conn.get(last_fee_key).await.unwrap_or(None);
|
||||
|
||||
let now = chrono::Utc::now();
|
||||
let current_month = format!("{}-{}", now.year(), now.month());
|
||||
|
||||
if let Some(last_month) = last_fee {
|
||||
if last_month == current_month {
|
||||
return Ok(()); // Monthly fees already applied this month
|
||||
}
|
||||
}
|
||||
|
||||
// Apply monthly fees
|
||||
let processed = self.apply_monthly_fees().await?;
|
||||
|
||||
// Update last fee timestamp
|
||||
let _: () = conn.set(last_fee_key, current_month).await.unwrap_or(());
|
||||
|
||||
info!("Applied monthly fees to {} accounts for {}", processed, current_month);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_system_statistics(&self) -> ChargingResult<SystemStats> {
|
||||
let mut conn = self.redis_client.get_async_connection().await
|
||||
.context("Failed to get Redis connection")?;
|
||||
|
||||
let active_sessions: u64 = conn.get("stats:active_sessions").await.unwrap_or(0);
|
||||
let total_accounts: u64 = conn.keys("account:*").await.unwrap_or_default().len() as u64;
|
||||
let blocked_users: u64 = conn.keys("block:*").await.unwrap_or_default().len() as u64;
|
||||
let low_balance_alerts: u64 = conn.keys("alert:low_balance:*").await.unwrap_or_default().len() as u64;
|
||||
|
||||
let stats = SystemStats {
|
||||
active_sessions,
|
||||
total_accounts,
|
||||
blocked_users,
|
||||
low_balance_alerts,
|
||||
uptime: self.get_uptime().await?,
|
||||
};
|
||||
|
||||
Ok(stats)
|
||||
}
|
||||
|
||||
async fn get_uptime(&self) -> ChargingResult<u64> {
|
||||
// This would track the actual uptime in a real implementation
|
||||
// For now, return a placeholder
|
||||
Ok(std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_secs())
|
||||
}
|
||||
|
||||
pub async fn health_check(&self) -> ChargingResult<HealthStatus> {
|
||||
let mut conn = self.redis_client.get_async_connection().await
|
||||
.context("Failed to get Redis connection")?;
|
||||
|
||||
// Test Redis connection
|
||||
let _: String = conn.get("health_check").await.unwrap_or_else(|_| "ok".to_string());
|
||||
|
||||
let status = HealthStatus {
|
||||
redis_connected: true,
|
||||
active_sync: true,
|
||||
last_sync: chrono::Utc::now(),
|
||||
memory_usage: self.get_memory_usage().await?,
|
||||
};
|
||||
|
||||
Ok(status)
|
||||
}
|
||||
|
||||
async fn get_memory_usage(&self) -> ChargingResult<u64> {
|
||||
// This would get actual memory usage in a real implementation
|
||||
// For now, return a placeholder
|
||||
Ok(50_000_000) // 50MB placeholder
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SystemStats {
|
||||
pub active_sessions: u64,
|
||||
pub total_accounts: u64,
|
||||
pub blocked_users: u64,
|
||||
pub low_balance_alerts: u64,
|
||||
pub uptime: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct HealthStatus {
|
||||
pub redis_connected: bool,
|
||||
pub active_sync: bool,
|
||||
pub last_sync: chrono::DateTime<chrono::Utc>,
|
||||
pub memory_usage: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PerformanceMetrics {
|
||||
pub connected_clients: u64,
|
||||
pub used_memory: u64,
|
||||
pub total_commands_processed: u64,
|
||||
pub requests_per_second: f64,
|
||||
pub average_response_time: f64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ErrorStats {
|
||||
pub total_errors: u64,
|
||||
pub error_types: std::collections::HashMap<String, u64>,
|
||||
pub last_error: Option<String>,
|
||||
}
|
||||
Reference in New Issue
Block a user