1use reqwest::{
2 Response,
3 header::{self, HeaderMap, HeaderValue},
4};
5use serde::de::DeserializeOwned;
6
7use crate::{Error, ratelimit::Ratelimit};
8
9#[derive(Default)]
10pub struct Cookie(String);
11
12impl std::fmt::Display for Cookie {
13 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
14 write!(f, "{}", self.0)
15 }
16}
17
18impl From<&str> for Cookie {
19 fn from(value: &str) -> Self {
20 Self(format!(".ROBLOSECURITY={}", value))
21 }
22}
23
24#[derive(Default, Debug)]
25pub struct ClientRequestor {
26 pub(crate) client: reqwest::Client,
27 pub(crate) default_headers: HeaderMap,
28}
29
30#[derive(Default, Debug)]
31pub struct Client {
32 pub requestor: ClientRequestor,
33 pub(crate) ratelimit: Option<Ratelimit>,
34}
35
36impl Client {
37 pub fn from_cookie(cookie: Cookie) -> Self {
38 let client = reqwest::Client::new();
39 let mut default_headers = HeaderMap::new();
40
41 default_headers.insert(
42 header::USER_AGENT,
43 HeaderValue::from_str("Roblox/WinInet").unwrap(),
44 );
45
46 default_headers.insert(
47 header::COOKIE,
48 HeaderValue::from_str(&cookie.to_string()).unwrap(),
49 );
50
51 default_headers.append(
53 header::COOKIE,
54 HeaderValue::from_str("RBXEventTrackerV2=&browserid=2").unwrap(),
55 );
56
57 Client {
58 ratelimit: None,
59 requestor: ClientRequestor {
60 client,
61 default_headers,
62 },
63 }
64 }
65}
66
67impl ClientRequestor {
68 pub(crate) async fn parse_json<T: DeserializeOwned>(
69 &self,
70 response: Response,
71 ) -> Result<T, Error> {
72 Ok(response.json::<T>().await?)
73 }
74}