app
Adom Chip Fetcher
Public Made by Adomby adom
Your whole parts library — manufacturer-grade chip CAD (symbol, footprint, 3D) one tap from your EDA tool.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
use anyhow::Result;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::path::PathBuf;
use std::time::{SystemTime, UNIX_EPOCH};
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Project {
pub name: String,
pub mpns: Vec<String>,
#[serde(default)]
pub description: String,
#[serde(default)]
pub created: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct ProjectStore {
pub projects: BTreeMap<String, Project>,
#[serde(default)]
pub active: Option<String>,
}
fn now_unix() -> u64 {
SystemTime::now().duration_since(UNIX_EPOCH).map(|d| d.as_secs()).unwrap_or(0)
}
fn store_path() -> PathBuf {
let home = std::env::var("HOME").unwrap_or_else(|_| "/tmp".into());
let dir = PathBuf::from(home).join(".config/adom-chip-fetcher");
let _ = std::fs::create_dir_all(&dir);
dir.join("projects.json")
}
pub fn load() -> ProjectStore {
let path = store_path();
match std::fs::read_to_string(&path) {
Ok(s) => serde_json::from_str(&s).unwrap_or_default(),
Err(_) => ProjectStore::default(),
}
}
pub fn save(store: &ProjectStore) -> Result<()> {
let path = store_path();
let json = serde_json::to_string_pretty(store)?;
std::fs::write(&path, json)?;
Ok(())
}
pub fn add_mpn(project: &str, mpn: &str) -> Result<()> {
let mut store = load();
let proj = store.projects.entry(project.to_string()).or_insert_with(|| Project {
name: project.to_string(),
mpns: vec![],
description: String::new(),
created: now_unix().to_string(),
});
if !proj.mpns.contains(&mpn.to_string()) {
proj.mpns.push(mpn.to_string());
}
save(&store)
}
pub fn remove_mpn(project: &str, mpn: &str) -> Result<()> {
let mut store = load();
if let Some(proj) = store.projects.get_mut(project) {
proj.mpns.retain(|m| m != mpn);
}
save(&store)
}
pub fn set_active(project: Option<&str>) -> Result<()> {
let mut store = load();
store.active = project.map(|s| s.to_string());
save(&store)
}
pub fn get_active() -> Option<String> {
load().active
}
pub fn list_projects() -> Vec<Project> {
load().projects.values().cloned().collect()
}
pub fn get_project(name: &str) -> Option<Project> {
load().projects.get(name).cloned()
}
pub fn mpns_for_project(name: &str) -> Vec<String> {
load().projects.get(name).map(|p| p.mpns.clone()).unwrap_or_default()
}
pub fn create_project(name: &str, description: &str) -> Result<()> {
let mut store = load();
store.projects.entry(name.to_string()).or_insert_with(|| Project {
name: name.to_string(),
mpns: vec![],
description: description.to_string(),
created: now_unix().to_string(),
});
save(&store)
}
pub fn delete_project(name: &str) -> Result<()> {
let mut store = load();
store.projects.remove(name);
if store.active.as_deref() == Some(name) {
store.active = None;
}
save(&store)
}