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 {
136 sn_handler: Option<IFabricServiceNotificationEventHandler>,
137 cc_handler: Option<LambdaClientConnectionNotificationHandler>,
138 client_role: ClientRole,
139 connection_strings: Option<Vec<crate::WString>>,
140 client_settings: Option<FabricClientSettings>,
141 client_credentials: Option<FabricSecurityCredentials>,
142}
143
144impl Default for FabricClientBuilder {
145 fn default() -> Self {
146 Self::new()
147 }
148}
149
150impl FabricClientBuilder {
151 pub fn new() -> Self {
153 Self {
154 sn_handler: None,
155 cc_handler: None,
156 client_role: ClientRole::Unknown,
157 connection_strings: None,
158 client_settings: None,
159 client_credentials: None,
160 }
161 }
162
163 fn with_service_notification_handler(
165 mut self,
166 handler: impl ServiceNotificationEventHandler,
167 ) -> Self {
168 self.sn_handler = Some(ServiceNotificationEventHandlerBridge::new_com(handler));
169 self
170 }
171
172 pub fn with_on_service_notification<T>(self, f: T) -> Self
178 where
179 T: Fn(ServiceNotification) -> crate::Result<()> + 'static,
180 {
181 let handler = LambdaServiceNotificationHandler::new(f);
182 self.with_service_notification_handler(handler)
183 }
184
185 pub fn with_on_client_connect<T>(mut self, f: T) -> Self
187 where
188 T: Fn(&GatewayInformationResult) -> crate::Result<()> + 'static,
189 {
190 if self.cc_handler.is_none() {
191 self.cc_handler = Some(LambdaClientConnectionNotificationHandler::new());
192 }
193 if let Some(cc) = self.cc_handler.as_mut() {
194 cc.set_f_conn(f)
195 }
196 self
197 }
198
199 pub fn with_on_client_disconnect<T>(mut self, f: T) -> Self
202 where
203 T: Fn(&GatewayInformationResult) -> crate::Result<()> + 'static,
204 {
205 if self.cc_handler.is_none() {
206 self.cc_handler = Some(LambdaClientConnectionNotificationHandler::new());
207 }
208 if let Some(cc) = self.cc_handler.as_mut() {
209 cc.set_f_disconn(f)
210 }
211 self
212 }
213
214 pub fn with_on_claims_retrieval<T>(mut self, f: T) -> Self
221 where
222 T: Fn(connection::ClaimsRetrievalMetadata) -> crate::Result<crate::WString> + 'static,
223 {
224 if self.cc_handler.is_none() {
225 self.cc_handler = Some(LambdaClientConnectionNotificationHandler::new());
226 }
227 if let Some(cc) = self.cc_handler.as_mut() {
228 cc.set_f_claims(f)
229 }
230 self
231 }
232
233 pub fn with_client_role(mut self, role: ClientRole) -> Self {
237 self.client_role = role;
238 self
239 }
240
241 pub fn with_connection_strings(mut self, addrs: Vec<crate::WString>) -> Self {
244 self.connection_strings = Some(addrs);
245 self
246 }
247
248 pub fn with_client_settings(mut self, client_settings: FabricClientSettings) -> Self {
250 self.client_settings = Some(client_settings);
251 self
252 }
253
254 pub fn with_credentials(mut self, client_credentials: FabricSecurityCredentials) -> Self {
256 self.client_credentials = Some(client_credentials);
257 self
258 }
259
260 pub fn build(self) -> Result<FabricClient, FabricClientCreationError> {
265 let c = Self::build_interface(self)?;
266 Ok(FabricClient::from_com(c))
267 }
268
269 pub fn build_interface<T: Interface>(self) -> Result<T, FabricClientCreationError> {
271 let cc_handler = self
272 .cc_handler
273 .map(ClientConnectionEventHandlerBridge::new_com);
274 create_local_client_internal::<T>(
275 self.connection_strings.as_ref(),
276 self.sn_handler.as_ref(),
277 cc_handler.as_ref(),
278 Some(self.client_role),
279 self.client_settings,
280 self.client_credentials,
281 )
282 }
283}
284
285#[derive(Debug, Clone)]
289pub struct FabricClient {
290 property_client: PropertyManagementClient,
291 service_client: ServiceManagementClient,
292 query_client: QueryClient,
293 health_client: HealthClient,
294 application_client: ApplicationManagementClient,
295}
296
297impl FabricClient {
298 pub fn builder() -> FabricClientBuilder {
300 FabricClientBuilder::new()
301 }
302
303 pub fn from_com(com: IFabricPropertyManagementClient2) -> Self {
307 let com_property_client = com.clone();
308 let com_service_client = com
309 .clone()
310 .cast::<IFabricServiceManagementClient8>()
311 .unwrap();
312 let com_query_client = com.clone().cast::<IFabricQueryClient13>().unwrap();
313 let com_health_client = com.clone().cast::<IFabricHealthClient4>().unwrap();
314 let com_application_client = com
315 .clone()
316 .cast::<IFabricApplicationManagementClient>()
317 .unwrap();
318 Self {
319 property_client: PropertyManagementClient::from(com_property_client),
320 service_client: ServiceManagementClient::from(com_service_client),
321 query_client: QueryClient::from(com_query_client),
322 health_client: HealthClient::from(com_health_client),
323 application_client: ApplicationManagementClient::from(com_application_client),
324 }
325 }
326
327 pub fn get_property_manager(&self) -> &PropertyManagementClient {
329 &self.property_client
330 }
331
332 pub fn get_query_manager(&self) -> &QueryClient {
334 &self.query_client
335 }
336
337 pub fn get_service_manager(&self) -> &ServiceManagementClient {
339 &self.service_client
340 }
341
342 pub fn get_health_manager(&self) -> &HealthClient {
344 &self.health_client
345 }
346
347 pub fn get_application_manager(&self) -> &ApplicationManagementClient {
350 &self.application_client
351 }
352}