feat(brahman-handshake): ListMatches endpoint + timeline en broker-explorer
Iter 21. Cierra el loop iniciado en iter 20: ahora se ven sesiones
+ matches actuales + cómo cambian a través del tiempo.
brahman-handshake/messages:
- Frame::ListMatches → Frame::MatchList(Vec<brahman_broker::Match>).
brahman-handshake/server:
- run_post_handshake pasa Option<&SharedBroker> a handle_inbound_frame.
- Sin broker configurado → MatchList vacía (no error).
brahman-handshake/client + brahman-sidecar:
- Client::list_matches() análogo a list_sessions, drena MatchEvents.
- list_matches / list_matches_blocking, mismo patrón.
brahman-broker-explorer:
- Poll-tick agrega list_matches_blocking además de list_sessions.
- last_match_keys: HashSet<MatchKey> para diff entre ticks.
- timeline: VecDeque<TimelineEntry> cap 50.
- diff_matches (free fn): Available para keys nuevas, Lost para
desaparecidas. Primer tick marca todo Available (boot UX).
- Render: stat_card "Timeline" con HH:MM:SS {+/-} formato compacto.
5 tests broker-explorer (3 nuevos del diff). Stack verde.
Decisión: timeline polled cada POLL_INTERVAL=5s, no push. MatchEvents
del broker son consumer-céntricos (cada session ve sólo SUS matches);
"system-wide timeline" requeriría broker subscribe-all (mucho scope).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -172,6 +172,16 @@ where
|
||||
got: "SessionList (pre-handshake)",
|
||||
});
|
||||
}
|
||||
Frame::ListMatches(_) => {
|
||||
return Err(ClientError::UnexpectedFrame {
|
||||
got: "ListMatches (pre-handshake)",
|
||||
});
|
||||
}
|
||||
Frame::MatchList(_) => {
|
||||
return Err(ClientError::UnexpectedFrame {
|
||||
got: "MatchList (pre-handshake)",
|
||||
});
|
||||
}
|
||||
};
|
||||
Ok(Self {
|
||||
stream,
|
||||
@@ -263,6 +273,31 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Pide al servidor el listado de matches actuales del broker
|
||||
/// (consumer↔producer pares con tipo y estrategia). Mismo patrón
|
||||
/// de drenado de `MatchEvent`s intermedios.
|
||||
pub async fn list_matches(&mut self) -> Result<crate::messages::MatchList, ClientError> {
|
||||
write_frame(
|
||||
&mut self.stream,
|
||||
&Frame::ListMatches(crate::messages::ListMatches {
|
||||
session: self.session,
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
loop {
|
||||
match read_frame(&mut self.stream).await? {
|
||||
Frame::MatchList(list) => return Ok(list),
|
||||
Frame::MatchEvent(ev) => self.pending_events.push_back(ev),
|
||||
Frame::Error(e) => return Err(ClientError::Server(e)),
|
||||
_ => {
|
||||
return Err(ClientError::UnexpectedFrame {
|
||||
got: "non-match-list",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Cierre cooperativo. Consume el cliente.
|
||||
pub async fn farewell(mut self) -> Result<(), ClientError> {
|
||||
write_frame(
|
||||
|
||||
Reference in New Issue
Block a user