RM: configurable CEM endpoint, stable structural IDs, richer dashboard#16
Open
martijnversluis wants to merge 3 commits into
Open
RM: configurable CEM endpoint, stable structural IDs, richer dashboard#16martijnversluis wants to merge 3 commits into
martijnversluis wants to merge 3 commits into
Conversation
The RM defaults to the bundled demo CEM stand-in inside rm-mqtt-ws-bridge/cem/. This change lets an operator point the RM at any CEM without editing compose files: * CEM_BASE_URL is now a docker-compose passthrough. demo.sh reads it and, if unset, probes cem-reference-1 on localhost:8003 and points the RM at ws://host.docker.internal:8003/ws when it answers. Only if there is no CEM_BASE_URL and no reference CEM running does it fall back to the bundled stand-in, which now sits under a "bundled-cem" compose profile so it stays offline in the other two modes. * MOSQUITTO_HOST_PORT and RESOURCE_ID were also promoted to passthroughs so they can be overridden when the defaults clash with something on the host. * The three-panel demo screen no longer hard-codes ws://localhost:9000/s2 or the CEM iframe. It fetches /traffic from the RM on load (and every 2s) and, when CEM_BASE_URL points outside the compose network, replaces the CEM iframe with an "S2 CEM external" tile that shows the live endpoint and link state. When the bundled stand-in is active the iframe is restored, so the original click-through demo still works. * TrafficController now sets Access-Control-Allow-Origin so the demo panel can read /traffic from a different origin.
FRBCSystemDescriptionFactory used SecureRandom.uuid for the actuator, both
operation modes, and the transitions. Every reconnect (or RM restart) produced
a fresh set, so any earlier FRBC.Instruction persisted on the CEM referenced
IDs that no longer existed in the current system description. The wepositive
CEM surfaces that as a warning triangle next to the actuator_id and
operation_mode fields on stored instructions.
The structural IDs are now derived deterministically via UUIDv5, namespaced
per role and per resource:
Digest::UUID.uuid_v5(NAMESPACE, "<resource.s2_identifier>/<role>")
Same resource + same role -> same UUID, across reconnects and restarts, with
no persistent state to maintain. Only message_id stays random per emission,
as the S2 spec requires.
The RM dashboard feed treated ReceptionStatus as an ordinary row, gave S2 setup messages no direction indicator, hid the raw payload of S2 messages entirely, and dropped the RM->CEM InstructionStatusUpdate that follows the reverse path. * TrafficLog now stores the parsed body plus message_id / subject_message_id / status for each entry. S2MessageLogger and MQTTMessageLogger extract those fields from the payload and pass them through. * ReceptionStatus is no longer its own row. Every S2 message row shows a small badge next to its message type: green tick for status=OK, red ! for any other status, grey ... while no ack has arrived yet. The badge is a toggle: clicking it opens the raw ReceptionStatus JSON inline. * Every S2 and MQTT message row is clickable and expands to reveal its raw JSON body, matching the "> raw message" affordance the MQTT panel already provides. Open/closed state is preserved across the 1.2s poll cycle via a stable id hashed from peer/direction/timestamp/message_id/subject_message_id. * Setup rows (Handshake, HandshakeResponse, ResourceManagerDetails, SelectControlType, FRBC.SystemDescription) now carry a direction arrow so RM->CEM and CEM->RM are distinguishable at a glance. * The FWD map now includes instruction_update -> InstructionStatusUpdate, so the RM->CEM acknowledgement of an FRBC.Instruction shows up on its own row (with the CEM's ack badge) instead of being silently dropped.
Contributor
|
Cool. Really nice improvements @martijnversluis One thing worth mentioning: it is not wrong to use reuse Ids in the FRBC system description but from the S2 pov also not required: a CEM should not require the Ids to be stable over multiple sessions. Every session is fully self contained and state is not supposed to be shared over multiple session. Nevertheless, for debugging purposes and system insights it can be helpful to use the same Ids. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three focused fixes to the
rm-mqtt-ws-bridgereference implementation. Each is a separate commit so it can be reviewed on its own.1. Route the RM to a configurable CEM endpoint
Today the RM in the three-panel demo is hard-wired to the bundled stand-in in
rm-mqtt-ws-bridge/cem/. This makes it awkward to interoperate withcem-reference-1or any external CEM without editing the compose file.The change turns
CEM_BASE_URLinto a proper knob:CEM_BASE_URL=wss://your-cem.example/ws ./demo.shroutes the RM there and skips the bundled stand-in.CEM_BASE_URL,demo.shprobescem-reference-1onlocalhost:8003/healthand, when it answers, wires the RM tows://host.docker.internal:8003/ws. Cross-container-to-host works through the newly addedextra_hosts: host.docker.internal:host-gatewayon the RM service.cemstand-in, now guarded by abundled-cemcompose profile so it only starts in this mode.depends_on: cemon bothrmanddemousesrequired: falseso the graph stays valid without it.MOSQUITTO_HOST_PORTandRESOURCE_IDwere also promoted to passthroughs so the defaults can be overridden without editing files.The three-panel demo screen (
demo/index.html) was hard-codingws://localhost:9000/s2and always framing the CEM stand-in iframe. It now fetches/trafficfrom the RM at page-load (and every 2 s), fills the address bar with the livecem_endpoint, and, when that URL points outside the compose network, replaces the CEM iframe with an "S2 CEM external" info tile that shows the endpoint and the link state. When the bundled stand-in is active the iframe is restored, so the original click-through walkthrough still works.TrafficControllersendsAccess-Control-Allow-Origin: *so the demo panel can read/trafficcross-origin.2. Keep FRBC system description IDs stable across reconnects
FRBCSystemDescriptionFactorygenerated the actuator id, both operation mode ids, and both transition ids withSecureRandom.uuid. Every reconnect (or RM restart) produced a fresh set, so anyFRBC.Instructiona CEM had already persisted referenced actuator/operation_mode ids that no longer existed in the new system description. On the wepositive CEM this shows up as a red warning triangle next to those fields on stored instructions.The structural ids are now derived deterministically with
Digest::UUID.uuid_v5from a fixed namespace and<resource.s2_identifier>/<role>. Same resource + same role → same UUID, across reconnects and restarts, with no persistent state to maintain. Onlymessage_idstays random per emission, as the S2 spec requires.3. Fold reception statuses and raw bodies into the RM dashboard feed
The RM dashboard feed had four rough edges:
ReceptionStatuswas rendered as its own row, doubling the feed length and hiding which message it acked.InstructionStatusUpdatethat the RM sends back after processing anFRBC.Instructionwas silently dropped by the render filter.The change:
TrafficLognow storesmessage_id,subject_message_id,status, and the parsedbodyper entry.S2MessageLoggerandMQTTMessageLoggerextract those fields from the payload.ReceptionStatusis no longer its own row. Every S2 message row carries a small badge: green ✓ (OK), red ! (any other status), grey … (waiting). Clicking the badge opens the rawReceptionStatusJSON inline in a green-tinted block.←, toward the CEM column) and CEM→RM (→) are distinguishable at a glance, matching the existing arrow convention on report and command rows.FWDmap gainedinstruction_update → InstructionStatusUpdate, so the reverse-path acknowledgement now surfaces on its own row (with the CEM's ack badge) instead of being filtered out.