initial commit
This commit is contained in:
commit
dded5403d1
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/target
|
1088
Cargo.lock
generated
Normal file
1088
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
11
Cargo.toml
Normal file
11
Cargo.toml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[package]
|
||||||
|
name = "protohacke-rs"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
futures = "0.3.30"
|
||||||
|
miette = { version = "5", features = ["fancy"] }
|
||||||
|
pin-project = "1"
|
||||||
|
ruchei = "0.0.72"
|
||||||
|
smol = "1.3.0"
|
96
src/main.rs
Normal file
96
src/main.rs
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
use std::{
|
||||||
|
pin::Pin,
|
||||||
|
task::{Context, Poll},
|
||||||
|
};
|
||||||
|
|
||||||
|
use futures::{ready, AsyncRead, AsyncWrite, Sink, Stream, StreamExt};
|
||||||
|
use miette::IntoDiagnostic;
|
||||||
|
use ruchei::echo::bufferless::EchoBufferless;
|
||||||
|
|
||||||
|
async fn handle(stream: smol::io::Result<smol::net::TcpStream>) -> smol::io::Result<()> {
|
||||||
|
Forward {
|
||||||
|
stream: stream?,
|
||||||
|
write_buf: None,
|
||||||
|
}
|
||||||
|
.fuse()
|
||||||
|
.echo_bufferless()
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
struct WriteBuf {
|
||||||
|
msg: Vec<u8>,
|
||||||
|
start: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pin_project::pin_project]
|
||||||
|
struct Forward {
|
||||||
|
#[pin]
|
||||||
|
stream: smol::net::TcpStream,
|
||||||
|
write_buf: Option<WriteBuf>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Stream for Forward {
|
||||||
|
type Item = smol::io::Result<Vec<u8>>;
|
||||||
|
|
||||||
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
|
let this = self.project();
|
||||||
|
let mut buf = [0; 65536];
|
||||||
|
let read = ready!(this.stream.poll_read(cx, &mut buf))?;
|
||||||
|
if read == 0 {
|
||||||
|
Poll::Ready(None)
|
||||||
|
} else {
|
||||||
|
Poll::Ready(Some(Ok(buf[..read].into())))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sink<Vec<u8>> for Forward {
|
||||||
|
type Error = smol::io::Error;
|
||||||
|
|
||||||
|
fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||||
|
let mut this = self.project();
|
||||||
|
while let Some(write_buf) = this.write_buf {
|
||||||
|
let bytes = ready!(this
|
||||||
|
.stream
|
||||||
|
.as_mut()
|
||||||
|
.poll_write(cx, &write_buf.msg[write_buf.start..]))?;
|
||||||
|
write_buf.start += bytes;
|
||||||
|
if write_buf.start == write_buf.msg.len() || bytes == 0 {
|
||||||
|
*this.write_buf = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Poll::Ready(Ok(()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_send(self: Pin<&mut Self>, msg: Vec<u8>) -> Result<(), Self::Error> {
|
||||||
|
if !msg.is_empty() {
|
||||||
|
*self.project().write_buf = Some(WriteBuf { msg, start: 0 });
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||||
|
ready!(self.as_mut().poll_ready(cx))?;
|
||||||
|
self.project().stream.poll_flush(cx)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||||
|
self.project().stream.poll_close(cx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> miette::Result<()> {
|
||||||
|
smol::block_on(async {
|
||||||
|
smol::net::TcpListener::bind("localhost:42042")
|
||||||
|
.await
|
||||||
|
.into_diagnostic()?
|
||||||
|
.incoming()
|
||||||
|
.for_each_concurrent(None, |stream| async {
|
||||||
|
if let Err(e) = handle(stream).await.into_diagnostic() {
|
||||||
|
eprintln!("{e}");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user