mirror of
https://github.com/OMGeeky/tarpc.git
synced 2026-02-23 15:49:54 +01:00
Clean up the syntax; add the README.md (I forgot to git add it last time)
This commit is contained in:
44
tarpc/README.md
Normal file
44
tarpc/README.md
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
## tarpc
|
||||||
|
|
||||||
|
tarpc is an RPC framework for rust with a focus on ease of use. Defining and implementing an echo-like server can be done in just a few lines of code:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#![feature(custom_derive, plugin)]
|
||||||
|
#![plugin(serde_macros)]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate tarpc;
|
||||||
|
extern crate serde;
|
||||||
|
|
||||||
|
rpc! {
|
||||||
|
mod hello_service {
|
||||||
|
service {
|
||||||
|
hello(name: String) -> String;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl hello_service::Service for () {
|
||||||
|
fn hello(&self, name: String) -> String {
|
||||||
|
format!("Hello, {}!", s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let server_handle = hello_service::serve("0.0.0.0:0", ()).unwrap();
|
||||||
|
let client = hello_service::Client::new(server_handle.local_addr()).unwrap();
|
||||||
|
assert_eq!("Hello, Mom!".into(), client.hello("Mom".into()).unwrap());
|
||||||
|
drop(client);
|
||||||
|
server_handle.shutdown();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The `rpc!` macro generates a module in the current module. In the above example, the module is named `hello_service`. This module will contain a `Client` type, a `Service` trait, and a `serve` function. `serve` can be used to start a server listening on a tcp port. A `Client` can connect to such a service. Any type implementing the `Service` trait can be passed to `serve`. These generated types are specific to the echo service, and make it easy and ergonomic to write servers without dealing with sockets or serialization directly. See the tarpc_examples package for more sophisticated examples.
|
||||||
|
|
||||||
|
## Planned Improvements (actively being worked on)
|
||||||
|
|
||||||
|
- Automatically reconnect on the client side when the connection cuts out.
|
||||||
|
- Allow omitting the return type in rpc definitions when the type is `()`.
|
||||||
|
- Allow users to specify imports inside the `rpc!` macro
|
||||||
|
- Support arbitrary serialization. (currently `serde_json` is used for all serialization)
|
||||||
|
- Support asynchronous server implementations (currently thread per connection).
|
||||||
|
- Support doc comments on rpc method definitions
|
||||||
@@ -8,10 +8,14 @@
|
|||||||
//! # #![plugin(serde_macros)]
|
//! # #![plugin(serde_macros)]
|
||||||
//! # #[macro_use] extern crate tarpc;
|
//! # #[macro_use] extern crate tarpc;
|
||||||
//! # extern crate serde;
|
//! # extern crate serde;
|
||||||
//! rpc_service!(my_server:
|
//! rpc! {
|
||||||
//! rpc hello(name: String) -> String;
|
//! mod my_server {
|
||||||
//! rpc add(x: i32, y: i32) -> i32;
|
//! service {
|
||||||
//! );
|
//! hello(name: String) -> String;
|
||||||
|
//! add(x: i32, y: i32) -> i32;
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
//!
|
//!
|
||||||
//! use self::my_server::*;
|
//! use self::my_server::*;
|
||||||
//!
|
//!
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! as_item { ($i:item) => {$i} }
|
macro_rules! as_item { ($i:item) => {$i} }
|
||||||
|
|
||||||
// Required because if-let can't be used with irrefutable patterns, so it needs to be special
|
// Required because if-let can't be used with irrefutable patterns, so it needs
|
||||||
|
// to be special
|
||||||
// cased.
|
// cased.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! request_fns {
|
macro_rules! request_fns {
|
||||||
@@ -48,11 +49,46 @@ macro_rules! request_variant {
|
|||||||
|
|
||||||
// The main macro that creates RPC services.
|
// The main macro that creates RPC services.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! rpc_service { ($server:ident:
|
macro_rules! rpc {
|
||||||
$( rpc $fn_name:ident( $( $arg:ident : $in_:ty ),* ) -> $out:ty;)*) => {
|
(
|
||||||
|
mod $server:ident {
|
||||||
|
|
||||||
|
service {
|
||||||
|
$( $fn_name:ident( $( $arg:ident : $in_:ty ),* ) -> $out:ty;)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
rpc! {
|
||||||
|
mod $server {
|
||||||
|
|
||||||
|
items { }
|
||||||
|
|
||||||
|
service { $( $fn_name($($arg: $in_),*) -> $out;)* }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
(
|
||||||
|
// Names the service
|
||||||
|
mod $server:ident {
|
||||||
|
|
||||||
|
// Include any desired or required items. Conflicts can arise with the following names:
|
||||||
|
// 1. Service
|
||||||
|
// 2. Client
|
||||||
|
// 3. serve
|
||||||
|
// 4. __Reply
|
||||||
|
// 5. __Request
|
||||||
|
items { $($i:item)* }
|
||||||
|
|
||||||
|
// List any rpc methods: rpc foo(arg1: Arg1, ..., argN: ArgN) -> Out
|
||||||
|
service { $( $fn_name:ident( $( $arg:ident : $in_:ty ),* ) -> $out:ty;)* }
|
||||||
|
}
|
||||||
|
) => {
|
||||||
#[doc="A module containing an rpc service and client stub."]
|
#[doc="A module containing an rpc service and client stub."]
|
||||||
pub mod $server {
|
pub mod $server {
|
||||||
|
|
||||||
|
$($i)*
|
||||||
|
|
||||||
#[doc="The provided RPC service."]
|
#[doc="The provided RPC service."]
|
||||||
pub trait Service: Send + Sync {
|
pub trait Service: Send + Sync {
|
||||||
$(
|
$(
|
||||||
@@ -115,22 +151,27 @@ macro_rules! rpc_service { ($server:ident:
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
mod test {
|
mod test {
|
||||||
rpc_service!(my_server:
|
rpc! {
|
||||||
rpc hello(foo: super::Foo) -> super::Foo;
|
mod my_server {
|
||||||
|
items {
|
||||||
|
#[derive(PartialEq, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct Foo {
|
||||||
|
pub message: String
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rpc add(x: i32, y: i32) -> i32;
|
service {
|
||||||
);
|
hello(foo: Foo) -> Foo;
|
||||||
|
add(x: i32, y: i32) -> i32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
use self::my_server::*;
|
use self::my_server::*;
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Serialize, Deserialize)]
|
|
||||||
pub struct Foo {
|
|
||||||
message: String
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Service for () {
|
impl Service for () {
|
||||||
fn hello(&self, s: Foo) -> Foo {
|
fn hello(&self, s: Foo) -> Foo {
|
||||||
Foo{message: format!("Hello, {}", &s.message)}
|
Foo { message: format!("Hello, {}", &s.message) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add(&self, x: i32, y: i32) -> i32 {
|
fn add(&self, x: i32, y: i32) -> i32 {
|
||||||
@@ -145,15 +186,32 @@ mod test {
|
|||||||
let shutdown = my_server::serve(addr, ()).unwrap();
|
let shutdown = my_server::serve(addr, ()).unwrap();
|
||||||
let client = Client::new(addr).unwrap();
|
let client = Client::new(addr).unwrap();
|
||||||
assert_eq!(3, client.add(1, 2).unwrap());
|
assert_eq!(3, client.add(1, 2).unwrap());
|
||||||
let foo = Foo{message: "Adam".into()};
|
let foo = Foo { message: "Adam".into() };
|
||||||
let want = Foo{message: format!("Hello, {}", &foo.message)};
|
let want = Foo { message: format!("Hello, {}", &foo.message) };
|
||||||
assert_eq!(want, client.hello(Foo{message: "Adam".into()}).unwrap());
|
assert_eq!(want, client.hello(Foo { message: "Adam".into() }).unwrap());
|
||||||
drop(client);
|
drop(client);
|
||||||
shutdown.shutdown();
|
shutdown.shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a test of a service with a fn that takes no args
|
// Tests a service definition with a fn that takes no args
|
||||||
rpc_service! {foo:
|
rpc! {
|
||||||
rpc hello() -> String;
|
mod foo {
|
||||||
|
service {
|
||||||
|
hello() -> String;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests a service definition with an import
|
||||||
|
rpc! {
|
||||||
|
mod bar {
|
||||||
|
items {
|
||||||
|
use std::collections::HashMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
service {
|
||||||
|
baz(s: String) -> HashMap<String, String>;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user