add interactive chatting with stdin

main
_ 2025-02-24 05:02:33 +00:00
parent 54560e118f
commit a0b6726af0
3 changed files with 39 additions and 3 deletions

View File

@ -35,6 +35,10 @@ impl App {
}) })
} }
pub(crate) fn handle_stdin(&mut self, line: String) -> Result<()> {
self.client.handle_stdin(line)
}
pub(crate) fn poll_run(&mut self, cx: &mut Context<'_>) -> Poll<Result<()>> { pub(crate) fn poll_run(&mut self, cx: &mut Context<'_>) -> Poll<Result<()>> {
match self.step(cx) { match self.step(cx) {
Ok(()) => Poll::Pending, Ok(()) => Poll::Pending,
@ -126,14 +130,22 @@ impl Client {
self.enqueue(&ToServer::SetName { name }) self.enqueue(&ToServer::SetName { name })
} }
pub(crate) fn handle_stdin(&mut self, line: String) -> Result<()> {
let msg = ToServer::ChatLine {
line,
sequence: self.sequence,
};
self.sequence += 1;
self.enqueue(&msg)
}
fn handle_timeout(&mut self) -> Result<()> { fn handle_timeout(&mut self) -> Result<()> {
let msg = ToServer::ChatLine { let msg = ToServer::ChatLine {
line: "There was a time, in the era of great chaos, when the Earth and the Moon were at war with each other. A daredevil from the Moon piloted a bizarre aircraft. It was feared, and because of its shape, called EINHANDER.".to_string(), line: "There was a time, in the era of great chaos, when the Earth and the Moon were at war with each other. A daredevil from the Moon piloted a bizarre aircraft. It was feared, and because of its shape, called EINHANDER.".to_string(),
sequence: self.sequence, sequence: self.sequence,
}; };
self.sequence += 1; self.sequence += 1;
self.enqueue(&msg)?; self.enqueue(&msg)
Ok(())
} }
fn poll_send(&mut self) -> Option<Bytes> { fn poll_send(&mut self) -> Option<Bytes> {

View File

@ -71,6 +71,12 @@ async fn main() -> Result<()> {
async fn run_client(args: client::Args) -> Result<()> { async fn run_client(args: client::Args) -> Result<()> {
let mut ctrl_c = signal(SignalKind::interrupt())?; let mut ctrl_c = signal(SignalKind::interrupt())?;
let (stdin_tx, mut stdin_rx) = tokio::sync::mpsc::channel(1);
std::thread::spawn(move || {
for line in std::io::stdin().lines() {
stdin_tx.blocking_send(line).unwrap();
}
});
let mut app = client::App::new(args).await?; let mut app = client::App::new(args).await?;
loop { loop {
let ctl = poll_fn(|cx| { let ctl = poll_fn(|cx| {
@ -80,6 +86,24 @@ async fn run_client(args: client::Args) -> Result<()> {
return Poll::Ready(ControlFlow::Break(Ok(()))); return Poll::Ready(ControlFlow::Break(Ok(())));
} }
match stdin_rx.poll_recv(cx) {
Poll::Pending => {}
Poll::Ready(None) => {
return Poll::Ready(ControlFlow::Break(Err(anyhow!(
"Stdin thread somehow died"
))));
}
Poll::Ready(Some(line)) => {
let line = line.unwrap();
cx.waker().wake_by_ref();
if let Err(err) = app.handle_stdin(line) {
return Poll::Ready(ControlFlow::Break(
Err(err).context("app.handle_stdin"),
));
}
}
}
match app.poll_run(cx) { match app.poll_run(cx) {
Poll::Pending => Poll::Pending, Poll::Pending => Poll::Pending,
Poll::Ready(Ok(())) => Poll::Ready(ControlFlow::Continue(())), Poll::Ready(Ok(())) => Poll::Ready(ControlFlow::Continue(())),

View File

@ -1,5 +1,5 @@
pub(crate) use crate::messages::{ToClient, ToClientEvent, ToServer}; pub(crate) use crate::messages::{ToClient, ToClientEvent, ToServer};
pub use anyhow::{Context as _, Result, bail}; pub use anyhow::{Context as _, Result, anyhow, bail};
pub use bytes::Bytes; pub use bytes::Bytes;
pub use futures_core::stream::Stream; pub use futures_core::stream::Stream;
pub use futures_sink::Sink; pub use futures_sink::Sink;