use crate::{ffi, from_c_bool, properties::Properties, reason_code::ReasonCode};
use std::ffi::CStr;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ServerRequest {
None,
Connect,
Subscribe,
SubscribeMany(usize),
Unsubscribe,
UnsubscribeMany(usize),
}
impl Default for ServerRequest {
fn default() -> Self {
ServerRequest::None
}
}
#[derive(Clone, Debug)]
pub enum RequestResponse {
None,
Connect(ConnectResponse),
Subscribe(i32),
SubscribeMany(Vec<i32>),
Unsubscribe(i32),
UnsubscribeMany(Vec<i32>),
}
impl Default for RequestResponse {
fn default() -> Self {
RequestResponse::None
}
}
#[derive(Clone, Default, Debug)]
pub struct ConnectResponse {
pub server_uri: String,
pub mqtt_version: u32,
pub session_present: bool,
}
#[derive(Clone, Default, Debug)]
pub struct ServerResponse {
rsp: RequestResponse,
props: Properties,
reason_code: ReasonCode,
}
impl ServerResponse {
pub fn new() -> Self {
ServerResponse::default()
}
pub unsafe fn from_success(req: ServerRequest, rsp: &ffi::MQTTAsync_successData) -> Self {
use ServerRequest::*;
let rsp = match req {
Connect => {
let conn_rsp = ConnectResponse {
server_uri: CStr::from_ptr(rsp.alt.connect.serverURI)
.to_string_lossy()
.to_string(),
mqtt_version: rsp.alt.connect.MQTTVersion as u32,
session_present: from_c_bool(rsp.alt.connect.sessionPresent),
};
RequestResponse::Connect(conn_rsp)
}
Subscribe => RequestResponse::Subscribe(rsp.alt.qos),
SubscribeMany(n) => {
let mut qosv = Vec::new();
if n == 1 {
qosv.push(rsp.alt.qos);
}
else if !rsp.alt.qosList.is_null() {
for i in 0..n {
qosv.push(*rsp.alt.qosList.add(i));
}
}
debug!("Subscribed to {} topics w/ QoS: {:?}", qosv.len(), qosv);
RequestResponse::SubscribeMany(qosv)
}
_ => RequestResponse::None,
};
Self {
rsp,
props: Properties::new(),
reason_code: ReasonCode::default(),
}
}
pub unsafe fn from_success5(req: ServerRequest, rsp: &ffi::MQTTAsync_successData5) -> Self {
use ServerRequest::*;
let props = Properties::from_c_struct(&rsp.properties);
let reason_code = ReasonCode::from(rsp.reasonCode);
let rsp = match req {
Connect => {
let conn_rsp = ConnectResponse {
server_uri: CStr::from_ptr(rsp.alt.connect.serverURI)
.to_string_lossy()
.to_string(),
mqtt_version: rsp.alt.connect.MQTTVersion as u32,
session_present: from_c_bool(rsp.alt.connect.sessionPresent),
};
RequestResponse::Connect(conn_rsp)
}
Subscribe => RequestResponse::Subscribe(rsp.reasonCode as i32),
SubscribeMany(n) => {
let ncode = rsp.alt.sub.reasonCodeCount as usize;
debug_assert!(n == ncode);
let n = std::cmp::min(n, ncode);
let mut qosv = Vec::new();
if n == 1 {
qosv.push(rsp.reasonCode as i32);
}
else if !rsp.alt.sub.reasonCodes.is_null() {
for i in 0..n {
qosv.push(rsp.alt.sub.reasonCodes.add(i) as i32);
}
}
debug!("Subscribed to {} topics w/ QoS: {:?}", qosv.len(), qosv);
RequestResponse::SubscribeMany(qosv)
}
Unsubscribe => RequestResponse::Unsubscribe(rsp.reasonCode as i32),
UnsubscribeMany(n) => {
let ncode = rsp.alt.unsub.reasonCodeCount as usize;
debug!("Server returned {} unsubscribe codes", ncode);
debug_assert!(n == ncode);
let n = std::cmp::min(n, ncode);
let mut qosv = Vec::new();
if n == 1 {
qosv.push(rsp.reasonCode as i32);
}
else if !rsp.alt.sub.reasonCodes.is_null() {
for i in 0..n {
qosv.push(rsp.alt.unsub.reasonCodes.add(i) as i32);
}
}
debug!("Subscribed to {} topics w/ Qos: {:?}", qosv.len(), qosv);
RequestResponse::SubscribeMany(qosv)
}
_ => RequestResponse::None,
};
Self {
rsp,
props,
reason_code,
}
}
pub unsafe fn from_failure5(rsp: &ffi::MQTTAsync_failureData5) -> Self {
Self {
rsp: RequestResponse::default(),
props: Properties::from_c_struct(&rsp.properties),
reason_code: rsp.reasonCode.into(),
}
}
pub fn request_response(&self) -> &RequestResponse {
&self.rsp
}
pub fn connect_response(&self) -> Option<ConnectResponse> {
match &self.rsp {
RequestResponse::Connect(conn_rsp) => Some(conn_rsp.clone()),
_ => None,
}
}
pub fn subscribe_response(&self) -> Option<i32> {
match &self.rsp {
RequestResponse::Subscribe(qos) => Some(*qos),
_ => None,
}
}
pub fn subscribe_many_response(&self) -> Option<Vec<i32>> {
match &self.rsp {
RequestResponse::SubscribeMany(qosv) => Some(qosv.clone()),
_ => None,
}
}
pub fn unsubscribe_response(&self) -> Option<i32> {
match &self.rsp {
RequestResponse::Unsubscribe(qos) => Some(*qos),
_ => None,
}
}
pub fn unsubscribe_many_response(&self) -> Option<Vec<i32>> {
match &self.rsp {
RequestResponse::UnsubscribeMany(qosv) => Some(qosv.clone()),
_ => None,
}
}
pub fn properties(&self) -> &Properties {
&self.props
}
pub fn reason_code(&self) -> ReasonCode {
self.reason_code
}
}