mssf_core/types/client/
service.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
6#![cfg_attr(
7    not(feature = "tokio_async"),
8    allow(dead_code, reason = "code configured out")
9)]
10
11use std::{ffi::c_void, marker::PhantomData};
12
13use mssf_com::FabricTypes::{
14    FABRIC_NAMED_REPARTITION_DESCRIPTION, FABRIC_SERVICE_DESCRIPTION,
15    FABRIC_SERVICE_DESCRIPTION_KIND_STATEFUL, FABRIC_SERVICE_DESCRIPTION_KIND_STATELESS,
16    FABRIC_SERVICE_PARTITION_KIND, FABRIC_SERVICE_PARTITION_KIND_INVALID,
17    FABRIC_SERVICE_PARTITION_KIND_NAMED, FABRIC_SERVICE_UPDATE_DESCRIPTION,
18    FABRIC_STATEFUL_SERVICE_DESCRIPTION, FABRIC_STATEFUL_SERVICE_DESCRIPTION_EX1,
19    FABRIC_STATEFUL_SERVICE_DESCRIPTION_EX2, FABRIC_STATEFUL_SERVICE_DESCRIPTION_EX3,
20    FABRIC_STATEFUL_SERVICE_DESCRIPTION_EX4, FABRIC_STATEFUL_SERVICE_UPDATE_DESCRIPTION,
21    FABRIC_STATEFUL_SERVICE_UPDATE_DESCRIPTION_EX1, FABRIC_STATEFUL_SERVICE_UPDATE_DESCRIPTION_EX2,
22    FABRIC_STATEFUL_SERVICE_UPDATE_DESCRIPTION_EX3, FABRIC_STATEFUL_SERVICE_UPDATE_DESCRIPTION_EX4,
23    FABRIC_STATEFUL_SERVICE_UPDATE_DESCRIPTION_EX5, FABRIC_STATELESS_SERVICE_DESCRIPTION,
24    FABRIC_STATELESS_SERVICE_DESCRIPTION_EX1, FABRIC_STATELESS_SERVICE_DESCRIPTION_EX2,
25    FABRIC_STATELESS_SERVICE_DESCRIPTION_EX3, FABRIC_STATELESS_SERVICE_DESCRIPTION_EX4,
26    FABRIC_STATELESS_SERVICE_UPDATE_DESCRIPTION, FABRIC_STATELESS_SERVICE_UPDATE_DESCRIPTION_EX1,
27    FABRIC_STATELESS_SERVICE_UPDATE_DESCRIPTION_EX2,
28    FABRIC_STATELESS_SERVICE_UPDATE_DESCRIPTION_EX3, FABRIC_URI,
29};
30use windows_core::{WString, PCWSTR};
31
32use crate::types::{MoveCost, PartitionSchemeDescription, ServicePackageActivationMode, Uri};
33
34pub enum ServiceDescription {
35    // Invalid,
36    Stateful(StatefulServiceDescription), // FABRIC_STATEFUL_SERVICE_DESCRIPTION
37    Stateless(StatelessServiceDescription), // FABRIC_STATELESS_SERVICE_DESCRIPTION
38}
39
40#[derive(Debug)]
41pub struct StatefulServiceDescription {
42    // common
43    // Note: if application_name is not set, SF com api will succeed but the service does not show up in the SF explorer.
44    // May need to file a bug with SF team.
45    application_name: Uri,
46    service_name: Uri,
47    service_type_name: WString,
48    initialization_data: Option<Vec<u8>>,
49    partition_scheme: PartitionSchemeDescription,
50    // stateful
51    min_replica_set_size: i32,
52    target_replica_set_size: i32,
53    // common
54    placement_contraints: WString,
55    _correlations: Vec<WString>, // TODO: FABRIC_SERVICE_CORRELATION_DESCRIPTION
56    _metrics: Vec<WString>,      // TODO: FABRIC_SERVICE_LOAD_METRIC_DESCRIPTION
57    has_persistent_state: bool,
58    // ex1
59    _policy_list: Vec<WString>, // TODO: FABRIC_SERVICE_PLACEMENT_POLICY_DESCRIPTION
60    _failover_settings: WString, // TODO: FABRIC_SERVICE_PARTITION_KIND
61    // ex2
62    default_move_cost: Option<MoveCost>, // TODO: FABRIC_MOVE_COST
63    // ex3
64    service_package_activation_mode: ServicePackageActivationMode,
65    _service_dns_name: Option<WString>, // TODO: FABRIC_SERVICE_DNS_NAME
66    // ex4
67    _service_scaling_policys: Vec<WString>, // TODO: FABRIC_SERVICE_SCALING_POLICY
68}
69
70impl StatefulServiceDescription {
71    /// Following the csharp validator code:
72    /// The required fields are here, but optional fields can be set by other setters.
73    pub fn new(
74        application_name: Uri,
75        service_name: Uri,
76        service_type_name: WString,
77        partition_scheme: PartitionSchemeDescription,
78    ) -> Self {
79        Self {
80            application_name,
81            service_name,
82            service_type_name,
83            initialization_data: None,
84            partition_scheme,
85            min_replica_set_size: 1,
86            target_replica_set_size: 1,
87            placement_contraints: WString::default(),
88            _correlations: Vec::new(),
89            _metrics: Vec::new(),
90            has_persistent_state: false,
91            _policy_list: Vec::new(),
92            _failover_settings: WString::default(),
93            default_move_cost: None,
94            service_package_activation_mode: ServicePackageActivationMode::default(),
95            _service_dns_name: None,
96            _service_scaling_policys: Vec::new(),
97        }
98    }
99
100    // TODO: add more setters for the fields.
101
102    pub fn with_initialization_data(mut self, initialization_data: Vec<u8>) -> Self {
103        self.initialization_data = Some(initialization_data);
104        self
105    }
106
107    pub fn with_min_replica_set_size(mut self, min_replica_set_size: i32) -> Self {
108        self.min_replica_set_size = min_replica_set_size;
109        self
110    }
111    pub fn with_target_replica_set_size(mut self, target_replica_set_size: i32) -> Self {
112        self.target_replica_set_size = target_replica_set_size;
113        self
114    }
115    pub fn with_has_persistent_state(mut self, has_persistent_state: bool) -> Self {
116        self.has_persistent_state = has_persistent_state;
117        self
118    }
119
120    pub fn with_default_move_cost(mut self, default_move_cost: MoveCost) -> Self {
121        self.default_move_cost = Some(default_move_cost);
122        self
123    }
124    pub fn with_service_activation_mode(
125        mut self,
126        service_package_activation_mode: ServicePackageActivationMode,
127    ) -> Self {
128        self.service_package_activation_mode = service_package_activation_mode;
129        self
130    }
131}
132
133pub(crate) struct StatefulServiceDescriptionRaw<'a> {
134    internal: Box<FABRIC_STATEFUL_SERVICE_DESCRIPTION>,
135    _internal_ex1: Box<FABRIC_STATEFUL_SERVICE_DESCRIPTION_EX1>,
136    _internal_ex2: Box<FABRIC_STATEFUL_SERVICE_DESCRIPTION_EX2>,
137    _internal_ex3: Box<FABRIC_STATEFUL_SERVICE_DESCRIPTION_EX3>,
138    _internal_ex4: Box<FABRIC_STATEFUL_SERVICE_DESCRIPTION_EX4>,
139    phantom: PhantomData<&'a StatefulServiceDescription>,
140}
141
142impl StatefulServiceDescriptionRaw<'_> {
143    pub fn as_ffi(&self) -> &FABRIC_STATEFUL_SERVICE_DESCRIPTION {
144        self.internal.as_ref()
145    }
146}
147
148impl StatefulServiceDescription {
149    // Initializes the internal struct
150    fn build_raw(&self) -> StatefulServiceDescriptionRaw {
151        let ex4 = Box::new(FABRIC_STATEFUL_SERVICE_DESCRIPTION_EX4 {
152            ServiceScalingPolicies: std::ptr::null_mut(), // TODO: support scaling policies
153            ScalingPolicyCount: 0,
154            Reserved: std::ptr::null_mut(),
155        });
156        let ex3 = Box::new(FABRIC_STATEFUL_SERVICE_DESCRIPTION_EX3 {
157            ServiceDnsName: windows_core::PCWSTR::null(), // TODO: FABRIC_SERVICE_DNS_NAME
158            ServicePackageActivationMode: self.service_package_activation_mode.clone().into(),
159            Reserved: ex4.as_ref() as *const _ as *mut c_void,
160        });
161        let ex2 = Box::new(FABRIC_STATEFUL_SERVICE_DESCRIPTION_EX2 {
162            IsDefaultMoveCostSpecified: self.default_move_cost.is_some(),
163            DefaultMoveCost: self
164                .default_move_cost
165                .clone()
166                .unwrap_or(MoveCost::Zero)
167                .into(),
168            Reserved: ex3.as_ref() as *const _ as *mut c_void,
169        });
170        let ex1 = Box::new(FABRIC_STATEFUL_SERVICE_DESCRIPTION_EX1 {
171            PolicyList: std::ptr::null_mut(),       // TODO:
172            FailoverSettings: std::ptr::null_mut(), // TODO:
173            Reserved: ex2.as_ref() as *const _ as *mut c_void,
174        });
175
176        let (init_data, init_data_len) = self
177            .initialization_data
178            .as_ref()
179            .map(|v| (v.as_ptr() as *mut u8, v.len() as u32))
180            .unwrap_or((std::ptr::null_mut(), 0));
181
182        let internal = Box::new(FABRIC_STATEFUL_SERVICE_DESCRIPTION {
183            ApplicationName: self.application_name.as_raw(),
184            ServiceName: self.service_name.as_raw(),
185            ServiceTypeName: self.service_type_name.as_pcwstr(),
186            InitializationDataSize: init_data_len,
187            InitializationData: init_data,
188            PartitionScheme: self.partition_scheme.as_raw().0,
189            PartitionSchemeDescription: self.partition_scheme.as_raw().1,
190            TargetReplicaSetSize: self.target_replica_set_size,
191            MinReplicaSetSize: self.min_replica_set_size,
192            PlacementConstraints: self.placement_contraints.as_pcwstr(), // TODO:
193            CorrelationCount: 0,
194            Correlations: std::ptr::null_mut(), // TODO: FABRIC_SERVICE_CORRELATION_DESCRIPTION
195            Metrics: std::ptr::null_mut(),      // TODO:
196            MetricCount: 0,
197            HasPersistedState: self.has_persistent_state,
198            Reserved: ex1.as_ref() as *const _ as *mut c_void,
199        });
200
201        StatefulServiceDescriptionRaw {
202            internal,
203            _internal_ex1: ex1,
204            _internal_ex2: ex2,
205            _internal_ex3: ex3,
206            _internal_ex4: ex4,
207            phantom: PhantomData,
208        }
209    }
210}
211
212pub struct StatelessServiceDescription {
213    // common
214    application_name: WString,
215    service_name: WString,
216    service_type_name: WString,
217    initialization_data: Option<Vec<u8>>,
218    partition_scheme_description: PartitionSchemeDescription,
219    // stateless
220    instance_count: i32,
221    // common
222    placement_contraints: WString,
223    _correlations: Vec<WString>, // TODO: FABRIC_SERVICE_CORRELATION_DESCRIPTION
224    _metrics: Vec<WString>,      // TODO: FABRIC_SERVICE_LOAD_METRIC_DESCRIPTION
225    // ex1
226    _policy_list: Vec<WString>, // TODO: FABRIC_SERVICE_PLACEMENT_POLICY_DESCRIPTION
227    // ex2
228    default_move_cost: Option<MoveCost>, // TODO: FABRIC_MOVE_COST
229    // ex3
230    service_package_activation_mode: ServicePackageActivationMode, // TODO: FABRIC_SERVICE_PACKAGE_ACTIVATION_MODE
231    _service_dns_name: WString,                                    // TODO: FABRIC_SERVICE_DNS_NAME
232    // ex4
233    _service_scaling_policys: Vec<WString>, // TODO: FABRIC_SERVICE_SCALING_POLICY
234}
235impl StatelessServiceDescription {
236    pub fn new(
237        application_name: WString,
238        service_name: WString,
239        service_type_name: WString,
240        partition_scheme_description: PartitionSchemeDescription,
241    ) -> Self {
242        Self {
243            application_name,
244            service_name,
245            service_type_name,
246            initialization_data: None,
247            partition_scheme_description,
248            instance_count: 1,
249            placement_contraints: WString::default(),
250            _correlations: Vec::new(),
251            _metrics: Vec::new(),
252            _policy_list: Vec::new(),
253            default_move_cost: None,
254            service_package_activation_mode: ServicePackageActivationMode::default(),
255            _service_dns_name: WString::default(),
256            _service_scaling_policys: Vec::new(),
257        }
258    }
259
260    pub fn with_initialization_data(mut self, initialization_data: Vec<u8>) -> Self {
261        self.initialization_data = Some(initialization_data);
262        self
263    }
264    pub fn with_instance_count(mut self, instance_count: i32) -> Self {
265        self.instance_count = instance_count;
266        self
267    }
268    pub fn with_placement_constraints(mut self, placement_contraints: WString) -> Self {
269        self.placement_contraints = placement_contraints;
270        self
271    }
272    pub fn with_default_move_cost(mut self, default_move_cost: MoveCost) -> Self {
273        self.default_move_cost = Some(default_move_cost);
274        self
275    }
276    pub fn with_service_activation_mode(
277        mut self,
278        service_package_activation_mode: ServicePackageActivationMode,
279    ) -> Self {
280        self.service_package_activation_mode = service_package_activation_mode;
281        self
282    }
283}
284pub(crate) struct StatelessServiceDescriptionRaw<'a> {
285    internal: Box<FABRIC_STATELESS_SERVICE_DESCRIPTION>,
286    _internal_ex1: Box<FABRIC_STATELESS_SERVICE_DESCRIPTION_EX1>,
287    _internal_ex2: Box<FABRIC_STATELESS_SERVICE_DESCRIPTION_EX2>,
288    _internal_ex3: Box<FABRIC_STATELESS_SERVICE_DESCRIPTION_EX3>,
289    _internal_ex4: Box<FABRIC_STATELESS_SERVICE_DESCRIPTION_EX4>,
290    phantom: PhantomData<&'a StatelessServiceDescription>,
291}
292impl StatelessServiceDescriptionRaw<'_> {
293    pub fn as_ffi(&self) -> &FABRIC_STATELESS_SERVICE_DESCRIPTION {
294        self.internal.as_ref()
295    }
296}
297
298impl StatelessServiceDescription {
299    fn build_raw(&self) -> StatelessServiceDescriptionRaw {
300        let ex4 = Box::new(FABRIC_STATELESS_SERVICE_DESCRIPTION_EX4 {
301            ServiceScalingPolicies: std::ptr::null_mut(), // TODO: support scaling policies
302            ScalingPolicyCount: 0,
303            Reserved: std::ptr::null_mut(),
304        });
305        let ex3 = Box::new(FABRIC_STATELESS_SERVICE_DESCRIPTION_EX3 {
306            ServiceDnsName: windows_core::PCWSTR::null(), // TODO: FABRIC_SERVICE_DNS_NAME
307            ServicePackageActivationMode: self.service_package_activation_mode.clone().into(),
308            Reserved: ex4.as_ref() as *const _ as *mut c_void,
309        });
310        let ex2 = Box::new(FABRIC_STATELESS_SERVICE_DESCRIPTION_EX2 {
311            IsDefaultMoveCostSpecified: self.default_move_cost.is_some(),
312            DefaultMoveCost: self
313                .default_move_cost
314                .clone()
315                .unwrap_or(MoveCost::Zero)
316                .into(),
317            Reserved: ex3.as_ref() as *const _ as *mut c_void,
318        });
319        let ex1 = Box::new(FABRIC_STATELESS_SERVICE_DESCRIPTION_EX1 {
320            PolicyList: std::ptr::null_mut(), // TODO:
321            Reserved: ex2.as_ref() as *const _ as *mut c_void,
322        });
323
324        let (init_data, init_data_len) = self
325            .initialization_data
326            .as_ref()
327            .map(|v| (v.as_ptr() as *mut u8, v.len() as u32))
328            .unwrap_or((std::ptr::null_mut(), 0));
329
330        let internal = Box::new(FABRIC_STATELESS_SERVICE_DESCRIPTION {
331            ApplicationName: FABRIC_URI(self.application_name.as_ptr() as *mut u16),
332            ServiceName: FABRIC_URI(self.service_name.as_ptr() as *mut u16),
333            ServiceTypeName: self.service_type_name.as_pcwstr(),
334            InitializationDataSize: init_data_len,
335            InitializationData: init_data,
336            PartitionScheme: self.partition_scheme_description.as_raw().0,
337            PartitionSchemeDescription: self.partition_scheme_description.as_raw().1,
338            InstanceCount: self.instance_count,
339            PlacementConstraints: self.placement_contraints.as_pcwstr(), // TODO:
340            CorrelationCount: 0,
341            Correlations: std::ptr::null_mut(), // TODO: FABRIC_SERVICE_CORRELATION_DESCRIPTION
342            Metrics: std::ptr::null_mut(),      // TODO:
343            MetricCount: 0,
344            Reserved: ex1.as_ref() as *const _ as *mut c_void,
345        });
346        StatelessServiceDescriptionRaw {
347            internal,
348            _internal_ex1: ex1,
349            _internal_ex2: ex2,
350            _internal_ex3: ex3,
351            _internal_ex4: ex4,
352            phantom: PhantomData,
353        }
354    }
355}
356
357pub(crate) enum ServiceDescriptionRaw<'a> {
358    Stateful(StatefulServiceDescriptionRaw<'a>),
359    Stateless(StatelessServiceDescriptionRaw<'a>),
360}
361
362impl ServiceDescriptionRaw<'_> {
363    pub(crate) fn as_ffi(&self) -> FABRIC_SERVICE_DESCRIPTION {
364        match self {
365            ServiceDescriptionRaw::Stateful(ref desc) => FABRIC_SERVICE_DESCRIPTION {
366                Kind: FABRIC_SERVICE_DESCRIPTION_KIND_STATEFUL,
367                Value: desc.as_ffi() as *const _ as *mut c_void,
368            },
369            ServiceDescriptionRaw::Stateless(ref desc) => FABRIC_SERVICE_DESCRIPTION {
370                Kind: FABRIC_SERVICE_DESCRIPTION_KIND_STATELESS,
371                Value: desc.as_ffi() as *const _ as *mut c_void,
372            },
373        }
374    }
375}
376
377impl ServiceDescription {
378    /// The raw type contains the ffi pointers on heap to be used by SF.
379    /// mssf build the raw type on the stack and call the SF API with it.
380    pub(crate) fn build_raw(&self) -> ServiceDescriptionRaw {
381        match self {
382            ServiceDescription::Stateful(ref desc) => {
383                ServiceDescriptionRaw::Stateful(desc.build_raw())
384            }
385            ServiceDescription::Stateless(ref desc) => {
386                ServiceDescriptionRaw::Stateless(desc.build_raw())
387            }
388        }
389    }
390}
391
392// Update API payloads
393// ===================================================
394
395#[derive(Debug, Default)]
396pub enum ServiceRepartitionDescription {
397    #[default]
398    Invalid,
399    Named(NamedRepartitionDescription), // FABRIC_SERVICE_REPARTITION_DESCRIPTION
400}
401
402// FABRIC_NAMED_REPARTITION_DESCRIPTION
403#[derive(Debug)]
404pub struct NamedRepartitionDescription {
405    pub names_to_add: Vec<WString>,
406    pub names_to_remove: Vec<WString>,
407}
408
409/// Holder for memories passed to the FFI
410pub(crate) struct NamedRepartitionDescriptionRaw<'a> {
411    _names_to_add: Vec<PCWSTR>,
412    _names_to_remove: Vec<PCWSTR>,
413    internal: Box<FABRIC_NAMED_REPARTITION_DESCRIPTION>,
414    phantom: PhantomData<&'a NamedRepartitionDescription>,
415}
416
417impl NamedRepartitionDescription {
418    pub(crate) fn as_raw(&self) -> NamedRepartitionDescriptionRaw {
419        let names_to_add = self
420            .names_to_add
421            .iter()
422            .map(|s| s.as_pcwstr())
423            .collect::<Vec<_>>();
424        let names_to_remove = self
425            .names_to_remove
426            .iter()
427            .map(|s| s.as_pcwstr())
428            .collect::<Vec<_>>();
429        let internal = Box::new(FABRIC_NAMED_REPARTITION_DESCRIPTION {
430            NamesToAddCount: names_to_add.len() as u32,
431            NamesToAdd: names_to_add.as_ptr(),
432            NamesToRemoveCount: names_to_remove.len() as u32,
433            NamesToRemove: names_to_remove.as_ptr(),
434            Reserved: std::ptr::null_mut(),
435        });
436        NamedRepartitionDescriptionRaw {
437            _names_to_add: names_to_add,
438            _names_to_remove: names_to_remove,
439            internal,
440            phantom: PhantomData,
441        }
442    }
443}
444
445impl NamedRepartitionDescriptionRaw<'_> {
446    pub(crate) fn as_ffi(&self) -> &FABRIC_NAMED_REPARTITION_DESCRIPTION {
447        self.internal.as_ref()
448    }
449}
450
451/// Memory holder for the repartition description passed to the FFI
452pub(crate) enum ServiceRepartitionDescriptionRaw<'a> {
453    Invalid,
454    Named(NamedRepartitionDescriptionRaw<'a>),
455}
456
457impl ServiceRepartitionDescription {
458    pub(crate) fn as_raw(&self) -> ServiceRepartitionDescriptionRaw {
459        match self {
460            ServiceRepartitionDescription::Named(ref desc) => {
461                ServiceRepartitionDescriptionRaw::Named(desc.as_raw())
462            }
463            ServiceRepartitionDescription::Invalid => ServiceRepartitionDescriptionRaw::Invalid,
464        }
465    }
466}
467
468impl ServiceRepartitionDescriptionRaw<'_> {
469    pub(crate) fn as_ffi(&self) -> (FABRIC_SERVICE_PARTITION_KIND, *const c_void) {
470        match self {
471            ServiceRepartitionDescriptionRaw::Named(ref desc) => (
472                FABRIC_SERVICE_PARTITION_KIND_NAMED,
473                desc.as_ffi() as *const _ as *const _,
474            ),
475            ServiceRepartitionDescriptionRaw::Invalid => {
476                (FABRIC_SERVICE_PARTITION_KIND_INVALID, std::ptr::null_mut())
477            }
478        }
479    }
480}
481
482bitflags::bitflags! {
483    /// FABRIC_STATEFUL_SERVICE_UPDATE_DESCRIPTION_FLAGS
484    /// Indicates what fields are set in the description.
485    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
486    pub struct StatefulServiceUpdateDescriptionFlags: u32 {
487        const FABRIC_STATEFUL_SERVICE_NONE = mssf_com::FabricTypes::FABRIC_STATEFUL_SERVICE_NONE.0 as u32;
488        const FABRIC_STATEFUL_SERVICE_TARGET_REPLICA_SET_SIZE = mssf_com::FabricTypes::FABRIC_STATEFUL_SERVICE_TARGET_REPLICA_SET_SIZE.0 as u32;
489        const FABRIC_STATEFUL_SERVICE_REPLICA_RESTART_WAIT_DURATION = mssf_com::FabricTypes::FABRIC_STATELESS_SERVICE_CORRELATIONS.0 as u32;
490        const FABRIC_STATEFUL_SERVICE_QUORUM_LOSS_WAIT_DURATION = mssf_com::FabricTypes::FABRIC_STATEFUL_SERVICE_QUORUM_LOSS_WAIT_DURATION.0 as u32;
491        const FABRIC_STATEFUL_SERVICE_STANDBY_REPLICA_KEEP_DURATION = mssf_com::FabricTypes::FABRIC_STATEFUL_SERVICE_STANDBY_REPLICA_KEEP_DURATION.0 as u32;
492        const FABRIC_STATEFUL_SERVICE_MIN_REPLICA_SET_SIZE = mssf_com::FabricTypes::FABRIC_STATEFUL_SERVICE_MIN_REPLICA_SET_SIZE.0 as u32;
493        const FABRIC_STATEFUL_SERVICE_PLACEMENT_CONSTRAINTS = mssf_com::FabricTypes::FABRIC_STATEFUL_SERVICE_PLACEMENT_CONSTRAINTS.0 as u32;
494        const FABRIC_STATEFUL_SERVICE_POLICY_LIST = mssf_com::FabricTypes::FABRIC_STATEFUL_SERVICE_POLICY_LIST.0 as u32;
495        const FABRIC_STATEFUL_SERVICE_CORRELATIONS = mssf_com::FabricTypes::FABRIC_STATEFUL_SERVICE_CORRELATIONS.0 as u32;
496        const FABRIC_STATEFUL_SERVICE_METRICS = mssf_com::FabricTypes::FABRIC_STATEFUL_SERVICE_METRICS.0 as u32;
497        const FABRIC_STATEFUL_SERVICE_MOVE_COST = mssf_com::FabricTypes::FABRIC_STATEFUL_SERVICE_MOVE_COST.0 as u32;
498        const FABRIC_STATEFUL_SERVICE_SCALING_POLICY = mssf_com::FabricTypes::FABRIC_STATEFUL_SERVICE_SCALING_POLICY.0 as u32;
499    }
500}
501impl Default for StatefulServiceUpdateDescriptionFlags {
502    fn default() -> Self {
503        StatefulServiceUpdateDescriptionFlags::FABRIC_STATEFUL_SERVICE_NONE
504    }
505}
506
507/// FABRIC_STATEFUL_SERVICE_UPDATE_DESCRIPTION
508pub enum ServiceUpdateDescription {
509    Stateful(StatefulServiceUpdateDescription), // FABRIC_STATEFUL_SERVICE_UPDATE_DESCRIPTION
510    Stateless(StatelessServiceUpdateDescription), // FABRIC_STATELESS_SERVICE_UPDATE_DESCRIPTION
511}
512
513impl ServiceUpdateDescription {
514    /// The raw type contains the ffi pointers on heap to be used by SF.
515    /// mssf build the raw type on the stack and call the SF API with it.
516    pub(crate) fn build_raw(&self) -> ServiceUpdateDescriptionRaw {
517        match self {
518            ServiceUpdateDescription::Stateful(ref desc) => {
519                ServiceUpdateDescriptionRaw::Stateful(desc.build_raw())
520            }
521            ServiceUpdateDescription::Stateless(ref desc) => {
522                ServiceUpdateDescriptionRaw::Stateless(desc.build_raw())
523            }
524        }
525    }
526}
527
528/// FABRIC_STATEFUL_SERVICE_UPDATE_DESCRIPTION
529#[derive(Debug, Default)]
530pub struct StatefulServiceUpdateDescription {
531    flags: StatefulServiceUpdateDescriptionFlags,
532    target_replica_set_size: i32,
533    replica_restart_wait_duration_seconds: u32,
534    quorum_loss_wait_duration_seconds: u32,
535    // ex1
536    stand_by_replica_keep_duration_seconds: u32,
537    // ex2
538    min_replica_set_size: i32,
539    // ex3
540    placement_contraints: WString,
541    _policy_list: Vec<WString>, // TODO: FABRIC_SERVICE_PLACEMENT_POLICY_DESCRIPTION
542    _correlations: Vec<WString>, // TODO: FABRIC_SERVICE_CORRELATION_DESCRIPTION
543    _metrics: Vec<WString>,     // TODO: FABRIC_SERVICE_LOAD_METRIC_DESCRIPTION
544    // ex4
545    default_move_cost: MoveCost, // TODO: FABRIC_MOVE_COST
546    // ex5
547    repartition_description: ServiceRepartitionDescription,
548    _scaling_policys: Vec<WString>, // TODO: FABRIC_SERVICE_SCALING_POLICY
549}
550
551// setters for the fields
552impl StatefulServiceUpdateDescription {
553    pub fn new() -> Self {
554        Self::default()
555    }
556
557    pub fn with_target_replica_set_size(mut self, target_replica_set_size: i32) -> Self {
558        self.flags |=
559            StatefulServiceUpdateDescriptionFlags::FABRIC_STATEFUL_SERVICE_TARGET_REPLICA_SET_SIZE;
560        self.target_replica_set_size = target_replica_set_size;
561        self
562    }
563
564    pub fn with_replica_restart_wait_duration_seconds(
565        mut self,
566        replica_restart_wait_duration_seconds: u32,
567    ) -> Self {
568        self.flags |= StatefulServiceUpdateDescriptionFlags::FABRIC_STATEFUL_SERVICE_REPLICA_RESTART_WAIT_DURATION;
569        self.replica_restart_wait_duration_seconds = replica_restart_wait_duration_seconds;
570        self
571    }
572    pub fn with_quorum_loss_wait_duration_seconds(
573        mut self,
574        quorum_loss_wait_duration_seconds: u32,
575    ) -> Self {
576        self.flags |= StatefulServiceUpdateDescriptionFlags::FABRIC_STATEFUL_SERVICE_QUORUM_LOSS_WAIT_DURATION;
577        self.quorum_loss_wait_duration_seconds = quorum_loss_wait_duration_seconds;
578        self
579    }
580    pub fn with_stand_by_replica_keep_duration_seconds(
581        mut self,
582        stand_by_replica_keep_duration_seconds: u32,
583    ) -> Self {
584        self.flags |= StatefulServiceUpdateDescriptionFlags::FABRIC_STATEFUL_SERVICE_STANDBY_REPLICA_KEEP_DURATION;
585        self.stand_by_replica_keep_duration_seconds = stand_by_replica_keep_duration_seconds;
586        self
587    }
588    pub fn with_min_replica_set_size(mut self, min_replica_set_size: i32) -> Self {
589        self.flags |=
590            StatefulServiceUpdateDescriptionFlags::FABRIC_STATEFUL_SERVICE_MIN_REPLICA_SET_SIZE;
591        self.min_replica_set_size = min_replica_set_size;
592        self
593    }
594
595    pub fn with_move_cost(mut self, default_move_cost: MoveCost) -> Self {
596        self.flags |= StatefulServiceUpdateDescriptionFlags::FABRIC_STATEFUL_SERVICE_MOVE_COST;
597        self.default_move_cost = default_move_cost;
598        self
599    }
600
601    pub fn with_repartition_description(
602        mut self,
603        repartition_description: ServiceRepartitionDescription,
604    ) -> Self {
605        // the ffi field is a ptr so no need to set the flag
606        self.repartition_description = repartition_description;
607        self
608    }
609}
610
611/// FABRIC_STATELESS_SERVICE_UPDATE_DESCRIPTION
612pub struct StatelessServiceUpdateDescription {
613    pub flags: StatefulServiceUpdateDescriptionFlags,
614    pub instance_count: i32,
615    // ex1
616    pub placement_contraints: WString,
617    pub policy_list: Vec<WString>, // TODO: FABRIC_SERVICE_PLACEMENT_POLICY_DESCRIPTION
618    pub correlations: Vec<WString>, // TODO: FABRIC_SERVICE_CORRELATION_DESCRIPTION
619    pub metrics: Vec<WString>,     // TODO: FABRIC_SERVICE_LOAD_METRIC_DESCRIPTION
620    // ex2
621    pub default_move_cost: Option<MoveCost>, // TODO: FABRIC_MOVE_COST
622    // ex5
623    pub repartition_description: PartitionSchemeDescription, // TODO
624    pub scaling_policys: Vec<WString>,                       // TODO: FABRIC_SERVICE_SCALING_POLICY
625}
626
627impl StatelessServiceUpdateDescription {
628    fn build_raw(&self) -> StatelessServiceUpdateDescriptionRaw {
629        unimplemented!()
630    }
631}
632
633/// Temp enum to hold the raw data
634pub(crate) enum ServiceUpdateDescriptionRaw<'a> {
635    Stateful(StatefulServiceUpdateDescriptionRaw<'a>),
636    Stateless(StatelessServiceUpdateDescriptionRaw),
637}
638
639/// Raw type
640pub(crate) struct StatefulServiceUpdateDescriptionRaw<'a> {
641    internal: Box<FABRIC_STATEFUL_SERVICE_UPDATE_DESCRIPTION>,
642    _internal_ex1: Box<FABRIC_STATEFUL_SERVICE_UPDATE_DESCRIPTION_EX1>,
643    _internal_ex2: Box<FABRIC_STATEFUL_SERVICE_UPDATE_DESCRIPTION_EX2>,
644    _internal_ex3: Box<FABRIC_STATEFUL_SERVICE_UPDATE_DESCRIPTION_EX3>,
645    _internal_ex4: Box<FABRIC_STATEFUL_SERVICE_UPDATE_DESCRIPTION_EX4>,
646    _internal_ex5: Box<FABRIC_STATEFUL_SERVICE_UPDATE_DESCRIPTION_EX5>,
647    _repartition_owner: ServiceRepartitionDescriptionRaw<'a>,
648}
649
650impl StatefulServiceUpdateDescriptionRaw<'_> {
651    pub(crate) fn as_ffi(&self) -> &FABRIC_STATEFUL_SERVICE_UPDATE_DESCRIPTION {
652        self.internal.as_ref()
653    }
654}
655
656pub(crate) struct StatelessServiceUpdateDescriptionRaw {
657    _internal: Box<FABRIC_STATELESS_SERVICE_UPDATE_DESCRIPTION>,
658    _internal_ex1: Box<FABRIC_STATELESS_SERVICE_UPDATE_DESCRIPTION_EX1>,
659    _internal_ex2: Box<FABRIC_STATELESS_SERVICE_UPDATE_DESCRIPTION_EX2>,
660    _internal_ex3: Box<FABRIC_STATELESS_SERVICE_UPDATE_DESCRIPTION_EX3>,
661}
662
663impl StatelessServiceUpdateDescriptionRaw {
664    // TODO:
665    pub(crate) fn as_ffi(&self) -> &FABRIC_STATELESS_SERVICE_UPDATE_DESCRIPTION {
666        unimplemented!()
667        //self.internal.as_ref()
668    }
669}
670
671impl ServiceUpdateDescriptionRaw<'_> {
672    /// Must have the same lifetime as the original struct
673    pub(crate) fn as_ffi(&self) -> FABRIC_SERVICE_UPDATE_DESCRIPTION {
674        match self {
675            ServiceUpdateDescriptionRaw::Stateful(ref desc) => FABRIC_SERVICE_UPDATE_DESCRIPTION {
676                Kind: FABRIC_SERVICE_DESCRIPTION_KIND_STATEFUL,
677                Value: desc.as_ffi() as *const _ as *mut c_void,
678            },
679            ServiceUpdateDescriptionRaw::Stateless(ref desc) => FABRIC_SERVICE_UPDATE_DESCRIPTION {
680                Kind: FABRIC_SERVICE_DESCRIPTION_KIND_STATELESS,
681                Value: desc.as_ffi() as *const _ as *mut c_void,
682            },
683        }
684    }
685}
686
687impl StatefulServiceUpdateDescription {
688    pub(crate) fn build_raw(&self) -> StatefulServiceUpdateDescriptionRaw {
689        let repartition_raw = self.repartition_description.as_raw();
690        let ex5 = Box::new(FABRIC_STATEFUL_SERVICE_UPDATE_DESCRIPTION_EX5 {
691            RepartitionDescription: repartition_raw.as_ffi().1 as *const _ as *mut _,
692            RepartitionKind: repartition_raw.as_ffi().0,
693            ScalingPolicyCount: 0,
694            ServiceScalingPolicies: std::ptr::null_mut(), // TODO: FABRIC_SERVICE_SCALING_POLICY
695            Reserved: std::ptr::null_mut(),
696        });
697        let ex4 = Box::new(FABRIC_STATEFUL_SERVICE_UPDATE_DESCRIPTION_EX4 {
698            DefaultMoveCost: self.default_move_cost.clone().into(),
699            Reserved: ex5.as_ref() as *const _ as *mut c_void,
700        });
701        let ex3 = Box::new(FABRIC_STATEFUL_SERVICE_UPDATE_DESCRIPTION_EX3 {
702            PlacementConstraints: self.placement_contraints.as_pcwstr(), // TODO:
703            PolicyList: std::ptr::null_mut(),                            // TODO:
704            CorrelationCount: 0,
705            Correlations: std::ptr::null_mut(), // TODO: FABRIC_SERVICE_CORRELATION_DESCRIPTION
706            Metrics: std::ptr::null_mut(),      // TODO:
707            MetricCount: 0,
708            Reserved: ex4.as_ref() as *const _ as *mut c_void,
709        });
710        let ex2 = Box::new(FABRIC_STATEFUL_SERVICE_UPDATE_DESCRIPTION_EX2 {
711            MinReplicaSetSize: self.min_replica_set_size,
712            Reserved: ex3.as_ref() as *const _ as *mut c_void,
713        });
714        let ex1 = Box::new(FABRIC_STATEFUL_SERVICE_UPDATE_DESCRIPTION_EX1 {
715            StandByReplicaKeepDurationSeconds: self.stand_by_replica_keep_duration_seconds,
716            Reserved: ex2.as_ref() as *const _ as *mut c_void,
717        });
718
719        let internal = Box::new(FABRIC_STATEFUL_SERVICE_UPDATE_DESCRIPTION {
720            Flags: self.flags.bits(),
721            TargetReplicaSetSize: self.target_replica_set_size,
722            ReplicaRestartWaitDurationSeconds: self.replica_restart_wait_duration_seconds,
723            QuorumLossWaitDurationSeconds: self.quorum_loss_wait_duration_seconds,
724            Reserved: ex1.as_ref() as *const _ as *mut c_void,
725        });
726
727        StatefulServiceUpdateDescriptionRaw {
728            internal,
729            _internal_ex1: ex1,
730            _internal_ex2: ex2,
731            _internal_ex3: ex3,
732            _internal_ex4: ex4,
733            _internal_ex5: ex5,
734            _repartition_owner: repartition_raw,
735        }
736    }
737}