ipfrs_cli/commands/
block.rs1use anyhow::Result;
11
12use crate::output::{self, error, format_bytes, print_cid, print_kv, success};
13use crate::progress;
14
15pub async fn block_get(cid_str: String) -> Result<()> {
17 use ipfrs_core::Cid;
18 use ipfrs_storage::{BlockStoreConfig, BlockStoreTrait, SledBlockStore};
19
20 let cid = cid_str
21 .parse::<Cid>()
22 .map_err(|e| anyhow::anyhow!("Invalid CID: {}", e))?;
23
24 let config = BlockStoreConfig::default();
25 let store = SledBlockStore::new(config)?;
26
27 match store.get(&cid).await? {
28 Some(block) => {
29 use std::io::Write;
30 std::io::stdout().write_all(block.data())?;
31 Ok(())
32 }
33 None => {
34 eprintln!("Block not found: {}", cid);
35 std::process::exit(1);
36 }
37 }
38}
39
40pub async fn block_stat(cid_str: String, format: &str) -> Result<()> {
42 use ipfrs_core::Cid;
43 use ipfrs_storage::{BlockStoreConfig, BlockStoreTrait, SledBlockStore};
44
45 let cid = cid_str
46 .parse::<Cid>()
47 .map_err(|e| anyhow::anyhow!("Invalid CID: {}", e))?;
48
49 let config = BlockStoreConfig::default();
50 let store = SledBlockStore::new(config)?;
51
52 match store.get(&cid).await? {
53 Some(block) => {
54 match format {
55 "json" => {
56 println!("{{");
57 println!(" \"cid\": \"{}\",", cid);
58 println!(" \"size\": {}", block.size());
59 println!("}}");
60 }
61 _ => {
62 println!("CID: {}", cid);
63 println!("Size: {} bytes", block.size());
64 }
65 }
66 Ok(())
67 }
68 None => {
69 eprintln!("Block not found: {}", cid);
70 std::process::exit(1);
71 }
72 }
73}
74
75pub async fn block_put(path: String, format: &str) -> Result<()> {
77 use bytes::Bytes;
78 use ipfrs_core::Block;
79 use ipfrs_storage::{BlockStoreConfig, BlockStoreTrait, SledBlockStore};
80
81 let file_path = std::path::Path::new(&path);
82 let filename = file_path
83 .file_name()
84 .map(|s| s.to_string_lossy().to_string())
85 .unwrap_or_else(|| path.clone());
86
87 let pb = progress::spinner(&format!("Reading {}", filename));
89 let data = tokio::fs::read(&path).await?;
90 let size = data.len() as u64;
91 let bytes_data = Bytes::from(data);
92 progress::finish_spinner_success(&pb, &format!("Read {} bytes", size));
93
94 let pb = progress::spinner("Creating block");
96 let block = Block::new(bytes_data)?;
97 let cid = *block.cid();
98 progress::finish_spinner_success(&pb, "Block created");
99
100 let config = BlockStoreConfig::default();
102 let store = SledBlockStore::new(config)?;
103
104 let pb = progress::spinner("Storing raw block");
106 store.put(&block).await?;
107 progress::finish_spinner_success(&pb, "Block stored");
108
109 match format {
110 "json" => {
111 println!("{{");
112 println!(" \"cid\": \"{}\",", cid);
113 println!(" \"size\": {}", block.size());
114 println!("}}");
115 }
116 _ => {
117 success("Raw block stored");
118 print_cid("CID", &cid.to_string());
119 print_kv("Size", &format_bytes(block.size()));
120 }
121 }
122
123 Ok(())
124}
125
126pub async fn block_rm(cid_str: String, force: bool) -> Result<()> {
128 use ipfrs_core::Cid;
129 use ipfrs_storage::{BlockStoreConfig, BlockStoreTrait, SledBlockStore};
130 use std::io::{self, Write};
131
132 let cid = cid_str
133 .parse::<Cid>()
134 .map_err(|e| anyhow::anyhow!("Invalid CID: {}", e))?;
135
136 let config = BlockStoreConfig::default();
137 let store = SledBlockStore::new(config)?;
138
139 if !store.has(&cid).await? {
140 error(&format!("Block not found: {}", cid));
141 std::process::exit(1);
142 }
143
144 if !force {
146 print!("Remove block {}? [y/N] ", cid);
147 io::stdout().flush()?;
148
149 let mut input = String::new();
150 io::stdin().read_line(&mut input)?;
151
152 if !input.trim().eq_ignore_ascii_case("y") {
153 output::info("Aborted");
154 return Ok(());
155 }
156 }
157
158 store.delete(&cid).await?;
159 success(&format!("Removed block: {}", cid));
160
161 Ok(())
162}
163
164pub async fn list_blocks(format: &str) -> Result<()> {
166 use ipfrs_storage::{BlockStoreConfig, BlockStoreTrait, SledBlockStore};
167
168 let config = BlockStoreConfig::default();
170 let store = SledBlockStore::new(config)?;
171
172 let cids = store.list_cids()?;
174
175 if cids.is_empty() {
176 match format {
177 "json" => println!("[]"),
178 _ => println!("No blocks stored"),
179 }
180 } else {
181 match format {
182 "json" => {
183 println!("[");
184 for (i, cid) in cids.iter().enumerate() {
185 if let Some(block) = store.get(cid).await? {
186 print!(" {{");
187 print!("\"cid\": \"{}\", ", cid);
188 print!("\"size\": {}", block.size());
189 if i < cids.len() - 1 {
190 println!("}},");
191 } else {
192 println!("}}");
193 }
194 }
195 }
196 println!("]");
197 }
198 _ => {
199 println!("Stored blocks ({} total):", cids.len());
200 for cid in cids {
201 if let Some(block) = store.get(&cid).await? {
202 println!(" {} ({} bytes)", cid, block.size());
203 }
204 }
205 }
206 }
207 }
208
209 Ok(())
210}