1use crate::{
7 Interface,
8 types::{FabricClientSettings, FabricSecurityCredentials},
9};
10use connection::{ClientConnectionEventHandlerBridge, LambdaClientConnectionNotificationHandler};
11use health_client::HealthClient;
12use mssf_com::FabricClient::{
13 IFabricApplicationManagementClient, IFabricClientConnectionEventHandler,
14 IFabricClientSettings2, IFabricHealthClient4, IFabricPropertyManagementClient2,
15 IFabricQueryClient13, IFabricServiceManagementClient8, IFabricServiceNotificationEventHandler,
16};
17use notification::{
18 LambdaServiceNotificationHandler, ServiceNotificationEventHandler,
19 ServiceNotificationEventHandlerBridge,
20};
21
22use crate::types::ClientRole;
23
24use self::{query_client::QueryClient, svc_mgmt_client::ServiceManagementClient};
25
26mod connection;
27mod notification;
28
29pub mod application_client;
31pub mod health_client;
32mod property_client;
33pub mod query_client;
34pub mod svc_mgmt_client;
35pub use application_client::ApplicationManagementClient;
37pub use connection::{ClaimsRetrievalMetadata, GatewayInformationResult};
38pub use notification::ServiceNotification;
39pub use property_client::PropertyManagementClient;
40
41#[cfg(test)]
42mod tests;
43
44#[non_exhaustive]
45#[derive(Debug)]
46pub enum FabricClientCreationError {
47 InvalidFabricClientSettings(crate::Error),
48 InvalidFabricSecurityCredentials(crate::Error),
49}
50
51impl core::fmt::Display for FabricClientCreationError {
52 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53 match self {
54 FabricClientCreationError::InvalidFabricClientSettings(error) => {
55 write!(f, "InvalidFabricClientSettings({error})")
56 }
57 FabricClientCreationError::InvalidFabricSecurityCredentials(error) => {
58 write!(f, "InvalidFabricSecurityCredentialss({error})")
59 }
60 }
61 }
62}
63
64impl core::error::Error for FabricClientCreationError {}
65
66fn create_local_client_internal<T: Interface>(
68 connection_strings: Option<&Vec<crate::WString>>,
69 service_notification_handler: Option<&IFabricServiceNotificationEventHandler>,
70 client_connection_handler: Option<&IFabricClientConnectionEventHandler>,
71 client_role: Option<ClientRole>,
72 client_settings: Option<FabricClientSettings>,
73 client_credentials: Option<FabricSecurityCredentials>,
74) -> Result<T, FabricClientCreationError> {
75 let role = client_role.unwrap_or(ClientRole::Unknown);
76
77 let connection_strings_ptrs = connection_strings.map(|addrs| {
79 addrs
80 .iter()
81 .map(|s| crate::PCWSTR(s.as_ptr()))
82 .collect::<Vec<_>>()
83 });
84
85 let client = match connection_strings_ptrs {
86 Some(addrs) => {
87 assert!(
88 role == ClientRole::Unknown,
89 "ClientRole is for local client only and cannot be used for connecting to remote cluster."
90 );
91 crate::API_TABLE.fabric_create_client3::<T>(
92 &addrs,
93 service_notification_handler,
94 client_connection_handler,
95 )
96 },
97 None => {
98 if role == ClientRole::Unknown {
99 crate::API_TABLE.fabric_create_local_client3::<T>(
101 service_notification_handler,
102 client_connection_handler,
103 )
104 } else {
105 crate::API_TABLE.fabric_create_local_client4::<T>(
106 service_notification_handler,
107 client_connection_handler,
108 role.into(),
109 )
110 }
111 }
112 }
113 .expect("failed to create fabric client");
115 if client_settings.is_some() || client_credentials.is_some() {
116 let setting_interface = client
117 .clone()
118 .cast::<IFabricClientSettings2>()
119 .expect("failed to cast fabric client to IFabricClientSettings2");
120 if let Some(desired_settings) = client_settings {
121 desired_settings
122 .apply(&setting_interface)
123 .map_err(FabricClientCreationError::InvalidFabricClientSettings)?;
124 }
125 if let Some(desired_credentials) = client_credentials {
126 desired_credentials
127 .apply(setting_interface)
128 .map_err(FabricClientCreationError::InvalidFabricSecurityCredentials)?;
129 }
130 };
131 Ok(client)
132}
133
134pub struct FabricClientBuilder {
139 sn_handler: Option<IFabricServiceNotificationEventHandler>,
140 cc_handler: Option<LambdaClientConnectionNotificationHandler>,
141 client_role: ClientRole,
142 connection_strings: Option<Vec<crate::WString>>,
143 client_settings: Option<FabricClientSettings>,
144 client_credentials: Option<FabricSecurityCredentials>,
145}
146
147impl Default for FabricClientBuilder {
148 fn default() -> Self {
149 Self::new()
150 }
151}
152
153impl FabricClientBuilder {
154 pub fn new() -> Self {
156 Self {
157 sn_handler: None,
158 cc_handler: None,
159 client_role: ClientRole::Unknown,
160 connection_strings: None,
161 client_settings: None,
162 client_credentials: None,
163 }
164 }
165
166 fn with_service_notification_handler(
168 mut self,
169 handler: impl ServiceNotificationEventHandler,
170 ) -> Self {
171 self.sn_handler = Some(ServiceNotificationEventHandlerBridge::new_com(handler));
172 self
173 }
174
175 pub fn with_on_service_notification<T>(self, f: T) -> Self
181 where
182 T: Fn(ServiceNotification) -> crate::Result<()> + Send + Sync + 'static,
183 {
184 let handler = LambdaServiceNotificationHandler::new(f);
185 self.with_service_notification_handler(handler)
186 }
187
188 pub fn with_on_client_connect<T>(mut self, f: T) -> Self
190 where
191 T: Fn(&GatewayInformationResult) -> crate::Result<()> + Send + Sync + 'static,
192 {
193 if self.cc_handler.is_none() {
194 self.cc_handler = Some(LambdaClientConnectionNotificationHandler::new());
195 }
196 if let Some(cc) = self.cc_handler.as_mut() {
197 cc.set_f_conn(f)
198 }
199 self
200 }
201
202 pub fn with_on_client_disconnect<T>(mut self, f: T) -> Self
205 where
206 T: Fn(&GatewayInformationResult) -> crate::Result<()> + Send + Sync + 'static,
207 {
208 if self.cc_handler.is_none() {
209 self.cc_handler = Some(LambdaClientConnectionNotificationHandler::new());
210 }
211 if let Some(cc) = self.cc_handler.as_mut() {
212 cc.set_f_disconn(f)
213 }
214 self
215 }
216
217 pub fn with_on_claims_retrieval<T>(mut self, f: T) -> Self
224 where
225 T: Fn(connection::ClaimsRetrievalMetadata) -> crate::Result<crate::WString>
226 + Send
227 + Sync
228 + 'static,
229 {
230 if self.cc_handler.is_none() {
231 self.cc_handler = Some(LambdaClientConnectionNotificationHandler::new());
232 }
233 if let Some(cc) = self.cc_handler.as_mut() {
234 cc.set_f_claims(f)
235 }
236 self
237 }
238
239 pub fn with_client_role(mut self, role: ClientRole) -> Self {
243 self.client_role = role;
244 self
245 }
246
247 pub fn with_connection_strings(mut self, addrs: Vec<crate::WString>) -> Self {
250 self.connection_strings = Some(addrs);
251 self
252 }
253
254 pub fn with_client_settings(mut self, client_settings: FabricClientSettings) -> Self {
256 self.client_settings = Some(client_settings);
257 self
258 }
259
260 pub fn with_credentials(mut self, client_credentials: FabricSecurityCredentials) -> Self {
262 self.client_credentials = Some(client_credentials);
263 self
264 }
265
266 pub fn build(self) -> Result<FabricClient, FabricClientCreationError> {
271 let c = Self::build_interface(self)?;
272 Ok(FabricClient::from_com(c))
273 }
274
275 pub fn build_interface<T: Interface>(self) -> Result<T, FabricClientCreationError> {
277 let cc_handler = self
278 .cc_handler
279 .map(ClientConnectionEventHandlerBridge::new_com);
280 create_local_client_internal::<T>(
281 self.connection_strings.as_ref(),
282 self.sn_handler.as_ref(),
283 cc_handler.as_ref(),
284 Some(self.client_role),
285 self.client_settings,
286 self.client_credentials,
287 )
288 }
289}
290
291#[derive(Debug, Clone)]
295pub struct FabricClient {
296 property_client: PropertyManagementClient,
297 service_client: ServiceManagementClient,
298 query_client: QueryClient,
299 health_client: HealthClient,
300 application_client: ApplicationManagementClient,
301}
302
303impl FabricClient {
304 pub fn builder() -> FabricClientBuilder {
306 FabricClientBuilder::new()
307 }
308
309 pub fn from_com(com: IFabricPropertyManagementClient2) -> Self {
313 let com_property_client = com.clone();
314 let com_service_client = com
315 .clone()
316 .cast::<IFabricServiceManagementClient8>()
317 .unwrap();
318 let com_query_client = com.clone().cast::<IFabricQueryClient13>().unwrap();
319 let com_health_client = com.clone().cast::<IFabricHealthClient4>().unwrap();
320 let com_application_client = com
321 .clone()
322 .cast::<IFabricApplicationManagementClient>()
323 .unwrap();
324 Self {
325 property_client: PropertyManagementClient::from(com_property_client),
326 service_client: ServiceManagementClient::from(com_service_client),
327 query_client: QueryClient::from(com_query_client),
328 health_client: HealthClient::from(com_health_client),
329 application_client: ApplicationManagementClient::from(com_application_client),
330 }
331 }
332
333 pub fn get_property_manager(&self) -> &PropertyManagementClient {
335 &self.property_client
336 }
337
338 pub fn get_query_manager(&self) -> &QueryClient {
340 &self.query_client
341 }
342
343 pub fn get_service_manager(&self) -> &ServiceManagementClient {
345 &self.service_client
346 }
347
348 pub fn get_health_manager(&self) -> &HealthClient {
350 &self.health_client
351 }
352
353 pub fn get_application_manager(&self) -> &ApplicationManagementClient {
356 &self.application_client
357 }
358}