mirror of
https://github.com/OMGeeky/tarpc.git
synced 2026-02-23 15:49:54 +01:00
Remove some panics, and don't use ToSocketAddrs in async methods.
This commit is contained in:
@@ -97,7 +97,7 @@ pub use errors::{WireError};
|
||||
#[doc(hidden)]
|
||||
pub use framed::Framed;
|
||||
#[doc(hidden)]
|
||||
pub use server::{ListenFuture, Response, listen_pipeline};
|
||||
pub use server::{ListenFuture, Response, listen, listen_with};
|
||||
|
||||
/// Provides some utility error types, as well as a trait for spawning futures on the default event
|
||||
/// loop.
|
||||
|
||||
@@ -399,10 +399,8 @@ macro_rules! service {
|
||||
pub trait FutureServiceExt: FutureService {
|
||||
/// Spawns the service, binding to the given address and running on
|
||||
/// the default tokio `Loop`.
|
||||
fn listen<L>(self, addr: L) -> $crate::ListenFuture
|
||||
where L: ::std::net::ToSocketAddrs
|
||||
{
|
||||
return $crate::listen_pipeline(addr, __tarpc_service_AsyncServer(self));
|
||||
fn listen(self, addr: ::std::net::SocketAddr) -> $crate::ListenFuture {
|
||||
return $crate::listen(addr, __tarpc_service_AsyncServer(self));
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Clone)]
|
||||
@@ -523,14 +521,20 @@ macro_rules! service {
|
||||
/// Spawns the service, binding to the given address and running on
|
||||
/// the default tokio `Loop`.
|
||||
fn listen<L>(self, addr: L)
|
||||
-> $crate::tokio_proto::server::ServerHandle
|
||||
-> ::std::io::Result<$crate::tokio_proto::server::ServerHandle>
|
||||
where L: ::std::net::ToSocketAddrs
|
||||
{
|
||||
let addr = if let ::std::option::Option::Some(a) = ::std::iter::Iterator::next(&mut try!(::std::net::ToSocketAddrs::to_socket_addrs(&addr))) {
|
||||
a
|
||||
} else {
|
||||
return Err(::std::io::Error::new(::std::io::ErrorKind::AddrNotAvailable,
|
||||
"`ToSocketAddrs::to_socket_addrs` returned an empty iterator."));
|
||||
};
|
||||
|
||||
let __tarpc_service_service = __SyncServer {
|
||||
service: self,
|
||||
};
|
||||
return ::std::result::Result::unwrap($crate::futures::Future::wait(FutureServiceExt::listen(__tarpc_service_service, addr)));
|
||||
return $crate::futures::Future::wait(FutureServiceExt::listen(__tarpc_service_service, addr));
|
||||
|
||||
#[derive(Clone)]
|
||||
struct __SyncServer<S> {
|
||||
@@ -733,6 +737,7 @@ mod syntax_test {
|
||||
|
||||
#[cfg(test)]
|
||||
mod functional_test {
|
||||
use util::FirstSocketAddr;
|
||||
use futures::{Future, failed};
|
||||
extern crate env_logger;
|
||||
|
||||
@@ -742,6 +747,7 @@ mod functional_test {
|
||||
}
|
||||
|
||||
mod sync {
|
||||
use util::FirstSocketAddr;
|
||||
use super::{SyncClient, SyncService, SyncServiceExt};
|
||||
use super::env_logger;
|
||||
use sync::Connect;
|
||||
@@ -762,7 +768,7 @@ mod functional_test {
|
||||
#[test]
|
||||
fn simple() {
|
||||
let _ = env_logger::init();
|
||||
let handle = Server.listen("localhost:0");
|
||||
let handle = Server.listen("localhost:0".first_socket_addr()).unwrap();
|
||||
let client = SyncClient::connect(handle.local_addr()).unwrap();
|
||||
assert_eq!(3, client.add(1, 2).unwrap());
|
||||
assert_eq!("Hey, Tim.", client.hey("Tim".to_string()).unwrap());
|
||||
@@ -770,7 +776,7 @@ mod functional_test {
|
||||
|
||||
#[test]
|
||||
fn clone() {
|
||||
let handle = Server.listen("localhost:0");
|
||||
let handle = Server.listen("localhost:0".first_socket_addr()).unwrap();
|
||||
let client1 = SyncClient::connect(handle.local_addr()).unwrap();
|
||||
let client2 = client1.clone();
|
||||
assert_eq!(3, client1.add(1, 2).unwrap());
|
||||
@@ -780,7 +786,7 @@ mod functional_test {
|
||||
#[test]
|
||||
fn other_service() {
|
||||
let _ = env_logger::init();
|
||||
let handle = Server.listen("localhost:0");
|
||||
let handle = Server.listen("localhost:0".first_socket_addr()).unwrap();
|
||||
let client = super::other_service::SyncClient::connect(handle.local_addr()).unwrap();
|
||||
match client.foo().err().unwrap() {
|
||||
::Error::ServerDeserialize(_) => {} // good
|
||||
@@ -790,6 +796,7 @@ mod functional_test {
|
||||
}
|
||||
|
||||
mod future {
|
||||
use util::FirstSocketAddr;
|
||||
use future::Connect;
|
||||
use futures::{Finished, Future, finished};
|
||||
use super::{FutureClient, FutureService, FutureServiceExt};
|
||||
@@ -816,7 +823,7 @@ mod functional_test {
|
||||
#[test]
|
||||
fn simple() {
|
||||
let _ = env_logger::init();
|
||||
let handle = Server.listen("localhost:0").wait().unwrap();
|
||||
let handle = Server.listen("localhost:0".first_socket_addr()).wait().unwrap();
|
||||
let client = FutureClient::connect(handle.local_addr()).wait().unwrap();
|
||||
assert_eq!(3, client.add(1, 2).wait().unwrap());
|
||||
assert_eq!("Hey, Tim.", client.hey("Tim".to_string()).wait().unwrap());
|
||||
@@ -825,7 +832,7 @@ mod functional_test {
|
||||
#[test]
|
||||
fn clone() {
|
||||
let _ = env_logger::init();
|
||||
let handle = Server.listen("localhost:0").wait().unwrap();
|
||||
let handle = Server.listen("localhost:0".first_socket_addr()).wait().unwrap();
|
||||
let client1 = FutureClient::connect(handle.local_addr()).wait().unwrap();
|
||||
let client2 = client1.clone();
|
||||
assert_eq!(3, client1.add(1, 2).wait().unwrap());
|
||||
@@ -835,7 +842,7 @@ mod functional_test {
|
||||
#[test]
|
||||
fn other_service() {
|
||||
let _ = env_logger::init();
|
||||
let handle = Server.listen("localhost:0").wait().unwrap();
|
||||
let handle = Server.listen("localhost:0".first_socket_addr()).wait().unwrap();
|
||||
let client =
|
||||
super::other_service::FutureClient::connect(handle.local_addr()).wait().unwrap();
|
||||
match client.foo().wait().err().unwrap() {
|
||||
@@ -871,7 +878,7 @@ mod functional_test {
|
||||
use self::error_service::*;
|
||||
let _ = env_logger::init();
|
||||
|
||||
let handle = ErrorServer.listen("localhost:0").wait().unwrap();
|
||||
let handle = ErrorServer.listen("localhost:0".first_socket_addr()).wait().unwrap();
|
||||
let client = FutureClient::connect(handle.local_addr()).wait().unwrap();
|
||||
client.bar()
|
||||
.then(move |result| {
|
||||
|
||||
@@ -11,7 +11,8 @@ use futures::stream::Empty;
|
||||
use framed::Framed;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::io;
|
||||
use std::net::ToSocketAddrs;
|
||||
use std::net::SocketAddr;
|
||||
use tokio_core::reactor::Handle;
|
||||
use tokio_proto::pipeline;
|
||||
use tokio_proto::server::{self, ServerHandle};
|
||||
use tokio_service::NewService;
|
||||
@@ -20,40 +21,50 @@ use util::Never;
|
||||
/// A message from server to client.
|
||||
pub type Response<T, E> = pipeline::Message<Result<T, WireError<E>>, Empty<Never, io::Error>>;
|
||||
|
||||
/// Spawns a service that binds to the given address and runs on the default tokio `Loop`.
|
||||
pub fn listen_pipeline<A, S, Req, Resp, E>(addr: A, new_service: S) -> ListenFuture
|
||||
/// Spawns a service that binds to the given address and runs on the default reactor core.
|
||||
pub fn listen<S, Req, Resp, E>(addr: SocketAddr, new_service: S) -> ListenFuture
|
||||
where S: NewService<Request = Result<Req, DeserializeError>,
|
||||
Response = Response<Resp, E>,
|
||||
Error = io::Error> + Send + 'static,
|
||||
A: ToSocketAddrs,
|
||||
Req: Deserialize,
|
||||
Resp: Serialize,
|
||||
E: Serialize,
|
||||
{
|
||||
// TODO(tikue): don't use ToSocketAddrs, or don't unwrap.
|
||||
let addr = addr.to_socket_addrs().unwrap().next().unwrap();
|
||||
|
||||
let (tx, rx) = futures::oneshot();
|
||||
REMOTE.spawn(move |handle| {
|
||||
Ok(tx.complete(server::listen(handle, addr, move |stream| {
|
||||
pipeline::Server::new(new_service.new_service()?, Framed::new(stream))
|
||||
}).unwrap()))
|
||||
Ok(tx.complete(listen_with(addr, new_service, handle)))
|
||||
});
|
||||
ListenFuture { inner: rx }
|
||||
}
|
||||
|
||||
/// Spawns a service that binds to the given address using the given handle.
|
||||
pub fn listen_with<S, Req, Resp, E>(addr: SocketAddr, new_service: S, handle: &Handle)
|
||||
-> io::Result<ServerHandle>
|
||||
where S: NewService<Request = Result<Req, DeserializeError>,
|
||||
Response = Response<Resp, E>,
|
||||
Error = io::Error> + Send + 'static,
|
||||
Req: Deserialize,
|
||||
Resp: Serialize,
|
||||
E: Serialize,
|
||||
{
|
||||
server::listen(handle, addr, move |stream| {
|
||||
pipeline::Server::new(new_service.new_service()?, Framed::new(stream))
|
||||
})
|
||||
}
|
||||
|
||||
/// A future that resolves to a `ServerHandle`.
|
||||
pub struct ListenFuture {
|
||||
inner: futures::Oneshot<ServerHandle>,
|
||||
inner: futures::Oneshot<io::Result<ServerHandle>>,
|
||||
}
|
||||
|
||||
impl Future for ListenFuture {
|
||||
type Item = ServerHandle;
|
||||
type Error = Never;
|
||||
type Error = io::Error;
|
||||
|
||||
fn poll(&mut self) -> futures::Poll<Self::Item, Self::Error> {
|
||||
// Can't panic the oneshot is always completed.
|
||||
match self.inner.poll().unwrap() {
|
||||
Async::Ready(server_handle) => Ok(Async::Ready(server_handle)),
|
||||
Async::Ready(result) => result.map(Async::Ready),
|
||||
Async::NotReady => Ok(Async::NotReady),
|
||||
}
|
||||
}
|
||||
|
||||
13
src/util.rs
13
src/util.rs
@@ -7,6 +7,7 @@ use futures::{Future, Poll};
|
||||
use futures::stream::Stream;
|
||||
use std::fmt;
|
||||
use std::error::Error;
|
||||
use std::net::{SocketAddr, ToSocketAddrs};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
/// A bottom type that impls `Error`, `Serialize`, and `Deserialize`. It is impossible to
|
||||
@@ -97,3 +98,15 @@ impl<S: Into<String>> From<S> for Message {
|
||||
Message(s.into())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Provides a utility method for more ergonomically parsing a `SocketAddr` when panicking is
|
||||
/// acceptable.
|
||||
pub trait FirstSocketAddr: ToSocketAddrs {
|
||||
/// Returns the first resolved `SocketAddr` or panics otherwise.
|
||||
fn first_socket_addr(&self) -> SocketAddr {
|
||||
self.to_socket_addrs().unwrap().next().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: ToSocketAddrs> FirstSocketAddr for A {}
|
||||
|
||||
Reference in New Issue
Block a user