Skip to content

Commit

Permalink
support callback interface
Browse files Browse the repository at this point in the history
  • Loading branch information
youyuanwu committed Sep 6, 2024
1 parent 9d611b8 commit e9eb0ea
Show file tree
Hide file tree
Showing 7 changed files with 343 additions and 31 deletions.
94 changes: 94 additions & 0 deletions crates/libs/core/src/client/connection.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
// --------------------------------------------------

use mssf_com::FabricClient::{
IFabricClientConnectionEventHandler, IFabricClientConnectionEventHandler_Impl,
IFabricGatewayInformationResult,
};

use crate::{strings::HSTRINGWrap, types::NodeId};

pub trait ClientConnectionEventHandler: 'static {
fn on_connected(&self, info: &GatewayInformationResult) -> crate::Result<()>;
fn on_disconnected(&self, info: &GatewayInformationResult) -> crate::Result<()>;
}

// IFabricGatewayInformationResult
#[derive(Debug, Clone)]
pub struct GatewayInformationResult {
pub node_address: crate::HSTRING,
pub node_id: NodeId,
pub node_instance_id: u64,
pub node_name: crate::HSTRING,
}

impl GatewayInformationResult {
fn from_com(com: &IFabricGatewayInformationResult) -> Self {
let info = unsafe { com.get_GatewayInformation().as_ref().unwrap() };
Self {
node_address: HSTRINGWrap::from(info.NodeAddress).into(),
node_id: info.NodeId.into(),
node_instance_id: info.NodeInstanceId,
node_name: HSTRINGWrap::from(info.NodeName).into(),
}
}
}

// IFabricClientConnectionEventHandler
#[windows_core::implement(IFabricClientConnectionEventHandler)]
pub struct ClientConnectionEventHandlerBridge<T>
where
T: ClientConnectionEventHandler,
{
inner: T,
}

impl<T> ClientConnectionEventHandlerBridge<T>
where
T: ClientConnectionEventHandler,
{
pub fn new(inner: T) -> Self {
Self { inner }
}
pub fn new_com(inner: T) -> IFabricClientConnectionEventHandler {
Self::new(inner).into()
}
}

impl<T> IFabricClientConnectionEventHandler_Impl for ClientConnectionEventHandlerBridge<T>
where
T: ClientConnectionEventHandler,
{
fn OnConnected(
&self,
gw_info: Option<&IFabricGatewayInformationResult>,
) -> windows_core::Result<()> {
let info = GatewayInformationResult::from_com(gw_info.unwrap());
self.inner.on_connected(&info)
}

fn OnDisconnected(
&self,
gw_info: Option<&IFabricGatewayInformationResult>,
) -> windows_core::Result<()> {
let info = GatewayInformationResult::from_com(gw_info.unwrap());
self.inner.on_disconnected(&info)
}
}

// Default implementation of ClientConnectionEventHandler
pub struct DefaultClientConnectionEventHandler {}

impl ClientConnectionEventHandler for DefaultClientConnectionEventHandler {
fn on_connected(&self, info: &GatewayInformationResult) -> crate::Result<()> {
tracing::debug!("on_connected: {:?}", info);
Ok(())
}

fn on_disconnected(&self, info: &GatewayInformationResult) -> crate::Result<()> {
tracing::debug!("on_disconnected: {:?}", info);
Ok(())
}
}
56 changes: 54 additions & 2 deletions crates/libs/core/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,71 @@
// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
// ------------------------------------------------------------

use connection::{
ClientConnectionEventHandler, ClientConnectionEventHandlerBridge,
DefaultClientConnectionEventHandler,
};
use mssf_com::FabricClient::{
IFabricPropertyManagementClient2, IFabricQueryClient10, IFabricServiceManagementClient6,
FabricCreateLocalClient4, IFabricPropertyManagementClient2, IFabricQueryClient10,
IFabricServiceManagementClient6,
};
use notification::{
DefaultServiceNotificationEventHandler, ServiceNotificationEventHandler,
ServiceNotificationEventHandlerBridge,
};
use windows_core::Interface;

