mirror of
https://github.com/OMGeeky/tarpc.git
synced 2026-01-19 18:00:48 +01:00
* Make a reactor handle mandatory for server. This removes the Send bound from FutureService. The Send bound is still required for SyncService, since clones are sent to new threads for each request. (This is more fodder for the argument that there should be a distinct Options struct for each combination of async/sync and client/server.) This commit also makes FutureService::listen return an io::Result rather than a Future; the future was never really necessary and had the unintended consequence of making SyncService::listen deadlock when the options specified a handle (because that means the reactor driving the service lives on the same thread that SyncService is waiting on). `SyncClient` is no longer `Clone` because it needs to create a new `reactor::Core` when cloning. Tokio Clients are `Clone` but they don't allow moving the cloned client onto a new reactor. * Change pubsub to use Rc<Refcell<>> instead of Arc<Mutex<>>. This is possible since services no longer need to be Send. * Remove some unnecessary unstable features. There 3 remaining unstable features. The hardest to remove is plugin, because we rely on compiler plugins to rewrite types from snake case to camel. It's possible this can be removed before the proc macros rewrite lands if impl Trait is extended to work with traits. * Clean up example * Sync servers now spawn a reactor on a thread. It's decided that sync users should not have to know about tokio at all. * Don't allow specifying a reactor::Core on client options. * Fail fast in server::listen if local_addr() returns Err.
197 lines
6.0 KiB
Rust
197 lines
6.0 KiB
Rust
// Copyright 2016 Google Inc. All Rights Reserved.
|
|
//
|
|
// Licensed under the MIT License, <LICENSE or http://opensource.org/licenses/MIT>.
|
|
// This file may not be copied, modified, or distributed except according to those terms.
|
|
|
|
//! tarpc is an RPC framework for rust with a focus on ease of use. Defining a
|
|
//! service can be done in just a few lines of code, and most of the boilerplate of
|
|
//! writing a server is taken care of for you.
|
|
//!
|
|
//! ## What is an RPC framework?
|
|
//! "RPC" stands for "Remote Procedure Call," a function call where the work of
|
|
//! producing the return value is being done somewhere else. When an rpc function is
|
|
//! invoked, behind the scenes the function contacts some other process somewhere
|
|
//! and asks them to evaluate the function instead. The original function then
|
|
//! returns the value produced by the other process.
|
|
//!
|
|
//! RPC frameworks are a fundamental building block of most microservices-oriented
|
|
//! architectures. Two well-known ones are [gRPC](http://www.grpc.io) and
|
|
//! [Cap'n Proto](https://capnproto.org/).
|
|
//!
|
|
//! tarpc differentiates itself from other RPC frameworks by defining the schema in code,
|
|
//! rather than in a separate language such as .proto. This means there's no separate compilation
|
|
//! process, and no cognitive context switching between different languages. Additionally, it
|
|
//! works with the community-backed library serde: any serde-serializable type can be used as
|
|
//! arguments to tarpc fns.
|
|
//!
|
|
//! Example usage:
|
|
//!
|
|
//! ```
|
|
//! // required by `FutureClient` (not used in this example)
|
|
//! #![feature(conservative_impl_trait, plugin)]
|
|
//! #![plugin(tarpc_plugins)]
|
|
//!
|
|
//! #[macro_use]
|
|
//! extern crate tarpc;
|
|
//! extern crate tokio_core;
|
|
//!
|
|
//! use tarpc::{client, server};
|
|
//! use tarpc::client::sync::ClientExt;
|
|
//! use tarpc::util::Never;
|
|
//! use tokio_core::reactor;
|
|
//!
|
|
//! service! {
|
|
//! rpc hello(name: String) -> String;
|
|
//! }
|
|
//!
|
|
//! #[derive(Clone)]
|
|
//! struct HelloServer;
|
|
//!
|
|
//! impl SyncService for HelloServer {
|
|
//! fn hello(&self, name: String) -> Result<String, Never> {
|
|
//! Ok(format!("Hello, {}!", name))
|
|
//! }
|
|
//! }
|
|
//!
|
|
//! fn main() {
|
|
//! let addr = "localhost:10000";
|
|
//! let reactor = reactor::Core::new().unwrap();
|
|
//! let _server = HelloServer.listen(addr, server::Options::default());
|
|
//! let mut client = SyncClient::connect(addr, client::Options::default()).unwrap();
|
|
//! println!("{}", client.hello("Mom".to_string()).unwrap());
|
|
//! }
|
|
//! ```
|
|
//!
|
|
//! Example usage with TLS:
|
|
//!
|
|
//! ```ignore
|
|
//! // required by `FutureClient` (not used in this example)
|
|
//! #![feature(conservative_impl_trait, plugin)]
|
|
//! #![plugin(tarpc_plugins)]
|
|
//!
|
|
//! #[macro_use]
|
|
//! extern crate tarpc;
|
|
//!
|
|
//! use tarpc::{client, server};
|
|
//! use tarpc::client::sync::ClientExt;
|
|
//! use tarpc::util::Never;
|
|
//! use tarpc::native_tls::{TlsAcceptor, Pkcs12};
|
|
//!
|
|
//! service! {
|
|
//! rpc hello(name: String) -> String;
|
|
//! }
|
|
//!
|
|
//! #[derive(Clone)]
|
|
//! struct HelloServer;
|
|
//!
|
|
//! impl SyncService for HelloServer {
|
|
//! fn hello(&self, name: String) -> Result<String, Never> {
|
|
//! Ok(format!("Hello, {}!", name))
|
|
//! }
|
|
//! }
|
|
//!
|
|
//! fn get_acceptor() -> TlsAcceptor {
|
|
//! let buf = include_bytes!("test/identity.p12");
|
|
//! let pkcs12 = Pkcs12::from_der(buf, "password").unwrap();
|
|
//! TlsAcceptor::builder(pkcs12).unwrap().build().unwrap()
|
|
//! }
|
|
//!
|
|
//! fn main() {
|
|
//! let addr = "localhost:10000";
|
|
//! let acceptor = get_acceptor();
|
|
//! let _server = HelloServer.listen(addr, server::Options::default().tls(acceptor));
|
|
//! let mut client = SyncClient::connect(addr,
|
|
//! client::Options::default()
|
|
//! .tls(client::tls::Context::new("foobar.com").unwrap()))
|
|
//! .unwrap();
|
|
//! println!("{}", client.hello("Mom".to_string()).unwrap());
|
|
//! }
|
|
//! ```
|
|
//!
|
|
#![deny(missing_docs)]
|
|
#![feature(plugin, never_type, struct_field_attributes)]
|
|
#![plugin(tarpc_plugins)]
|
|
|
|
extern crate byteorder;
|
|
#[macro_use]
|
|
extern crate lazy_static;
|
|
#[macro_use]
|
|
extern crate log;
|
|
extern crate net2;
|
|
#[macro_use]
|
|
extern crate serde_derive;
|
|
#[macro_use]
|
|
extern crate cfg_if;
|
|
|
|
#[doc(hidden)]
|
|
pub extern crate bincode;
|
|
#[doc(hidden)]
|
|
pub extern crate futures;
|
|
#[doc(hidden)]
|
|
pub extern crate serde;
|
|
#[doc(hidden)]
|
|
pub extern crate tokio_core;
|
|
#[doc(hidden)]
|
|
pub extern crate tokio_proto;
|
|
#[doc(hidden)]
|
|
pub extern crate tokio_service;
|
|
|
|
pub use errors::Error;
|
|
#[doc(hidden)]
|
|
pub use errors::WireError;
|
|
|
|
/// Provides some utility error types, as well as a trait for spawning futures on the default event
|
|
/// loop.
|
|
pub mod util;
|
|
|
|
/// Provides the macro used for constructing rpc services and client stubs.
|
|
#[macro_use]
|
|
mod macros;
|
|
/// Provides the base client stubs used by the service macro.
|
|
pub mod client;
|
|
/// Provides the base server boilerplate used by service implementations.
|
|
pub mod server;
|
|
/// Provides implementations of `ClientProto` and `ServerProto` that implement the tarpc protocol.
|
|
/// The tarpc protocol is a length-delimited, bincode-serialized payload.
|
|
mod protocol;
|
|
/// Provides a few different error types.
|
|
mod errors;
|
|
/// Provides an abstraction over TLS and TCP streams.
|
|
mod stream_type;
|
|
|
|
use std::sync::mpsc;
|
|
use std::thread;
|
|
use tokio_core::reactor;
|
|
|
|
lazy_static! {
|
|
/// The `Remote` for the default reactor core.
|
|
static ref REMOTE: reactor::Remote = {
|
|
spawn_core()
|
|
};
|
|
}
|
|
|
|
/// Spawns a `reactor::Core` running forever on a new thread.
|
|
fn spawn_core() -> reactor::Remote {
|
|
let (tx, rx) = mpsc::channel();
|
|
thread::spawn(move || {
|
|
let mut core = reactor::Core::new().unwrap();
|
|
tx.send(core.handle().remote().clone()).unwrap();
|
|
|
|
// Run forever
|
|
core.run(futures::empty::<(), !>()).unwrap();
|
|
});
|
|
rx.recv().unwrap()
|
|
}
|
|
|
|
cfg_if! {
|
|
if #[cfg(feature = "tls")] {
|
|
extern crate tokio_tls;
|
|
extern crate native_tls as native_tls_inner;
|
|
|
|
/// Re-exported TLS-related types
|
|
pub mod native_tls {
|
|
pub use native_tls_inner::{Error, Pkcs12, TlsAcceptor, TlsConnector};
|
|
}
|
|
} else {}
|
|
}
|