mssf_core/client/
property_client.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 std::time::Duration;
7
8use crate::{
9    WString,
10    runtime::executor::BoxedCancelToken,
11    sync::{FabricReceiver, fabric_begin_end_proxy},
12    types::{NameEnumerationResult, PropertyMetadataResult, PropertyValueResult, Uri},
13};
14use mssf_com::{
15    FabricClient::{
16        IFabricNameEnumerationResult, IFabricPropertyBatchResult, IFabricPropertyEnumerationResult,
17        IFabricPropertyMetadataResult, IFabricPropertyValueResult,
18    },
19    FabricTypes::{FABRIC_PROPERTY_BATCH_OPERATION, FABRIC_PUT_CUSTOM_PROPERTY_OPERATION},
20};
21
22use mssf_com::FabricClient::IFabricPropertyManagementClient2;
23
24#[derive(Debug, Clone)]
25pub struct PropertyManagementClient {
26    com: IFabricPropertyManagementClient2,
27}
28
29impl From<IFabricPropertyManagementClient2> for PropertyManagementClient {
30    fn from(com: IFabricPropertyManagementClient2) -> Self {
31        Self { com }
32    }
33}
34
35impl From<PropertyManagementClient> for IFabricPropertyManagementClient2 {
36    fn from(value: PropertyManagementClient) -> Self {
37        value.com
38    }
39}
40
41impl PropertyManagementClient {
42    fn create_name_internal(
43        &self,
44        name: &Uri,
45        timeout_milliseconds: u32,
46        cancellation_token: Option<BoxedCancelToken>,
47    ) -> FabricReceiver<crate::WinResult<()>> {
48        let com1 = &self.com;
49        let com2 = self.com.clone();
50        fabric_begin_end_proxy(
51            move |callback| unsafe {
52                com1.BeginCreateName(name.as_raw(), timeout_milliseconds, callback)
53            },
54            move |ctx| unsafe { com2.EndCreateName(ctx) },
55            cancellation_token,
56        )
57    }
58
59    fn delete_name_internal(
60        &self,
61        name: &Uri,
62        timeout_milliseconds: u32,
63        cancellation_token: Option<BoxedCancelToken>,
64    ) -> FabricReceiver<crate::WinResult<()>> {
65        let com1 = &self.com;
66        let com2 = self.com.clone();
67        fabric_begin_end_proxy(
68            move |callback| unsafe {
69                com1.BeginDeleteName(name.as_raw(), timeout_milliseconds, callback)
70            },
71            move |ctx| unsafe { com2.EndDeleteName(ctx) },
72            cancellation_token,
73        )
74    }
75
76    fn name_exists_internal(
77        &self,
78        name: &Uri,
79        timeout_milliseconds: u32,
80        cancellation_token: Option<BoxedCancelToken>,
81    ) -> FabricReceiver<crate::WinResult<u8>> {
82        let com1 = &self.com;
83        let com2 = self.com.clone();
84        fabric_begin_end_proxy(
85            move |callback| unsafe {
86                com1.BeginNameExists(name.as_raw(), timeout_milliseconds, callback)
87            },
88            move |ctx| unsafe { com2.EndNameExists(ctx) },
89            cancellation_token,
90        )
91    }
92
93    fn enumerate_sub_names_internal(
94        &self,
95        name: &Uri,
96        prev: Option<&IFabricNameEnumerationResult>,
97        recursive: bool,
98        timeout_milliseconds: u32,
99        cancellation_token: Option<BoxedCancelToken>,
100    ) -> FabricReceiver<crate::WinResult<IFabricNameEnumerationResult>> {
101        let com1 = &self.com;
102        let com2 = self.com.clone();
103        fabric_begin_end_proxy(
104            move |callback| unsafe {
105                com1.BeginEnumerateSubNames(
106                    name.as_raw(),
107                    prev,
108                    recursive,
109                    timeout_milliseconds,
110                    callback,
111                )
112            },
113            move |ctx| unsafe { com2.EndEnumerateSubNames(ctx) },
114            cancellation_token,
115        )
116    }
117
118    fn put_property_binary_internal(
119        &self,
120        name: &Uri,
121        property_name: &WString,
122        data: &[u8],
123        timeout_milliseconds: u32,
124        cancellation_token: Option<BoxedCancelToken>,
125    ) -> FabricReceiver<crate::WinResult<()>> {
126        let com1 = &self.com;
127        let com2 = self.com.clone();
128        fabric_begin_end_proxy(
129            move |callback| unsafe {
130                com1.BeginPutPropertyBinary(
131                    name.as_raw(),
132                    property_name.as_pcwstr(),
133                    data,
134                    timeout_milliseconds,
135                    callback,
136                )
137            },
138            move |ctx| unsafe { com2.EndPutPropertyBinary(ctx) },
139            cancellation_token,
140        )
141    }
142
143    fn put_property_int64_internal(
144        &self,
145        name: &Uri,
146        property_name: &WString,
147        data: i64,
148        timeout_milliseconds: u32,
149        cancellation_token: Option<BoxedCancelToken>,
150    ) -> FabricReceiver<crate::WinResult<()>> {
151        let com1 = &self.com;
152        let com2 = self.com.clone();
153        fabric_begin_end_proxy(
154            move |callback| unsafe {
155                com1.BeginPutPropertyInt64(
156                    name.as_raw(),
157                    property_name.as_pcwstr(),
158                    data,
159                    timeout_milliseconds,
160                    callback,
161                )
162            },
163            move |ctx| unsafe { com2.EndPutPropertyInt64(ctx) },
164            cancellation_token,
165        )
166    }
167
168    fn put_property_double_internal(
169        &self,
170        name: &Uri,
171        property_name: &WString,
172        data: f64,
173        timeout_milliseconds: u32,
174        cancellation_token: Option<BoxedCancelToken>,
175    ) -> FabricReceiver<crate::WinResult<()>> {
176        let com1 = &self.com;
177        let com2 = self.com.clone();
178        fabric_begin_end_proxy(
179            move |callback| unsafe {
180                com1.BeginPutPropertyDouble(
181                    name.as_raw(),
182                    property_name.as_pcwstr(),
183                    data,
184                    timeout_milliseconds,
185                    callback,
186                )
187            },
188            move |ctx| unsafe { com2.EndPutPropertyDouble(ctx) },
189            cancellation_token,
190        )
191    }
192
193    fn put_property_wstring_internal(
194        &self,
195        name: &Uri,
196        property_name: &WString,
197        data: &WString,
198        timeout_milliseconds: u32,
199        cancellation_token: Option<BoxedCancelToken>,
200    ) -> FabricReceiver<crate::WinResult<()>> {
201        let com1 = &self.com;
202        let com2 = self.com.clone();
203        fabric_begin_end_proxy(
204            move |callback| unsafe {
205                com1.BeginPutPropertyWString(
206                    name.as_raw(),
207                    property_name.as_pcwstr(),
208                    data.as_pcwstr(),
209                    timeout_milliseconds,
210                    callback,
211                )
212            },
213            move |ctx| unsafe { com2.EndPutPropertyWString(ctx) },
214            cancellation_token,
215        )
216    }
217
218    fn put_property_guid_internal(
219        &self,
220        name: &Uri,
221        property_name: &WString,
222        data: &windows_core::GUID,
223        timeout_milliseconds: u32,
224        cancellation_token: Option<BoxedCancelToken>,
225    ) -> FabricReceiver<crate::WinResult<()>> {
226        let com1 = &self.com;
227        let com2 = self.com.clone();
228        fabric_begin_end_proxy(
229            move |callback| unsafe {
230                com1.BeginPutPropertyGuid(
231                    name.as_raw(),
232                    property_name.as_pcwstr(),
233                    data,
234                    timeout_milliseconds,
235                    callback,
236                )
237            },
238            move |ctx| unsafe { com2.EndPutPropertyGuid(ctx) },
239            cancellation_token,
240        )
241    }
242
243    fn delete_property_internal(
244        &self,
245        name: &Uri,
246        property_name: &WString,
247        timeout_milliseconds: u32,
248        cancellation_token: Option<BoxedCancelToken>,
249    ) -> FabricReceiver<crate::WinResult<()>> {
250        let com1 = &self.com;
251        let com2 = self.com.clone();
252        fabric_begin_end_proxy(
253            move |callback| unsafe {
254                com1.BeginDeleteProperty(
255                    name.as_raw(),
256                    property_name.as_pcwstr(),
257                    timeout_milliseconds,
258                    callback,
259                )
260            },
261            move |ctx| unsafe { com2.EndDeleteProperty(ctx) },
262            cancellation_token,
263        )
264    }
265
266    fn get_property_metadata_internal(
267        &self,
268        name: &Uri,
269        property_name: &WString,
270        timeout_milliseconds: u32,
271        cancellation_token: Option<BoxedCancelToken>,
272    ) -> FabricReceiver<crate::WinResult<IFabricPropertyMetadataResult>> {
273        let com1 = &self.com;
274        let com2 = self.com.clone();
275        fabric_begin_end_proxy(
276            move |callback| unsafe {
277                com1.BeginGetPropertyMetadata(
278                    name.as_raw(),
279                    property_name.as_pcwstr(),
280                    timeout_milliseconds,
281                    callback,
282                )
283            },
284            move |ctx| unsafe { com2.EndGetPropertyMetadata(ctx) },
285            cancellation_token,
286        )
287    }
288
289    fn get_property_internal(
290        &self,
291        name: &Uri,
292        property_name: &WString,
293        timeout_milliseconds: u32,
294        cancellation_token: Option<BoxedCancelToken>,
295    ) -> FabricReceiver<crate::WinResult<IFabricPropertyValueResult>> {
296        let com1 = &self.com;
297        let com2 = self.com.clone();
298        fabric_begin_end_proxy(
299            move |callback| unsafe {
300                com1.BeginGetProperty(
301                    name.as_raw(),
302                    property_name.as_pcwstr(),
303                    timeout_milliseconds,
304                    callback,
305                )
306            },
307            move |ctx| unsafe { com2.EndGetProperty(ctx) },
308            cancellation_token,
309        )
310    }
311
312    // TODO: implement this
313    // Batch operations are not supported yet.
314    #[allow(dead_code)]
315    fn submit_property_batch_internal(
316        &self,
317        name: &Uri,
318        batch: &[FABRIC_PROPERTY_BATCH_OPERATION],
319        timeout_milliseconds: u32,
320        cancellation_token: Option<BoxedCancelToken>,
321    ) -> FabricReceiver<crate::WinResult<(u32, IFabricPropertyBatchResult)>> {
322        let com1 = &self.com;
323        let com2 = self.com.clone();
324        fabric_begin_end_proxy(
325            move |callback| unsafe {
326                com1.BeginSubmitPropertyBatch(name.as_raw(), batch, timeout_milliseconds, callback)
327            },
328            move |ctx| unsafe {
329                let mut failed_operation_index_in_request = 0;
330                let result =
331                    com2.EndSubmitPropertyBatch(ctx, &mut failed_operation_index_in_request);
332                result.map(|res| (failed_operation_index_in_request, res))
333            },
334            cancellation_token,
335        )
336    }
337
338    // TODO: implement this
339    #[allow(dead_code)]
340    fn enumerate_properties_internal(
341        &self,
342        name: &Uri,
343        include_values: bool,
344        prev: Option<&IFabricPropertyEnumerationResult>,
345        timeout_milliseconds: u32,
346        cancellation_token: Option<BoxedCancelToken>,
347    ) -> FabricReceiver<crate::WinResult<IFabricPropertyEnumerationResult>> {
348        let com1 = &self.com;
349        let com2 = self.com.clone();
350        fabric_begin_end_proxy(
351            move |callback| unsafe {
352                com1.BeginEnumerateProperties(
353                    name.as_raw(),
354                    include_values,
355                    prev,
356                    timeout_milliseconds,
357                    callback,
358                )
359            },
360            move |ctx| unsafe { com2.EndEnumerateProperties(ctx) },
361            cancellation_token,
362        )
363    }
364
365    // TODO: implement this
366    #[allow(dead_code)]
367    fn put_custom_property_operation_internal(
368        &self,
369        name: &Uri,
370        property_operation: &FABRIC_PUT_CUSTOM_PROPERTY_OPERATION,
371        timeout_milliseconds: u32,
372        cancellation_token: Option<BoxedCancelToken>,
373    ) -> FabricReceiver<crate::WinResult<()>> {
374        let com1 = &self.com;
375        let com2 = self.com.clone();
376        fabric_begin_end_proxy(
377            move |callback| unsafe {
378                com1.BeginPutCustomPropertyOperation(
379                    name.as_raw(),
380                    property_operation,
381                    timeout_milliseconds,
382                    callback,
383                )
384            },
385            move |ctx| unsafe { com2.EndPutCustomPropertyOperation(ctx) },
386            cancellation_token,
387        )
388    }
389}
390
391impl PropertyManagementClient {
392    /// Creates a SF name in Naming Service.
393    /// Provisioned app and service will automatically create names:
394    /// For example, fabric:/myapp/mysvc service will create 2 names in the same hierarchy:
395    /// - fabric:/myapp
396    /// - fabric:/myapp/mysvc
397    ///
398    /// One can create names not related to any app or service as well.
399    pub async fn create_name(
400        &self,
401        name: &Uri,
402        timeout: Duration,
403        cancellation_token: Option<BoxedCancelToken>,
404    ) -> crate::Result<()> {
405        self.create_name_internal(
406            name,
407            timeout.as_millis().try_into().unwrap(),
408            cancellation_token,
409        )
410        .await??;
411        Ok(())
412    }
413
414    /// Deletes a SF name from Naming Service.
415    /// All properties needs to be deleted first before this call,
416    /// otherwise it will fail.
417    pub async fn delete_name(
418        &self,
419        name: &Uri,
420        timeout: Duration,
421        cancellation_token: Option<BoxedCancelToken>,
422    ) -> crate::Result<()> {
423        self.delete_name_internal(
424            name,
425            timeout.as_millis().try_into().unwrap(),
426            cancellation_token,
427        )
428        .await??;
429        Ok(())
430    }
431
432    /// Checks if a SF name exists in Naming Service.
433    pub async fn name_exists(
434        &self,
435        name: &Uri,
436        timeout: Duration,
437        cancellation_token: Option<BoxedCancelToken>,
438    ) -> crate::Result<bool> {
439        self.name_exists_internal(
440            name,
441            timeout.as_millis().try_into().unwrap(),
442            cancellation_token,
443        )
444        .await?
445        .map_err(|e| e.into())
446        .map(|exist| exist != 0)
447    }
448
449    /// Enumerates sub-names of a SF name in Naming Service.
450    /// For example, if you have a name `fabric:/myapp`,
451    /// it will return all sub-names like:
452    /// - fabric:/myapp/mysvc1
453    pub async fn enumerate_sub_names(
454        &self,
455        name: &Uri,
456        prev: Option<&NameEnumerationResult>,
457        recursive: bool,
458        timeout: Duration,
459        cancellation_token: Option<BoxedCancelToken>,
460    ) -> crate::Result<NameEnumerationResult> {
461        self.enumerate_sub_names_internal(
462            name,
463            prev.map(|x| x.as_com()),
464            recursive,
465            timeout.as_millis().try_into().unwrap(),
466            cancellation_token,
467        )
468        .await?
469        .map_err(|e| e.into())
470        .map(NameEnumerationResult::from_com)
471    }
472
473    /// Put a binary property to a SF name.
474    pub async fn put_property_binary(
475        &self,
476        name: &Uri,
477        property_name: &WString,
478        data: &[u8],
479        timeout: Duration,
480        cancellation_token: Option<BoxedCancelToken>,
481    ) -> crate::Result<()> {
482        self.put_property_binary_internal(
483            name,
484            property_name,
485            data,
486            timeout.as_millis().try_into().unwrap(),
487            cancellation_token,
488        )
489        .await??;
490        Ok(())
491    }
492
493    /// Put a double property to a SF name.
494    pub async fn put_property_double(
495        &self,
496        name: &Uri,
497        property_name: &WString,
498        data: f64,
499        timeout: Duration,
500        cancellation_token: Option<BoxedCancelToken>,
501    ) -> crate::Result<()> {
502        self.put_property_double_internal(
503            name,
504            property_name,
505            data,
506            timeout.as_millis().try_into().unwrap(),
507            cancellation_token,
508        )
509        .await??;
510        Ok(())
511    }
512
513    /// Put an int64 property to a SF name.
514    pub async fn put_property_int64(
515        &self,
516        name: &Uri,
517        property_name: &WString,
518        data: i64,
519        timeout: Duration,
520        cancellation_token: Option<BoxedCancelToken>,
521    ) -> crate::Result<()> {
522        self.put_property_int64_internal(
523            name,
524            property_name,
525            data,
526            timeout.as_millis().try_into().unwrap(),
527            cancellation_token,
528        )
529        .await??;
530        Ok(())
531    }
532
533    /// Put a wstring property to a SF name.
534    pub async fn put_property_wstring(
535        &self,
536        name: &Uri,
537        property_name: &WString,
538        data: &WString,
539        timeout: Duration,
540        cancellation_token: Option<BoxedCancelToken>,
541    ) -> crate::Result<()> {
542        self.put_property_wstring_internal(
543            name,
544            property_name,
545            data,
546            timeout.as_millis().try_into().unwrap(),
547            cancellation_token,
548        )
549        .await??;
550        Ok(())
551    }
552
553    /// Put a GUID property to a SF name.
554    pub async fn put_property_guid(
555        &self,
556        name: &Uri,
557        property_name: &WString,
558        data: &windows_core::GUID,
559        timeout: Duration,
560        cancellation_token: Option<BoxedCancelToken>,
561    ) -> crate::Result<()> {
562        self.put_property_guid_internal(
563            name,
564            property_name,
565            data,
566            timeout.as_millis().try_into().unwrap(),
567            cancellation_token,
568        )
569        .await??;
570        Ok(())
571    }
572
573    /// Deletes a property from a SF name.
574    pub async fn delete_property(
575        &self,
576        name: &Uri,
577        property_name: &WString,
578        timeout: Duration,
579        cancellation_token: Option<BoxedCancelToken>,
580    ) -> crate::Result<()> {
581        self.delete_property_internal(
582            name,
583            property_name,
584            timeout.as_millis().try_into().unwrap(),
585            cancellation_token,
586        )
587        .await??;
588        Ok(())
589    }
590
591    /// Gets metadata of a property from a SF name.
592    pub async fn get_property_metadata(
593        &self,
594        name: &Uri,
595        property_name: &WString,
596        timeout: Duration,
597        cancellation_token: Option<BoxedCancelToken>,
598    ) -> crate::Result<PropertyMetadataResult> {
599        self.get_property_metadata_internal(
600            name,
601            property_name,
602            timeout.as_millis().try_into().unwrap(),
603            cancellation_token,
604        )
605        .await?
606        .map_err(|e| e.into())
607        .map(PropertyMetadataResult::from_com)
608    }
609
610    /// Gets a property value from a SF name.
611    pub async fn get_property(
612        &self,
613        name: &Uri,
614        property_name: &WString,
615        timeout: Duration,
616        cancellation_token: Option<BoxedCancelToken>,
617    ) -> crate::Result<PropertyValueResult> {
618        self.get_property_internal(
619            name,
620            property_name,
621            timeout.as_millis().try_into().unwrap(),
622            cancellation_token,
623        )
624        .await?
625        .map_err(|e| e.into())
626        .map(PropertyValueResult::from_com)
627    }
628}