Skip to content

Commit 2f6a259

Browse files
committed
Move heartbeat timer into session state
1 parent a3b1d61 commit 2f6a259

2 files changed

Lines changed: 46 additions & 19 deletions

File tree

crates/hotfix/src/session.rs

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use crate::message::sequence_reset::SequenceReset;
3131
use crate::message::test_request::TestRequest;
3232
use crate::message_utils::is_admin;
3333
use crate::session::event::AwaitingActiveSessionResponse;
34-
use crate::session::state::AwaitingResendState;
34+
use crate::session::state::{ActiveState, AwaitingResendState};
3535
use crate::session_schedule::SessionSchedule;
3636
use event::SessionEvent;
3737
use hotfix_message::parsed_message::ParsedMessage;
@@ -120,7 +120,6 @@ struct Session<M, S> {
120120
store: S,
121121
awaiting_test_response: Option<TestRequestId>,
122122

123-
heartbeat_timer: Option<Pin<Box<Sleep>>>,
124123
peer_timer: Pin<Box<Sleep>>,
125124
schedule_check_timer: Pin<Box<Sleep>>,
126125
}
@@ -150,7 +149,6 @@ impl<M: FixMessage, S: MessageStore> Session<M, S> {
150149
application,
151150
store,
152151
awaiting_test_response: None,
153-
heartbeat_timer: None,
154152
peer_timer: Box::pin(peer_timer),
155153
schedule_check_timer: Box::pin(schedule_check_timer),
156154
}
@@ -255,9 +253,12 @@ impl<M: FixMessage, S: MessageStore> Session<M, S> {
255253
async fn check_end_of_resend(&mut self) -> Result<()> {
256254
let ended_state = if let SessionState::AwaitingResend(state) = &mut self.state {
257255
if self.store.next_target_seq_number() > state.end_seq_number {
258-
let new_state = SessionState::Active {
256+
let new_state = SessionState::Active(ActiveState {
259257
writer: state.writer.clone(),
260-
};
258+
heartbeat_timer: Box::pin(sleep(Duration::from_secs(
259+
self.config.heartbeat_interval,
260+
))),
261+
});
261262
Some(std::mem::replace(&mut self.state, new_state))
262263
} else {
263264
None
@@ -355,9 +356,12 @@ impl<M: FixMessage, S: MessageStore> Session<M, S> {
355356
match self.verify_message(message).await {
356357
Ok(_) => {
357358
// happy logon flow, the session is now active
358-
self.state = SessionState::Active {
359+
self.state = SessionState::Active(ActiveState {
359360
writer: writer.clone(),
360-
}
361+
heartbeat_timer: Box::pin(sleep(Duration::from_secs(
362+
self.config.heartbeat_interval,
363+
))),
364+
})
361365
}
362366
Err(err) => match err {
363367
MessageVerificationError::SeqNumberTooLow { actual, expected } => {
@@ -543,13 +547,8 @@ impl<M: FixMessage, S: MessageStore> Session<M, S> {
543547
}
544548

545549
fn reset_heartbeat_timer(&mut self) {
546-
let deadline = Instant::now() + Duration::from_secs(self.config.heartbeat_interval);
547-
if let Some(heartbeat_timer) = &mut self.heartbeat_timer {
548-
heartbeat_timer.as_mut().reset(deadline);
549-
} else {
550-
let timer = sleep(Duration::from_secs(self.config.heartbeat_interval));
551-
self.heartbeat_timer = Some(Box::pin(timer));
552-
}
550+
self.state
551+
.reset_heartbeat_timer(self.config.heartbeat_interval);
553552
}
554553

555554
fn reset_peer_timer(&mut self, awaiting_req_id: Option<TestRequestId>) {
@@ -747,7 +746,7 @@ where
747746
}
748747
}
749748
() = async {
750-
if let Some(ref mut timer) = session.heartbeat_timer {
749+
if let Some(ref mut timer) = session.state.heartbeat_timer() {
751750
timer.as_mut().await
752751
} else {
753752
std::future::pending().await

crates/hotfix/src/session/state.rs

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ use crate::session::event::AwaitingActiveSessionResponse;
33
use crate::transport::writer::WriterRef;
44
use hotfix_message::message::Message;
55
use std::collections::VecDeque;
6+
use std::pin::Pin;
7+
use std::time::Duration;
68
use tokio::sync::oneshot;
9+
use tokio::time::{Instant, Sleep};
710
use tracing::{debug, error};
811

912
pub enum SessionState {
@@ -14,7 +17,7 @@ pub enum SessionState {
1417
/// We are in the process of gracefully logging out
1518
AwaitingLogout { writer: WriterRef }, // we need the writer so we can disconnect it on successful logout
1619
/// The session is active, we have connected and mutually logged on.
17-
Active { writer: WriterRef },
20+
Active(ActiveState),
1821
/// The peer has logged us out.
1922
LoggedOut { reconnect: bool },
2023
/// The TCP connection has been dropped.
@@ -38,7 +41,8 @@ impl SessionState {
3841

3942
pub async fn send_message(&mut self, message_type: &[u8], message: RawFixMessage) {
4043
match self {
41-
Self::Active { writer } | Self::AwaitingResend(AwaitingResendState { writer, .. }) => {
44+
Self::Active(ActiveState { writer, .. })
45+
| Self::AwaitingResend(AwaitingResendState { writer, .. }) => {
4246
if message_type == b"A" {
4347
error!("logon message is invalid for active sessions")
4448
} else {
@@ -76,7 +80,7 @@ impl SessionState {
7680

7781
pub async fn disconnect(&self) {
7882
match self {
79-
Self::Active { writer }
83+
Self::Active(ActiveState { writer, .. })
8084
| Self::AwaitingLogon { writer, .. }
8185
| Self::AwaitingLogout { writer }
8286
| Self::AwaitingResend(AwaitingResendState { writer, .. }) => writer.disconnect().await,
@@ -86,7 +90,7 @@ impl SessionState {
8690

8791
pub fn try_transition_to_awaiting_logout(&mut self) -> bool {
8892
match self {
89-
Self::Active { writer }
93+
Self::Active(ActiveState { writer, .. })
9094
| Self::AwaitingLogon { writer, .. }
9195
| Self::AwaitingResend(AwaitingResendState { writer, .. }) => {
9296
*self = SessionState::AwaitingLogout {
@@ -137,6 +141,30 @@ impl SessionState {
137141
}
138142
}
139143
}
144+
145+
pub fn heartbeat_timer(&mut self) -> Option<&mut Pin<Box<Sleep>>> {
146+
match self {
147+
Self::Active(ActiveState {
148+
heartbeat_timer, ..
149+
}) => Some(heartbeat_timer),
150+
_ => None,
151+
}
152+
}
153+
154+
pub fn reset_heartbeat_timer(&mut self, heartbeat_interval: u64) {
155+
if let Self::Active(ActiveState {
156+
heartbeat_timer, ..
157+
}) = self
158+
{
159+
let deadline = Instant::now() + Duration::from_secs(heartbeat_interval);
160+
heartbeat_timer.as_mut().reset(deadline);
161+
}
162+
}
163+
}
164+
165+
pub struct ActiveState {
166+
pub(crate) writer: WriterRef,
167+
pub(crate) heartbeat_timer: Pin<Box<Sleep>>,
140168
}
141169

142170
/// Session state we're in while processing messages we requested to be resent.

0 commit comments

Comments
 (0)