1use std::fmt::{Debug, Formatter};
2use std::sync::Arc;
3
4use async_trait::async_trait;
5
6use token_source::{TokenSource, TokenSourceProvider};
7
8use crate::credentials::CredentialsFile;
9use crate::error::Error;
10use crate::project::{
11 create_token_source_from_credentials, create_token_source_from_project, project, Config, Project,
12};
13use crate::token_source::TokenSource as InternalTokenSource;
14
15pub const TOKEN_URL: &str = "https://oauth2.googleapis.com/token";
16
17#[derive(Debug, Clone)]
18pub struct Token {
19 pub access_token: String,
20 pub token_type: String,
21 pub expiry: Option<time::OffsetDateTime>,
22}
23
24impl Token {
25 pub fn value(&self) -> String {
26 format!("Bearer {}", self.access_token)
27 }
28
29 pub fn valid(&self) -> bool {
30 !self.access_token.is_empty() && !self.expired()
31 }
32
33 fn expired(&self) -> bool {
34 match self.expiry {
35 None => false,
36 Some(s) => {
37 let now = time::OffsetDateTime::now_utc();
38 let exp = s + time::Duration::seconds(-10);
39 now > exp
40 }
41 }
42 }
43}
44
45pub struct DefaultTokenSourceProvider {
46 ts: Arc<DefaultTokenSource>,
47 pub project_id: Option<String>,
48 pub source_credentials: Option<Box<CredentialsFile>>,
49}
50
51impl Debug for DefaultTokenSourceProvider {
52 fn fmt(&self, _: &mut Formatter<'_>) -> std::fmt::Result {
53 Ok(())
54 }
55}
56
57impl DefaultTokenSourceProvider {
58 pub async fn new(config: Config<'_>) -> Result<Self, Error> {
59 let project = project().await?;
60 let internal_token_source = create_token_source_from_project(&project, config).await?;
61
62 let (project_id, source_credentials) = match project {
63 Project::FromMetadataServer(info) => (info.project_id, None),
64 Project::FromFile(cred) => {
65 (cred.project_id.as_ref().or(cred.quota_project_id.as_ref()).cloned(), Some(cred))
66 }
67 };
68 Ok(Self {
69 ts: Arc::new(DefaultTokenSource {
70 inner: internal_token_source.into(),
71 }),
72 project_id,
73 source_credentials,
74 })
75 }
76
77 pub async fn new_with_credentials(config: Config<'_>, credentials: Box<CredentialsFile>) -> Result<Self, Error> {
79 let inner = create_token_source_from_credentials(&credentials, &config)
80 .await?
81 .into();
82 let project_id = credentials.project_id.clone();
83 let ts = Arc::new(DefaultTokenSource { inner });
84 let source_credentials = Some(credentials);
85 Ok(Self {
86 ts,
87 project_id,
88 source_credentials,
89 })
90 }
91}
92
93impl TokenSourceProvider for DefaultTokenSourceProvider {
94 fn token_source(&self) -> Arc<dyn TokenSource> {
95 self.ts.clone()
96 }
97}
98
99#[derive(Debug, Clone)]
100pub struct DefaultTokenSource {
101 inner: Arc<dyn InternalTokenSource>,
102}
103
104#[async_trait]
105impl TokenSource for DefaultTokenSource {
106 async fn token(&self) -> Result<String, Box<dyn std::error::Error + Send + Sync>> {
107 let token = self.inner.token().await?;
108 Ok(format!("Bearer {0}", token.access_token))
109 }
110}