1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
use serde::{Deserialize, Serialize};
use oauth2::helpers;
use oauth2::{basic::BasicTokenType, Client, ExtraTokenFields, TokenType};
use crate::AccessToken;
use std::time::Duration;
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct TwitchTokenResponse<EF, TT>
where
TT: TokenType,
EF: ExtraTokenFields, {
pub access_token: AccessToken,
#[serde(bound = "TT: TokenType")]
#[serde(deserialize_with = "helpers::deserialize_untagged_enum_case_insensitive")]
pub token_type: TT,
#[serde(skip_serializing_if = "Option::is_none")]
pub expires_in: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub refresh_token: Option<oauth2::RefreshToken>,
#[serde(rename = "scope")]
#[serde(default)]
pub scopes: Option<Vec<oauth2::Scope>>,
#[serde(bound = "EF: ExtraTokenFields")]
#[serde(flatten)]
pub extra_fields: EF,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct TwitchTokenErrorResponse {
#[serde(with = "status_code")]
pub status: http::StatusCode,
pub message: String,
}
#[doc(hidden)]
pub mod status_code {
use http::StatusCode;
use serde::{
de::{Deserialize, Error, Unexpected},
Deserializer, Serializer,
};
pub fn deserialize<'de, D>(de: D) -> Result<StatusCode, D::Error>
where D: Deserializer<'de> {
let code: u16 = Deserialize::deserialize(de)?;
match StatusCode::from_u16(code) {
Ok(code) => Ok(code),
Err(_) => Err(Error::invalid_value(
Unexpected::Unsigned(code as u64),
&"a value between 100 and 600",
)),
}
}
pub fn serialize<S>(status: &StatusCode, ser: S) -> Result<S::Ok, S::Error>
where S: Serializer {
ser.serialize_u16(status.as_u16())
}
}
impl std::fmt::Display for TwitchTokenErrorResponse {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} {}", self.status.as_u16(), self.message)
}
}
impl<EF, TT> oauth2::TokenResponse<TT> for TwitchTokenResponse<EF, TT>
where
TT: TokenType,
EF: ExtraTokenFields,
{
fn access_token(&self) -> &AccessToken { &self.access_token }
fn token_type(&self) -> &TT { &self.token_type }
fn expires_in(&self) -> Option<Duration> { self.expires_in.map(Duration::from_secs) }
fn refresh_token(&self) -> Option<&oauth2::RefreshToken> { self.refresh_token.as_ref() }
fn scopes(&self) -> Option<&Vec<oauth2::Scope>> { self.scopes.as_ref() }
}
impl oauth2::ErrorResponse for TwitchTokenErrorResponse {}
pub type TwitchClient = Client<
TwitchTokenErrorResponse,
TwitchTokenResponse<oauth2::EmptyExtraTokenFields, BasicTokenType>,
BasicTokenType,
>;