Last active
August 8, 2019 19:37
-
-
Save DutchGhost/6cb59713594319453f3a880492bbe208 to your computer and use it in GitHub Desktop.
A simple proxy with async/await syntax!
This file contains hidden or 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
| #![feature(async_await)] | |
| extern crate structopt; | |
| use structopt::StructOpt; | |
| use std::{ | |
| future::Future as StdFuture, | |
| net::{IpAddr, SocketAddr}, | |
| }; | |
| use futures::{ | |
| executor, | |
| future::{self, TryFutureExt}, | |
| io, AsyncRead, AsyncReadExt, AsyncWrite, StreamExt, | |
| }; | |
| use romio::{TcpListener, TcpStream}; | |
| #[derive(Debug, StructOpt)] | |
| #[structopt(name = "SimpleProxy", about = "A simple, async proxy")] | |
| struct Cli { | |
| /// Localhost, can be set to internal only. | |
| #[structopt(long = "localhost", parse(try_from_str), default_value = "0.0.0.0")] | |
| localhost: IpAddr, | |
| /// The port the proxy should run on. | |
| #[structopt(short = "l", parse(try_from_str), default_value = "8080")] | |
| localport: u16, | |
| /// The host this server is a proxy to. | |
| #[structopt(short = "r", long = "remotehost", parse(try_from_str))] | |
| remotehost: IpAddr, | |
| /// The port of the host this server should proxy to. | |
| #[structopt(short = "p", long = "remoteport", parse(try_from_str))] | |
| remoteport: u16, | |
| } | |
| fn main() -> std::io::Result<()> { | |
| let app = Cli::from_args(); | |
| let server_addr = SocketAddr::new(app.localhost, app.localport); | |
| let host_addr = SocketAddr::new(app.remotehost, app.remoteport); | |
| let mut tcp = TcpListener::bind(&server_addr).unwrap(); | |
| let mut incoming = tcp.incoming(); | |
| executor::block_on(async { | |
| while let Some(stream) = incoming.next().await { | |
| let stream = stream?; | |
| juliex::spawn(async move { | |
| let _ = proxy(stream, &host_addr).await; | |
| }); | |
| } | |
| Ok(()) | |
| }) | |
| } | |
| fn copy<'a, R: 'a, W>(reader: R, writer: &'a mut W) -> impl StdFuture<Output = io::Result<()>> + 'a | |
| where | |
| R: AsyncReadExt, | |
| W: AsyncWrite + Unpin, | |
| { | |
| reader | |
| .copy_into(writer) | |
| .map_ok(|n| println!("wrote {} bytes", n)) | |
| } | |
| async fn proxy<R>(server: R, host: &SocketAddr) -> io::Result<()> | |
| where | |
| R: AsyncRead + AsyncWrite + Send + Sync, | |
| { | |
| let stream = TcpStream::connect(host).await?; | |
| let (server_reader, mut server_writer) = server.split(); | |
| let (host_reader, mut host_writer) = stream.split(); | |
| let sending = copy(server_reader, &mut host_writer); | |
| let receiving = copy(host_reader, &mut server_writer); | |
| let proxy = future::select(sending, receiving); | |
| let _ = proxy.await.factor_first().0?; | |
| Ok(()) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment