(feat) added loggind(tracing)

This commit is contained in:
Rorik Star Platinum 2025-11-07 16:59:05 +03:00
parent e4cfc5eee5
commit 131ff952ca
10 changed files with 79 additions and 43 deletions

4
Cargo.lock generated
View file

@ -1111,9 +1111,9 @@ dependencies = [
[[package]]
name = "jsonwebtoken"
version = "10.1.0"
version = "10.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d119c6924272d16f0ab9ce41f7aa0bfef9340c00b0bb7ca3dd3b263d4a9150b"
checksum = "c76e1c7d7df3e34443b3621b459b066a7b79644f059fc8b2db7070c825fd417e"
dependencies = [
"aws-lc-rs",
"base64",

View file

@ -6,5 +6,5 @@ pub mod consents;
pub mod accounts;
pub mod transactions;
pub use client::{Bank, BankClient, BankingClients, BankingError};
pub use client::{BankClient, BankingError, BankingClients};
pub use models::{ApiResponse, AccountData, TransactionData, ConsentResponse};

View file

@ -1,23 +1,18 @@
// src/api/consents.rs
// Consent request and retrieval logic
// Consent request and retrieval logic - Functional style
use super::{client::{BankClient, BankingError}, models::{ConsentRequestBody, ConsentResponse}};
use tracing::{info, debug, error};
impl BankClient {
pub async fn request_consent(&self, client_id: &str) -> Result<ConsentResponse, BankingError> {
info!("🔐 Requesting consent for client_id: {}", client_id);
let body = self.build_consent_request(client_id);
let token = self.get_token().await?;
let body = ConsentRequestBody {
client_id: client_id.to_string(),
permissions: vec![
"ReadAccountsDetail".to_string(),
"ReadBalances".to_string(),
"ReadTransactionsDetail".to_string(),
],
reason: "Account aggregation for Multiberry app".to_string(),
requesting_bank: self.client_id.clone(),
requesting_bank_name: "Multiberry Backend".to_string(),
};
debug!("✅ Got bank token");
debug!("📤 Sending consent request to bank");
let response = self.http_client
.post(self.base_url.join("/account-consents/request")?)
@ -27,12 +22,44 @@ impl BankClient {
.send()
.await?;
match response.status().is_success() {
true => response.json().await.map_err(Into::into),
false => Err(BankingError::ApiError {
status: response.status().as_u16(),
body: response.text().await.unwrap_or_default(),
}),
debug!("📥 Bank response status: {}", response.status());
response
.text()
.await
.map_err(Into::into)
.and_then(|text| self.parse_consent_response(&text))
}
fn build_consent_request(&self, client_id: &str) -> ConsentRequestBody {
ConsentRequestBody {
client_id: client_id.to_string(),
permissions: vec![
"ReadAccountsDetail".to_string(),
"ReadBalances".to_string(),
"ReadTransactionsDetail".to_string(),
],
reason: "Account aggregation for Multiberry app".to_string(),
requesting_bank: self.client_id.clone(),
requesting_bank_name: "Multiberry Backend".to_string(),
}
}
fn parse_consent_response(&self, text: &str) -> Result<ConsentResponse, BankingError> {
info!("✅ Bank consent response: {}", text);
serde_json::from_str::<ConsentResponse>(text)
.map_err(|e| {
error!("❌ Failed to deserialize ConsentResponse: {}", e);
error!("Raw response was: {}", text);
BankingError::ApiError {
status: 500,
body: format!("Deserialization error: {}", e),
}
})
.map(|consent| {
info!("✅ Successfully parsed consent: {}", consent.consent_id);
consent
})
}
}

View file

@ -33,7 +33,7 @@ pub struct Meta {
// --- Consent Models ---
#[derive(Debug, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
#[serde(rename_all = "snake_case")]
pub struct ConsentRequestBody {
pub client_id: String,
pub permissions: Vec<String>,

View file

@ -5,5 +5,4 @@ pub mod jwt;
pub mod middleware;
pub mod password;
pub use jwt::Claims;
pub use middleware::auth_middleware;

View file

@ -11,7 +11,7 @@ use axum::{
};
use serde_json::json;
use super::jwt::{validate_token, Claims};
use super::jwt::validate_token;
pub async fn auth_middleware(
headers: HeaderMap,

View file

@ -1,7 +1,7 @@
// src/db/accounts.rs
use sqlx::PgPool;
use chrono::{DateTime, Utc, NaiveDate};
use chrono::NaiveDate;
pub async fn store_account(
pool: &PgPool,

View file

@ -14,19 +14,22 @@ use crate::state::AppState;
#[tokio::main]
async fn main() {
// 1. Загружаем переменные окружения из .env или secrets (через sops)
dotenvy::dotenv().ok();
// 3. Создаём общее состояние приложения
let app_state = AppState::new().await;
// Initialize tracing
tracing_subscriber::fmt()
.with_max_level(tracing::Level::DEBUG)
.init();
// 4. Конфигурируем роуты (все роуты централизованы в route::router())
tracing::info!("🚀 Starting Multiberry Backend Server");
let app_state = AppState::new().await;
let app = route::router(app_state);
// 5. Запускаем сервер
let addr = SocketAddr::from(([0, 0, 0, 0], 3000));
let addr = std::net::SocketAddr::from(([0, 0, 0, 0], 3000));
println!("🚀 Server listening on {}", addr);
let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
axum::serve(listener, app).await.unwrap();
}

View file

@ -6,25 +6,30 @@ use axum::{middleware, routing::{get, post}, Router};
use crate::{state::AppState, auth};
pub fn router(app_state: AppState) -> Router {
Router::new()
// Public routes (no auth required)
let public_routes = Router::new()
.route("/api/health", get(handlers::health_handler))
.route("/api/auth/register", post(auth::handlers::register_handler))
.route("/api/auth/login", post(auth::handlers::login_handler))
.route("/api/auth/login", post(auth::handlers::login_handler));
// Protected routes (auth required)
let protected_routes = Router::new()
.route("/api/auth/me", get(auth::handlers::me_handler))
.route("/api/consent/:bank/:user_id",
.route("/api/consent/{bank}/{user_id}",
post(handlers::create_consent_handler)
.get(handlers::get_consent_handler)
)
.route("/api/accounts/:bank/:user_id",
.route("/api/accounts/{bank}/{user_id}",
get(handlers::get_accounts_handler)
)
.route("/api/transactions/:bank/:user_id/:account_id",
.route("/api/transactions/{bank}/{user_id}/{account_id}",
get(handlers::get_transactions_handler)
)
.layer(middleware::from_fn(auth::auth_middleware))
.layer(middleware::from_fn(auth::auth_middleware));
// Merge both
public_routes
.merge(protected_routes)
.with_state(app_state)
}

View file

@ -55,8 +55,10 @@ pub async fn create_consent_handler(
let client = state.banking_clients.get_client(bank);
let consent_response = client.request_consent(&user_id).await
.map_err(|e| map_banking_error(e))?;
let consent_response = client
.request_consent(&user_id)
.await
.map_err(map_banking_error)?;
db::consents::store_consent(
&state.db_pool,