// Copyright 2016 Google Inc. All Rights Reserved. // // Licensed under the MIT License, . // This file may not be copied, modified, or distributed except according to those terms. use errors::{SerializableError, WireError}; use futures::{self, Future}; use futures::stream::Empty; use futures_cpupool::{CpuFuture, CpuPool}; use protocol::{LOOP_HANDLE, TarpcTransport}; use protocol::writer::Packet; use serde::Serialize; use std::io; use std::net::ToSocketAddrs; use tokio_proto::pipeline; use tokio_proto::NewService; use tokio_proto::server::{self, ServerHandle}; /// Start a Tarpc service listening on the given address. pub fn listen(addr: A, new_service: T) -> io::Result where T: NewService, Resp = pipeline::Message>, Error = io::Error> + Send + 'static, A: ToSocketAddrs { let mut addrs = addr.to_socket_addrs()?; let addr = if let Some(a) = addrs.next() { a } else { return Err(io::Error::new(io::ErrorKind::AddrNotAvailable, "`ToSocketAddrs::to_socket_addrs` returned an empty iterator.")); }; server::listen(LOOP_HANDLE.clone(), addr, move |stream| { pipeline::Server::new(new_service.new_service()?, TarpcTransport::new(stream)) }) .wait() } /// Returns a future containing the serialized reply. /// /// Because serialization can take a non-trivial /// amount of cpu time, it is run on a thread pool. #[doc(hidden)] #[inline] pub fn serialize_reply(result: Result>) -> SerializeFuture { POOL.spawn(futures::lazy(move || { let packet = match Packet::serialize(&result) { Ok(packet) => packet, Err(e) => { let err: Result> = Err(WireError::ServerSerialize(e.to_string())); Packet::serialize(&err).unwrap() } }; futures::finished(pipeline::Message::WithoutBody(packet)) })) } #[doc(hidden)] pub type SerializeFuture = CpuFuture; #[doc(hidden)] pub type SerializedReply = pipeline::Message>; lazy_static! { static ref POOL: CpuPool = { CpuPool::new_num_cpus() }; }