//! Asking `brokerd` for a session's state on its `state.sock` (M5c spec, section 7): one question //! per connection, one final answer, as on every socket between the roles. use std::os::unix::net::UnixStream; use std::path::Path; use std::time::Duration; use bxcore::{ Envelope, Message, PROTOCOL_VERSION, SessionId, SessionState, SessionStateReply, read_frame, write_frame, }; /// How long `brokerd` may leave the connection without a byte, sending or answering. pub const WAIT: Duration = Duration::from_secs(5); /// The runbook entry for a `brokerd` that does not answer. pub const RUNBOOK: &str = "see docs/runbook.md#broker-state-unavailable"; /// `brokerd`'s answer for `session`, asked on `socket`. `wait` is the read and the write timeout; /// the connect has none, and fails at once when nothing listens. Any error, an error frame /// included, is `Err` with one line that names the socket or `brokerd`. pub fn ask( socket: &Path, session: &SessionId, wait: Duration, ) -> Result { let line = |e: &dyn std::fmt::Display| format!("{}: {e}", socket.display()); let mut stream = UnixStream::connect(socket).map_err(|e| line(&e))?; stream.set_read_timeout(Some(wait)).map_err(|e| line(&e))?; stream.set_write_timeout(Some(wait)).map_err(|e| line(&e))?; let question = Envelope { v: PROTOCOL_VERSION, id: 1, r#final: true, msg: Message::SessionState(SessionState { session: session.clone(), }), }; write_frame(&mut stream, &question).map_err(|e| line(&e))?; match read_frame(&mut stream).map_err(|e| line(&e))?.msg { Message::SessionStateReply(reply) => Ok(reply), Message::Error(e) => Err(format!("brokerd: {}", e.detail)), _ => Err("brokerd answered with the wrong message".to_string()), } }