1use crate::{
4 custom_serde::{duration_second, space_separated_scopes},
5 ModelResult,
6};
7
8use std::{
9 collections::{HashMap, HashSet},
10 fs,
11 io::{Read, Write},
12 path::Path,
13};
14
15use chrono::{DateTime, Duration, TimeDelta, Utc};
16use serde::{Deserialize, Serialize};
17
18#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
22pub struct Token {
23 pub access_token: String,
25 #[serde(with = "duration_second")]
27 pub expires_in: Duration,
28 pub expires_at: Option<DateTime<Utc>>,
31 pub refresh_token: Option<String>,
34 #[serde(default, with = "space_separated_scopes", rename = "scope")]
42 pub scopes: HashSet<String>,
43}
44
45impl Default for Token {
46 fn default() -> Self {
47 Self {
48 access_token: String::new(),
49 expires_in: Duration::try_seconds(0).unwrap(),
50 expires_at: Some(Utc::now()),
51 refresh_token: None,
52 scopes: HashSet::new(),
53 }
54 }
55}
56
57impl Token {
58 pub fn from_cache<T: AsRef<Path>>(path: T) -> ModelResult<Self> {
60 let mut file = fs::File::open(path)?;
61 let mut tok_str = String::new();
62 file.read_to_string(&mut tok_str)?;
63 let tok = serde_json::from_str(&tok_str)?;
64
65 Ok(tok)
66 }
67
68 pub fn write_cache<T: AsRef<Path>>(&self, path: T) -> ModelResult<()> {
70 let token_info = serde_json::to_string(&self)?;
71
72 let mut file = fs::OpenOptions::new().write(true).create(true).open(path)?;
73 file.set_len(0)?;
74 file.write_all(token_info.as_bytes())?;
75
76 Ok(())
77 }
78
79 #[must_use]
82 pub fn is_expired(&self) -> bool {
83 self.expires_at.map_or(true, |expiration| {
84 Utc::now() + TimeDelta::try_seconds(10).unwrap() >= expiration
85 })
86 }
87
88 #[must_use]
90 pub fn auth_headers(&self) -> HashMap<String, String> {
91 let auth = "authorization".to_owned();
92 let value = format!("Bearer {}", self.access_token);
93
94 let mut headers = HashMap::new();
95 headers.insert(auth, value);
96 headers
97 }
98}
99
100#[cfg(test)]
101mod test {
102 use std::collections::HashSet;
103
104 use crate::Token;
105 use serde_json::json;
106
107 #[test]
108 fn test_bearer_auth() {
109 let tok = Token {
110 access_token: "access_token".to_string(),
111 ..Default::default()
112 };
113
114 let headers = tok.auth_headers();
115 assert_eq!(headers.len(), 1);
116 assert_eq!(
117 headers.get("authorization"),
118 Some(&"Bearer access_token".to_owned())
119 );
120 }
121
122 #[test]
123 fn test_token_deserialize() {
124 let mut scopes = HashSet::<String>::new();
125 scopes.insert("user-read-email".to_owned());
126 let tok = Token {
127 access_token: "access_token".to_string(),
128 scopes,
129 ..Default::default()
130 };
131 let value = json!(tok);
132 let token = serde_json::from_value::<Token>(value);
133 assert!(token.is_ok());
134 assert_eq!(token.unwrap().scopes, tok.scopes);
135 }
136}