use crate::types::ClientRole;

use self::{query_client::QueryClient, svc_mgmt_client::ServiceManagementClient};

mod connection;
mod notification;
pub mod query_client;
pub mod svc_mgmt_client;

#[cfg(test)]
mod tests;

// Fabric Client creation
// Creates the local client
pub fn create_local_client<T: Interface>(
service_notification_handler: Option<impl ServiceNotificationEventHandler>,
client_connection_handler: Option<impl ClientConnectionEventHandler>,
client_role: Option<ClientRole>,
) -> T {
let sn_handler =
service_notification_handler.map(|sn| ServiceNotificationEventHandlerBridge::new_com(sn));
let cc_handler =
client_connection_handler.map(|cc| ClientConnectionEventHandlerBridge::new_com(cc));
let role = client_role.unwrap_or(ClientRole::User);
assert_ne!(
role,
ClientRole::Unknown,
"Unknown role should not be used."
);
let raw = unsafe {
FabricCreateLocalClient4(
sn_handler.as_ref(),
cc_handler.as_ref(),
role.into(),
&T::IID,
)
}
.expect("failed to create fabric client");
// if params are right, client should be created. There is no network call involved during obj creation.
unsafe { T::from_raw(raw) }
}

// Used for convenience.
pub(crate) fn create_local_client_default<T: Interface>() -> T {
create_local_client::<T>(
None::<DefaultServiceNotificationEventHandler>,
None::<DefaultClientConnectionEventHandler>,
None,
)
}

