about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFlorian Klink <flokli@flokli.de>2023-02-12T13·34+0100
committerflokli <flokli@flokli.de>2023-03-10T10·58+0000
commitdd1ee7a2e761852c39a82eb8301ab4599ff642cd (patch)
tree191f9f4220e11218ad1c0fbf14b87b35a52cc506
parent9b3228959a99e81ab6f1ce9c3a21136dfee82c62 (diff)
feat(tvix/store): add GRPCPathInfoServiceWrapper r/5920
This exposes a proto::pathinfo_service_server::PathInfoService for a
directoryservice::PathInfoService and a way to calculate NARs.

Change-Id: I30cd058562f83d063c78b84976ec97190de49400
Reviewed-on: https://cl.tvl.fyi/c/depot/+/8097
Tested-by: BuildkiteCI
Reviewed-by: raitobezarius <tvl@lahfa.xyz>
-rw-r--r--tvix/store/src/proto/grpc_pathinfoservice_wrapper.rs85
-rw-r--r--tvix/store/src/proto/mod.rs2
2 files changed, 87 insertions, 0 deletions
diff --git a/tvix/store/src/proto/grpc_pathinfoservice_wrapper.rs b/tvix/store/src/proto/grpc_pathinfoservice_wrapper.rs
new file mode 100644
index 0000000000..c7df6b643a
--- /dev/null
+++ b/tvix/store/src/proto/grpc_pathinfoservice_wrapper.rs
@@ -0,0 +1,85 @@
+use crate::nar::RenderError;
+use crate::proto;
+use crate::{nar::NARCalculationService, pathinfoservice::PathInfoService};
+use tonic::{async_trait, Request, Response, Result, Status};
+use tracing::{instrument, warn};
+
+pub struct GRPCPathInfoServiceWrapper<PS: PathInfoService, NS: NARCalculationService> {
+    path_info_service: PS,
+    nar_calculation_service: NS,
+}
+
+impl<PS: PathInfoService, NS: NARCalculationService> GRPCPathInfoServiceWrapper<PS, NS> {
+    pub fn new(path_info_service: PS, nar_calculation_service: NS) -> Self {
+        Self {
+            path_info_service,
+            nar_calculation_service,
+        }
+    }
+}
+
+#[async_trait]
+impl<
+        PS: PathInfoService + Send + Sync + 'static,
+        NS: NARCalculationService + Send + Sync + 'static,
+    > proto::path_info_service_server::PathInfoService for GRPCPathInfoServiceWrapper<PS, NS>
+{
+    #[instrument(skip(self))]
+    async fn get(
+        &self,
+        request: Request<proto::GetPathInfoRequest>,
+    ) -> Result<Response<proto::PathInfo>> {
+        match request.into_inner().by_what {
+            None => Err(Status::unimplemented("by_what needs to be specified")),
+            Some(by_what) => match self.path_info_service.get(by_what) {
+                Ok(None) => Err(Status::not_found("PathInfo not found")),
+                Ok(Some(path_info)) => Ok(Response::new(path_info)),
+                Err(e) => {
+                    warn!("failed to retrieve PathInfo: {}", e);
+                    Err(e.into())
+                }
+            },
+        }
+    }
+
+    #[instrument(skip(self))]
+    async fn put(&self, request: Request<proto::PathInfo>) -> Result<Response<proto::PathInfo>> {
+        let path_info = request.into_inner();
+
+        // Store the PathInfo in the client. Clients MUST validate the data
+        // they receive, so we don't validate additionally here.
+        match self.path_info_service.put(path_info) {
+            Ok(path_info_new) => Ok(Response::new(path_info_new)),
+            Err(e) => {
+                warn!("failed to insert PathInfo: {}", e);
+                Err(e.into())
+            }
+        }
+    }
+
+    #[instrument(skip(self))]
+    async fn calculate_nar(
+        &self,
+        request: Request<proto::Node>,
+    ) -> Result<Response<proto::CalculateNarResponse>> {
+        match request.into_inner().node {
+            None => Err(Status::invalid_argument("no root node sent")),
+            Some(root_node) => match self.nar_calculation_service.calculate_nar(root_node) {
+                Ok(resp) => Ok(Response::new(resp)),
+                Err(e) => Err(e.into()),
+            },
+        }
+    }
+}
+
+impl From<RenderError> for tonic::Status {
+    fn from(value: RenderError) -> Self {
+        match value {
+            RenderError::BlobNotFound(_, _) => Self::not_found(value.to_string()),
+            RenderError::DirectoryNotFound(_, _) => Self::not_found(value.to_string()),
+            RenderError::NARWriterError(_) => Self::internal(value.to_string()),
+            RenderError::StoreError(_) => Self::internal(value.to_string()),
+            RenderError::UnexpectedBlobMeta(_, _, _, _) => Self::internal(value.to_string()),
+        }
+    }
+}
diff --git a/tvix/store/src/proto/mod.rs b/tvix/store/src/proto/mod.rs
index 84eeda3c66..ae5054df54 100644
--- a/tvix/store/src/proto/mod.rs
+++ b/tvix/store/src/proto/mod.rs
@@ -9,9 +9,11 @@ use nix_compat::store_path::{ParseStorePathError, StorePath};
 
 mod grpc_blobservice_wrapper;
 mod grpc_directoryservice_wrapper;
+mod grpc_pathinfoservice_wrapper;
 
 pub use grpc_blobservice_wrapper::GRPCBlobServiceWrapper;
 pub use grpc_directoryservice_wrapper::GRPCDirectoryServiceWrapper;
+pub use grpc_pathinfoservice_wrapper::GRPCPathInfoServiceWrapper;
 
 tonic::include_proto!("tvix.store.v1");