ipfrs_cli/commands/
pin.rs

1//! Pin management commands
2//!
3//! This module provides pin operations:
4//! - `pin_add` - Pin content
5//! - `pin_rm` - Unpin content
6//! - `pin_ls` - List pins
7//! - `pin_verify` - Verify pin integrity
8
9use anyhow::Result;
10
11use crate::output::{self, error, print_header, print_kv, success};
12use crate::progress;
13
14/// Pin content
15pub async fn pin_add(cid_str: &str, recursive: bool, name: Option<&str>) -> Result<()> {
16    use ipfrs::{Node, NodeConfig};
17    use ipfrs_core::Cid;
18
19    let cid = cid_str
20        .parse::<Cid>()
21        .map_err(|e| anyhow::anyhow!("Invalid CID: {}", e))?;
22
23    let pb = progress::spinner(&format!("Pinning {}", cid));
24    let mut node = Node::new(NodeConfig::default())?;
25    node.start().await?;
26
27    node.pin_add(&cid, recursive, name.map(|s| s.to_string()))
28        .await?;
29    progress::finish_spinner_success(&pb, "Pinned successfully");
30
31    let pin_type = if recursive { "recursively" } else { "directly" };
32    success(&format!("Pinned {} {}", cid, pin_type));
33    if let Some(n) = name {
34        print_kv("Name", n);
35    }
36
37    node.stop().await?;
38    Ok(())
39}
40
41/// Unpin content
42pub async fn pin_rm(cid_str: &str, recursive: bool) -> Result<()> {
43    use ipfrs::{Node, NodeConfig};
44    use ipfrs_core::Cid;
45
46    let cid = cid_str
47        .parse::<Cid>()
48        .map_err(|e| anyhow::anyhow!("Invalid CID: {}", e))?;
49
50    let pb = progress::spinner(&format!("Unpinning {}", cid));
51    let mut node = Node::new(NodeConfig::default())?;
52    node.start().await?;
53
54    node.pin_rm(&cid, recursive).await?;
55    progress::finish_spinner_success(&pb, "Unpinned successfully");
56
57    success(&format!("Unpinned {}", cid));
58
59    node.stop().await?;
60    Ok(())
61}
62
63/// List pins
64pub async fn pin_ls(_pin_type: &str, format: &str) -> Result<()> {
65    use ipfrs::{Node, NodeConfig};
66
67    let pb = progress::spinner("Listing pins");
68    let mut node = Node::new(NodeConfig::default())?;
69    node.start().await?;
70
71    let pins = node.pin_ls()?;
72    progress::finish_spinner_success(&pb, "Pins listed");
73
74    match format {
75        "json" => {
76            println!("[");
77            for (i, pin_info) in pins.iter().enumerate() {
78                print!(
79                    "  {{\"cid\": \"{}\", \"type\": \"{:?}\"}}",
80                    pin_info.cid, pin_info.pin_type
81                );
82                if i < pins.len() - 1 {
83                    println!(",");
84                } else {
85                    println!();
86                }
87            }
88            println!("]");
89        }
90        _ => {
91            if pins.is_empty() {
92                output::info("No pinned content");
93            } else {
94                print_header(&format!("Pinned Content ({})", pins.len()));
95                for pin_info in pins {
96                    println!("  {} ({:?})", pin_info.cid, pin_info.pin_type);
97                }
98            }
99        }
100    }
101
102    node.stop().await?;
103    Ok(())
104}
105
106/// Verify pin integrity
107pub async fn pin_verify(format: &str) -> Result<()> {
108    use ipfrs::{Node, NodeConfig};
109
110    let pb = progress::spinner("Verifying pins");
111    let mut node = Node::new(NodeConfig::default())?;
112    node.start().await?;
113
114    let results = node.pin_verify().await?;
115    progress::finish_spinner_success(&pb, "Verification complete");
116
117    let valid_count = results.iter().filter(|(_, valid)| *valid).count();
118    let invalid_count = results.len() - valid_count;
119
120    match format {
121        "json" => {
122            println!("{{");
123            println!("  \"total\": {},", results.len());
124            println!("  \"valid\": {},", valid_count);
125            println!("  \"invalid\": {}", invalid_count);
126            println!("}}");
127        }
128        _ => {
129            print_header("Pin Verification Results");
130            print_kv("Total pins", &results.len().to_string());
131            print_kv("Valid", &valid_count.to_string());
132            print_kv("Invalid", &invalid_count.to_string());
133
134            if invalid_count > 0 {
135                println!("\nInvalid pins:");
136                for (cid, valid) in &results {
137                    if !valid {
138                        error(&format!("  {}", cid));
139                    }
140                }
141            } else {
142                success("All pins verified successfully");
143            }
144        }
145    }
146
147    node.stop().await?;
148    Ok(())
149}