Added unsubscribe management for server side
This commit is contained in:
@@ -29,4 +29,10 @@ public interface IMessaging {
|
||||
void removeSubscriptions(String clientID);
|
||||
|
||||
void close();
|
||||
|
||||
/**
|
||||
* Remove the clientID from topic subscription, if not previously subscribed,
|
||||
* doesn't reply any error
|
||||
*/
|
||||
void unsubscribe(String topic, String clientID);
|
||||
}
|
||||
|
||||
+25
-12
@@ -119,20 +119,33 @@ public class SimpleMessaging implements IMessaging {
|
||||
public void subscribe(String clientId, String topic, QOSType qos) {
|
||||
Subscription newSubscription = new Subscription(clientId, topic, qos);
|
||||
rwLock.writeLock().lock();
|
||||
subscriptions.add(newSubscription);
|
||||
|
||||
//scans reatained messages to be published to the new subscription
|
||||
LOG.debug("Scanning all retained messages...");
|
||||
for (Map.Entry<String, StoredMessage> entry : m_retainedStore) {
|
||||
StoredMessage storedMsg = entry.getValue();
|
||||
if (matchTopics(entry.getKey(), topic)) {
|
||||
//fire the as retained the message
|
||||
m_notifier.notify(newSubscription.clientId, topic, storedMsg.getQos(),
|
||||
storedMsg.getPayload(), true);
|
||||
try {
|
||||
subscriptions.add(newSubscription);
|
||||
|
||||
//scans retained messages to be published to the new subscription
|
||||
LOG.debug("Scanning all retained messages...");
|
||||
for (Map.Entry<String, StoredMessage> entry : m_retainedStore) {
|
||||
StoredMessage storedMsg = entry.getValue();
|
||||
if (matchTopics(entry.getKey(), topic)) {
|
||||
//fire the as retained the message
|
||||
m_notifier.notify(newSubscription.clientId, topic, storedMsg.getQos(),
|
||||
storedMsg.getPayload(), true);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
LOG.debug("Finished firing retained messages");
|
||||
rwLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void unsubscribe(String topic, String clientID) {
|
||||
rwLock.writeLock().lock();
|
||||
try {
|
||||
subscriptions.removeSubscription(topic, clientID);
|
||||
} finally {
|
||||
rwLock.writeLock().unlock();
|
||||
}
|
||||
LOG.debug("Finished firing retained messages");
|
||||
rwLock.writeLock().unlock();
|
||||
}
|
||||
|
||||
|
||||
|
||||
+49
-2
@@ -217,12 +217,42 @@ public class SubscriptionsStore {
|
||||
}
|
||||
|
||||
protected void addDirect(Subscription newSubscription) {
|
||||
// List<Token> tokens = new ArrayList<Token>();
|
||||
// try {
|
||||
// tokens = splitTopic(newSubscription.topic);
|
||||
// } catch (ParseException ex) {
|
||||
// //TODO handle the parse exception
|
||||
// LOG.error(null, ex);
|
||||
//// return;
|
||||
// }
|
||||
//
|
||||
// TreeNode current = subscriptions;
|
||||
// for (Token token : tokens) {
|
||||
// TreeNode matchingChildren;
|
||||
//
|
||||
// //check if a children with the same token already exists
|
||||
// if ((matchingChildren = current.childWithToken(token)) != null) {
|
||||
// current = matchingChildren;
|
||||
// } else {
|
||||
// //create a new node for the newly inserted token
|
||||
// matchingChildren = new TreeNode(current);
|
||||
// matchingChildren.setToken(token);
|
||||
// current.addChild(matchingChildren);
|
||||
// current = matchingChildren;
|
||||
// }
|
||||
// }
|
||||
TreeNode current = findMatchingNode(newSubscription.topic);
|
||||
current.addSubcription(newSubscription);
|
||||
}
|
||||
|
||||
private TreeNode findMatchingNode(String topic) {
|
||||
List<Token> tokens = new ArrayList<Token>();
|
||||
try {
|
||||
tokens = splitTopic(newSubscription.topic);
|
||||
tokens = splitTopic(topic);
|
||||
} catch (ParseException ex) {
|
||||
//TODO handle the parse exception
|
||||
LOG.error(null, ex);
|
||||
// return;
|
||||
}
|
||||
|
||||
TreeNode current = subscriptions;
|
||||
@@ -240,7 +270,7 @@ public class SubscriptionsStore {
|
||||
current = matchingChildren;
|
||||
}
|
||||
}
|
||||
current.addSubcription(newSubscription);
|
||||
return current;
|
||||
}
|
||||
|
||||
public void add(Subscription newSubscription) {
|
||||
@@ -257,6 +287,23 @@ public class SubscriptionsStore {
|
||||
m_persistent.put(clientID, subs);
|
||||
// pageFile.flush();
|
||||
}
|
||||
|
||||
public void removeSubscription(String topic, String clientID) {
|
||||
TreeNode matchNode = findMatchingNode(topic);
|
||||
|
||||
//search fr the subscription to remove
|
||||
Subscription toBeRemoved = null;
|
||||
for (Subscription sub : matchNode.subscriptions()) {
|
||||
if (sub.topic.equals(topic)) {
|
||||
toBeRemoved = sub;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (toBeRemoved != null) {
|
||||
matchNode.subscriptions().remove(toBeRemoved);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visit the topics tree to remove matching subscriptions with clientID
|
||||
|
||||
@@ -19,6 +19,8 @@ import org.dna.mqtt.moquette.proto.messages.PingRespMessage;
|
||||
import org.dna.mqtt.moquette.proto.messages.PublishMessage;
|
||||
import org.dna.mqtt.moquette.proto.messages.SubAckMessage;
|
||||
import org.dna.mqtt.moquette.proto.messages.SubscribeMessage;
|
||||
import org.dna.mqtt.moquette.proto.messages.UnsubAckMessage;
|
||||
import org.dna.mqtt.moquette.proto.messages.UnsubscribeMessage;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -50,6 +52,9 @@ public class MQTTHandler extends IoHandlerAdapter implements INotifier {
|
||||
case SUBSCRIBE:
|
||||
handleSubscribe(session, (SubscribeMessage) msg);
|
||||
break;
|
||||
case UNSUBSCRIBE:
|
||||
handleUnsubscribe(session, (UnsubscribeMessage) msg);
|
||||
break;
|
||||
case PUBLISH:
|
||||
handlePublish(session, (PublishMessage) msg);
|
||||
break;
|
||||
@@ -164,6 +169,19 @@ public class MQTTHandler extends IoHandlerAdapter implements INotifier {
|
||||
LOG.info("replying with SubAct to MSG ID {0}", msg.getMessageID());
|
||||
session.write(ackMessage);
|
||||
}
|
||||
|
||||
private void handleUnsubscribe(IoSession session, UnsubscribeMessage msg) {
|
||||
LOG.info("unregistering the subscriptions");
|
||||
for (String topic : msg.topics()) {
|
||||
m_messaging.unsubscribe(topic, (String) session.getAttribute(ATTR_CLIENTID));
|
||||
}
|
||||
//ack the client
|
||||
UnsubAckMessage ackMessage = new UnsubAckMessage();
|
||||
ackMessage.setMessageID(msg.getMessageID());
|
||||
|
||||
LOG.info("replying with UnsubAct to MSG ID {0}", msg.getMessageID());
|
||||
session.write(ackMessage);
|
||||
}
|
||||
|
||||
protected void handlePublish(IoSession session, PublishMessage message) {
|
||||
m_messaging.publish(message.getTopicName(), message.getPayload(),
|
||||
@@ -205,6 +223,8 @@ public class MQTTHandler extends IoHandlerAdapter implements INotifier {
|
||||
pubMessage.setTopicName(topic);
|
||||
pubMessage.setQos(qOSType);
|
||||
pubMessage.setPayload(payload);
|
||||
assert m_clientIDs != null;
|
||||
assert m_clientIDs.get(clientId) != null;
|
||||
m_clientIDs.get(clientId).getSession().write(pubMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,10 +21,13 @@ import org.dna.mqtt.moquette.proto.PublishDecoder;
|
||||
import org.dna.mqtt.moquette.proto.PublishEncoder;
|
||||
import org.dna.mqtt.moquette.proto.SubAckEncoder;
|
||||
import org.dna.mqtt.moquette.proto.SubscribeDecoder;
|
||||
import org.dna.mqtt.moquette.proto.UnsubAckEncoder;
|
||||
import org.dna.mqtt.moquette.proto.UnsubscribeDecoder;
|
||||
import org.dna.mqtt.moquette.proto.messages.ConnAckMessage;
|
||||
import org.dna.mqtt.moquette.proto.messages.PingRespMessage;
|
||||
import org.dna.mqtt.moquette.proto.messages.PublishMessage;
|
||||
import org.dna.mqtt.moquette.proto.messages.SubAckMessage;
|
||||
import org.dna.mqtt.moquette.proto.messages.UnsubAckMessage;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
/**
|
||||
@@ -52,6 +55,7 @@ public class Server {
|
||||
decoder.addMessageDecoder(new ConnectDecoder());
|
||||
decoder.addMessageDecoder(new PublishDecoder());
|
||||
decoder.addMessageDecoder(new SubscribeDecoder());
|
||||
decoder.addMessageDecoder(new UnsubscribeDecoder());
|
||||
decoder.addMessageDecoder(new DisconnectDecoder());
|
||||
decoder.addMessageDecoder(new PingReqDecoder());
|
||||
|
||||
@@ -59,6 +63,7 @@ public class Server {
|
||||
// encoder.addMessageEncoder(ConnectMessage.class, new ConnectEncoder());
|
||||
encoder.addMessageEncoder(ConnAckMessage.class, new ConnAckEncoder());
|
||||
encoder.addMessageEncoder(SubAckMessage.class, new SubAckEncoder());
|
||||
encoder.addMessageEncoder(UnsubAckMessage.class, new UnsubAckEncoder());
|
||||
encoder.addMessageEncoder(PublishMessage.class, new PublishEncoder());
|
||||
encoder.addMessageEncoder(PingRespMessage.class, new PingRespEncoder());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user