1use std::{future::Future, ops::DerefMut, sync::Arc};
2
3use bytes::Bytes;
4use tokio::{
5 io::{AsyncReadExt, AsyncWriteExt, ReadHalf, WriteHalf, copy_buf, split},
6 sync::Mutex,
7};
8use tracing::{debug, warn};
9
10use super::{
11 NixDaemonIO,
12 framing::{NixFramedReader, StderrReadFramedReader},
13 types::{QueryValidPaths, ValidPathInfo},
14 worker_protocol::{ClientSettings, Operation, STDERR_LAST, Trust, server_handshake_client},
15};
16
17use crate::{
18 nix_daemon::types::BuildPaths,
19 store_path::StorePath,
20 wire::{
21 ProtocolVersion,
22 de::{NixRead, NixReader},
23 ser::{NixSerialize, NixWrite, NixWriter, NixWriterBuilder},
24 },
25};
26
27use crate::{nix_daemon::types::NixError, worker_protocol::STDERR_ERROR};
28
29#[allow(dead_code)]
40pub struct NixDaemon<IO, R, W> {
41 io: Arc<IO>,
42 protocol_version: ProtocolVersion,
43 client_settings: ClientSettings,
44 reader: NixReader<R>,
45 writer: Arc<Mutex<NixWriter<W>>>,
46}
47
48impl<IO, R, W> NixDaemon<IO, R, W>
49where
50 IO: NixDaemonIO + Sync + Send,
51{
52 pub fn new(
53 io: Arc<IO>,
54 protocol_version: ProtocolVersion,
55 client_settings: ClientSettings,
56 reader: NixReader<R>,
57 writer: NixWriter<W>,
58 ) -> Self {
59 Self {
60 io,
61 protocol_version,
62 client_settings,
63 reader,
64 writer: Arc::new(Mutex::new(writer)),
65 }
66 }
67}
68
69impl<IO, RW> NixDaemon<IO, ReadHalf<RW>, WriteHalf<RW>>
70where
71 RW: AsyncReadExt + AsyncWriteExt + Send + Unpin + 'static,
72 IO: NixDaemonIO + Sync + Send,
73{
74 pub async fn initialize(io: Arc<IO>, mut connection: RW) -> Result<Self, std::io::Error>
81 where
82 RW: AsyncReadExt + AsyncWriteExt + Send + Unpin,
83 {
84 let protocol_version =
85 server_handshake_client(&mut connection, "2.18.2", Trust::Trusted).await?;
86
87 connection.write_u64_le(STDERR_LAST).await?;
88 let (reader, writer) = split(connection);
89 let mut reader = NixReader::builder()
90 .set_version(protocol_version)
91 .build(reader);
92 let mut writer = NixWriterBuilder::default()
93 .set_version(protocol_version)
94 .build(writer);
95
96 let operation: Operation = reader.read_value().await?;
98 if operation != Operation::SetOptions {
99 return Err(std::io::Error::other(
100 "Expected SetOptions operation, but got {operation}",
101 ));
102 }
103 let client_settings: ClientSettings = reader.read_value().await?;
104 writer.write_number(STDERR_LAST).await?;
105 writer.flush().await?;
106
107 Ok(Self::new(
108 io,
109 protocol_version,
110 client_settings,
111 reader,
112 writer,
113 ))
114 }
115
116 pub async fn handle_client(&mut self) -> Result<(), std::io::Error> {
118 let io = self.io.clone();
119 loop {
120 let op_code = self.reader.read_number().await?;
121 let op = TryInto::<Operation>::try_into(op_code);
122 debug!(?op, "Received operation");
123 match op {
124 Ok(operation) => match operation {
126 Operation::IsValidPath => {
127 let path: StorePath = self.reader.read_value().await?;
128 Self::handle(&self.writer, io.is_valid_path(&path)).await?
129 }
130 Operation::SetOptions => {
135 self.client_settings = self.reader.read_value().await?;
136 Self::handle(&self.writer, async { Ok(()) }).await?
137 }
138 Operation::QueryPathInfo => {
139 let path: StorePath = self.reader.read_value().await?;
140 Self::handle(&self.writer, io.query_path_info(&path)).await?
141 }
142 Operation::QueryPathFromHashPart => {
143 let hash: Bytes = self.reader.read_value().await?;
144 Self::handle(&self.writer, io.query_path_from_hash_part(&hash)).await?
145 }
146 Operation::QueryValidPaths => {
147 let query: QueryValidPaths = self.reader.read_value().await?;
148 Self::handle(&self.writer, io.query_valid_paths(&query)).await?
149 }
150 Operation::QueryValidDerivers => {
151 let path: StorePath = self.reader.read_value().await?;
152 Self::handle(&self.writer, io.query_valid_derivers(&path)).await?
153 }
154 Operation::QueryReferrers | Operation::QueryRealisation => {
161 let _: String = self.reader.read_value().await?;
162 Self::handle(&self.writer, async move {
163 warn!(
164 ?operation,
165 "This operation is not implemented. Returning empty result..."
166 );
167 Ok(Vec::<StorePath>::new())
168 })
169 .await?
170 }
171 Operation::AddMultipleToStore => {
172 let repair = self.reader.read_value::<bool>().await?;
173 let dont_check_sigs = self.reader.read_value::<bool>().await?;
174
175 let builder = NixReader::builder().set_version(self.reader.version());
176 let mut framed = NixFramedReader::new(&mut self.reader);
177 Self::handle(&self.writer, async {
178 let mut source = builder.build(&mut framed);
179 let count = source.read_number().await?;
180 for _ in 0..count {
181 let info = source.read_value::<ValidPathInfo>().await?;
182 self.io
183 .add_to_store_nar(info, &mut source, repair, dont_check_sigs)
184 .await?;
185 }
186 Ok(())
187 })
188 .await?;
189
190 if !framed.is_eof_unpin().await? {
193 return Err(std::io::Error::new(
194 std::io::ErrorKind::InvalidData,
195 "payload was not fully consumed",
196 ));
197 }
198 }
199 Operation::AddToStoreNar => {
200 let info = self.reader.read_value::<ValidPathInfo>().await?;
201 let repair = self.reader.read_value::<bool>().await?;
202 let dont_check_sigs = self.reader.read_value::<bool>().await?;
203
204 let minor_version = self.protocol_version.minor();
205 match minor_version {
206 ..21 => {
207 Self::handle(
210 &self.writer,
211 self.io.add_to_store_nar(
212 info,
213 &mut self.reader,
214 repair,
215 dont_check_sigs,
216 ),
217 )
218 .await?
219 }
220 21..23 => {
221 Self::handle(&self.writer, async {
223 let mut writer = self.writer.lock().await;
224 let mut reader = StderrReadFramedReader::new(
225 &mut self.reader,
226 writer.deref_mut(),
227 );
228 self.io
229 .add_to_store_nar(
230 info,
231 &mut reader,
232 repair,
233 dont_check_sigs,
234 )
235 .await
236 })
238 .await?
239 }
240 23.. => {
241 let mut framed = NixFramedReader::new(&mut self.reader);
243
244 Self::handle(&self.writer, async {
245 self.io
246 .add_to_store_nar(
247 info,
248 &mut framed,
249 repair,
250 dont_check_sigs,
251 )
252 .await
253 })
254 .await?;
255
256 if !framed.is_eof_unpin().await? {
259 return Err(std::io::Error::new(
260 std::io::ErrorKind::InvalidData,
261 "payload was not fully consumed",
262 ));
263 }
264 }
265 }
266 }
267 Operation::BuildPaths => {
268 let args: BuildPaths = self.reader.read_value().await?;
269 Self::handle(&self.writer, self.io.build_paths(args.paths, args.mode))
270 .await?
271 }
272 Operation::BuildPathsWithResults => {
273 let args: BuildPaths = self.reader.read_value().await?;
274 Self::handle(
275 &self.writer,
276 self.io.build_paths_with_results(args.paths, args.mode),
277 )
278 .await?
279 }
280 Operation::QueryMissing => {
281 let derived_paths = self.reader.read_value().await?;
282 Self::handle(&self.writer, self.io.query_missing(derived_paths)).await?
283 }
284 Operation::EnsurePath => {
285 let store_path = self.reader.read_value().await?;
286 Self::handle(&self.writer, self.io.ensure_path(&store_path)).await?
287 }
288 Operation::QueryDerivationOutputMap => {
289 let store_path = self.reader.read_value().await?;
290 Self::handle(
291 &self.writer,
292 self.io.query_derivation_output_map(&store_path),
293 )
294 .await?
295 }
296 Operation::NarFromPath => {
297 let store_path = self.reader.read_value().await?;
298 let result = self.io.nar_from_path(&store_path).await;
299 let mut writer = self.writer.lock().await;
300
301 match result {
302 Ok(mut reader) => {
303 writer.write_number(STDERR_LAST).await?;
306 copy_buf(&mut reader, &mut *writer).await?;
307 writer.flush().await?;
308 }
309 Err(err) => {
310 debug!(%err, "IO error");
311 writer.write_number(STDERR_ERROR).await?;
312 writer.write_value(&NixError::new(format!("{err}"))).await?;
313 writer.flush().await?;
314 }
315 }
316 }
317 _ => {
318 return Err(std::io::Error::other(format!(
319 "Operation {operation:?} is not implemented"
320 )));
321 }
322 },
323 _ => {
324 return Err(std::io::Error::other(format!(
325 "Unknown operation code received: {op_code}"
326 )));
327 }
328 }
329 }
330 }
331
332 async fn handle<T>(
342 writer: &Arc<Mutex<NixWriter<WriteHalf<RW>>>>,
343 future: impl Future<Output = std::io::Result<T>>,
344 ) -> Result<(), std::io::Error>
345 where
346 T: NixSerialize + Send,
347 {
348 let result = future.await;
349 let mut writer = writer.lock().await;
350
351 match result {
352 Ok(r) => {
353 writer.write_number(STDERR_LAST).await?;
356 writer.write_value(&r).await?;
357 writer.flush().await
358 }
359 Err(e) => {
360 debug!(err = ?e, "IO error");
361 writer.write_number(STDERR_ERROR).await?;
362 writer.write_value(&NixError::new(format!("{e:?}"))).await?;
363 writer.flush().await
364 }
365 }
366 }
367}
368
369#[cfg(test)]
370mod tests {
371 use super::*;
372 use std::{io::ErrorKind, sync::Arc};
373
374 use mockall::predicate;
375 use tokio::io::AsyncWriteExt;
376
377 use crate::{
378 nix_daemon::MockNixDaemonIO,
379 wire::ProtocolVersion,
380 worker_protocol::{ClientSettings, WORKER_MAGIC_1, WORKER_MAGIC_2},
381 };
382
383 #[tokio::test]
384 async fn test_daemon_initialization() {
385 let mut builder = tokio_test::io::Builder::new();
386 let test_conn = builder
387 .read(&WORKER_MAGIC_1.to_le_bytes())
388 .write(&WORKER_MAGIC_2.to_le_bytes())
389 .write(&[37, 1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
391 .read(&[35, 1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
393 .read(&[0; 8])
395 .read(&[0; 8])
397 .write(&[0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
399 .write(&[50, 46, 49, 56, 46, 50, 0, 0])
401 .write(&[1, 0, 0, 0, 0, 0, 0, 0])
403 .write(&[115, 116, 108, 97, 0, 0, 0, 0]);
405
406 let mut bytes = Vec::new();
407 let mut writer = NixWriter::new(&mut bytes);
408 writer
409 .write_value(&ClientSettings::default())
410 .await
411 .unwrap();
412 writer.flush().await.unwrap();
413
414 let test_conn = test_conn
415 .read(&[19, 0, 0, 0, 0, 0, 0, 0])
417 .read(&bytes)
418 .write(&[115, 116, 108, 97, 0, 0, 0, 0])
420 .build();
421
422 let mock = MockNixDaemonIO::new();
423 let daemon = NixDaemon::initialize(Arc::new(mock), test_conn)
424 .await
425 .unwrap();
426 assert_eq!(daemon.client_settings, ClientSettings::default());
427 assert_eq!(daemon.protocol_version, ProtocolVersion::from_parts(1, 35));
428 }
429
430 async fn serialize<T>(req: &T, protocol_version: ProtocolVersion) -> Vec<u8>
431 where
432 T: NixSerialize + Send,
433 {
434 let mut result: Vec<u8> = Vec::new();
435 let mut w = NixWriter::builder()
436 .set_version(protocol_version)
437 .build(&mut result);
438 w.write_value(req).await.unwrap();
439 w.flush().await.unwrap();
440 result
441 }
442
443 async fn respond<T>(
444 resp: &Result<T, std::io::Error>,
445 protocol_version: ProtocolVersion,
446 ) -> Vec<u8>
447 where
448 T: NixSerialize + Send,
449 {
450 let mut result: Vec<u8> = Vec::new();
451 let mut w = NixWriter::builder()
452 .set_version(protocol_version)
453 .build(&mut result);
454 match resp {
455 Ok(value) => {
456 w.write_value(&STDERR_LAST).await.unwrap();
457 w.write_value(value).await.unwrap();
458 }
459 Err(e) => {
460 w.write_value(&STDERR_ERROR).await.unwrap();
461 w.write_value(&NixError::new(format!("{e:?}")))
462 .await
463 .unwrap();
464 }
465 }
466 w.flush().await.unwrap();
467 result
468 }
469
470 #[tokio::test]
471 async fn test_handle_is_valid_path_ok() {
472 let version = ProtocolVersion::from_parts(1, 37);
473 let (io, mut handle) = tokio_test::io::Builder::new().build_with_handle();
474 let mut mock = MockNixDaemonIO::new();
475 let (reader, writer) = split(io);
476 let path = StorePath::from_absolute_path(
477 "/nix/store/33l4p0pn0mybmqzaxfkpppyh7vx1c74p-hello-2.12.1".as_bytes(),
478 )
479 .unwrap();
480 mock.expect_is_valid_path()
481 .with(predicate::eq(path.clone()))
482 .times(1)
483 .returning(|_| Box::pin(async { Ok(true) }));
484
485 handle.read(&Into::<u64>::into(Operation::IsValidPath).to_le_bytes());
486 handle.read(&serialize(&path, version).await);
487 handle.write(&respond(&Ok(true), version).await);
488 drop(handle);
489
490 let mut daemon = NixDaemon::new(
491 Arc::new(mock),
492 version,
493 ClientSettings::default(),
494 NixReader::new(reader),
495 NixWriter::new(writer),
496 );
497 assert_eq!(
498 ErrorKind::UnexpectedEof,
499 daemon
500 .handle_client()
501 .await
502 .expect_err("Expecting eof")
503 .kind()
504 );
505 }
506
507 #[tokio::test]
508 async fn test_handle_is_valid_path_err() {
509 let version = ProtocolVersion::from_parts(1, 37);
510 let (io, mut handle) = tokio_test::io::Builder::new().build_with_handle();
511 let mut mock = MockNixDaemonIO::new();
512 let (reader, writer) = split(io);
513 let path: StorePath = StorePath::from_absolute_path(
514 "/nix/store/33l4p0pn0mybmqzaxfkpppyh7vx1c74p-hello-2.12.1".as_bytes(),
515 )
516 .unwrap();
517 mock.expect_is_valid_path()
518 .with(predicate::eq(path.clone()))
519 .times(1)
520 .returning(|_| Box::pin(async { Err(std::io::Error::other("hello")) }));
521
522 handle.read(&Into::<u64>::into(Operation::IsValidPath).to_le_bytes());
523 handle.read(&serialize(&path, version).await);
524 handle.write(&respond::<bool>(&Err(std::io::Error::other("hello")), version).await);
525 drop(handle);
526
527 let mut daemon = NixDaemon::new(
528 Arc::new(mock),
529 version,
530 ClientSettings::default(),
531 NixReader::new(reader),
532 NixWriter::new(writer),
533 );
534 assert_eq!(
535 ErrorKind::UnexpectedEof,
536 daemon
537 .handle_client()
538 .await
539 .expect_err("Expecting eof")
540 .kind()
541 );
542 }
543}