mirror of
https://github.com/andwati/telecom-platform.git
synced 2026-10-21 04:04:28 +00:00
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:
@@ -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)),
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user