1use std::pin::Pin;
2
3use futures::stream::{self, Stream};
4
5use crate::codec::{decode_tree_node, is_tree_node};
6use crate::crypto::{decrypt_chk, EncryptionKey};
7use crate::store::Store;
8use crate::types::{to_hex, Cid, Hash, Link};
9
10use super::{HashTree, HashTreeError};
11
12impl<S: Store> HashTree<S> {
13 pub fn get_stream(
18 &self,
19 cid: &Cid,
20 ) -> Pin<Box<dyn Stream<Item = Result<Vec<u8>, HashTreeError>> + Send + '_>> {
21 let hash = cid.hash;
22 let key = cid.key;
23
24 if let Some(k) = key {
25 Box::pin(self.read_file_stream_encrypted(hash, k))
27 } else {
28 self.read_file_stream(hash)
30 }
31 }
32
33 fn read_file_stream_encrypted(
35 &self,
36 hash: Hash,
37 key: EncryptionKey,
38 ) -> impl Stream<Item = Result<Vec<u8>, HashTreeError>> + Send + '_ {
39 stream::unfold(
40 EncryptedStreamState::Init {
41 hash,
42 key,
43 tree: self,
44 },
45 |state| async move {
46 match state {
47 EncryptedStreamState::Init { hash, key, tree } => {
48 let data = match tree.store.get(&hash).await {
49 Ok(Some(d)) => d,
50 Ok(None) => return None,
51 Err(e) => {
52 return Some((
53 Err(HashTreeError::Store(e.to_string())),
54 EncryptedStreamState::Done,
55 ))
56 }
57 };
58
59 let decrypted = match decrypt_chk(&data, &key) {
61 Ok(d) => d,
62 Err(e) => {
63 return Some((
64 Err(HashTreeError::Decryption(e.to_string())),
65 EncryptedStreamState::Done,
66 ))
67 }
68 };
69
70 if !is_tree_node(&decrypted) {
71 return Some((Ok(decrypted), EncryptedStreamState::Done));
73 }
74
75 let node = match decode_tree_node(&decrypted) {
77 Ok(n) => n,
78 Err(e) => {
79 return Some((
80 Err(HashTreeError::Codec(e)),
81 EncryptedStreamState::Done,
82 ))
83 }
84 };
85
86 let mut stack = node.links.into_iter().rev().collect();
87
88 tree.process_encrypted_stream_stack(&mut stack).await
89 }
90 EncryptedStreamState::Processing { mut stack, tree } => {
91 tree.process_encrypted_stream_stack(&mut stack).await
92 }
93 EncryptedStreamState::Done => None,
94 }
95 },
96 )
97 }
98
99 async fn process_encrypted_stream_stack<'a>(
100 &'a self,
101 stack: &mut Vec<Link>,
102 ) -> Option<(Result<Vec<u8>, HashTreeError>, EncryptedStreamState<'a, S>)> {
103 while let Some(item) = stack.pop() {
104 let data = match self.store.get(&item.hash).await {
105 Ok(Some(d)) => d,
106 Ok(None) => {
107 return Some((
108 Err(HashTreeError::MissingChunk(to_hex(&item.hash))),
109 EncryptedStreamState::Done,
110 ))
111 }
112 Err(e) => {
113 return Some((
114 Err(HashTreeError::Store(e.to_string())),
115 EncryptedStreamState::Done,
116 ))
117 }
118 };
119
120 let decrypted = if let Some(key) = item.key {
122 match decrypt_chk(&data, &key) {
123 Ok(d) => d,
124 Err(e) => {
125 return Some((
126 Err(HashTreeError::Decryption(e.to_string())),
127 EncryptedStreamState::Done,
128 ))
129 }
130 }
131 } else {
132 data
133 };
134
135 match Self::decode_linked_file_node(&item, &decrypted) {
136 Ok(Some(node)) => stack.extend(node.links.into_iter().rev()),
137 Ok(None) => {
138 return Some((
139 Ok(decrypted),
140 EncryptedStreamState::Processing {
141 stack: std::mem::take(stack),
142 tree: self,
143 },
144 ))
145 }
146 Err(e) => return Some((Err(e), EncryptedStreamState::Done)),
147 }
148 }
149 None
150 }
151
152 pub fn read_file_stream(
155 &self,
156 hash: Hash,
157 ) -> Pin<Box<dyn Stream<Item = Result<Vec<u8>, HashTreeError>> + Send + '_>> {
158 Box::pin(stream::unfold(
159 ReadStreamState::Init { hash, tree: self },
160 |state| async move {
161 match state {
162 ReadStreamState::Init { hash, tree } => {
163 let data = match tree.store.get(&hash).await {
164 Ok(Some(d)) => d,
165 Ok(None) => return None,
166 Err(e) => {
167 return Some((
168 Err(HashTreeError::Store(e.to_string())),
169 ReadStreamState::Done,
170 ))
171 }
172 };
173
174 if !is_tree_node(&data) {
175 return Some((Ok(data), ReadStreamState::Done));
177 }
178
179 let node = match decode_tree_node(&data) {
181 Ok(n) => n,
182 Err(e) => {
183 return Some((Err(HashTreeError::Codec(e)), ReadStreamState::Done))
184 }
185 };
186
187 let mut stack = node.links.into_iter().rev().collect();
189
190 tree.process_stream_stack(&mut stack).await
192 }
193 ReadStreamState::Processing { mut stack, tree } => {
194 tree.process_stream_stack(&mut stack).await
195 }
196 ReadStreamState::Done => None,
197 }
198 },
199 ))
200 }
201
202 async fn process_stream_stack<'a>(
203 &'a self,
204 stack: &mut Vec<Link>,
205 ) -> Option<(Result<Vec<u8>, HashTreeError>, ReadStreamState<'a, S>)> {
206 while let Some(item) = stack.pop() {
207 let data = match self.store.get(&item.hash).await {
208 Ok(Some(d)) => d,
209 Ok(None) => {
210 return Some((
211 Err(HashTreeError::MissingChunk(to_hex(&item.hash))),
212 ReadStreamState::Done,
213 ))
214 }
215 Err(e) => {
216 return Some((
217 Err(HashTreeError::Store(e.to_string())),
218 ReadStreamState::Done,
219 ))
220 }
221 };
222
223 match Self::decode_linked_file_node(&item, &data) {
224 Ok(Some(node)) => stack.extend(node.links.into_iter().rev()),
225 Ok(None) => {
226 return Some((
227 Ok(data),
228 ReadStreamState::Processing {
229 stack: std::mem::take(stack),
230 tree: self,
231 },
232 ))
233 }
234 Err(e) => return Some((Err(e), ReadStreamState::Done)),
235 }
236 }
237 None
238 }
239}
240
241enum ReadStreamState<'a, S: Store> {
244 Init {
245 hash: Hash,
246 tree: &'a HashTree<S>,
247 },
248 Processing {
249 stack: Vec<Link>,
250 tree: &'a HashTree<S>,
251 },
252 Done,
253}
254
255enum EncryptedStreamState<'a, S: Store> {
257 Init {
258 hash: Hash,
259 key: [u8; 32],
260 tree: &'a HashTree<S>,
261 },
262 Processing {
263 stack: Vec<Link>,
264 tree: &'a HashTree<S>,
265 },
266 Done,
267}