Skip to content

Commit

Permalink
Impl config loading wrapper for activation context (#22)
Browse files Browse the repository at this point in the history
Added safe rust wrappers for config package loading.
  • Loading branch information
youyuanwu authored Apr 22, 2024
1 parent b2267ea commit 507d9ab
Show file tree
Hide file tree
Showing 8 changed files with 386 additions and 3 deletions.
17 changes: 17 additions & 0 deletions crates/libs/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,23 @@ fn unsafe_pwstr_to_hstring(raw: PCWSTR) -> HSTRING {
HSTRING::from_wide(unsafe { raw.as_wide() }).unwrap()
}

struct HSTRINGWrap {
h: HSTRING,
}

impl From<PCWSTR> for HSTRINGWrap {
fn from(value: PCWSTR) -> Self {
let h = unsafe_pwstr_to_hstring(value);
Self { h }
}
}

impl From<HSTRINGWrap> for HSTRING {
fn from(val: HSTRINGWrap) -> Self {
val.h
}
}

#[cfg(test)]
mod test {
use super::{IFabricStringResultToHString, StringResult};
Expand Down
192 changes: 192 additions & 0 deletions crates/libs/core/src/runtime/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
use mssf_com::{
FabricCommon::FabricRuntime::IFabricConfigurationPackage, FABRIC_CONFIGURATION_PARAMETER,
FABRIC_CONFIGURATION_PARAMETER_LIST, FABRIC_CONFIGURATION_SECTION,
FABRIC_CONFIGURATION_SECTION_LIST,
};
use windows::Win32::Foundation::{BOOLEAN, E_POINTER};
use windows_core::HSTRING;

use crate::{unsafe_pwstr_to_hstring, HSTRINGWrap, IFabricStringResultToHString};

use super::iter::{FabricIter, FabricListAccessor};

pub struct ConfigurationPackage {
com: IFabricConfigurationPackage,
}

pub struct ConfigurationPackageDesc {
pub name: HSTRING,
pub ServiceManifestName: HSTRING,
pub ServiceManifestVersion: HSTRING,
pub Version: HSTRING,
}

pub struct ConfigurationSettings {
pub sections: ConfigurationSectionList,
}

// FABRIC_CONFIGURATION_SECTION_LIST
pub struct ConfigurationSectionList {
com: IFabricConfigurationPackage,
}

type ConfigurationSectionListIter<'a> =
FabricIter<'a, FABRIC_CONFIGURATION_SECTION, ConfigurationSection, ConfigurationSectionList>;

impl ConfigurationSectionList {
fn get_section_list_ref(&self) -> &FABRIC_CONFIGURATION_SECTION_LIST {
let raw = unsafe { self.com.get_Settings().as_ref().unwrap() };
unsafe { raw.Sections.as_ref().unwrap() }
}
pub fn iter(&self) -> ConfigurationSectionListIter {
ConfigurationSectionListIter::new(self, self)
}
}

impl FabricListAccessor<FABRIC_CONFIGURATION_SECTION> for ConfigurationSectionList {
fn get_count(&self) -> u32 {
self.get_section_list_ref().Count
}

fn get_first_item(&self) -> *const FABRIC_CONFIGURATION_SECTION {
self.get_section_list_ref().Items
}
}

impl ConfigurationPackage {
pub fn from_com(com: IFabricConfigurationPackage) -> Self {
Self { com }
}

pub fn get_description(&self) -> ConfigurationPackageDesc {
let raw = unsafe { self.com.get_Description().as_ref().unwrap() };

ConfigurationPackageDesc {
name: unsafe_pwstr_to_hstring(raw.Name),
ServiceManifestName: unsafe_pwstr_to_hstring(raw.ServiceManifestName),
ServiceManifestVersion: unsafe_pwstr_to_hstring(raw.ServiceManifestVersion),
Version: unsafe_pwstr_to_hstring(raw.Version),
}
}

pub fn get_settings(&self) -> ConfigurationSettings {
ConfigurationSettings {
sections: ConfigurationSectionList {
com: self.com.clone(),
},
}
}

pub fn get_path(&self) -> HSTRING {
let raw = unsafe { self.com.get_Path() };
HSTRINGWrap::from(raw).into()
}

pub fn get_section(
&self,
section_name: &HSTRING,
) -> windows_core::Result<ConfigurationSection> {
let raw = unsafe { self.com.GetSection(section_name) }?;
let raw_ref = unsafe { raw.as_ref() };
match raw_ref {
Some(c) => {
let mut res = ConfigurationSection::from(c);
res.owner = Some(self.com.clone());
Ok(res)
}
None => Err(E_POINTER.into()),
}
}

pub fn get_value(
&self,
section_name: &HSTRING,
parameter_name: &HSTRING,
) -> windows_core::Result<(HSTRING, bool)> {
let mut is_encrypted: BOOLEAN = Default::default();
let raw = unsafe {
self.com.GetValue(
section_name,
parameter_name,
std::ptr::addr_of_mut!(is_encrypted.0),
)
}?;
Ok((HSTRINGWrap::from(raw).into(), is_encrypted.as_bool()))
}

pub fn decrypt_value(&self, encryptedvalue: &HSTRING) -> windows_core::Result<HSTRING> {
let s = unsafe { self.com.DecryptValue(encryptedvalue) }?;
Ok(IFabricStringResultToHString(&s))
}
}

// Note: parameter has ptr to raw memory into
// Com obj, but this relationship is not tracked by lifetime,
// So when using config section and parameter list,
// make sure the com obj is still in scope.
// TODO: find a way to make lifetime work.
pub struct ConfigurationSection {
owner: Option<IFabricConfigurationPackage>,
pub name: HSTRING,
pub parameters: ConfigurationParameterList, // Note: the list has no lifetime tracking
}

impl From<&FABRIC_CONFIGURATION_SECTION> for ConfigurationSection {
fn from(value: &FABRIC_CONFIGURATION_SECTION) -> Self {
Self {
owner: None,
name: HSTRINGWrap::from(value.Name).into(),
parameters: ConfigurationParameterList {
list: value.Parameters, // TODO: ownership/lifetime escaped here.
},
}
}
}

// FABRIC_CONFIGURATION_PARAMETER_LIST
// TODO: the owner is not accessible.
type ConfigurationParameterListIter<'a> = FabricIter<
'a,
FABRIC_CONFIGURATION_PARAMETER,
ConfigurationParameter,
ConfigurationParameterList,
>;

pub struct ConfigurationParameterList {
list: *const FABRIC_CONFIGURATION_PARAMETER_LIST,
}

impl ConfigurationParameterList {
pub fn iter(&self) -> ConfigurationParameterListIter {
ConfigurationParameterListIter::new(self, self)
}
}

impl FabricListAccessor<FABRIC_CONFIGURATION_PARAMETER> for ConfigurationParameterList {
fn get_count(&self) -> u32 {
unsafe { self.list.as_ref().unwrap().Count }
}

fn get_first_item(&self) -> *const FABRIC_CONFIGURATION_PARAMETER {
unsafe { self.list.as_ref().unwrap().Items }
}
}

#[derive(Debug)]
pub struct ConfigurationParameter {
pub is_encrypted: bool,
pub must_overrride: bool,
pub name: HSTRING,
pub value: HSTRING,
}

impl From<&FABRIC_CONFIGURATION_PARAMETER> for ConfigurationParameter {
fn from(value: &FABRIC_CONFIGURATION_PARAMETER) -> Self {
Self {
name: HSTRINGWrap::from(value.Name).into(),
is_encrypted: value.IsEncrypted.as_bool(),
must_overrride: value.MustOverride.as_bool(),
value: HSTRINGWrap::from(value.Value).into(),
}
}
}
121 changes: 121 additions & 0 deletions crates/libs/core/src/runtime/iter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// iterator implementation

use std::marker::PhantomData;

// Access fabric list metadata
// T is the fabric raw type that needs to iterate through by pointer arithmetic
pub trait FabricListAccessor<T> {
fn get_count(&self) -> u32;
fn get_first_item(&self) -> *const T;
}

pub struct FabricIter<'b, T, R, O>
where
R: for<'a> std::convert::From<&'a T>,
{
_owner: &'b O, // owns the memory that the curr ptr points to. Typically this is a COM obj.
count: u32, // total
index: u32,
curr: *const T,
phantom: PhantomData<R>, // R is the converted type
}

impl<'b, T, R, O> FabricIter<'b, T, R, O>
where
R: for<'a> std::convert::From<&'a T>,
{
pub fn new(accessor: &impl FabricListAccessor<T>, owner: &'b O) -> Self {
let count = accessor.get_count();
let first = accessor.get_first_item();
Self {
count,
index: 0,
curr: first,
phantom: PhantomData {},
_owner: owner,
}
}
}

impl<T, R, O> Iterator for FabricIter<'_, T, R, O>
where
R: for<'a> std::convert::From<&'a T>,
{
type Item = R;
fn next(&mut self) -> Option<Self::Item> {
if self.index >= self.count {
return None;
}
// get the curr out
let raw = unsafe { self.curr.as_ref().unwrap() };

let res: R = raw.into();
self.index += 1;
self.curr = unsafe { self.curr.offset(1) };
Some(res)
}
}

#[cfg(test)]
mod test {

use super::{FabricIter, FabricListAccessor};

struct MyVal {
val: String,
}

struct MyVal2 {
val: String,
}

impl From<&MyVal> for MyVal2 {
fn from(value: &MyVal) -> Self {
Self {
val: value.val.clone() + "Suffix",
}
}
}

struct MyVec {
v: Vec<MyVal>,
}

impl FabricListAccessor<MyVal> for MyVec {
fn get_count(&self) -> u32 {
self.v.len() as u32
}

fn get_first_item(&self) -> *const MyVal {
self.v.as_ptr()
}
}

type MyVecIter<'a> = FabricIter<'a, MyVal, MyVal2, MyVec>;

impl MyVec {
fn get_iter(&self) -> MyVecIter {
MyVecIter::new(self, self)
}
}

#[test]
fn test_vector() {
let v = MyVec {
v: vec![
MyVal {
val: "hi".to_string(),
},
MyVal {
val: "hi2".to_string(),
},
],
};

let it = v.get_iter();
let vv = it.collect::<Vec<_>>();
assert_eq!(vv.len(), 2);
assert_eq!(vv.first().unwrap().val, "hiSuffix");
assert_eq!(vv.last().unwrap().val, "hi2Suffix");
}
}
12 changes: 11 additions & 1 deletion crates/libs/core/src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@ use windows::core::implement;
use windows_core::{Error, Interface, HSTRING, PCWSTR};

use self::{
executor::Executor, stateful::StatefulServiceFactory,
config::ConfigurationPackage, executor::Executor, stateful::StatefulServiceFactory,
stateful_bridge::StatefulServiceFactoryBridge, stateless::StatelessServiceFactory,
stateless_bridge::StatelessServiceFactoryBridge,
};

pub mod config;
pub mod error;
pub mod executor;
mod iter;
pub mod node_context;
pub mod stateful;
pub mod stateful_bridge;
Expand Down Expand Up @@ -149,6 +151,14 @@ impl ActivationContext {
Ok(desc)
}

pub fn get_configuration_package(
&self,
configpackagename: &HSTRING,
) -> windows_core::Result<ConfigurationPackage> {
let c = unsafe { self.com_impl.GetConfigurationPackage(configpackagename) }?;
Ok(ConfigurationPackage::from_com(c))
}

pub fn get_com(&self) -> IFabricCodePackageActivationContext {
self.com_impl.clone()
}
Expand Down
2 changes: 2 additions & 0 deletions crates/samples/echo2/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,7 @@ add_custom_command(TARGET build_rust_sample_echo2 POST_BUILD
COMMAND ${CMAKE_COMMAND}
-E copy_if_different ${_pkg_src}/manifests/ApplicationManifest.xml ${_pkg_root}/ApplicationManifest.xml
COMMAND ${CMAKE_COMMAND}
-E copy_if_different ${_pkg_src}/manifests/EchoAppServicePackage2/Config/Settings.xml ${_pkg_root}/EchoAppServicePackage2/Config/Settings.xml
COMMAND ${CMAKE_COMMAND}
-E copy_if_different ${_pkg_exe} ${_pkg_root}/EchoAppServicePackage2/Code/echo2.exe
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8" ?>
<Settings xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/2011/01/fabric">
<!-- Add your custom configuration sections and parameters here -->

<Section Name="MyConfigSection">
<Parameter Name="MyParameter" Value="Value1" />
</Section>

</Settings>
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<EnvironmentVariable Name="RUST_LOG" Value="info"/>
</EnvironmentVariables>
</CodePackage>
<!-- <ConfigPackage Name="EchoAppService.Config" Version="1.0" /> -->
<ConfigPackage Name="Config" Version="1.0.0" />
<!-- <DataPackage Name="EchoAppService.Data" Version="1.0" /> -->
<Resources>
<Endpoints>
Expand Down
Loading

0 comments on commit 507d9ab

Please sign in to comment.