mirror of
https://github.com/OMGeeky/tarpc.git
synced 2026-02-23 15:49:54 +01:00
This PR obsoletes the JSON and Bincode transports and instead introduces a unified transport that is generic over any tokio-serde serialization format as well as AsyncRead + AsyncWrite medium. This comes with a slight hit for usability (having to manually specify the underlying transport and codec), but it can be alleviated by making custom freestanding connect and listen fns.
80 lines
3.0 KiB
Rust
80 lines
3.0 KiB
Rust
// Copyright 2018 Google LLC
|
|
//
|
|
// Use of this source code is governed by an MIT-style
|
|
// license that can be found in the LICENSE file or at
|
|
// https://opensource.org/licenses/MIT.
|
|
|
|
use futures::{
|
|
future::{self, Ready},
|
|
prelude::*,
|
|
};
|
|
use std::io;
|
|
use tarpc::{
|
|
client, context,
|
|
server::{BaseChannel, Channel},
|
|
};
|
|
use tokio_serde::formats::Json;
|
|
|
|
/// 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 {
|
|
async fn hello(name: String) -> String;
|
|
}
|
|
|
|
/// This is the type that implements the generated World trait. It is the business logic
|
|
/// and is used to start the server.
|
|
#[derive(Clone)]
|
|
struct HelloServer;
|
|
|
|
impl World for HelloServer {
|
|
// Each defined rpc generates two items in the trait, a fn that serves the RPC, and
|
|
// an associated type representing the future output by the fn.
|
|
|
|
type HelloFut = Ready<String>;
|
|
|
|
fn hello(self, _: context::Context, name: String) -> Self::HelloFut {
|
|
future::ready(format!("Hello, {}!", name))
|
|
}
|
|
}
|
|
|
|
#[tokio::main]
|
|
async fn main() -> io::Result<()> {
|
|
// tarpc_json_transport is provided by the associated crate json_transport. It makes it
|
|
// easy to start up a serde-powered JSON serialization strategy over TCP.
|
|
let mut transport = tarpc::serde_transport::tcp::listen("localhost:0", Json::default).await?;
|
|
let addr = transport.local_addr();
|
|
|
|
let server = async move {
|
|
// For this example, we're just going to wait for one connection.
|
|
let client = transport.next().await.unwrap().unwrap();
|
|
|
|
// `Channel` is a trait representing a server-side connection. It is a trait to allow
|
|
// for some channels to be instrumented: for example, to track the number of open connections.
|
|
// BaseChannel is the most basic channel, simply wrapping a transport with no added
|
|
// functionality.
|
|
BaseChannel::with_defaults(client)
|
|
// serve_world is generated by the tarpc::service attribute. It takes as input any type
|
|
// implementing the generated World trait.
|
|
.respond_with(HelloServer.serve())
|
|
.execute()
|
|
.await;
|
|
};
|
|
tokio::spawn(server);
|
|
|
|
let transport = tarpc::serde_transport::tcp::connect(addr, Json::default()).await?;
|
|
|
|
// WorldClient is generated by the tarpc::service attribute. It has a constructor `new` that
|
|
// takes a config and any Transport as input.
|
|
let mut client = WorldClient::new(client::Config::default(), transport).spawn()?;
|
|
|
|
// The client has an RPC method for each RPC defined in the annotated trait. It takes the same
|
|
// args as defined, with the addition of a Context, which is always the first arg. The Context
|
|
// specifies a deadline and trace information which can be helpful in debugging requests.
|
|
let hello = client.hello(context::current(), "Stim".to_string()).await?;
|
|
|
|
eprintln!("{}", hello);
|
|
|
|
Ok(())
|
|
}
|