@@ -2,32 +2,34 @@ use crate::protocol::packet::{PublishPacket, QoS};
22use crate :: protocol:: v3:: subscribe_return_codes:: { FAILURE , MAXIMUM_QOS_0 } ;
33use crate :: protocol:: Packet ;
44use crate :: session:: Mailbox ;
5+ use crate :: storage:: { PersistedRetainedMessage , Storage , StoredQoS } ;
6+ use chrono:: Utc ;
57use std:: collections:: { HashMap , HashSet } ;
8+ use std:: sync:: Arc ;
69use tokio:: sync:: RwLock ;
7- use tracing:: info;
10+ use tracing:: { info, warn } ;
811
912struct RouterInternal {
1013 // FILTER -> (SESSION_ID -> (SENDER, QoS))
1114 filters : HashMap < String , HashMap < String , ( Mailbox , QoS ) > > ,
1215 // SESSION_ID -> FILTER
1316 sessions : HashMap < String , HashSet < String > > ,
14- // TOPIC -> RETAINED MESSAGE
15- retained_messages : HashMap < String , PublishPacket > ,
1617}
1718
1819pub struct Router {
1920 data : RwLock < RouterInternal > ,
21+ storage : Arc < dyn Storage > ,
2022 retained_message_limit : usize ,
2123}
2224
2325impl Router {
24- pub fn new ( retained_message_limit : usize ) -> Self {
26+ pub fn new ( retained_message_limit : usize , storage : Arc < dyn Storage > ) -> Self {
2527 Self {
2628 data : RwLock :: new ( RouterInternal {
2729 filters : HashMap :: new ( ) ,
2830 sessions : HashMap :: new ( ) ,
29- retained_messages : HashMap :: new ( ) ,
3031 } ) ,
32+ storage,
3133 retained_message_limit,
3234 }
3335 }
@@ -93,6 +95,15 @@ impl Router {
9395 let mut return_codes = Vec :: new ( ) ;
9496 let mut retained_to_send = Vec :: new ( ) ;
9597
98+ // Load all retained messages from storage
99+ let retained_messages = match self . storage . load_all_retained_messages ( ) {
100+ Ok ( msgs) => msgs,
101+ Err ( e) => {
102+ warn ! ( "Failed to load retained messages: {}" , e) ;
103+ Vec :: new ( )
104+ }
105+ } ;
106+
96107 {
97108 let mut router = self . data . write ( ) . await ;
98109
@@ -130,10 +141,11 @@ impl Router {
130141 ) ;
131142
132143 // Find retained messages matching this subscription
133- for ( topic, retained_packet) in router. retained_messages . iter ( ) {
134- if Self :: topic_matches ( topic, & filter. 0 ) {
144+ for retained in & retained_messages {
145+ if Self :: topic_matches ( & retained. topic , & filter. 0 ) {
146+ let retained_qos = QoS :: from ( retained. qos ) ;
135147 // Apply QoS downgrade for retained messages too
136- let effective_qos = match ( retained_packet . qos , filter. 1 ) {
148+ let effective_qos = match ( retained_qos , filter. 1 ) {
137149 ( QoS :: AtMostOnce , _) => QoS :: AtMostOnce ,
138150 ( _, QoS :: AtMostOnce ) => QoS :: AtMostOnce ,
139151 ( QoS :: AtLeastOnce , QoS :: AtLeastOnce ) => QoS :: AtLeastOnce ,
@@ -142,13 +154,19 @@ impl Router {
142154 ( QoS :: ExactlyOnce , QoS :: ExactlyOnce ) => QoS :: AtLeastOnce , // We don't support QoS=2 yet
143155 } ;
144156
145- let mut packet = retained_packet. clone ( ) ;
146- // Retained messages should be sent with retain flag set to true
147- packet. retain = true ;
148- packet. qos = effective_qos;
157+ let packet = PublishPacket {
158+ topic : retained. topic . clone ( ) ,
159+ packet_id : None ,
160+ payload : retained. payload . clone ( ) ,
161+ qos : effective_qos,
162+ retain : true ,
163+ dup : false ,
164+ } ;
149165 retained_to_send. push ( packet) ;
150- info ! ( "Found retained message for topic {} matching filter {}, downgraded QoS from {:?} to {:?}" ,
151- topic, filter. 0 , retained_packet. qos, effective_qos) ;
166+ info ! (
167+ "Found retained message for topic {} matching filter {}, QoS {:?} -> {:?}" ,
168+ retained. topic, filter. 0 , retained_qos, effective_qos
169+ ) ;
152170 }
153171 }
154172 }
@@ -214,39 +232,49 @@ impl Router {
214232
215233 // Handle retained message storage
216234 if packet. retain {
217- let mut router = self . data . write ( ) . await ;
218-
219235 if packet. payload . is_empty ( ) {
220236 // Empty payload with retain=true means delete the retained message
221- router. retained_messages . remove ( & packet. topic ) ;
222- info ! ( "Deleted retained message for topic: {}" , packet. topic) ;
237+ if let Err ( e) = self . storage . delete_retained_message ( & packet. topic ) {
238+ warn ! (
239+ "Failed to delete retained message for {}: {}" ,
240+ packet. topic, e
241+ ) ;
242+ } else {
243+ info ! ( "Deleted retained message for topic: {}" , packet. topic) ;
244+ }
223245 } else {
224246 // Check if we're at the limit and this is a new topic
225- if !router. retained_messages . contains_key ( & packet. topic )
226- && router. retained_messages . len ( ) >= self . retained_message_limit
227- {
247+ let existing = self . storage . load_retained_message ( & packet. topic ) ;
248+ let count = self . storage . count_retained_messages ( ) . unwrap_or ( 0 ) ;
249+
250+ let is_new = matches ! ( existing, Ok ( None ) ) ;
251+ if is_new && count >= self . retained_message_limit {
228252 info ! (
229253 "Retained message limit reached ({}/{}), dropping message for topic: {}" ,
230- router. retained_messages. len( ) ,
231- self . retained_message_limit,
232- packet. topic
254+ count, self . retained_message_limit, packet. topic
233255 ) ;
234256 } else {
235257 // Store the retained message
236- router
237- . retained_messages
238- . insert ( packet. topic . clone ( ) , packet. clone ( ) ) ;
239- info ! (
240- "Stored retained message for topic: {} (total: {}/{})" ,
241- packet. topic,
242- router. retained_messages. len( ) ,
243- self . retained_message_limit
244- ) ;
258+ let retained = PersistedRetainedMessage {
259+ topic : packet. topic . clone ( ) ,
260+ payload : packet. payload . clone ( ) ,
261+ qos : StoredQoS :: from ( packet. qos ) ,
262+ updated_at : Utc :: now ( ) ,
263+ } ;
264+ if let Err ( e) = self . storage . save_retained_message ( & retained) {
265+ warn ! (
266+ "Failed to save retained message for {}: {}" ,
267+ packet. topic, e
268+ ) ;
269+ } else {
270+ let new_count = self . storage . count_retained_messages ( ) . unwrap_or ( 0 ) ;
271+ info ! (
272+ "Stored retained message for topic: {} (total: {}/{})" ,
273+ packet. topic, new_count, self . retained_message_limit
274+ ) ;
275+ }
245276 }
246277 }
247-
248- // Continue to route to current subscribers
249- drop ( router) ;
250278 }
251279
252280 // Route to current subscribers
0 commit comments