Add idiomatic documentation to Go, Java, Python, and Rust clients

This commit is contained in:
Joseph Doherty
2026-04-30 12:04:46 -04:00
parent eed1e88a37
commit 8d3352f2c6
44 changed files with 1631 additions and 102 deletions
+74 -1
View File
@@ -1,3 +1,11 @@
//! High-level wrapper around the generated `MxAccessGateway` gRPC client.
//!
//! [`GatewayClient::connect`] builds an authenticated `tonic` channel using
//! the supplied [`ClientOptions`], applies the bearer-token interceptor, and
//! exposes typed methods for the unary and streaming RPCs. Most application
//! code should prefer [`GatewayClient::open_session`] and the [`Session`]
//! handle it returns, rather than the `*_raw` methods.
use std::fs;
use tonic::codegen::InterceptedService;
@@ -14,11 +22,21 @@ use crate::generated::mxaccess_gateway::v1::{
use crate::options::ClientOptions;
use crate::session::Session;
/// Generated gateway client wrapped in the auth interceptor that
/// [`GatewayClient`] uses internally.
pub type RawGatewayClient = MxAccessGatewayClient<InterceptedService<Channel, AuthInterceptor>>;
/// Pinned, boxed [`MxEvent`] stream returned by
/// [`GatewayClient::stream_events`]. Errors are pre-mapped from
/// `tonic::Status` to [`Error`]; dropping the stream cancels the call.
pub type EventStream =
std::pin::Pin<Box<dyn futures_core::Stream<Item = Result<MxEvent, Error>> + Send + 'static>>;
/// Thin owner for the generated gateway client.
/// Thin async wrapper around the generated gateway client.
///
/// The wrapper is `Clone`: every clone shares the underlying tonic channel
/// (cheap, reference-counted) and the same call/stream timeouts. It is
/// designed to be cheap enough to clone per request handler.
#[derive(Clone)]
pub struct GatewayClient {
inner: RawGatewayClient,
@@ -27,6 +45,13 @@ pub struct GatewayClient {
}
impl GatewayClient {
/// Connect to the gateway endpoint described by `options` and return a
/// ready-to-use client.
///
/// # Errors
///
/// Returns [`Error::InvalidEndpoint`] if the endpoint URL or CA file is
/// malformed, and [`Error::Transport`] if the TCP/TLS handshake fails.
pub async fn connect(options: ClientOptions) -> Result<Self, Error> {
let mut endpoint =
Channel::from_shared(options.endpoint().to_owned()).map_err(|source| {
@@ -62,18 +87,30 @@ impl GatewayClient {
})
}
/// Borrow the underlying generated client. Use this only when you need
/// access to RPCs not surfaced by the wrapper.
pub fn raw_client(&mut self) -> &mut RawGatewayClient {
&mut self.inner
}
/// Consume the wrapper and return the underlying generated client.
pub fn into_inner(self) -> RawGatewayClient {
self.inner
}
/// Build a [`Session`] handle from a previously opened session id. No
/// RPC is performed — this is the cheap counterpart to
/// [`GatewayClient::open_session`] for callers that already own the id.
pub fn session(&self, session_id: impl Into<String>) -> Session {
Session::new(session_id, self.clone())
}
/// Issue an `OpenSession` RPC and return the raw reply without
/// validating its `protocol_status`.
///
/// # Errors
///
/// Returns the `tonic::Status` mapped through [`Error::from`].
pub async fn open_session_raw(
&self,
request: OpenSessionRequest,
@@ -83,12 +120,25 @@ impl GatewayClient {
Ok(response.into_inner())
}
/// Open a session, validate its `protocol_status`, and return a typed
/// [`Session`] handle bound to this client.
///
/// # Errors
///
/// Returns [`Error::ProtocolStatus`] if the gateway accepts the call
/// but reports a non-OK protocol status, plus any of the
/// [`Error`] variants produced by [`open_session_raw`](Self::open_session_raw).
pub async fn open_session(&self, request: OpenSessionRequest) -> Result<Session, Error> {
let reply = self.open_session_raw(request).await?;
ensure_protocol_success("open session", reply.protocol_status.as_ref())?;
Ok(Session::new(reply.session_id, self.clone()))
}
/// Issue a `CloseSession` RPC and return the raw reply.
///
/// # Errors
///
/// Returns the `tonic::Status` mapped through [`Error::from`].
pub async fn close_session_raw(
&self,
request: CloseSessionRequest,
@@ -98,16 +148,39 @@ impl GatewayClient {
Ok(response.into_inner())
}
/// Issue an `Invoke` RPC and return the raw reply, even when the
/// command-level protocol status is non-OK.
///
/// # Errors
///
/// Returns the `tonic::Status` mapped through [`Error::from`].
pub async fn invoke_raw(&self, request: MxCommandRequest) -> Result<MxCommandReply, Error> {
let mut client = self.inner.clone();
let response = client.invoke(self.unary_request(request)).await?;
Ok(response.into_inner())
}
/// Issue an `Invoke` RPC and surface a non-OK reply as
/// [`Error::Command`].
///
/// # Errors
///
/// Returns [`Error::Command`] when the reply's `protocol_status` is not
/// `Ok`, plus any errors propagated by
/// [`invoke_raw`](Self::invoke_raw).
pub async fn invoke(&self, request: MxCommandRequest) -> Result<MxCommandReply, Error> {
ensure_command_success(self.invoke_raw(request).await?)
}
/// Open the server-streaming `StreamEvents` RPC.
///
/// The returned [`EventStream`] yields `MxEvent` messages as the worker
/// produces them. Dropping the stream cancels the gRPC call cooperatively.
///
/// # Errors
///
/// Returns the `tonic::Status` mapped through [`Error::from`] if the
/// server rejects the subscription.
pub async fn stream_events(&self, request: StreamEventsRequest) -> Result<EventStream, Error> {
let mut client = self.inner.clone();
let response = client.stream_events(self.stream_request(request)).await?;