Skip to main content

finam_sdk/
auth.rs

1use std::{sync::{Arc, Mutex, RwLock}, time::Duration};
2
3use tonic::{metadata::{Ascii, MetadataValue}, service::Interceptor, transport::Channel, Request};
4
5use crate::proto::auth::{auth_service_client::AuthServiceClient, AuthRequest};
6
7pub const TOKEN_UPDATE_PERIOD: Duration = Duration::from_secs(14*60); //каждые 14 минут
8
9pub type Token = MetadataValue<Ascii>;
10
11#[derive(Debug, Clone)]
12pub struct TokenInterceptor {
13    token: Arc<Mutex<Token>>,
14}
15
16impl TokenInterceptor {
17    pub async fn with_duration(channel: Channel, secret: impl ToString, update_period: Duration) -> Result<Self, tonic::Status> {
18        let secret = secret.to_string();
19        let token = Arc::new(Mutex::new(get_token(channel.clone(), secret.clone()).await?));
20        log::info!("JWT received");
21        let weak = Arc::downgrade(&token);
22        tokio::spawn(async move {
23            tokio::time::sleep(update_period).await;
24            while let Some(token) = weak.upgrade() {
25                match get_token(channel.clone(), secret.clone()).await {
26                    Ok(updated) => {
27                        *token.lock().unwrap() = updated;
28                        drop(token);
29                        log::info!("JWT updated");
30                        tokio::time::sleep(update_period).await;
31                    },
32                    Err(e) => {
33                        log::error!("Cannot update token: {e}");
34                        tokio::time::sleep(crate::RETRY_DELAY).await;
35                    }
36                }
37            }
38            log::info!("token updating stopped");
39        });
40        Ok(Self { token })
41    }
42    pub async fn new(channel: Channel, secret: impl ToString) -> Result<Self, tonic::Status> {
43        Self::with_duration(channel, secret, TOKEN_UPDATE_PERIOD).await
44    }
45    pub fn get_token(&self) -> Arc<Mutex<Token>> {
46        self.token.clone()
47    }
48}
49
50impl Interceptor for TokenInterceptor {
51    fn call(&mut self, mut req: Request<()>) -> Result<Request<()>, tonic::Status> {
52        let token = self.token.lock().unwrap().clone();
53        req.metadata_mut().append(
54            "authorization",
55            token,
56        );
57        Ok(req)
58    }
59}
60
61async fn get_token(channel: Channel, secret: String) -> Result<MetadataValue<Ascii>, tonic::Status> {
62    let mut serv = AuthServiceClient::new(channel);
63    let crate::proto::auth::AuthResponse {token} = serv.auth(AuthRequest { secret }).await?.into_inner();
64    Ok(token.parse().unwrap())
65}