///|
/// StdioTransport with buffered I/O for improved performance.
/// Buffering reduces the number of syscalls and context switches,
/// which is critical for high-frequency request/response patterns.
pub struct StdioTransport {
mut closed : Bool
// @stdio.stdin is already buffered internally, so use it directly
reader : @stdio.Input
// Buffer writes with 8KB buffer to reduce syscalls
// (stdout is not buffered by default, so we wrap it)
writer : @io.BufferedWriter[@stdio.Output]
}
///|
pub fn StdioTransport::StdioTransport() -> StdioTransport {
{
closed: false,
// stdin is already buffered internally (has ReaderBuffer)
reader: @stdio.stdin,
// Wrap stdout with BufferedWriter to batch writes (8KB buffer)
writer: @io.BufferedWriter::new(@stdio.stdout, size=8192),
}
}
///|
pub async fn StdioTransport::receive(
self : StdioTransport,
) -> String? raise @types.TransportError {
if self.closed {
return None
}
// Use the Reader trait's read_until method
// (stdin is already buffered, so this is efficient)
let line_opt = self.reader.read_until("\n") catch {
e => raise @types.ReadError("Failed to read from stdin: " + e.to_string())
}
match line_opt {
None => {
self.closed = true
None
}
Some(line_view) => {
let message = line_view.trim().to_owned()
if message.is_empty() {
return self.receive()
}
Some(message)
}
}
}
///|
pub async fn StdioTransport::send(
self : StdioTransport,
message : String,
) -> Unit raise @types.TransportError {
if self.closed {
raise @types.InvalidState("Cannot send on closed transport")
}
match validate_jsonrpc_message(message) {
Err(e) =>
raise @types.WriteError("Invalid JSON-RPC message: " + e.message())
Ok(_) => ()
}
// Write to buffered writer (batches small writes)
self.writer.write(message) catch {
e => raise @types.WriteError("Failed to write to stdout: " + e.to_string())
}
self.writer.write("\n") catch {
e => raise @types.WriteError("Failed to write newline: " + e.to_string())
}
// Flush immediately to ensure message is sent
// (important for request-response pattern)
self.writer.flush() catch {
e => raise @types.WriteError("Failed to flush stdout: " + e.to_string())
}
}
///|
pub fn StdioTransport::send_event(
_self : StdioTransport,
event_type~ : String,
data~ : String,
) -> Unit {
ignore(event_type)
ignore(data)
()
}
///|
pub fn StdioTransport::supports_streaming(_self : StdioTransport) -> Bool {
false
}
///|
pub async fn StdioTransport::send_notification(
self : StdioTransport,
notification : @types.Notification,
) -> Unit raise @types.TransportError {
if self.closed {
raise @types.InvalidState("Cannot send on closed transport")
}
let json = notification.to_jsonrpc_string()
// Write to buffered writer
self.writer.write(json) catch {
e =>
raise @types.WriteError("Failed to send notification: " + e.to_string())
}
self.writer.write("\n") catch {
e => raise @types.WriteError("Failed to write newline: " + e.to_string())
}
self.writer.flush() catch {
e =>
raise @types.WriteError("Failed to flush notification: " + e.to_string())
}
}
///|
pub fn StdioTransport::close(self : StdioTransport) -> Unit {
if !self.closed {
self.closed = true
}
}