-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Impl config loading wrapper for activation context (#22)
Added safe rust wrappers for config package loading.
- Loading branch information
Showing
8 changed files
with
386 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(), | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
9 changes: 9 additions & 0 deletions
9
crates/samples/echo2/manifests/EchoAppServicePackage2/Config/Settings.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.