├── .gitignore ├── .travis.yml ├── Cargo.toml ├── LICENSE ├── README.md └── src ├── actors ├── actions │ ├── dispatch.rs │ ├── mod.rs │ ├── recv.rs │ ├── send.rs │ ├── status.rs │ └── stop.rs ├── macros.rs ├── mod.rs ├── packets │ ├── connack.rs │ ├── connect.rs │ ├── disconnect.rs │ ├── macros.rs │ ├── mod.rs │ ├── pingreq.rs │ ├── pingresp.rs │ ├── puback.rs │ ├── pubcomp.rs │ ├── publish.rs │ ├── pubrec.rs │ ├── pubrel.rs │ ├── suback.rs │ ├── subscribe.rs │ ├── unsuback.rs │ └── unsubscribe.rs └── utils.rs ├── client.rs ├── consts.rs └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | .idea/ 5 | *.iml -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - stable 4 | os: 5 | - linux 6 | - osx 7 | - windows 8 | matrix: 9 | fast_finish: true 10 | script: 11 | - cargo build -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "actix-mqtt-client" 3 | version = "0.5.1" 4 | authors = ["Syndim "] 5 | edition = "2018" 6 | repository = "https://github.com/Syndim/actix-mqtt-client" 7 | description = "A MQTT client based on the actix framework" 8 | license = "MIT" 9 | documentation = "https://docs.rs/actix-mqtt-client/" 10 | 11 | [dependencies] 12 | actix = "0.12" 13 | log = "0.4" 14 | futures = "0.3" 15 | lazy_static = "1.4" 16 | rand = "0.8" 17 | 18 | [dependencies.tokio] 19 | version = "1.6" 20 | features = ["net", "io-util", "time", "sync"] 21 | 22 | [dependencies.mqtt-protocol] 23 | version = "0.11" 24 | features = ["tokio"] 25 | 26 | [dev-dependencies] 27 | env_logger = "0.8" 28 | tokio-stream = "0.1" 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2019 Syndim 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A MQTT v3.1.1 client based on actix framework 2 | 3 | The `actix-mqtt-client` crate is a mqtt v3.1.1 client based on the [actix](https://github.com/actix/actix) framework 4 | 5 | [![Build Status](https://travis-ci.org/Syndim/actix-mqtt-client.svg?branch=master)](https://travis-ci.org/Syndim/actix-mqtt-client) [![crates.io](https://img.shields.io/crates/v/actix-mqtt-client.svg)](https://crates.io/crates/actix-mqtt-client) [![docs.rs](https://docs.rs/actix-mqtt-client/badge.svg)](https://docs.rs/actix-mqtt-client) 6 | 7 | ## Basic usage and example 8 | 9 | First, create 2 actix actors, one for receiving publish messages, the other one for receiving error messages from the client, you can also create an optional actix actor for receiving the stop message: 10 | ```rust 11 | pub struct ErrorActor; 12 | 13 | impl actix::Actor for ErrorActor { 14 | type Context = actix::Context; 15 | } 16 | 17 | impl actix::Handler for ErrorActor { 18 | type Result = (); 19 | fn handle(&mut self, error: ErrorMessage, _: &mut Self::Context) -> Self::Result { 20 | log::error!("{}", error.0); 21 | } 22 | } 23 | 24 | pub struct MessageActor; 25 | 26 | impl actix::Actor for MessageActor { 27 | type Context = actix::Context; 28 | } 29 | 30 | impl actix::Handler for MessageActor { 31 | type Result = (); 32 | fn handle( 33 | &mut self, 34 | msg: PublishMessage, 35 | _: &mut Self::Context, 36 | ) -> Self::Result { 37 | log::info!( 38 | "Got message: id:{}, topic: {}, payload: {:?}", 39 | msg.id, 40 | msg.topic_name, 41 | msg.payload 42 | ); 43 | } 44 | } 45 | ``` 46 | 47 | Then, connect to the server(using tokio) and use the read and write part of the stream along with the actors to create a MqttClient: 48 | ```rust 49 | use std::io::Error as IoError; 50 | use std::net::SocketAddr; 51 | use std::str::FromStr; 52 | use std::time::Duration; 53 | use actix::{Actor, Arbiter, System}; 54 | use env_logger; 55 | use tokio::io::split; 56 | use tokio::net::TcpStream; 57 | use tokio::time::{sleep_until, Instant}; 58 | use actix_mqtt_client::client::{MqttClient, MqttOptions}; 59 | 60 | let sys = System::new(); 61 | let socket_addr = SocketAddr::from_str("127.0.0.1:1883").unwrap(); 62 | sys.block_on(async move { 63 | let result = async move { 64 | let stream = TcpStream::connect(socket_addr).await?; 65 | let (r, w) = split(stream); 66 | log::info!("TCP connected"); 67 | let mut client = MqttClient::new( 68 | r, 69 | w, 70 | String::from("test"), 71 | MqttOptions::default(), 72 | MessageActor.start().recipient(), 73 | ErrorActor.start().recipient(), 74 | None, 75 | ); 76 | client.connect().await?; 77 | 78 | // Waiting for the client to be connected 79 | while !client.is_connected().await? { 80 | let delay_time = Instant::now() + Duration::new(1, 0); 81 | sleep_until(delay_time).await; 82 | } 83 | 84 | log::info!("MQTT connected"); 85 | log::info!("Subscribe"); 86 | client 87 | .subscribe(String::from("test"), mqtt::QualityOfService::Level2) 88 | .await?; 89 | log::info!("Publish"); 90 | client 91 | .publish( 92 | String::from("test"), 93 | mqtt::QualityOfService::Level0, 94 | Vec::from("test".as_bytes()), 95 | ) 96 | .await?; 97 | log::info!("Wait for 10s"); 98 | let delay_time = Instant::now() + Duration::new(10, 0); 99 | sleep_until(delay_time).await; 100 | client 101 | .publish( 102 | String::from("test"), 103 | mqtt::QualityOfService::Level1, 104 | Vec::from("test2".as_bytes()), 105 | ) 106 | .await?; 107 | log::info!("Wait for 10s"); 108 | let delay_time = Instant::now() + Duration::new(10, 0); 109 | sleep_until(delay_time).await; 110 | client 111 | .publish( 112 | String::from("test"), 113 | mqtt::QualityOfService::Level2, 114 | Vec::from("test3".as_bytes()), 115 | ) 116 | .await?; 117 | log::info!("Wait for 10s"); 118 | let delay_time = Instant::now() + Duration::new(10, 0); 119 | sleep_until(delay_time).await; 120 | log::info!("Disconnect"); 121 | client.disconnect(false).await?; 122 | log::info!("Check if disconnect is successful"); 123 | Ok(assert_eq!(true, client.is_disconnected())) as Result<(), IoError> 124 | } 125 | .await; 126 | result.unwrap() 127 | }); 128 | sys.run().unwrap(); 129 | ``` 130 | -------------------------------------------------------------------------------- /src/actors/actions/dispatch.rs: -------------------------------------------------------------------------------- 1 | use actix::{Handler, Recipient}; 2 | use mqtt::packet::{ 3 | ConnackPacket, PingrespPacket, PubackPacket, PubcompPacket, PublishPacket, PubrecPacket, 4 | PubrelPacket, SubackPacket, UnsubackPacket, VariablePacket, 5 | }; 6 | 7 | use crate::actors::packets::{PacketMessage, VariablePacketMessage}; 8 | use crate::actors::{handle_send_error, ErrorMessage, StopMessage}; 9 | 10 | pub struct DispatchActor { 11 | error_recipient: Recipient, 12 | stop_recipient: Recipient, 13 | connack_recipient: Recipient>, 14 | pingresp_recipient: Recipient>, 15 | publish_recipient: Recipient>, 16 | puback_recipient: Recipient>, 17 | pubrec_recipient: Recipient>, 18 | pubrel_recipient: Recipient>, 19 | pubcomp_recipient: Recipient>, 20 | suback_recipient: Recipient>, 21 | unsuback_recipient: Recipient>, 22 | } 23 | 24 | impl DispatchActor { 25 | pub fn new( 26 | error_recipient: Recipient, 27 | stop_recipient: Recipient, 28 | connack_recipient: Recipient>, 29 | pingresp_recipient: Recipient>, 30 | publish_recipient: Recipient>, 31 | puback_recipient: Recipient>, 32 | pubrec_recipient: Recipient>, 33 | pubrel_recipient: Recipient>, 34 | pubcomp_recipient: Recipient>, 35 | suback_recipient: Recipient>, 36 | unsuback_recipient: Recipient>, 37 | ) -> Self { 38 | DispatchActor { 39 | error_recipient, 40 | stop_recipient, 41 | connack_recipient, 42 | pingresp_recipient, 43 | publish_recipient, 44 | puback_recipient, 45 | pubrec_recipient, 46 | pubcomp_recipient, 47 | pubrel_recipient, 48 | suback_recipient, 49 | unsuback_recipient, 50 | } 51 | } 52 | } 53 | 54 | impl_empty_actor!(DispatchActor); 55 | impl_stop_handler!(DispatchActor); 56 | 57 | impl Handler for DispatchActor { 58 | type Result = (); 59 | fn handle(&mut self, msg: VariablePacketMessage, _: &mut Self::Context) -> Self::Result { 60 | macro_rules! send_message { 61 | ($target:ident, $msg: ident) => { 62 | if let Err(e) = self.$target.try_send(PacketMessage::new($msg, 0)) { 63 | handle_send_error( 64 | concat!("DispatchActor:", stringify!($target)), 65 | e, 66 | &self.error_recipient, 67 | &self.stop_recipient, 68 | ); 69 | } 70 | }; 71 | } 72 | 73 | match msg.packet { 74 | VariablePacket::ConnackPacket(connack) => { 75 | send_message!(connack_recipient, connack); 76 | } 77 | VariablePacket::PingrespPacket(pingresp) => { 78 | send_message!(pingresp_recipient, pingresp); 79 | } 80 | VariablePacket::PublishPacket(publish) => { 81 | send_message!(publish_recipient, publish); 82 | } 83 | VariablePacket::PubackPacket(puback) => { 84 | send_message!(puback_recipient, puback); 85 | } 86 | VariablePacket::PubrecPacket(pubrec) => { 87 | send_message!(pubrec_recipient, pubrec); 88 | } 89 | VariablePacket::PubrelPacket(pubrel) => { 90 | send_message!(pubrel_recipient, pubrel); 91 | } 92 | VariablePacket::PubcompPacket(pubcomp) => { 93 | send_message!(pubcomp_recipient, pubcomp); 94 | } 95 | VariablePacket::SubackPacket(suback) => { 96 | send_message!(suback_recipient, suback); 97 | } 98 | VariablePacket::UnsubackPacket(unsuback) => { 99 | send_message!(unsuback_recipient, unsuback); 100 | } 101 | _ => (), 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/actors/actions/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod dispatch; 2 | pub mod recv; 3 | pub mod send; 4 | pub mod status; 5 | pub mod stop; 6 | -------------------------------------------------------------------------------- /src/actors/actions/recv.rs: -------------------------------------------------------------------------------- 1 | use std::io::ErrorKind; 2 | 3 | use actix::{Actor, ActorContext, Context as ActixContext, Handler, Recipient, StreamHandler}; 4 | use futures::stream; 5 | use log::{error, trace}; 6 | use mqtt::packet::VariablePacket; 7 | use tokio::io::AsyncRead; 8 | 9 | use crate::actors::packets::VariablePacketMessage; 10 | use crate::actors::{send_error, ErrorMessage, StopMessage}; 11 | 12 | pub struct RecvActor { 13 | stream: Option, 14 | recipient: Recipient, 15 | error_recipient: Recipient, 16 | stop_recipient: Recipient, 17 | } 18 | 19 | impl RecvActor { 20 | pub fn new( 21 | stream: T, 22 | recipient: Recipient, 23 | error_recipient: Recipient, 24 | stop_recipient: Recipient, 25 | ) -> Self { 26 | RecvActor { 27 | stream: Some(stream), 28 | recipient, 29 | error_recipient, 30 | stop_recipient, 31 | } 32 | } 33 | } 34 | 35 | impl Handler for RecvActor { 36 | type Result = (); 37 | 38 | fn handle(&mut self, _: StopMessage, ctx: &mut Self::Context) -> Self::Result { 39 | ctx.stop(); 40 | } 41 | } 42 | 43 | impl StreamHandler for RecvActor { 44 | fn handle(&mut self, item: VariablePacket, _ctx: &mut Self::Context) { 45 | if let Err(e) = self.recipient.try_send(VariablePacketMessage::new(item, 0)) { 46 | send_error( 47 | "RecvActor::stream_handler", 48 | &self.error_recipient, 49 | ErrorKind::Interrupted, 50 | format!("Error when sending packet: {}", e), 51 | ); 52 | } 53 | } 54 | } 55 | 56 | impl Actor for RecvActor { 57 | type Context = ActixContext; 58 | fn started(&mut self, ctx: &mut Self::Context) { 59 | trace!("RecvActor started"); 60 | 61 | if let Some(reader) = self.stream.take() { 62 | let error_recipient = self.error_recipient.clone(); 63 | let stop_recipient = self.stop_recipient.clone(); 64 | let packet_stream = stream::unfold(reader, move |mut r| { 65 | let error_recipient = error_recipient.clone(); 66 | let stop_recipient = stop_recipient.clone(); 67 | async move { 68 | let packet_result = VariablePacket::parse(&mut r).await; 69 | match packet_result { 70 | Ok(packet) => { 71 | trace!("Parse packet succeeded"); 72 | Some((packet, r)) 73 | } 74 | Err(e) => { 75 | error!("Failed to parse packet: {}", e); 76 | send_error( 77 | "RecvActor::parse_packet", 78 | &error_recipient, 79 | ErrorKind::Interrupted, 80 | format!("Error when parsing packet: {}", e), 81 | ); 82 | let _ = stop_recipient.try_send(StopMessage); 83 | 84 | None 85 | } 86 | } 87 | } 88 | }); 89 | Self::add_stream(packet_stream, ctx); 90 | } else { 91 | send_error( 92 | "RecvActor::stream", 93 | &self.error_recipient, 94 | ErrorKind::NotFound, 95 | "Failed to create packet stream: input stream is None", 96 | ); 97 | let _ = self.stop_recipient.do_send(StopMessage); 98 | } 99 | } 100 | 101 | fn stopped(&mut self, _: &mut Self::Context) { 102 | trace!("RecvActor stopped"); 103 | let _ = self.stop_recipient.do_send(StopMessage); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/actors/actions/send.rs: -------------------------------------------------------------------------------- 1 | use std::io::{Error, ErrorKind}; 2 | 3 | use actix::io::{WriteHandler, Writer}; 4 | use actix::{Actor, ActorContext, Context, Handler, Recipient, Running}; 5 | use log::{error, trace}; 6 | use mqtt::encodable::Encodable; 7 | use tokio::io::AsyncWrite; 8 | 9 | use crate::actors::packets::VariablePacketMessage; 10 | use crate::actors::{send_error, ErrorMessage, StopMessage}; 11 | 12 | pub struct SendActor { 13 | stream: Option, 14 | writer: Option>, 15 | error_recipient: Recipient, 16 | stop_recipient: Recipient, 17 | } 18 | 19 | impl SendActor { 20 | pub fn new( 21 | stream: T, 22 | error_recipient: Recipient, 23 | stop_recipient: Recipient, 24 | ) -> Self { 25 | SendActor { 26 | stream: Some(stream), 27 | writer: None, 28 | error_recipient, 29 | stop_recipient, 30 | } 31 | } 32 | } 33 | 34 | impl WriteHandler for SendActor { 35 | fn error(&mut self, err: Error, _ctx: &mut Self::Context) -> Running { 36 | error!("Error in write handler, {:?}", err); 37 | send_error( 38 | "SendActor::error", 39 | &self.error_recipient, 40 | ErrorKind::Interrupted, 41 | format!("{:?}", err), 42 | ); 43 | let _ = self.stop_recipient.do_send(StopMessage); 44 | Running::Stop 45 | } 46 | 47 | fn finished(&mut self, ctx: &mut Self::Context) { 48 | trace!("Writer finished"); 49 | ctx.stop() 50 | } 51 | } 52 | 53 | impl Actor for SendActor { 54 | type Context = Context; 55 | fn started(&mut self, ctx: &mut Self::Context) { 56 | let stream = self.stream.take().unwrap(); 57 | self.writer = Some(Writer::new(stream, ctx)); 58 | trace!("SendActor started"); 59 | } 60 | 61 | fn stopped(&mut self, _: &mut Self::Context) { 62 | trace!("SendActor stopped"); 63 | } 64 | } 65 | 66 | impl actix::Handler for SendActor { 67 | type Result = (); 68 | 69 | fn handle(&mut self, _: StopMessage, ctx: &mut Self::Context) -> Self::Result { 70 | trace!("Got stop message"); 71 | ctx.stop(); 72 | } 73 | } 74 | 75 | impl Handler for SendActor { 76 | type Result = (); 77 | fn handle(&mut self, msg: VariablePacketMessage, _: &mut Self::Context) -> Self::Result { 78 | if self.writer.is_none() { 79 | error!("Writer is none"); 80 | send_error( 81 | "SendActor::writer", 82 | &self.error_recipient, 83 | ErrorKind::NotFound, 84 | "Writer is none", 85 | ); 86 | 87 | return; 88 | } 89 | 90 | let mut buf = Vec::new(); 91 | if let Err(e) = msg.packet.encode(&mut buf) { 92 | error!("Failed to encode message, error {}", e); 93 | send_error( 94 | "SendActor::encode", 95 | &self.error_recipient, 96 | ErrorKind::Interrupted, 97 | format!("Failed to send message, error: {}", e), 98 | ); 99 | } 100 | 101 | let writer = self.writer.as_mut().unwrap(); 102 | writer.write(&*buf); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/actors/actions/status.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use actix::{Handler, Message, Recipient}; 4 | 5 | use crate::actors::packets::disconnect::PacketSendStatus; 6 | 7 | pub enum StatusOperationMessage { 8 | SetPacketStatus(u16, PacketStatus), 9 | GetAndRemovePacketStatus(u16), 10 | RemovePacketStatus(u16), 11 | } 12 | 13 | pub struct PacketStatus { 14 | pub id: u16, 15 | pub retry_count: u16, 16 | pub payload: T, 17 | } 18 | 19 | impl Message for StatusOperationMessage { 20 | type Result = Option>; 21 | } 22 | 23 | #[derive(Message)] 24 | #[rtype(result = "bool")] 25 | pub struct StatusExistenceMessage(pub u16); 26 | 27 | pub struct PacketStatusActor { 28 | name: &'static str, 29 | packet_status_map: HashMap>, 30 | packet_send_status_recipient_option: Option>, 31 | } 32 | 33 | impl PacketStatusActor { 34 | pub fn new( 35 | name: &'static str, 36 | packet_send_status_recipient_option: Option>, 37 | ) -> Self { 38 | PacketStatusActor { 39 | name, 40 | packet_status_map: HashMap::new(), 41 | packet_send_status_recipient_option, 42 | } 43 | } 44 | } 45 | 46 | impl_generic_empty_actor!(PacketStatusActor); 47 | impl_generic_stop_handler!(PacketStatusActor); 48 | 49 | impl Handler for PacketStatusActor { 50 | type Result = bool; 51 | fn handle(&mut self, msg: StatusExistenceMessage, _: &mut Self::Context) -> Self::Result { 52 | self.packet_status_map.contains_key(&msg.0) 53 | } 54 | } 55 | 56 | impl Handler> for PacketStatusActor { 57 | type Result = Option>; 58 | fn handle(&mut self, msg: StatusOperationMessage, _: &mut Self::Context) -> Self::Result { 59 | let result = match msg { 60 | StatusOperationMessage::SetPacketStatus(id, status) => { 61 | self.packet_status_map.insert(id, status); 62 | None 63 | } 64 | StatusOperationMessage::GetAndRemovePacketStatus(id) => { 65 | if self.packet_status_map.contains_key(&id) { 66 | self.packet_status_map.remove(&id) 67 | } else { 68 | None 69 | } 70 | } 71 | StatusOperationMessage::RemovePacketStatus(id) => { 72 | self.packet_status_map.remove(&id); 73 | None 74 | } 75 | }; 76 | 77 | if let Some(ref send_status_recipient) = self.packet_send_status_recipient_option { 78 | let _ = send_status_recipient.do_send(PacketSendStatus { 79 | finished: self.packet_status_map.len() == 0, 80 | }); 81 | } 82 | 83 | result 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/actors/actions/stop.rs: -------------------------------------------------------------------------------- 1 | use std::vec::Vec; 2 | 3 | use actix::{ActorContext, Handler, Message, Recipient}; 4 | use log::trace; 5 | 6 | use crate::actors::StopMessage; 7 | 8 | #[derive(Message)] 9 | #[rtype(result = "()")] 10 | pub struct AddStopRecipient(pub Recipient); 11 | 12 | pub struct StopActor { 13 | stop_recipients: Vec>, 14 | stopping: bool, 15 | } 16 | 17 | impl StopActor { 18 | pub fn new() -> Self { 19 | StopActor { 20 | stop_recipients: Vec::new(), 21 | stopping: false, 22 | } 23 | } 24 | } 25 | 26 | impl_empty_actor!(StopActor); 27 | 28 | impl Handler for StopActor { 29 | type Result = (); 30 | fn handle(&mut self, _: StopMessage, ctx: &mut Self::Context) -> Self::Result { 31 | if self.stopping { 32 | trace!("Already stopping"); 33 | return; 34 | } 35 | 36 | self.stopping = true; 37 | for stop_recipient in &self.stop_recipients { 38 | let _ = stop_recipient.do_send(StopMessage); 39 | } 40 | 41 | ctx.stop(); 42 | } 43 | } 44 | 45 | impl Handler for StopActor { 46 | type Result = (); 47 | fn handle(&mut self, msg: AddStopRecipient, _: &mut Self::Context) -> Self::Result { 48 | self.stop_recipients.push(msg.0); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/actors/macros.rs: -------------------------------------------------------------------------------- 1 | macro_rules! impl_empty_actor { 2 | ($name:ident) => { 3 | impl_empty_actor!($name, crate::consts::DEFAULT_MAILBOX_CAPACITY); 4 | }; 5 | ($name:ident, $mailbox_capacity:expr) => { 6 | impl actix::Actor for $name { 7 | type Context = actix::Context; 8 | fn started(&mut self, ctx: &mut Self::Context) { 9 | ctx.set_mailbox_capacity($mailbox_capacity); 10 | log::debug!(concat!(stringify!($name), " started")); 11 | } 12 | 13 | fn stopped(&mut self, _: &mut Self::Context) { 14 | log::debug!(concat!(stringify!($name), " stopped")); 15 | } 16 | } 17 | }; 18 | } 19 | 20 | macro_rules! impl_generic_empty_actor { 21 | ($name:ident) => { 22 | impl_generic_empty_actor!($name, crate::consts::DEFAULT_MAILBOX_CAPACITY); 23 | }; 24 | ($name:ident, $mailbox_capacity:expr) => { 25 | impl actix::Actor for $name { 26 | type Context = actix::Context; 27 | fn started(&mut self, ctx: &mut Self::Context) { 28 | ctx.set_mailbox_capacity($mailbox_capacity); 29 | log::debug!(concat!(stringify!($name), "[{}]", " started"), self.name); 30 | } 31 | 32 | fn stopped(&mut self, _: &mut Self::Context) { 33 | log::debug!(concat!(stringify!($name), "[{}]", " stopped"), self.name); 34 | } 35 | } 36 | }; 37 | } 38 | 39 | macro_rules! impl_stop_handler { 40 | ($name:ident) => { 41 | impl actix::Handler for $name { 42 | type Result = (); 43 | 44 | fn handle( 45 | &mut self, 46 | _: crate::actors::StopMessage, 47 | ctx: &mut Self::Context, 48 | ) -> Self::Result { 49 | log::debug!(concat!("Handle stop message for ", stringify!($name))); 50 | use actix::ActorContext; 51 | ctx.stop(); 52 | } 53 | } 54 | }; 55 | } 56 | 57 | macro_rules! impl_generic_stop_handler { 58 | ($name:ident) => { 59 | impl actix::Handler for $name { 60 | type Result = (); 61 | 62 | fn handle( 63 | &mut self, 64 | _: crate::actors::StopMessage, 65 | ctx: &mut Self::Context, 66 | ) -> Self::Result { 67 | log::debug!(concat!("Handle stop message for ", stringify!($name))); 68 | use actix::ActorContext; 69 | ctx.stop(); 70 | } 71 | } 72 | }; 73 | } 74 | -------------------------------------------------------------------------------- /src/actors/mod.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | 3 | #[macro_use] 4 | pub mod macros; 5 | pub mod actions; 6 | pub mod packets; 7 | mod utils; 8 | 9 | use std::io::ErrorKind; 10 | 11 | use actix::dev::ToEnvelope; 12 | use actix::prelude::SendError; 13 | use actix::{Actor, Addr, Arbiter, Handler, MailboxError, Message, Recipient}; 14 | use log::trace; 15 | use tokio::time::{sleep_until, Instant}; 16 | 17 | use crate::consts::RESEND_DELAY; 18 | 19 | /// The actix message indicating that the client is about to stop 20 | #[derive(Message)] 21 | #[rtype(result = "()")] 22 | pub struct StopMessage; 23 | 24 | /// The actix message containing the error happens inside the client 25 | #[derive(Message)] 26 | #[rtype(result = "()")] 27 | pub struct ErrorMessage(pub io::Error); 28 | 29 | pub fn send_error>( 30 | tag: &str, 31 | error_recipient: &Recipient, 32 | kind: io::ErrorKind, 33 | message: T, 34 | ) { 35 | let error = io::Error::new(kind, message.as_ref()); 36 | let send_result = error_recipient.try_send(ErrorMessage(error)); 37 | log::debug!( 38 | "[{}] Send result for error recipient: {:?}", 39 | tag, 40 | send_result 41 | ); 42 | } 43 | 44 | fn resend(addr: Addr, msg: TMessage) 45 | where 46 | TMessage: Message + Send + 'static, 47 | TActor: Actor + Handler, 48 | TMessage::Result: Send, 49 | TActor::Context: ToEnvelope, 50 | { 51 | trace!("Schedule resend message"); 52 | let later_func = async move { 53 | let delay_time = Instant::now() + RESEND_DELAY.clone(); 54 | sleep_until(delay_time).await; 55 | addr.do_send(msg); 56 | }; 57 | Arbiter::current().spawn(later_func); 58 | } 59 | 60 | fn handle_send_error( 61 | tag: &str, 62 | e: SendError, 63 | error_recipient: &Recipient, 64 | stop_recipient: &Recipient, 65 | ) { 66 | match e { 67 | SendError::Closed(_) => { 68 | send_error( 69 | tag, 70 | error_recipient, 71 | ErrorKind::Interrupted, 72 | format!("[{}] Target mailbox is closed", tag), 73 | ); 74 | let _ = stop_recipient.do_send(StopMessage); 75 | } 76 | SendError::Full(_) => { 77 | // Do nothing 78 | send_error( 79 | tag, 80 | error_recipient, 81 | ErrorKind::Other, 82 | format!("[{}] Target mailbox is full", tag), 83 | ); 84 | } 85 | } 86 | } 87 | 88 | fn handle_send_error_with_resend( 89 | tag: &str, 90 | e: SendError, 91 | error_recipient: &Recipient, 92 | stop_recipient: &Recipient, 93 | addr: Addr, 94 | msg: TMessage, 95 | ) where 96 | TMessage: Message + Send + 'static, 97 | TActor: Actor + Handler, 98 | TMessage::Result: Send, 99 | TActor::Context: ToEnvelope, 100 | { 101 | match e { 102 | SendError::Closed(_) => { 103 | send_error( 104 | tag, 105 | error_recipient, 106 | ErrorKind::Interrupted, 107 | format!("[{}] Target mailbox is closed", tag), 108 | ); 109 | let _ = stop_recipient.do_send(StopMessage); 110 | } 111 | SendError::Full(_) => { 112 | send_error( 113 | tag, 114 | error_recipient, 115 | ErrorKind::Other, 116 | format!("[{}] Target mailbox is full, will retry send", tag), 117 | ); 118 | resend(addr, msg); 119 | } 120 | } 121 | } 122 | 123 | // fn handle_mailbox_error( 124 | // e: MailboxError, 125 | // error_recipient: &Recipient, 126 | // stop_recipient: &Recipient, 127 | // ) { 128 | // match e { 129 | // MailboxError::Closed => { 130 | // send_error( 131 | // error_recipient, 132 | // ErrorKind::Interrupted, 133 | // "Target mailbox is closed", 134 | // ); 135 | // stop_system(stop_recipient, errors::ERROR_CODE_FAILED_TO_SEND_MESSAGE); 136 | // } 137 | // MailboxError::Timeout => { 138 | // // Do nothing 139 | // send_error(error_recipient, ErrorKind::Other, "Send timeout"); 140 | // } 141 | // } 142 | // } 143 | 144 | fn handle_mailbox_error_with_resend( 145 | tag: &str, 146 | e: MailboxError, 147 | error_recipient: &Recipient, 148 | stop_recipient: &Recipient, 149 | addr: Addr, 150 | msg: TMessage, 151 | ) where 152 | TMessage: Message + Send + 'static, 153 | TActor: Actor + Handler, 154 | TMessage::Result: Send, 155 | TActor::Context: ToEnvelope, 156 | { 157 | match e { 158 | MailboxError::Closed => { 159 | send_error( 160 | tag, 161 | error_recipient, 162 | ErrorKind::Interrupted, 163 | "Target mailbox is closed", 164 | ); 165 | let _ = stop_recipient.do_send(StopMessage); 166 | } 167 | MailboxError::Timeout => { 168 | send_error( 169 | tag, 170 | error_recipient, 171 | ErrorKind::Other, 172 | "Send timeout, will resend", 173 | ); 174 | 175 | resend(addr, msg); 176 | } 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /src/actors/packets/connack.rs: -------------------------------------------------------------------------------- 1 | use std::io::ErrorKind; 2 | 3 | use actix::{ActorContext, Handler, Recipient}; 4 | use log::trace; 5 | use mqtt::control::variable_header::ConnectReturnCode; 6 | use mqtt::packet::ConnackPacket; 7 | 8 | use crate::actors::actions::status::{PacketStatus, StatusOperationMessage}; 9 | use crate::actors::{send_error, ErrorMessage, StopMessage}; 10 | 11 | use super::PacketMessage; 12 | 13 | pub struct ConnackActor { 14 | status_recipient: Recipient>, 15 | error_recipient: Recipient, 16 | connect_stop_recipient: Recipient, 17 | stop_recipient: Recipient, 18 | } 19 | 20 | impl ConnackActor { 21 | pub fn new( 22 | status_recipient: Recipient>, 23 | error_recipient: Recipient, 24 | connect_stop_recipient: Recipient, 25 | stop_recipient: Recipient, 26 | ) -> Self { 27 | ConnackActor { 28 | status_recipient, 29 | error_recipient, 30 | connect_stop_recipient, 31 | stop_recipient, 32 | } 33 | } 34 | } 35 | 36 | impl_empty_actor!(ConnackActor); 37 | impl_stop_handler!(ConnackActor); 38 | 39 | impl Handler> for ConnackActor { 40 | type Result = (); 41 | fn handle( 42 | &mut self, 43 | msg: PacketMessage, 44 | ctx: &mut Self::Context, 45 | ) -> Self::Result { 46 | trace!("Handle message for ConnackActor"); 47 | if let Err(e) = self 48 | .status_recipient 49 | .try_send(StatusOperationMessage::RemovePacketStatus(0)) 50 | { 51 | send_error( 52 | "ConnackActor::status_recipient", 53 | &self.error_recipient, 54 | ErrorKind::NotConnected, 55 | format!("Failed to mark status for connack packet: {}", e), 56 | ); 57 | let _ = self.stop_recipient.do_send(StopMessage); 58 | } else { 59 | let return_code = msg.packet.connect_return_code(); 60 | if return_code == ConnectReturnCode::ConnectionAccepted { 61 | // For connect status: 62 | // status message with id = 0 indicating the connecing status 63 | // status message with id = 1 indicating the connected status 64 | let _ = self 65 | .status_recipient 66 | .do_send(StatusOperationMessage::SetPacketStatus( 67 | 1, 68 | PacketStatus { 69 | id: 1, 70 | retry_count: 0, 71 | payload: (), 72 | }, 73 | )); 74 | let _ = self.connect_stop_recipient.do_send(StopMessage); 75 | ctx.stop(); 76 | } else { 77 | send_error( 78 | "ConnackActor::connect", 79 | &self.error_recipient, 80 | ErrorKind::NotConnected, 81 | format!( 82 | "Failed to connect to server, server returns: {:?}", 83 | return_code 84 | ), 85 | ); 86 | 87 | let _ = self.stop_recipient.do_send(StopMessage); 88 | } 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/actors/packets/connect.rs: -------------------------------------------------------------------------------- 1 | use std::io::ErrorKind; 2 | 3 | use actix::{Arbiter, AsyncContext, Handler, Message, Recipient}; 4 | use log::trace; 5 | use mqtt::packet::{ConnectPacket, VariablePacket}; 6 | 7 | use crate::actors::actions::status::{PacketStatus, StatusOperationMessage}; 8 | use crate::actors::send_error; 9 | use crate::actors::{ErrorMessage, StopMessage}; 10 | use crate::consts::COMMAND_TIMEOUT; 11 | 12 | use super::VariablePacketMessage; 13 | 14 | #[derive(Message)] 15 | #[rtype(result = "()")] 16 | pub struct Connect { 17 | pub user_name: Option, 18 | pub password: Option, 19 | pub keep_alive: Option, 20 | } 21 | 22 | pub struct ConnectActor { 23 | send_recipient: Recipient, 24 | status_recipient: Recipient>, 25 | stop_recipient: Recipient, 26 | error_recipient: Recipient, 27 | client_name: String, 28 | } 29 | 30 | impl ConnectActor { 31 | pub fn new( 32 | send_recipient: Recipient, 33 | status_recipient: Recipient>, 34 | stop_recipient: Recipient, 35 | error_recipient: Recipient, 36 | client_name: String, 37 | ) -> Self { 38 | ConnectActor { 39 | send_recipient, 40 | status_recipient, 41 | stop_recipient, 42 | error_recipient, 43 | client_name, 44 | } 45 | } 46 | } 47 | 48 | impl_empty_actor!(ConnectActor); 49 | impl_stop_handler!(ConnectActor); 50 | 51 | impl Handler for ConnectActor { 52 | type Result = (); 53 | fn handle(&mut self, msg: Connect, ctx: &mut Self::Context) -> Self::Result { 54 | trace!("Handle message for ConnectActor"); 55 | 56 | // For connect status: 57 | // status message with id = 0 indicating the connecing status 58 | // status message with id = 1 indicating the connected status 59 | if let Err(e) = self 60 | .status_recipient 61 | .do_send(StatusOperationMessage::SetPacketStatus( 62 | 0, 63 | PacketStatus { 64 | id: 0, 65 | retry_count: 0, 66 | payload: (), 67 | }, 68 | )) 69 | { 70 | send_error( 71 | "ConnectActor::status_recipient", 72 | &self.error_recipient, 73 | ErrorKind::Interrupted, 74 | format!("Failed to set packet status: {}", e), 75 | ); 76 | let _ = self.stop_recipient.do_send(StopMessage); 77 | return; 78 | } 79 | 80 | let mut packet = ConnectPacket::new(&self.client_name); 81 | packet.set_user_name(msg.user_name); 82 | packet.set_password(msg.password); 83 | if let Some(keep_alive) = msg.keep_alive { 84 | packet.set_keep_alive(keep_alive); 85 | } 86 | 87 | let connect_variable_packet = VariablePacket::ConnectPacket(packet); 88 | if let Err(e) = self 89 | .send_recipient 90 | .do_send(VariablePacketMessage::new(connect_variable_packet, 0)) 91 | { 92 | send_error( 93 | "ConnectActor::send_recipient", 94 | &self.error_recipient, 95 | ErrorKind::Interrupted, 96 | format!("Failed to send connect packet: {}", e), 97 | ); 98 | let _ = self.stop_recipient.do_send(StopMessage); 99 | return; 100 | } 101 | 102 | let stop_recipient = self.stop_recipient.clone(); 103 | ctx.run_later(COMMAND_TIMEOUT.clone(), |actor, ctx| { 104 | let addr = ctx.address(); 105 | let error_recipient = actor.error_recipient.clone(); 106 | let status_recipient = actor.status_recipient.clone(); 107 | let status_future = async move { 108 | let status_result = status_recipient 109 | .send(StatusOperationMessage::GetAndRemovePacketStatus(0)) 110 | .await; 111 | match status_result { 112 | Ok(status) => { 113 | if status.is_some() { 114 | send_error( 115 | "ConnectActor::status_recipient_ack", 116 | &error_recipient, 117 | ErrorKind::InvalidData, 118 | format!("Doesn't got connect ack from server, exit"), 119 | ); 120 | let _ = stop_recipient.do_send(StopMessage); 121 | } else { 122 | // Stop the connect actor 123 | addr.do_send(StopMessage); 124 | } 125 | } 126 | Err(e) => { 127 | send_error( 128 | "ConnectActor::status_recipient", 129 | &error_recipient, 130 | ErrorKind::InvalidData, 131 | format!("Failed to check connect ack status: {}", e), 132 | ); 133 | let _ = stop_recipient.do_send(StopMessage); 134 | } 135 | } 136 | }; 137 | Arbiter::current().spawn(status_future); 138 | }); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/actors/packets/disconnect.rs: -------------------------------------------------------------------------------- 1 | use actix::{ActorContext, AsyncContext, Handler, Message, Recipient}; 2 | use log::{debug, trace}; 3 | use mqtt::packet::{DisconnectPacket, VariablePacket}; 4 | 5 | use crate::actors::{ErrorMessage, StopMessage}; 6 | 7 | use super::{send_packet, VariablePacketMessage}; 8 | 9 | #[derive(Message)] 10 | #[rtype(result = "()")] 11 | pub struct Disconnect { 12 | pub force: bool, 13 | } 14 | 15 | #[derive(Message)] 16 | #[rtype(result = "()")] 17 | pub struct PacketSendStatus { 18 | pub finished: bool, 19 | } 20 | 21 | pub struct DisconnectActor { 22 | stop_recipient: Recipient, 23 | error_recipient: Recipient, 24 | send_recipient: Recipient, 25 | packet_send_finished: bool, 26 | pending_disconnect: bool, 27 | } 28 | 29 | impl DisconnectActor { 30 | pub fn new( 31 | send_recipient: Recipient, 32 | error_recipient: Recipient, 33 | stop_recipient: Recipient, 34 | ) -> Self { 35 | DisconnectActor { 36 | send_recipient, 37 | error_recipient, 38 | stop_recipient, 39 | packet_send_finished: true, 40 | pending_disconnect: false, 41 | } 42 | } 43 | } 44 | 45 | impl_empty_actor!(DisconnectActor); 46 | impl_stop_handler!(DisconnectActor); 47 | 48 | impl Handler for DisconnectActor { 49 | type Result = (); 50 | fn handle(&mut self, msg: Disconnect, ctx: &mut Self::Context) -> Self::Result { 51 | trace!("Handle message for DisconnectActor"); 52 | // Need to wait for all pending packets to be sent before sending disconnect to server 53 | if msg.force || self.packet_send_finished { 54 | debug!( 55 | "Sending disconnect to sever, force: {}, no pending packet: {}", 56 | msg.force, self.packet_send_finished 57 | ); 58 | let packet = VariablePacket::DisconnectPacket(DisconnectPacket::new()); 59 | send_packet( 60 | "DisconnectActor::disconnect", 61 | ctx, 62 | &self.send_recipient, 63 | &self.error_recipient, 64 | &self.stop_recipient, 65 | packet, 66 | msg, 67 | ); 68 | 69 | let _ = self.stop_recipient.do_send(StopMessage); 70 | ctx.stop(); 71 | } else { 72 | trace!( 73 | "Has pending packet, wait for them to be sent before sending disconnect to server" 74 | ); 75 | self.pending_disconnect = true; 76 | } 77 | } 78 | } 79 | 80 | impl Handler for DisconnectActor { 81 | type Result = (); 82 | fn handle(&mut self, msg: PacketSendStatus, ctx: &mut Self::Context) -> Self::Result { 83 | self.packet_send_finished = msg.finished; 84 | if self.pending_disconnect && self.packet_send_finished { 85 | self.pending_disconnect = false; 86 | ctx.address().do_send(Disconnect { force: true }); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/actors/packets/macros.rs: -------------------------------------------------------------------------------- 1 | macro_rules! assert_valid_retry_count { 2 | ($name:expr, $self:ident, $last_retry_count:expr, $id:expr) => { 3 | if $last_retry_count > crate::consts::MAX_RETRY_COUNT { 4 | log::error!("Max retry count excceeded"); 5 | if let Err(e) = $self.status_recipient.do_send( 6 | crate::actors::actions::status::StatusOperationMessage::RemovePacketStatus($id), 7 | ) { 8 | crate::actors::handle_send_error( 9 | concat!(stringify!($name), ":status_recipient"), 10 | e, 11 | &$self.error_recipient, 12 | &$self.stop_recipient, 13 | ); 14 | } 15 | 16 | return; 17 | } 18 | }; 19 | } 20 | 21 | macro_rules! define_response_packet_actor { 22 | ($name:ident) => { 23 | define_response_packet_actor!($name, ()); 24 | }; 25 | ($name:ident, $status_payload_type:ty) => { 26 | pub struct $name { 27 | status_recipient: actix::Recipient< 28 | crate::actors::actions::status::StatusOperationMessage<$status_payload_type>, 29 | >, 30 | error_recipient: actix::Recipient, 31 | stop_recipient: actix::Recipient, 32 | } 33 | 34 | impl $name { 35 | pub fn new( 36 | status_recipient: actix::Recipient< 37 | crate::actors::actions::status::StatusOperationMessage<$status_payload_type>, 38 | >, 39 | error_recipient: actix::Recipient, 40 | stop_recipient: actix::Recipient, 41 | ) -> Self { 42 | $name { 43 | status_recipient, 44 | error_recipient, 45 | stop_recipient, 46 | } 47 | } 48 | } 49 | }; 50 | } 51 | 52 | macro_rules! impl_response_packet_actor { 53 | ($name:ident, $packet:ident, $get_id_from_packet:ident, $get_retry_msg_from_msg:ident) => { 54 | impl_empty_actor!($name); 55 | impl_stop_handler!($name); 56 | 57 | impl actix::Handler> 58 | for $name 59 | { 60 | type Result = (); 61 | fn handle( 62 | &mut self, 63 | msg: crate::actors::packets::PacketMessage, 64 | ctx: &mut Self::Context, 65 | ) -> Self::Result { 66 | log::trace!(concat!("Handling message for ", stringify!($name))); 67 | let id = $get_id_from_packet(&msg.packet); 68 | crate::actors::packets::reset_packet_status( 69 | stringify!($name), 70 | ctx, 71 | &self.status_recipient, 72 | &self.error_recipient, 73 | &self.stop_recipient, 74 | id, 75 | $get_retry_msg_from_msg(msg), 76 | ); 77 | } 78 | } 79 | }; 80 | } 81 | 82 | macro_rules! get_packet_identifier_func { 83 | ($name:ident, $packet_type: ty) => { 84 | fn $name(packet: &$packet_type) -> u16 { 85 | packet.packet_identifier() 86 | } 87 | }; 88 | } 89 | 90 | macro_rules! get_retry_msg_func { 91 | ($name:ident, $msg_type: ty) => { 92 | fn $name(msg: $msg_type) -> $msg_type { 93 | let mut resend_msg = msg; 94 | resend_msg.retry_count += 1; 95 | resend_msg 96 | } 97 | }; 98 | } 99 | 100 | macro_rules! define_send_packet_actor { 101 | ($name:ident) => { 102 | define_send_packet_actor!($name, ()); 103 | }; 104 | ($name:ident, $status_paylod_type:ty) => { 105 | pub struct $name { 106 | status_recipient: actix::Recipient< 107 | crate::actors::actions::status::StatusOperationMessage<$status_paylod_type>, 108 | >, 109 | send_recipient: actix::Recipient, 110 | error_recipient: actix::Recipient, 111 | stop_recipient: actix::Recipient, 112 | } 113 | 114 | impl $name { 115 | pub fn new( 116 | status_recipient: actix::Recipient< 117 | crate::actors::actions::status::StatusOperationMessage<$status_paylod_type>, 118 | >, 119 | send_recipient: actix::Recipient, 120 | error_recipient: actix::Recipient, 121 | stop_recipient: actix::Recipient, 122 | ) -> Self { 123 | $name { 124 | status_recipient, 125 | send_recipient, 126 | error_recipient, 127 | stop_recipient, 128 | } 129 | } 130 | } 131 | }; 132 | } 133 | 134 | macro_rules! impl_send_packet_actor { 135 | ($name:ident, $message:ty, $packet:ident, $get_retry_count_from_message:ident, $create_retry_msessage_from_message:ident, $create_packet_and_id_from_message:ident) => { 136 | impl_send_packet_actor!( 137 | $name, 138 | $message, 139 | $packet, 140 | $get_retry_count_from_message, 141 | $create_retry_msessage_from_message, 142 | $create_packet_and_id_from_message, 143 | |id, retry_count| { 144 | crate::actors::actions::status::StatusOperationMessage::SetPacketStatus( 145 | id, 146 | crate::actors::actions::status::PacketStatus { 147 | id, 148 | retry_count, 149 | payload: (), 150 | }, 151 | ) 152 | }, 153 | |status| status.is_some() 154 | ); 155 | }; 156 | ($name:ident, $message:ty, $packet:ident, $get_retry_count_from_message:ident, $create_retry_msessage_from_message:ident, $create_packet_and_id_from_message:ident, $create_status_from_id_and_retry_count:expr, $status_check_func:expr) => { 157 | impl_stop_handler!($name); 158 | 159 | impl actix::Handler<$message> for $name { 160 | type Result = (); 161 | fn handle(&mut self, msg: $message, ctx: &mut Self::Context) -> Self::Result { 162 | log::trace!(concat!("Handling message for ", stringify!($name))); 163 | let packet_and_id_option = $create_packet_and_id_from_message(&msg); 164 | if packet_and_id_option.is_none() { 165 | return; 166 | } 167 | 168 | let (packet, id) = packet_and_id_option.unwrap(); 169 | let last_retry_count = $get_retry_count_from_message(&msg); 170 | assert_valid_retry_count!($name, self, last_retry_count, id); 171 | 172 | let resend_msg = $create_retry_msessage_from_message(msg); 173 | let status_msg = $create_status_from_id_and_retry_count(id, last_retry_count); 174 | if !crate::actors::packets::set_packet_status( 175 | stringify!($name), 176 | ctx, 177 | &self.status_recipient, 178 | &self.error_recipient, 179 | &self.stop_recipient, 180 | resend_msg.clone(), 181 | status_msg, 182 | ) { 183 | return; 184 | } 185 | 186 | if !crate::actors::packets::send_packet( 187 | stringify!($name), 188 | ctx, 189 | &self.send_recipient, 190 | &self.error_recipient, 191 | &self.stop_recipient, 192 | mqtt::packet::VariablePacket::$packet(packet), 193 | resend_msg.clone(), 194 | ) { 195 | return; 196 | } 197 | 198 | crate::actors::packets::schedule_status_check( 199 | ctx, 200 | &self.status_recipient, 201 | &self.error_recipient, 202 | &self.stop_recipient, 203 | id, 204 | resend_msg, 205 | $status_check_func, 206 | ); 207 | } 208 | } 209 | }; 210 | } 211 | -------------------------------------------------------------------------------- /src/actors/packets/mod.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | mod macros; 3 | pub mod connack; 4 | pub mod connect; 5 | pub mod disconnect; 6 | pub mod pingreq; 7 | pub mod pingresp; 8 | pub mod puback; 9 | pub mod pubcomp; 10 | pub mod publish; 11 | pub mod pubrec; 12 | pub mod pubrel; 13 | pub mod suback; 14 | pub mod subscribe; 15 | pub mod unsuback; 16 | pub mod unsubscribe; 17 | 18 | use std::vec::Vec; 19 | 20 | use actix::dev::ToEnvelope; 21 | use actix::{Actor, AsyncContext, Context, Handler, Message, Recipient}; 22 | use mqtt::packet::VariablePacket; 23 | 24 | use crate::actors::actions::status::{PacketStatus, StatusOperationMessage}; 25 | use crate::actors::{ErrorMessage, StopMessage}; 26 | use crate::consts::COMMAND_TIMEOUT; 27 | 28 | use super::{handle_mailbox_error_with_resend, handle_send_error_with_resend, send_error}; 29 | 30 | #[derive(Clone)] 31 | pub struct PacketMessage { 32 | pub packet: T, 33 | pub retry_count: u16, 34 | } 35 | 36 | impl Message for PacketMessage { 37 | type Result = (); 38 | } 39 | 40 | impl PacketMessage { 41 | pub fn new(packet: T, retry_count: u16) -> Self { 42 | PacketMessage { 43 | packet, 44 | retry_count, 45 | } 46 | } 47 | } 48 | 49 | pub type VariablePacketMessage = PacketMessage; 50 | 51 | /// The actix message containing the payload of a MQTT publish packet 52 | #[derive(Debug, Message, Clone)] 53 | #[rtype(result = "()")] 54 | pub struct PublishMessage { 55 | /// The packet identifier of the publish packet for QoS Level 1 and Level 2, or 0 for QoS Level 0 56 | pub id: u16, 57 | /// The topic name of the message 58 | pub topic_name: String, 59 | /// The message payload 60 | pub payload: Vec, 61 | } 62 | 63 | #[derive(PartialEq)] 64 | pub enum PublishPacketStatus { 65 | PendingAck, 66 | PendingRec, 67 | PendingRel, 68 | PendingComp, 69 | } 70 | 71 | fn schedule_status_check( 72 | ctx: &mut Context, 73 | status_recipient: &Recipient>, 74 | error_recipient: &Recipient, 75 | stop_recipient: &Recipient, 76 | id: u16, 77 | retry_msg: TMessage, 78 | status_check_func: TStatusCheckFunc, 79 | ) where 80 | TActor: Actor> + Handler, 81 | TMessage: Message + Send + 'static + Clone, 82 | TMessage::Result: Send, 83 | TActor::Context: ToEnvelope, 84 | TStatusPayload: Send + 'static, 85 | TStatusCheckFunc: FnOnce(&Option>) -> bool + Send + 'static, 86 | { 87 | let error_recipient = error_recipient.clone(); 88 | let stop_recipient = stop_recipient.clone(); 89 | let status_recipient = status_recipient.clone(); 90 | let addr = ctx.address(); 91 | let addr_clone = addr.clone(); 92 | let msg_clone = retry_msg.clone(); 93 | ctx.run_later(COMMAND_TIMEOUT.clone(), move |_, _| { 94 | let status_future = async move { 95 | let status_result = status_recipient 96 | .send( 97 | crate::actors::actions::status::StatusOperationMessage::GetAndRemovePacketStatus( 98 | id, 99 | ), 100 | ) 101 | .await; 102 | match status_result { 103 | Ok(status) => { 104 | if status_check_func(&status) { 105 | addr.do_send(retry_msg); 106 | } 107 | } 108 | Err(e) => { 109 | handle_mailbox_error_with_resend( 110 | "schedule_status_check", 111 | e, 112 | &error_recipient, 113 | &stop_recipient, 114 | addr_clone, 115 | msg_clone, 116 | ); 117 | } 118 | } 119 | }; 120 | 121 | actix::Arbiter::current().spawn(status_future); 122 | }); 123 | } 124 | 125 | fn set_packet_status( 126 | tag: &str, 127 | ctx: &mut Context, 128 | status_recipient: &Recipient>, 129 | error_recipient: &Recipient, 130 | stop_recipient: &Recipient, 131 | resend_msg: TMessage, 132 | status_message: StatusOperationMessage, 133 | ) -> bool 134 | where 135 | TActor: Actor> + Handler, 136 | TMessage: Message + Send + 'static, 137 | TMessage::Result: Send, 138 | TActor::Context: ToEnvelope, 139 | TStatusPayload: Send + 'static, 140 | { 141 | if let Err(e) = status_recipient.try_send(status_message) { 142 | let addr = ctx.address(); 143 | handle_send_error_with_resend(tag, e, error_recipient, stop_recipient, addr, resend_msg); 144 | false 145 | } else { 146 | true 147 | } 148 | } 149 | 150 | fn reset_packet_status( 151 | tag: &str, 152 | ctx: &mut Context, 153 | status_recipient: &Recipient>, 154 | error_recipient: &Recipient, 155 | stop_recipient: &Recipient, 156 | id: u16, 157 | resend_msg: TMessage, 158 | ) -> bool 159 | where 160 | TActor: Actor> + Handler, 161 | TMessage: Message + Send + 'static, 162 | TMessage::Result: Send, 163 | TActor::Context: ToEnvelope, 164 | TStatusPayload: Send + 'static, 165 | { 166 | if let Err(e) = status_recipient.try_send(StatusOperationMessage::RemovePacketStatus(id)) { 167 | let addr = ctx.address(); 168 | handle_send_error_with_resend(tag, e, error_recipient, stop_recipient, addr, resend_msg); 169 | false 170 | } else { 171 | true 172 | } 173 | } 174 | 175 | fn send_packet( 176 | tag: &str, 177 | ctx: &Context, 178 | send_recipient: &Recipient, 179 | error_recipient: &Recipient, 180 | stop_recipient: &Recipient, 181 | packet: VariablePacket, 182 | resend_msg: TMessage, 183 | ) -> bool 184 | where 185 | TActor: Actor> + Handler, 186 | TMessage: Message + Send + 'static, 187 | TMessage::Result: Send, 188 | TActor::Context: ToEnvelope, 189 | { 190 | let message = VariablePacketMessage::new(packet, 0); 191 | if let Err(e) = send_recipient.try_send(message) { 192 | let addr = ctx.address(); 193 | handle_send_error_with_resend(tag, e, error_recipient, stop_recipient, addr, resend_msg); 194 | false 195 | } else { 196 | true 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /src/actors/packets/pingreq.rs: -------------------------------------------------------------------------------- 1 | use std::time::Duration; 2 | 3 | use actix::{Actor, Arbiter, AsyncContext, Context, Handler, Message, Recipient}; 4 | use log::{error, trace}; 5 | use mqtt::packet::PingreqPacket; 6 | 7 | use crate::actors::actions::status::{StatusExistenceMessage, StatusOperationMessage}; 8 | use crate::actors::{ErrorMessage, StopMessage}; 9 | 10 | use super::handle_mailbox_error_with_resend; 11 | use super::VariablePacketMessage; 12 | 13 | #[derive(Message)] 14 | #[rtype(result = "()")] 15 | pub struct Pingreq(pub u16); 16 | 17 | #[derive(Message, Clone)] 18 | #[rtype(result = "()")] 19 | struct SendPing(pub u16); 20 | 21 | pub struct PingreqActor { 22 | status_recipient: Recipient>, 23 | connect_status_recipient: Recipient, 24 | send_recipient: Recipient, 25 | error_recipient: Recipient, 26 | stop_recipient: Recipient, 27 | interval: Duration, 28 | } 29 | 30 | impl PingreqActor { 31 | pub fn new( 32 | status_recipient: Recipient>, 33 | connect_status_recipient: Recipient, 34 | send_recipient: Recipient, 35 | error_recipient: Recipient, 36 | stop_recipient: Recipient, 37 | interval: Duration, 38 | ) -> Self { 39 | PingreqActor { 40 | status_recipient, 41 | connect_status_recipient, 42 | send_recipient, 43 | error_recipient, 44 | stop_recipient, 45 | interval, 46 | } 47 | } 48 | } 49 | 50 | impl Actor for PingreqActor { 51 | type Context = Context; 52 | fn started(&mut self, ctx: &mut Self::Context) { 53 | trace!("PingreqActor started"); 54 | ctx.notify(Pingreq(0)); 55 | ctx.run_interval(self.interval.clone(), |_, ctx| { 56 | trace!("Start to send ping"); 57 | ctx.notify(Pingreq(0)); 58 | }); 59 | } 60 | 61 | fn stopped(&mut self, _: &mut Self::Context) { 62 | trace!("PingreqActor stopped"); 63 | } 64 | } 65 | 66 | impl Handler for PingreqActor { 67 | type Result = (); 68 | fn handle(&mut self, msg: Pingreq, ctx: &mut Self::Context) -> Self::Result { 69 | let last_retry_count = msg.0; 70 | assert_valid_retry_count!(PingreqActor, self, last_retry_count, 0); 71 | let status_recipient = self.status_recipient.clone(); 72 | let connect_status_recipient = self.connect_status_recipient.clone(); 73 | let error_recipient = self.error_recipient.clone(); 74 | let stop_recipient = self.stop_recipient.clone(); 75 | let addr = ctx.address(); 76 | let addr_clone = addr.clone(); 77 | let status_future = async move { 78 | // For connect status: 79 | // status message with id = 0 indicating the connecing status 80 | // status message with id = 1 indicating the connected status 81 | let connect_status_result = connect_status_recipient 82 | .send(StatusExistenceMessage(1u16)) 83 | .await; 84 | match connect_status_result { 85 | Ok(false) => { 86 | trace!("Server not connected yet, do nothing."); 87 | return; 88 | } 89 | Err(e) => { 90 | error!("Failed to get connect status: {}", e); 91 | return; 92 | } 93 | _ => { 94 | trace!("Server connected, will send ping"); 95 | } 96 | } 97 | 98 | let status_result = status_recipient 99 | .send(StatusOperationMessage::GetAndRemovePacketStatus(0)) 100 | .await; 101 | match status_result { 102 | Ok(status) => { 103 | if status.is_none() { 104 | // Only try send ping if no previous on-going ping 105 | addr.do_send(SendPing(0)); 106 | } 107 | } 108 | Err(e) => { 109 | handle_mailbox_error_with_resend( 110 | "PingreqActor:status_recipient", 111 | e, 112 | &error_recipient, 113 | &stop_recipient, 114 | addr_clone, 115 | Pingreq(last_retry_count + 1), 116 | ); 117 | } 118 | } 119 | }; 120 | Arbiter::current().spawn(status_future); 121 | } 122 | } 123 | 124 | fn get_retry_count_from_message(msg: &SendPing) -> u16 { 125 | msg.0 126 | } 127 | 128 | fn create_retry_msessage_from_message(msg: SendPing) -> SendPing { 129 | SendPing(msg.0 + 1) 130 | } 131 | 132 | fn create_packet_and_id_from_message(_: &SendPing) -> Option<(PingreqPacket, u16)> { 133 | Some((PingreqPacket::new(), 0)) 134 | } 135 | 136 | impl_send_packet_actor!( 137 | PingreqActor, 138 | SendPing, 139 | PingreqPacket, 140 | get_retry_count_from_message, 141 | create_retry_msessage_from_message, 142 | create_packet_and_id_from_message 143 | ); 144 | -------------------------------------------------------------------------------- /src/actors/packets/pingresp.rs: -------------------------------------------------------------------------------- 1 | fn get_id(_: &mqtt::packet::PingrespPacket) -> u16 { 2 | 0 3 | } 4 | 5 | get_retry_msg_func!( 6 | get_retry_msg_from_msg, 7 | crate::actors::packets::PacketMessage 8 | ); 9 | 10 | define_response_packet_actor!(PingrespActor); 11 | impl_response_packet_actor!( 12 | PingrespActor, 13 | PingrespPacket, 14 | get_id, 15 | get_retry_msg_from_msg 16 | ); 17 | -------------------------------------------------------------------------------- /src/actors/packets/puback.rs: -------------------------------------------------------------------------------- 1 | get_packet_identifier_func!(get_id, mqtt::packet::PubackPacket); 2 | get_retry_msg_func!( 3 | get_retry_msg_from_msg, 4 | crate::actors::packets::PacketMessage 5 | ); 6 | define_response_packet_actor!(PubackActor, crate::actors::packets::PublishPacketStatus); 7 | impl_response_packet_actor!(PubackActor, PubackPacket, get_id, get_retry_msg_from_msg); 8 | -------------------------------------------------------------------------------- /src/actors/packets/pubcomp.rs: -------------------------------------------------------------------------------- 1 | get_packet_identifier_func!(get_id, mqtt::packet::PubcompPacket); 2 | get_retry_msg_func!( 3 | get_retry_msg_from_msg, 4 | crate::actors::packets::PacketMessage 5 | ); 6 | define_response_packet_actor!(PubcompActor, crate::actors::packets::PublishPacketStatus); 7 | impl_response_packet_actor!(PubcompActor, PubcompPacket, get_id, get_retry_msg_from_msg); 8 | -------------------------------------------------------------------------------- /src/actors/packets/publish.rs: -------------------------------------------------------------------------------- 1 | use std::io::ErrorKind; 2 | 3 | use actix::{Addr, Arbiter, AsyncContext, Handler, MailboxError, Message, Recipient}; 4 | use log::{debug, trace}; 5 | use mqtt::packet::{ 6 | PubackPacket, PublishPacket, PubrecPacket, QoSWithPacketIdentifier, VariablePacket, 7 | }; 8 | use mqtt::{QualityOfService, TopicName}; 9 | use tokio::time::{sleep_until, Instant}; 10 | 11 | use crate::actors::actions::status::{PacketStatus, StatusOperationMessage}; 12 | use crate::actors::utils; 13 | use crate::actors::{ 14 | handle_mailbox_error_with_resend, handle_send_error, handle_send_error_with_resend, 15 | ErrorMessage, StopMessage, 16 | }; 17 | use crate::consts::{COMMAND_TIMEOUT, MAILBOX_CAPACITY_FOR_PUBLISH}; 18 | 19 | use super::{ 20 | schedule_status_check, send_error, PacketMessage, PublishMessage, PublishPacketStatus, 21 | VariablePacketMessage, 22 | }; 23 | 24 | #[derive(Message, Clone)] 25 | #[rtype(result = "()")] 26 | pub struct Publish { 27 | topic: String, 28 | qos: QualityOfService, 29 | payload: Vec, 30 | retry_count: u16, 31 | } 32 | 33 | impl Publish { 34 | pub fn new(topic: String, qos: QualityOfService, payload: Vec) -> Self { 35 | Publish { 36 | topic, 37 | qos, 38 | payload, 39 | retry_count: 0, 40 | } 41 | } 42 | } 43 | 44 | fn create_packet_and_id_from_message( 45 | msg: &Publish, 46 | error_recipient: &Recipient, 47 | ) -> Option<(PublishPacket, u16)> { 48 | match TopicName::new(msg.topic.clone()) { 49 | Ok(topic) => { 50 | let id = if msg.qos == QualityOfService::Level0 { 51 | 0 52 | } else { 53 | utils::next_id() 54 | }; 55 | let packet = PublishPacket::new( 56 | topic, 57 | QoSWithPacketIdentifier::new(msg.qos, id), 58 | msg.payload.clone(), 59 | ); 60 | Some((packet, id)) 61 | } 62 | Err(e) => { 63 | send_error( 64 | "create_packet_and_id_from_message", 65 | error_recipient, 66 | ErrorKind::InvalidInput, 67 | format!("Failed to create topic from {}, error: {}", &*msg.topic, e), 68 | ); 69 | None 70 | } 71 | } 72 | } 73 | 74 | pub struct SendPublishActor { 75 | status_recipient: Recipient>, 76 | send_recipient: Recipient, 77 | error_recipient: Recipient, 78 | stop_recipient: Recipient, 79 | } 80 | 81 | impl SendPublishActor { 82 | pub fn new( 83 | status_recipient: Recipient>, 84 | send_recipient: Recipient, 85 | error_recipient: Recipient, 86 | stop_recipient: Recipient, 87 | ) -> Self { 88 | SendPublishActor { 89 | status_recipient, 90 | send_recipient, 91 | error_recipient, 92 | stop_recipient, 93 | } 94 | } 95 | } 96 | 97 | impl_empty_actor!(SendPublishActor, MAILBOX_CAPACITY_FOR_PUBLISH); 98 | impl_stop_handler!(SendPublishActor); 99 | 100 | impl Handler for SendPublishActor { 101 | type Result = (); 102 | fn handle(&mut self, msg: Publish, ctx: &mut Self::Context) -> Self::Result { 103 | trace!("Handle message for SendPublishActor"); 104 | assert_valid_retry_count!(SendPublishActor, self, msg.retry_count, 0); 105 | let packet_and_id_option = create_packet_and_id_from_message(&msg, &self.error_recipient); 106 | if packet_and_id_option.is_none() { 107 | return; 108 | } 109 | 110 | let (packet, id) = packet_and_id_option.unwrap(); 111 | let variable_packet = VariablePacket::PublishPacket(packet); 112 | let variable_message = VariablePacketMessage::new(variable_packet, 0); 113 | 114 | match msg.qos { 115 | QualityOfService::Level0 => { 116 | if let Err(e) = self.send_recipient.try_send(variable_message) { 117 | handle_send_error( 118 | "RecvPublishActor:send_recipient", 119 | e, 120 | &self.error_recipient, 121 | &self.stop_recipient, 122 | ); 123 | return; 124 | } 125 | } 126 | QualityOfService::Level1 => { 127 | let mut resend_msg = msg.clone(); 128 | resend_msg.retry_count += 1; 129 | 130 | if let Err(e) = 131 | self.status_recipient 132 | .try_send(StatusOperationMessage::SetPacketStatus( 133 | id, 134 | PacketStatus { 135 | id, 136 | retry_count: msg.retry_count, 137 | payload: PublishPacketStatus::PendingAck, 138 | }, 139 | )) 140 | { 141 | handle_send_error_with_resend( 142 | "RecvPublishActor:status_recipient", 143 | e, 144 | &self.error_recipient, 145 | &self.stop_recipient, 146 | ctx.address(), 147 | resend_msg, 148 | ); 149 | return; 150 | } 151 | 152 | if let Err(e) = self.send_recipient.try_send(variable_message) { 153 | handle_send_error_with_resend( 154 | "RecvPublishActor:send_recipient", 155 | e, 156 | &self.error_recipient, 157 | &self.stop_recipient, 158 | ctx.address(), 159 | resend_msg, 160 | ); 161 | return; 162 | } 163 | 164 | schedule_status_check( 165 | ctx, 166 | &self.status_recipient, 167 | &self.error_recipient, 168 | &self.stop_recipient, 169 | id, 170 | resend_msg, 171 | |status| status.is_some(), 172 | ); 173 | } 174 | QualityOfService::Level2 => { 175 | let mut resend_msg = msg.clone(); 176 | resend_msg.retry_count += 1; 177 | 178 | if let Err(e) = 179 | self.status_recipient 180 | .try_send(StatusOperationMessage::SetPacketStatus( 181 | id, 182 | PacketStatus { 183 | id, 184 | retry_count: msg.retry_count, 185 | payload: PublishPacketStatus::PendingRec, 186 | }, 187 | )) 188 | { 189 | handle_send_error_with_resend( 190 | "RecvPublishActor:status_recipient", 191 | e, 192 | &self.error_recipient, 193 | &self.stop_recipient, 194 | ctx.address(), 195 | resend_msg, 196 | ); 197 | return; 198 | } 199 | 200 | if let Err(e) = self.send_recipient.try_send(variable_message) { 201 | handle_send_error_with_resend( 202 | "RecvPublishActor:send_recipient", 203 | e, 204 | &self.error_recipient, 205 | &self.stop_recipient, 206 | ctx.address(), 207 | resend_msg, 208 | ); 209 | return; 210 | } 211 | 212 | let addr = ctx.address(); 213 | let addr_clone = addr.clone(); 214 | let msg_clone = resend_msg.clone(); 215 | let error_recipient = self.error_recipient.clone(); 216 | let stop_recipient = self.stop_recipient.clone(); 217 | ctx.run_later(COMMAND_TIMEOUT.clone(), move |actor, _| { 218 | let status_recipient = actor.status_recipient.clone(); 219 | let status_future = async move { 220 | let status_result = status_recipient 221 | .send(StatusOperationMessage::GetAndRemovePacketStatus(id)) 222 | .await; 223 | match status_result { 224 | Ok(status) => { 225 | if let Some(s) = status { 226 | if s.payload == PublishPacketStatus::PendingRec { 227 | addr.do_send(resend_msg); 228 | } 229 | } 230 | } 231 | Err(e) => { 232 | handle_mailbox_error_with_resend( 233 | "SendPublishActor:status_recipient", 234 | e, 235 | &error_recipient, 236 | &stop_recipient, 237 | addr_clone, 238 | msg_clone, 239 | ); 240 | } 241 | } 242 | }; 243 | Arbiter::current().spawn(status_future); 244 | }); 245 | } 246 | } 247 | } 248 | } 249 | 250 | pub struct RecvPublishActor { 251 | status_recipient: Recipient>, 252 | send_recipient: Recipient, 253 | error_recipient: Recipient, 254 | stop_recipient: Recipient, 255 | remote_message_recipient: Recipient, 256 | } 257 | 258 | impl RecvPublishActor { 259 | pub fn new( 260 | status_recipient: Recipient>, 261 | send_recipient: Recipient, 262 | error_recipient: Recipient, 263 | stop_recipient: Recipient, 264 | remote_message_recipient: Recipient, 265 | ) -> Self { 266 | RecvPublishActor { 267 | status_recipient, 268 | send_recipient, 269 | error_recipient, 270 | stop_recipient, 271 | remote_message_recipient, 272 | } 273 | } 274 | 275 | async fn check_status_phase_2( 276 | id: u16, 277 | addr: Addr, 278 | resend_msg: PacketMessage, 279 | status_recipient: Recipient>, 280 | error_recipient: Recipient, 281 | stop_recipient: Recipient, 282 | ) { 283 | let status_result = status_recipient 284 | .send(StatusOperationMessage::GetAndRemovePacketStatus(id)) 285 | .await; 286 | match status_result { 287 | Ok(status) => { 288 | if let Some(s) = status { 289 | if s.payload == PublishPacketStatus::PendingRec { 290 | addr.do_send(resend_msg); 291 | } 292 | } 293 | } 294 | Err(e) => match e { 295 | MailboxError::Closed => { 296 | debug!("Status mailbox is closed, no need for status check phase 2"); 297 | } 298 | _ => { 299 | handle_mailbox_error_with_resend( 300 | "check_status_phase_2", 301 | e, 302 | &error_recipient, 303 | &stop_recipient, 304 | addr, 305 | resend_msg, 306 | ); 307 | } 308 | }, 309 | } 310 | } 311 | 312 | async fn delayed_resend( 313 | id: u16, 314 | addr: Addr, 315 | resend_msg: PacketMessage, 316 | status_recipient: Recipient>, 317 | error_recipient: Recipient, 318 | stop_recipient: Recipient, 319 | ) { 320 | let command_deadline = Instant::now() + COMMAND_TIMEOUT.clone(); 321 | sleep_until(command_deadline).await; 322 | Arbiter::current().spawn(Self::check_status_phase_2( 323 | id, 324 | addr, 325 | resend_msg, 326 | status_recipient, 327 | error_recipient, 328 | stop_recipient, 329 | )); 330 | } 331 | } 332 | 333 | impl_empty_actor!(RecvPublishActor); 334 | impl_stop_handler!(RecvPublishActor); 335 | 336 | impl Handler> for RecvPublishActor { 337 | type Result = (); 338 | fn handle( 339 | &mut self, 340 | msg: PacketMessage, 341 | ctx: &mut Self::Context, 342 | ) -> Self::Result { 343 | trace!("Handle message for RecvPublishActor"); 344 | let packet = &msg.packet; 345 | match packet.qos() { 346 | QoSWithPacketIdentifier::Level0 => { 347 | assert_valid_retry_count!(RecvPublishActor, self, msg.retry_count, 0); 348 | let publish_message = PublishMessage { 349 | id: 0, 350 | topic_name: String::from(packet.topic_name()), 351 | payload: Vec::from(msg.packet.payload()), 352 | }; 353 | if let Err(e) = self 354 | .status_recipient 355 | .do_send(StatusOperationMessage::RemovePacketStatus(0)) 356 | { 357 | handle_send_error( 358 | "RecvPublishActor:status_recipient", 359 | e, 360 | &self.error_recipient, 361 | &self.stop_recipient, 362 | ); 363 | } 364 | 365 | if let Err(e) = self.remote_message_recipient.try_send(publish_message) { 366 | handle_send_error( 367 | "RecvPublishActor:remote_message_recipient", 368 | e, 369 | &self.error_recipient, 370 | &self.stop_recipient, 371 | ); 372 | } 373 | } 374 | QoSWithPacketIdentifier::Level1(id) => { 375 | assert_valid_retry_count!(RecvPublishActor, self, msg.retry_count, id); 376 | let mut resend_msg = msg.clone(); 377 | resend_msg.retry_count += 1; 378 | 379 | let puback_packet = PubackPacket::new(id); 380 | let packet_message = 381 | VariablePacketMessage::new(VariablePacket::PubackPacket(puback_packet), 0); 382 | if let Err(e) = self.send_recipient.try_send(packet_message) { 383 | handle_send_error_with_resend( 384 | "RecvPublishActor:send_recipient", 385 | e, 386 | &self.error_recipient, 387 | &self.stop_recipient, 388 | ctx.address(), 389 | resend_msg, 390 | ); 391 | 392 | return; 393 | } 394 | 395 | let publish_message = PublishMessage { 396 | id, 397 | topic_name: String::from(packet.topic_name()), 398 | payload: Vec::from(msg.packet.payload()), 399 | }; 400 | if let Err(e) = self.remote_message_recipient.try_send(publish_message) { 401 | handle_send_error_with_resend( 402 | "RecvPublishActor:remote_message_recipient", 403 | e, 404 | &self.error_recipient, 405 | &self.stop_recipient, 406 | ctx.address(), 407 | resend_msg, 408 | ); 409 | } 410 | } 411 | QoSWithPacketIdentifier::Level2(id) => { 412 | assert_valid_retry_count!(RecvPublishActor, self, msg.retry_count, id); 413 | let mut resend_msg = msg.clone(); 414 | resend_msg.retry_count += 1; 415 | let addr = ctx.address(); 416 | let addr_clone = addr.clone(); 417 | let msg_clone = resend_msg.clone(); 418 | let status_recipient = self.status_recipient.clone(); 419 | let error_recipient = self.error_recipient.clone(); 420 | let error_recipient_clone = error_recipient.clone(); 421 | let stop_recipient = self.stop_recipient.clone(); 422 | let stop_recipient_clone = stop_recipient.clone(); 423 | let send_recipient = self.send_recipient.clone(); 424 | let remote_message_recipient = self.remote_message_recipient.clone(); 425 | let packet = msg.packet; 426 | let retry_count = msg.retry_count; 427 | let status_future = async move { 428 | let status_result = status_recipient 429 | .send(StatusOperationMessage::GetAndRemovePacketStatus(id)) 430 | .await; 431 | match status_result { 432 | Ok(status) => { 433 | if status.is_none() && retry_count == 0 { 434 | let publish_message = PublishMessage { 435 | id, 436 | topic_name: String::from(packet.topic_name()), 437 | payload: Vec::from(packet.payload()), 438 | }; 439 | if let Err(e) = remote_message_recipient.try_send(publish_message) { 440 | let mut resend_msg_for_publish = resend_msg; 441 | resend_msg_for_publish.retry_count -= 1; 442 | handle_send_error_with_resend( 443 | "RecvPublishActor:remote_message_recipient", 444 | e, 445 | &error_recipient, 446 | &stop_recipient, 447 | addr, 448 | resend_msg_for_publish, 449 | ); 450 | return; 451 | } 452 | } 453 | 454 | if let Err(e) = 455 | status_recipient.try_send(StatusOperationMessage::SetPacketStatus( 456 | id, 457 | PacketStatus { 458 | id, 459 | retry_count, 460 | payload: PublishPacketStatus::PendingRel, 461 | }, 462 | )) 463 | { 464 | handle_send_error_with_resend( 465 | "RecvPublishActor:status_recipient", 466 | e, 467 | &error_recipient, 468 | &stop_recipient, 469 | addr, 470 | resend_msg, 471 | ); 472 | 473 | return; 474 | } 475 | 476 | let pubrec_packet = PubrecPacket::new(id); 477 | let packet_message = VariablePacketMessage::new( 478 | VariablePacket::PubrecPacket(pubrec_packet), 479 | 0, 480 | ); 481 | if let Err(e) = send_recipient.try_send(packet_message) { 482 | handle_send_error_with_resend( 483 | "RecvPublishActor:send_recipient", 484 | e, 485 | &error_recipient, 486 | &stop_recipient, 487 | addr, 488 | resend_msg, 489 | ); 490 | 491 | return; 492 | } 493 | 494 | Arbiter::current().spawn(Self::delayed_resend( 495 | id, 496 | addr, 497 | resend_msg, 498 | status_recipient, 499 | error_recipient, 500 | stop_recipient, 501 | )); 502 | } 503 | Err(e) => { 504 | handle_mailbox_error_with_resend( 505 | "RecvPublishActor:status_recipient", 506 | e, 507 | &error_recipient_clone, 508 | &stop_recipient_clone, 509 | addr_clone, 510 | msg_clone, 511 | ); 512 | } 513 | } 514 | }; 515 | Arbiter::current().spawn(status_future); 516 | } 517 | } 518 | } 519 | } 520 | -------------------------------------------------------------------------------- /src/actors/packets/pubrec.rs: -------------------------------------------------------------------------------- 1 | use mqtt::packet::{PubrecPacket, PubrelPacket}; 2 | 3 | use crate::actors::actions::status::{PacketStatus, StatusOperationMessage}; 4 | use crate::actors::packets::{PacketMessage, PublishPacketStatus}; 5 | 6 | fn get_retry_count_from_message(msg: &PacketMessage) -> u16 { 7 | msg.retry_count 8 | } 9 | 10 | fn create_retry_message_from_message( 11 | msg: PacketMessage, 12 | ) -> PacketMessage { 13 | let mut retry_msg = msg; 14 | retry_msg.retry_count += 1; 15 | retry_msg 16 | } 17 | 18 | fn create_packet_and_id_from_message( 19 | msg: &PacketMessage, 20 | ) -> Option<(PubrelPacket, u16)> { 21 | let id = msg.packet.packet_identifier(); 22 | Some((PubrelPacket::new(id), id)) 23 | } 24 | 25 | define_send_packet_actor!(PubrecActor, PublishPacketStatus); 26 | impl_empty_actor!(PubrecActor); 27 | impl_send_packet_actor!( 28 | PubrecActor, 29 | PacketMessage, 30 | PubrelPacket, 31 | get_retry_count_from_message, 32 | create_retry_message_from_message, 33 | create_packet_and_id_from_message, 34 | |id, retry_count| StatusOperationMessage::SetPacketStatus( 35 | id, 36 | PacketStatus { 37 | id, 38 | retry_count, 39 | payload: PublishPacketStatus::PendingComp 40 | } 41 | ), 42 | |status| { 43 | if let Some(s) = status { 44 | s.payload == PublishPacketStatus::PendingRec 45 | } else { 46 | false 47 | } 48 | } 49 | ); 50 | -------------------------------------------------------------------------------- /src/actors/packets/pubrel.rs: -------------------------------------------------------------------------------- 1 | use mqtt::packet::{PubcompPacket, PubrelPacket}; 2 | 3 | use crate::actors::actions::status::StatusOperationMessage; 4 | use crate::actors::packets::{PacketMessage, PublishPacketStatus}; 5 | 6 | fn get_retry_count_from_message(msg: &PacketMessage) -> u16 { 7 | msg.retry_count 8 | } 9 | 10 | fn create_retry_message_from_message( 11 | msg: PacketMessage, 12 | ) -> PacketMessage { 13 | let mut retry_msg = msg; 14 | retry_msg.retry_count += 1; 15 | retry_msg 16 | } 17 | 18 | fn create_packet_and_id_from_message( 19 | msg: &PacketMessage, 20 | ) -> Option<(PubcompPacket, u16)> { 21 | let id = msg.packet.packet_identifier(); 22 | Some((PubcompPacket::new(id), id)) 23 | } 24 | 25 | define_send_packet_actor!(PubrelActor, PublishPacketStatus); 26 | impl_empty_actor!(PubrelActor); 27 | impl_send_packet_actor!( 28 | PubrelActor, 29 | PacketMessage, 30 | PubcompPacket, 31 | get_retry_count_from_message, 32 | create_retry_message_from_message, 33 | create_packet_and_id_from_message, 34 | |id, _| StatusOperationMessage::RemovePacketStatus(id), 35 | |status| { 36 | if let Some(s) = status { 37 | s.payload == PublishPacketStatus::PendingRel 38 | } else { 39 | false 40 | } 41 | } 42 | ); 43 | -------------------------------------------------------------------------------- /src/actors/packets/suback.rs: -------------------------------------------------------------------------------- 1 | get_packet_identifier_func!(get_id, mqtt::packet::SubackPacket); 2 | get_retry_msg_func!( 3 | get_retry_msg_from_msg, 4 | crate::actors::packets::PacketMessage 5 | ); 6 | define_response_packet_actor!(SubackActor); 7 | impl_response_packet_actor!(SubackActor, SubackPacket, get_id, get_retry_msg_from_msg); 8 | -------------------------------------------------------------------------------- /src/actors/packets/subscribe.rs: -------------------------------------------------------------------------------- 1 | use std::vec::Vec; 2 | 3 | use actix::{AsyncContext, Handler, Message}; 4 | use log::error; 5 | use mqtt::packet::SubscribePacket; 6 | pub use mqtt::{QualityOfService, TopicFilter}; 7 | 8 | use crate::actors::utils; 9 | 10 | #[derive(Message, Clone)] 11 | #[rtype(result = "()")] 12 | pub struct Subscribe { 13 | topic: String, 14 | qos: QualityOfService, 15 | } 16 | 17 | impl Subscribe { 18 | pub fn new(topic: String, qos: QualityOfService) -> Self { 19 | Subscribe { topic, qos } 20 | } 21 | } 22 | 23 | #[derive(Message, Clone)] 24 | #[rtype(result = "()")] 25 | pub struct BatchSubscribe { 26 | subscriptions: Vec, 27 | retry_count: u16, 28 | } 29 | 30 | impl BatchSubscribe { 31 | pub fn new(subscriptions: Vec) -> Self { 32 | BatchSubscribe { 33 | subscriptions, 34 | retry_count: 0, 35 | } 36 | } 37 | } 38 | 39 | fn get_retry_count_from_message(msg: &BatchSubscribe) -> u16 { 40 | msg.retry_count 41 | } 42 | 43 | fn create_retry_message_from_message(msg: BatchSubscribe) -> BatchSubscribe { 44 | let mut retry_msg = msg; 45 | retry_msg.retry_count += 1; 46 | retry_msg 47 | } 48 | 49 | fn create_packet_and_id_from_message(msg: &BatchSubscribe) -> Option<(SubscribePacket, u16)> { 50 | let subscriptions: Vec<(TopicFilter, QualityOfService)> = msg 51 | .subscriptions 52 | .clone() 53 | .into_iter() 54 | .map(|s| (TopicFilter::new(s.topic), s.qos)) 55 | .filter(|(result, _)| match result { 56 | Ok(_) => true, 57 | Err(e) => { 58 | error!("Error pasing topic: {}, ignore", e); 59 | false 60 | } 61 | }) 62 | .map(|(result, qos)| (result.unwrap(), qos)) 63 | .collect(); 64 | if subscriptions.is_empty() { 65 | error!("No valid topic found"); 66 | return None; 67 | } 68 | 69 | let id = utils::next_id(); 70 | let subscribe_packet = SubscribePacket::new(id, subscriptions); 71 | Some((subscribe_packet, id)) 72 | } 73 | 74 | define_send_packet_actor!(SubscribeActor); 75 | impl_empty_actor!(SubscribeActor); 76 | impl_send_packet_actor!( 77 | SubscribeActor, 78 | BatchSubscribe, 79 | SubscribePacket, 80 | get_retry_count_from_message, 81 | create_retry_message_from_message, 82 | create_packet_and_id_from_message 83 | ); 84 | 85 | impl Handler for SubscribeActor { 86 | type Result = (); 87 | fn handle(&mut self, msg: Subscribe, ctx: &mut Self::Context) -> Self::Result { 88 | let batch_msg = BatchSubscribe::new(vec![msg]); 89 | ctx.notify(batch_msg); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/actors/packets/unsuback.rs: -------------------------------------------------------------------------------- 1 | get_packet_identifier_func!(get_id, mqtt::packet::UnsubackPacket); 2 | get_retry_msg_func!( 3 | get_retry_msg_from_msg, 4 | crate::actors::packets::PacketMessage 5 | ); 6 | define_response_packet_actor!(UnsubackActor); 7 | impl_response_packet_actor!( 8 | UnsubackActor, 9 | UnsubackPacket, 10 | get_id, 11 | get_retry_msg_from_msg 12 | ); 13 | -------------------------------------------------------------------------------- /src/actors/packets/unsubscribe.rs: -------------------------------------------------------------------------------- 1 | use actix::{AsyncContext, Handler, Message}; 2 | use log::error; 3 | use mqtt::packet::UnsubscribePacket; 4 | use mqtt::TopicFilter; 5 | 6 | use crate::actors::utils; 7 | 8 | #[derive(Message)] 9 | #[rtype(result = "()")] 10 | pub struct Unsubscribe { 11 | topic: String, 12 | } 13 | 14 | impl Unsubscribe { 15 | pub fn new(topic: String) -> Self { 16 | Unsubscribe { topic } 17 | } 18 | } 19 | 20 | #[derive(Message, Clone)] 21 | #[rtype(result = "()")] 22 | pub struct BatchUnsubscribe { 23 | topics: Vec, 24 | retry_count: u16, 25 | } 26 | 27 | impl BatchUnsubscribe { 28 | pub fn new(topics: Vec) -> Self { 29 | BatchUnsubscribe { 30 | topics, 31 | retry_count: 0, 32 | } 33 | } 34 | } 35 | 36 | fn get_retry_count_from_message(msg: &BatchUnsubscribe) -> u16 { 37 | msg.retry_count 38 | } 39 | 40 | fn create_retry_message_from_message(msg: BatchUnsubscribe) -> BatchUnsubscribe { 41 | let mut retry_msg = msg; 42 | retry_msg.retry_count += 1; 43 | retry_msg 44 | } 45 | 46 | fn create_packet_and_id_from_message(msg: &BatchUnsubscribe) -> Option<(UnsubscribePacket, u16)> { 47 | let subscriptions: Vec = msg 48 | .topics 49 | .clone() 50 | .into_iter() 51 | .map(|s| TopicFilter::new(s)) 52 | .filter(|r| match r { 53 | Ok(_) => true, 54 | Err(e) => { 55 | error!("Failed to parse topic: {}", e); 56 | false 57 | } 58 | }) 59 | .map(|r| r.unwrap()) 60 | .collect(); 61 | if subscriptions.is_empty() { 62 | error!("No valid topic found"); 63 | return None; 64 | } 65 | 66 | let id = utils::next_id(); 67 | let unsubscribe_packet = UnsubscribePacket::new(id, subscriptions); 68 | Some((unsubscribe_packet, id)) 69 | } 70 | 71 | define_send_packet_actor!(UnsubscribeActor); 72 | impl_empty_actor!(UnsubscribeActor); 73 | impl_send_packet_actor!( 74 | UnsubscribeActor, 75 | BatchUnsubscribe, 76 | UnsubscribePacket, 77 | get_retry_count_from_message, 78 | create_retry_message_from_message, 79 | create_packet_and_id_from_message 80 | ); 81 | 82 | impl Handler for UnsubscribeActor { 83 | type Result = (); 84 | fn handle(&mut self, msg: Unsubscribe, ctx: &mut Self::Context) -> Self::Result { 85 | let batch_msg = BatchUnsubscribe::new(vec![msg.topic]); 86 | ctx.notify(batch_msg); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/actors/utils.rs: -------------------------------------------------------------------------------- 1 | use std; 2 | use std::sync::atomic::{AtomicUsize, Ordering}; 3 | 4 | use lazy_static::lazy_static; 5 | use rand; 6 | 7 | lazy_static! { 8 | static ref ID: AtomicUsize = AtomicUsize::new(rand::random()); 9 | } 10 | 11 | static U16_MAX: usize = std::u16::MAX as usize; 12 | 13 | pub fn next_id() -> u16 { 14 | (ID.fetch_add(1, Ordering::SeqCst) % U16_MAX + 1) as u16 15 | } 16 | -------------------------------------------------------------------------------- /src/client.rs: -------------------------------------------------------------------------------- 1 | use std::io::{Error as IoError, ErrorKind, Result as IoResult}; 2 | use std::sync::Arc; 3 | 4 | use actix::{Actor, Addr, MailboxError, Recipient}; 5 | use mqtt::QualityOfService; 6 | use tokio::io::{AsyncRead, AsyncWrite}; 7 | 8 | use crate::actors::actions::dispatch::DispatchActor; 9 | use crate::actors::actions::recv::RecvActor; 10 | use crate::actors::actions::send::SendActor; 11 | use crate::actors::actions::status::{PacketStatusActor, StatusExistenceMessage}; 12 | use crate::actors::actions::stop::{AddStopRecipient, StopActor}; 13 | use crate::actors::packets::connack::ConnackActor; 14 | use crate::actors::packets::connect::{Connect, ConnectActor}; 15 | use crate::actors::packets::disconnect::{Disconnect, DisconnectActor}; 16 | use crate::actors::packets::pingreq::PingreqActor; 17 | use crate::actors::packets::pingresp::PingrespActor; 18 | use crate::actors::packets::puback::PubackActor; 19 | use crate::actors::packets::pubcomp::PubcompActor; 20 | use crate::actors::packets::publish::{Publish, RecvPublishActor, SendPublishActor}; 21 | use crate::actors::packets::pubrec::PubrecActor; 22 | use crate::actors::packets::pubrel::PubrelActor; 23 | use crate::actors::packets::suback::SubackActor; 24 | use crate::actors::packets::subscribe::{Subscribe, SubscribeActor}; 25 | use crate::actors::packets::unsuback::UnsubackActor; 26 | use crate::actors::packets::unsubscribe::{Unsubscribe, UnsubscribeActor}; 27 | use crate::actors::packets::{PublishMessage, PublishPacketStatus}; 28 | use crate::actors::{ErrorMessage, StopMessage}; 29 | use crate::consts::PING_INTERVAL; 30 | 31 | #[inline] 32 | fn map_mailbox_error_to_io_error(e: MailboxError) -> IoError { 33 | IoError::new(ErrorKind::Interrupted, format!("{}", e)) 34 | } 35 | 36 | #[inline] 37 | fn address_not_found_error(name: &str) -> IoError { 38 | IoError::new(ErrorKind::NotFound, format!("{} address not found", name)) 39 | } 40 | 41 | /// The options for setting up MQTT connection 42 | #[derive(Default, Clone)] 43 | pub struct MqttOptions { 44 | /// User name 45 | pub user_name: Option, 46 | /// Password 47 | pub password: Option, 48 | /// Keep alive time(in seconds) 49 | pub keep_alive: Option, 50 | } 51 | 52 | /// The client for connecting to the MQTT server 53 | #[derive(Clone)] 54 | pub struct MqttClient { 55 | conn_addr: Option>, 56 | pub_addr: Option>, 57 | sub_addr: Option>, 58 | unsub_addr: Option>, 59 | stop_addr: Option>, 60 | disconnect_addr: Option>, 61 | conn_status_addr: Option>>, 62 | client_name: Arc, 63 | options: Option, 64 | } 65 | 66 | impl MqttClient { 67 | /// Create a new MQTT client 68 | pub fn new< 69 | TReader: AsyncRead + Send + 'static + Unpin, 70 | TWriter: AsyncWrite + Send + 'static + Unpin, 71 | >( 72 | reader: TReader, 73 | writer: TWriter, 74 | client_name: String, 75 | options: MqttOptions, 76 | message_recipient: Recipient, 77 | error_recipient: Recipient, 78 | stop_recipient: Option>, 79 | ) -> Self { 80 | let mut client = MqttClient { 81 | conn_addr: None, 82 | pub_addr: None, 83 | sub_addr: None, 84 | unsub_addr: None, 85 | stop_addr: None, 86 | disconnect_addr: None, 87 | conn_status_addr: None, 88 | client_name: Arc::new(client_name), 89 | options: Some(options), 90 | }; 91 | client.start_actors( 92 | reader, 93 | writer, 94 | message_recipient, 95 | error_recipient, 96 | stop_recipient, 97 | ); 98 | client 99 | } 100 | 101 | /// Returns the name of the client 102 | pub fn name(&self) -> &str { 103 | &*self.client_name 104 | } 105 | 106 | /// Perform the connect operation to the remote MQTT server 107 | /// 108 | /// Note: This function can only be called once for each client, calling it the second time will return an error 109 | /// Note: The successful return of this function *DOES NOT* mean that the MQTT connection is successful, if anything wrong happens the error actor will receive an error 110 | /// Note: Please use is_connected() to check whether the MQTT connection is successful or not 111 | pub async fn connect(&mut self) -> Result<(), IoError> { 112 | if let (Some(connect_addr), Some(mut options)) = 113 | (self.conn_addr.take(), self.options.take()) 114 | { 115 | connect_addr 116 | .send(Connect { 117 | user_name: options.user_name.take(), 118 | password: options.password.take(), 119 | keep_alive: options.keep_alive.take(), 120 | }) 121 | .await 122 | .map_err(map_mailbox_error_to_io_error) 123 | } else { 124 | Err(IoError::new(ErrorKind::AlreadyExists, "Already connected")) 125 | } 126 | } 127 | 128 | /// Check whether the client has connected to the server successfully 129 | pub async fn is_connected(&self) -> IoResult { 130 | match self.conn_status_addr { 131 | Some(ref addr) => { 132 | let connected = addr 133 | .send(StatusExistenceMessage(1)) 134 | .await 135 | .map_err(|e| { 136 | log::error!("Failed to get connection status: {}", e); 137 | IoError::new(ErrorKind::NotConnected, "Failed to connect to server") 138 | })?; 139 | Ok(connected) 140 | } 141 | None => Ok(false), 142 | } 143 | } 144 | 145 | /// Subscribe to the server with a topic and QoS 146 | pub async fn subscribe(&self, topic: String, qos: QualityOfService) -> Result<(), IoError> { 147 | if let Some(ref sub_addr) = self.sub_addr { 148 | sub_addr 149 | .send(Subscribe::new(topic, qos)) 150 | .await 151 | .map_err(map_mailbox_error_to_io_error) 152 | } else { 153 | Err(address_not_found_error("subscribe")) 154 | } 155 | } 156 | 157 | /// Unsubscribe from the server 158 | pub async fn unsubscribe(&self, topic: String) -> Result<(), IoError> { 159 | if let Some(ref unsub_addr) = self.unsub_addr { 160 | unsub_addr 161 | .send(Unsubscribe::new(topic)) 162 | .await 163 | .map_err(map_mailbox_error_to_io_error) 164 | } else { 165 | Err(address_not_found_error("unsubscribe")) 166 | } 167 | } 168 | 169 | /// Publish a message 170 | pub async fn publish( 171 | &self, 172 | topic: String, 173 | qos: QualityOfService, 174 | payload: Vec, 175 | ) -> Result<(), IoError> { 176 | if let Some(ref pub_addr) = self.pub_addr { 177 | pub_addr 178 | .send(Publish::new(topic, qos, payload)) 179 | .await 180 | .map_err(map_mailbox_error_to_io_error) 181 | } else { 182 | Err(address_not_found_error("publish")) 183 | } 184 | } 185 | 186 | /// Disconnect from the server 187 | pub async fn disconnect(&mut self, force: bool) -> Result<(), IoError> { 188 | if let Some(ref disconnect_addr) = self.disconnect_addr { 189 | let result = disconnect_addr 190 | .send(Disconnect { force }) 191 | .await 192 | .map_err(map_mailbox_error_to_io_error); 193 | self.clear_all_addrs(force); 194 | result 195 | } else { 196 | Err(address_not_found_error("disconnect")) 197 | } 198 | } 199 | 200 | /// Check if the client has been disconnected from the server, useful to check whether disconnection is completed 201 | pub fn is_disconnected(&self) -> bool { 202 | if let Some(ref disconnect_addr) = self.disconnect_addr { 203 | !disconnect_addr.connected() 204 | } else { 205 | true 206 | } 207 | } 208 | 209 | /// Set all addrs to None to prevent further operations 210 | fn clear_all_addrs(&mut self, include_disconnect: bool) { 211 | self.pub_addr = None; 212 | self.sub_addr = None; 213 | self.unsub_addr = None; 214 | self.conn_addr = None; 215 | self.conn_status_addr = None; 216 | 217 | if include_disconnect { 218 | self.disconnect_addr = None; 219 | } 220 | } 221 | 222 | fn start_actors< 223 | TReader: AsyncRead + Send + 'static + Unpin, 224 | TWriter: AsyncWrite + Send + 'static + Unpin, 225 | >( 226 | &mut self, 227 | reader: TReader, 228 | writer: TWriter, 229 | publish_message_recipient: Recipient, 230 | error_recipient: Recipient, 231 | client_stop_recipient_option: Option>, 232 | ) { 233 | let stop_addr = StopActor::new().start(); 234 | 235 | if let Some(client_stop_recipient) = client_stop_recipient_option { 236 | let _ = stop_addr.do_send(AddStopRecipient(client_stop_recipient)); 237 | } 238 | 239 | let stop_recipient = stop_addr.clone().recipient(); 240 | let stop_recipient_container = stop_addr.clone().recipient(); 241 | 242 | let send_addr = 243 | SendActor::new(writer, error_recipient.clone(), stop_recipient.clone()).start(); 244 | let send_recipient = send_addr.clone().recipient(); 245 | let _ = stop_addr.do_send(AddStopRecipient(send_addr.recipient())); 246 | 247 | let disconnect_actor_addr = DisconnectActor::new( 248 | send_recipient.clone(), 249 | error_recipient.clone(), 250 | stop_recipient.clone(), 251 | ) 252 | .start(); 253 | 254 | macro_rules! start_response_actor { 255 | ($addr_name:ident, $actor_name:ident, $status_recipient:ident) => { 256 | let $addr_name = $actor_name::new( 257 | $status_recipient.clone(), 258 | error_recipient.clone(), 259 | stop_recipient.clone(), 260 | ) 261 | .start(); 262 | let _ = stop_recipient_container 263 | .do_send(AddStopRecipient($addr_name.clone().recipient())); 264 | }; 265 | } 266 | 267 | macro_rules! start_send_actor { 268 | ($addr_name:ident, $actor_name:ident, $status_recipient:ident) => { 269 | let $addr_name = $actor_name::new( 270 | $status_recipient.clone(), 271 | send_recipient.clone(), 272 | error_recipient.clone(), 273 | stop_recipient.clone(), 274 | ) 275 | .start(); 276 | let _ = stop_recipient_container 277 | .do_send(AddStopRecipient($addr_name.clone().recipient())); 278 | }; 279 | } 280 | 281 | macro_rules! start_status_actor { 282 | ($name:ident, $status_name:tt, $payload_type:ty, $send_status_recipient:expr) => { 283 | let status_addr = 284 | PacketStatusActor::<$payload_type>::new($status_name, $send_status_recipient) 285 | .start(); 286 | let $name = status_addr.clone().recipient(); 287 | let _ = stop_recipient_container.do_send(AddStopRecipient(status_addr.recipient())); 288 | }; 289 | } 290 | 291 | let send_status_recipient = disconnect_actor_addr.clone().recipient(); 292 | start_status_actor!( 293 | publish_status_recipient, 294 | "Disconnect", 295 | PublishPacketStatus, 296 | Some(send_status_recipient) 297 | ); 298 | 299 | start_send_actor!( 300 | send_pub_actor_addr, 301 | SendPublishActor, 302 | publish_status_recipient 303 | ); 304 | let recv_pub_actor_addr = RecvPublishActor::new( 305 | publish_status_recipient.clone(), 306 | send_recipient.clone(), 307 | error_recipient.clone(), 308 | stop_recipient.clone(), 309 | publish_message_recipient, 310 | ) 311 | .start(); 312 | let _ = stop_recipient_container 313 | .do_send(AddStopRecipient(recv_pub_actor_addr.clone().recipient())); 314 | start_response_actor!(puback_actor_addr, PubackActor, publish_status_recipient); 315 | start_send_actor!(pubrec_actor_addr, PubrecActor, publish_status_recipient); 316 | start_send_actor!(pubrel_actor_addr, PubrelActor, publish_status_recipient); 317 | start_response_actor!(pubcomp_actor_addr, PubcompActor, publish_status_recipient); 318 | 319 | start_status_actor!(subscribe_status_recipient, "Subscribe", (), None); 320 | start_send_actor!( 321 | subscribe_actor_addr, 322 | SubscribeActor, 323 | subscribe_status_recipient 324 | ); 325 | start_response_actor!(suback_actor_addr, SubackActor, subscribe_status_recipient); 326 | 327 | start_status_actor!(unsubscribe_status_recipient, "Unsubscribe", (), None); 328 | start_send_actor!( 329 | unsubscribe_actor_addr, 330 | UnsubscribeActor, 331 | unsubscribe_status_recipient 332 | ); 333 | start_response_actor!( 334 | unsuback_actor_addr, 335 | UnsubackActor, 336 | unsubscribe_status_recipient 337 | ); 338 | 339 | let connect_status_actor_addr = PacketStatusActor::new("Connect", None).start(); 340 | let connect_actor_addr = ConnectActor::new( 341 | send_recipient.clone(), 342 | connect_status_actor_addr.clone().recipient(), 343 | stop_recipient.clone(), 344 | error_recipient.clone(), 345 | (&*self.client_name).clone(), 346 | ) 347 | .start(); 348 | 349 | let connack_actor_addr = ConnackActor::new( 350 | connect_status_actor_addr.clone().recipient(), 351 | error_recipient.clone(), 352 | connect_actor_addr.clone().recipient(), 353 | stop_recipient.clone(), 354 | ) 355 | .start(); 356 | 357 | start_status_actor!(ping_status_recipient, "Ping", (), None); 358 | let send_ping_actor_addr = PingreqActor::new( 359 | ping_status_recipient.clone(), 360 | connect_status_actor_addr.clone().recipient(), 361 | send_recipient.clone(), 362 | error_recipient.clone(), 363 | stop_recipient.clone(), 364 | PING_INTERVAL.clone(), 365 | ) 366 | .start(); 367 | let _ = stop_recipient_container 368 | .do_send(AddStopRecipient(send_ping_actor_addr.clone().recipient())); 369 | start_response_actor!(pingresp_actor_addr, PingrespActor, ping_status_recipient); 370 | 371 | let dispatch_actor_addr = DispatchActor::new( 372 | error_recipient.clone(), 373 | stop_recipient.clone(), 374 | connack_actor_addr.recipient(), 375 | pingresp_actor_addr.recipient(), 376 | recv_pub_actor_addr.recipient(), 377 | puback_actor_addr.recipient(), 378 | pubrec_actor_addr.recipient(), 379 | pubrel_actor_addr.recipient(), 380 | pubcomp_actor_addr.recipient(), 381 | suback_actor_addr.recipient(), 382 | unsuback_actor_addr.recipient(), 383 | ) 384 | .start(); 385 | let recv_addr = RecvActor::new( 386 | reader, 387 | dispatch_actor_addr.clone().recipient(), 388 | error_recipient, 389 | stop_recipient, 390 | ) 391 | .start(); 392 | let _ = stop_addr.do_send(AddStopRecipient(recv_addr.recipient())); 393 | 394 | self.sub_addr = Some(subscribe_actor_addr); 395 | self.unsub_addr = Some(unsubscribe_actor_addr); 396 | self.pub_addr = Some(send_pub_actor_addr); 397 | self.disconnect_addr = Some(disconnect_actor_addr); 398 | self.conn_addr = Some(connect_actor_addr); 399 | self.stop_addr = Some(stop_addr); 400 | self.conn_status_addr = Some(connect_status_actor_addr); 401 | } 402 | } 403 | -------------------------------------------------------------------------------- /src/consts.rs: -------------------------------------------------------------------------------- 1 | use std::time::Duration; 2 | 3 | use lazy_static::lazy_static; 4 | 5 | pub const MAX_RETRY_COUNT: u16 = 5; 6 | pub const DEFAULT_MAILBOX_CAPACITY: usize = 64; 7 | pub const MAILBOX_CAPACITY_FOR_PUBLISH: usize = 256; 8 | 9 | lazy_static! { 10 | pub static ref COMMAND_TIMEOUT: Duration = Duration::new(5, 0); 11 | pub static ref DELAY_BEFORE_SHUTDOWN: Duration = Duration::new(5, 0); 12 | pub static ref RESEND_DELAY: Duration = Duration::new(1, 0); 13 | pub static ref PING_INTERVAL: Duration = Duration::new(10, 0); 14 | } 15 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! # A MQTT client based on actix framework 2 | //! 3 | //! The `actix-mqtt-client` crate is a mqtt client based on the [actix](https://github.com/actix/actix) framework 4 | //! 5 | //! ## Basic usage and example 6 | //! 7 | //! First, create 2 actix actors, one for receiving publish messages, the other one for receiving error messages from the client, you can also create an optional actix actor for receiving the stop message: 8 | //! ```rust 9 | //! pub struct ErrorActor; 10 | //! 11 | //! impl actix::Actor for ErrorActor { 12 | //! type Context = actix::Context; 13 | //! } 14 | //! 15 | //! impl actix::Handler for ErrorActor { 16 | //! type Result = (); 17 | //! fn handle(&mut self, error: ErrorMessage, _: &mut Self::Context) -> Self::Result { 18 | //! log::error!("{}", error.0); 19 | //! } 20 | //! } 21 | //! 22 | //! pub struct MessageActor; 23 | //! 24 | //! impl actix::Actor for MessageActor { 25 | //! type Context = actix::Context; 26 | //! } 27 | //! 28 | //! impl actix::Handler for MessageActor { 29 | //! type Result = (); 30 | //! fn handle( 31 | //! &mut self, 32 | //! msg: PublishMessage, 33 | //! _: &mut Self::Context, 34 | //! ) -> Self::Result { 35 | //! log::info!( 36 | //! "Got message: id:{}, topic: {}, payload: {:?}", 37 | //! msg.id, 38 | //! msg.topic_name, 39 | //! msg.payload 40 | //! ); 41 | //! } 42 | //! } 43 | //! ``` 44 | //! 45 | //! Then, connect to the server(using tokio) and use the read and write part of the stream along with the actors to create a [MqttClient](struct.MqttClient.html): 46 | //! ```rust 47 | //! use std::io::Error as IoError; 48 | //! use std::net::SocketAddr; 49 | //! use std::str::FromStr; 50 | //! use std::time::Duration; 51 | //! use actix::{Actor, Arbiter, System}; 52 | //! use env_logger; 53 | //! use tokio::io::split; 54 | //! use tokio::net::TcpStream; 55 | //! use tokio::time::{sleep_until, Instant}; 56 | //! use actix_mqtt_client::client::{MqttClient, MqttOptions}; 57 | //! 58 | //! let sys = System::new(); 59 | //! let socket_addr = SocketAddr::from_str("127.0.0.1:1883").unwrap(); 60 | //! sys.block_on(async move { 61 | //! let result = async move { 62 | //! let stream = TcpStream::connect(socket_addr).await?; 63 | //! let (r, w) = split(stream); 64 | //! log::info!("TCP connected"); 65 | //! let mut client = MqttClient::new( 66 | //! r, 67 | //! w, 68 | //! String::from("test"), 69 | //! MqttOptions::default(), 70 | //! MessageActor.start().recipient(), 71 | //! ErrorActor.start().recipient(), 72 | //! None, 73 | //! ); 74 | //! client.connect().await?; 75 | //! // Waiting for the client to be connected 76 | //! while !client.is_connected().await? { 77 | //! let delay_time = Instant::now() + Duration::new(1, 0); 78 | //! sleep_until(delay_time).await; 79 | //! } 80 | //! log::info!("MQTT connected"); 81 | //! log::info!("Subscribe"); 82 | //! client 83 | //! .subscribe(String::from("test"), mqtt::QualityOfService::Level2) 84 | //! .await?; 85 | //! log::info!("Publish"); 86 | //! client 87 | //! .publish( 88 | //! String::from("test"), 89 | //! mqtt::QualityOfService::Level0, 90 | //! Vec::from("test".as_bytes()), 91 | //! ) 92 | //! .await?; 93 | //! log::info!("Wait for 10s"); 94 | //! let delay_time = Instant::now() + Duration::new(10, 0); 95 | //! sleep_until(delay_time).await; 96 | //! client 97 | //! .publish( 98 | //! String::from("test"), 99 | //! mqtt::QualityOfService::Level1, 100 | //! Vec::from("test2".as_bytes()), 101 | //! ) 102 | //! .await?; 103 | //! log::info!("Wait for 10s"); 104 | //! let delay_time = Instant::now() + Duration::new(10, 0); 105 | //! sleep_until(delay_time).await; 106 | //! client 107 | //! .publish( 108 | //! String::from("test"), 109 | //! mqtt::QualityOfService::Level2, 110 | //! Vec::from("test3".as_bytes()), 111 | //! ) 112 | //! .await?; 113 | //! log::info!("Wait for 10s"); 114 | //! let delay_time = Instant::now() + Duration::new(10, 0); 115 | //! sleep_until(delay_time).await; 116 | //! log::info!("Disconnect"); 117 | //! client.disconnect(false).await?; 118 | //! log::info!("Check if disconnect is successful"); 119 | //! Ok(assert_eq!(true, client.is_disconnected())) as Result<(), IoError> 120 | //! } 121 | //! .await; 122 | //! result.unwrap() 123 | //! }); 124 | //! sys.run().unwrap(); 125 | //! ``` 126 | 127 | mod actors; 128 | mod client; 129 | mod consts; 130 | 131 | pub use actix; 132 | pub use futures; 133 | pub use mqtt::QualityOfService; 134 | pub use tokio; 135 | 136 | pub use crate::actors::packets::PublishMessage; 137 | pub use crate::actors::{ErrorMessage, StopMessage}; 138 | pub use crate::client::{MqttClient, MqttOptions}; 139 | 140 | #[cfg(test)] 141 | mod tests { 142 | pub struct ErrorActor; 143 | 144 | impl actix::Actor for ErrorActor { 145 | type Context = actix::Context; 146 | } 147 | 148 | impl actix::Handler for ErrorActor { 149 | type Result = (); 150 | fn handle(&mut self, error: super::ErrorMessage, _: &mut Self::Context) -> Self::Result { 151 | log::error!("{}", error.0); 152 | } 153 | } 154 | 155 | pub struct MessageActor; 156 | 157 | impl actix::Actor for MessageActor { 158 | type Context = actix::Context; 159 | } 160 | 161 | impl actix::Handler for MessageActor { 162 | type Result = (); 163 | fn handle( 164 | &mut self, 165 | msg: crate::actors::packets::PublishMessage, 166 | _: &mut Self::Context, 167 | ) -> Self::Result { 168 | log::info!( 169 | "Got message: id:{}, topic: {}, payload: {:?}", 170 | msg.id, 171 | msg.topic_name, 172 | msg.payload 173 | ); 174 | } 175 | } 176 | 177 | #[test] 178 | fn test_client() { 179 | use std::io::Error as IoError; 180 | use std::net::SocketAddr; 181 | use std::str::FromStr; 182 | use std::time::Duration; 183 | 184 | use actix::{Actor, System}; 185 | use env_logger; 186 | use tokio::io::split; 187 | use tokio::net::TcpStream; 188 | use tokio::time::{sleep_until, Instant}; 189 | 190 | use crate::client::{MqttClient, MqttOptions}; 191 | 192 | env_logger::init(); 193 | 194 | let sys = System::new(); 195 | let socket_addr = SocketAddr::from_str("127.0.0.1:1883").unwrap(); 196 | sys.block_on(async move { 197 | let result = async move { 198 | let stream = TcpStream::connect(socket_addr).await?; 199 | let (r, w) = split(stream); 200 | log::info!("TCP connected"); 201 | let mut client = MqttClient::new( 202 | r, 203 | w, 204 | String::from("test"), 205 | MqttOptions::default(), 206 | MessageActor.start().recipient(), 207 | ErrorActor.start().recipient(), 208 | None, 209 | ); 210 | client.connect().await?; 211 | while !client.is_connected().await.unwrap() { 212 | log::info!("Waiting for client to be connected"); 213 | let delay_time = Instant::now() + Duration::new(0, 100); 214 | sleep_until(delay_time).await; 215 | } 216 | 217 | log::info!("MQTT connected"); 218 | log::info!("Subscribe"); 219 | client 220 | .subscribe(String::from("test"), mqtt::QualityOfService::Level2) 221 | .await?; 222 | log::info!("Publish"); 223 | client 224 | .publish( 225 | String::from("test"), 226 | mqtt::QualityOfService::Level0, 227 | Vec::from("test".as_bytes()), 228 | ) 229 | .await?; 230 | log::info!("Wait for 1s"); 231 | let delay_time = Instant::now() + Duration::new(1, 0); 232 | sleep_until(delay_time).await; 233 | client 234 | .publish( 235 | String::from("test"), 236 | mqtt::QualityOfService::Level1, 237 | Vec::from("test2".as_bytes()), 238 | ) 239 | .await?; 240 | log::info!("Wait for 1s"); 241 | let delay_time = Instant::now() + Duration::new(1, 0); 242 | sleep_until(delay_time).await; 243 | client 244 | .publish( 245 | String::from("test"), 246 | mqtt::QualityOfService::Level2, 247 | Vec::from("test3".as_bytes()), 248 | ) 249 | .await?; 250 | log::info!("Wait for 1s"); 251 | let delay_time = Instant::now() + Duration::new(1, 0); 252 | sleep_until(delay_time).await; 253 | log::info!("Disconnect"); 254 | client.disconnect(false).await?; 255 | log::info!("Check if disconnect is successful"); 256 | for _ in (0 as i32)..5 { 257 | if client.is_disconnected() { 258 | break; 259 | } 260 | 261 | let delay_time = Instant::now() + Duration::new(0, 200); 262 | sleep_until(delay_time).await; 263 | } 264 | 265 | Ok(assert_eq!(true, client.is_disconnected())) as Result<(), IoError> 266 | } 267 | .await; 268 | let r = result.unwrap(); 269 | System::current().stop(); 270 | r 271 | }); 272 | sys.run().unwrap(); 273 | } 274 | } 275 | 276 | #[cfg(test)] 277 | mod random_test { 278 | use tokio::sync::mpsc::{channel, Sender}; 279 | 280 | pub struct ErrorActor; 281 | 282 | impl actix::Actor for ErrorActor { 283 | type Context = actix::Context; 284 | } 285 | 286 | impl actix::Handler for ErrorActor { 287 | type Result = (); 288 | fn handle(&mut self, error: super::ErrorMessage, _: &mut Self::Context) -> Self::Result { 289 | log::error!("{}", error.0); 290 | } 291 | } 292 | 293 | pub struct MessageActor(Sender<(bool, Vec)>); 294 | 295 | impl actix::Actor for MessageActor { 296 | type Context = actix::Context; 297 | } 298 | 299 | impl actix::Handler for MessageActor { 300 | type Result = (); 301 | fn handle( 302 | &mut self, 303 | msg: crate::actors::packets::PublishMessage, 304 | _: &mut Self::Context, 305 | ) -> Self::Result { 306 | log::info!( 307 | "Got message: id:{}, topic: {}, payload: {:?}", 308 | msg.id, 309 | msg.topic_name, 310 | msg.payload 311 | ); 312 | 313 | self.0.try_send((false, msg.payload)).unwrap(); 314 | } 315 | } 316 | 317 | lazy_static::lazy_static! { 318 | static ref PACKETS: std::sync::Mutex>> = std::sync::Mutex::new(std::collections::HashSet::new()); 319 | } 320 | 321 | #[test] 322 | fn test_random_publish_level0_cloned_client() { 323 | use std::io::Error as IoError; 324 | use std::net::SocketAddr; 325 | use std::str::FromStr; 326 | use std::time::Duration; 327 | 328 | use actix::{Actor, Arbiter, System}; 329 | use env_logger; 330 | use futures::stream::StreamExt; 331 | use tokio::io::split; 332 | use tokio::net::TcpStream; 333 | use tokio::time::{sleep_until, Instant}; 334 | use tokio_stream::wrappers::ReceiverStream; 335 | 336 | use crate::client::{MqttClient, MqttOptions}; 337 | 338 | env_logger::init(); 339 | 340 | let (sender, recv) = channel(100); 341 | let sys = System::new(); 342 | let socket_addr = SocketAddr::from_str("127.0.0.1:1883").unwrap(); 343 | 344 | sys.block_on(async move { 345 | let future = async move { 346 | let result = async move { 347 | let stream = TcpStream::connect(socket_addr).await?; 348 | let (r, w) = split(stream); 349 | let mut client = MqttClient::new( 350 | r, 351 | w, 352 | String::from("test"), 353 | MqttOptions::default(), 354 | MessageActor(sender.clone()).start().recipient(), 355 | ErrorActor.start().recipient(), 356 | None, 357 | ); 358 | client.connect().await?; 359 | while !client.is_connected().await.unwrap() { 360 | log::info!("Waiting for client to be connected"); 361 | let delay_time = Instant::now() + Duration::new(0, 100); 362 | sleep_until(delay_time).await; 363 | } 364 | 365 | log::info!("Connected"); 366 | log::info!("Subscribe"); 367 | client 368 | .subscribe(String::from("test"), mqtt::QualityOfService::Level0) 369 | .await?; 370 | async fn random_send( 371 | client_id: i32, 372 | client: MqttClient, 373 | sender: Sender<(bool, Vec)>, 374 | ) { 375 | let mut count: i32 = 0; 376 | loop { 377 | count += 1; 378 | use rand::RngCore; 379 | let mut data = [0u8; 32]; 380 | rand::thread_rng().fill_bytes(&mut data); 381 | let payload = Vec::from(&data[..]); 382 | log::info!("[{}:{}] Publish {:?}", client_id, count, payload); 383 | sleep_until(Instant::now() + Duration::from_millis(100)).await; 384 | sender.try_send((true, payload.clone())).unwrap(); 385 | client 386 | .publish( 387 | String::from("test"), 388 | mqtt::QualityOfService::Level0, 389 | payload, 390 | ) 391 | .await 392 | .unwrap(); 393 | } 394 | } 395 | 396 | for i in 0..5 { 397 | let client_clone = client.clone(); 398 | let sender_clone = sender.clone(); 399 | let future = random_send(i, client_clone, sender_clone); 400 | Arbiter::current().spawn(future); 401 | } 402 | 403 | Ok(()) as Result<(), IoError> 404 | } 405 | .await; 406 | result.unwrap(); 407 | }; 408 | 409 | Arbiter::current().spawn(future); 410 | let recv_future = async { 411 | let result = async { 412 | ReceiverStream::new(recv) 413 | .fold((), |_, (is_send, payload)| async move { 414 | let mut p = PACKETS.lock().unwrap(); 415 | if is_send { 416 | p.insert(payload); 417 | } else if p.contains(&payload) { 418 | p.remove(&payload); 419 | } 420 | 421 | log::info!("Pending recv items: {}", p.len()); 422 | 423 | () 424 | }) 425 | .await; 426 | Ok(()) as Result<(), IoError> 427 | } 428 | .await; 429 | result.unwrap() 430 | }; 431 | Arbiter::current().spawn(recv_future); 432 | }); 433 | sys.run().unwrap(); 434 | } 435 | 436 | #[test] 437 | fn test_random_publish_level0_created_client() { 438 | use std::io::Error as IoError; 439 | use std::net::SocketAddr; 440 | use std::str::FromStr; 441 | use std::time::Duration; 442 | 443 | use actix::{Actor, Arbiter, System}; 444 | use env_logger; 445 | use futures::stream::StreamExt; 446 | use tokio::io::split; 447 | use tokio::net::TcpStream; 448 | use tokio::time::{sleep_until, Instant}; 449 | use tokio_stream::wrappers::ReceiverStream; 450 | 451 | use crate::client::{MqttClient, MqttOptions}; 452 | 453 | env_logger::init(); 454 | 455 | async fn test_send(client_id: i32, sender: Sender<(bool, Vec)>) { 456 | let socket_addr = SocketAddr::from_str("127.0.0.1:1883").unwrap(); 457 | async move { 458 | let stream = TcpStream::connect(socket_addr).await?; 459 | let (r, w) = split(stream); 460 | let mut client = MqttClient::new( 461 | r, 462 | w, 463 | format!("test_{}", client_id), 464 | MqttOptions::default(), 465 | MessageActor(sender.clone()).start().recipient(), 466 | ErrorActor.start().recipient(), 467 | None, 468 | ); 469 | client.connect().await?; 470 | while !client.is_connected().await.unwrap() { 471 | log::info!("Waiting for client to be connected"); 472 | let delay_time = Instant::now() + Duration::new(0, 100); 473 | sleep_until(delay_time).await; 474 | } 475 | log::info!("Connected"); 476 | log::info!("Subscribe"); 477 | client 478 | .subscribe(String::from("test"), mqtt::QualityOfService::Level0) 479 | .await?; 480 | async fn random_send( 481 | client_id: i32, 482 | client: MqttClient, 483 | sender: Sender<(bool, Vec)>, 484 | ) { 485 | let mut count: i32 = 0; 486 | loop { 487 | count += 1; 488 | use rand::RngCore; 489 | let mut data = [0u8; 32]; 490 | rand::thread_rng().fill_bytes(&mut data); 491 | let payload = Vec::from(&data[..]); 492 | log::info!("[{}:{}] Publish {:?}", client_id, count, payload); 493 | sleep_until(Instant::now() + Duration::from_millis(100)).await; 494 | sender.try_send((true, payload.clone())).unwrap(); 495 | client 496 | .publish( 497 | String::from("test"), 498 | mqtt::QualityOfService::Level0, 499 | payload, 500 | ) 501 | .await 502 | .unwrap(); 503 | } 504 | } 505 | 506 | let future = random_send(client_id, client, sender); 507 | Arbiter::current().spawn(future); 508 | 509 | Ok(()) as Result<(), IoError> 510 | } 511 | .await 512 | .unwrap(); 513 | } 514 | 515 | let sys = System::new(); 516 | sys.block_on(async move { 517 | let (sender, recv) = channel(100); 518 | for i in 0..5 { 519 | let future = test_send(i, sender.clone()); 520 | Arbiter::current().spawn(future); 521 | } 522 | 523 | let recv_future = async { 524 | let result = async { 525 | ReceiverStream::new(recv) 526 | .fold((), |_, (is_send, payload)| async move { 527 | let mut p = PACKETS.lock().unwrap(); 528 | if is_send { 529 | p.insert(payload); 530 | } else if p.contains(&payload) { 531 | p.remove(&payload); 532 | } 533 | 534 | log::info!("Pending recv items: {}", p.len()); 535 | 536 | () 537 | }) 538 | .await; 539 | Ok(()) as Result<(), IoError> 540 | } 541 | .await; 542 | result.unwrap() 543 | }; 544 | Arbiter::current().spawn(recv_future); 545 | }); 546 | sys.run().unwrap(); 547 | } 548 | 549 | #[test] 550 | fn test_random_publish_level2() { 551 | use std::io::Error as IoError; 552 | use std::net::SocketAddr; 553 | use std::str::FromStr; 554 | use std::time::Duration; 555 | 556 | use actix::{Actor, Arbiter, System}; 557 | use env_logger; 558 | use futures::stream::StreamExt; 559 | use tokio::io::split; 560 | use tokio::net::TcpStream; 561 | use tokio::time::{sleep_until, Instant}; 562 | use tokio_stream::wrappers::ReceiverStream; 563 | 564 | use crate::client::{MqttClient, MqttOptions}; 565 | 566 | env_logger::init(); 567 | 568 | let (sender, recv) = channel(100); 569 | let sender_clone = sender.clone(); 570 | 571 | let sys = System::new(); 572 | sys.block_on(async move { 573 | let socket_addr = SocketAddr::from_str("127.0.0.1:1883").unwrap(); 574 | let future = async move { 575 | let result = async move { 576 | let stream = TcpStream::connect(socket_addr).await?; 577 | let (r, w) = split(stream); 578 | let mut client = MqttClient::new( 579 | r, 580 | w, 581 | String::from("test"), 582 | MqttOptions::default(), 583 | MessageActor(sender).start().recipient(), 584 | ErrorActor.start().recipient(), 585 | None, 586 | ); 587 | client.connect().await?; 588 | while !client.is_connected().await.unwrap() { 589 | log::info!("Waiting for client to be connected"); 590 | let delay_time = Instant::now() + Duration::new(0, 100); 591 | sleep_until(delay_time).await; 592 | } 593 | log::info!("Connected"); 594 | log::info!("Subscribe"); 595 | client 596 | .subscribe(String::from("test"), mqtt::QualityOfService::Level2) 597 | .await?; 598 | futures::stream::repeat(()) 599 | .fold((client, sender_clone), |(client, sender), _| async { 600 | use rand::RngCore; 601 | let mut data = [0u8; 32]; 602 | rand::thread_rng().fill_bytes(&mut data); 603 | let payload = Vec::from(&data[..]); 604 | log::info!("Publish {:?}", payload); 605 | sleep_until(Instant::now() + Duration::from_millis(10)).await; 606 | sender.try_send((true, payload.clone())).unwrap(); 607 | client 608 | .publish( 609 | String::from("test"), 610 | mqtt::QualityOfService::Level2, 611 | payload, 612 | ) 613 | .await 614 | .unwrap(); 615 | (client, sender) 616 | }) 617 | .await; 618 | Ok(()) as Result<(), IoError> 619 | } 620 | .await; 621 | result.unwrap() 622 | }; 623 | Arbiter::current().spawn(future); 624 | let recv_future = async { 625 | let result = async { 626 | ReceiverStream::new(recv) 627 | .fold((), |_, (is_send, payload)| async move { 628 | let mut p = PACKETS.lock().unwrap(); 629 | if is_send { 630 | p.insert(payload); 631 | } else if !p.contains(&payload) { 632 | panic!("Multiple receive for level 2: {:?}", payload); 633 | } else { 634 | p.remove(&payload); 635 | } 636 | 637 | log::info!("Pending recv items: {}", p.len()); 638 | 639 | () 640 | }) 641 | .await; 642 | Ok(()) as Result<(), IoError> 643 | } 644 | .await; 645 | result.unwrap() 646 | }; 647 | Arbiter::current().spawn(recv_future); 648 | }); 649 | sys.run().unwrap(); 650 | } 651 | } 652 | --------------------------------------------------------------------------------