Files
boxmaker/crates/gatewayd/tests/support/brokerd_client.rs
T
kyle c38e450f44 gatewayd: serve, posting approvals, marking them, and the listener
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-24 05:07:50 -07:00

98 lines
2.8 KiB
Rust

//! `brokerd`'s side of one `gateway.sock` connection, for tests: ask, read what comes back,
//! answer with an outcome, or close. Do not edit.
#![allow(dead_code)] // each test file uses a different part of this module
use std::os::unix::net::UnixStream;
use std::path::Path;
use std::time::Duration;
use proto::{
ApprovalOutcome, ApprovalReply, ApprovalRequest, CallId, DataClass, Envelope, GatewayOutcome,
Message, PROTOCOL_VERSION, PendingApproval, SessionId, Timestamp, read_frame, write_frame,
};
pub struct Asking {
stream: UnixStream,
pub posts: Vec<String>,
}
/// An approval of `session`, with these arguments.
pub fn pending(approval: u64, session: &str, arguments: &str) -> PendingApproval {
PendingApproval {
approval,
session: SessionId::new(session).unwrap(),
call: CallId(3),
tool: "read_file".to_string(),
arguments: arguments.to_string(),
grant: "notes".to_string(),
taint: DataClass::Private,
created: Timestamp::parse("2026-09-24T08:05:00.000Z").unwrap(),
expires: Timestamp::parse("2026-09-24T08:20:00.000Z").unwrap(),
}
}
fn frame(id: u64, last: bool, msg: Message) -> Envelope {
Envelope {
v: PROTOCOL_VERSION,
id,
r#final: last,
msg,
}
}
/// Connect and ask; `Ok` with the posts, or `Err` with gatewayd's error detail.
pub fn ask(socket: &Path, info: PendingApproval) -> Result<Asking, String> {
let mut stream = UnixStream::connect(socket).map_err(|e| e.to_string())?;
stream
.set_read_timeout(Some(Duration::from_secs(10)))
.unwrap();
write_frame(
&mut stream,
&frame(
1,
true,
Message::ApprovalRequest(ApprovalRequest { approval: info }),
),
)
.unwrap();
match read_frame(&mut stream).map_err(|e| e.to_string())?.msg {
Message::ApprovalPosted(p) => Ok(Asking {
stream,
posts: p.posts,
}),
Message::Error(e) => Err(e.detail),
other => panic!("{other:?}"),
}
}
impl Asking {
/// The answer, within `wait`, or `None`.
pub fn answer(&mut self, wait: Duration) -> Option<ApprovalReply> {
self.stream.set_read_timeout(Some(wait)).unwrap();
match read_frame(&mut self.stream) {
Ok(Envelope {
msg: Message::ApprovalReply(r),
..
}) => Some(r),
_ => None,
}
}
pub fn outcome(&mut self, outcome: GatewayOutcome) {
write_frame(
&mut self.stream,
&frame(
2,
true,
Message::ApprovalOutcome(ApprovalOutcome { outcome }),
),
)
.unwrap();
}
pub fn close(self) {
let _ = self.stream.shutdown(std::net::Shutdown::Both);
}
}