-
-
Save snnsnn/05f22eb8f187166b03ddc23a44cbdfe1 to your computer and use it in GitHub Desktop.
(Mostly working) Sample to use TowerGRPC against a TLS endpoint.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// [dependencies] | |
// futures = "0.1.27" | |
// http = "0.1.17" | |
// tokio = "0.1.21" | |
// tower-request-modifier = { git = "https://github.com/tower-rs/tower-http" } | |
// tower-grpc = { version = "0.1.0", features = ["tower-hyper"] } | |
// tower-service = "0.2" | |
// tower-util = "0.1" | |
// tokio-rustls = "0.10.0-alpha.3" | |
// webpki = "0.19.1" | |
// webpki-roots = "0.16.0" | |
// tower-h2 = { git = "https://github.com/tower-rs/tower-h2" } | |
// openssl = "*" | |
// openssl-probe = "*" | |
use std::thread; | |
use std::sync::{Arc}; | |
use futures::{future, Future}; | |
use tower_util::MakeService; | |
use tokio_rustls::client::TlsStream; | |
use tokio_rustls::{rustls::ClientConfig, TlsConnector}; | |
use std::net::SocketAddr; | |
use tokio::executor::DefaultExecutor; | |
use tokio::net::tcp::TcpStream; | |
use tower_h2; | |
use std::net::ToSocketAddrs; | |
struct Dst(SocketAddr); | |
impl tower_service::Service<()> for Dst { | |
type Response = TlsStream<TcpStream>; | |
type Error = ::std::io::Error; | |
type Future = Box<dyn Future<Item = TlsStream<TcpStream>, Error = ::std::io::Error> + Send>; | |
fn poll_ready(&mut self) -> futures::Poll<(), Self::Error> { | |
Ok(().into()) | |
} | |
fn call(&mut self, _: ()) -> Self::Future { | |
println!("{:?}", self.0); | |
let mut config = ClientConfig::new(); | |
config.alpn_protocols.push(b"h2".to_vec()); | |
config.root_store.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS); | |
let config = Arc::new(config); | |
let tls_connector = TlsConnector::from(config); | |
let addr_string_local = "mydomain.com"; | |
let domain = webpki::DNSNameRef::try_from_ascii_str(addr_string_local).unwrap(); | |
let domain_local = domain.to_owned(); | |
let stream = TcpStream::connect(&self.0).and_then(move |sock| { | |
sock.set_nodelay(true).unwrap(); | |
tls_connector.connect(domain_local.as_ref(), sock) | |
}) | |
.map(move |tcp| tcp); | |
Box::new(stream) | |
} | |
} | |
// Same implementation but without TLS. Should make it straightforward to run without TLS | |
// when testing on local machine | |
// impl tower_service::Service<()> for Dst { | |
// type Response = TcpStream; | |
// type Error = ::std::io::Error; | |
// type Future = Box<dyn Future<Item = TcpStream, Error = ::std::io::Error> + Send>; | |
// fn poll_ready(&mut self) -> futures::Poll<(), Self::Error> { | |
// Ok(().into()) | |
// } | |
// fn call(&mut self, _: ()) -> Self::Future { | |
// let mut config = ClientConfig::new(); | |
// config.alpn_protocols.push(b"h2".to_vec()); | |
// config.root_store.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS); | |
// let addr_string_local = "mydomain.com".to_string(); | |
// let addr = addr_string_local.as_str(); | |
// let stream = TcpStream::connect(&self.0) | |
// .and_then(move |sock| { | |
// sock.set_nodelay(true).unwrap(); | |
// Ok(sock) | |
// }); | |
// Box::new(stream) | |
// } | |
// } | |
fn connect() { | |
let keepalive = future::loop_fn((), move |_| { | |
let uri: http::Uri = "https://mydomain.com".parse().unwrap(); | |
println!("Connecting to network at: {:?}", uri); | |
let addr = "https://mydomain.com:443" | |
.to_socket_addrs() | |
.unwrap() | |
.next() | |
.unwrap(); | |
let h2_settings = Default::default(); | |
let mut make_client = tower_h2::client::Connect::new(Dst {0: addr}, h2_settings, DefaultExecutor::current()); | |
make_client | |
.make_service(()) | |
.map_err(|e| { | |
eprintln!("HTTP/2 connection failed; err={:?}", e); | |
}) | |
.and_then(move |conn| { | |
let conn = tower_request_modifier::Builder::new() | |
.set_origin(uri) | |
.build(conn) | |
.unwrap(); | |
MyGrpcService::new(conn) | |
// Wait until the client is ready... | |
.ready() | |
.map_err(|e| eprintln!("client closed: {:?}", e)) | |
}) | |
.and_then(move |mut client| { | |
// do stuff | |
}) | |
.then(|e| { | |
eprintln!("Reopening client connection to network: {:?}", e); | |
let retry_sleep = std::time::Duration::from_secs(1); | |
thread::sleep(retry_sleep); | |
Ok(future::Loop::Continue(())) | |
}) | |
}); | |
thread::spawn(move || tokio::run(keepalive)); | |
} | |
pub fn main() { | |
connect(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment