use super::NARCalculationService; use crate::proto; use tonic::transport::Channel; use tonic::Status; /// A NAR calculation service which asks a remote tvix-store for NAR calculation /// (via the gRPC PathInfoService). #[derive(Clone)] pub struct GRPCNARCalculationService { /// A handle into the active tokio runtime. Necessary to spawn tasks. tokio_handle: tokio::runtime::Handle, /// The internal reference to a gRPC client. /// Cloning it is cheap, and it internally handles concurrent requests. grpc_client: proto::path_info_service_client::PathInfoServiceClient, } impl GRPCNARCalculationService { /// construct a new [GRPCNARCalculationService], by passing a handle to the /// tokio runtime, and a gRPC client. pub fn new( tokio_handle: tokio::runtime::Handle, grpc_client: proto::path_info_service_client::PathInfoServiceClient, ) -> Self { Self { tokio_handle, grpc_client, } } /// construct a [GRPCNARCalculationService], from a [proto::path_info_service_client::PathInfoServiceClient]. /// panics if called outside the context of a tokio runtime. pub fn from_client( grpc_client: proto::path_info_service_client::PathInfoServiceClient, ) -> Self { Self { tokio_handle: tokio::runtime::Handle::current(), grpc_client, } } } impl NARCalculationService for GRPCNARCalculationService { fn calculate_nar( &self, root_node: &proto::node::Node, ) -> Result<(u64, [u8; 32]), super::RenderError> { // Get a new handle to the gRPC client, and copy the root node. let mut grpc_client = self.grpc_client.clone(); let root_node = root_node.clone(); let task: tokio::task::JoinHandle> = self.tokio_handle.spawn(async move { Ok(grpc_client .calculate_nar(proto::Node { node: Some(root_node), }) .await? .into_inner()) }); match self.tokio_handle.block_on(task).unwrap() { Ok(resp) => Ok((resp.nar_size, resp.nar_sha256.to_vec().try_into().unwrap())), Err(e) => Err(super::RenderError::StoreError(crate::Error::StorageError( e.to_string(), ))), } } }