1use crate::transport::post;
10use origin_domain::{AppError, Result};
11use tokio::io::{AsyncBufReadExt, AsyncWrite, AsyncWriteExt, BufReader};
12
13const PING: &str = r#"{"jsonrpc":"2.0","id":0,"method":"ping","params":{}}"#;
16
17pub async fn is_alive(url: &str, token: Option<&str>) -> bool {
19 match post(url, token, PING).await {
20 Ok(body) => serde_json::from_str::<serde_json::Value>(&body)
21 .map(|value| value.get("result").is_some())
22 .unwrap_or(false),
23 Err(_) => false,
24 }
25}
26
27pub async fn proxy_streams<R, W>(
30 input: BufReader<R>,
31 mut output: W,
32 url: &str,
33 token: Option<&str>,
34) -> Result<()>
35where
36 R: tokio::io::AsyncRead + Unpin,
37 W: AsyncWrite + Unpin,
38{
39 tracing::info!(url, "proxying stdio to a running instance over http");
40
41 let mut lines = input.lines();
42 loop {
43 let line = match lines.next_line().await {
44 Ok(Some(line)) => line,
45 Ok(None) => break,
46 Err(error) => {
47 return Err(AppError::internal(format!("cannot read stdin: {error}")));
48 }
49 };
50
51 if line.trim().is_empty() {
52 continue;
53 }
54
55 let body = post(url, token, &line).await?;
56 if body.trim().is_empty() {
57 continue;
59 }
60
61 output
62 .write_all(body.as_bytes())
63 .await
64 .map_err(|error| AppError::internal(format!("cannot write stdout: {error}")))?;
65 output
66 .write_all(b"\n")
67 .await
68 .map_err(|error| AppError::internal(format!("cannot write stdout: {error}")))?;
69 output
70 .flush()
71 .await
72 .map_err(|error| AppError::internal(format!("cannot flush stdout: {error}")))?;
73 }
74
75 Ok(())
76}