Files
telemt/src/web/session/activity.rs
T
2026-09-03 20:13:37 +03:00

106 lines
3.2 KiB
Rust

use std::time::{Duration, Instant};
use super::{SessionState, WebSession};
use crate::web::telemetry::WebSessionLifecycleObservation;
/// Session-local activity clocks with distinct lease and diagnostic authority.
pub(super) struct SessionActivity {
last_peer: Instant,
last_progress: Instant,
}
impl WebSession {
/// Refreshes the authenticated peer lease and records only threshold-crossing gaps.
pub(super) fn touch_peer_locked(
&self,
state: &mut SessionState,
now: Instant,
observation: WebSessionLifecycleObservation,
) {
let gap = state.activity.touch_peer(now);
if gap >= Duration::from_secs(self.timeouts.reconnect_grace_secs)
&& let Some(manager) = self.manager.upgrade()
{
manager
.telemetry()
.record_session_observation(self.carrier(), observation);
}
}
/// Records one valid WebSocket control message as authenticated peer activity.
pub(crate) fn record_websocket_peer_activity(&self) -> bool {
let mut state = self.state.lock();
if state.closed {
return false;
}
self.touch_peer_locked(
&mut state,
Instant::now(),
WebSessionLifecycleObservation::WebSocketActivityAfterGap,
);
true
}
}
impl SessionActivity {
/// Starts both activity clocks at the same session creation instant.
pub(super) fn new(now: Instant) -> Self {
Self {
last_peer: now,
last_progress: now,
}
}
/// Records one validated peer operation and returns the preceding peer gap.
pub(super) fn touch_peer(&mut self, now: Instant) -> Duration {
let gap = now.saturating_duration_since(self.last_peer);
self.last_peer = now;
self.last_progress = now;
gap
}
/// Records server-side carrier progress without extending the peer lease.
pub(super) fn touch_progress(&mut self, now: Instant) {
self.last_progress = now;
}
/// Returns elapsed time since the latest validated peer operation.
pub(super) fn peer_idle(&self, now: Instant) -> Duration {
now.saturating_duration_since(self.last_peer)
}
/// Returns elapsed time since the latest carrier-side progress.
pub(super) fn progress_idle(&self, now: Instant) -> Duration {
now.saturating_duration_since(self.last_progress)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn progress_does_not_extend_the_authenticated_peer_lease() {
let started = Instant::now();
let mut activity = SessionActivity::new(started);
activity.touch_progress(started + Duration::from_secs(4));
assert_eq!(
activity.peer_idle(started + Duration::from_secs(9)),
Duration::from_secs(9)
);
assert_eq!(
activity.progress_idle(started + Duration::from_secs(9)),
Duration::from_secs(5)
);
assert_eq!(
activity.touch_peer(started + Duration::from_secs(9)),
Duration::from_secs(9)
);
assert_eq!(
activity.peer_idle(started + Duration::from_secs(10)),
Duration::from_secs(1)
);
}
}