@@ -113,10 +113,10 @@ public function __construct(
113
113
* If no custom settings are passed, the client will use the default settings.
114
114
* See {@see ConnectionSettings} for more details about the defaults.
115
115
*
116
- * @param string|null $username
117
- * @param string|null $password
118
- * @param ConnectionSettings $settings
119
- * @param bool $sendCleanSessionFlag
116
+ * @param string|null $username
117
+ * @param string|null $password
118
+ * @param ConnectionSettings|null $settings
119
+ * @param bool $sendCleanSessionFlag
120
120
* @return void
121
121
* @throws ConnectingToBrokerFailedException
122
122
*/
@@ -469,6 +469,24 @@ protected function publishMessage(
469
469
/**
470
470
* Subscribe to the given topic with the given quality of service.
471
471
*
472
+ * The subscription callback is passed the topic as first and the message as second
473
+ * parameter. A third parameter indicates whether the received message has been sent
474
+ * because it was retained by the broker.
475
+ *
476
+ * Example:
477
+ * ```php
478
+ * $mqtt->subscribe(
479
+ * '/foo/bar/+',
480
+ * function (string $topic, string $message, bool $retained) use ($logger) {
481
+ * $logger->info("Received {retained} message on topic [{topic}]: {message}", [
482
+ * 'topic' => $topic,
483
+ * 'message' => $message,
484
+ * 'retained' => $retained ? 'retained' : 'live'
485
+ * ]);
486
+ * }
487
+ * );
488
+ * ```
489
+ *
472
490
* @param string $topic
473
491
* @param callable $callback
474
492
* @param int $qualityOfService
@@ -598,6 +616,7 @@ public function loop(bool $allowSleep = true, bool $exitWhenQueuesEmpty = false,
598
616
// Read the first byte of a message (command and flags).
599
617
$ command = (int )(ord ($ byte ) / 16 );
600
618
$ qualityOfService = (ord ($ byte ) & 0x06 ) >> 1 ;
619
+ $ retained = (bool ) (ord ($ byte ) & 0x01 );
601
620
602
621
// Read the second byte of a message (remaining length)
603
622
// If the continuation bit (8) is set on the length byte,
@@ -621,7 +640,7 @@ public function loop(bool $allowSleep = true, bool $exitWhenQueuesEmpty = false,
621
640
case 2 :
622
641
throw new UnexpectedAcknowledgementException (self ::EXCEPTION_ACK_CONNECT , 'We unexpectedly received a connection acknowledgement. ' );
623
642
case 3 :
624
- $ this ->handlePublishedMessage ($ buffer , $ qualityOfService );
643
+ $ this ->handlePublishedMessage ($ buffer , $ qualityOfService, $ retained );
625
644
break ;
626
645
case 4 :
627
646
$ this ->handlePublishAcknowledgement ($ buffer );
@@ -722,10 +741,11 @@ protected function allQueuesAreEmpty(): bool
722
741
*
723
742
* @param string $buffer
724
743
* @param int $qualityOfServiceLevel
744
+ * @param bool $retained
725
745
* @return void
726
746
* @throws DataTransferException
727
747
*/
728
- protected function handlePublishedMessage (string $ buffer , int $ qualityOfServiceLevel ): void
748
+ protected function handlePublishedMessage (string $ buffer , int $ qualityOfServiceLevel, bool $ retained = false ): void
729
749
{
730
750
$ topicLength = (ord ($ buffer [0 ]) << 8 ) + ord ($ buffer [1 ]);
731
751
$ topic = substr ($ buffer , 2 , $ topicLength );
@@ -762,7 +782,7 @@ protected function handlePublishedMessage(string $buffer, int $qualityOfServiceL
762
782
}
763
783
}
764
784
765
- $ this ->deliverPublishedMessage ($ topic , $ message , $ qualityOfServiceLevel );
785
+ $ this ->deliverPublishedMessage ($ topic , $ message , $ qualityOfServiceLevel, $ retained );
766
786
}
767
787
768
788
/**
@@ -1061,9 +1081,10 @@ protected function handlePingAcknowledgement(): void
1061
1081
* @param string $topic
1062
1082
* @param string $message
1063
1083
* @param int $qualityOfServiceLevel
1084
+ * @param bool $retained
1064
1085
* @return void
1065
1086
*/
1066
- protected function deliverPublishedMessage (string $ topic , string $ message , int $ qualityOfServiceLevel ): void
1087
+ protected function deliverPublishedMessage (string $ topic , string $ message , int $ qualityOfServiceLevel, bool $ retained = false ): void
1067
1088
{
1068
1089
$ subscribers = $ this ->repository ->getTopicSubscriptionsMatchingTopic ($ topic );
1069
1090
@@ -1082,7 +1103,7 @@ protected function deliverPublishedMessage(string $topic, string $message, int $
1082
1103
}
1083
1104
1084
1105
try {
1085
- call_user_func ($ subscriber ->getCallback (), $ topic , $ message );
1106
+ call_user_func ($ subscriber ->getCallback (), $ topic , $ message, $ retained );
1086
1107
} catch (\Throwable $ e ) {
1087
1108
// We ignore errors produced by custom callbacks.
1088
1109
}
@@ -1300,7 +1321,7 @@ protected function writeToSocket(string $data, int $length = null): void
1300
1321
]);
1301
1322
throw new DataTransferException (self ::EXCEPTION_TX_DATA , 'Sending data over the socket failed. Has it been closed? ' );
1302
1323
}
1303
-
1324
+
1304
1325
// After writing successfully to the socket, the broker should have received a new message from us.
1305
1326
// Because we only need to send a ping if no other messages are delivered, we can safely reset the ping timer.
1306
1327
$ this ->lastPingAt = microtime (true );
0 commit comments