#[path = "../helpers/mod.rs"]
mod helpers;
use std::sync::Arc;
use helpers::{make_table, table_schema};
use lightstream::models::readers::tcp::TcpTableReader;
use lightstream::models::streams::tcp::TcpByteStream;
use lightstream::models::writers::tcp::TcpTableWriter;
use lightstream::traits::transport_reader::IPCTransportReader;
use lightstream::traits::transport_writer::IPCTransportWriter;
use rustls::pki_types::{CertificateDer, PrivateKeyDer, ServerName};
use rustls::{ClientConfig, RootCertStore, ServerConfig};
use tokio::net::TcpListener;
use tokio_rustls::TlsAcceptor;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("TCP Arrow IPC over TLS Example");
println!("==============================\n");
rustls::crypto::ring::default_provider()
.install_default()
.expect("install ring crypto provider");
let cert = rcgen::generate_simple_self_signed(vec!["localhost".to_string()])?;
let cert_der: CertificateDer<'static> = cert.cert.der().clone();
let key_der: PrivateKeyDer<'static> = PrivateKeyDer::try_from(cert.signing_key.serialize_der())
.map_err(|e| format!("private key: {e}"))?;
let server_config = ServerConfig::builder()
.with_no_client_auth()
.with_single_cert(vec![cert_der.clone()], key_der)?;
let acceptor = TlsAcceptor::from(Arc::new(server_config));
let mut roots = RootCertStore::empty();
roots.add(cert_der)?;
let client_config = ClientConfig::builder()
.with_root_certificates(roots)
.with_no_client_auth();
let client_config = Arc::new(client_config);
let listener = TcpListener::bind("127.0.0.1:0").await?;
let addr = listener.local_addr()?;
println!("Listener bound to {addr}");
let acceptor_for_task = acceptor.clone();
let server = tokio::spawn(async move {
let (tcp, peer) = listener.accept().await.expect("accept");
println!("Server accepted TCP connection from {peer}");
let tls = acceptor_for_task.accept(tcp).await.expect("tls handshake");
println!("Server TLS handshake complete");
let (read_half, _write_half) = tokio::io::split(tls);
let byte_stream =
TcpByteStream::from_tls_read_half(read_half, lightstream::enums::BufferChunkSize::Http);
let reader = TcpTableReader::from_stream(
byte_stream,
lightstream::enums::IPCMessageProtocol::Stream,
None,
);
let tables = reader.read_all_tables().await.expect("read all tables");
for t in &tables {
println!(
" Server got table: {} rows, {} cols",
t.n_rows,
t.cols.len()
);
}
assert_eq!(tables.len(), 3);
println!("Server received all {} tables over TLS.", tables.len());
});
let server_name = ServerName::try_from("localhost".to_string())?;
let mut writer =
TcpTableWriter::connect_tls(addr, server_name, client_config, table_schema(), None).await?;
println!("Client TLS handshake complete to {addr}");
writer.write_table(make_table("batch_1", 5)).await?;
writer.write_table(make_table("batch_2", 3)).await?;
writer.write_table(make_table("batch_3", 7)).await?;
writer.finish().await?;
server.await?;
println!("\nTCP Arrow IPC over TLS example completed successfully!");
Ok(())
}