use crate::{
Interface,
types::{FabricClientSettings, FabricSecurityCredentials},
};
use connection::{ClientConnectionEventHandlerBridge, LambdaClientConnectionNotificationHandler};
use health_client::HealthClient;
use mssf_com::FabricClient::{
IFabricClientConnectionEventHandler, IFabricClientSettings2, IFabricHealthClient4,
IFabricPropertyManagementClient2, IFabricQueryClient10, IFabricServiceManagementClient6,
IFabricServiceNotificationEventHandler,
};
use notification::{
LambdaServiceNotificationHandler, ServiceNotificationEventHandler,
ServiceNotificationEventHandlerBridge,
};
use crate::types::ClientRole;
use self::{query_client::QueryClient, svc_mgmt_client::ServiceManagementClient};
mod connection;
mod notification;
pub mod health_client;
mod property_client;
pub mod query_client;
pub mod svc_mgmt_client;
pub use connection::GatewayInformationResult;
pub use notification::ServiceNotification;
pub use property_client::PropertyManagementClient;
#[cfg(test)]
mod tests;
#[non_exhaustive]
#[derive(Debug)]
pub enum FabricClientCreationError {
InvalidFabricClientSettings(crate::Error),
InvalidFabricSecurityCredentials(crate::Error),
}
impl core::fmt::Display for FabricClientCreationError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
FabricClientCreationError::InvalidFabricClientSettings(error) => {
write!(f, "InvalidFabricClientSettings({error})")
}
FabricClientCreationError::InvalidFabricSecurityCredentials(error) => {
write!(f, "InvalidFabricSecurityCredentialss({error})")
}
}
}
}
impl core::error::Error for FabricClientCreationError {}
fn create_local_client_internal<T: Interface>(
connection_strings: Option<&Vec<crate::WString>>,
service_notification_handler: Option<&IFabricServiceNotificationEventHandler>,
client_connection_handler: Option<&IFabricClientConnectionEventHandler>,
client_role: Option<ClientRole>,
client_settings: Option<FabricClientSettings>,
client_credentials: Option<FabricSecurityCredentials>,
) -> Result<T, FabricClientCreationError> {
let role = client_role.unwrap_or(ClientRole::Unknown);
let connection_strings_ptrs = connection_strings.map(|addrs| {
addrs
.iter()
.map(|s| crate::PCWSTR(s.as_ptr()))
.collect::<Vec<_>>()
});
let client = match connection_strings_ptrs {
Some(addrs) => {
assert!(
role == ClientRole::Unknown,
"ClientRole is for local client only and cannot be used for connecting to remote cluster."
);
crate::API_TABLE.fabric_create_client3::<T>(
&addrs,
service_notification_handler,
client_connection_handler,
)
},
None => {
if role == ClientRole::Unknown {
crate::API_TABLE.fabric_create_local_client3::<T>(
service_notification_handler,
client_connection_handler,
)
} else {
crate::API_TABLE.fabric_create_local_client4::<T>(
service_notification_handler,
client_connection_handler,
role.into(),
)
}
}
}
.expect("failed to create fabric client");
if client_settings.is_some() || client_credentials.is_some() {
let setting_interface = client
.clone()
.cast::<IFabricClientSettings2>()
.expect("failed to cast fabric client to IFabricClientSettings2");
if let Some(desired_settings) = client_settings {
desired_settings
.apply(&setting_interface)
.map_err(FabricClientCreationError::InvalidFabricClientSettings)?;
}
if let Some(desired_credentials) = client_credentials {
desired_credentials
.apply(setting_interface)
.map_err(FabricClientCreationError::InvalidFabricSecurityCredentials)?;
}
};
Ok(client)
}
pub struct FabricClientBuilder {
sn_handler: Option<IFabricServiceNotificationEventHandler>,
cc_handler: Option<LambdaClientConnectionNotificationHandler>,
client_role: ClientRole,
connection_strings: Option<Vec<crate::WString>>,
client_settings: Option<FabricClientSettings>,
client_credentials: Option<FabricSecurityCredentials>,
}
impl Default for FabricClientBuilder {
fn default() -> Self {
Self::new()
}
}
impl FabricClientBuilder {
pub fn new() -> Self {
Self {
sn_handler: None,
cc_handler: None,
client_role: ClientRole::Unknown,
connection_strings: None,
client_settings: None,
client_credentials: None,
}
}
fn with_service_notification_handler(
mut self,
handler: impl ServiceNotificationEventHandler,
) -> Self {
self.sn_handler = Some(ServiceNotificationEventHandlerBridge::new_com(handler));
self
}
pub fn with_on_service_notification<T>(self, f: T) -> Self
where
T: Fn(ServiceNotification) -> crate::Result<()> + 'static,
{
let handler = LambdaServiceNotificationHandler::new(f);
self.with_service_notification_handler(handler)
}
pub fn with_on_client_connect<T>(mut self, f: T) -> Self
where
T: Fn(&GatewayInformationResult) -> crate::Result<()> + 'static,
{
if self.cc_handler.is_none() {
self.cc_handler = Some(LambdaClientConnectionNotificationHandler::new());
}
if let Some(cc) = self.cc_handler.as_mut() {
cc.set_f_conn(f)
}
self
}
pub fn with_on_client_disconnect<T>(mut self, f: T) -> Self
where
T: Fn(&GatewayInformationResult) -> crate::Result<()> + 'static,
{
if self.cc_handler.is_none() {
self.cc_handler = Some(LambdaClientConnectionNotificationHandler::new());
}
if let Some(cc) = self.cc_handler.as_mut() {
cc.set_f_disconn(f)
}
self
}
pub fn with_client_role(mut self, role: ClientRole) -> Self {
self.client_role = role;
self
}
pub fn with_connection_strings(mut self, addrs: Vec<crate::WString>) -> Self {
self.connection_strings = Some(addrs);
self
}
pub fn with_client_settings(mut self, client_settings: FabricClientSettings) -> Self {
self.client_settings = Some(client_settings);
self
}
pub fn with_credentials(mut self, client_credentials: FabricSecurityCredentials) -> Self {
self.client_credentials = Some(client_credentials);
self
}
pub fn build(self) -> Result<FabricClient, FabricClientCreationError> {
let c = Self::build_interface(self)?;
Ok(FabricClient::from_com(c))
}
pub fn build_interface<T: Interface>(self) -> Result<T, FabricClientCreationError> {
let cc_handler = self
.cc_handler
.map(ClientConnectionEventHandlerBridge::new_com);
create_local_client_internal::<T>(
self.connection_strings.as_ref(),
self.sn_handler.as_ref(),
cc_handler.as_ref(),
Some(self.client_role),
self.client_settings,
self.client_credentials,
)
}
}
#[derive(Debug, Clone)]
pub struct FabricClient {
property_client: PropertyManagementClient,
service_client: ServiceManagementClient,
query_client: QueryClient,
health_client: HealthClient,
}
impl FabricClient {
pub fn builder() -> FabricClientBuilder {
FabricClientBuilder::new()
}
pub fn from_com(com: IFabricPropertyManagementClient2) -> Self {
let com_property_client = com.clone();
let com_service_client = com
.clone()
.cast::<IFabricServiceManagementClient6>()
.unwrap();
let com_query_client = com.clone().cast::<IFabricQueryClient10>().unwrap();
let com_health_client = com.clone().cast::<IFabricHealthClient4>().unwrap();
Self {
property_client: PropertyManagementClient::from(com_property_client),
service_client: ServiceManagementClient::from(com_service_client),
query_client: QueryClient::from(com_query_client),
health_client: HealthClient::from(com_health_client),
}
}
pub fn get_property_manager(&self) -> &PropertyManagementClient {
&self.property_client
}
pub fn get_query_manager(&self) -> &QueryClient {
&self.query_client
}
pub fn get_service_manager(&self) -> &ServiceManagementClient {
&self.service_client
}
pub fn get_health_manager(&self) -> &HealthClient {
&self.health_client
}
}