Skip to content

Instantly share code, notes, and snippets.

@laysakura
Last active January 19, 2021 02:21
Show Gist options
  • Select an option

  • Save laysakura/8baf784923181042aa54dce179d76aa4 to your computer and use it in GitHub Desktop.

Select an option

Save laysakura/8baf784923181042aa54dce179d76aa4 to your computer and use it in GitHub Desktop.
tarpc !Sync server
// [dependencies]
// futures = "0.3"
// tarpc = {version = "0.24", features = ["full"]}
// tokio = {version = "1.0", features = ["macros"]}
use futures::{
future::{self},
prelude::*,
};
use std::{
net::{IpAddr, SocketAddr},
pin::Pin,
};
use tarpc::server::Channel;
use tarpc::{
context,
server::{self, Handler},
tokio_serde::formats::Json,
};
use tokio::task;
// This is the service definition. It looks a lot like a trait definition.
// It defines one RPC, hello, which takes one arg, name, and returns a String.
#[tarpc::service]
pub trait World {
/// Returns a greeting for name.
async fn hello(name: String) -> String;
}
type BoxFut<O> = Pin<Box<dyn Future<Output = O>>>;
// This is the type that implements the generated World trait. It is the business logic
// and is used to start the server.
#[derive(Clone)]
pub struct HelloServer(SocketAddr);
impl World for HelloServer {
type HelloFut = BoxFut<String>;
fn hello(self, _: context::Context, name: String) -> Self::HelloFut {
async move { format!("Hello, {}!", name) }.boxed_local()
}
}
#[tokio::main]
async fn main() -> std::io::Result<()> {
let local = task::LocalSet::new();
local
.run_until(async move {
let port = "8888"
.parse()
.unwrap_or_else(|e| panic!(r#"--port value "{}" invalid: {}"#, "8888", e));
let server_addr = (IpAddr::from([0, 0, 0, 0]), port);
let listener = tarpc::serde_transport::tcp::listen(&server_addr, Json::default)
.await
.unwrap();
listener
// Ignore accept errors.
.filter_map(|r| future::ready(r.ok()))
.map(server::BaseChannel::with_defaults)
// Limit channels to 1 per IP.
.max_channels_per_key(1, |t| t.as_ref().peer_addr().unwrap().ip())
// serve is generated by the service attribute. It takes as input any type implementing
// the generated World trait.
.map(|channel| {
let server = HelloServer(channel.as_ref().as_ref().peer_addr().unwrap());
channel.respond_with(server.serve()).try_for_each(
|request_handler| async move {
request_handler.await;
Ok(())
},
)
})
// Max 10 channels.
.buffer_unordered(10)
.for_each(|_| async {})
.await;
})
.await;
Ok(())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment