hardware_toolkit/src/utils/step_downloader.rs

207 lines
6.3 KiB
Rust
Raw Normal View History

use anyhow::Result;
use image::EncodableLayout;
#[allow(unused_imports)]
use tracing::{error, info, warn};
2025-06-28 16:43:09 +08:00
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct SearchResultItem {
name: String,
code: String,
has_device: String,
img_urls: Vec<String>,
}
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct FetchResultItem {
pub imgs: Vec<iced::widget::image::Handle>,
pub name: String,
pub model:String,
pub code :String,
pub model_id: String,
pub datasheet:String,
}
/// 访问一次api得到需要的部分数据
pub async fn search_keyword(
keyword: String,
cur_page: u32,
page_size: u32,
) -> Result<Vec<SearchResultItem>> {
let mut form_maps = std::collections::HashMap::new();
form_maps.insert("keyword", keyword);
let cur_page = format!("{cur_page}");
let page_size = format!("{page_size}");
form_maps.insert("curPage", cur_page);
form_maps.insert("pageSize", page_size);
let resp = reqwest::Client::new()
.post("https://pro.lceda.cn/api/eda/product/search")
.form(&form_maps)
.send()
.await?;
let text = resp.text().await?;
let j: KeywordSearchRoot = serde_json::from_str(&text)?;
let mut r = Vec::new();
for i in j.result.productList.iter() {
if let Some(has) = i.hasDevice.clone() {
let mut imgs = Vec::new();
if let Some(s) = i.image.clone() {
for img in s.imgs() {
imgs.push(img.clone());
}
}
let ii = SearchResultItem {
name: i.model.clone(),
code:i.code.clone(),
has_device: has,
img_urls: imgs,
};
r.push(ii);
}
}
Ok(r)
}
pub async fn download_step(id: String) -> Result<String> {
let url = format!("https://modules.lceda.cn/qAxj6KHrDKw4blvCG8QJPs7Y/{id}");
let url = url.as_str();
let resp = reqwest::get(url).await?;
let text = resp.text().await?;
Ok(text)
}
pub async fn fetch_item(item: SearchResultItem) -> Result<FetchResultItem> {
let h = search_has_device(&item.has_device).await?;
let mut has_device = String::new();
let v: serde_json::Value = serde_json::from_str(h.as_str())?;
let id = v["result"][0]["attributes"]["3D Model"].clone();
if let serde_json::Value::String(id) = id {
has_device = id.clone();
}
let mut title = String::new();
let mut footprint = String::new();
let mut datasheet = String::new();
if let serde_json::Value::String(t) = v["result"][0]["title"].clone(){
title = t;
}
if let serde_json::Value::String(t) = v["result"][0]["attributes"]["Supplier Footprint"].clone(){
footprint = t;
}
if let serde_json::Value::String(t) = v["result"][0]["attributes"]["Datasheet"].clone(){
datasheet = t;
}
let mut step_id = String::new();
let resp = search_model_id(has_device.as_str()).await?;
let mut model = String::new();
let v: serde_json::Value = serde_json::from_str(resp.as_str())?;
info!("In search_model_id: The v is : {v:#?}");
let data_str: serde_json::Value = v["result"][0]["dataStr"].clone();
if let serde_json::Value::String(data_str) = data_str {
let data_str: DataStr = serde_json::from_str(data_str.as_str())?;
if let Some(m) = data_str.model {
step_id = m;
}else{
return Err(anyhow::Error::msg("Failed to get model"));
}
}
let mut imgs = Vec::new();
for img_url in item.img_urls {
info!("Fetching img url: {}", img_url);
let img = reqwest::get(img_url).await?.bytes().await?;
// let img = image::load_from_memory(&img)?;
let img = iced::widget::image::Handle::from_bytes(img.clone());
imgs.push(img);
}
let rst = FetchResultItem {
name: item.name.clone(),
model_id: step_id,
model:footprint,
code:item.code,
imgs,
datasheet,
};
Ok(rst)
2025-06-28 16:43:09 +08:00
}
async fn search_has_device(has_device: &str) -> Result<String> {
let mut form_maps = std::collections::HashMap::new();
form_maps.insert("uuids[]", has_device);
let url = "https://pro.lceda.cn/api/devices/searchByIds";
let resp = reqwest::Client::new()
.post(url)
.form(&form_maps)
.send()
.await?;
let text = resp.text().await?;
Ok(text)
}
async fn search_model_id(uuid: &str) -> Result<String> {
let mut form_maps = std::collections::HashMap::new();
form_maps.insert("uuids[]", uuid);
form_maps.insert("dataStr", "yes");
let url = "https://pro.lceda.cn/api/components/searchByIds?forceOnline=1";
2025-06-28 16:43:09 +08:00
let resp = reqwest::Client::new()
.post(url)
.form(&form_maps)
.send()
.await?;
let text = resp.text().await?;
info!("In search_model_id: The v is : {}",text.clone());
return Ok(text)
}
#[derive(Clone, Default, Debug, serde::Serialize, serde::Deserialize, Eq, PartialEq)]
struct KeywordSearchRoot {
code: u32,
success: bool,
result: KeywordSearchResult,
}
#[allow(non_snake_case)]
#[derive(Default, Debug, serde::Serialize, serde::Deserialize, Clone, Eq, PartialEq)]
struct KeywordSearchResult {
total: u32,
productList: Vec<KeywordSearchListItem>,
}
#[allow(non_snake_case)]
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, Eq, PartialEq)]
struct KeywordSearchListItem {
id: u32,
code: String,
image: Option<KeywordChipImages>,
model: String,
hasDevice: Option<String>,
}
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, Eq, PartialEq)]
struct KeywordChipImages(String);
#[allow(dead_code)]
impl KeywordChipImages {
pub fn imgs(&self) -> Vec<String> {
let urls = self.0.clone();
let list = urls.split("<$>");
let mut rst = Vec::new();
for i in list {
rst.push(i.to_string());
}
rst
2025-06-28 16:43:09 +08:00
}
}
#[derive(Debug, serde::Serialize, serde::Deserialize)]
struct KeywordDevInfo {
uuid: String,
description: String,
title: String,
images: Vec<String>,
attributes: KeywordAttributes,
}
#[allow(non_snake_case)]
#[derive(Debug, serde::Serialize, serde::Deserialize)]
struct KeywordAttributes {
Datasheet: Option<String>,
}
#[derive(Debug, serde::Serialize, serde::Deserialize)]
struct DataStr {
model: Option<String>,
src: Option<String>,
_type: Option<String>,
}