1use std::sync::Arc;
2
3use anyhow::{Result, anyhow};
4pub use cloud_api_types::*;
5use futures::AsyncReadExt as _;
6use http_client::{AsyncBody, HttpClientWithUrl, Method, Request};
7use parking_lot::RwLock;
8
9struct Credentials {
10 user_id: u32,
11 access_token: String,
12}
13
14pub struct CloudApiClient {
15 credentials: RwLock<Option<Credentials>>,
16 http_client: Arc<HttpClientWithUrl>,
17}
18
19impl CloudApiClient {
20 pub fn new(http_client: Arc<HttpClientWithUrl>) -> Self {
21 Self {
22 credentials: RwLock::new(None),
23 http_client,
24 }
25 }
26
27 pub fn set_credentials(&self, user_id: u32, access_token: String) {
28 *self.credentials.write() = Some(Credentials {
29 user_id,
30 access_token,
31 });
32 }
33
34 fn authorization_header(&self) -> Result<String> {
35 let guard = self.credentials.read();
36 let credentials = guard
37 .as_ref()
38 .ok_or_else(|| anyhow!("No credentials provided"))?;
39
40 Ok(format!(
41 "{} {}",
42 credentials.user_id, credentials.access_token
43 ))
44 }
45
46 pub async fn get_authenticated_user(&self) -> Result<AuthenticatedUser> {
47 let request = Request::builder()
48 .method(Method::GET)
49 .uri(
50 self.http_client
51 .build_zed_cloud_url("/client/users/me", &[])?
52 .as_ref(),
53 )
54 .header("Content-Type", "application/json")
55 .header("Authorization", self.authorization_header()?)
56 .body(AsyncBody::default())?;
57
58 let mut response = self.http_client.send(request).await?;
59
60 if !response.status().is_success() {
61 let mut body = String::new();
62 response.body_mut().read_to_string(&mut body).await?;
63
64 anyhow::bail!(
65 "Failed to get authenticated user.\nStatus: {:?}\nBody: {body}",
66 response.status()
67 )
68 }
69
70 let mut body = String::new();
71 response.body_mut().read_to_string(&mut body).await?;
72 let response: GetAuthenticatedUserResponse = serde_json::from_str(&body)?;
73
74 Ok(response.user)
75 }
76}