Download codex-rs/app-server-test-client/src/loopback_responses_server.rs from SaylorTwift/codex: direct link, hf CLI and curl.
- Browser
- Download file 4.79 kB
-
https://huggingface.co/SaylorTwift/codex/resolve/main/codex-rs/app-server-test-client/src/loopback_responses_server.rs
- Command line
-
hf download hf://SaylorTwift/codex/codex-rs/app-server-test-client/src/loopback_responses_server.rs
-
curl -L -o loopback_responses_server.rs https://huggingface.co/SaylorTwift/codex/resolve/main/codex-rs/app-server-test-client/src/loopback_responses_server.rs
4.79 kB
| use anyhow::Context; | |
| use anyhow::Result; | |
| use std::io; | |
| use std::io::Read; | |
| use std::io::Write; | |
| use std::net::TcpListener; | |
| use std::net::TcpStream; | |
| use std::sync::Arc; | |
| use std::sync::atomic::AtomicBool; | |
| use std::sync::atomic::Ordering; | |
| use std::thread; | |
| use std::thread::JoinHandle; | |
| use std::time::Duration; | |
| pub(super) struct LoopbackResponsesServer { | |
| base_url: String, | |
| shutdown: Arc<AtomicBool>, | |
| thread: Option<JoinHandle<()>>, | |
| } | |
| impl LoopbackResponsesServer { | |
| pub(super) fn start() -> Result<Self> { | |
| let listener = | |
| TcpListener::bind("127.0.0.1:0").context("bind loopback Responses API server")?; | |
| listener | |
| .set_nonblocking(true) | |
| .context("set loopback Responses API server nonblocking")?; | |
| let address = listener.local_addr()?; | |
| let shutdown = Arc::new(AtomicBool::new(false)); | |
| let thread_shutdown = Arc::clone(&shutdown); | |
| let thread = thread::spawn(move || { | |
| while !thread_shutdown.load(Ordering::Relaxed) { | |
| match listener.accept() { | |
| Ok((stream, _)) => { | |
| if let Err(err) = handle_model_connection(stream) { | |
| eprintln!("loopback Responses API server error: {err}"); | |
| } | |
| } | |
| Err(err) if err.kind() == io::ErrorKind::WouldBlock => { | |
| thread::sleep(Duration::from_millis(10)); | |
| } | |
| Err(err) => { | |
| eprintln!("loopback Responses API accept error: {err}"); | |
| break; | |
| } | |
| } | |
| } | |
| }); | |
| Ok(Self { | |
| base_url: format!("http://{address}"), | |
| shutdown, | |
| thread: Some(thread), | |
| }) | |
| } | |
| pub(super) fn base_url(&self) -> &str { | |
| &self.base_url | |
| } | |
| } | |
| impl Drop for LoopbackResponsesServer { | |
| fn drop(&mut self) { | |
| self.shutdown.store(true, Ordering::Relaxed); | |
| if let Some(thread) = self.thread.take() { | |
| let _ = thread.join(); | |
| } | |
| } | |
| } | |
| fn handle_model_connection(mut stream: TcpStream) -> io::Result<()> { | |
| stream.set_nonblocking(false)?; | |
| stream.set_read_timeout(Some(Duration::from_secs(2)))?; | |
| let request = read_http_request(&mut stream)?; | |
| let request_line = request | |
| .split(|byte| *byte == b'\n') | |
| .next() | |
| .and_then(|line| std::str::from_utf8(line).ok()) | |
| .unwrap_or_default(); | |
| if request_line.starts_with("POST ") && request_line.contains("/responses ") { | |
| let body = concat!( | |
| "event: response.created\n", | |
| "data: {\"type\":\"response.created\",\"response\":{\"id\":\"resp-plugin-analytics\"}}\n\n", | |
| "event: response.completed\n", | |
| "data: {\"type\":\"response.completed\",\"response\":{\"id\":\"resp-plugin-analytics\",\"usage\":{\"input_tokens\":0,\"input_tokens_details\":null,\"output_tokens\":0,\"output_tokens_details\":null,\"total_tokens\":0}}}\n\n" | |
| ); | |
| write_http_response(&mut stream, "200 OK", "text/event-stream", body) | |
| } else { | |
| write_http_response( | |
| &mut stream, | |
| "404 Not Found", | |
| "application/json", | |
| r#"{"error":"not found"}"#, | |
| ) | |
| } | |
| } | |
| fn read_http_request(stream: &mut TcpStream) -> io::Result<Vec<u8>> { | |
| let mut request = Vec::new(); | |
| let mut buffer = [0_u8; 4096]; | |
| let header_end = loop { | |
| let read = stream.read(&mut buffer)?; | |
| if read == 0 { | |
| return Ok(request); | |
| } | |
| request.extend_from_slice(&buffer[..read]); | |
| if let Some(position) = request.windows(4).position(|window| window == b"\r\n\r\n") { | |
| break position + 4; | |
| } | |
| }; | |
| let content_length = parse_content_length(&request[..header_end]); | |
| while request.len() < header_end + content_length { | |
| let read = stream.read(&mut buffer)?; | |
| if read == 0 { | |
| break; | |
| } | |
| request.extend_from_slice(&buffer[..read]); | |
| } | |
| Ok(request) | |
| } | |
| fn parse_content_length(headers: &[u8]) -> usize { | |
| String::from_utf8_lossy(headers) | |
| .lines() | |
| .find_map(|line| { | |
| let (name, value) = line.split_once(':')?; | |
| name.eq_ignore_ascii_case("content-length") | |
| .then(|| value.trim().parse().ok()) | |
| .flatten() | |
| }) | |
| .unwrap_or(0) | |
| } | |
| fn write_http_response( | |
| stream: &mut TcpStream, | |
| status: &str, | |
| content_type: &str, | |
| body: &str, | |
| ) -> io::Result<()> { | |
| write!( | |
| stream, | |
| "HTTP/1.1 {status}\r\nContent-Type: {content_type}\r\nContent-Length: {}\r\nConnection: close\r\n\r\n{body}", | |
| body.len() | |
| )?; | |
| stream.flush() | |
| } | |