Rust client: port stream-alarms and acknowledge-alarm + fix stream-events family + 8MB Windows stack
Adds the session-less alarm CLI subcommands to mxgw. stream-alarms attaches to
the gateway's central alarm feed (--filter-prefix, --max-events, --json/--jsonl;
aggregate shape `{messageCount, messages: [...]}`); acknowledge-alarm is a unary
ack (--reference required, --comment, --operator). stream_alarms joins
query_active_alarms on GatewayClient and re-exports AlarmFeedStream.
Also extends stream-events JSON to emit a full `events` array (itemHandle, value
projected to protojson-shaped `*Value` keys, etc.) instead of just `eventCount`,
matching the other four CLIs, and renders MxEvent.family as the protobuf enum
NAME (MX_EVENT_FAMILY_ON_WRITE_COMPLETE) rather than the raw i32 so the e2e
write round-trip can recognise the OnWriteComplete echo.
Adds clients/rust/.cargo/config.toml bumping the Windows main-thread stack to
8 MB via /STACK:8388608. clap-derive's Command enum (one variant per subcommand)
overflowed the default 1 MB stack in debug builds after the new variants
landed; release builds were unaffected but the e2e matrix runs Rust via
`cargo run` (debug).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -16,9 +16,10 @@ use crate::auth::AuthInterceptor;
|
||||
use crate::error::{ensure_command_success, ensure_protocol_success, Error};
|
||||
use crate::generated::mxaccess_gateway::v1::mx_access_gateway_client::MxAccessGatewayClient;
|
||||
use crate::generated::mxaccess_gateway::v1::{
|
||||
AcknowledgeAlarmReply, AcknowledgeAlarmRequest, ActiveAlarmSnapshot, CloseSessionReply,
|
||||
CloseSessionRequest, MxCommandReply, MxCommandRequest, MxEvent, OpenSessionReply,
|
||||
OpenSessionRequest, QueryActiveAlarmsRequest, StreamEventsRequest,
|
||||
AcknowledgeAlarmReply, AcknowledgeAlarmRequest, ActiveAlarmSnapshot, AlarmFeedMessage,
|
||||
CloseSessionReply, CloseSessionRequest, MxCommandReply, MxCommandRequest, MxEvent,
|
||||
OpenSessionReply, OpenSessionRequest, QueryActiveAlarmsRequest, StreamAlarmsRequest,
|
||||
StreamEventsRequest,
|
||||
};
|
||||
use crate::options::ClientOptions;
|
||||
use crate::session::Session;
|
||||
@@ -40,6 +41,13 @@ pub type ActiveAlarmStream = std::pin::Pin<
|
||||
Box<dyn futures_core::Stream<Item = Result<ActiveAlarmSnapshot, Error>> + Send + 'static>,
|
||||
>;
|
||||
|
||||
/// Pinned, boxed [`AlarmFeedMessage`] stream returned by
|
||||
/// [`GatewayClient::stream_alarms`]. Errors are pre-mapped from
|
||||
/// `tonic::Status` to [`Error`]; dropping the stream cancels the call.
|
||||
pub type AlarmFeedStream = std::pin::Pin<
|
||||
Box<dyn futures_core::Stream<Item = Result<AlarmFeedMessage, Error>> + Send + 'static>,
|
||||
>;
|
||||
|
||||
/// Thin async wrapper around the generated gateway client.
|
||||
///
|
||||
/// The wrapper is `Clone`: every clone shares the underlying tonic channel
|
||||
@@ -219,7 +227,9 @@ impl GatewayClient {
|
||||
request: AcknowledgeAlarmRequest,
|
||||
) -> Result<AcknowledgeAlarmReply, Error> {
|
||||
let mut client = self.inner.clone();
|
||||
let response = client.acknowledge_alarm(self.unary_request(request)).await?;
|
||||
let response = client
|
||||
.acknowledge_alarm(self.unary_request(request))
|
||||
.await?;
|
||||
let reply = response.into_inner();
|
||||
ensure_protocol_success("acknowledge alarm", reply.protocol_status.as_ref())?;
|
||||
Ok(reply)
|
||||
@@ -252,6 +262,34 @@ impl GatewayClient {
|
||||
Ok(Box::pin(stream))
|
||||
}
|
||||
|
||||
/// Attach to the gateway's central `StreamAlarms` feed.
|
||||
///
|
||||
/// The returned [`AlarmFeedStream`] opens with one [`AlarmFeedMessage`]
|
||||
/// per currently-active alarm (the ConditionRefresh snapshot), then a
|
||||
/// single `snapshot_complete`, then a `transition` for every subsequent
|
||||
/// raise / acknowledge / clear. It is served by the gateway's always-on
|
||||
/// alarm monitor — no worker session is opened — so any number of clients
|
||||
/// may attach. Dropping the stream cancels the gRPC call cooperatively.
|
||||
/// Optional alarm-reference prefix scoping (`request.alarm_filter_prefix`)
|
||||
/// limits the stream to a sub-tree.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns the `tonic::Status` mapped through [`Error::from`] if the
|
||||
/// server rejects the request.
|
||||
pub async fn stream_alarms(
|
||||
&self,
|
||||
request: StreamAlarmsRequest,
|
||||
) -> Result<AlarmFeedStream, Error> {
|
||||
let mut client = self.inner.clone();
|
||||
let response = client.stream_alarms(self.stream_request(request)).await?;
|
||||
let stream = futures_util::StreamExt::map(response.into_inner(), |result| {
|
||||
result.map_err(Error::from)
|
||||
});
|
||||
|
||||
Ok(Box::pin(stream))
|
||||
}
|
||||
|
||||
fn unary_request<T>(&self, message: T) -> Request<T> {
|
||||
let mut request = Request::new(message);
|
||||
request.set_timeout(self.call_timeout);
|
||||
|
||||
@@ -24,7 +24,7 @@ pub mod version;
|
||||
#[doc(inline)]
|
||||
pub use auth::{ApiKey, AuthInterceptor};
|
||||
#[doc(inline)]
|
||||
pub use client::{EventStream, GatewayClient};
|
||||
pub use client::{AlarmFeedStream, EventStream, GatewayClient};
|
||||
#[doc(inline)]
|
||||
pub use error::{CommandError, Error};
|
||||
#[doc(inline)]
|
||||
|
||||
Reference in New Issue
Block a user