Skip to content

Instantly share code, notes, and snippets.

@willcl-ark
Created August 29, 2024 08:32
Show Gist options
  • Save willcl-ark/5c95c05f795b35d9e3069a07ffbffd5e to your computer and use it in GitHub Desktop.
Save willcl-ark/5c95c05f795b35d9e3069a07ffbffd5e to your computer and use it in GitHub Desktop.
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