First refactoring using the concept of ClientSession also for publish
This commit is contained in:
@@ -156,8 +156,8 @@ public class ServerIntegrationFuseTest {
|
||||
//reconnect and expect to receive the hello 2 message
|
||||
m_subscriber = m_mqtt.blockingConnection();
|
||||
m_subscriber.connect();
|
||||
topics = new Topic[]{new Topic("/topic", QoS.AT_LEAST_ONCE)};
|
||||
m_subscriber.subscribe(topics);
|
||||
//topics = new Topic[]{new Topic("/topic", QoS.AT_LEAST_ONCE)};
|
||||
//m_subscriber.subscribe(topics);
|
||||
msg = m_subscriber.receive();
|
||||
msg.ack();
|
||||
assertEquals("Hello world MQTT!!-2", new String(msg.getPayload()));
|
||||
|
||||
@@ -38,8 +38,13 @@ public class MemoryStorageService implements IMessagesStore, ISessionsStore {
|
||||
|
||||
private Map<String, StoredMessage> m_retainedStore = new HashMap<>();
|
||||
//TODO move in a multimap because only Qos1 and QoS2 are stored here and they have messageID(key of secondary map)
|
||||
private Map<String, List<PublishEvent>> m_persistentMessageStore = new HashMap<>();
|
||||
private Map<String, PublishEvent> m_inflightStore = new HashMap<>();
|
||||
private Map<String, PublishEvent> m_persistentMessageStore = new HashMap<>();
|
||||
//maps clientID->[MessageId -> guid]
|
||||
private Map<String, Map<Integer, String>> m_inflightStore = new HashMap<>();
|
||||
//maps clientID->[guid*]
|
||||
private Map<String, Set<String>> m_enqueuedStore = new HashMap<>();
|
||||
//maps clientID->[messageID*]
|
||||
private Map<String, Set<Integer>> m_secondPhaseStore = new HashMap<>();
|
||||
private Map<String, Set<Integer>> m_inflightIDs = new HashMap<>();
|
||||
private Map<String, PublishEvent> m_qos2Store = new HashMap<>();
|
||||
private MemorySessionStore m_sessionsStore;
|
||||
@@ -85,37 +90,21 @@ public class MemoryStorageService implements IMessagesStore, ISessionsStore {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void storePublishForFuture(PublishEvent evt) {
|
||||
public String storePublishForFuture(PublishEvent evt) {
|
||||
LOG.debug("storePublishForFuture store evt {}", evt);
|
||||
String clientID = evt.getClientID();
|
||||
List<PublishEvent> storedEvents = defaultGet(m_persistentMessageStore, clientID, new ArrayList<PublishEvent>());
|
||||
storedEvents.add(evt);
|
||||
m_persistentMessageStore.put(clientID, storedEvents);
|
||||
String guid = UUID.randomUUID().toString();
|
||||
evt.setGuid(guid);
|
||||
m_persistentMessageStore.put(guid, evt);
|
||||
return guid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PublishEvent> listMessagesInSession(String clientID) {
|
||||
return new ArrayList<>(defaultGet(m_persistentMessageStore, clientID, Collections.<PublishEvent>emptyList()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeMessage(String clientID, Integer messageID) {
|
||||
List<PublishEvent> events = m_persistentMessageStore.get(clientID);
|
||||
if (events == null) {
|
||||
return;
|
||||
public List<PublishEvent> listMessagesInSession(Collection<String> guids) {
|
||||
List<PublishEvent> ret = new ArrayList<>();
|
||||
for (String guid : guids) {
|
||||
ret.add(m_persistentMessageStore.get(guid));
|
||||
}
|
||||
PublishEvent toRemoveEvt = null;
|
||||
for (PublishEvent evt : events) {
|
||||
if (evt.getMessageID() == null && messageID == null) {
|
||||
//was a qos0 message (no ID)
|
||||
toRemoveEvt = evt;
|
||||
}
|
||||
if (evt.getMessageID() == messageID) {
|
||||
toRemoveEvt = evt;
|
||||
}
|
||||
}
|
||||
events.remove(toRemoveEvt);
|
||||
m_persistentMessageStore.put(clientID, events);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -123,22 +112,6 @@ public class MemoryStorageService implements IMessagesStore, ISessionsStore {
|
||||
m_persistentMessageStore.remove(clientID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanTemporaryPublish(String clientID, int packetID) {
|
||||
String publishKey = String.format("%s%d", clientID, packetID);
|
||||
m_inflightStore.remove(publishKey);
|
||||
Set<Integer> inFlightForClient = m_inflightIDs.get(clientID);
|
||||
if (inFlightForClient != null) {
|
||||
inFlightForClient.remove(packetID);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void storeTemporaryPublish(PublishEvent evt, String clientID, int packetID) {
|
||||
String publishKey = String.format("%s%d", clientID, packetID);
|
||||
m_inflightStore.put(publishKey, evt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the next valid packetIdentifier for the given client session.
|
||||
* */
|
||||
@@ -229,4 +202,57 @@ public class MemoryStorageService implements IMessagesStore, ISessionsStore {
|
||||
public void deactivate(String clientID) {
|
||||
m_sessionsStore.deactivate(clientID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inFlightAck(String clientID, int messageID) {
|
||||
Map<Integer, String> m = this.m_inflightStore.get(clientID);
|
||||
if (m == null) {
|
||||
LOG.error("Can't find the inFlight record for client <{}>", clientID);
|
||||
return;
|
||||
}
|
||||
m.remove(messageID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inFlight(String clientID, int messageID, String guid) {
|
||||
Map<Integer, String> m = this.m_inflightStore.get(clientID);
|
||||
if (m == null) {
|
||||
m = new HashMap<>();
|
||||
}
|
||||
m.put(messageID, guid);
|
||||
this.m_inflightStore.put(clientID, m);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindToDeliver(String guid, String clientID) {
|
||||
Set<String> guids = defaultGet(m_enqueuedStore, clientID, new HashSet<String>());
|
||||
guids.add(guid);
|
||||
m_enqueuedStore.put(clientID, guids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> enqueued(String clientID) {
|
||||
return defaultGet(m_enqueuedStore, clientID, new HashSet<String>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeEnqueued(String clientID, String guid) {
|
||||
Set<String> guids = defaultGet(m_enqueuedStore, clientID, new HashSet<String>());
|
||||
guids.remove(guid);
|
||||
m_enqueuedStore.put(clientID, guids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void secondPhaseAcknowledged(String clientID, int messageID) {
|
||||
Set<Integer> messageIDs = defaultGet(m_secondPhaseStore, clientID, new HashSet<Integer>());
|
||||
messageIDs.remove(messageID);
|
||||
m_secondPhaseStore.put(clientID, messageIDs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void secondPhaseAckWaiting(String clientID, int messageID) {
|
||||
Set<Integer> messageIDs = defaultGet(m_secondPhaseStore, clientID, new HashSet<Integer>());
|
||||
messageIDs.add(messageID);
|
||||
m_secondPhaseStore.put(clientID, messageIDs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,7 +368,8 @@ public class ProtocolProcessorTest {
|
||||
m_processor.processConnect(m_session, connectMessage);
|
||||
|
||||
//Verify no messages are still stored
|
||||
assertTrue(m_storageService.listMessagesInSession(FAKE_PUBLISHER_ID).isEmpty());
|
||||
Collection<String> guids = m_sessionStore.enqueued(FAKE_PUBLISHER_ID);
|
||||
assertTrue(m_storageService.listMessagesInSession(guids).isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -483,8 +484,8 @@ public class ProtocolProcessorTest {
|
||||
|
||||
ProtocolProcessor processor = new ProtocolProcessor() {
|
||||
@Override
|
||||
protected void sendPublish(String clientId, String topic, AbstractMessage.QOSType qos, ByteBuffer message,
|
||||
boolean retained, Integer messageID) {
|
||||
protected void directSend(String clientId, String topic, AbstractMessage.QOSType qos, ByteBuffer message,
|
||||
boolean retained, Integer messageID) {
|
||||
publishedForwarded.add(new PublishEvent(topic, qos, message, retained, clientId, messageID));
|
||||
}
|
||||
};
|
||||
|
||||
+2
-2
@@ -243,7 +243,7 @@ public class ProtocolProcessor_CONNECT_Test {
|
||||
//Connect a first time
|
||||
m_processor.processConnect(m_session, connMsg);
|
||||
//disconnect
|
||||
m_processor.processDisconnect(m_session, new DisconnectMessage());
|
||||
m_processor.processDisconnect(m_session);
|
||||
|
||||
//Exercise, reconnect
|
||||
MockReceiverChannel firstReceiverSession = new MockReceiverChannel();
|
||||
@@ -278,7 +278,7 @@ public class ProtocolProcessor_CONNECT_Test {
|
||||
assertTrue(subscriptions.contains(expectedSubscription));
|
||||
|
||||
//disconnect
|
||||
m_processor.processDisconnect(m_session, new DisconnectMessage());
|
||||
m_processor.processDisconnect(m_session);
|
||||
|
||||
//reconnect clean session a false
|
||||
m_processor.processConnect(m_session, connMsg);
|
||||
|
||||
+1
-1
@@ -91,7 +91,7 @@ public class MapDBPersistentStoreTest {
|
||||
assertEquals(1, packetId);
|
||||
|
||||
//release the ID
|
||||
m_storageService.cleanTemporaryPublish("CLIENT", packetId);
|
||||
// m_storageService.cleanTemporaryPublish("CLIENT", packetId);
|
||||
|
||||
//request a second packetID, counter restarts from 0
|
||||
packetId = m_storageService.nextPacketID("CLIENT");
|
||||
|
||||
@@ -19,6 +19,8 @@ import org.eclipse.moquette.spi.ClientSession;
|
||||
import org.eclipse.moquette.spi.IMessagesStore;
|
||||
import org.eclipse.moquette.spi.ISessionsStore;
|
||||
import org.eclipse.moquette.spi.impl.subscriptions.Subscription;
|
||||
|
||||
import static org.eclipse.moquette.spi.impl.Utils.defaultGet;
|
||||
import static org.eclipse.moquette.spi.persistence.MapDBPersistentStore.PersistentSession;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -36,6 +38,13 @@ public class MemorySessionStore implements ISessionsStore {
|
||||
|
||||
private Map<String, PersistentSession> m_persistentSessions = new HashMap<>();
|
||||
|
||||
//maps clientID->[MessageId -> guid]
|
||||
private Map<String, Map<Integer, String>> m_inflightStore = new HashMap<>();
|
||||
//maps clientID->[guid*]
|
||||
private Map<String, Set<String>> m_enqueuedStore = new HashMap<>();
|
||||
//maps clientID->[messageID*]
|
||||
private Map<String, Set<Integer>> m_secondPhaseStore = new HashMap<>();
|
||||
|
||||
private final IMessagesStore m_messagesStore;
|
||||
|
||||
public MemorySessionStore(IMessagesStore messagesStore) {
|
||||
@@ -146,4 +155,57 @@ public class MemorySessionStore implements ISessionsStore {
|
||||
PersistentSession newStoredSession = new PersistentSession(storedSession.cleanSession, activation);
|
||||
m_persistentSessions.put(clientID, newStoredSession);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inFlightAck(String clientID, int messageID) {
|
||||
Map<Integer, String> m = this.m_inflightStore.get(clientID);
|
||||
if (m == null) {
|
||||
LOG.error("Can't find the inFlight record for client <{}>", clientID);
|
||||
return;
|
||||
}
|
||||
m.remove(messageID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inFlight(String clientID, int messageID, String guid) {
|
||||
Map<Integer, String> m = this.m_inflightStore.get(clientID);
|
||||
if (m == null) {
|
||||
m = new HashMap<>();
|
||||
}
|
||||
m.put(messageID, guid);
|
||||
this.m_inflightStore.put(clientID, m);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindToDeliver(String guid, String clientID) {
|
||||
Set<String> guids = defaultGet(m_enqueuedStore, clientID, new HashSet<String>());
|
||||
guids.add(guid);
|
||||
m_enqueuedStore.put(clientID, guids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> enqueued(String clientID) {
|
||||
return defaultGet(m_enqueuedStore, clientID, new HashSet<String>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeEnqueued(String clientID, String guid) {
|
||||
Set<String> guids = defaultGet(m_enqueuedStore, clientID, new HashSet<String>());
|
||||
guids.remove(guid);
|
||||
m_enqueuedStore.put(clientID, guids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void secondPhaseAcknowledged(String clientID, int messageID) {
|
||||
Set<Integer> messageIDs = defaultGet(m_secondPhaseStore, clientID, new HashSet<Integer>());
|
||||
messageIDs.remove(messageID);
|
||||
m_secondPhaseStore.put(clientID, messageIDs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void secondPhaseAckWaiting(String clientID, int messageID) {
|
||||
Set<Integer> messageIDs = defaultGet(m_secondPhaseStore, clientID, new HashSet<Integer>());
|
||||
messageIDs.add(messageID);
|
||||
m_secondPhaseStore.put(clientID, messageIDs);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user