1use serde_derive::{Deserialize, Serialize};
4
5use crate::{AccessToken, RequestParseError};
6use std::time::Duration;
7#[derive(Clone, Debug, Deserialize, Serialize)]
14pub struct TwitchTokenResponse {
15 pub access_token: AccessToken,
17 #[serde(skip_serializing_if = "Option::is_none")]
19 pub expires_in: Option<u64>,
20 #[serde(skip_serializing_if = "Option::is_none")]
22 pub refresh_token: Option<crate::RefreshToken>,
23 #[serde(rename = "scope", deserialize_with = "scope::deserialize")]
25 #[serde(default)]
26 pub scopes: Option<Vec<crate::Scope>>,
27}
28
29impl TwitchTokenResponse {
30 pub fn from_response<B: AsRef<[u8]>>(
32 response: &http::Response<B>,
33 ) -> Result<TwitchTokenResponse, RequestParseError> {
34 crate::parse_response(response)
35 }
36
37 pub fn access_token(&self) -> &crate::AccessTokenRef { &self.access_token }
39
40 pub fn expires_in(&self) -> Option<Duration> { self.expires_in.map(Duration::from_secs) }
42
43 pub fn refresh_token(&self) -> Option<&crate::RefreshTokenRef> { self.refresh_token.as_deref() }
45
46 pub fn scopes(&self) -> Option<&[crate::Scope]> { self.scopes.as_deref() }
48}
49
50#[derive(Clone, Debug, Deserialize, Serialize, thiserror::Error)]
52pub struct TwitchTokenErrorResponse {
53 #[serde(with = "status_code")]
55 pub status: http::StatusCode,
56 pub message: String,
58 pub error: Option<String>,
60}
61
62impl std::fmt::Display for TwitchTokenErrorResponse {
63 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64 write!(
65 f,
66 "{error} - {message}",
67 error = self
68 .error
69 .as_deref()
70 .unwrap_or_else(|| self.status.canonical_reason().unwrap_or("Error")),
71 message = self.message
72 )
73 }
74}
75#[derive(Clone, Debug, Deserialize, Serialize)]
77pub struct DeviceCodeResponse {
78 pub device_code: String,
80 pub expires_in: u64,
82 pub interval: u64,
84 pub user_code: String,
86 pub verification_uri: String,
88}
89
90#[doc(hidden)]
91pub mod status_code {
92 use http::StatusCode;
93 use serde::{
94 de::{Deserialize, Error, Unexpected},
95 Deserializer, Serializer,
96 };
97
98 pub fn deserialize<'de, D>(de: D) -> Result<StatusCode, D::Error>
99 where D: Deserializer<'de> {
100 let code: u16 = Deserialize::deserialize(de)?;
101 match StatusCode::from_u16(code) {
102 Ok(code) => Ok(code),
103 Err(_) => Err(Error::invalid_value(
104 Unexpected::Unsigned(code as u64),
105 &"a value between 100 and 600",
106 )),
107 }
108 }
109
110 pub fn serialize<S>(status: &StatusCode, ser: S) -> Result<S::Ok, S::Error>
111 where S: Serializer {
112 ser.serialize_u16(status.as_u16())
113 }
114}
115
116#[doc(hidden)]
117pub mod scope {
118 use serde::{de::Deserialize, Deserializer};
119
120 pub fn deserialize<'de, D>(de: D) -> Result<Option<Vec<crate::Scope>>, D::Error>
121 where D: Deserializer<'de> {
122 let scopes: Option<Vec<crate::Scope>> = Deserialize::deserialize(de)?;
123 if let Some(scopes) = scopes {
124 match scopes {
125 scopes if scopes.is_empty() || scopes.len() > 1 => Ok(Some(scopes)),
126 scopes if scopes.len() == 1 && scopes.first().unwrap().as_str() == "" => Ok(None),
127 _ => Ok(Some(scopes)),
128 }
129 } else {
130 Ok(None)
131 }
132 }
133}