saluki_env/helpers/
tonic.rs

1//! Generic helper types/functions for building Tonic-based gRPC clients.
2
3use std::{path::Path, str::FromStr as _};
4
5use saluki_error::{generic_error, GenericError};
6use tonic::{
7    metadata::{Ascii, MetadataValue},
8    service::Interceptor,
9    Request, Status,
10};
11
12/// A Tonic request interceptor that adds a bearer token to the request metadata.
13#[derive(Clone)]
14pub struct BearerAuthInterceptor {
15    bearer_token: MetadataValue<Ascii>,
16}
17
18impl BearerAuthInterceptor {
19    /// Creates a new `BearerAuthInterceptor` from the bearer token in the given file.
20    ///
21    /// # Errors
22    ///
23    /// If the file path is invalid, if the file cannot be read, or if the bearer token is not valid ASCII, an error
24    /// variant will be returned.
25    pub async fn from_file<P>(file_path: P) -> Result<Self, GenericError>
26    where
27        P: AsRef<Path>,
28    {
29        let file_path = file_path.as_ref();
30        let raw_bearer_token = tokio::fs::read_to_string(file_path).await.map_err(|e| {
31            generic_error!(
32                "Failed to read bearer token from file '{}' ({}).",
33                file_path.display(),
34                e.kind()
35            )
36        })?;
37
38        let raw_bearer_token = format!("bearer {}", raw_bearer_token);
39        match MetadataValue::<Ascii>::from_str(&raw_bearer_token) {
40            Ok(bearer_token) => Ok(Self { bearer_token }),
41            Err(_) => Err(generic_error!(
42                "Found invalid characters for bearer token in file '{}'. Bearer token can only contain visible ASCII characters (0x20 - 0x7F).",
43                file_path.display(),
44            )),
45        }
46    }
47}
48
49impl Interceptor for BearerAuthInterceptor {
50    fn call(&mut self, mut request: Request<()>) -> Result<Request<()>, Status> {
51        request
52            .metadata_mut()
53            .insert("authorization", self.bearer_token.clone());
54        Ok(request)
55    }
56}