1use crate::{
7 Interface,
8 types::{FabricClientSettings, FabricSecurityCredentials},
9};
10use connection::{ClientConnectionEventHandlerBridge, LambdaClientConnectionNotificationHandler};
11use health_client::HealthClient;
12use mssf_com::FabricClient::{
13 IFabricClientConnectionEventHandler, IFabricClientSettings2, IFabricHealthClient4,
14 IFabricPropertyManagementClient2, IFabricQueryClient10, IFabricServiceManagementClient6,
15 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 health_client;
31mod property_client;
32pub mod query_client;
33pub mod svc_mgmt_client;
34pub use connection::{ClaimsRetrievalMetadata, GatewayInformationResult};
36pub use notification::ServiceNotification;
37pub use property_client::PropertyManagementClient;
38
39#[cfg(test)]
40mod tests;
41
42#[non_exhaustive]
43#[derive(Debug)]
44pub enum FabricClientCreationError {
45 InvalidFabricClientSettings(crate::Error),
46 InvalidFabricSecurityCredentials(crate::Error),
47}
48
49impl core::fmt::Display for FabricClientCreationError {
50 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51 match self {
52 FabricClientCreationError::InvalidFabricClientSettings(error) => {
53 write!(f, "InvalidFabricClientSettings({error})")
54 }
55 FabricClientCreationError::InvalidFabricSecurityCredentials(error) => {
56 write!(f, "InvalidFabricSecurityCredentialss({error})")
57 }
58 }
59 }
60}
61
62impl core::error::Error for FabricClientCreationError {}
63
64fn create_local_client_internal<T: Interface>(
66 connection_strings: Option<&Vec<crate::WString>>,
67 service_notification_handler: Option<&IFabricServiceNotificationEventHandler>,
68 client_connection_handler: Option<&IFabricClientConnectionEventHandler>,
69 client_role: Option<ClientRole>,
70 client_settings: Option<FabricClientSettings>,
71 client_credentials: Option<FabricSecurityCredentials>,
72) -> Result<T, FabricClientCreationError> {
73 let role = client_role.unwrap_or(ClientRole::Unknown);
74
75 let connection_strings_ptrs = connection_strings.map(|addrs| {
77 addrs
78 .iter()
79 .map(|s| crate::PCWSTR(s.as_ptr()))
80 .collect::<Vec<_>>()
81 });
82
83 let client = match connection_strings_ptrs {
84 Some(addrs) => {
85 assert!(
86 role == ClientRole::Unknown,
87 "ClientRole is for local client only and cannot be used for connecting to remote cluster."
88 );
89 crate::API_TABLE.fabric_create_client3::<T>(
90 &addrs,
91 service_notification_handler,
92 client_connection_handler,
93 )
94 },
95 None => {
96 if role == ClientRole::Unknown {
97 crate::API_TABLE.fabric_create_local_client3::<T>(
99 service_notification_handler,
100 client_connection_handler,
101 )
102 } else {
103 crate::API_TABLE.fabric_create_local_client4::<T>(
104 service_notification_handler,
105 client_connection_handler,
106 role.into(),
107 )
108 }
109 }
110 }
111 .expect("failed to create fabric client");
113 if client_settings.is_some() || client_credentials.is_some() {
114 let setting_interface = client
115 .clone()
116 .cast::<IFabricClientSettings2>()
117 .expect("failed to cast fabric client to IFabricClientSettings2");
118 if let Some(desired_settings) = client_settings {
119 desired_settings
120 .apply(&setting_interface)
121 .map_err(FabricClientCreationError::InvalidFabricClientSettings)?;
122 }
123 if let Some(desired_credentials) = client_credentials {
124 desired_credentials
125 .apply(setting_interface)
126 .map_err(FabricClientCreationError::InvalidFabricSecurityCredentials)?;
127 }
128 };
129 Ok(client)
130}
131
132pub struct FabricClientBuilder {
134 sn_handler: Option<IFabricServiceNotificationEventHandler>,
135 cc_handler: Option<LambdaClientConnectionNotificationHandler>,
136 client_role: ClientRole,
137 connection_strings: Option<Vec<crate::WString>>,
138 client_settings: Option<FabricClientSettings>,
139 client_credentials: Option<FabricSecurityCredentials>,
140}
141
142impl Default for FabricClientBuilder {
143 fn default() -> Self {
144 Self::new()
145 }
146}
147
148impl FabricClientBuilder {
149 pub fn new() -> Self {
151 Self {
152 sn_handler: None,
153 cc_handler: None,
154 client_role: ClientRole::Unknown,
155 connection_strings: None,
156 client_settings: None,
157 client_credentials: None,
158 }
159 }
160
161 fn with_service_notification_handler(
163 mut self,
164 handler: impl ServiceNotificationEventHandler,
165 ) -> Self {
166 self.sn_handler = Some(ServiceNotificationEventHandlerBridge::new_com(handler));
167 self
168 }
169
170 pub fn with_on_service_notification<T>(self, f: T) -> Self
176 where
177 T: Fn(ServiceNotification) -> crate::Result<()> + 'static,
178 {
179 let handler = LambdaServiceNotificationHandler::new(f);
180 self.with_service_notification_handler(handler)
181 }
182
183 pub fn with_on_client_connect<T>(mut self, f: T) -> Self
185 where
186 T: Fn(&GatewayInformationResult) -> crate::Result<()> + 'static,
187 {
188 if self.cc_handler.is_none() {
189 self.cc_handler = Some(LambdaClientConnectionNotificationHandler::new());
190 }
191 if let Some(cc) = self.cc_handler.as_mut() {
192 cc.set_f_conn(f)
193 }
194 self
195 }
196
197 pub fn with_on_client_disconnect<T>(mut self, f: T) -> Self
200 where
201 T: Fn(&GatewayInformationResult) -> crate::Result<()> + 'static,
202 {
203 if self.cc_handler.is_none() {
204 self.cc_handler = Some(LambdaClientConnectionNotificationHandler::new());
205 }
206 if let Some(cc) = self.cc_handler.as_mut() {
207 cc.set_f_disconn(f)
208 }
209 self
210 }
211
212 pub fn with_on_claims_retrieval<T>(mut self, f: T) -> Self
219 where
220 T: Fn(connection::ClaimsRetrievalMetadata) -> crate::Result<crate::WString> + 'static,
221 {
222 if self.cc_handler.is_none() {
223 self.cc_handler = Some(LambdaClientConnectionNotificationHandler::new());
224 }
225 if let Some(cc) = self.cc_handler.as_mut() {
226 cc.set_f_claims(f)
227 }
228 self
229 }
230
231 pub fn with_client_role(mut self, role: ClientRole) -> Self {
235 self.client_role = role;
236 self
237 }
238
239 pub fn with_connection_strings(mut self, addrs: Vec<crate::WString>) -> Self {
242 self.connection_strings = Some(addrs);
243 self
244 }
245
246 pub fn with_client_settings(mut self, client_settings: FabricClientSettings) -> Self {
248 self.client_settings = Some(client_settings);
249 self
250 }
251
252 pub fn with_credentials(mut self, client_credentials: FabricSecurityCredentials) -> Self {
254 self.client_credentials = Some(client_credentials);
255 self
256 }
257
258 pub fn build(self) -> Result<FabricClient, FabricClientCreationError> {
263 let c = Self::build_interface(self)?;
264 Ok(FabricClient::from_com(c))
265 }
266
267 pub fn build_interface<T: Interface>(self) -> Result<T, FabricClientCreationError> {
269 let cc_handler = self
270 .cc_handler
271 .map(ClientConnectionEventHandlerBridge::new_com);
272 create_local_client_internal::<T>(
273 self.connection_strings.as_ref(),
274 self.sn_handler.as_ref(),
275 cc_handler.as_ref(),
276 Some(self.client_role),
277 self.client_settings,
278 self.client_credentials,
279 )
280 }
281}
282
283#[derive(Debug, Clone)]
287pub struct FabricClient {
288 property_client: PropertyManagementClient,
289 service_client: ServiceManagementClient,
290 query_client: QueryClient,
291 health_client: HealthClient,
292}
293
294impl FabricClient {
295 pub fn builder() -> FabricClientBuilder {
297 FabricClientBuilder::new()
298 }
299
300 pub fn from_com(com: IFabricPropertyManagementClient2) -> Self {
304 let com_property_client = com.clone();
305 let com_service_client = com
306 .clone()
307 .cast::<IFabricServiceManagementClient6>()
308 .unwrap();
309 let com_query_client = com.clone().cast::<IFabricQueryClient10>().unwrap();
310 let com_health_client = com.clone().cast::<IFabricHealthClient4>().unwrap();
311 Self {
312 property_client: PropertyManagementClient::from(com_property_client),
313 service_client: ServiceManagementClient::from(com_service_client),
314 query_client: QueryClient::from(com_query_client),
315 health_client: HealthClient::from(com_health_client),
316 }
317 }
318
319 pub fn get_property_manager(&self) -> &PropertyManagementClient {
321 &self.property_client
322 }
323
324 pub fn get_query_manager(&self) -> &QueryClient {
326 &self.query_client
327 }
328
329 pub fn get_service_manager(&self) -> &ServiceManagementClient {
331 &self.service_client
332 }
333
334 pub fn get_health_manager(&self) -> &HealthClient {
336 &self.health_client
337 }
338}