gimpey_db_gateway/clients/
account_client.rs

1use rustls::crypto::ring::default_provider;
2use rustls::{ClientConfig, RootCertStore};
3use rustls_native_certs::load_native_certs;
4use std::str::FromStr;
5use tonic::{metadata::MetadataValue, Request, Status};
6use tonic_rustls::channel::Channel as RustlsChannel;
7
8use crate::generated::account::{
9    account_service_client::AccountServiceClient, CreateAccountRequest, CreateAccountResponse,
10    GetAccountRequest, GetAccountResponse, GetAccountsRequest, GetAccountsResponse,
11    IncrementNonceRequest, UpdateAccountRequest, UpdateAccountResponse,
12};
13
14#[derive(Debug, Clone)]
15pub struct AccountClient {
16    inner: AccountServiceClient<RustlsChannel>,
17    api_key: String,
18}
19
20impl AccountClient {
21    pub async fn connect(
22        domain: &str,
23        api_key: String,
24        is_secure: bool,
25    ) -> Result<Self, Box<dyn std::error::Error>> {
26        let channel = if is_secure {
27            let provider = default_provider();
28            let _ = provider.install_default();
29
30            let mut roots = RootCertStore::empty();
31            for cert in load_native_certs().expect("Could not load platform certs") {
32                roots.add(cert).unwrap();
33            }
34
35            let config = ClientConfig::builder()
36                .with_root_certificates(roots)
37                .with_no_client_auth();
38
39            let channel = RustlsChannel::from_shared(format!("https://{domain}"))?
40                .tls_config(config)?
41                .connect()
42                .await?;
43
44            channel
45        } else {
46            RustlsChannel::from_shared(format!("http://{domain}"))?
47                .connect()
48                .await?
49        };
50
51        Ok(Self {
52            inner: AccountServiceClient::new(channel),
53            api_key,
54        })
55    }
56
57    fn with_auth<T>(&self, message: T) -> Request<T> {
58        let mut req = Request::new(message);
59        let meta = MetadataValue::from_str(&self.api_key).unwrap();
60        req.metadata_mut().insert("x-api-key", meta);
61        req
62    }
63
64    pub async fn create_account(
65        &mut self,
66        email: String,
67        username: String,
68        password: String,
69        beta_code: Option<String>,
70        referral_code: Option<String>,
71    ) -> Result<CreateAccountResponse, Status> {
72        let request = CreateAccountRequest {
73            email,
74            username,
75            password,
76            beta_code,
77            referral_code,
78        };
79
80        let response = self.inner.create_account(self.with_auth(request)).await?;
81
82        Ok(response.into_inner())
83    }
84
85    /// Implements the `get_account` method at `src/services/account_service.rs`.
86    pub async fn get_account(&mut self, identifier: String) -> Result<GetAccountResponse, Status> {
87        let request = GetAccountRequest { identifier };
88
89        let response = self.inner.get_account(self.with_auth(request)).await?;
90        Ok(response.into_inner())
91    }
92
93    pub async fn update_account(
94        &mut self,
95        id: String,
96        email: String,
97        username: String,
98        password: String,
99    ) -> Result<UpdateAccountResponse, Status> {
100        let request = UpdateAccountRequest {
101            id,
102            email,
103            username,
104            password,
105        };
106
107        let response = self.inner.update_account(self.with_auth(request)).await?;
108        Ok(response.into_inner())
109    }
110
111    pub async fn get_accounts(
112        &mut self,
113        limit: Option<u32>,
114        cursor: Option<String>,
115        sort_by: Option<i32>,
116        order: Option<String>,
117        search: Option<String>,
118    ) -> Result<GetAccountsResponse, Status> {
119        let request = GetAccountsRequest {
120            limit,
121            cursor,
122            sort_by,
123            order,
124            search,
125        };
126        let response = self.inner.get_accounts(self.with_auth(request)).await?;
127        Ok(response.into_inner())
128    }
129
130    pub async fn increment_avatar_nonce(&mut self, id: String) -> Result<i32, Status> {
131        let request = IncrementNonceRequest { id };
132        let response = self
133            .inner
134            .increment_avatar_nonce(self.with_auth(request))
135            .await?;
136        let nonce = response.into_inner().nonce;
137        Ok(nonce as i32)
138    }
139
140    pub async fn increment_banner_nonce(&mut self, id: String) -> Result<i32, Status> {
141        let request = IncrementNonceRequest { id };
142        let response = self
143            .inner
144            .increment_banner_nonce(self.with_auth(request))
145            .await?;
146        let nonce = response.into_inner().nonce;
147        Ok(nonce as i32)
148    }
149
150    pub async fn increment_totp_nonce(&mut self, id: String) -> Result<i32, Status> {
151        let request = IncrementNonceRequest { id };
152        let response = self
153            .inner
154            .increment_totp_nonce(self.with_auth(request))
155            .await?;
156        let nonce = response.into_inner().nonce;
157        Ok(nonce as i32)
158    }
159}