Created
August 29, 2024 08:32
-
-
Save willcl-ark/5c95c05f795b35d9e3069a07ffbffd5e to your computer and use it in GitHub Desktop.
This file contains hidden or 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
use std::marker::PhantomData; | |
use tokio::sync::mpsc; | |
use anyhow::Result; | |
// Define a trait for RPC methods | |
pub trait RpcMethod<C> { | |
type Input; | |
type Output; | |
fn call(client: &C, input: Self::Input) -> Result<Self::Output>; | |
} | |
// Generic Proxy struct | |
pub struct Proxy<C> { | |
sender: mpsc::UnboundedSender<Box<dyn FnOnce(&C) -> Result<()> + Send>>, | |
_phantom: PhantomData<C>, | |
} | |
impl<C: 'static> Proxy<C> { | |
pub fn new(client: C) -> Self { | |
let (sender, mut receiver) = mpsc::unbounded_channel(); | |
tokio::spawn(async move { | |
while let Some(task) = receiver.recv().await { | |
task(&client)?; | |
} | |
}); | |
Self { | |
sender, | |
_phantom: PhantomData, | |
} | |
} | |
pub async fn call<M: RpcMethod<C> + 'static>(&self, input: M::Input) -> Result<M::Output> { | |
let (response_sender, response_receiver) = tokio::sync::oneshot::channel(); | |
self.sender.send(Box::new(move |client| { | |
let result = M::call(client, input); | |
response_sender.send(result).map_err(|_| anyhow::anyhow!("Failed to send response"))?; | |
Ok(()) | |
}))?; | |
response_receiver.await? | |
} | |
} | |
// Macro to generate client implementations | |
macro_rules! impl_client { | |
($client:ident, $($method:ident($input:ty) -> $output:ty),*) => { | |
$( | |
pub struct $method; | |
impl RpcMethod<$client> for $method { | |
type Input = $input; | |
type Output = $output; | |
fn call(client: &$client, input: Self::Input) -> Result<Self::Output> { | |
client.$method(input) | |
} | |
} | |
)* | |
}; | |
} | |
// EchoClient implementation | |
pub struct EchoClient { | |
// Add any necessary fields | |
} | |
impl EchoClient { | |
pub fn new() -> Self { | |
Self {} | |
} | |
pub fn echo(&self, message: String) -> Result<String> { | |
Ok(message) | |
} | |
} | |
impl_client!(EchoClient, echo(String) -> String); | |
// Usage example | |
async fn example() -> Result<()> { | |
let echo_client = EchoClient::new(); | |
let proxy = Proxy::new(echo_client); | |
let result = proxy.call::<echo>(String::from("Hello, world!")).await?; | |
println!("Echo result: {}", result); | |
Ok(()) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment