1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
// ------------------------------------------------------------

#![deny(non_snake_case)] // this file is safe rust

use mssf_com::{
    FabricCommon::FabricRuntime::IFabricStatelessServicePartition,
    FABRIC_INT64_RANGE_PARTITION_INFORMATION, FABRIC_NAMED_PARTITION_INFORMATION,
    FABRIC_SERVICE_PARTITION_KIND_INT64_RANGE, FABRIC_SERVICE_PARTITION_KIND_INVALID,
    FABRIC_SERVICE_PARTITION_KIND_NAMED, FABRIC_SERVICE_PARTITION_KIND_SINGLETON,
    FABRIC_SINGLETON_PARTITION_INFORMATION,
};
use windows_core::HSTRING;

// wrap of com interface
pub struct StatelessServicePartition {
    com_impl: IFabricStatelessServicePartition,
}

#[derive(Debug)]
pub struct SingletonPartitionInfo {
    pub id: ::windows_core::GUID,
}

#[derive(Debug)]
pub struct Int64PartitionInfo {
    pub id: ::windows_core::GUID,
    pub low_key: i64,
    pub high_key: i64,
}

#[derive(Debug)]
pub struct NamedPartitionInfo {
    pub id: ::windows_core::GUID,
    pub name: ::windows_core::HSTRING,
}

#[derive(Debug)]
pub enum PartitionKind {
    Invalid,
    Singleton(SingletonPartitionInfo),
    Int64Range(Int64PartitionInfo),
    Named(NamedPartitionInfo),
}

impl StatelessServicePartition {
    pub fn new(com_impl: IFabricStatelessServicePartition) -> StatelessServicePartition {
        StatelessServicePartition { com_impl }
    }

    pub fn get_partition_info(&self) -> ::windows_core::Result<PartitionKind> {
        let raw = unsafe { self.com_impl.GetPartitionInfo() }?;
        let raw_ref = unsafe { raw.as_ref().unwrap() };
        assert!(!raw.is_null());
        let res: PartitionKind = match raw_ref.Kind {
            FABRIC_SERVICE_PARTITION_KIND_INVALID => PartitionKind::Invalid,
            FABRIC_SERVICE_PARTITION_KIND_SINGLETON => {
                let raw_info =
                    unsafe { &mut *(raw_ref.Value as *mut FABRIC_SINGLETON_PARTITION_INFORMATION) };
                let info = SingletonPartitionInfo { id: raw_info.Id };
                PartitionKind::Singleton(info)
            }
            FABRIC_SERVICE_PARTITION_KIND_INT64_RANGE => {
                let raw_info = unsafe {
                    &mut *(raw_ref.Value as *mut FABRIC_INT64_RANGE_PARTITION_INFORMATION)
                };
                let info = Int64PartitionInfo {
                    id: raw_info.Id,
                    low_key: raw_info.LowKey,
                    high_key: raw_info.HighKey,
                };
                PartitionKind::Int64Range(info)
            }
            FABRIC_SERVICE_PARTITION_KIND_NAMED => {
                let raw_info =
                    unsafe { &mut *(raw_ref.Value as *mut FABRIC_NAMED_PARTITION_INFORMATION) };
                let info = NamedPartitionInfo {
                    id: raw_info.Id,
                    name: HSTRING::from_wide(unsafe { raw_info.Name.as_wide() }).unwrap(),
                };
                PartitionKind::Named(info)
            }
            _ => PartitionKind::Invalid,
        };
        Ok(res)
    }
}

// safe factory
pub trait StatelessServiceFactory {
    fn create_instance(
        &self,
        servicetypename: &HSTRING,
        servicename: &HSTRING,
        initializationdata: &[u8],
        partitionid: &::windows::core::GUID,
        instanceid: i64,
    ) -> windows_core::Result<impl StatelessServiceInstance>;
}

// safe service instance
#[trait_variant::make(StatelessServiceInstance: Send)]
pub trait LocalStatelessServiceInstance: Send + Sync + 'static {
    async fn open(&self, partition: &StatelessServicePartition) -> windows::core::Result<HSTRING>;
    async fn close(&self) -> windows::core::Result<()>;
    fn abort(&self);
}