mod drive;
mod handshake;
mod inbound;
mod operations;
mod state;
#[cfg(test)]
mod tests;
use crate::de::PacketReader;
use crate::ser::MAX_FIXED_HEADER_SIZE;
use crate::types::Auth;
use crate::{ConfigBuilder, Op, QoS, Will};
use heapless::String;
use super::{ConnectEvent, Io, OpKind, OpStatus};
use state::{RuntimeState, SessionData};
pub struct Session<'buf> {
client_id: String<64>,
packet_reader: PacketReader<'buf>,
data: SessionData<'buf>,
runtime: RuntimeState,
will: Option<Will<'buf>>,
auth: Option<Auth<'buf>>,
session_expiry_interval: u32,
downgrade_qos: bool,
}
impl<'buf> Session<'buf> {
pub fn new(config: ConfigBuilder<'buf>) -> Self {
let (
buffers,
will,
client_id,
keepalive_interval,
session_expiry_interval,
downgrade_qos,
auth,
) = config.into_parts();
let (rx, tx) = buffers.into_parts();
Self {
client_id,
packet_reader: PacketReader::new(rx),
data: SessionData::new(tx),
runtime: RuntimeState::new(keepalive_interval),
will,
auth,
session_expiry_interval,
downgrade_qos,
}
}
pub fn max_rx_packet_size(&self) -> usize {
self.packet_reader.capacity()
}
pub fn max_tx_packet_size(&self) -> usize {
self.data.outbound.capacity()
}
fn can_publish(&self, qos: QoS) -> bool {
if qos == QoS::AtMostOnce {
self.data.outbound.scratch_len() >= MAX_FIXED_HEADER_SIZE
} else {
self.runtime.send_quota != 0 && self.data.outbound.can_retain()
}
}
pub fn is_publish_quiescent(&self) -> bool {
self.data.outbound.is_quiescent()
}
fn status(&self, op: &Op) -> OpStatus {
if op.generation != self.data.generation() {
return OpStatus::Invalidated;
}
let pending = match op.kind {
OpKind::PublishAtLeastOnce | OpKind::Subscribe | OpKind::Unsubscribe => {
self.data.outbound.has_retained(op.packet_id)
}
OpKind::PublishExactlyOnce => {
self.data.outbound.has_retained(op.packet_id)
|| self.data.outbound.has_pending_release(op.packet_id)
}
};
if pending {
OpStatus::Pending
} else {
OpStatus::Complete
}
}
pub fn is_pending(&self, op: &Op) -> bool {
self.status(op) == OpStatus::Pending
}
pub fn is_complete(&self, op: &Op) -> bool {
self.status(op) == OpStatus::Complete
}
pub fn is_invalidated(&self, op: &Op) -> bool {
self.status(op) == OpStatus::Invalidated
}
}
pub struct Connection<'a, 'buf, IO> {
pub(super) session: &'a mut Session<'buf>,
pub(super) io: IO,
pub(super) event: ConnectEvent,
pub(super) live: bool,
}
impl<'buf, IO: Io> Connection<'_, 'buf, IO> {
pub fn connect_event(&self) -> ConnectEvent {
self.event
}
pub fn session(&self) -> &Session<'buf> {
self.session
}
pub fn can_publish(&self, qos: QoS) -> bool {
self.live && self.session.can_publish(qos)
}
pub fn is_connected(&self) -> bool {
self.live
}
pub fn is_pending(&self, op: &Op) -> bool {
self.session.is_pending(op)
}
pub fn is_complete(&self, op: &Op) -> bool {
self.session.is_complete(op)
}
pub fn is_invalidated(&self, op: &Op) -> bool {
self.session.is_invalidated(op)
}
pub fn into_inner(mut self) -> IO {
self.handle_disconnect();
self.io
}
pub fn handle_disconnect(&mut self) {
self.live = false;
self.session.handle_disconnect();
}
}