Rearchitected the broker, switching from ProtocolProcessor and publisher to MQTTConnection, Session and PostOffice
This commit is contained in:
@@ -10,7 +10,7 @@ import io.moquette.spi.impl.subscriptions.ISubscriptionsDirectory;
|
||||
import io.moquette.spi.impl.subscriptions.Subscription;
|
||||
import io.moquette.spi.impl.subscriptions.Topic;
|
||||
import io.moquette.spi.security.IAuthenticator;
|
||||
import io.moquette.spi.security.IAuthorizator;
|
||||
import io.moquette.spi.security.IAuthorizatorPolicy;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
@@ -40,7 +40,7 @@ public class ConnectHandler {
|
||||
private SessionsRepository sessionsRepository;
|
||||
private ISessionsStore m_sessionsStore;
|
||||
private IAuthenticator m_authenticator;
|
||||
private IAuthorizator m_authorizator;
|
||||
private IAuthorizatorPolicy m_authorizator;
|
||||
private ISubscriptionsDirectory subscriptions;
|
||||
private boolean allowAnonymous;
|
||||
private boolean allowZeroByteClientId;
|
||||
@@ -48,7 +48,7 @@ public class ConnectHandler {
|
||||
private InternalRepublisher internalRepublisher;
|
||||
|
||||
ConnectHandler(IConnectionsManager connectedClients, BrokerInterceptor interceptor, SessionsRepository sessionsRepository,
|
||||
ISessionsStore sessionsStore, IAuthenticator authenticator, IAuthorizator authorizator,
|
||||
ISessionsStore sessionsStore, IAuthenticator authenticator, IAuthorizatorPolicy authorizator,
|
||||
ISubscriptionsDirectory subscriptions, boolean allowAnonymous, boolean allowZeroByteClientId,
|
||||
boolean reauthorizeSubscriptionsOnConnect, InternalRepublisher internalRepublisher) {
|
||||
this.connectionDescriptors = connectedClients;
|
||||
|
||||
@@ -20,10 +20,19 @@ import io.netty.buffer.ByteBuf;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
final class DebugUtils {
|
||||
public final class DebugUtils {
|
||||
|
||||
static String payload2Str(ByteBuf content) {
|
||||
return new String(content.copy().array(), StandardCharsets.UTF_8);
|
||||
public static String payload2Str(ByteBuf content) {
|
||||
final ByteBuf copy = content.copy();
|
||||
final byte[] bytesContent;
|
||||
if (copy.isDirect()) {
|
||||
final int size = copy.readableBytes();
|
||||
bytesContent = new byte[size];
|
||||
copy.readBytes(bytesContent);
|
||||
} else {
|
||||
bytesContent = copy.array();
|
||||
}
|
||||
return new String(bytesContent, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private DebugUtils() {
|
||||
|
||||
@@ -31,7 +31,7 @@ import io.moquette.spi.impl.subscriptions.ISubscriptionsDirectory;
|
||||
import io.moquette.spi.impl.subscriptions.Subscription;
|
||||
import io.moquette.spi.impl.subscriptions.Topic;
|
||||
import io.moquette.spi.security.IAuthenticator;
|
||||
import io.moquette.spi.security.IAuthorizator;
|
||||
import io.moquette.spi.security.IAuthorizatorPolicy;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.handler.codec.mqtt.*;
|
||||
@@ -41,11 +41,9 @@ import org.slf4j.LoggerFactory;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import static io.moquette.server.ConnectionDescriptor.ConnectionState.*;
|
||||
import static io.moquette.spi.impl.InternalRepublisher.createPublishForQos;
|
||||
import static io.moquette.spi.impl.Utils.messageId;
|
||||
import static io.moquette.spi.impl.Utils.readBytesAndRewind;
|
||||
@@ -72,7 +70,7 @@ public class ProtocolProcessor {
|
||||
private ConcurrentMap<RunningSubscription, SubscriptionState> subscriptionInCourse;
|
||||
|
||||
private ISubscriptionsDirectory subscriptions;
|
||||
private IAuthorizator m_authorizator;
|
||||
private IAuthorizatorPolicy m_authorizator;
|
||||
|
||||
private IMessagesStore m_messagesStore;
|
||||
|
||||
@@ -94,7 +92,7 @@ public class ProtocolProcessor {
|
||||
}
|
||||
|
||||
public void init(ISubscriptionsDirectory subscriptions, IMessagesStore storageService, ISessionsStore sessionsStore,
|
||||
IAuthenticator authenticator, boolean allowAnonymous, IAuthorizator authorizator,
|
||||
IAuthenticator authenticator, boolean allowAnonymous, IAuthorizatorPolicy authorizator,
|
||||
BrokerInterceptor interceptor, SessionsRepository sessionsRepository,
|
||||
boolean reauthorizeSubscriptionsOnConnect) {
|
||||
init(subscriptions, storageService, sessionsStore, authenticator, allowAnonymous, false,
|
||||
@@ -103,7 +101,7 @@ public class ProtocolProcessor {
|
||||
|
||||
public void init(ISubscriptionsDirectory subscriptions, IMessagesStore storageService, ISessionsStore sessionsStore,
|
||||
IAuthenticator authenticator, boolean allowAnonymous, boolean allowZeroByteClientId,
|
||||
IAuthorizator authorizator, BrokerInterceptor interceptor, SessionsRepository sessionsRepository,
|
||||
IAuthorizatorPolicy authorizator, BrokerInterceptor interceptor, SessionsRepository sessionsRepository,
|
||||
boolean reauthorizeSubscriptionsOnConnect) {
|
||||
init(new ConnectionDescriptorStore(), subscriptions, storageService, sessionsStore,
|
||||
authenticator, allowAnonymous, allowZeroByteClientId, authorizator, interceptor, sessionsRepository,
|
||||
@@ -130,7 +128,7 @@ public class ProtocolProcessor {
|
||||
*/
|
||||
void init(IConnectionsManager connectionDescriptors, ISubscriptionsDirectory subscriptions,
|
||||
IMessagesStore storageService, ISessionsStore sessionsStore, IAuthenticator authenticator,
|
||||
boolean allowAnonymous, boolean allowZeroByteClientId, IAuthorizator authorizator,
|
||||
boolean allowAnonymous, boolean allowZeroByteClientId, IAuthorizatorPolicy authorizator,
|
||||
BrokerInterceptor interceptor, SessionsRepository sessionsRepository,
|
||||
boolean reauthorizeSubscriptionsOnConnect) {
|
||||
LOG.info("Initializing MQTT protocol processor..");
|
||||
|
||||
@@ -31,7 +31,7 @@ import io.moquette.spi.impl.subscriptions.CTrieSubscriptionDirectory;
|
||||
import io.moquette.spi.impl.subscriptions.ISubscriptionsDirectory;
|
||||
import io.moquette.spi.impl.subscriptions.Subscription;
|
||||
import io.moquette.spi.security.IAuthenticator;
|
||||
import io.moquette.spi.security.IAuthorizator;
|
||||
import io.moquette.spi.security.IAuthorizatorPolicy;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -82,7 +82,7 @@ public class ProtocolProcessorBootstrapper {
|
||||
* @return the processor created for the broker.
|
||||
*/
|
||||
public ProtocolProcessor init(IConfig props, List<? extends InterceptHandler> embeddedObservers,
|
||||
IAuthenticator authenticator, IAuthorizator authorizator, Server server) {
|
||||
IAuthenticator authenticator, IAuthorizatorPolicy authorizator, Server server) {
|
||||
IMessagesStore messagesStore;
|
||||
LOG.info("Initializing messages and sessions stores...");
|
||||
String storageClassName = props.getProperty(BrokerConstants.STORAGE_CLASS_NAME, INMEMDB_STORE_CLASS);
|
||||
@@ -145,13 +145,13 @@ public class ProtocolProcessorBootstrapper {
|
||||
LOG.info("Configuring MQTT authorizator...");
|
||||
String authorizatorClassName = props.getProperty(BrokerConstants.AUTHORIZATOR_CLASS_NAME, "");
|
||||
if (authorizator == null && !authorizatorClassName.isEmpty()) {
|
||||
authorizator = loadClass(authorizatorClassName, IAuthorizator.class, IConfig.class, props);
|
||||
authorizator = loadClass(authorizatorClassName, IAuthorizatorPolicy.class, IConfig.class, props);
|
||||
}
|
||||
|
||||
if (authorizator == null) {
|
||||
String aclFilePath = props.getProperty(BrokerConstants.ACL_FILE_PROPERTY_NAME, "");
|
||||
if (aclFilePath != null && !aclFilePath.isEmpty()) {
|
||||
authorizator = new DenyAllAuthorizator();
|
||||
authorizator = new DenyAllAuthorizatorPolicy();
|
||||
try {
|
||||
LOG.info("Parsing ACL file. Path = {}", aclFilePath);
|
||||
authorizator = ACLFileParser.parse(resourceLoader.loadResource(aclFilePath));
|
||||
@@ -159,7 +159,7 @@ public class ProtocolProcessorBootstrapper {
|
||||
LOG.error("Unable to parse ACL file. path=" + aclFilePath, pex);
|
||||
}
|
||||
} else {
|
||||
authorizator = new PermitAllAuthorizator();
|
||||
authorizator = new PermitAllAuthorizatorPolicy();
|
||||
}
|
||||
LOG.info("An {} authorizator instance will be used", authorizator.getClass().getName());
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ package io.moquette.spi.impl;
|
||||
import io.moquette.server.netty.NettyUtils;
|
||||
import io.moquette.spi.IMessagesStore;
|
||||
import io.moquette.spi.impl.subscriptions.Topic;
|
||||
import io.moquette.spi.security.IAuthorizator;
|
||||
import io.moquette.spi.security.IAuthorizatorPolicy;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.handler.codec.mqtt.MqttPublishMessage;
|
||||
import org.slf4j.Logger;
|
||||
@@ -34,7 +34,7 @@ class Qos0PublishHandler extends QosPublishHandler {
|
||||
private final BrokerInterceptor m_interceptor;
|
||||
private final MessagesPublisher publisher;
|
||||
|
||||
public Qos0PublishHandler(IAuthorizator authorizator, IMessagesStore messagesStore, BrokerInterceptor interceptor,
|
||||
public Qos0PublishHandler(IAuthorizatorPolicy authorizator, IMessagesStore messagesStore, BrokerInterceptor interceptor,
|
||||
MessagesPublisher messagesPublisher) {
|
||||
super(authorizator);
|
||||
this.m_messagesStore = messagesStore;
|
||||
|
||||
@@ -18,11 +18,10 @@ package io.moquette.spi.impl;
|
||||
|
||||
import io.moquette.connections.IConnectionsManager;
|
||||
import io.moquette.server.ConnectionDescriptor;
|
||||
import io.moquette.server.ConnectionDescriptorStore;
|
||||
import io.moquette.server.netty.NettyUtils;
|
||||
import io.moquette.spi.IMessagesStore;
|
||||
import io.moquette.spi.impl.subscriptions.Topic;
|
||||
import io.moquette.spi.security.IAuthorizator;
|
||||
import io.moquette.spi.security.IAuthorizatorPolicy;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.handler.codec.mqtt.MqttFixedHeader;
|
||||
import io.netty.handler.codec.mqtt.MqttMessageType;
|
||||
@@ -47,7 +46,7 @@ class Qos1PublishHandler extends QosPublishHandler {
|
||||
private final IConnectionsManager connectionDescriptors;
|
||||
private final MessagesPublisher publisher;
|
||||
|
||||
Qos1PublishHandler(IAuthorizator authorizator, IMessagesStore messagesStore, BrokerInterceptor interceptor,
|
||||
Qos1PublishHandler(IAuthorizatorPolicy authorizator, IMessagesStore messagesStore, BrokerInterceptor interceptor,
|
||||
IConnectionsManager connectionDescriptors, MessagesPublisher messagesPublisher) {
|
||||
super(authorizator);
|
||||
this.m_messagesStore = messagesStore;
|
||||
|
||||
@@ -18,14 +18,12 @@ package io.moquette.spi.impl;
|
||||
|
||||
import io.moquette.connections.IConnectionsManager;
|
||||
import io.moquette.server.ConnectionDescriptor;
|
||||
import io.moquette.server.ConnectionDescriptorStore;
|
||||
import io.moquette.server.netty.NettyUtils;
|
||||
import io.moquette.spi.ClientSession;
|
||||
import io.moquette.spi.IMessagesStore;
|
||||
import io.moquette.spi.ISessionsStore;
|
||||
import io.moquette.spi.impl.subscriptions.ISubscriptionsDirectory;
|
||||
import io.moquette.spi.impl.subscriptions.Topic;
|
||||
import io.moquette.spi.security.IAuthorizator;
|
||||
import io.moquette.spi.security.IAuthorizatorPolicy;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.handler.codec.mqtt.*;
|
||||
import org.slf4j.Logger;
|
||||
@@ -50,7 +48,7 @@ class Qos2PublishHandler extends QosPublishHandler {
|
||||
private final MessagesPublisher publisher;
|
||||
private final SessionsRepository sessionsRepository;
|
||||
|
||||
Qos2PublishHandler(IAuthorizator authorizator, ISubscriptionsDirectory subscriptions,
|
||||
Qos2PublishHandler(IAuthorizatorPolicy authorizator, ISubscriptionsDirectory subscriptions,
|
||||
IMessagesStore messagesStore, BrokerInterceptor interceptor,
|
||||
IConnectionsManager connectionDescriptors,
|
||||
MessagesPublisher messagesPublisher, SessionsRepository sessionsRepository) {
|
||||
|
||||
@@ -20,16 +20,16 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import io.moquette.server.netty.NettyUtils;
|
||||
import io.moquette.spi.impl.subscriptions.Topic;
|
||||
import io.moquette.spi.security.IAuthorizator;
|
||||
import io.moquette.spi.security.IAuthorizatorPolicy;
|
||||
import io.netty.channel.Channel;
|
||||
|
||||
abstract class QosPublishHandler {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(QosPublishHandler.class);
|
||||
|
||||
protected final IAuthorizator m_authorizator;
|
||||
protected final IAuthorizatorPolicy m_authorizator;
|
||||
|
||||
protected QosPublishHandler(IAuthorizator m_authorizator) {
|
||||
protected QosPublishHandler(IAuthorizatorPolicy m_authorizator) {
|
||||
this.m_authorizator = m_authorizator;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package io.moquette.spi.impl.security;
|
||||
|
||||
import io.moquette.spi.impl.subscriptions.Topic;
|
||||
import io.moquette.spi.security.IAuthorizator;
|
||||
import io.moquette.spi.security.IAuthorizatorPolicy;
|
||||
import java.text.ParseException;
|
||||
import java.util.*;
|
||||
|
||||
@@ -27,7 +27,7 @@ import java.util.*;
|
||||
*
|
||||
* Not thread safe.
|
||||
*/
|
||||
class AuthorizationsCollector implements IAuthorizator {
|
||||
class AuthorizationsCollector implements IAuthorizatorPolicy {
|
||||
|
||||
private List<Authorization> m_globalAuthorizations = new ArrayList<>();
|
||||
private List<Authorization> m_patternAuthorizations = new ArrayList<>();
|
||||
|
||||
+2
-2
@@ -17,9 +17,9 @@
|
||||
package io.moquette.spi.impl.security;
|
||||
|
||||
import io.moquette.spi.impl.subscriptions.Topic;
|
||||
import io.moquette.spi.security.IAuthorizator;
|
||||
import io.moquette.spi.security.IAuthorizatorPolicy;
|
||||
|
||||
public class DenyAllAuthorizator implements IAuthorizator {
|
||||
public class DenyAllAuthorizatorPolicy implements IAuthorizatorPolicy {
|
||||
|
||||
@Override
|
||||
public boolean canWrite(Topic topic, String user, String client) {
|
||||
+2
-2
@@ -17,9 +17,9 @@
|
||||
package io.moquette.spi.impl.security;
|
||||
|
||||
import io.moquette.spi.impl.subscriptions.Topic;
|
||||
import io.moquette.spi.security.IAuthorizator;
|
||||
import io.moquette.spi.security.IAuthorizatorPolicy;
|
||||
|
||||
public class PermitAllAuthorizator implements IAuthorizator {
|
||||
public class PermitAllAuthorizatorPolicy implements IAuthorizatorPolicy {
|
||||
|
||||
@Override
|
||||
public boolean canWrite(Topic topic, String user, String client) {
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package io.moquette.spi.impl.subscriptions;
|
||||
|
||||
import io.netty.handler.codec.mqtt.MqttQoS;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
class CNode {
|
||||
@@ -79,8 +81,8 @@ class CNode {
|
||||
this.children.remove(node);
|
||||
}
|
||||
|
||||
CNode addSubscription(String clientId, Topic topic) {
|
||||
this.subscriptions.add(new Subscription(clientId, topic));
|
||||
CNode addSubscription(Subscription newSubscription) {
|
||||
this.subscriptions.add(new Subscription(newSubscription));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
+53
-17
@@ -98,9 +98,45 @@ public class CTrieSubscriptionDirectory implements ISubscriptionsDirectory {
|
||||
* to use fo searching matching subscriptions.
|
||||
* @return the list of matching subscriptions, or empty if not matching.
|
||||
*/
|
||||
Set<Subscription> match(Topic topic) {
|
||||
final Set<Subscription> matchingSubs = recursiveMatch(topic, this.root);
|
||||
@Override
|
||||
public Set<Subscription> matchWithoutQosSharpening(Topic topic) {
|
||||
return recursiveMatch(topic, this.root);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Subscription> matchQosSharpening(Topic topic) {
|
||||
final Set<Subscription> subscriptions = matchWithoutQosSharpening(topic);
|
||||
|
||||
Map<String, Subscription> subsGroupedByClient = new HashMap<>();
|
||||
for (Subscription sub : subscriptions) {
|
||||
Subscription existingSub = subsGroupedByClient.get(sub.clientId);
|
||||
// update the selected subscriptions if not present or if has a greater qos
|
||||
if (existingSub == null || existingSub.qosLessThan(sub)) {
|
||||
subsGroupedByClient.put(sub.clientId, sub);
|
||||
}
|
||||
}
|
||||
return new HashSet<>(subsGroupedByClient.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a topic string return the clients subscriptions that matches it. Topic string can't
|
||||
* contain character # and + because they are reserved to listeners subscriptions, and not topic
|
||||
* publishing.
|
||||
*
|
||||
* @param topic
|
||||
* to use fo searching matching subscriptions.
|
||||
* @return the list of matching subscriptions, or empty if not matching.
|
||||
*/
|
||||
@Deprecated
|
||||
Set<Subscription> match(Topic topic) {
|
||||
final Set<Subscription> matchingSubs = matchWithoutQosSharpening(topic);
|
||||
// remove the overlapping subscriptions, selecting ones with greatest qos
|
||||
Map<String, Subscription> subsForClient = loadSubscriptionsFromStorage(matchingSubs);
|
||||
return new HashSet<>(subsForClient.values());
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
private Map<String, Subscription> loadSubscriptionsFromStorage(Set<Subscription> matchingSubs) {
|
||||
Map<String, Subscription> subsForClient = new HashMap<>();
|
||||
for (Subscription matchingSub : matchingSubs) {
|
||||
Subscription existingSub = subsForClient.get(matchingSub.clientId);
|
||||
@@ -120,7 +156,7 @@ public class CTrieSubscriptionDirectory implements ISubscriptionsDirectory {
|
||||
subsForClient.put(sub.clientId, sub);
|
||||
}
|
||||
}
|
||||
return new HashSet<>(subsForClient.values());
|
||||
return subsForClient;
|
||||
}
|
||||
|
||||
Set<Subscription> recursiveMatch(Topic topic, INode inode) {
|
||||
@@ -171,28 +207,28 @@ public class CTrieSubscriptionDirectory implements ISubscriptionsDirectory {
|
||||
public void add(Subscription newSubscription) {
|
||||
Action res;
|
||||
do {
|
||||
res = insert(newSubscription.clientId, newSubscription.topicFilter, this.root, newSubscription.topicFilter);
|
||||
res = insert(newSubscription.topicFilter, this.root, newSubscription);
|
||||
} while (res == Action.REPEAT);
|
||||
}
|
||||
|
||||
private Action insert(String clientId, Topic topic, final INode inode, Topic fullpath) {
|
||||
private Action insert(Topic topic, final INode inode, Subscription newSubscription) {
|
||||
Token token = topic.headToken();
|
||||
if (!topic.isEmpty() && inode.mainNode().anyChildrenMatch(token)) {
|
||||
Topic remainingTopic = topic.exceptHeadToken();
|
||||
INode nextInode = inode.mainNode().childOf(token);
|
||||
return insert(clientId, remainingTopic, nextInode, fullpath);
|
||||
return insert(remainingTopic, nextInode, newSubscription);
|
||||
} else {
|
||||
if (topic.isEmpty()) {
|
||||
return insertSubscription(clientId, fullpath, inode);
|
||||
return insertSubscription(inode, newSubscription);
|
||||
} else {
|
||||
return createNodeAndInsertSubscription(clientId, topic, inode, fullpath);
|
||||
return createNodeAndInsertSubscription(topic, inode, newSubscription);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Action insertSubscription(String clientId, Topic topic, INode inode) {
|
||||
private Action insertSubscription(INode inode, Subscription newSubscription) {
|
||||
CNode cnode = inode.mainNode();
|
||||
CNode updatedCnode = cnode.copy().addSubscription(clientId, topic);
|
||||
CNode updatedCnode = cnode.copy().addSubscription(newSubscription);
|
||||
if (inode.compareAndSet(cnode, updatedCnode)) {
|
||||
return Action.OK;
|
||||
} else {
|
||||
@@ -200,8 +236,8 @@ public class CTrieSubscriptionDirectory implements ISubscriptionsDirectory {
|
||||
}
|
||||
}
|
||||
|
||||
private Action createNodeAndInsertSubscription(String clientId, Topic topic, INode inode, Topic fullpath) {
|
||||
INode newInode = createPathRec(clientId, topic, fullpath);
|
||||
private Action createNodeAndInsertSubscription(Topic topic, INode inode, Subscription newSubscription) {
|
||||
INode newInode = createPathRec(topic, newSubscription);
|
||||
CNode cnode = inode.mainNode();
|
||||
CNode updatedCnode = cnode.copy();
|
||||
updatedCnode.add(newInode);
|
||||
@@ -209,24 +245,24 @@ public class CTrieSubscriptionDirectory implements ISubscriptionsDirectory {
|
||||
return inode.compareAndSet(cnode, updatedCnode) ? Action.OK : Action.REPEAT;
|
||||
}
|
||||
|
||||
private INode createLeafNodes(String clientId, Topic fullpath, Token token) {
|
||||
private INode createLeafNodes(Token token, Subscription newSubscription) {
|
||||
CNode newLeafCnode = new CNode();
|
||||
newLeafCnode.token = token;
|
||||
newLeafCnode.addSubscription(clientId, fullpath);
|
||||
newLeafCnode.addSubscription(newSubscription);
|
||||
|
||||
return new INode(newLeafCnode);
|
||||
}
|
||||
|
||||
private INode createPathRec(String clientId, Topic topic, Topic fullpath) {
|
||||
private INode createPathRec(Topic topic, Subscription newSubscription) {
|
||||
Topic remainingTopic = topic.exceptHeadToken();
|
||||
if (!remainingTopic.isEmpty()) {
|
||||
INode inode = createPathRec(clientId, remainingTopic, fullpath);
|
||||
INode inode = createPathRec(remainingTopic, newSubscription);
|
||||
CNode cnode = new CNode();
|
||||
cnode.token = topic.headToken();
|
||||
cnode.add(inode);
|
||||
return new INode(cnode);
|
||||
} else {
|
||||
return createLeafNodes(clientId, fullpath, topic.headToken());
|
||||
return createLeafNodes(topic.headToken(), newSubscription);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,11 +18,16 @@ package io.moquette.spi.impl.subscriptions;
|
||||
import io.moquette.spi.impl.SessionsRepository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public interface ISubscriptionsDirectory {
|
||||
|
||||
void init(SessionsRepository sessionsRepository);
|
||||
|
||||
Set<Subscription> matchWithoutQosSharpening(Topic topic);
|
||||
|
||||
Set<Subscription> matchQosSharpening(Topic topic);
|
||||
|
||||
void add(Subscription newSubscription);
|
||||
|
||||
void removeSubscription(Topic topic, String clientID);
|
||||
|
||||
@@ -33,7 +33,7 @@ class TNode extends CNode {
|
||||
}
|
||||
|
||||
@Override
|
||||
CNode addSubscription(String clientId, Topic topic) {
|
||||
CNode addSubscription(Subscription newSubscription) {
|
||||
throw new IllegalStateException("Can't be invoked on TNode");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user