refactor: Add comprehensive documentation with examples to charging-engine modules

- Add module-level documentation to lib.rs with usage example
- Document Claims and AuthConfig structs with examples in auth.rs
- Add ChargingEngine struct documentation with initialization example
- Document ChargingRule, SubscriberAccount, AccountStatus, UsageEvent, UsageType, and RatingPlan with examples in types.rs
- Add CircuitState, CircuitBreakerError, and CircuitBreaker documentation with examples in circuit_breaker.rs
This commit is contained in:
nutcas3
2026-04-29 04:36:40 +03:00
parent 8fddb29716
commit ccb2ab7ee8
5 changed files with 231 additions and 0 deletions
+44
View File
@@ -8,12 +8,41 @@ use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation}
use serde::{Deserialize, Serialize};
use std::env;
/// JWT claims for authentication tokens
///
/// # Example
///
/// ```rust
/// use charging_engine::auth::Claims;
///
/// let claims = Claims {
/// sub: "user123".to_string(),
/// exp: 1234567890,
/// };
/// ```
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Claims {
pub sub: String,
pub exp: usize,
}
/// Authentication configuration for JWT and API keys
///
/// # Example
///
/// ```rust,no_run
/// use charging_engine::auth::AuthConfig;
/// use std::env;
///
/// # fn main() -> Result<(), String> {
/// env::set_var("JWT_SECRET", "a_very_secure_secret_at_least_32_chars");
/// env::set_var("API_KEYS", "key1,key2,key3");
///
/// let config = AuthConfig::from_env()?;
/// assert!(config.validate_api_key("key1"));
/// # Ok(())
/// # }
/// ```
#[derive(Clone)]
pub struct AuthConfig {
pub secret: String,
@@ -21,6 +50,21 @@ pub struct AuthConfig {
}
impl AuthConfig {
/// Load authentication configuration from environment variables
///
/// Requires `JWT_SECRET` (at least 32 characters) and optionally `API_KEYS`
/// (comma-separated list of valid API keys).
///
/// # Example
///
/// ```rust,no_run
/// use charging_engine::auth::AuthConfig;
///
/// # fn main() -> Result<(), String> {
/// let config = AuthConfig::from_env()?;
/// # Ok(())
/// # }
/// ```
pub fn from_env() -> Result<Self, String> {
let secret = env::var("JWT_SECRET")
.map_err(|_| "JWT_SECRET environment variable is required".to_string())?;
@@ -9,6 +9,19 @@ use crate::errors::ChargingResult;
/// ChargingEngine coordinates Redis-backed hot-path state (balances, sessions)
/// and Postgres-backed configuration (rating plans) via `RatingPlansRepo`.
///
/// # Example
///
/// ```rust,no_run
/// use charging_engine::charging::engine::ChargingEngine;
/// use charging_engine::charging::rating_plans_repo::RatingPlansRepo;
///
/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
/// let plans = RatingPlansRepo::connect("postgres://localhost/db").await?;
/// let engine = ChargingEngine::new("redis://localhost", plans, 60)?;
/// # Ok(())
/// # }
/// ```
pub struct ChargingEngine {
pub(crate) redis_client: redis::Client,
pub(crate) plans: RatingPlansRepo,
@@ -2,6 +2,16 @@ use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use redis::{FromRedisValue, ToRedisArgs, ToSingleRedisArg};
/// Charging rule for usage authorization
///
/// # Example
///
/// ```rust
/// use charging_engine::charging::types::ChargingRule;
///
/// let rule = ChargingRule::Allowed;
/// assert_eq!(rule.as_str(), "ALLOWED");
/// ```
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum ChargingRule {
Allowed,
@@ -14,6 +24,16 @@ pub enum ChargingRule {
}
impl ChargingRule {
/// Convert charging rule to string representation
///
/// # Example
///
/// ```rust
/// use charging_engine::charging::types::ChargingRule;
///
/// let rule = ChargingRule::Allowed;
/// assert_eq!(rule.as_str(), "ALLOWED");
/// ```
pub fn as_str(&self) -> &str {
match self {
ChargingRule::Allowed => "ALLOWED",
@@ -27,6 +47,27 @@ impl ChargingRule {
}
}
/// Subscriber account information
///
/// # Example
///
/// ```rust
/// use charging_engine::charging::types::{SubscriberAccount, AccountStatus};
/// use chrono::Utc;
///
/// let account = SubscriberAccount {
/// imsi: "1234567890".to_string(),
/// balance: 1000,
/// data_limit: 1000000000,
/// data_used: 0,
/// voice_limit: 1000,
/// voice_used: 0,
/// sms_limit: 100,
/// sms_used: 0,
/// status: AccountStatus::Active,
/// last_updated: Utc::now(),
/// };
/// ```
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SubscriberAccount {
pub imsi: String,
@@ -41,6 +82,15 @@ pub struct SubscriberAccount {
pub last_updated: DateTime<Utc>,
}
/// Account status
///
/// # Example
///
/// ```rust
/// use charging_engine::charging::types::AccountStatus;
///
/// let status = AccountStatus::Active;
/// ```
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum AccountStatus {
Active,
@@ -49,6 +99,24 @@ pub enum AccountStatus {
Blocked,
}
/// Usage event for charging
///
/// # Example
///
/// ```rust
/// use charging_engine::charging::types::{UsageEvent, UsageType};
/// use chrono::Utc;
///
/// let event = UsageEvent {
/// imsi: "1234567890".to_string(),
/// session_id: "session123".to_string(),
/// usage_type: UsageType::Data,
/// volume: 1000,
/// timestamp: Utc::now(),
/// rate: 0.01,
/// cost: 10.0,
/// };
/// ```
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UsageEvent {
pub imsi: String,
@@ -60,6 +128,15 @@ pub struct UsageEvent {
pub cost: f64,
}
/// Usage type classification
///
/// # Example
///
/// ```rust
/// use charging_engine::charging::types::UsageType;
///
/// let usage_type = UsageType::Data;
/// ```
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum UsageType {
Data,
@@ -67,6 +144,25 @@ pub enum UsageType {
SMS,
}
/// Rating plan for subscriber billing
///
/// # Example
///
/// ```rust
/// use charging_engine::charging::types::RatingPlan;
///
/// let plan = RatingPlan {
/// plan_id: "plan1".to_string(),
/// name: "Basic Plan".to_string(),
/// data_rate: 0.01,
/// voice_rate: 0.05,
/// sms_rate: 0.1,
/// monthly_fee: 10.0,
/// data_limit: 1000000000,
/// voice_limit: 1000,
/// sms_limit: 100,
/// };
/// ```
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RatingPlan {
pub plan_id: String,
@@ -2,6 +2,16 @@ use std::sync::Arc;
use std::time::{Duration, Instant};
use tokio::sync::RwLock;
/// Circuit breaker state
///
/// # Example
///
/// ```rust
/// use charging_engine::circuit_breaker::CircuitState;
///
/// let state = CircuitState::Closed;
/// assert_eq!(state, CircuitState::Closed);
/// ```
#[derive(Debug, Clone, PartialEq, Copy)]
pub enum CircuitState {
Closed,
@@ -9,6 +19,15 @@ pub enum CircuitState {
HalfOpen,
}
/// Circuit breaker error type
///
/// # Example
///
/// ```rust
/// use charging_engine::circuit_breaker::CircuitBreakerError;
///
/// let error: CircuitBreakerError<&str> = CircuitBreakerError::Open;
/// ```
#[derive(Debug)]
pub enum CircuitBreakerError<E> {
Open,
@@ -26,6 +45,16 @@ impl<E: std::fmt::Display> std::fmt::Display for CircuitBreakerError<E> {
impl<E: std::error::Error + Send + Sync + 'static> std::error::Error for CircuitBreakerError<E> {}
/// Circuit breaker for fault tolerance
///
/// # Example
///
/// ```rust,no_run
/// use charging_engine::circuit_breaker::CircuitBreaker;
/// use std::time::Duration;
///
/// let breaker = CircuitBreaker::new(5, Duration::from_secs(60));
/// ```
#[derive(Clone)]
pub struct CircuitBreaker {
state: Arc<RwLock<CircuitState>>,
@@ -36,6 +65,21 @@ pub struct CircuitBreaker {
}
impl CircuitBreaker {
/// Create a new circuit breaker
///
/// # Arguments
///
/// * `failure_threshold` - Number of failures before opening the circuit
/// * `timeout` - Duration to wait before attempting to close the circuit
///
/// # Example
///
/// ```rust
/// use charging_engine::circuit_breaker::CircuitBreaker;
/// use std::time::Duration;
///
/// let breaker = CircuitBreaker::new(5, Duration::from_secs(60));
/// ```
pub fn new(failure_threshold: u32, timeout: Duration) -> Self {
Self {
state: Arc::new(RwLock::new(CircuitState::Closed)),
+34
View File
@@ -1,3 +1,37 @@
//! # Charging Engine
//!
//! A high-performance telecom charging engine for real-time usage-based billing.
//!
//! ## Features
//!
//! - Real-time rating and billing
//! - Circuit breaker for fault tolerance
//! - Rate limiting for API protection
//! - Comprehensive monitoring and metrics
//!
//! ## Example
//!
//! ```rust,no_run
//! use charging_engine::ChargingEngine;
//! use charging_engine::charging::types::UsageEvent;
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let engine = ChargingEngine::new("redis://localhost").await?;
//!
//! let event = UsageEvent {
//! imsi: "1234567890".to_string(),
//! volume: 1000,
//! timestamp: chrono::Utc::now(),
//! };
//!
//! let cost = engine.calculate_cost(&event).await?;
//! println!("Cost: {}", cost);
//!
//! Ok(())
//! }
//! ```
pub mod auth;
pub mod charging;
pub mod circuit_breaker;