mirror of
https://github.com/andwati/telecom-platform.git
synced 2026-10-24 21:52:16 +00:00
feat: Add charging engine client with usage reporting and batch processing support
- Add ChargingEngineClient struct with reqwest HTTP client and configurable base URL - Add report_usage method for single usage event reporting with volume conversion (bytes to MB) - Add report_batch_usage method for processing multiple usage events with error tolerance - Add UsageEvent and UsageResponse types for API request/response serialization - Add tracing integration (info, warn, error) for usage reporting
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
use anyhow::{Context, Result};
|
||||
use chrono::Utc;
|
||||
use reqwest::Client;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::{info, warn, error};
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct UsageEvent {
|
||||
imsi: String,
|
||||
session_id: String,
|
||||
volume: f64,
|
||||
usage_type: String,
|
||||
timestamp: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct UsageResponse {
|
||||
success: bool,
|
||||
message: Option<String>,
|
||||
}
|
||||
|
||||
pub struct ChargingEngineClient {
|
||||
client: Client,
|
||||
base_url: String,
|
||||
}
|
||||
|
||||
impl ChargingEngineClient {
|
||||
pub fn new(base_url: String) -> Self {
|
||||
Self {
|
||||
client: Client::new(),
|
||||
base_url,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn report_usage(
|
||||
&self,
|
||||
imsi: String,
|
||||
session_id: String,
|
||||
volume_bytes: u64,
|
||||
) -> Result<()> {
|
||||
let volume_mb = volume_bytes as f64 / (1024.0 * 1024.0);
|
||||
let timestamp = Utc::now().timestamp();
|
||||
|
||||
let event = UsageEvent {
|
||||
imsi: imsi.clone(),
|
||||
session_id,
|
||||
volume: volume_mb,
|
||||
usage_type: "Data".to_string(),
|
||||
timestamp,
|
||||
};
|
||||
|
||||
let url = format!("{}/v1/usage/process", self.base_url);
|
||||
|
||||
match self
|
||||
.client
|
||||
.post(&url)
|
||||
.json(&event)
|
||||
.send()
|
||||
.await
|
||||
{
|
||||
Ok(response) => {
|
||||
if response.status().is_success() {
|
||||
info!("Successfully reported usage for IMSI {}: {} MB", imsi, volume_mb);
|
||||
Ok(())
|
||||
} else {
|
||||
let status = response.status();
|
||||
let body = response.text().await.unwrap_or_default();
|
||||
warn!(
|
||||
"Failed to report usage for IMSI {}: {} - {}",
|
||||
imsi, status, body
|
||||
);
|
||||
Err(anyhow::anyhow!(
|
||||
"Charging engine returned error {}: {}",
|
||||
status,
|
||||
body
|
||||
))
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Failed to send usage to charging engine: {}", e);
|
||||
Err(e.context("Failed to send usage to charging engine"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn report_batch_usage(
|
||||
&self,
|
||||
usage_data: Vec<(String, String, u64)>,
|
||||
) -> Result<()> {
|
||||
for (imsi, session_id, volume_bytes) in usage_data {
|
||||
if let Err(e) = self.report_usage(imsi, session_id, volume_bytes).await {
|
||||
warn!("Failed to report usage for one session: {}", e);
|
||||
// Continue with other sessions instead of failing the entire batch
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user