Process an incoming frame and return a response frame (if any). Security-context parameters are optional — when provided, per-delta RLS enforcement, rate limiting, silent rejection, and DLQ persistence are active. `None` puts the session in permissive mode (testing / internal replication channels). # Timeseries push In production, the listener intercepts `TimeseriesPush` before calling `process
(
&mut self,
frame: &SyncFrame,
jwt_validator: &JwtValidator,
rls_store: Option<&RlsPolicyStore>,
audit_log: Option<&mut AuditLog>,
dlq: Option<&mut Syn
| 35 | /// |
| 36 | /// [`SharedStateDispatcher`]: super::super::timeseries_handler::SharedStateDispatcher |
| 37 | pub fn process_frame( |
| 38 | &mut self, |
| 39 | frame: &SyncFrame, |
| 40 | jwt_validator: &JwtValidator, |
| 41 | rls_store: Option<&RlsPolicyStore>, |
| 42 | audit_log: Option<&mut AuditLog>, |
| 43 | dlq: Option<&mut SyncDlq>, |
| 44 | epoch_tracker: Option<&std::sync::Mutex<HashMap<String, u64>>>, |
| 45 | ) -> Option<SyncFrame> { |
| 46 | match frame.msg_type { |
| 47 | SyncMessageType::Handshake => { |
| 48 | let msg: HandshakeMsg = frame.decode_body()?; |
| 49 | self.handle_handshake( |
| 50 | &msg, |
| 51 | jwt_validator, |
| 52 | self.server_clock.clone(), |
| 53 | epoch_tracker, |
| 54 | ) |
| 55 | } |
| 56 | SyncMessageType::DeltaPush => { |
| 57 | let msg: DeltaPushMsg = frame.decode_body()?; |
| 58 | self.handle_delta_push(&msg, rls_store, audit_log, dlq) |
| 59 | } |
| 60 | SyncMessageType::VectorClockSync => { |
| 61 | let msg: VectorClockSyncMsg = frame.decode_body()?; |
| 62 | self.handle_vector_clock_sync(&msg) |
| 63 | } |
| 64 | SyncMessageType::ShapeSubscribe => { |
| 65 | let msg: super::super::shape::handler::ShapeSubscribeMsg = frame.decode_body()?; |
| 66 | let registry = super::super::shape::registry::ShapeRegistry::new(); |
| 67 | let tenant_id = self.tenant_id.map(|t| t.as_u64()).unwrap_or(0); |
| 68 | let current_lsn = self.server_clock.values().copied().max().unwrap_or(0); |
| 69 | // Record the subscription so CollectionPurged broadcast |
| 70 | // notifies this session when the shape's source |
| 71 | // collection is hard-deleted. Graph shapes have no |
| 72 | // single source collection; skip tracking for those. |
| 73 | if let Some(coll) = msg.shape.collection() { |
| 74 | self.track_collection(tenant_id, coll); |
| 75 | } |
| 76 | super::super::shape::handler::handle_subscribe( |
| 77 | &self.session_id, |
| 78 | tenant_id, |
| 79 | &msg, |
| 80 | ®istry, |
| 81 | current_lsn, |
| 82 | |_shape, _lsn| super::super::shape::handler::ShapeSnapshotData::empty(), |
| 83 | ) |
| 84 | } |
| 85 | SyncMessageType::ShapeUnsubscribe => { |
| 86 | let msg: super::super::shape::handler::ShapeUnsubscribeMsg = frame.decode_body()?; |
| 87 | let registry = super::super::shape::registry::ShapeRegistry::new(); |
| 88 | super::super::shape::handler::handle_unsubscribe(&self.session_id, &msg, ®istry); |
| 89 | None |
| 90 | } |
| 91 | SyncMessageType::TimeseriesPush => { |
| 92 | // Production path: listener.rs intercepts TimeseriesPush |
| 93 | // before this dispatch and runs it through |
| 94 | // SharedStateDispatcher. Reaching this arm means the |
no test coverage detected