hive_console_sdk/
supergraph_fetcher.rs

1use std::time::Duration;
2
3#[derive(Debug)]
4pub struct SupergraphFetcher {
5    client: reqwest::blocking::Client,
6    endpoint: String,
7    key: String,
8    user_agent: String,
9    etag: Option<String>,
10}
11
12impl SupergraphFetcher {
13    pub fn try_new(
14        endpoint: String,
15        key: String,
16        user_agent: String,
17        connect_timeout: Duration,
18        request_timeout: Duration,
19        accept_invalid_certs: bool,
20    ) -> Result<Self, String> {
21        let mut endpoint = endpoint;
22        if !endpoint.ends_with("/supergraph") {
23            if endpoint.ends_with("/") {
24                endpoint.push_str("supergraph")
25            } else {
26                endpoint.push_str("/supergraph")
27            }
28        }
29
30        let client = reqwest::blocking::Client::builder()
31            .danger_accept_invalid_certs(accept_invalid_certs)
32            .connect_timeout(connect_timeout)
33            .timeout(request_timeout)
34            .build()
35            .map_err(|e| e.to_string())?;
36
37        Ok(Self {
38            client,
39            endpoint,
40            key,
41            user_agent,
42            etag: None,
43        })
44    }
45
46    pub fn fetch_supergraph(&mut self) -> Result<Option<String>, String> {
47        let mut headers = reqwest::header::HeaderMap::new();
48
49        headers.insert(
50            reqwest::header::USER_AGENT,
51            reqwest::header::HeaderValue::from_str(&self.user_agent).unwrap(),
52        );
53        headers.insert("X-Hive-CDN-Key", self.key.parse().unwrap());
54
55        if let Some(checksum) = &self.etag {
56            headers.insert("If-None-Match", checksum.parse().unwrap());
57        }
58
59        let resp = self
60            .client
61            .get(self.endpoint.as_str())
62            .headers(headers)
63            .send()
64            .map_err(|e| e.to_string())?;
65
66        match resp.headers().get("etag") {
67            Some(checksum) => {
68                let etag = checksum.to_str().map_err(|e| e.to_string())?;
69                self.update_latest_etag(Some(etag.to_string()));
70            }
71            None => {
72                self.update_latest_etag(None);
73            }
74        }
75
76        if resp.status().as_u16() == 304 {
77            return Ok(None);
78        }
79
80        Ok(Some(resp.text().map_err(|e| e.to_string())?))
81    }
82
83    fn update_latest_etag(&mut self, etag: Option<String>) {
84        self.etag = etag;
85    }
86}