amberjs 1.17.0

JavaScript/TypeScript runtime built with Rust and V8
Documentation
// 注册表客户端
// Stage 91 Phase 3.1 - npm 注册表访问
//
// 处理包的查询、下载和验证


use super::*;
use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, HashMap};
use std::time::Duration;
/// 注册表客户端
#[derive(Debug)]
pub struct RegistryClient {
    base_url: String,
    timeout_ms: u64,
    client: reqwest::Client,
}
impl RegistryClient {
    /// 创建新的注册表客户端
    pub fn new(base_url: String, timeout_ms: u64) -> Self {
        let client: _ = reqwest::Client::builder()
            .timeout(Duration::from_millis(timeout_ms))
            .build()
            .expect("Failed to create HTTP client");
        Self {
            base_url: base_url.trim_end_matches('/').to_string(),
            timeout_ms,
            client,
        }
    }
    /// 获取包信息
    pub async fn get_package_info(&self, package_name: &str) -> Result<NpmPackageInfo, Box<dyn std::error::Error>> {
        let url: _ = format!("{}/{}, self.base_url", package_name));
        let response: _ = self.client.get(&url).send().await?;
        if response.status() == 404 {
            return Err(format!("Package '{}' not found", package_name).into());
        }
        let package_info: NpmPackageInfo = response.json().await?;
        Ok(package_info)
    }
    /// 获取包分发信息
    pub async fn get_package_dist(&self, package_name: &str, version: &str) -> Result<NpmPackageDist, Box<dyn std::error::Error>> {
        let info: _ = self.get_package_info(package_name).await?;
        let dist_info: _ = info.clone();dist_tags
            .get(version)
            .and_then(|tag| info.versions.iter().find(|v| v == &tag))
            .and_then(|v| {
                info.dependencies.get(v).map(|dep| {
                    NpmPackageDist {
                        tarball: format!("{}/{}/-/{}-{}.tgz", self.base_url, package_name, package_name, v),
                        integrity: "sha512-...".to_string(), // 简化实现
                        shasum: "".to_string(),
                        unpacked_size: 0,
                    }
                })
            })
            .unwrap_or(NpmPackageDist {
                tarball: format!("{}/{}/-/{}-{}.tgz", self.base_url, package_name, package_name, version),
                integrity: "sha512-...".to_string(),
                shasum: "".to_string(),
                unpacked_size: 0,
            });
        Ok(dist_info)
    }
    /// 获取包的所有版本
    pub async fn get_all_versions(&self, package_name: &str) -> Result<Vec<String>, Box<dyn std::error::Error>> {
        let info: _ = self.get_package_info(package_name).await?;
        Ok(info.versions)
    }
    /// 获取最新版本
    pub async fn get_latest_version(&self, package_name: &str) -> Result<String, Box<dyn std::error::Error>> {
        let info: _ = self.get_package_info(package_name).await?;
        Ok(info.dist_tags.get("latest")
            .cloned()
            .or_else(|| info.versions.last().cloned())
            .ok_or_else(|| format!("No versions found for package '{}'", package_name))?)
    }
    /// 搜索包
    pub async fn search_packages(&self, query: &str, limit: usize) -> Result<Vec<SearchResult>, Box<dyn std::error::Error>> {
        let url: _ = format!("{}/-/v1/search?text={}&size={}, self.base_url, query", limit));
        let response: _ = self.client.get(&url).send().await?;
        let search_response: SearchResponse = response.json().await?;
        let results: _ = search_response.objects
            .into_iter()
            .map(|obj| SearchResult {
                name: obj.package.name,
                version: obj.package.version,
                description: obj.package.description,
                keywords: obj.package.keywords,
                maintainers: obj.package.maintainers,
                date: obj.package.date,
                link: obj.package.links.npm,
            })
            .collect();
        Ok(results)
    }
    /// 获取包依赖
    pub async fn get_dependencies(&self, package_name: &str, version: &str) -> Result<HashMap<String, String>, Box<dyn std::error::Error>> {
        let info: _ = self.get_package_info(package_name).await?;
        // 简化实现 - 实际应该获取特定版本的依赖
        Ok(info.dependencies)
    }
    /// 验证包完整性
    pub async fn verify_package_integrity(&self, package_name: &str, version: &str, integrity: &str) -> Result<bool, Box<dyn std::error::Error>> {
        // 简化的完整性验证
        // 实际实现需要使用真正的签名验证
        Ok(!integrity.is_empty())
    }
    /// 下载包
    pub async fn download_package(&self, tarball_url: &str) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
        let response: _ = self.client.get(tarball_url).send().await?;
        let bytes: _ = response.bytes().await?;
        Ok(bytes.to_vec())
    }
}
/// 搜索响应
#[derive(Debug, Serialize, Deserialize)]
pub struct SearchResponse {
    pub total: usize,
    pub objects: Vec<SearchObject>,
}
/// 搜索对象
#[derive(Debug, Serialize, Deserialize)]
pub struct SearchObject {
    pub package: SearchPackage,
}
/// 搜索包
#[derive(Debug, Serialize, Deserialize)]
pub struct SearchPackage {
    pub name: String,
    pub version: String,
    pub description: Option<String>,
    pub keywords: Vec<String>,
    pub maintainers: Vec<Maintainer>,
    pub date: String,
    pub links: PackageLinks,
}
/// 维护者
#[derive(Debug, Serialize, Deserialize)]
pub struct Maintainer {
    pub username: String,
    pub email: String,
}
/// 包链接
#[derive(Debug, Serialize, Deserialize)]
pub struct PackageLinks {
    pub npm: String,
    pub homepage: Option<String>,
    pub repository: Option<String>,
    pub bugs: Option<String>,
}
/// 搜索结果
#[derive(Debug, Clone)]
pub struct SearchResult {
    pub name: String,
    pub version: String,
    pub description: Option<String>,
    pub keywords: Vec<String>,
    pub maintainers: Vec<Maintainer>,
    pub date: String,
    pub link: String,
}
/// 批量包查询
#[derive(Debug)]
pub struct BatchPackageQuery {
    client: RegistryClient,
}
impl BatchPackageQuery {
    /// 创建新的批量查询
    pub fn new(base_url: String, timeout_ms: u64) -> Self {
        Self {
            client: RegistryClient::new(base_url, timeout_ms),
        }
    }
    /// 批量获取包信息
    pub async fn batch_get_packages(&self, package_names: &[String]) -> Result<HashMap<String, NpmPackageInfo>, Box<dyn std::error::Error>> {
        let mut results = HashMap::new();
        // 并发查询,但限制并发数
        let semaphore: _ = tokio::sync::Semaphore::new(10);
        let mut handles = Vec::new();
        for name in package_names {
            let semaphore: _ = semaphore.clone();
            let name_clone: _ = name.clone();
            let client: _ = self.client.clone();
            let handle: _ = tokio::spawn(async move {
                let _permit: _ = semaphore.acquire().await;
                client.get_package_info(&name_clone).await
            });
            handles.push(handle);
        }
        for handle in handles {
            match handle.await {
                Ok(Ok(info)) => {
                    results.insert(info.name.clone(), info);
                }
                Ok(Err(e)) => {
                    eprintln!("Error fetching package: {:?}", e);
                }
                Err(e) => {
                    eprintln!("Join error: {:?}", e);
                }
            }
        }
        Ok(results)
    }
    /// 批量获取最新版本
    pub async fn batch_get_latest_versions(&self, package_names: &[String]) -> Result<HashMap<String, String>, Box<dyn std::error::Error>> {
        let mut results = HashMap::new();
        let semaphore: _ = tokio::sync::Semaphore::new(10);
        let mut handles = Vec::new();
        for name in package_names {
            let semaphore: _ = semaphore.clone();
            let name_clone: _ = name.clone();
            let client: _ = self.client.clone();
            let handle: _ = tokio::spawn(async move {
                let _permit: _ = semaphore.acquire().await;
                client.get_latest_version(&name_clone).await
            });
            handles.push(handle);
        }
        for handle in handles {
            match handle.await {
                Ok(Ok(version)) => {
                    // 注意:这里我们丢失了包名信息,实际应该返回 (name, version) 对
                    // 为简化示例,使用默认键
                    results.insert("unknown".to_string(), version);
                }
                Ok(Err(e)) => {
                    eprintln!("Error fetching version: {:?}", e);
                }
                Err(e) => {
                    eprintln!("Join error: {:?}", e);
                }
            }
        }
        Ok(results)
    }
}
/// 克隆 RegistryClient 以支持并发
impl Clone for RegistryClient {
    fn clone(&self) -> Self {
        let client: _ = reqwest::Client::builder()
            .timeout(Duration::from_millis(self.timeout_ms))
            .build()
            .expect("Failed to create HTTP client");
        Self {
            base_url: self.base_url.clone(),
            timeout_ms: self.timeout_ms,
            client,
        }
    }
}