Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How do I pass state to the async interceptor function? #10

Open
Falmarri opened this issue Jan 15, 2024 · 1 comment
Open

How do I pass state to the async interceptor function? #10

Falmarri opened this issue Jan 15, 2024 · 1 comment

Comments

@Falmarri
Copy link

For example, I want to access a database. I can't figure out how to pass the database into the function. I've tried implementing the AsyncInterceptor, but ran into the fact that the associated type is a future, and I can't figure out how to name the future because of rust-lang/rust#63063

    type Future = impl futures_core::Future<Output=Result<Request<()>, Status>>;

    async fn call(&mut self, request: Request<()>) -> Result<Request<()>, Status> {`
        todo!()
    }
}

doesn't work. I've also tried type Future = Box<dyn futures_core::Future<Output=Result<Request<()>, Status>> + Unpin>; but ran into

   = note: expected signature `fn(&mut MyService, tonic::Request<_>) -> Box<(dyn futures_core::Future<Output = Result<tonic::Request<()>, tonic::Status>> + Unpin + 'static)>`
              found signature `fn(&mut MyService, tonic::Request<_>) -> impl futures_core::Future<Output = Result<tonic::Request<()>, tonic::Status>>`

@isaaguilar
Copy link

This worked for me:

#[derive(Clone)]
pub struct MyAuthInterceptor {
    pub db: Pool<Postgres>,
}

impl AsyncInterceptor for MyAuthInterceptor {
    type Future = Pin<Box<dyn Future<Output = Result<Request<()>, Status>> + Send + 'static>>;

    fn call(&mut self, request: Request<()>) -> Self::Future {
        let fut = self.authenticate(request);
        Box::pin(fut)
    }
}

impl MyAuthInterceptor {
    pub fn new(db: Pool<Postgres>) -> Self {
        Self { db }
    }

    pub fn authenticate(
        &self,
        request: Request<()>,
    ) -> impl Future<Output = Result<Request<()>, Status>> + Send + 'static {
        let db = self.db.clone(); // Clone the database pool
        let metadata = request.metadata().clone(); // Clone the request metadata
        async move {
            // Now we can use db inside the async block
            //  match sqlx::query("...").fetch_one(db).await {
            //     Ok(_) => {}
            //     Err(_) => {}
            // }
            Ok(request)
        }
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Setup stuff like `svc` and `address`
    let db = PgPoolOptions::new().max_connections(5).connect(&dsn).await?;
    let auth_service = MyAuthInterceptor::new(db);
    Server::builder()
        .layer(async_interceptor(auth_service)) // <----- Add the async interceptor here
        .add_service(svc)
        .serve(address)
        .await?;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants