From 0527f7f5b705be5a22943f8ced982d69a546413b Mon Sep 17 00:00:00 2001 From: Youyuan Wu Date: Sat, 30 Dec 2023 17:17:00 -0800 Subject: [PATCH] refactor bridges to use generics --- crates/fabric/rs/src/runtime/mod.rs | 26 +++++--- crates/fabric/rs/src/runtime/stateful.rs | 7 ++- .../fabric/rs/src/runtime/stateful_bridge.rs | 56 ++++++++++++------ crates/fabric/rs/src/runtime/stateless.rs | 7 ++- .../fabric/rs/src/runtime/stateless_bridge.rs | 59 +++++++++++++------ crates/samples/echo2/src/echo.rs | 6 +- crates/samples/echo2/src/main.rs | 2 +- crates/samples/kvstore/src/kvstore.rs | 6 +- crates/samples/kvstore/src/main.rs | 2 +- scripts/echo2_ctl.ps1 | 59 +------------------ 10 files changed, 117 insertions(+), 113 deletions(-) diff --git a/crates/fabric/rs/src/runtime/mod.rs b/crates/fabric/rs/src/runtime/mod.rs index 200d53de..82618deb 100644 --- a/crates/fabric/rs/src/runtime/mod.rs +++ b/crates/fabric/rs/src/runtime/mod.rs @@ -17,8 +17,10 @@ use windows::core::implement; use windows_core::{ComInterface, Error, Interface, HSTRING, PCWSTR}; use self::{ - stateful::StatefulServiceFactory, stateful_bridge::StatefulServiceFactoryBridge, - stateless::StatelessServiceFactory, stateless_bridge::StatelessServiceFactoryBridge, + stateful::{StatefulServiceFactory, StatefulServiceReplica}, + stateful_bridge::StatefulServiceFactoryBridge, + stateless::{StatelessServiceFactory, StatelessServiceInstance}, + stateless_bridge::StatelessServiceFactoryBridge, }; pub mod error; @@ -61,11 +63,15 @@ impl Runtime { Ok(Runtime { com_impl: com, rt }) } - pub fn register_stateless_service_factory( + pub fn register_stateless_service_factory( &self, servicetypename: &HSTRING, - factory: Box, - ) -> windows_core::Result<()> { + factory: F, + ) -> windows_core::Result<()> + where + F: StatelessServiceFactory, + S: StatelessServiceInstance + 'static, + { let rt_cp = self.rt.clone(); let bridge: IFabricStatelessServiceFactory = StatelessServiceFactoryBridge::create(factory, rt_cp).into(); @@ -75,11 +81,15 @@ impl Runtime { } } - pub fn register_stateful_service_factory( + pub fn register_stateful_service_factory( &self, servicetypename: &HSTRING, - factory: Box, - ) -> windows_core::Result<()> { + factory: F, + ) -> windows_core::Result<()> + where + F: StatefulServiceFactory, + R: StatefulServiceReplica + 'static, + { let rt_cp = self.rt.clone(); let bridge: IFabricStatefulServiceFactory = StatefulServiceFactoryBridge::create(factory, rt_cp).into(); diff --git a/crates/fabric/rs/src/runtime/stateful.rs b/crates/fabric/rs/src/runtime/stateful.rs index b801675f..08232a8c 100644 --- a/crates/fabric/rs/src/runtime/stateful.rs +++ b/crates/fabric/rs/src/runtime/stateful.rs @@ -8,7 +8,10 @@ use super::stateful_types::{ Epoch, OpenMode, ReplicaInfo, ReplicaSetConfig, ReplicaSetQuarumMode, Role, }; -pub trait StatefulServiceFactory { +pub trait StatefulServiceFactory +where + R: StatefulServiceReplica, +{ fn create_replica( &self, servicetypename: &HSTRING, @@ -16,7 +19,7 @@ pub trait StatefulServiceFactory { initializationdata: &[u8], partitionid: &::windows::core::GUID, replicaid: i64, - ) -> Result, Error>; + ) -> Result; } // safe service instance diff --git a/crates/fabric/rs/src/runtime/stateful_bridge.rs b/crates/fabric/rs/src/runtime/stateful_bridge.rs index 79289397..bd32f782 100644 --- a/crates/fabric/rs/src/runtime/stateful_bridge.rs +++ b/crates/fabric/rs/src/runtime/stateful_bridge.rs @@ -1,6 +1,6 @@ // stateful bridge is to wrap rs types into com to expose to SF -use std::sync::Arc; +use std::{marker::PhantomData, sync::Arc}; use log::info; use tokio::runtime::Handle; @@ -35,21 +35,35 @@ use super::stateful::{ }; #[implement(IFabricStatefulServiceFactory)] -pub struct StatefulServiceFactoryBridge { - inner: Box, +pub struct StatefulServiceFactoryBridge +where + F: StatefulServiceFactory, + R: StatefulServiceReplica + 'static, +{ + inner: F, rt: Handle, + phantom: PhantomData, } -impl StatefulServiceFactoryBridge { - pub fn create( - factory: Box, - rt: Handle, - ) -> StatefulServiceFactoryBridge { - StatefulServiceFactoryBridge { inner: factory, rt } +impl StatefulServiceFactoryBridge +where + F: StatefulServiceFactory, + R: StatefulServiceReplica, +{ + pub fn create(factory: F, rt: Handle) -> StatefulServiceFactoryBridge { + StatefulServiceFactoryBridge:: { + inner: factory, + rt, + phantom: PhantomData, + } } } -impl IFabricStatefulServiceFactory_Impl for StatefulServiceFactoryBridge { +impl IFabricStatefulServiceFactory_Impl for StatefulServiceFactoryBridge +where + F: StatefulServiceFactory, + R: StatefulServiceReplica + 'static, +{ #[allow(clippy::not_unsafe_ptr_arg_deref)] fn CreateReplica( &self, @@ -524,16 +538,19 @@ impl IFabricPrimaryReplicator_Impl for IFabricPrimaryReplicatorBridge { // bridge from safe service instance to com #[implement(IFabricStatefulServiceReplica)] -pub struct IFabricStatefulServiceReplicaBridge { - inner: Arc>, +pub struct IFabricStatefulServiceReplicaBridge +where + R: StatefulServiceReplica + 'static, +{ + inner: Arc, rt: Handle, } -impl IFabricStatefulServiceReplicaBridge { - pub fn create( - rplctr: Box, - rt: Handle, - ) -> IFabricStatefulServiceReplicaBridge { +impl IFabricStatefulServiceReplicaBridge +where + R: StatefulServiceReplica, +{ + pub fn create(rplctr: R, rt: Handle) -> IFabricStatefulServiceReplicaBridge { IFabricStatefulServiceReplicaBridge { inner: Arc::new(rplctr), rt, @@ -541,7 +558,10 @@ impl IFabricStatefulServiceReplicaBridge { } } -impl IFabricStatefulServiceReplica_Impl for IFabricStatefulServiceReplicaBridge { +impl IFabricStatefulServiceReplica_Impl for IFabricStatefulServiceReplicaBridge +where + R: StatefulServiceReplica + 'static, +{ fn BeginOpen( &self, openmode: FABRIC_REPLICA_OPEN_MODE, diff --git a/crates/fabric/rs/src/runtime/stateless.rs b/crates/fabric/rs/src/runtime/stateless.rs index 1104aed1..b5585c80 100644 --- a/crates/fabric/rs/src/runtime/stateless.rs +++ b/crates/fabric/rs/src/runtime/stateless.rs @@ -85,7 +85,10 @@ impl StatelessServicePartition { } // safe factory -pub trait StatelessServiceFactory { +pub trait StatelessServiceFactory +where + T: StatelessServiceInstance, +{ fn create_instance( &self, servicetypename: &HSTRING, @@ -93,7 +96,7 @@ pub trait StatelessServiceFactory { initializationdata: &[u8], partitionid: &::windows::core::GUID, instanceid: i64, - ) -> Box; + ) -> T; } // safe service instance diff --git a/crates/fabric/rs/src/runtime/stateless_bridge.rs b/crates/fabric/rs/src/runtime/stateless_bridge.rs index bc11650d..510b4990 100644 --- a/crates/fabric/rs/src/runtime/stateless_bridge.rs +++ b/crates/fabric/rs/src/runtime/stateless_bridge.rs @@ -1,6 +1,6 @@ #![deny(non_snake_case)] // this file is safe rust -use std::sync::Arc; +use std::{marker::PhantomData, sync::Arc}; use crate::{ runtime::{stateless::StatelessServicePartition, BridgeContext}, @@ -22,21 +22,35 @@ use windows_core::{AsImpl, Error, HSTRING}; use super::stateless::{StatelessServiceFactory, StatelessServiceInstance}; #[implement(IFabricStatelessServiceFactory)] -pub struct StatelessServiceFactoryBridge { - inner: Box, +pub struct StatelessServiceFactoryBridge +where + F: StatelessServiceFactory, + S: StatelessServiceInstance + 'static, +{ + inner: F, rt: Handle, + phantom: PhantomData, } -impl StatelessServiceFactoryBridge { - pub fn create( - factory: Box, - rt: Handle, - ) -> StatelessServiceFactoryBridge { - StatelessServiceFactoryBridge { inner: factory, rt } +impl StatelessServiceFactoryBridge +where + F: StatelessServiceFactory, + S: StatelessServiceInstance, +{ + pub fn create(factory: F, rt: Handle) -> StatelessServiceFactoryBridge { + StatelessServiceFactoryBridge:: { + inner: factory, + rt, + phantom: PhantomData, + } } } -impl IFabricStatelessServiceFactory_Impl for StatelessServiceFactoryBridge { +impl IFabricStatelessServiceFactory_Impl for StatelessServiceFactoryBridge +where + F: StatelessServiceFactory, + S: StatelessServiceInstance + 'static, +{ #[allow(clippy::not_unsafe_ptr_arg_deref)] fn CreateInstance( &self, @@ -72,16 +86,22 @@ impl IFabricStatelessServiceFactory_Impl for StatelessServiceFactoryBridge { // bridge from safe service instance to com #[implement(IFabricStatelessServiceInstance)] -struct IFabricStatelessServiceInstanceBridge { - inner: Arc>, +struct IFabricStatelessServiceInstanceBridge +where + S: StatelessServiceInstance + 'static, +{ + inner: Arc, rt: Handle, } -impl IFabricStatelessServiceInstanceBridge { - pub fn create( - instance: Box, - rt: Handle, - ) -> IFabricStatelessServiceInstanceBridge { +impl IFabricStatelessServiceInstanceBridge +where + S: StatelessServiceInstance, +{ + pub fn create(instance: S, rt: Handle) -> IFabricStatelessServiceInstanceBridge + where + S: StatelessServiceInstance, + { IFabricStatelessServiceInstanceBridge { inner: Arc::new(instance), rt, @@ -89,7 +109,10 @@ impl IFabricStatelessServiceInstanceBridge { } } -impl IFabricStatelessServiceInstance_Impl for IFabricStatelessServiceInstanceBridge { +impl IFabricStatelessServiceInstance_Impl for IFabricStatelessServiceInstanceBridge +where + S: StatelessServiceInstance + 'static, +{ fn BeginOpen( &self, partition: ::core::option::Option<&IFabricStatelessServicePartition>, diff --git a/crates/samples/echo2/src/echo.rs b/crates/samples/echo2/src/echo.rs index aa096f44..200b0ca0 100644 --- a/crates/samples/echo2/src/echo.rs +++ b/crates/samples/echo2/src/echo.rs @@ -8,7 +8,7 @@ use windows_core::HSTRING; #[derive(Default)] pub struct Factory {} -impl StatelessServiceFactory for Factory { +impl StatelessServiceFactory for Factory { fn create_instance( &self, servicetypename: &windows_core::HSTRING, @@ -16,7 +16,7 @@ impl StatelessServiceFactory for Factory { initializationdata: &[u8], partitionid: &windows::core::GUID, instanceid: i64, - ) -> Box { + ) -> Instance { info!( "Factory::create_instance, servicetype {}, service {}, init len {}, ptid {:?}, iid {}", servicetypename, @@ -25,7 +25,7 @@ impl StatelessServiceFactory for Factory { partitionid, instanceid ); - Box::::default() + Instance::default() } } diff --git a/crates/samples/echo2/src/main.rs b/crates/samples/echo2/src/main.rs index 1e634d8f..cb7e2fc4 100644 --- a/crates/samples/echo2/src/main.rs +++ b/crates/samples/echo2/src/main.rs @@ -21,7 +21,7 @@ fn main() -> windows::core::Result<()> { let rt = tokio::runtime::Runtime::new().unwrap(); let runtime = Runtime::create(rt.handle().clone()).unwrap(); - let factory = Box::::default(); + let factory = echo::Factory::default(); runtime .register_stateless_service_factory(&HSTRING::from("EchoAppService2"), factory) .unwrap(); diff --git a/crates/samples/kvstore/src/kvstore.rs b/crates/samples/kvstore/src/kvstore.rs index d5c2ddc4..d65f8f10 100644 --- a/crates/samples/kvstore/src/kvstore.rs +++ b/crates/samples/kvstore/src/kvstore.rs @@ -47,7 +47,7 @@ fn get_addr(port: u32, hostname: HSTRING) -> String { addr } -impl StatefulServiceFactory for Factory { +impl StatefulServiceFactory for Factory { fn create_replica( &self, servicetypename: &windows_core::HSTRING, @@ -55,7 +55,7 @@ impl StatefulServiceFactory for Factory { initializationdata: &[u8], partitionid: &windows::core::GUID, replicaid: i64, - ) -> Result, Error> { + ) -> Result { info!( "Factory::create_replica type {}, service {}, init data size {}", servicetypename, @@ -89,7 +89,7 @@ impl StatefulServiceFactory for Factory { let svc = Service::new(kv, self.rt.clone()); let replica = Replica::new(proxy, svc); - Ok(Box::new(replica)) + Ok(replica) } } diff --git a/crates/samples/kvstore/src/main.rs b/crates/samples/kvstore/src/main.rs index 8962d655..d8eae6da 100644 --- a/crates/samples/kvstore/src/main.rs +++ b/crates/samples/kvstore/src/main.rs @@ -40,7 +40,7 @@ fn main() -> windows::core::Result<()> { .get_endpoint_resource(&HSTRING::from("KvReplicatorEndpoint")) .unwrap(); - let factory = Box::new(Factory::create(endpoint.Port, rt.handle().clone())); + let factory = Factory::create(endpoint.Port, rt.handle().clone()); runtime .register_stateful_service_factory(&HSTRING::from("KvStoreService"), factory) .unwrap(); diff --git a/scripts/echo2_ctl.ps1 b/scripts/echo2_ctl.ps1 index 9e2bd67f..062cf9c9 100644 --- a/scripts/echo2_ctl.ps1 +++ b/scripts/echo2_ctl.ps1 @@ -27,64 +27,9 @@ if($Action -eq "Connect"){ Remove-ServiceFabricApplicationPackage -ApplicationPackagePathInImageStore MyApplicationV1 -Force }elseif($Action -eq "Resolve"){ Connect-ServiceFabricCluster - Resolve-ServiceFabricService -ServiceName fabric:/EchoApp/EchoAppService -PartitionKindSingleton -ForceRefresh + Resolve-ServiceFabricService -ServiceName fabric:/EchoApp2/EchoAppService -PartitionKindSingleton -ForceRefresh }elseif($Action -eq "Echo"){ - Connect-ServiceFabricCluster - $resolve = Resolve-ServiceFabricService -ServiceName fabric:/EchoApp/EchoAppService -PartitionKindSingleton -ForceRefresh - Write-Host $resolve - $addr = $resolve.Endpoints.Address - $pair = $addr.Split(":") - $hostname = $pair[0] - $port = $pair[1] - - $tcpConnection = New-Object System.Net.Sockets.TcpClient("$hostname", "$port") - $tcpStream = $tcpConnection.GetStream() - $reader = New-Object System.IO.StreamReader($tcpStream) - $writer = New-Object System.IO.StreamWriter($tcpStream) - $writer.AutoFlush = $true - - while ($tcpConnection.Connected) - { - if ($tcpConnection.Connected) - { - if($Mode -eq "Test"){ - $writer.WriteLine("hello") | Out-Null - }else{ - Write-Host -NoNewline "prompt> " - $command = Read-Host - - if ($command -eq "escape") - { - break - } - - $writer.WriteLine($command) | Out-Null - } - } - while ($tcpStream.DataAvailable -or $reader.Peek() -ne -1 ) { - if($Mode -eq "Test"){ - $reply = $reader.ReadLine() - if($reply -ne "hello") - { - Write-Error "reply $reply is not hello" - Exit 1 - } - Write-Host "Echo test success" - break - }else{ - Write-Host $reader.ReadLine() - } - } - - if($Mode -eq "Test"){ - break - } - start-sleep -Milliseconds 500 - } - - $reader.Close() - $writer.Close() - $tcpConnection.Close() + }