newton-core 0.4.16

newton protocol core sdk
use std::fmt;

use serde::{Deserialize, Serialize};

/// Fallback public IPFS gateway.
pub const PUBLIC_IPFS_GATEWAY: &str = "https://ipfs.io/ipfs/";

/// Default Newton-operated IPFS gateway.
pub const NEWTON_IPFS_GATEWAY: &str = "https://ipfs.newt.foundation/ipfs/";

fn default_fallback_gateway() -> String {
    std::env::var("IPFS_FALLBACK_GATEWAY").unwrap_or(PUBLIC_IPFS_GATEWAY.to_string())
}

/// Default values for cache configuration
fn default_cache_enabled() -> bool {
    std::env::var("IPFS_CACHE_ENABLED")
        .ok()
        .and_then(|v| v.parse().ok())
        .unwrap_or(true)
}

fn default_memory_cache_size() -> usize {
    std::env::var("IPFS_MEMORY_CACHE_SIZE")
        .ok()
        .and_then(|v| v.parse().ok())
        .unwrap_or(100)
}

fn default_memory_cache_ttl_secs() -> u64 {
    std::env::var("IPFS_MEMORY_CACHE_TTL_SECS")
        .ok()
        .and_then(|v| v.parse().ok())
        .unwrap_or(3600) // 1 hour
}

fn default_redis_cache_enabled() -> bool {
    std::env::var("IPFS_REDIS_CACHE_ENABLED")
        .ok()
        .and_then(|v| v.parse().ok())
        .unwrap_or(true)
}

fn default_redis_cache_ttl_secs() -> u64 {
    std::env::var("IPFS_REDIS_CACHE_TTL_SECS")
        .ok()
        .and_then(|v| v.parse().ok())
        .unwrap_or(43200) // 12 hours
}

fn default_max_fetch_size_bytes() -> usize {
    std::env::var("IPFS_MAX_FETCH_SIZE_BYTES")
        .ok()
        .and_then(|v| v.parse().ok())
        .unwrap_or(50 * 1024 * 1024) // 50 MiB
}

/// Configuration for IPFS gateway access.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct IpfsConfig {
    /// Base URL of the IPFS gateway.
    pub gateway: String,
    /// Additional query parameters appended to IPFS requests.
    pub params: String,
    /// Base URL of the fallback public IPFS gateway used after primary failure.
    #[serde(default = "default_fallback_gateway")]
    pub fallback_gateway: String,

    /// Enable IPFS content caching (L1 memory + L2 Redis).
    #[serde(default = "default_cache_enabled")]
    pub cache_enabled: bool,

    /// Maximum number of entries in the L1 in-memory cache.
    #[serde(default = "default_memory_cache_size")]
    pub memory_cache_size: usize,

    /// TTL for L1 in-memory cache entries in seconds.
    #[serde(default = "default_memory_cache_ttl_secs")]
    pub memory_cache_ttl_secs: u64,

    /// Enable Redis L2 cache for IPFS content.
    #[serde(default = "default_redis_cache_enabled")]
    pub redis_cache_enabled: bool,

    /// TTL for L2 Redis cache entries in seconds.
    #[serde(default = "default_redis_cache_ttl_secs")]
    pub redis_cache_ttl_secs: u64,

    /// Maximum size in bytes for a single IPFS fetch response.
    #[serde(default = "default_max_fetch_size_bytes")]
    pub max_fetch_size_bytes: usize,
}

impl fmt::Display for IpfsConfig {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "IpfsConfig: {}/<cid>?{} (fallback: {}, cache: {}, memory_size: {}, redis: {}, max_fetch: {})",
            self.gateway,
            self.params,
            self.fallback_gateway,
            self.cache_enabled,
            self.memory_cache_size,
            self.redis_cache_enabled,
            self.max_fetch_size_bytes
        )
    }
}

impl Default for IpfsConfig {
    fn default() -> Self {
        Self {
            gateway: std::env::var("IPFS_GATEWAY").unwrap_or(PUBLIC_IPFS_GATEWAY.to_string()),
            params: std::env::var("IPFS_PARAMS").unwrap_or_default(),
            fallback_gateway: default_fallback_gateway(),
            cache_enabled: default_cache_enabled(),
            memory_cache_size: default_memory_cache_size(),
            memory_cache_ttl_secs: default_memory_cache_ttl_secs(),
            redis_cache_enabled: default_redis_cache_enabled(),
            redis_cache_ttl_secs: default_redis_cache_ttl_secs(),
            max_fetch_size_bytes: default_max_fetch_size_bytes(),
        }
    }
}