6 个版本 (破坏性更新)
0.7.0 | 2019 年 5 月 11 日 |
---|---|
0.6.0 | 2019 年 4 月 30 日 |
0.5.0 | 2019 年 4 月 16 日 |
0.4.0 | 2019 年 3 月 27 日 |
0.1.0 | 2018 年 10 月 17 日 |
#23 in #bincode
115KB
2.5K SLoC
tarpc: Tim & Adam 的 RPC 库
免责声明:这不是一个官方的 Google 产品。
tarpc 是一个专注于易用性的 Rust RPC 框架。定义一个服务只需要几行代码,大多数编写服务器的样板代码都由框架自动处理。
什么是 RPC 框架?
"RPC" 代表 "远程过程调用",是一种函数调用,其中生成返回值的操作在其他地方进行。当调用 RPC 函数时,在幕后,函数会联系其他地方的某个进程,请求它们评估该函数。原始函数随后返回其他进程生成的值。
RPC 框架是大多数面向微服务的架构的基本构建块。其中两个著名的框架是 gRPC 和 Cap'n Proto。
tarpc 与其他 RPC 框架的不同之处在于,它通过代码定义模式,而不是使用如 .proto 这样的单独语言。这意味着没有单独的编译过程,也不需要在不同语言之间进行认知上下文切换。此外,它还与社区支持的库 serde 一起工作:任何 serde 序列化的类型都可以用作 tarpc 函数的参数。
用法
将以下依赖项添加到您的 Cargo.toml
tarpc = "0.18.0"
service!
宏扩展为形成一个 RPC 服务的项目集合。在上面的示例中,该宏在 hello_service
模块中被调用。此模块将包含一个 Client
模板和 Service
特性。这些生成的类型使得编写服务器变得简单而直观,无需直接处理序列化。只需实现生成的特性之一,您就可以开始编写服务了!
示例
这是一个小型服务。
#![feature(arbitrary_self_types, await_macro, async_await, proc_macro_hygiene)]
use futures::{
compat::Executor01CompatExt,
future::{self, Ready},
prelude::*,
};
use tarpc::{
client, context,
server::{self, Handler},
};
use std::io;
// 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! {
/// Returns a greeting for name.
rpc hello(name: String) -> String;
}
// This is the type that implements the generated Service trait. It is the business logic
// and is used to start the server.
#[derive(Clone)]
struct HelloServer;
impl Service 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))
}
}
async fn run() -> io::Result<()> {
// bincode_transport is provided by the associated crate bincode-transport. It makes it easy
// to start up a serde-powered bincode serialization strategy over TCP.
let transport = bincode_transport::listen(&"0.0.0.0:0".parse().unwrap())?;
let addr = transport.local_addr();
// The server is configured with the defaults.
let server = server::new(server::Config::default())
// Server can listen on any type that implements the Transport trait.
.incoming(transport)
// Close the stream after the client connects
.take(1)
// serve is generated by the service! macro. It takes as input any type implementing
// the generated Service trait.
.respond_with(serve(HelloServer));
tokio_executor::spawn(server.unit_error().boxed().compat());
let transport = await!(bincode_transport::connect(&addr))?;
// new_stub is generated by the service! macro. Like Server, it takes a config and any
// Transport as input, and returns a Client, also generated by the macro.
// by the service mcro.
let mut client = await!(new_stub(client::Config::default(), transport))?;
// The client has an RPC method for each RPC defined in service!. 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 = await!(client.hello(context::current(), "Stim".to_string()))?;
println!("{}", hello);
Ok(())
}
fn main() {
tarpc::init(tokio::executor::DefaultExecutor::current().compat());
tokio::run(run()
.map_err(|e| eprintln!("Oh no: {}", e))
.boxed()
.compat(),
);
}
服务文档
与平常一样使用 cargo doc
来查看由 service!
调用扩展的所有项目的文档。
依赖
~8.5MB
~148K SLoC