Skip to main content

mssf_core/client/
connection.rs

1// ------------------------------------------------------------
2// Copyright (c) Microsoft Corporation.  All rights reserved.
3// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
4// --------------------------------------------------
5
6use mssf_com::{
7    FabricClient::{
8        IFabricClientConnectionEventHandler, IFabricClientConnectionEventHandler_Impl,
9        IFabricClientConnectionEventHandler2, IFabricClientConnectionEventHandler2_Impl,
10        IFabricGatewayInformationResult,
11    },
12    FabricTypes::FABRIC_CLAIMS_RETRIEVAL_METADATA,
13};
14
15use crate::{WString, types::NodeId};
16
17/// Internal trait that rust code implements that can be bridged into IFabricClientConnectionEventHandler.
18/// Not exposed to user.
19pub trait ClientConnectionEventHandler: 'static {
20    fn on_connected(&self, info: &GatewayInformationResult) -> crate::Result<()>;
21    fn on_disconnected(&self, info: &GatewayInformationResult) -> crate::Result<()>;
22    fn on_claims_retrieval(&self, metadata: ClaimsRetrievalMetadata) -> crate::Result<WString>;
23}
24
25/// FabricClient connection information.
26/// Traslated from IFabricGatewayInformationResult
27#[derive(Debug, Clone)]
28pub struct GatewayInformationResult {
29    pub node_address: crate::WString,
30    pub node_id: NodeId,
31    pub node_instance_id: u64,
32    pub node_name: crate::WString,
33}
34
35impl From<&IFabricGatewayInformationResult> for GatewayInformationResult {
36    fn from(com: &IFabricGatewayInformationResult) -> Self {
37        let info = unsafe { com.get_GatewayInformation().as_ref().unwrap() };
38        Self {
39            node_address: WString::from(info.NodeAddress),
40            node_id: info.NodeId.into(),
41            node_instance_id: info.NodeInstanceId,
42            node_name: WString::from(info.NodeName),
43        }
44    }
45}
46
47/// Bridge for IFabricClientConnectionEventHandler.
48/// Turn rust trait into SF com object.
49#[windows_core::implement(IFabricClientConnectionEventHandler2)]
50pub struct ClientConnectionEventHandlerBridge<T>
51where
52    T: ClientConnectionEventHandler,
53{
54    inner: T,
55}
56
57impl<T> ClientConnectionEventHandlerBridge<T>
58where
59    T: ClientConnectionEventHandler,
60{
61    pub fn new(inner: T) -> Self {
62        Self { inner }
63    }
64    pub fn new_com(inner: T) -> IFabricClientConnectionEventHandler {
65        let h1: IFabricClientConnectionEventHandler2 = Self::new(inner).into();
66        use windows_core::Interface;
67        h1.cast().unwrap()
68    }
69}
70
71impl<T> IFabricClientConnectionEventHandler_Impl for ClientConnectionEventHandlerBridge_Impl<T>
72where
73    T: ClientConnectionEventHandler,
74{
75    fn OnConnected(
76        &self,
77        gw_info: windows_core::Ref<IFabricGatewayInformationResult>,
78    ) -> crate::WinResult<()> {
79        let info = GatewayInformationResult::from(gw_info.unwrap());
80        self.inner
81            .on_connected(&info)
82            .map_err(crate::WinError::from)
83    }
84
85    fn OnDisconnected(
86        &self,
87        gw_info: windows_core::Ref<IFabricGatewayInformationResult>,
88    ) -> crate::WinResult<()> {
89        let info = GatewayInformationResult::from(gw_info.unwrap());
90        self.inner
91            .on_disconnected(&info)
92            .map_err(crate::WinError::from)
93    }
94}
95
96impl<T> IFabricClientConnectionEventHandler2_Impl for ClientConnectionEventHandlerBridge_Impl<T>
97where
98    T: ClientConnectionEventHandler,
99{
100    fn OnClaimsRetrieval(
101        &self,
102        metadata: *const mssf_com::Microsoft::ServiceFabric::FabricTypes::FABRIC_CLAIMS_RETRIEVAL_METADATA,
103    ) -> crate::WinResult<mssf_com::Microsoft::ServiceFabric::FabricCommon::IFabricStringResult>
104    {
105        let meta = unsafe { metadata.as_ref().unwrap() };
106        let claims_meta = ClaimsRetrievalMetadata::from(meta);
107        let result = self
108            .inner
109            .on_claims_retrieval(claims_meta)
110            .map_err(crate::WinError::from)?;
111
112        let string_result = crate::strings::StringResult::new(result);
113        Ok(string_result.into())
114    }
115}
116
117/// Connection notification function signature to avoid code repeatition.
118/// Trait alias feature in rust (not yet stable) would eliminate this trait definition.
119pub trait ConnectionNotificationFn:
120    Fn(&GatewayInformationResult) -> crate::Result<()> + 'static
121{
122}
123impl<T: Fn(&GatewayInformationResult) -> crate::Result<()> + 'static> ConnectionNotificationFn
124    for T
125{
126}
127
128pub trait ClaimsRetrievalFn:
129    Fn(ClaimsRetrievalMetadata) -> crate::Result<WString> + 'static
130{
131}
132impl<T: Fn(ClaimsRetrievalMetadata) -> crate::Result<WString> + 'static> ClaimsRetrievalFn for T {}
133
134/// Lambda implementation of the ClientConnectionEventHandler trait.
135/// This is used in FabricClientBuilder to build handler from functions.
136pub struct LambdaClientConnectionNotificationHandler {
137    f_conn: Option<Box<dyn ConnectionNotificationFn>>,
138    f_disconn: Option<Box<dyn ConnectionNotificationFn>>,
139    f_claims: Option<Box<dyn ClaimsRetrievalFn>>,
140}
141
142impl LambdaClientConnectionNotificationHandler {
143    pub fn new() -> Self {
144        Self {
145            f_conn: None,
146            f_disconn: None,
147            f_claims: None,
148        }
149    }
150
151    /// Set the on_connected callback.
152    pub fn set_f_conn(&mut self, f: impl ConnectionNotificationFn) {
153        self.f_conn = Some(Box::new(f));
154    }
155
156    /// Set the on_disconnected callback.
157    pub fn set_f_disconn(&mut self, f: impl ConnectionNotificationFn) {
158        self.f_disconn = Some(Box::new(f));
159    }
160
161    /// Set the on_claims_retrieval callback.
162    pub fn set_f_claims(&mut self, f: impl ClaimsRetrievalFn) {
163        self.f_claims = Some(Box::new(f));
164    }
165}
166
167impl ClientConnectionEventHandler for LambdaClientConnectionNotificationHandler {
168    fn on_connected(&self, info: &GatewayInformationResult) -> crate::Result<()> {
169        if let Some(f) = &self.f_conn {
170            f(info)
171        } else {
172            Ok(())
173        }
174    }
175
176    fn on_disconnected(&self, info: &GatewayInformationResult) -> crate::Result<()> {
177        if let Some(f) = &self.f_disconn {
178            f(info)
179        } else {
180            Ok(())
181        }
182    }
183
184    fn on_claims_retrieval(&self, metadata: ClaimsRetrievalMetadata) -> crate::Result<WString> {
185        if let Some(f) = &self.f_claims {
186            f(metadata)
187        } else {
188            // Not implemented
189            Err(crate::ErrorCode::E_NOTIMPL.into())
190        }
191    }
192}
193
194/// FABRIC_AAD_CLAIMS_RETRIEVAL_METADATA
195#[derive(Debug, Clone, PartialEq)]
196pub struct AadClaimsRetrievalMetadata {
197    pub authority: WString,
198    pub tenant_id: WString,
199    pub cluster_application: WString,
200    pub client_application: WString,
201    pub client_redirect: WString,
202    // ex1
203    pub login_endpoint: WString,
204}
205
206/// FABRIC_CLAIMS_RETRIEVAL_METADATA
207#[derive(Debug, Clone, PartialEq)]
208pub enum ClaimsRetrievalMetadata {
209    AAD(AadClaimsRetrievalMetadata),
210    None,
211}
212
213impl From<&FABRIC_CLAIMS_RETRIEVAL_METADATA> for ClaimsRetrievalMetadata {
214    fn from(value: &FABRIC_CLAIMS_RETRIEVAL_METADATA) -> Self {
215        match value.Kind {
216            mssf_com::FabricTypes::FABRIC_CLAIMS_RETRIEVAL_METADATA_KIND_AAD => {
217                let aad_meta = unsafe {
218                    (value.Value
219                        as *const mssf_com::FabricTypes::FABRIC_AAD_CLAIMS_RETRIEVAL_METADATA)
220                        .as_ref()
221                        .unwrap()
222                };
223                let ex1 = unsafe {
224                    (aad_meta.Reserved
225                        as *const mssf_com::FabricTypes::FABRIC_AAD_CLAIMS_RETRIEVAL_METADATA_EX1)
226                        .as_ref()
227                };
228
229                ClaimsRetrievalMetadata::AAD(AadClaimsRetrievalMetadata {
230                    authority: WString::from(aad_meta.Authority),
231                    tenant_id: WString::from(aad_meta.TenantId),
232                    cluster_application: WString::from(aad_meta.ClusterApplication),
233                    client_application: WString::from(aad_meta.ClientApplication),
234                    client_redirect: WString::from(aad_meta.ClientRedirect),
235                    login_endpoint: ex1.map_or(WString::new(), |v| WString::from(v.LoginEndpoint)),
236                })
237            }
238            mssf_com::FabricTypes::FABRIC_CLAIMS_RETRIEVAL_METADATA_KIND_NONE => {
239                ClaimsRetrievalMetadata::None
240            }
241            _ => ClaimsRetrievalMetadata::None,
242        }
243    }
244}