reqwest_oauth1/
token_reader.rs1use std::{collections::HashMap, future::Future};
2
3use async_trait::async_trait;
4use reqwest::Response;
5use serde::Deserialize;
6
7use crate::{Error, Result, TokenReaderError, TokenReaderResult};
8
9const OAUTH_TOKEN_KEY: &str = "oauth_token";
10
11const OAUTH_TOKEN_SECRET_KEY: &str = "oauth_token_secret";
12
13#[derive(Deserialize, Debug)]
15pub struct TokenResponse {
16 pub oauth_token: String,
18 pub oauth_token_secret: String,
20 #[serde(flatten)]
22 pub remain: HashMap<String, String>,
23}
24
25#[async_trait(?Send)]
28pub trait TokenReader: private::Sealed {
29 async fn parse_oauth_token(self) -> Result<TokenResponse>;
30}
31
32#[async_trait(?Send)]
33impl TokenReader for Response {
34 async fn parse_oauth_token(self) -> Result<TokenResponse> {
35 let text = self.text().await?;
36 Ok(read_oauth_token(text)?)
39 }
40}
41
42#[async_trait(?Send)]
45pub trait TokenReaderFuture: private::SealedWrapper {
46 async fn parse_oauth_token(self) -> Result<TokenResponse>;
47}
48
49#[async_trait(?Send)]
62impl<T, E> TokenReaderFuture for T
63where
64 T: Future<Output = std::result::Result<Response, E>>,
65 E: Into<Error> + 'static,
66{
67 async fn parse_oauth_token(self) -> Result<TokenResponse> {
68 match self.await {
69 Ok(resp) => Ok(resp.parse_oauth_token().await?),
70 Err(err) => Err(err.into()),
71 }
72 }
73}
74
75fn read_oauth_token(text: String) -> TokenReaderResult<TokenResponse> {
76 let mut destructured = text
77 .split("&")
78 .map(|e| e.splitn(2, "="))
79 .map(|v| {
80 let mut iter = v.into_iter();
81 (
82 iter.next().unwrap_or_default().to_string(),
83 iter.next().unwrap_or_default().to_string(),
84 )
85 })
86 .collect::<HashMap<String, String>>();
87 let oauth_token = destructured.remove(OAUTH_TOKEN_KEY);
88 let oauth_token_secret = destructured.remove(OAUTH_TOKEN_SECRET_KEY);
89 match (oauth_token, oauth_token_secret) {
90 (Some(t), Some(s)) => Ok(TokenResponse {
91 oauth_token: t,
92 oauth_token_secret: s,
93 remain: destructured,
94 }),
95 (None, _) => Err(TokenReaderError::TokenKeyNotFound(OAUTH_TOKEN_KEY, text)),
96 (_, _) => Err(TokenReaderError::TokenKeyNotFound(
97 OAUTH_TOKEN_SECRET_KEY,
98 text,
99 )),
100 }
101}
102
103mod private {
104 use std::future::Future;
105
106 use reqwest::Response;
107
108 use crate::Error;
109
110 pub trait Sealed {}
111 impl Sealed for Response {}
112 pub trait SealedWrapper {}
113 impl<T, E> SealedWrapper for T
115 where
116 T: Future<Output = Result<Response, E>>,
117 E: Into<Error>,
118 {
119 }
120}
121
122#[cfg(test)]
123mod test {
124
125 use super::*;
126
127 #[test]
128 fn parse_response_typical() {
129 let resp_str_sample = "oauth_token=Z6eEdO8MOmk394WozF5oKyuAv855l4Mlqo7hhlSLik&oauth_token_secret=Kd75W4OQfb2oJTV0vzGzeXftVAwgMnEK9MumzYcM&oauth_callback_confirmed=true";
130 for parsed in &[
131 read_oauth_token(resp_str_sample.to_string()).unwrap(),
132 serde_urlencoded::from_str::<TokenResponse>(resp_str_sample).unwrap(),
133 ] {
134 assert_eq!(
135 parsed.oauth_token,
136 "Z6eEdO8MOmk394WozF5oKyuAv855l4Mlqo7hhlSLik"
137 );
138 assert_eq!(
139 parsed.oauth_token_secret,
140 "Kd75W4OQfb2oJTV0vzGzeXftVAwgMnEK9MumzYcM"
141 );
142 assert_eq!(parsed.remain.len(), 1);
143 let oauth_callback_confirmed = parsed.remain.get("oauth_callback_confirmed").unwrap();
144 assert_eq!(oauth_callback_confirmed, "true");
145 }
146 }
147
148 #[test]
149 fn parse_response_edge() {
150 let resp_str_sample = "oauth_token==&oauth_token_secret=&keyonly=&keyonly2&=&&";
151 for parsed in &[
152 read_oauth_token(resp_str_sample.to_string()).unwrap(),
153 serde_urlencoded::from_str::<TokenResponse>(resp_str_sample).unwrap(),
154 ] {
155 assert_eq!(parsed.oauth_token, "=");
156 assert_eq!(parsed.oauth_token_secret, "");
157 assert_eq!(parsed.remain.len(), 3);
158 let keyonly = parsed.remain.get("keyonly").unwrap();
159 assert_eq!(keyonly, "");
160 let keyonly2 = parsed.remain.get("keyonly2").unwrap();
161 assert_eq!(keyonly2, "");
162 let empty = parsed.remain.get("").unwrap();
163 assert_eq!(empty, "");
164 }
165 }
166
167 #[test]
168 fn parse_minimal() {
169 let resp_str_sample = "oauth_token&oauth_token_secret";
170 let parsed = read_oauth_token(resp_str_sample.to_string()).unwrap();
171 assert_eq!(parsed.oauth_token, "");
172 assert_eq!(parsed.oauth_token_secret, "");
173 assert_eq!(parsed.remain.len(), 0);
174 }
175
176 #[test]
177 fn parse_token_notfound() {
178 let resp_str_sample = "oauth_token_secret=";
179 let parsed = read_oauth_token(resp_str_sample.to_string());
180 assert!(parsed.is_err());
181 if let Err(TokenReaderError::TokenKeyNotFound(key, resp_str)) = parsed {
182 assert_eq!(key, OAUTH_TOKEN_KEY);
183 assert_eq!(resp_str, resp_str_sample)
184 } else {
185 assert!(false)
186 }
187 }
188
189 #[test]
190 fn parse_token_secret_notfound() {
191 let resp_str_sample = "oauth_token=";
192 let parsed = read_oauth_token(resp_str_sample.to_string());
193 assert!(parsed.is_err());
194 if let Err(TokenReaderError::TokenKeyNotFound(key, resp_str)) = parsed {
195 assert_eq!(key, OAUTH_TOKEN_SECRET_KEY);
196 assert_eq!(resp_str, resp_str_sample)
197 } else {
198 assert!(false)
199 }
200 }
201}