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::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_client_role(mut self, role: ClientRole) -> Self {
216 self.client_role = role;
217 self
218 }
219
220 pub fn with_connection_strings(mut self, addrs: Vec<crate::WString>) -> Self {
223 self.connection_strings = Some(addrs);
224 self
225 }
226
227 pub fn with_client_settings(mut self, client_settings: FabricClientSettings) -> Self {
229 self.client_settings = Some(client_settings);
230 self
231 }
232
233 pub fn with_credentials(mut self, client_credentials: FabricSecurityCredentials) -> Self {
235 self.client_credentials = Some(client_credentials);
236 self
237 }
238
239 pub fn build(self) -> Result<FabricClient, FabricClientCreationError> {
244 let c = Self::build_interface(self)?;
245 Ok(FabricClient::from_com(c))
246 }
247
248 pub fn build_interface<T: Interface>(self) -> Result<T, FabricClientCreationError> {
250 let cc_handler = self
251 .cc_handler
252 .map(ClientConnectionEventHandlerBridge::new_com);
253 create_local_client_internal::<T>(
254 self.connection_strings.as_ref(),
255 self.sn_handler.as_ref(),
256 cc_handler.as_ref(),
257 Some(self.client_role),
258 self.client_settings,
259 self.client_credentials,
260 )
261 }
262}
263
264#[derive(Debug, Clone)]
268pub struct FabricClient {
269 property_client: PropertyManagementClient,
270 service_client: ServiceManagementClient,
271 query_client: QueryClient,
272 health_client: HealthClient,
273}
274
275impl FabricClient {
276 pub fn builder() -> FabricClientBuilder {
278 FabricClientBuilder::new()
279 }
280
281 pub fn from_com(com: IFabricPropertyManagementClient2) -> Self {
285 let com_property_client = com.clone();
286 let com_service_client = com
287 .clone()
288 .cast::<IFabricServiceManagementClient6>()
289 .unwrap();
290 let com_query_client = com.clone().cast::<IFabricQueryClient10>().unwrap();
291 let com_health_client = com.clone().cast::<IFabricHealthClient4>().unwrap();
292 Self {
293 property_client: PropertyManagementClient::from(com_property_client),
294 service_client: ServiceManagementClient::from(com_service_client),
295 query_client: QueryClient::from(com_query_client),
296 health_client: HealthClient::from(com_health_client),
297 }
298 }
299
300 pub fn get_property_manager(&self) -> &PropertyManagementClient {
302 &self.property_client
303 }
304
305 pub fn get_query_manager(&self) -> &QueryClient {
307 &self.query_client
308 }
309
310 pub fn get_service_manager(&self) -> &ServiceManagementClient {
312 &self.service_client
313 }
314
315 pub fn get_health_manager(&self) -> &HealthClient {
317 &self.health_client
318 }
319}