1use crate::{pathinfoservice, utils::AsyncIoBridge};
2
3use super::{NarCalculationService, RenderError};
4use count_write::CountWrite;
5use nix_compat::nar::writer::r#async as nar_writer;
6use sha2::{Digest, Sha256};
7use snix_castore::{Node, blobservice::BlobService, directoryservice::DirectoryService};
8use tokio::io::{self, AsyncWrite, BufReader};
9use tonic::async_trait;
10use tracing::instrument;
11
12pub struct SimpleRenderer<BS, DS> {
13 blob_service: BS,
14 directory_service: DS,
15}
16
17impl<BS, DS> SimpleRenderer<BS, DS> {
18 pub fn new(blob_service: BS, directory_service: DS) -> Self {
19 Self {
20 blob_service,
21 directory_service,
22 }
23 }
24}
25
26#[async_trait]
27impl<BS, DS> NarCalculationService for SimpleRenderer<BS, DS>
28where
29 BS: BlobService + Clone,
30 DS: DirectoryService + Clone,
31{
32 async fn calculate_nar(
33 &self,
34 root_node: &Node,
35 ) -> Result<(u64, [u8; 32]), pathinfoservice::Error> {
36 Ok(calculate_size_and_sha256(
37 root_node,
38 self.blob_service.clone(),
39 self.directory_service.clone(),
40 )
41 .await?)
42 }
43}
44
45#[instrument(skip_all)]
48pub async fn calculate_size_and_sha256<BS, DS>(
49 root_node: &Node,
50 blob_service: BS,
51 directory_service: DS,
52) -> Result<(u64, [u8; 32]), RenderError>
53where
54 BS: BlobService + Send,
55 DS: DirectoryService + Send,
56{
57 let mut h = Sha256::new();
58 let mut cw = CountWrite::from(&mut h);
59
60 write_nar(
61 AsyncIoBridge(&mut cw),
64 root_node,
65 blob_service,
66 directory_service,
67 )
68 .await?;
69
70 Ok((cw.count(), h.finalize().into()))
71}
72
73pub async fn write_nar<W, BS, DS>(
78 mut w: W,
79 root_node: &Node,
80 blob_service: BS,
81 directory_service: DS,
82) -> Result<(), RenderError>
83where
84 W: AsyncWrite + Unpin + Send,
85 BS: BlobService + Send,
86 DS: DirectoryService + Send,
87{
88 let nar_root_node = nar_writer::open(&mut w)
90 .await
91 .map_err(RenderError::NARWriterError)?;
92
93 walk_node(
94 nar_root_node,
95 root_node,
96 b"",
97 blob_service,
98 directory_service,
99 )
100 .await?;
101
102 Ok(())
103}
104
105async fn walk_node<BS, DS>(
108 nar_node: nar_writer::Node<'_, '_>,
109 castore_node: &Node,
110 name: &[u8],
111 blob_service: BS,
112 directory_service: DS,
113) -> Result<(BS, DS), RenderError>
114where
115 BS: BlobService + Send,
116 DS: DirectoryService + Send,
117{
118 match castore_node {
119 Node::Symlink { target, .. } => {
120 nar_node
121 .symlink(target.as_ref())
122 .await
123 .map_err(RenderError::NARWriterError)?;
124 }
125 Node::File {
126 digest,
127 size,
128 executable,
129 } => {
130 let mut blob_reader = match blob_service
131 .open_read(digest)
132 .await
133 .map_err(RenderError::BlobService)?
134 {
135 Some(blob_reader) => Ok(BufReader::new(blob_reader)),
136 None => Err(RenderError::NARWriterError(io::Error::new(
137 io::ErrorKind::NotFound,
138 format!("blob with digest {} not found", &digest),
139 ))),
140 }?;
141
142 nar_node
143 .file(*executable, *size, &mut blob_reader)
144 .await
145 .map_err(RenderError::NARWriterError)?;
146 }
147 Node::Directory { digest, .. } => {
148 match directory_service
150 .get(digest)
151 .await
152 .map_err(RenderError::DirectoryService)?
153 {
154 None => Err(RenderError::DirectoryNotFound(
156 *digest,
157 bytes::Bytes::copy_from_slice(name),
158 ))?,
159 Some(directory) => {
160 let mut nar_node_directory = nar_node
162 .directory()
163 .await
164 .map_err(RenderError::NARWriterError)?;
165
166 let mut blob_service = blob_service;
169 let mut directory_service = directory_service;
170
171 for (name, node) in directory.nodes() {
174 let child_node = nar_node_directory
175 .entry(name.as_ref())
176 .await
177 .map_err(RenderError::NARWriterError)?;
178
179 (blob_service, directory_service) = Box::pin(walk_node(
180 child_node,
181 node,
182 name.as_ref(),
183 blob_service,
184 directory_service,
185 ))
186 .await?;
187 }
188
189 nar_node_directory
191 .close()
192 .await
193 .map_err(RenderError::NARWriterError)?;
194
195 return Ok((blob_service, directory_service));
196 }
197 }
198 }
199 }
200
201 Ok((blob_service, directory_service))
202}