yedad_eye 0.1.0

YEDAD EYE Matrix Engine - Real-time Network Explorer and Synchronizer
Documentation
// yedad_eye/src/providers/network.rs

use crate::{
    error::EyeError,
    types::{EyeCell, NodeMatrixRow},
    YedadEyeProvider,
};
use async_trait::async_trait;
use reqwest::Client;
use serde::Deserialize;
use std::collections::HashMap;

pub struct NetworkEyeProvider {
    base_url: String,
    client: Client,
}

impl NetworkEyeProvider {
    pub fn new(node_url: &str) -> Self {
        Self {
            base_url: node_url.trim_end_matches('/').to_string(),
            client: Client::builder()
                .timeout(std::time::Duration::from_secs(3))
                .build()
                .unwrap_or_default(),
        }
    }
}

/// ساختار منطبق با پاسخ `/slots` در api.rs
/// برخی فیلدها فقط برای Deserialize شدن نیاز هستند و مستقیماً استفاده نمی‌شوند
#[allow(dead_code)]
#[derive(Deserialize)]
struct SlotJson {
    user_address: String,
    pulse_id: u64,
    ladder_id: u32,
    step_number: u32,
    balance: u64,
    last_hash: String,
}

/// ساختار منطبق با پاسخ `/activity/:address` در api.rs
#[allow(dead_code)]
#[derive(Deserialize)]
struct ActivityResponse {
    pulse_id: u32,
    state_crc: u32,
    prev_hash: String,
}

#[async_trait]
impl YedadEyeProvider for NetworkEyeProvider {
    async fn fetch_all_active_addresses(&self) -> Result<Vec<String>, EyeError> {
        let url = format!("{}/slots", self.base_url);
        let res = self
            .client
            .get(&url)
            .send()
            .await
            .map_err(|e| EyeError::NetworkError(e.to_string()))?;
        let slots: Vec<SlotJson> = res
            .json()
            .await
            .map_err(|e| EyeError::ParsingError(e.to_string()))?;
        Ok(slots.into_iter().map(|s| s.user_address).collect())
    }

    async fn fetch_node_row(&self, address: &str) -> Result<NodeMatrixRow, EyeError> {
        let slot_url = format!("{}/slot/{}", self.base_url, address);
        let activity_url = format!("{}/activity/{}", self.base_url, address);

        // ۱. دریافت اسلات اصلی نود
        let slot_res = self
            .client
            .get(&slot_url)
            .send()
            .await
            .map_err(|e| EyeError::NetworkError(e.to_string()))?;
        let slot: SlotJson = slot_res
            .json()
            .await
            .map_err(|e| EyeError::ParsingError(e.to_string()))?;

        // ۲. دریافت آرایه فعالیت‌های نوت‌پد ۲
        let act_res = self
            .client
            .get(&activity_url)
            .send()
            .await
            .map_err(|e| EyeError::NetworkError(e.to_string()))?;
        let activities: Vec<ActivityResponse> = act_res
            .json()
            .await
            .map_err(|e| EyeError::ParsingError(e.to_string()))?;

        let mut history_map = HashMap::new();
        for act in activities {
            history_map.insert(
                act.pulse_id,
                EyeCell {
                    pulse_id: act.pulse_id,
                    state_crc: act.state_crc,
                },
            );
        }

        Ok(NodeMatrixRow {
            address: slot.user_address,
            current_rank: "Unknown (Sync via Network)".to_string(),
            balance: slot.balance,
            step_number: slot.step_number,
            history: history_map,
        })
    }
}