Skip to main content

lzc_sdk/
gateway.rs

1use std::fmt;
2use std::sync::Arc;
3
4use tonic::transport::Channel;
5
6use crate::proto::common::box_service_client::BoxServiceClient;
7use crate::proto::common::end_device_service_client::EndDeviceServiceClient;
8use crate::proto::common::file_handler_client::FileHandlerClient;
9use crate::proto::common::file_transfer_service_client::FileTransferServiceClient;
10use crate::proto::common::iscsi_service_client::IscsiServiceClient;
11use crate::proto::common::message_service_client::MessageServiceClient;
12use crate::proto::common::peripheral_device_service_client::PeripheralDeviceServiceClient;
13use crate::proto::common::permission_manager_client::PermissionManagerClient as RuntimePermissionManagerClient;
14use crate::proto::common::user_manager_client::UserManagerClient;
15use crate::proto::localdevice::contacts_manager_client::ContactsManagerClient;
16use crate::proto::localdevice::device_service_client::DeviceServiceClient;
17use crate::proto::localdevice::dialog_manager_client::DialogManagerClient;
18use crate::proto::localdevice::network_manager_client::NetworkManagerClient;
19use crate::proto::localdevice::permission_manager_client::PermissionManagerClient;
20use crate::proto::localdevice::photo_library_client::PhotoLibraryClient;
21use crate::proto::localdevice::remote_control_client::RemoteControlClient;
22use crate::proto::localdevice::rim_client::RimClient;
23use crate::proto::localdevice::user_config_client::UserConfigClient;
24use crate::proto::sys::access_controler_service_client::AccessControlerServiceClient;
25use crate::proto::sys::btrfs_util_client::BtrfsUtilClient;
26use crate::proto::sys::dir_monitor_client::DirMonitorClient;
27use crate::proto::sys::package_manager_client::PackageManagerClient;
28use crate::proto::sys::tv_os_client::TvOsClient;
29use crate::proto::sys::version_info_service_client::VersionInfoServiceClient;
30use crate::{
31    AuthToken, AuthenticatedService, ClientCredentials, CredentialPaths, DeviceProxyStatus, Error,
32    TokenProvider, connect_api_with,
33};
34
35type DeviceServiceTransport = AuthenticatedService<Channel>;
36
37/// Complete client composition for the `LazyCat` runtime API gateway.
38#[derive(Clone)]
39pub struct ApiGateway {
40    channel: Channel,
41    credentials: ClientCredentials,
42}
43
44impl ApiGateway {
45    /// Load runtime credentials and connect the API gateway.
46    ///
47    /// # Errors
48    ///
49    /// Returns an error when credentials cannot be loaded or the runtime API
50    /// cannot be reached.
51    pub async fn connect() -> Result<Self, Error> {
52        let credentials = ClientCredentials::load(CredentialPaths::runtime()).await?;
53        Self::connect_with(credentials).await
54    }
55
56    /// Connect the API gateway with preloaded credentials.
57    ///
58    /// # Errors
59    ///
60    /// Returns an error when the runtime API cannot be reached.
61    pub async fn connect_with(credentials: ClientCredentials) -> Result<Self, Error> {
62        let channel = connect_api_with(credentials.clone()).await?;
63        Ok(Self::from_channel(channel, credentials))
64    }
65
66    /// Compose a gateway around an existing runtime channel.
67    #[must_use]
68    pub fn from_channel(channel: Channel, credentials: ClientCredentials) -> Self {
69        Self {
70            channel,
71            credentials,
72        }
73    }
74
75    /// Connect an authenticated proxy for a remote `LazyCat` device API.
76    ///
77    /// # Errors
78    ///
79    /// Returns an error when the device URL or mTLS connection is invalid.
80    pub async fn device_proxy(&self, api_url: &str) -> Result<DeviceProxy, Error> {
81        DeviceProxy::connect(api_url, self.credentials.clone()).await
82    }
83
84    #[must_use]
85    pub fn box_service(&self) -> BoxServiceClient<Channel> {
86        BoxServiceClient::new(self.channel.clone())
87    }
88
89    #[must_use]
90    pub fn users(&self) -> UserManagerClient<Channel> {
91        UserManagerClient::new(self.channel.clone())
92    }
93
94    #[must_use]
95    pub fn devices(&self) -> EndDeviceServiceClient<Channel> {
96        EndDeviceServiceClient::new(self.channel.clone())
97    }
98
99    #[must_use]
100    pub fn permissions(&self) -> RuntimePermissionManagerClient<Channel> {
101        RuntimePermissionManagerClient::new(self.channel.clone())
102    }
103
104    #[must_use]
105    pub fn peripheral_device(&self) -> PeripheralDeviceServiceClient<Channel> {
106        PeripheralDeviceServiceClient::new(self.channel.clone())
107    }
108
109    #[must_use]
110    pub fn iscsi(&self) -> IscsiServiceClient<Channel> {
111        IscsiServiceClient::new(self.channel.clone())
112    }
113
114    #[must_use]
115    pub fn file_transfer(&self) -> FileTransferServiceClient<Channel> {
116        FileTransferServiceClient::new(self.channel.clone())
117    }
118
119    #[must_use]
120    pub fn package_manager(&self) -> PackageManagerClient<Channel> {
121        PackageManagerClient::new(self.channel.clone())
122    }
123
124    #[must_use]
125    pub fn access_controller(&self) -> AccessControlerServiceClient<Channel> {
126        AccessControlerServiceClient::new(self.channel.clone())
127    }
128
129    #[must_use]
130    pub fn btrfs(&self) -> BtrfsUtilClient<Channel> {
131        BtrfsUtilClient::new(self.channel.clone())
132    }
133
134    #[must_use]
135    pub fn dir_monitor(&self) -> DirMonitorClient<Channel> {
136        DirMonitorClient::new(self.channel.clone())
137    }
138
139    #[must_use]
140    pub fn message(&self) -> MessageServiceClient<Channel> {
141        MessageServiceClient::new(self.channel.clone())
142    }
143
144    #[must_use]
145    pub fn tv_os(&self) -> TvOsClient<Channel> {
146        TvOsClient::new(self.channel.clone())
147    }
148
149    #[must_use]
150    pub fn version(&self) -> VersionInfoServiceClient<Channel> {
151        VersionInfoServiceClient::new(self.channel.clone())
152    }
153}
154
155impl fmt::Debug for ApiGateway {
156    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
157        formatter
158            .debug_struct("ApiGateway")
159            .field("credentials", &self.credentials)
160            .finish_non_exhaustive()
161    }
162}
163
164/// Complete authenticated client composition for a `LazyCat` device API.
165#[derive(Clone)]
166pub struct DeviceProxy {
167    provider: TokenProvider,
168    service: DeviceServiceTransport,
169    status: Arc<DeviceProxyStatus>,
170}
171
172impl DeviceProxy {
173    /// Connect all device clients over one authenticated mTLS channel.
174    ///
175    /// # Errors
176    ///
177    /// Returns an error when the device URL or mTLS connection is invalid.
178    pub async fn connect(api_url: &str, credentials: ClientCredentials) -> Result<Self, Error> {
179        let provider = TokenProvider::connect(api_url, credentials).await?;
180        let service = provider.authenticated_service();
181        let status = Arc::new(DeviceProxyStatus::new(service.clone()));
182        Ok(Self {
183            provider,
184            service,
185            status,
186        })
187    }
188
189    /// Return the current cached token, refreshing it when necessary.
190    ///
191    /// # Errors
192    ///
193    /// Returns an error when token signing or acquisition fails.
194    pub async fn get_auth_token(&self) -> Result<Arc<AuthToken>, Error> {
195        self.provider.token().await
196    }
197
198    #[must_use]
199    pub fn config(&self) -> UserConfigClient<DeviceServiceTransport> {
200        UserConfigClient::new(self.service.clone())
201    }
202
203    #[must_use]
204    pub fn device(&self) -> DeviceServiceClient<DeviceServiceTransport> {
205        DeviceServiceClient::new(self.service.clone())
206    }
207
208    #[must_use]
209    pub fn dialog(&self) -> DialogManagerClient<DeviceServiceTransport> {
210        DialogManagerClient::new(self.service.clone())
211    }
212
213    #[must_use]
214    pub fn photo_library(&self) -> PhotoLibraryClient<DeviceServiceTransport> {
215        PhotoLibraryClient::new(self.service.clone())
216    }
217
218    #[must_use]
219    pub fn network(&self) -> NetworkManagerClient<DeviceServiceTransport> {
220        NetworkManagerClient::new(self.service.clone())
221    }
222
223    #[must_use]
224    pub fn permission(&self) -> PermissionManagerClient<DeviceServiceTransport> {
225        PermissionManagerClient::new(self.service.clone())
226    }
227
228    #[must_use]
229    pub fn file_handler(&self) -> FileHandlerClient<DeviceServiceTransport> {
230        FileHandlerClient::new(self.service.clone())
231    }
232
233    #[must_use]
234    pub fn rim(&self) -> RimClient<DeviceServiceTransport> {
235        RimClient::new(self.service.clone())
236    }
237
238    #[must_use]
239    pub fn remote_control(&self) -> RemoteControlClient<DeviceServiceTransport> {
240        RemoteControlClient::new(self.service.clone())
241    }
242
243    #[must_use]
244    pub fn contacts(&self) -> ContactsManagerClient<DeviceServiceTransport> {
245        ContactsManagerClient::new(self.service.clone())
246    }
247
248    #[must_use]
249    pub fn status(&self) -> DeviceProxyStatus {
250        self.status.as_ref().clone()
251    }
252}
253
254impl fmt::Debug for DeviceProxy {
255    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
256        formatter
257            .debug_struct("DeviceProxy")
258            .field("provider", &self.provider)
259            .finish_non_exhaustive()
260    }
261}