11package org .dromara .mica .mqtt .broker .cluster ;
22
3- import org .dromara .mica .mqtt .broker .cluster .message .ClusterMessage ;
4- import org .dromara .mica .mqtt .broker .cluster .message .GenericClusterMessage ;
5- import org .dromara .mica .mqtt .broker .cluster .message .StateSyncResponseMessage ;
3+ import org .dromara .mica .mqtt .broker .cluster .message .*;
4+ import org .dromara .mica .mqtt .codec .MqttQoS ;
65import org .dromara .mica .mqtt .core .server .MqttServer ;
76import org .dromara .mica .mqtt .core .server .model .Subscribe ;
87import org .slf4j .Logger ;
1211import org .tio .server .cluster .core .ClusterConfig ;
1312import org .tio .server .cluster .core .ClusterImpl ;
1413import org .tio .server .cluster .message .ClusterDataMessage ;
14+
1515import java .io .*;
16- import java .util .Collection ;
17- import java .util .HashMap ;
18- import java .util .List ;
19- import java .util .Map ;
16+ import java .util .*;
2017
2118public class MqttClusterManager {
2219 private static final Logger logger = LoggerFactory .getLogger (MqttClusterManager .class );
@@ -78,7 +75,7 @@ private void requestStateSync() {
7875 if (!nodeToString (seed ).equals (localNodeId )) {
7976 try {
8077 GenericClusterMessage syncRequest = new GenericClusterMessage ();
81- syncRequest .setType (org . dromara . mica . mqtt . broker . cluster . message . MessageType .STATE_SYNC_REQUEST );
78+ syncRequest .setType (MessageType .STATE_SYNC_REQUEST );
8279 syncRequest .setSourceNode (localNodeId );
8380 cluster .send (seed , serialize (syncRequest ));
8481 logger .info ("Sent state sync request to seed node: {}" , seed );
@@ -109,33 +106,28 @@ private void handleClusterMessage(ClusterDataMessage message) {
109106 private void handleClusterMessageInternal (ClusterMessage clusterMsg , ClusterDataMessage rawMessage ) {
110107 ClusterMqttSessionManager sessionManager = (ClusterMqttSessionManager ) mqttServer .getServerCreator ().getSessionManager ();
111108
112- if (clusterMsg .getType () == org .dromara .mica .mqtt .broker .cluster .message .MessageType .PUBLISH_FORWARD ) {
113- org .dromara .mica .mqtt .broker .cluster .message .PublishForwardMessage pfm =
114- (org .dromara .mica .mqtt .broker .cluster .message .PublishForwardMessage ) clusterMsg ;
115- mqttServer .publishAll (pfm .getTopic (), pfm .getPayload (), org .dromara .mica .mqtt .codec .MqttQoS .valueOf (pfm .getQos ()), pfm .isRetain ());
116- } else if (clusterMsg .getType () == org .dromara .mica .mqtt .broker .cluster .message .MessageType .SUBSCRIBE_NOTIFY ) {
117- org .dromara .mica .mqtt .broker .cluster .message .SubscribeNotifyMessage snm =
118- (org .dromara .mica .mqtt .broker .cluster .message .SubscribeNotifyMessage ) clusterMsg ;
109+ if (clusterMsg .getType () == MessageType .PUBLISH_FORWARD ) {
110+ PublishForwardMessage pfm = (PublishForwardMessage ) clusterMsg ;
111+ mqttServer .publishAll (pfm .getTopic (), pfm .getPayload (), MqttQoS .valueOf (pfm .getQos ()), pfm .isRetain ());
112+ } else if (clusterMsg .getType () == MessageType .SUBSCRIBE_NOTIFY ) {
113+ SubscribeNotifyMessage snm = (SubscribeNotifyMessage ) clusterMsg ;
119114 sessionManager .syncRemoteSubscriptions (snm .getClientId (), snm .getNodeId (), snm .getSubscriptions ());
120- } else if (clusterMsg .getType () == org .dromara .mica .mqtt .broker .cluster .message .MessageType .UNSUBSCRIBE_NOTIFY ) {
121- org .dromara .mica .mqtt .broker .cluster .message .UnsubscribeNotifyMessage unm =
122- (org .dromara .mica .mqtt .broker .cluster .message .UnsubscribeNotifyMessage ) clusterMsg ;
115+ } else if (clusterMsg .getType () == MessageType .UNSUBSCRIBE_NOTIFY ) {
116+ UnsubscribeNotifyMessage unm = (UnsubscribeNotifyMessage ) clusterMsg ;
123117 sessionManager .removeRemoteSubscriptions (unm .getClientId (), unm .getTopics ());
124- } else if (clusterMsg .getType () == org .dromara .mica .mqtt .broker .cluster .message .MessageType .CLIENT_CONNECT ) {
125- org .dromara .mica .mqtt .broker .cluster .message .ClientConnectMessage ccm =
126- (org .dromara .mica .mqtt .broker .cluster .message .ClientConnectMessage ) clusterMsg ;
118+ } else if (clusterMsg .getType () == MessageType .CLIENT_CONNECT ) {
119+ ClientConnectMessage ccm = (ClientConnectMessage ) clusterMsg ;
127120 sessionManager .registerRemoteClient (ccm .getClientId (), ccm .getSourceNode ());
128- } else if (clusterMsg .getType () == org .dromara .mica .mqtt .broker .cluster .message .MessageType .CLIENT_DISCONNECT ) {
129- org .dromara .mica .mqtt .broker .cluster .message .ClientDisconnectMessage cdm =
130- (org .dromara .mica .mqtt .broker .cluster .message .ClientDisconnectMessage ) clusterMsg ;
121+ } else if (clusterMsg .getType () == MessageType .CLIENT_DISCONNECT ) {
122+ ClientDisconnectMessage cdm = (ClientDisconnectMessage ) clusterMsg ;
131123 sessionManager .removeRemoteClient (cdm .getClientId ());
132- } else if (clusterMsg .getType () == org . dromara . mica . mqtt . broker . cluster . message . MessageType .STATE_SYNC_REQUEST ) {
124+ } else if (clusterMsg .getType () == MessageType .STATE_SYNC_REQUEST ) {
133125 handleStateSyncRequest (clusterMsg .getSourceNode ());
134- } else if (clusterMsg .getType () == org . dromara . mica . mqtt . broker . cluster . message . MessageType .STATE_SYNC_RESPONSE ) {
126+ } else if (clusterMsg .getType () == MessageType .STATE_SYNC_RESPONSE ) {
135127 StateSyncResponseMessage ssm = (StateSyncResponseMessage ) clusterMsg ;
136128 sessionManager .syncFullState (ssm .getClientNodeMap (), ssm .getSubscriptionMap ());
137129 logger .info ("State sync completed, received {} client mappings" , ssm .getClientNodeMap ().size ());
138- } else if (clusterMsg .getType () == org . dromara . mica . mqtt . broker . cluster . message . MessageType .NODE_LEAVE ) {
130+ } else if (clusterMsg .getType () == MessageType .NODE_LEAVE ) {
139131 // 节点离开消息,需要清理该节点的所有订阅
140132 String leavingNodeId = clusterMsg .getSourceNode ();
141133 sessionManager .clearNodeClientsAndSubscriptions (leavingNodeId );
@@ -150,7 +142,7 @@ private void handleStateSyncRequest(String requestNodeId) {
150142 ClusterMqttSessionManager sessionManager = (ClusterMqttSessionManager ) mqttServer .getServerCreator ().getSessionManager ();
151143
152144 StateSyncResponseMessage response = new StateSyncResponseMessage ();
153- response .setType (org . dromara . mica . mqtt . broker . cluster . message . MessageType .STATE_SYNC_RESPONSE );
145+ response .setType (MessageType .STATE_SYNC_RESPONSE );
154146 response .setSourceNode (localNodeId );
155147
156148 // 获取远程客户端映射
@@ -214,7 +206,7 @@ public void stop() {
214206 if (cluster != null ) {
215207 // 广播节点离开消息
216208 GenericClusterMessage leaveMsg = new GenericClusterMessage ();
217- leaveMsg .setType (org . dromara . mica . mqtt . broker . cluster . message . MessageType .NODE_LEAVE );
209+ leaveMsg .setType (MessageType .NODE_LEAVE );
218210 leaveMsg .setSourceNode (localNodeId );
219211 broadcast (leaveMsg );
220212
@@ -229,9 +221,55 @@ public void stop() {
229221 }
230222 }
231223
224+ /**
225+ * 集群级别的下发消息:发布消息到集群中的所有匹配订阅者
226+ *
227+ * @param topic 主题
228+ * @param payload 消息体
229+ * @param qos QoS
230+ * @param retain 是否保留消息
231+ */
232+ public void publish (String topic , byte [] payload , int qos , boolean retain ) {
233+ if (mqttServer == null ) {
234+ return ;
235+ }
236+
237+ // 1. 先在本地节点下发
238+ mqttServer .publishAll (topic , payload , MqttQoS .valueOf (qos ), retain );
239+
240+ // 2. 查找是否有其他节点存在该 topic 的订阅者,按需转发以节省网络开销
241+ if (config .isEnabled () && cluster != null ) {
242+ ClusterMqttSessionManager sessionManager = (ClusterMqttSessionManager ) mqttServer .getServerCreator ().getSessionManager ();
243+ List <Subscribe > allSubs = sessionManager .searchAllSubscribe (topic );
244+
245+ if (allSubs != null && !allSubs .isEmpty ()) {
246+ Set <String > targetNodes = new HashSet <>();
247+ for (Subscribe sub : allSubs ) {
248+ String node = sessionManager .getClientNode (sub .getClientId ());
249+ if (node != null && !node .equals (localNodeId )) {
250+ targetNodes .add (node );
251+ }
252+ }
253+
254+ if (!targetNodes .isEmpty ()) {
255+ PublishForwardMessage clusterMsg = new PublishForwardMessage ();
256+ clusterMsg .setType (MessageType .PUBLISH_FORWARD );
257+ clusterMsg .setTopic (topic );
258+ clusterMsg .setPayload (payload );
259+ clusterMsg .setQos (qos );
260+ clusterMsg .setRetain (retain );
261+
262+ for (String node : targetNodes ) {
263+ sendToNode (node , clusterMsg );
264+ }
265+ }
266+ }
267+ }
268+ }
269+
232270 public Collection <Node > getRemoteMembers () {
233271 if (cluster == null ) {
234- return java . util . Collections .emptyList ();
272+ return Collections .emptyList ();
235273 }
236274 return cluster .getRemoteMembers ();
237275 }
0 commit comments