// FabricClient safe wrapper
// The design of FabricClient follows from the csharp client:
// https://github.com/microsoft/service-fabric/blob/master/src/prod/src/managed/Api/src/System/Fabric/FabricClient.cs
Expand All @@ -34,7 +86,7 @@ impl Default for FabricClient {

impl FabricClient {
pub fn new() -> Self {
let com = crate::sync::CreateLocalClient::<IFabricPropertyManagementClient2>();
let com = create_local_client_default::<IFabricPropertyManagementClient2>();
Self::from_com(com)
}

Expand Down
136 changes: 136 additions & 0 deletions crates/libs/core/src/client/notification.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
// ------------------------------------------------------------

use mssf_com::{
FabricClient::{
IFabricServiceEndpointsVersion, IFabricServiceNotification,
IFabricServiceNotificationEventHandler, IFabricServiceNotificationEventHandler_Impl,
},
FabricTypes::FABRIC_RESOLVED_SERVICE_ENDPOINT,
};

use crate::{
iter::{FabricIter, FabricListAccessor},
types::ServicePartitionInformation,
};

use super::svc_mgmt_client::ResolvedServiceEndpoint;

pub trait ServiceNotificationEventHandler: 'static {
fn on_notification(&self, notification: &ServiceNotification) -> crate::Result<()>;
}

#[derive(Debug, Clone)]
pub struct ServiceNotification {
pub partition_info: ServicePartitionInformation,
pub partition_id: crate::GUID,
pub endpoints: ServiceEndpointList,
com: IFabricServiceNotification,
}

impl ServiceNotification {
fn from_com(com: IFabricServiceNotification) -> Self {
let raw = unsafe { com.get_Notification().as_ref().unwrap() };
Self {
partition_info: unsafe { raw.PartitionInfo.as_ref().unwrap().into() },
partition_id: raw.PartitionId,
endpoints: ServiceEndpointList { com: com.clone() },
com,
}
}

pub fn get_version(&self) -> crate::Result<ServiceEndpointsVersion> {
let version = unsafe { self.com.GetVersion() }?;
Ok(ServiceEndpointsVersion::from_com(version))
}
}

#[derive(Debug, Clone)]
pub struct ServiceEndpointList {
com: IFabricServiceNotification,
}

impl ServiceEndpointList {
// Get iterator for the list
pub fn iter(&self) -> ServiceEndpointListIter {
ServiceEndpointListIter::new(self, self)
}
}

impl FabricListAccessor<FABRIC_RESOLVED_SERVICE_ENDPOINT> for ServiceEndpointList {
fn get_count(&self) -> u32 {
let raw = unsafe { self.com.get_Notification().as_ref().unwrap() };
raw.EndpointCount
}

fn get_first_item(&self) -> *const FABRIC_RESOLVED_SERVICE_ENDPOINT {
let raw = unsafe { self.com.get_Notification().as_ref().unwrap() };
raw.Endpoints
}
}

type ServiceEndpointListIter<'a> =
FabricIter<'a, FABRIC_RESOLVED_SERVICE_ENDPOINT, ResolvedServiceEndpoint, ServiceEndpointList>;

pub struct ServiceEndpointsVersion {
com: IFabricServiceEndpointsVersion,
}

impl ServiceEndpointsVersion {
fn from_com(com: IFabricServiceEndpointsVersion) -> Self {
Self { com }
}

/// TODO: documentation.
pub fn compare(&self, other: &ServiceEndpointsVersion) -> crate::Result<i32> {
unsafe { self.com.Compare(&other.com) }
}
}

// Bridge implementation for the notification handler
#[windows_core::implement(IFabricServiceNotificationEventHandler)]
pub struct ServiceNotificationEventHandlerBridge<T>
where
T: ServiceNotificationEventHandler,
{
inner: T,
}

impl<T> ServiceNotificationEventHandlerBridge<T>
where
T: ServiceNotificationEventHandler,
{
pub fn new(inner: T) -> Self {
Self { inner }
}

pub fn new_com(inner: T) -> IFabricServiceNotificationEventHandler {
Self::new(inner).into()
}
}

impl<T> IFabricServiceNotificationEventHandler_Impl for ServiceNotificationEventHandlerBridge<T>
where
T: ServiceNotificationEventHandler,
{
fn OnNotification(
&self,
notification: Option<&IFabricServiceNotification>,
) -> crate::Result<()> {
let com = notification.unwrap();
let msg = ServiceNotification::from_com(com.to_owned());
self.inner.on_notification(&msg)
}
}

// default implementation of ServiceNotificationEventHandler
pub struct DefaultServiceNotificationEventHandler {}

impl ServiceNotificationEventHandler for DefaultServiceNotificationEventHandler {
fn on_notification(&self, notification: &ServiceNotification) -> crate::Result<()> {
tracing::debug!("Got service notification {:?}", notification);
Ok(())
}
}
12 changes: 2 additions & 10 deletions crates/libs/core/src/runtime/node_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use windows_core::{Interface, HSTRING};
use crate::{
strings::HSTRINGWrap,
sync::{fabric_begin_end_proxy2, CancellationToken},
types::NodeId,
};

pub fn get_com_node_context(
Expand All @@ -27,12 +28,6 @@ pub fn get_com_node_context(
)
}

#[derive(Debug)]
pub struct NodeId {
pub low: u64,
pub high: u64,
}

#[derive(Debug)]
pub struct NodeContext {
com: IFabricNodeContextResult,
Expand Down Expand Up @@ -81,10 +76,7 @@ impl From<&IFabricNodeContextResult> for NodeContext {
node_type: HSTRINGWrap::from(raw_ref.NodeType).into(),
ip_address_or_fqdn: HSTRINGWrap::from(raw_ref.IPAddressOrFQDN).into(),
node_instance_id: raw_ref.NodeInstanceId,
node_id: NodeId {
low: raw_ref.NodeId.Low,
high: raw_ref.NodeId.High,
},
node_id: raw_ref.NodeId.into(),
}
}
}
Loading

0 comments on commit e9eb0ea

Please sign in to comment.