bitwarden_uniffi/platform/
server_communication_config.rs

1use std::sync::Arc;
2
3use bitwarden_server_communication_config::{
4    AcquiredCookie, ServerCommunicationConfig, ServerCommunicationConfigPlatformApi,
5};
6
7use crate::error::Result;
8
9type UniffiRepository = UniffiRepositoryBridge<Arc<dyn ServerCommunicationConfigRepository>>;
10type UniffiPlatformApi = UniffiPlatformApiBridge<Arc<dyn ServerCommunicationConfigPlatformApi>>;
11
12/// UniFFI wrapper for ServerCommunicationConfigClient
13#[derive(uniffi::Object)]
14pub struct ServerCommunicationConfigClient {
15    client: bitwarden_server_communication_config::ServerCommunicationConfigClient<
16        UniffiRepository,
17        UniffiPlatformApi,
18    >,
19}
20
21impl ServerCommunicationConfigClient {
22    /// Creates a new server communication configuration client
23    pub fn new(
24        repository: Arc<dyn ServerCommunicationConfigRepository>,
25        platform_api: Arc<dyn ServerCommunicationConfigPlatformApi>,
26    ) -> Arc<Self> {
27        Arc::new(Self {
28            client: bitwarden_server_communication_config::ServerCommunicationConfigClient::new(
29                UniffiRepositoryBridge(repository),
30                UniffiPlatformApiBridge(platform_api),
31            ),
32        })
33    }
34}
35
36#[uniffi::export]
37impl ServerCommunicationConfigClient {
38    /// Retrieves the server communication configuration for a hostname
39    pub async fn get_config(&self, hostname: String) -> Result<ServerCommunicationConfig> {
40        self.client.get_config(hostname).await
41    }
42
43    /// Determines if cookie bootstrapping is needed for this hostname
44    pub async fn needs_bootstrap(&self, hostname: String) -> bool {
45        self.client.needs_bootstrap(hostname).await
46    }
47
48    /// Returns all cookies that should be included in requests to this server
49    pub async fn cookies(&self, hostname: String) -> Vec<AcquiredCookie> {
50        self.client
51            .cookies(hostname)
52            .await
53            .into_iter()
54            .map(|(name, value)| AcquiredCookie { name, value })
55            .collect()
56    }
57
58    /// Sets the server communication configuration for a hostname
59    ///
60    /// This method saves the provided communication configuration to the repository.
61    /// Typically called when receiving the `/api/config` response from the server.
62    pub async fn set_communication_type(
63        &self,
64        hostname: String,
65        config: ServerCommunicationConfig,
66    ) -> Result<()> {
67        self.client.set_communication_type(hostname, config).await?;
68        Ok(())
69    }
70
71    /// Acquires a cookie from the platform and saves it to the repository
72    pub async fn acquire_cookie(&self, hostname: String) -> Result<()> {
73        self.client.acquire_cookie(&hostname).await?;
74        Ok(())
75    }
76}
77
78/// UniFFI repository trait for server communication configuration
79#[uniffi::export(with_foreign)]
80#[async_trait::async_trait]
81pub trait ServerCommunicationConfigRepository: Send + Sync {
82    /// Get configuration for a hostname
83    async fn get(&self, hostname: String) -> Result<Option<ServerCommunicationConfig>>;
84
85    /// Save configuration for a hostname
86    async fn save(&self, hostname: String, config: ServerCommunicationConfig) -> Result<()>;
87}
88
89/// Bridge from UniFFI trait to internal repository trait
90pub struct UniffiRepositoryBridge<T>(pub T);
91
92impl<T: ?Sized> UniffiRepositoryBridge<Arc<T>> {
93    #[allow(dead_code)]
94    pub fn new(repo: Arc<T>) -> Arc<Self> {
95        Arc::new(UniffiRepositoryBridge(repo))
96    }
97}
98
99impl<T: std::fmt::Debug> std::fmt::Debug for UniffiRepositoryBridge<T> {
100    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
101        self.0.fmt(f)
102    }
103}
104
105impl<'a> bitwarden_server_communication_config::ServerCommunicationConfigRepository
106    for UniffiRepositoryBridge<Arc<dyn ServerCommunicationConfigRepository + 'a>>
107{
108    type GetError = crate::error::Error;
109    type SaveError = crate::error::Error;
110
111    async fn get(
112        &self,
113        hostname: String,
114    ) -> std::result::Result<Option<ServerCommunicationConfig>, Self::GetError> {
115        self.0.get(hostname).await
116    }
117
118    async fn save(
119        &self,
120        hostname: String,
121        config: ServerCommunicationConfig,
122    ) -> std::result::Result<(), Self::SaveError> {
123        self.0.save(hostname, config).await
124    }
125}
126
127/// Bridge for platform API trait
128pub struct UniffiPlatformApiBridge<T>(pub T);
129
130impl<T: std::fmt::Debug> std::fmt::Debug for UniffiPlatformApiBridge<T> {
131    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132        self.0.fmt(f)
133    }
134}
135
136#[async_trait::async_trait]
137impl<'a> ServerCommunicationConfigPlatformApi
138    for UniffiPlatformApiBridge<Arc<dyn ServerCommunicationConfigPlatformApi + 'a>>
139{
140    async fn acquire_cookies(&self, hostname: String) -> Option<Vec<AcquiredCookie>> {
141        self.0.acquire_cookies(hostname).await
142    }
143}