From 288c6bbf0453c2beaf5a050391adc4b7ac56da90 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Fri, 8 Oct 2021 12:04:34 +0200 Subject: [PATCH 1/3] Refactoring keepalive logic --- src/mqtt_client.rs | 32 ++++++++------------------------ src/session_state.rs | 37 ++++++++++++++++++++++++------------- 2 files changed, 32 insertions(+), 37 deletions(-) diff --git a/src/mqtt_client.rs b/src/mqtt_client.rs index 3e656de..a93c5e6 100644 --- a/src/mqtt_client.rs +++ b/src/mqtt_client.rs @@ -10,10 +10,6 @@ use crate::{ }; use embedded_nal::{IpAddr, SocketAddr, TcpClientStack}; -use embedded_time::{ - self, - duration::{Extensions, Seconds}, -}; use heapless::String; @@ -121,10 +117,7 @@ where let packet = serialize::connect_message( &mut buffer, self.session_state.client_id.as_str().as_bytes(), - self.session_state - .keep_alive_interval - .unwrap_or(0.seconds()) - .0 as u16, + self.session_state.keepalive_interval(), &properties, // Only perform a clean start if we do not have any session state. !self.session_state.is_present(), @@ -166,21 +159,14 @@ where /// messages are sent within 50% of the keep-alive interval. pub fn set_keepalive_interval( &mut self, - interval: impl Into>, + interval_seconds: u16, ) -> Result<(), Error> { - let interval = interval.into(); - if interval.0 > u16::MAX as u32 { - return Err(ProtocolError::Invalid.into()); - } - match self.connection_state.state() { - &States::Active => Err(Error::NotReady), - _ => { - self.session_state - .keep_alive_interval - .replace(interval.into()); - Ok(()) - } + if self.connection_state.state() != &States::Active { + return Err(Error::NotReady); } + + self.session_state.set_keepalive(interval_seconds); + Ok(()) } /// Subscribe to a topic. @@ -337,9 +323,7 @@ where String::from_str(id).or(Err(Error::ProvidedClientIdTooLong))?; } Property::ServerKeepAlive(keep_alive) => { - self.session_state - .keep_alive_interval - .replace((keep_alive as u32).seconds()); + self.session_state.set_keepalive(keep_alive); } _prop => info!("Ignoring property: {:?}", _prop), }; diff --git a/src/session_state.rs b/src/session_state.rs index c1aa19f..9085a3b 100644 --- a/src/session_state.rs +++ b/src/session_state.rs @@ -4,7 +4,7 @@ use embedded_nal::IpAddr; use heapless::{LinearMap, String, Vec}; use embedded_time::{ - duration::{Extensions, Seconds}, + duration::{Extensions, Milliseconds, Seconds}, Instant, }; @@ -13,7 +13,7 @@ const PING_TIMEOUT: Seconds = Seconds(5); pub struct SessionState { - pub keep_alive_interval: Option>, + pub keep_alive_interval: Option>, ping_timeout: Option>, next_ping: Option>, pub broker: IpAddr, @@ -37,7 +37,7 @@ impl broker, client_id: id, packet_id: 1, - keep_alive_interval: Some(59.seconds()), + keep_alive_interval: Some(59_000.milliseconds()), pending_subscriptions: Vec::new(), pending_publish: LinearMap::new(), pending_publish_ordering: Vec::new(), @@ -48,13 +48,30 @@ impl pub fn reset(&mut self) { self.active = false; self.packet_id = 1; - self.keep_alive_interval = Some(59.seconds()); + self.keep_alive_interval = Some(59_000.milliseconds()); self.maximum_packet_size = None; self.pending_subscriptions.clear(); self.pending_publish.clear(); self.pending_publish_ordering.clear(); } + /// Get the keep-alive interval as an integer number of seconds. + /// + /// # Note + /// If no keep-alive interval is specified, zero is returned. + pub fn keepalive_interval(&self) -> u16 { + (self.keep_alive_interval.unwrap_or(0.milliseconds()).0 * 1000) as u16 + } + + /// Update the keep-alive interval. + /// + /// # Args + /// * `seconds` - The number of seconds in the keep-alive interval. + pub fn set_keepalive(&mut self, seconds: u16) { + self.keep_alive_interval + .replace(Milliseconds(seconds as u32 * 1000)); + } + /// Called when publish with QoS 1 is called so that we can keep track of PUBACK pub fn handle_publish(&mut self, qos: QoS, id: u16, packet: &[u8]) { // This is not called for QoS 0 and QoS 2 is not implemented yet @@ -107,12 +124,9 @@ impl self.active = true; self.ping_timeout = None; - // The next ping should be sent out in half the keep-alive interval from now. To calculate - // that, we take the integral number of seconds in the keep-alive interval and multiply it - // by 500ms (1/2 seconds) to get half the interval. + // The next ping should be sent out in half the keep-alive interval from now. if let Some(interval) = self.keep_alive_interval { - self.next_ping - .replace(now + 500.milliseconds() * interval.0); + self.next_ping.replace(now + interval / 2); } } @@ -171,10 +185,7 @@ impl // Update the next ping deadline if the ping is due. if now > ping_deadline { // The next ping should be sent out in half the keep-alive interval from now. - // To calculate that, we take the integral number of seconds in the keep-alive - // interval and multiply it by 500ms (1/2 seconds) to get half the interval. - self.next_ping - .replace(now + 500.milliseconds() * keep_alive_interval.0); + self.next_ping.replace(now + keep_alive_interval / 2); self.ping_timeout.replace(now + PING_TIMEOUT); return Ok(true); From d706e62c8616cefd651da7c9ccfb5397a3ef49e3 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Fri, 8 Oct 2021 12:05:04 +0200 Subject: [PATCH 2/3] Updating CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93e8b16..a61e30d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ keep-alive interval * Fixing main docs. * Added support for publishing with QoS 1 * Refactoring network stack management into a separate container class +* Keep-alive settings now take a u16 integer number of seconds # Version 0.3.0 Version 0.3.0 was published on 2021-08-06 From 0a3c690a9023c8fc4f27392623205853b86cbce6 Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Fri, 8 Oct 2021 12:06:11 +0200 Subject: [PATCH 3/3] Removing public access to keep-alive --- src/session_state.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/session_state.rs b/src/session_state.rs index 9085a3b..92ee76c 100644 --- a/src/session_state.rs +++ b/src/session_state.rs @@ -13,7 +13,7 @@ const PING_TIMEOUT: Seconds = Seconds(5); pub struct SessionState { - pub keep_alive_interval: Option>, + keep_alive_interval: Option>, ping_timeout: Option>, next_ping: Option>, pub broker: IpAddr,